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/Android.bp b/Android.bp
index a083f89..470dd0f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -39,10 +39,7 @@
filegroup {
name: "hs20-osu-client_srcs",
srcs: [
- "hs20/client/spp_client.c",
- "hs20/client/oma_dm_client.c",
"hs20/client/osu_client.c",
- "hs20/client/est.c",
"src/common/wpa_ctrl.c",
"src/common/wpa_helpers.c",
"src/crypto/crypto_internal.c",
@@ -76,10 +73,7 @@
filegroup {
name: "hs20_client_srcs",
srcs: [
- "hs20/client/est.c",
- "hs20/client/oma_dm_client.c",
"hs20/client/osu_client.c",
- "hs20/client/spp_client.c",
"src/common/wpa_ctrl.c",
"src/common/wpa_helpers.c",
"src/crypto/crypto_internal.c",
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 5674962..0c13dab 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -143,7 +143,7 @@
LDFLAGS += -rdynamic
L_CFLAGS += -funwind-tables
ifdef CONFIG_WPA_TRACE_BFD
-L_CFLAGS += -DWPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD -fno-inline -fno-optimize-sibling-calls
LIBS += -lbfd
LIBS_c += -lbfd
LIBS_h += -lbfd
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 4c31ba9..db843a6 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -116,7 +116,7 @@
LDFLAGS += -rdynamic
CFLAGS += -funwind-tables
ifdef CONFIG_WPA_TRACE_BFD
-CFLAGS += -DPACKAGE="hostapd" -DWPA_TRACE_BFD
+CFLAGS += -DPACKAGE="hostapd" -DWPA_TRACE_BFD -fno-inline -fno-optimize-sibling-calls
LIBS += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz
@@ -713,6 +713,7 @@
endif
ifeq ($(CONFIG_TLS), wolfssl)
+CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
CONFIG_CRYPTO=wolfssl
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_wolfssl.o
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index f4a6aeb..a9310f2 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -713,10 +713,6 @@
else if (os_strcmp(start, "DPP") == 0)
val |= WPA_KEY_MGMT_DPP;
#endif /* CONFIG_DPP */
-#ifdef CONFIG_HS20
- else if (os_strcmp(start, "OSEN") == 0)
- val |= WPA_KEY_MGMT_OSEN;
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_PASN
else if (os_strcmp(start, "PASN") == 0)
val |= WPA_KEY_MGMT_PASN;
@@ -1834,233 +1830,6 @@
return 0;
}
-
-static int hs20_parse_icon(struct hostapd_bss_config *bss, char *pos)
-{
- struct hs20_icon *icon;
- char *end;
-
- icon = os_realloc_array(bss->hs20_icons, bss->hs20_icons_count + 1,
- sizeof(struct hs20_icon));
- if (icon == NULL)
- return -1;
- bss->hs20_icons = icon;
- icon = &bss->hs20_icons[bss->hs20_icons_count];
- os_memset(icon, 0, sizeof(*icon));
-
- icon->width = atoi(pos);
- pos = os_strchr(pos, ':');
- if (pos == NULL)
- return -1;
- pos++;
-
- icon->height = atoi(pos);
- pos = os_strchr(pos, ':');
- if (pos == NULL)
- return -1;
- pos++;
-
- end = os_strchr(pos, ':');
- if (end == NULL || end - pos > 3)
- return -1;
- os_memcpy(icon->language, pos, end - pos);
- pos = end + 1;
-
- end = os_strchr(pos, ':');
- if (end == NULL || end - pos > 255)
- return -1;
- os_memcpy(icon->type, pos, end - pos);
- pos = end + 1;
-
- end = os_strchr(pos, ':');
- if (end == NULL || end - pos > 255)
- return -1;
- os_memcpy(icon->name, pos, end - pos);
- pos = end + 1;
-
- if (os_strlen(pos) > 255)
- return -1;
- os_memcpy(icon->file, pos, os_strlen(pos));
-
- bss->hs20_icons_count++;
-
- return 0;
-}
-
-
-static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
- char *pos, int line)
-{
- size_t slen;
- char *str;
-
- str = wpa_config_parse_string(pos, &slen);
- if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
- os_free(str);
- return -1;
- }
-
- os_memcpy(bss->osu_ssid, str, slen);
- bss->osu_ssid_len = slen;
- os_free(str);
-
- return 0;
-}
-
-
-static int hs20_parse_osu_server_uri(struct hostapd_bss_config *bss,
- char *pos, int line)
-{
- struct hs20_osu_provider *p;
-
- p = os_realloc_array(bss->hs20_osu_providers,
- bss->hs20_osu_providers_count + 1, sizeof(*p));
- if (p == NULL)
- return -1;
-
- bss->hs20_osu_providers = p;
- bss->last_osu = &bss->hs20_osu_providers[bss->hs20_osu_providers_count];
- bss->hs20_osu_providers_count++;
- os_memset(bss->last_osu, 0, sizeof(*p));
- bss->last_osu->server_uri = os_strdup(pos);
-
- return 0;
-}
-
-
-static int hs20_parse_osu_friendly_name(struct hostapd_bss_config *bss,
- char *pos, int line)
-{
- if (bss->last_osu == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
- return -1;
- }
-
- if (parse_lang_string(&bss->last_osu->friendly_name,
- &bss->last_osu->friendly_name_count, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid osu_friendly_name '%s'",
- line, pos);
- return -1;
- }
-
- return 0;
-}
-
-
-static int hs20_parse_osu_nai(struct hostapd_bss_config *bss,
- char *pos, int line)
-{
- if (bss->last_osu == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
- return -1;
- }
-
- os_free(bss->last_osu->osu_nai);
- bss->last_osu->osu_nai = os_strdup(pos);
- if (bss->last_osu->osu_nai == NULL)
- return -1;
-
- return 0;
-}
-
-
-static int hs20_parse_osu_nai2(struct hostapd_bss_config *bss,
- char *pos, int line)
-{
- if (bss->last_osu == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
- return -1;
- }
-
- os_free(bss->last_osu->osu_nai2);
- bss->last_osu->osu_nai2 = os_strdup(pos);
- if (bss->last_osu->osu_nai2 == NULL)
- return -1;
- bss->hs20_osu_providers_nai_count++;
-
- return 0;
-}
-
-
-static int hs20_parse_osu_method_list(struct hostapd_bss_config *bss, char *pos,
- int line)
-{
- if (bss->last_osu == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
- return -1;
- }
-
- if (hostapd_parse_intlist(&bss->last_osu->method_list, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid osu_method_list", line);
- return -1;
- }
-
- return 0;
-}
-
-
-static int hs20_parse_osu_icon(struct hostapd_bss_config *bss, char *pos,
- int line)
-{
- char **n;
- struct hs20_osu_provider *p = bss->last_osu;
-
- if (p == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
- return -1;
- }
-
- n = os_realloc_array(p->icons, p->icons_count + 1, sizeof(char *));
- if (n == NULL)
- return -1;
- p->icons = n;
- p->icons[p->icons_count] = os_strdup(pos);
- if (p->icons[p->icons_count] == NULL)
- return -1;
- p->icons_count++;
-
- return 0;
-}
-
-
-static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
- char *pos, int line)
-{
- if (bss->last_osu == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Unexpected OSU field", line);
- return -1;
- }
-
- if (parse_lang_string(&bss->last_osu->service_desc,
- &bss->last_osu->service_desc_count, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid osu_service_desc '%s'",
- line, pos);
- return -1;
- }
-
- return 0;
-}
-
-
-static int hs20_parse_operator_icon(struct hostapd_bss_config *bss, char *pos,
- int line)
-{
- char **n;
-
- n = os_realloc_array(bss->hs20_operator_icon,
- bss->hs20_operator_icon_count + 1, sizeof(char *));
- if (!n)
- return -1;
- bss->hs20_operator_icon = n;
- bss->hs20_operator_icon[bss->hs20_operator_icon_count] = os_strdup(pos);
- if (!bss->hs20_operator_icon[bss->hs20_operator_icon_count])
- return -1;
- bss->hs20_operator_icon_count++;
-
- return 0;
-}
-
#endif /* CONFIG_HS20 */
@@ -3380,6 +3149,8 @@
bss->radius_server_auth_port = atoi(pos);
} else if (os_strcmp(buf, "radius_server_acct_port") == 0) {
bss->radius_server_acct_port = atoi(pos);
+ } else if (os_strcmp(buf, "radius_server_acct_log") == 0) {
+ bss->radius_server_acct_log = atoi(pos);
} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
bss->radius_server_ipv6 = atoi(pos);
#endif /* RADIUS_SERVER */
@@ -3707,6 +3478,8 @@
bss->rsn_override_mfp = atoi(pos);
} else if (os_strcmp(buf, "rsn_override_mfp_2") == 0) {
bss->rsn_override_mfp_2 = atoi(pos);
+ } else if (os_strcmp(buf, "spp_amsdu") == 0) {
+ bss->spp_amsdu = !!atoi(pos);
} else if (os_strcmp(buf, "group_mgmt_cipher") == 0) {
if (os_strcmp(pos, "AES-128-CMAC") == 0) {
bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
@@ -4383,8 +4156,6 @@
bss->disable_dgaf = atoi(pos);
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
bss->na_mcast_to_ucast = atoi(pos);
- } else if (os_strcmp(buf, "osen") == 0) {
- bss->osen = atoi(pos);
} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
bss->anqp_domain_id = atoi(pos);
} else if (os_strcmp(buf, "hs20_deauth_req_timeout") == 0) {
@@ -4423,44 +4194,6 @@
os_free(bss->hs20_operating_class);
bss->hs20_operating_class = oper_class;
bss->hs20_operating_class_len = oper_class_len;
- } else if (os_strcmp(buf, "hs20_icon") == 0) {
- if (hs20_parse_icon(bss, pos) < 0) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_icon '%s'",
- line, pos);
- return 1;
- }
- } else if (os_strcmp(buf, "osu_ssid") == 0) {
- if (hs20_parse_osu_ssid(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "osu_server_uri") == 0) {
- if (hs20_parse_osu_server_uri(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "osu_friendly_name") == 0) {
- if (hs20_parse_osu_friendly_name(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "osu_nai") == 0) {
- if (hs20_parse_osu_nai(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "osu_nai2") == 0) {
- if (hs20_parse_osu_nai2(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "osu_method_list") == 0) {
- if (hs20_parse_osu_method_list(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "osu_icon") == 0) {
- if (hs20_parse_osu_icon(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "osu_service_desc") == 0) {
- if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "operator_icon") == 0) {
- if (hs20_parse_operator_icon(bss, pos, line) < 0)
- return 1;
- } else if (os_strcmp(buf, "subscr_remediation_url") == 0) {
- os_free(bss->subscr_remediation_url);
- bss->subscr_remediation_url = os_strdup(pos);
- } else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
- bss->subscr_remediation_method = atoi(pos);
} else if (os_strcmp(buf, "hs20_t_c_filename") == 0) {
os_free(bss->t_c_filename);
bss->t_c_filename = os_strdup(pos);
@@ -4469,9 +4202,6 @@
} else if (os_strcmp(buf, "hs20_t_c_server_url") == 0) {
os_free(bss->t_c_server_url);
bss->t_c_server_url = os_strdup(pos);
- } else if (os_strcmp(buf, "hs20_sim_provisioning_url") == 0) {
- os_free(bss->hs20_sim_provisioning_url);
- bss->hs20_sim_provisioning_url = os_strdup(pos);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
} else if (os_strcmp(buf, "mbo") == 0) {
@@ -4501,6 +4231,8 @@
PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
} else if (os_strcmp(buf, "ecsa_ie_only") == 0) {
conf->ecsa_ie_only = atoi(pos);
+ } else if (os_strcmp(buf, "csa_ie_only") == 0) {
+ conf->csa_ie_only = atoi(pos);
} else if (os_strcmp(buf, "bss_load_test") == 0) {
WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
pos = os_strchr(pos, ':');
@@ -4641,6 +4373,8 @@
line);
return 1;
}
+ } else if (os_strcmp(buf, "sae_track_password") == 0) {
+ bss->sae_track_password = atoi(pos);
#endif /* CONFIG_SAE */
} else if (os_strcmp(buf, "vendor_elements") == 0) {
if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
@@ -5061,6 +4795,16 @@
return 1;
}
bss->macsec_csindex = macsec_csindex;
+ } else if (os_strcmp(buf, "macsec_icv_indicator") == 0) {
+ int macsec_icv_indicator = atoi(pos);
+
+ if (macsec_icv_indicator < 0 || macsec_icv_indicator > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid macsec_icv_indicator (%d): '%s'.",
+ line, macsec_icv_indicator, pos);
+ return 1;
+ }
+ bss->macsec_icv_indicator = macsec_icv_indicator;
} else if (os_strcmp(buf, "mka_cak") == 0) {
size_t len = os_strlen(pos);
@@ -5134,6 +4878,12 @@
if (val < 0 || val > 1)
return 1;
bss->ssid_protection = val;
+ } else if (os_strcmp(buf, "known_sta_identification") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 1)
+ return 1;
+ bss->known_sta_identification = val;
} else if (os_strcmp(buf, "channel_usage") == 0) {
conf->channel_usage = atoi(pos);
} else if (os_strcmp(buf, "peer_to_peer_twt") == 0) {
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index dd445d8..e74b1c7 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -596,31 +596,8 @@
#endif /* CONFIG_WPS */
+
#ifdef CONFIG_HS20
-
-static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- const char *url;
-
- if (hwaddr_aton(cmd, addr))
- return -1;
- url = cmd + 17;
- if (*url == '\0') {
- url = NULL;
- } else {
- if (*url != ' ')
- return -1;
- url++;
- if (*url == '\0')
- url = NULL;
- }
-
- return hs20_send_wnm_notification(hapd, addr, 1, url);
-}
-
-
static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd,
const char *cmd)
{
@@ -669,7 +646,6 @@
wpabuf_free(req);
return ret;
}
-
#endif /* CONFIG_HS20 */
@@ -4219,9 +4195,6 @@
reply_len = -1;
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
- } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) {
- if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15))
- reply_len = -1;
} else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) {
if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16))
reply_len = -1;
diff --git a/hostapd/eap_register.c b/hostapd/eap_register.c
index 3e870c7..8bb25f2 100644
--- a/hostapd/eap_register.c
+++ b/hostapd/eap_register.c
@@ -44,13 +44,6 @@
ret = eap_server_unauth_tls_register();
#endif /* EAP_SERVER_TLS */
-#ifdef EAP_SERVER_TLS
-#ifdef CONFIG_HS20
- if (ret == 0)
- ret = eap_server_wfa_unauth_tls_register();
-#endif /* CONFIG_HS20 */
-#endif /* EAP_SERVER_TLS */
-
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index b1e8ac5..338a16c 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1219,6 +1219,10 @@
# mka_priority (Priority of MKA Actor)
# Range: 0..255 (default: 255)
#
+# macsec_icv_indicator: Always include ICV indicator
+# 0 = ICV Indicator is not included when ICV has default length (default)
+# 1 = ICV Indicator is always included (compatibility mode)
+#
# macsec_csindex: IEEE 802.1X/MACsec cipher suite
# 0 = GCM-AES-128 (default)
# 1 = GCM-AES-256 (default)
@@ -1798,6 +1802,9 @@
# accounting while still enabling RADIUS authentication.
#radius_server_acct_port=1813
+# Log received RADIUS accounting data
+#radius_server_acct_log=1
+
# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
#radius_server_ipv6=1
@@ -1881,7 +1888,6 @@
# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
# DPP = Device Provisioning Protocol
-# OSEN = Hotspot 2.0 online signup with encryption
# (dot11RSNAConfigAuthenticationSuitesTable)
#wpa_key_mgmt=WPA-PSK WPA-EAP
@@ -2033,6 +2039,12 @@
# 1 = enabled
#beacon_prot=0
+# SPP (Signaling and Payload Protected) A-MSDU.
+# This depends on driver support and CCMP/GCMP cipher suite being used.
+# 0 = disabled (default)
+# 1 = enabled if driver indicates support for this
+#spp_amsdu=1
+
# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
# (maximum time to wait for a SA Query response)
# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
@@ -2122,6 +2134,24 @@
# contains and entry in the same format as sae_password uses.
#sae_password_file=/tc/hostapd.sae_passwords
+# Tracking of SAE password use
+# While SAE design does not allow the AP to determine the used password robustly
+# if multiple password are configured without use of password identifiers, a
+# small number of such passwords might be usable with minimal impact to STAs.
+# This parameter can be used to enable such mechanism by tracking which password
+# STAs have tried and either succeeded or failed to complete authentication
+# with. Configured passwords are then tried one by one until success. This shows
+# up as a potential attack to the STA, though, and as such, may result in the AP
+# getting rejected after a couple of attempts. Only one password can be tested
+# per attempt, so this limits this mechanism to only a small number (e.g., 2-3)
+# passwords without showing significant usability issues with some STAs. This
+# is meant as a workaround until SAE with password identifiers is deployed on
+# STAs.
+# This parameter sets the maximum number of STA MAC addresses to track per
+# SAE password. This should be set sufficiently high to cover the expected
+# number of active STAs.
+#sae_track_password=0
+
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
# This parameter defines how many open SAE instances can be in progress at the
# same time before the anti-clogging mechanism is taken into use.
@@ -2310,6 +2340,16 @@
#
#ssid_protection=0
+# Known STA Identification
+# IEEE Std 802.11-2024 adds a mechanism that allows the SA Query procedure on
+# (re)association to the previously used AP to be skipped when that AP still
+# has a valid security association. This can speed up cases where a STA needs to
+# reassociate back to the same AP to update some association parameters.
+#
+# 0 = Do not process Known STA Identification (default)
+# 1 = Allow Known STA Identification to be used to skip SA Query procedure
+#known_sta_identification=0
+
# RSNE/RSNXE override
#
# These parameters can be used to configure RSN parameters for STAs that support
@@ -2646,7 +2686,7 @@
# message when acting as a Registrar. If skip_cred_build=1, this data will also
# be able to override the Credential attribute that would have otherwise been
# automatically generated based on network configuration. This configuration
-# option points to an external file that much contain the WPS Credential
+# option points to an external file that contains the WPS Credential
# attribute(s) as binary data.
#extra_cred=hostapd.cred
@@ -3043,9 +3083,6 @@
# forging such frames to other stations in the BSS.
#disable_dgaf=1
-# OSU Server-Only Authenticated L2 Encryption Network
-#osen=1
-
# ANQP Domain ID (0..65535)
# An identifier for a set of APs in an ESS that share the same common ANQP
# information. 0 = Some of the ANQP information is unique to this AP (default).
@@ -3126,42 +3163,6 @@
# @1@ = MAC address of the STA (colon separated hex octets)
#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123
-# OSU and Operator icons
-# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path>
-#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
-#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
-
-# OSU SSID (see ssid2 for format description)
-# This is the SSID used for all OSU connections to all the listed OSU Providers.
-#osu_ssid="example"
-
-# OSU Providers
-# One or more sets of following parameter. Each OSU provider is started by the
-# mandatory osu_server_uri item. The other parameters add information for the
-# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN
-# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI
-# value for OSEN authentication when using a shared BSS (Single SSID) for OSU.
-#
-#osu_server_uri=https://example.com/osu/
-#osu_friendly_name=eng:Example operator
-#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
-#osu_nai=anonymous@example.com
-#osu_nai2=anonymous@example.com
-#osu_method_list=1 0
-#osu_icon=icon32
-#osu_icon=icon64
-#osu_service_desc=eng:Example services
-#osu_service_desc=fin:Esimerkkipalveluja
-#
-#osu_server_uri=...
-
-# Operator Icons
-# Operator icons are specified using references to the hs20_icon entries
-# (Name subfield). This information, if present, is advertsised in the
-# Operator Icon Metadata ANQO-element.
-#operator_icon=icon32
-#operator_icon=icon64
-
##### Multiband Operation (MBO) ###############################################
#
# MBO enabled
@@ -3340,6 +3341,10 @@
# (channel switch operating class is needed)
#ecsa_ie_only=0
#
+# Include only CSA IE without ECSA IE
+# (the operating class is not mentioned)
+#csa_ie_only=0
+
# Delay EAPOL-Key messages 1/4 and 3/4 by not sending the frame until the last
# attempt (wpa_pairwise_update_count). This will trigger a timeout on all
# previous attempts and thus delays the frame. (testing only)
diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk
index bb77341..a8ff6fc 100644
--- a/hs20/client/Android.mk
+++ b/hs20/client/Android.mk
@@ -30,10 +30,7 @@
L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
-OBJS = spp_client.c
-OBJS += oma_dm_client.c
-OBJS += osu_client.c
-OBJS += est.c
+OBJS = osu_client.c
OBJS += ../../src/common/wpa_ctrl.c
OBJS += ../../src/common/wpa_helpers.c
OBJS += ../../src/utils/xml-utils.c
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index 4dcfe2d..9e65dc6 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -24,10 +24,7 @@
endif
endif
-OBJS=spp_client.o
-OBJS += oma_dm_client.o
-OBJS += osu_client.o
-OBJS += est.o
+OBJS = osu_client.o
OBJS += ../../src/utils/xml-utils.o
CFLAGS += -DCONFIG_CTRL_IFACE
CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
diff --git a/hs20/client/devdetail.xml b/hs20/client/devdetail.xml
deleted file mode 100644
index 6d0389e..0000000
--- a/hs20/client/devdetail.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<DevDetail xmlns="urn:oma:mo:oma-dm-devdetail:1.0">
- <Ext>
- <org.wi-fi>
- <Wi-Fi>
- <EAPMethodList>
- <EAPMethod1>
- <EAPType>13</EAPType>
- </EAPMethod1>
- <EAPMethod2>
- <EAPType>21</EAPType>
- <InnerMethod>MS-CHAP-V2</InnerMethod>
- </EAPMethod2>
- <EAPMethod3>
- <EAPType>18</EAPType>
- </EAPMethod3>
- <EAPMethod4>
- <EAPType>23</EAPType>
- </EAPMethod4>
- <EAPMethod5>
- <EAPType>50</EAPType>
- </EAPMethod5>
- </EAPMethodList>
- <ManufacturingCertificate>false</ManufacturingCertificate>
- <Wi-FiMACAddress>020102030405</Wi-FiMACAddress>
- <IMSI>310026000000000</IMSI>
- <IMEI_MEID>imei:490123456789012</IMEI_MEID>
- <ClientTriggerRedirectURI>http://localhost:12345/</ClientTriggerRedirectURI>
- <Ops>
- <launchBrowserToURI></launchBrowserToURI>
- <negotiateClientCertTLS></negotiateClientCertTLS>
- <getCertificate></getCertificate>
- </Ops>
- </Wi-Fi>
- </org.wi-fi>
- </Ext>
- <URI>
- <MaxDepth>0</MaxDepth>
- <MaxTotLen>0</MaxTotLen>
- <MaxSegLen>0</MaxSegLen>
- </URI>
- <DevType>MobilePhone</DevType>
- <OEM>Manufacturer</OEM>
- <FwV>1.0</FwV>
- <SwV>1.0</SwV>
- <HwV>1.0</HwV>
- <LrgObj>false</LrgObj>
-</DevDetail>
diff --git a/hs20/client/devinfo.xml b/hs20/client/devinfo.xml
deleted file mode 100644
index d48a520..0000000
--- a/hs20/client/devinfo.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<DevInfo xmlns="urn:oma:mo:oma-dm-devinfo:1.0">
- <DevId>urn:Example:HS20-station:123456</DevId>
- <Man>Manufacturer</Man>
- <Mod>HS20-station</Mod>
- <DmV>1.2</DmV>
- <Lang>en</Lang>
-</DevInfo>
diff --git a/hs20/client/est.c b/hs20/client/est.c
deleted file mode 100644
index 425b72d..0000000
--- a/hs20/client/est.c
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * Hotspot 2.0 OSU client - EST client
- * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/pkcs7.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/opensslv.h>
-#include <openssl/buffer.h>
-
-#include "common.h"
-#include "utils/base64.h"
-#include "utils/xml-utils.h"
-#include "utils/http-utils.h"
-#include "osu_client.h"
-
-
-static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
- size_t len, char *pem_file, char *der_file)
-{
-#ifdef OPENSSL_IS_BORINGSSL
- CBS pkcs7_cbs;
-#else /* OPENSSL_IS_BORINGSSL */
- PKCS7 *p7 = NULL;
- const unsigned char *p = pkcs7;
-#endif /* OPENSSL_IS_BORINGSSL */
- STACK_OF(X509) *certs;
- int i, num, ret = -1;
- BIO *out = NULL;
-
-#ifdef OPENSSL_IS_BORINGSSL
- certs = sk_X509_new_null();
- if (!certs)
- goto fail;
- CBS_init(&pkcs7_cbs, pkcs7, len);
- if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
- wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
- ERR_error_string(ERR_get_error(), NULL));
- write_result(ctx, "Could not parse PKCS#7 object from EST");
- goto fail;
- }
-#else /* OPENSSL_IS_BORINGSSL */
- p7 = d2i_PKCS7(NULL, &p, len);
- if (p7 == NULL) {
- wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
- ERR_error_string(ERR_get_error(), NULL));
- write_result(ctx, "Could not parse PKCS#7 object from EST");
- goto fail;
- }
-
- switch (OBJ_obj2nid(p7->type)) {
- case NID_pkcs7_signed:
- certs = p7->d.sign->cert;
- break;
- case NID_pkcs7_signedAndEnveloped:
- certs = p7->d.signed_and_enveloped->cert;
- break;
- default:
- certs = NULL;
- break;
- }
-#endif /* OPENSSL_IS_BORINGSSL */
-
- if (!certs || ((num = sk_X509_num(certs)) == 0)) {
- wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
- write_result(ctx, "No certificates found in PKCS#7 object");
- goto fail;
- }
-
- if (der_file) {
- FILE *f = fopen(der_file, "wb");
- if (f == NULL)
- goto fail;
- i2d_X509_fp(f, sk_X509_value(certs, 0));
- fclose(f);
- }
-
- if (pem_file) {
- out = BIO_new(BIO_s_file());
- if (out == NULL ||
- BIO_write_filename(out, pem_file) <= 0)
- goto fail;
-
- for (i = 0; i < num; i++) {
- X509 *cert = sk_X509_value(certs, i);
- X509_print(out, cert);
- PEM_write_bio_X509(out, cert);
- BIO_puts(out, "\n");
- }
- }
-
- ret = 0;
-
-fail:
-#ifdef OPENSSL_IS_BORINGSSL
- if (certs)
- sk_X509_pop_free(certs, X509_free);
-#else /* OPENSSL_IS_BORINGSSL */
- PKCS7_free(p7);
-#endif /* OPENSSL_IS_BORINGSSL */
- if (out)
- BIO_free_all(out);
-
- return ret;
-}
-
-
-int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
-{
- char *buf, *resp;
- size_t buflen;
- unsigned char *pkcs7;
- size_t pkcs7_len, resp_len;
- int res;
-
- buflen = os_strlen(url) + 100;
- buf = os_malloc(buflen);
- if (buf == NULL)
- return -1;
-
- os_snprintf(buf, buflen, "%s/cacerts", url);
- wpa_printf(MSG_INFO, "Download EST cacerts from %s", buf);
- write_summary(ctx, "Download EST cacerts from %s", buf);
- ctx->no_osu_cert_validation = 1;
- http_ocsp_set(ctx->http, 1);
- res = http_download_file(ctx->http, buf, "Cert/est-cacerts.txt",
- ctx->ca_fname);
- http_ocsp_set(ctx->http,
- (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
- ctx->no_osu_cert_validation = 0;
- if (res < 0) {
- wpa_printf(MSG_INFO, "Failed to download EST cacerts from %s",
- buf);
- write_result(ctx, "Failed to download EST cacerts from %s",
- buf);
- os_free(buf);
- return -1;
- }
- os_free(buf);
-
- resp = os_readfile("Cert/est-cacerts.txt", &resp_len);
- if (resp == NULL) {
- wpa_printf(MSG_INFO, "Could not read Cert/est-cacerts.txt");
- write_result(ctx, "Could not read EST cacerts");
- return -1;
- }
-
- pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
- if (pkcs7 && pkcs7_len < resp_len / 2) {
- wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
- (unsigned int) pkcs7_len, (unsigned int) resp_len);
- os_free(pkcs7);
- pkcs7 = NULL;
- }
- if (pkcs7 == NULL) {
- wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
- pkcs7 = os_malloc(resp_len);
- if (pkcs7) {
- os_memcpy(pkcs7, resp, resp_len);
- pkcs7_len = resp_len;
- }
- }
- os_free(resp);
-
- if (pkcs7 == NULL) {
- wpa_printf(MSG_INFO, "Could not fetch PKCS7 cacerts");
- write_result(ctx, "Could not fetch EST PKCS#7 cacerts");
- return -1;
- }
-
- res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est-cacerts.pem",
- NULL);
- os_free(pkcs7);
- if (res < 0) {
- wpa_printf(MSG_INFO, "Could not parse CA certs from PKCS#7 cacerts response");
- write_result(ctx, "Could not parse CA certs from EST PKCS#7 cacerts response");
- return -1;
- }
- unlink("Cert/est-cacerts.txt");
-
- return 0;
-}
-
-
-/*
- * CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID
- *
- * AttrOrOID ::= CHOICE {
- * oid OBJECT IDENTIFIER,
- * attribute Attribute }
- *
- * Attribute ::= SEQUENCE {
- * type OBJECT IDENTIFIER,
- * values SET SIZE(1..MAX) OF OBJECT IDENTIFIER }
- */
-
-typedef struct {
- ASN1_OBJECT *type;
- STACK_OF(ASN1_OBJECT) *values;
-} Attribute;
-
-typedef struct {
- int type;
- union {
- ASN1_OBJECT *oid;
- Attribute *attribute;
- } d;
-} AttrOrOID;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-DEFINE_STACK_OF(AttrOrOID)
-#endif
-
-typedef struct {
- int type;
- STACK_OF(AttrOrOID) *attrs;
-} CsrAttrs;
-
-ASN1_SEQUENCE(Attribute) = {
- ASN1_SIMPLE(Attribute, type, ASN1_OBJECT),
- ASN1_SET_OF(Attribute, values, ASN1_OBJECT)
-} ASN1_SEQUENCE_END(Attribute);
-
-ASN1_CHOICE(AttrOrOID) = {
- ASN1_SIMPLE(AttrOrOID, d.oid, ASN1_OBJECT),
- ASN1_SIMPLE(AttrOrOID, d.attribute, Attribute)
-} ASN1_CHOICE_END(AttrOrOID);
-
-ASN1_CHOICE(CsrAttrs) = {
- ASN1_SEQUENCE_OF(CsrAttrs, attrs, AttrOrOID)
-} ASN1_CHOICE_END(CsrAttrs);
-
-IMPLEMENT_ASN1_FUNCTIONS(CsrAttrs);
-
-
-static void add_csrattrs_oid(struct hs20_osu_client *ctx, ASN1_OBJECT *oid,
- STACK_OF(X509_EXTENSION) *exts)
-{
- char txt[100];
- int res;
-
- if (!oid)
- return;
-
- res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
- if (res < 0 || res >= (int) sizeof(txt))
- return;
-
- if (os_strcmp(txt, "1.2.840.113549.1.9.7") == 0) {
- wpa_printf(MSG_INFO, "TODO: csrattr challengePassword");
- } else if (os_strcmp(txt, "1.2.840.113549.1.1.11") == 0) {
- wpa_printf(MSG_INFO, "csrattr sha256WithRSAEncryption");
- } else {
- wpa_printf(MSG_INFO, "Ignore unsupported csrattr oid %s", txt);
- }
-}
-
-
-static void add_csrattrs_ext_req(struct hs20_osu_client *ctx,
- STACK_OF(ASN1_OBJECT) *values,
- STACK_OF(X509_EXTENSION) *exts)
-{
- char txt[100];
- int i, num, res;
-
- num = sk_ASN1_OBJECT_num(values);
- for (i = 0; i < num; i++) {
- ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(values, i);
-
- res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
- if (res < 0 || res >= (int) sizeof(txt))
- continue;
-
- if (os_strcmp(txt, "1.3.6.1.1.1.1.22") == 0) {
- wpa_printf(MSG_INFO, "TODO: extReq macAddress");
- } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.3") == 0) {
- wpa_printf(MSG_INFO, "TODO: extReq imei");
- } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.4") == 0) {
- wpa_printf(MSG_INFO, "TODO: extReq meid");
- } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.5") == 0) {
- wpa_printf(MSG_INFO, "TODO: extReq DevId");
- } else {
- wpa_printf(MSG_INFO, "Ignore unsupported cstattr extensionsRequest %s",
- txt);
- }
- }
-}
-
-
-static void add_csrattrs_attr(struct hs20_osu_client *ctx, Attribute *attr,
- STACK_OF(X509_EXTENSION) *exts)
-{
- char txt[100], txt2[100];
- int i, num, res;
-
- if (!attr || !attr->type || !attr->values)
- return;
-
- res = OBJ_obj2txt(txt, sizeof(txt), attr->type, 1);
- if (res < 0 || res >= (int) sizeof(txt))
- return;
-
- if (os_strcmp(txt, "1.2.840.113549.1.9.14") == 0) {
- add_csrattrs_ext_req(ctx, attr->values, exts);
- return;
- }
-
- num = sk_ASN1_OBJECT_num(attr->values);
- for (i = 0; i < num; i++) {
- ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(attr->values, i);
-
- res = OBJ_obj2txt(txt2, sizeof(txt2), oid, 1);
- if (res < 0 || res >= (int) sizeof(txt2))
- continue;
-
- wpa_printf(MSG_INFO, "Ignore unsupported cstattr::attr %s oid %s",
- txt, txt2);
- }
-}
-
-
-static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
- STACK_OF(X509_EXTENSION) *exts)
-{
- int i, num;
-
- if (!csrattrs || ! csrattrs->attrs)
- return;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- num = sk_AttrOrOID_num(csrattrs->attrs);
-#else
- num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
-#endif
- for (i = 0; i < num; i++) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
-#else
- AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
-#endif
- switch (ao->type) {
- case 0:
- add_csrattrs_oid(ctx, ao->d.oid, exts);
- break;
- case 1:
- add_csrattrs_attr(ctx, ao->d.attribute, exts);
- break;
- }
- }
-}
-
-
-static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
- char *csr_pem, char *est_req, char *old_cert,
- CsrAttrs *csrattrs)
-{
- EVP_PKEY_CTX *pctx = NULL;
- EVP_PKEY *pkey = NULL;
- X509_REQ *req = NULL;
- int ret = -1;
- unsigned int val;
- X509_NAME *subj = NULL;
- char name[100];
- STACK_OF(X509_EXTENSION) *exts = NULL;
- X509_EXTENSION *ex;
- BIO *out;
- CONF *ctmp = NULL;
-
- wpa_printf(MSG_INFO, "Generate RSA private key");
- write_summary(ctx, "Generate RSA private key");
- pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
- if (!pctx)
- return -1;
-
- if (EVP_PKEY_keygen_init(pctx) <= 0)
- goto fail;
-
- if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0)
- goto fail;
-
- if (EVP_PKEY_keygen(pctx, &pkey) <= 0)
- goto fail;
- EVP_PKEY_CTX_free(pctx);
- pctx = NULL;
-
- if (key_pem) {
- FILE *f = fopen(key_pem, "wb");
- if (f == NULL)
- goto fail;
- if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
- wpa_printf(MSG_INFO, "Could not write private key: %s",
- ERR_error_string(ERR_get_error(), NULL));
- fclose(f);
- goto fail;
- }
- fclose(f);
- }
-
- wpa_printf(MSG_INFO, "Generate CSR");
- write_summary(ctx, "Generate CSR");
- req = X509_REQ_new();
- if (req == NULL)
- goto fail;
-
- if (old_cert) {
- FILE *f;
- X509 *cert;
- int res;
-
- f = fopen(old_cert, "r");
- if (f == NULL)
- goto fail;
- cert = PEM_read_X509(f, NULL, NULL, NULL);
- fclose(f);
-
- if (cert == NULL)
- goto fail;
- res = X509_REQ_set_subject_name(req,
- X509_get_subject_name(cert));
- X509_free(cert);
- if (!res)
- goto fail;
- } else {
- os_get_random((u8 *) &val, sizeof(val));
- os_snprintf(name, sizeof(name), "cert-user-%u", val);
- subj = X509_NAME_new();
- if (subj == NULL ||
- !X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC,
- (unsigned char *) name,
- -1, -1, 0) ||
- !X509_REQ_set_subject_name(req, subj))
- goto fail;
- X509_NAME_free(subj);
- subj = NULL;
- }
-
- if (!X509_REQ_set_pubkey(req, pkey))
- goto fail;
-
- exts = sk_X509_EXTENSION_new_null();
- if (!exts)
- goto fail;
-
- ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints,
- "CA:FALSE");
- if (ex == NULL ||
- !sk_X509_EXTENSION_push(exts, ex))
- goto fail;
-
- ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage,
- "nonRepudiation,digitalSignature,keyEncipherment");
- if (ex == NULL ||
- !sk_X509_EXTENSION_push(exts, ex))
- goto fail;
-
- ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage,
- "1.3.6.1.4.1.40808.1.1.2");
- if (ex == NULL ||
- !sk_X509_EXTENSION_push(exts, ex))
- goto fail;
-
- add_csrattrs(ctx, csrattrs, exts);
-
- if (!X509_REQ_add_extensions(req, exts))
- goto fail;
- sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
- exts = NULL;
-
- if (!X509_REQ_sign(req, pkey, EVP_sha256()))
- goto fail;
-
- out = BIO_new(BIO_s_mem());
- if (out) {
- char *txt;
- size_t rlen;
-
-#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
- X509_REQ_print(out, req);
-#endif
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (txt) {
- int res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_MSGDUMP, "OpenSSL: Certificate request:\n%s",
- txt);
- }
- os_free(txt);
- }
- BIO_free(out);
- }
-
- if (csr_pem) {
- FILE *f = fopen(csr_pem, "w");
- if (f == NULL)
- goto fail;
-#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
- X509_REQ_print_fp(f, req);
-#endif
- if (!PEM_write_X509_REQ(f, req)) {
- fclose(f);
- goto fail;
- }
- fclose(f);
- }
-
- if (est_req) {
- BIO *mem = BIO_new(BIO_s_mem());
- BUF_MEM *ptr;
- char *pos, *end, *buf_end;
- FILE *f;
-
- if (mem == NULL)
- goto fail;
- if (!PEM_write_bio_X509_REQ(mem, req)) {
- BIO_free(mem);
- goto fail;
- }
-
- BIO_get_mem_ptr(mem, &ptr);
- pos = ptr->data;
- buf_end = pos + ptr->length;
-
- /* Remove START/END lines */
- while (pos < buf_end && *pos != '\n')
- pos++;
- if (pos == buf_end) {
- BIO_free(mem);
- goto fail;
- }
- pos++;
-
- end = pos;
- while (end < buf_end && *end != '-')
- end++;
-
- f = fopen(est_req, "w");
- if (f == NULL) {
- BIO_free(mem);
- goto fail;
- }
- fwrite(pos, end - pos, 1, f);
- fclose(f);
-
- BIO_free(mem);
- }
-
- ret = 0;
-fail:
- if (exts)
- sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
- if (subj)
- X509_NAME_free(subj);
- if (req)
- X509_REQ_free(req);
- if (pkey)
- EVP_PKEY_free(pkey);
- if (pctx)
- EVP_PKEY_CTX_free(pctx);
- return ret;
-}
-
-
-int est_build_csr(struct hs20_osu_client *ctx, const char *url)
-{
- char *buf;
- size_t buflen;
- int res;
- char old_cert_buf[200];
- char *old_cert = NULL;
- CsrAttrs *csrattrs = NULL;
-
- buflen = os_strlen(url) + 100;
- buf = os_malloc(buflen);
- if (buf == NULL)
- return -1;
-
- os_snprintf(buf, buflen, "%s/csrattrs", url);
- wpa_printf(MSG_INFO, "Download csrattrs from %s", buf);
- write_summary(ctx, "Download EST csrattrs from %s", buf);
- ctx->no_osu_cert_validation = 1;
- http_ocsp_set(ctx->http, 1);
- res = http_download_file(ctx->http, buf, "Cert/est-csrattrs.txt",
- ctx->ca_fname);
- http_ocsp_set(ctx->http,
- (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
- ctx->no_osu_cert_validation = 0;
- os_free(buf);
- if (res < 0) {
- wpa_printf(MSG_INFO, "Failed to download EST csrattrs - assume no extra attributes are needed");
- } else {
- size_t resp_len;
- char *resp;
- unsigned char *attrs;
- const unsigned char *pos;
- size_t attrs_len;
-
- resp = os_readfile("Cert/est-csrattrs.txt", &resp_len);
- if (resp == NULL) {
- wpa_printf(MSG_INFO, "Could not read csrattrs");
- return -1;
- }
-
- attrs = base64_decode(resp, resp_len, &attrs_len);
- os_free(resp);
-
- if (attrs == NULL) {
- wpa_printf(MSG_INFO, "Could not base64 decode csrattrs");
- return -1;
- }
- unlink("Cert/est-csrattrs.txt");
-
- pos = attrs;
- csrattrs = d2i_CsrAttrs(NULL, &pos, attrs_len);
- os_free(attrs);
- if (csrattrs == NULL) {
- wpa_printf(MSG_INFO, "Failed to parse csrattrs ASN.1");
- /* Continue assuming no additional requirements */
- }
- }
-
- if (ctx->client_cert_present) {
- os_snprintf(old_cert_buf, sizeof(old_cert_buf),
- "SP/%s/client-cert.pem", ctx->fqdn);
- old_cert = old_cert_buf;
- }
-
- res = generate_csr(ctx, "Cert/privkey-plain.pem", "Cert/est-req.pem",
- "Cert/est-req.b64", old_cert, csrattrs);
- if (csrattrs)
- CsrAttrs_free(csrattrs);
-
- return res;
-}
-
-
-int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
- const char *user, const char *pw)
-{
- char *buf, *resp, *req, *req2;
- size_t buflen, resp_len, len, pkcs7_len;
- unsigned char *pkcs7;
- char client_cert_buf[200];
- char client_key_buf[200];
- const char *client_cert = NULL, *client_key = NULL;
- int res;
-
- req = os_readfile("Cert/est-req.b64", &len);
- if (req == NULL) {
- wpa_printf(MSG_INFO, "Could not read Cert/req.b64");
- return -1;
- }
- req2 = os_realloc(req, len + 1);
- if (req2 == NULL) {
- os_free(req);
- return -1;
- }
- req2[len] = '\0';
- req = req2;
- wpa_printf(MSG_DEBUG, "EST simpleenroll request: %s", req);
-
- buflen = os_strlen(url) + 100;
- buf = os_malloc(buflen);
- if (buf == NULL) {
- os_free(req);
- return -1;
- }
-
- if (ctx->client_cert_present) {
- os_snprintf(buf, buflen, "%s/simplereenroll", url);
- os_snprintf(client_cert_buf, sizeof(client_cert_buf),
- "SP/%s/client-cert.pem", ctx->fqdn);
- client_cert = client_cert_buf;
- os_snprintf(client_key_buf, sizeof(client_key_buf),
- "SP/%s/client-key.pem", ctx->fqdn);
- client_key = client_key_buf;
- } else
- os_snprintf(buf, buflen, "%s/simpleenroll", url);
- wpa_printf(MSG_INFO, "EST simpleenroll URL: %s", buf);
- write_summary(ctx, "EST simpleenroll URL: %s", buf);
- ctx->no_osu_cert_validation = 1;
- http_ocsp_set(ctx->http, 1);
- resp = http_post(ctx->http, buf, req, "application/pkcs10",
- "Content-Transfer-Encoding: base64",
- ctx->ca_fname, user, pw, client_cert, client_key,
- &resp_len);
- http_ocsp_set(ctx->http,
- (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
- ctx->no_osu_cert_validation = 0;
- os_free(buf);
- if (resp == NULL) {
- wpa_printf(MSG_INFO, "EST certificate enrollment failed");
- write_result(ctx, "EST certificate enrollment failed");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
-
- pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
- if (pkcs7 == NULL) {
- wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
- pkcs7 = os_malloc(resp_len);
- if (pkcs7) {
- os_memcpy(pkcs7, resp, resp_len);
- pkcs7_len = resp_len;
- }
- }
- os_free(resp);
-
- if (pkcs7 == NULL) {
- wpa_printf(MSG_INFO, "Failed to parse simpleenroll base64 response");
- write_result(ctx, "Failed to parse EST simpleenroll base64 response");
- return -1;
- }
-
- res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est_cert.pem",
- "Cert/est_cert.der");
- os_free(pkcs7);
-
- if (res < 0) {
- wpa_printf(MSG_INFO, "EST: Failed to extract certificate from PKCS7 file");
- write_result(ctx, "EST: Failed to extract certificate from EST PKCS7 file");
- return -1;
- }
-
- wpa_printf(MSG_INFO, "EST simple%senroll completed successfully",
- ctx->client_cert_present ? "re" : "");
- write_summary(ctx, "EST simple%senroll completed successfully",
- ctx->client_cert_present ? "re" : "");
-
- return 0;
-}
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
deleted file mode 100644
index bcd68b8..0000000
--- a/hs20/client/oma_dm_client.c
+++ /dev/null
@@ -1,1398 +0,0 @@
-/*
- * Hotspot 2.0 - OMA DM client
- * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa_helpers.h"
-#include "xml-utils.h"
-#include "http-utils.h"
-#include "utils/browser.h"
-#include "osu_client.h"
-
-
-#define DM_SERVER_INITIATED_MGMT 1200
-#define DM_CLIENT_INITIATED_MGMT 1201
-#define DM_GENERIC_ALERT 1226
-
-/* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */
-#define DM_RESP_OK 200
-#define DM_RESP_AUTH_ACCEPTED 212
-#define DM_RESP_CHUNKED_ITEM_ACCEPTED 213
-#define DM_RESP_NOT_EXECUTED 215
-#define DM_RESP_ATOMIC_ROLL_BACK_OK 216
-#define DM_RESP_NOT_MODIFIED 304
-#define DM_RESP_BAD_REQUEST 400
-#define DM_RESP_UNAUTHORIZED 401
-#define DM_RESP_FORBIDDEN 403
-#define DM_RESP_NOT_FOUND 404
-#define DM_RESP_COMMAND_NOT_ALLOWED 405
-#define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406
-#define DM_RESP_MISSING_CREDENTIALS 407
-#define DM_RESP_CONFLICT 409
-#define DM_RESP_GONE 410
-#define DM_RESP_INCOMPLETE_COMMAND 412
-#define DM_RESP_REQ_ENTITY_TOO_LARGE 413
-#define DM_RESP_URI_TOO_LONG 414
-#define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415
-#define DM_RESP_REQ_TOO_BIG 416
-#define DM_RESP_ALREADY_EXISTS 418
-#define DM_RESP_DEVICE_FULL 420
-#define DM_RESP_SIZE_MISMATCH 424
-#define DM_RESP_PERMISSION_DENIED 425
-#define DM_RESP_COMMAND_FAILED 500
-#define DM_RESP_COMMAND_NOT_IMPLEMENTED 501
-#define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516
-
-#define DM_HS20_SUBSCRIPTION_CREATION \
- "org.wi-fi.hotspot2dot0.SubscriptionCreation"
-#define DM_HS20_SUBSCRIPTION_PROVISIONING \
- "org.wi-fi.hotspot2dot0.SubscriptionProvisioning"
-#define DM_HS20_SUBSCRIPTION_REMEDIATION \
- "org.wi-fi.hotspot2dot0.SubscriptionRemediation"
-#define DM_HS20_POLICY_UPDATE \
- "org.wi-fi.hotspot2dot0.PolicyUpdate"
-
-#define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription"
-#define DM_URI_LAUNCH_BROWSER \
- "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI"
-
-
-static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
- const char *locuri, const char *data);
-
-
-static const char * int2str(int val)
-{
- static char buf[20];
- snprintf(buf, sizeof(buf), "%d", val);
- return buf;
-}
-
-
-static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx,
- xml_node_t *node)
-{
- xml_node_t *locuri;
- char *uri, *ret = NULL;
-
- locuri = get_node(ctx->xml, node, "Item/Target/LocURI");
- if (locuri == NULL)
- return NULL;
-
- uri = xml_node_get_text(ctx->xml, locuri);
- if (uri)
- ret = os_strdup(uri);
- xml_node_get_text_free(ctx->xml, uri);
- return ret;
-}
-
-
-static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent,
- const char *element, const char *uri)
-{
- xml_node_t *node;
-
- node = xml_node_create(ctx->xml, parent, NULL, element);
- if (node == NULL)
- return;
- xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri);
-}
-
-
-static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
- const char *url, int msgid)
-{
- xml_node_t *syncml, *synchdr;
- xml_namespace_t *ns;
-
- if (!ctx->devid) {
- wpa_printf(MSG_ERROR,
- "DevId from devinfo.xml is not available - cannot use OMA DM");
- return NULL;
- }
-
- syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
- "SyncML");
-
- synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr");
- xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2");
- xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2");
- xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1");
- xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid));
-
- oma_dm_add_locuri(ctx, synchdr, "Target", url);
- oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid);
-
- return syncml;
-}
-
-
-static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent,
- int cmdid)
-{
- xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid));
-}
-
-
-static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent,
- int cmdid, int data)
-{
- xml_node_t *node;
-
- node = xml_node_create(ctx->xml, parent, NULL, "Alert");
- if (node == NULL)
- return NULL;
- oma_dm_add_cmdid(ctx, node, cmdid);
- xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
-
- return node;
-}
-
-
-static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent,
- int msgref, int cmdref, int cmdid,
- const char *cmd, int data, const char *targetref)
-{
- xml_node_t *node;
-
- node = xml_node_create(ctx->xml, parent, NULL, "Status");
- if (node == NULL)
- return NULL;
- oma_dm_add_cmdid(ctx, node, cmdid);
- xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
- if (cmdref)
- xml_node_create_text(ctx->xml, node, NULL, "CmdRef",
- int2str(cmdref));
- xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd);
- xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
- if (targetref) {
- xml_node_create_text(ctx->xml, node, NULL, "TargetRef",
- targetref);
- }
-
- return node;
-}
-
-
-static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent,
- int msgref, int cmdref, int cmdid,
- const char *locuri, const char *data)
-{
- xml_node_t *node;
-
- node = xml_node_create(ctx->xml, parent, NULL, "Results");
- if (node == NULL)
- return NULL;
-
- oma_dm_add_cmdid(ctx, node, cmdid);
- xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
- xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref));
- add_item(ctx, node, locuri, data);
-
- return node;
-}
-
-
-static char * mo_str(struct hs20_osu_client *ctx, const char *urn,
- const char *fname)
-{
- xml_node_t *fnode, *tnds;
- char *str;
-
- fnode = node_from_file(ctx->xml, fname);
- if (!fnode)
- return NULL;
- tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2");
- xml_node_free(ctx->xml, fnode);
- if (!tnds)
- return NULL;
-
- str = xml_node_to_str(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (str == NULL)
- return NULL;
- wpa_printf(MSG_INFO, "MgmtTree: %s", str);
-
- return str;
-}
-
-
-static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
- const char *locuri, const char *data)
-{
- xml_node_t *item, *node;
-
- item = xml_node_create(ctx->xml, parent, NULL, "Item");
- oma_dm_add_locuri(ctx, item, "Source", locuri);
- node = xml_node_create(ctx->xml, item, NULL, "Meta");
- xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
- "Chr");
- xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type",
- "text/plain");
- xml_node_create_text(ctx->xml, item, NULL, "Data", data);
-}
-
-
-static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent,
- int cmdid)
-{
- xml_node_t *info, *child, *replace;
- const char *name;
- char locuri[200], *txt;
-
- info = node_from_file(ctx->xml, "devinfo.xml");
- if (info == NULL) {
- wpa_printf(MSG_INFO, "Could not read devinfo.xml");
- return;
- }
-
- replace = xml_node_create(ctx->xml, parent, NULL, "Replace");
- if (replace == NULL) {
- xml_node_free(ctx->xml, info);
- return;
- }
- oma_dm_add_cmdid(ctx, replace, cmdid);
-
- xml_node_for_each_child(ctx->xml, child, info) {
- xml_node_for_each_check(ctx->xml, child);
- name = xml_node_get_localname(ctx->xml, child);
- os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name);
- txt = xml_node_get_text(ctx->xml, child);
- if (txt) {
- add_item(ctx, replace, locuri, txt);
- xml_node_get_text_free(ctx->xml, txt);
- }
- }
-
- xml_node_free(ctx->xml, info);
-}
-
-
-static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx,
- xml_node_t *syncbody,
- int cmdid, const char *oper,
- const char *data)
-{
- xml_node_t *node, *item;
- char buf[200];
-
- node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT);
-
- item = xml_node_create(ctx->xml, node, NULL, "Item");
- oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS);
- node = xml_node_create(ctx->xml, item, NULL, "Meta");
- snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper);
- xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf);
- xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
- "xml");
- xml_node_create_text(ctx->xml, item, NULL, "Data", data);
-}
-
-
-static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx,
- const char *url, int msgid, const char *oper)
-{
- xml_node_t *syncml, *syncbody;
- char *str;
- int cmdid = 0;
-
- syncml = oma_dm_build_hdr(ctx, url, msgid);
- if (syncml == NULL)
- return NULL;
-
- syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
- if (syncbody == NULL) {
- xml_node_free(ctx->xml, syncml);
- return NULL;
- }
-
- cmdid++;
- add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT);
-
- str = mo_str(ctx, NULL, "devdetail.xml");
- if (str == NULL) {
- xml_node_free(ctx->xml, syncml);
- return NULL;
- }
- cmdid++;
- oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str);
- os_free(str);
-
- cmdid++;
- add_replace_devinfo(ctx, syncbody, cmdid);
-
- xml_node_create(ctx->xml, syncbody, NULL, "Final");
-
- return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx,
- const char *url, int msgid)
-{
- xml_node_t *syncml;
-
- syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION);
- if (syncml)
- debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml);
-
- return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx,
- const char *url, int msgid)
-{
- xml_node_t *syncml;
-
- syncml = build_oma_dm_1(ctx, url, msgid,
- DM_HS20_SUBSCRIPTION_PROVISIONING);
- if (syncml)
- debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml);
-
- return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx,
- const char *url, int msgid)
-{
- xml_node_t *syncml;
-
- syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE);
- if (syncml)
- debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml);
-
- return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx,
- const char *url, int msgid)
-{
- xml_node_t *syncml;
-
- syncml = build_oma_dm_1(ctx, url, msgid,
- DM_HS20_SUBSCRIPTION_REMEDIATION);
- if (syncml)
- debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml);
-
- return syncml;
-}
-
-
-static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
-{
- xml_node_t *node;
- char *data;
- int res;
-
- node = get_node(ctx->xml, exec, "Item/Data");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No Data node found");
- return DM_RESP_BAD_REQUEST;
- }
-
- data = xml_node_get_text(ctx->xml, node);
- if (data == NULL) {
- wpa_printf(MSG_INFO, "Invalid data");
- return DM_RESP_BAD_REQUEST;
- }
- wpa_printf(MSG_INFO, "Data: %s", data);
- wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
- write_summary(ctx, "Launch browser to URI '%s'", data);
- res = hs20_web_browser(data, 1);
- xml_node_get_text_free(ctx->xml, data);
- if (res > 0) {
- wpa_printf(MSG_INFO, "User response in browser completed successfully");
- write_summary(ctx, "User response in browser completed successfully");
- return DM_RESP_OK;
- } else {
- wpa_printf(MSG_INFO, "Failed to receive user response");
- write_summary(ctx, "Failed to receive user response");
- return DM_RESP_COMMAND_FAILED;
- }
-}
-
-
-static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec)
-{
- xml_node_t *node, *getcert;
- char *data;
- const char *name;
- int res;
-
- wpa_printf(MSG_INFO, "Client certificate enrollment");
- write_summary(ctx, "Client certificate enrollment");
-
- node = get_node(ctx->xml, exec, "Item/Data");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No Data node found");
- return DM_RESP_BAD_REQUEST;
- }
-
- data = xml_node_get_text(ctx->xml, node);
- if (data == NULL) {
- wpa_printf(MSG_INFO, "Invalid data");
- return DM_RESP_BAD_REQUEST;
- }
- wpa_printf(MSG_INFO, "Data: %s", data);
- getcert = xml_node_from_buf(ctx->xml, data);
- xml_node_get_text_free(ctx->xml, data);
-
- if (getcert == NULL) {
- wpa_printf(MSG_INFO, "Could not parse Item/Data node contents");
- return DM_RESP_BAD_REQUEST;
- }
-
- debug_dump_node(ctx, "OMA-DM getCertificate", getcert);
-
- name = xml_node_get_localname(ctx->xml, getcert);
- if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) {
- wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'",
- name);
- return DM_RESP_BAD_REQUEST;
- }
-
- res = osu_get_certificate(ctx, getcert);
-
- xml_node_free(ctx->xml, getcert);
-
- return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED;
-}
-
-
-static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec)
-{
- char *locuri;
- int ret;
-
- locuri = oma_dm_get_target_locuri(ctx, exec);
- if (locuri == NULL) {
- wpa_printf(MSG_INFO, "No Target LocURI node found");
- return DM_RESP_BAD_REQUEST;
- }
-
- wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
-
- if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
- "launchBrowserToURI") == 0) {
- ret = oma_dm_exec_browser(ctx, exec);
- } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
- "getCertificate") == 0) {
- ret = oma_dm_exec_get_cert(ctx, exec);
- } else {
- wpa_printf(MSG_INFO, "Unsupported exec Target LocURI");
- ret = DM_RESP_NOT_FOUND;
- }
- os_free(locuri);
-
- return ret;
-}
-
-
-static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri,
- xml_node_t *add, xml_node_t *pps,
- const char *pps_fname)
-{
- const char *pos;
- size_t fqdn_len;
- xml_node_t *node, *tnds, *unode, *pps_node;
- char *data, *uri, *upos, *end;
- int use_tnds = 0;
- size_t uri_len;
-
- wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri);
-
- if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
- wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi");
- return DM_RESP_PERMISSION_DENIED;
- }
- pos = locuri + 8;
-
- if (ctx->fqdn == NULL)
- return DM_RESP_COMMAND_FAILED;
- fqdn_len = os_strlen(ctx->fqdn);
- if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
- pos[fqdn_len] != '/') {
- wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s",
- ctx->fqdn);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos += fqdn_len + 1;
-
- if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
- wpa_printf(MSG_INFO,
- "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription",
- ctx->fqdn);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos += 24;
-
- wpa_printf(MSG_INFO, "Add command for PPS node %s", pos);
-
- pps_node = get_node(ctx->xml, pps, pos);
- if (pps_node) {
- wpa_printf(MSG_INFO, "Specified PPS node exists already");
- return DM_RESP_ALREADY_EXISTS;
- }
-
- uri = os_strdup(pos);
- if (uri == NULL)
- return DM_RESP_COMMAND_FAILED;
- while (!pps_node) {
- upos = os_strrchr(uri, '/');
- if (!upos)
- break;
- upos[0] = '\0';
- pps_node = get_node(ctx->xml, pps, uri);
- wpa_printf(MSG_INFO, "Node %s %s", uri,
- pps_node ? "exists" : "does not exist");
- }
-
- wpa_printf(MSG_INFO, "Parent URI: %s", uri);
-
- if (!pps_node) {
- /* Add at root of PPS MO */
- pps_node = pps;
- }
-
- uri_len = os_strlen(uri);
- os_strlcpy(uri, pos + uri_len, os_strlen(pos));
- upos = uri;
- while (*upos == '/')
- upos++;
- wpa_printf(MSG_INFO, "Nodes to add: %s", upos);
-
- for (;;) {
- end = os_strchr(upos, '/');
- if (!end)
- break;
- *end = '\0';
- wpa_printf(MSG_INFO, "Adding interim node %s", upos);
- pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos);
- if (pps_node == NULL) {
- os_free(uri);
- return DM_RESP_COMMAND_FAILED;
- }
- upos = end + 1;
- }
-
- wpa_printf(MSG_INFO, "Adding node %s", upos);
-
- node = get_node(ctx->xml, add, "Item/Meta/Type");
- if (node) {
- char *type;
- type = xml_node_get_text(ctx->xml, node);
- if (type == NULL) {
- wpa_printf(MSG_ERROR, "Could not find type text");
- os_free(uri);
- return DM_RESP_BAD_REQUEST;
- }
- use_tnds = node &&
- os_strstr(type, "application/vnd.syncml.dmtnds+xml");
- }
-
- node = get_node(ctx->xml, add, "Item/Data");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No Add/Item/Data found");
- os_free(uri);
- return DM_RESP_BAD_REQUEST;
- }
-
- data = xml_node_get_text(ctx->xml, node);
- if (data == NULL) {
- wpa_printf(MSG_INFO, "Could not get Add/Item/Data text");
- os_free(uri);
- return DM_RESP_BAD_REQUEST;
- }
-
- wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data);
-
- if (use_tnds) {
- tnds = xml_node_from_buf(ctx->xml, data);
- xml_node_get_text_free(ctx->xml, data);
- if (tnds == NULL) {
- wpa_printf(MSG_INFO,
- "Could not parse Add/Item/Data text");
- os_free(uri);
- return DM_RESP_BAD_REQUEST;
- }
-
- unode = tnds_to_mo(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (unode == NULL) {
- wpa_printf(MSG_INFO, "Could not parse TNDS text");
- os_free(uri);
- return DM_RESP_BAD_REQUEST;
- }
-
- debug_dump_node(ctx, "Parsed TNDS", unode);
-
- xml_node_add_child(ctx->xml, pps_node, unode);
- } else {
- /* TODO: What to do here? */
- os_free(uri);
- return DM_RESP_BAD_REQUEST;
- }
-
- os_free(uri);
-
- if (update_pps_file(ctx, pps_fname, pps) < 0)
- return DM_RESP_COMMAND_FAILED;
-
- ctx->pps_updated = 1;
-
- return DM_RESP_OK;
-}
-
-
-static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add,
- xml_node_t *pps, const char *pps_fname)
-{
- xml_node_t *node;
- char *locuri;
- char fname[300];
- int ret;
-
- node = get_node(ctx->xml, add, "Item/Target/LocURI");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No Target LocURI node found");
- return DM_RESP_BAD_REQUEST;
- }
- locuri = xml_node_get_text(ctx->xml, node);
- if (locuri == NULL) {
- wpa_printf(MSG_ERROR, "No LocURI node text found");
- return DM_RESP_BAD_REQUEST;
- }
- wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
- if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
- wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
- xml_node_get_text_free(ctx->xml, locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
-
- node = get_node(ctx->xml, add, "Item/Data");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No Data node found");
- xml_node_get_text_free(ctx->xml, locuri);
- return DM_RESP_BAD_REQUEST;
- }
-
- if (pps_fname && os_file_exists(pps_fname)) {
- ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname);
- if (ret != DM_RESP_OK) {
- xml_node_get_text_free(ctx->xml, locuri);
- return ret;
- }
- ret = 0;
- os_strlcpy(fname, pps_fname, sizeof(fname));
- } else
- ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname));
- xml_node_get_text_free(ctx->xml, locuri);
- if (ret < 0)
- return ret == -2 ? DM_RESP_ALREADY_EXISTS :
- DM_RESP_COMMAND_FAILED;
-
- if (ctx->no_reconnect == 2) {
- os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s",
- fname);
- ctx->pps_cred_set = 1;
- return DM_RESP_OK;
- }
-
- wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
- cmd_set_pps(ctx, fname);
-
- if (ctx->no_reconnect)
- return DM_RESP_OK;
-
- wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
- if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
- wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
-
- return DM_RESP_OK;
-}
-
-
-static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace,
- xml_node_t *pps, const char *pps_fname)
-{
- char *locuri, *pos;
- size_t fqdn_len;
- xml_node_t *node, *tnds, *unode, *pps_node, *parent;
- char *data;
- int use_tnds = 0;
-
- locuri = oma_dm_get_target_locuri(ctx, replace);
- if (locuri == NULL)
- return DM_RESP_BAD_REQUEST;
-
- wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri);
- if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
- wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi");
- os_free(locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos = locuri + 8;
-
- if (ctx->fqdn == NULL) {
- os_free(locuri);
- return DM_RESP_COMMAND_FAILED;
- }
- fqdn_len = os_strlen(ctx->fqdn);
- if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
- pos[fqdn_len] != '/') {
- wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s",
- ctx->fqdn);
- os_free(locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos += fqdn_len + 1;
-
- if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
- wpa_printf(MSG_INFO,
- "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription",
- ctx->fqdn);
- os_free(locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos += 24;
-
- wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos);
-
- pps_node = get_node(ctx->xml, pps, pos);
- if (pps_node == NULL) {
- wpa_printf(MSG_INFO, "Specified PPS node not found");
- os_free(locuri);
- return DM_RESP_NOT_FOUND;
- }
-
- node = get_node(ctx->xml, replace, "Item/Meta/Type");
- if (node) {
- char *type;
- type = xml_node_get_text(ctx->xml, node);
- if (type == NULL) {
- wpa_printf(MSG_INFO, "Could not find type text");
- os_free(locuri);
- return DM_RESP_BAD_REQUEST;
- }
- use_tnds = node &&
- os_strstr(type, "application/vnd.syncml.dmtnds+xml");
- }
-
- node = get_node(ctx->xml, replace, "Item/Data");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No Replace/Item/Data found");
- os_free(locuri);
- return DM_RESP_BAD_REQUEST;
- }
-
- data = xml_node_get_text(ctx->xml, node);
- if (data == NULL) {
- wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text");
- os_free(locuri);
- return DM_RESP_BAD_REQUEST;
- }
-
- wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data);
-
- if (use_tnds) {
- tnds = xml_node_from_buf(ctx->xml, data);
- xml_node_get_text_free(ctx->xml, data);
- if (tnds == NULL) {
- wpa_printf(MSG_INFO,
- "Could not parse Replace/Item/Data text");
- os_free(locuri);
- return DM_RESP_BAD_REQUEST;
- }
-
- unode = tnds_to_mo(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (unode == NULL) {
- wpa_printf(MSG_INFO, "Could not parse TNDS text");
- os_free(locuri);
- return DM_RESP_BAD_REQUEST;
- }
-
- debug_dump_node(ctx, "Parsed TNDS", unode);
-
- parent = xml_node_get_parent(ctx->xml, pps_node);
- xml_node_detach(ctx->xml, pps_node);
- xml_node_add_child(ctx->xml, parent, unode);
- } else {
- xml_node_set_text(ctx->xml, pps_node, data);
- xml_node_get_text_free(ctx->xml, data);
- }
-
- os_free(locuri);
-
- if (update_pps_file(ctx, pps_fname, pps) < 0)
- return DM_RESP_COMMAND_FAILED;
-
- ctx->pps_updated = 1;
-
- return DM_RESP_OK;
-}
-
-
-static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get,
- xml_node_t *pps, const char *pps_fname, char **value)
-{
- char *locuri, *pos;
- size_t fqdn_len;
- xml_node_t *pps_node;
- const char *name;
-
- *value = NULL;
-
- locuri = oma_dm_get_target_locuri(ctx, get);
- if (locuri == NULL)
- return DM_RESP_BAD_REQUEST;
-
- wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri);
- if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
- wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi");
- os_free(locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos = locuri + 8;
-
- if (ctx->fqdn == NULL)
- return DM_RESP_COMMAND_FAILED;
- fqdn_len = os_strlen(ctx->fqdn);
- if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
- pos[fqdn_len] != '/') {
- wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s",
- ctx->fqdn);
- os_free(locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos += fqdn_len + 1;
-
- if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
- wpa_printf(MSG_INFO,
- "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription",
- ctx->fqdn);
- os_free(locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
- pos += 24;
-
- wpa_printf(MSG_INFO, "Get command for PPS node %s", pos);
-
- pps_node = get_node(ctx->xml, pps, pos);
- if (pps_node == NULL) {
- wpa_printf(MSG_INFO, "Specified PPS node not found");
- os_free(locuri);
- return DM_RESP_NOT_FOUND;
- }
-
- name = xml_node_get_localname(ctx->xml, pps_node);
- wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name);
- if (os_strcasecmp(name, "Password") == 0) {
- wpa_printf(MSG_INFO, "Do not allow Get for Password node");
- os_free(locuri);
- return DM_RESP_PERMISSION_DENIED;
- }
-
- /*
- * TODO: No support for DMTNDS, so if interior node, reply with a
- * list of children node names in Results element. The child list type is
- * defined in [DMTND].
- */
-
- *value = xml_node_get_text(ctx->xml, pps_node);
- if (*value == NULL)
- return DM_RESP_COMMAND_FAILED;
-
- return DM_RESP_OK;
-}
-
-
-static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node)
-{
- xml_node_t *cnode;
- char *str;
- int ret;
-
- cnode = get_node(ctx->xml, node, "CmdID");
- if (cnode == NULL)
- return 0;
-
- str = xml_node_get_text(ctx->xml, cnode);
- if (str == NULL)
- return 0;
- ret = atoi(str);
- xml_node_get_text_free(ctx->xml, str);
- return ret;
-}
-
-
-static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
- const char *url, xml_node_t *syncml,
- const char *ext_hdr,
- const char *username, const char *password,
- const char *client_cert,
- const char *client_key)
-{
- xml_node_t *resp;
- char *str, *res;
- char *resp_uri = NULL;
-
- str = xml_node_to_str(ctx->xml, syncml);
- xml_node_free(ctx->xml, syncml);
- if (str == NULL)
- return NULL;
-
- wpa_printf(MSG_INFO, "Send OMA DM Package");
- write_summary(ctx, "Send OMA DM Package");
- os_free(ctx->server_url);
- ctx->server_url = os_strdup(url);
- res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
- ext_hdr, ctx->ca_fname, username, password,
- client_cert, client_key, NULL);
- os_free(str);
- os_free(resp_uri);
- resp_uri = NULL;
-
- if (res == NULL) {
- const char *err = http_get_err(ctx->http);
- if (err) {
- wpa_printf(MSG_INFO, "HTTP error: %s", err);
- write_result(ctx, "HTTP error: %s", err);
- } else {
- write_summary(ctx, "Failed to send OMA DM Package");
- }
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "Server response: %s", res);
-
- wpa_printf(MSG_INFO, "Process OMA DM Package");
- write_summary(ctx, "Process received OMA DM Package");
- resp = xml_node_from_buf(ctx->xml, res);
- os_free(res);
- if (resp == NULL) {
- wpa_printf(MSG_INFO, "Failed to parse OMA DM response");
- return NULL;
- }
-
- debug_dump_node(ctx, "OMA DM Package", resp);
-
- return resp;
-}
-
-
-static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url,
- xml_node_t *resp, int msgid,
- char **ret_resp_uri,
- xml_node_t *pps, const char *pps_fname)
-{
- xml_node_t *syncml, *syncbody, *hdr, *body, *child;
- const char *name;
- char *resp_uri = NULL;
- int server_msgid = 0;
- int cmdid = 0;
- int server_cmdid;
- int resp_needed = 0;
- char *tmp;
- int final = 0;
- char *locuri;
-
- *ret_resp_uri = NULL;
-
- name = xml_node_get_localname(ctx->xml, resp);
- if (name == NULL || os_strcasecmp(name, "SyncML") != 0) {
- wpa_printf(MSG_INFO, "SyncML node not found");
- return NULL;
- }
-
- hdr = get_node(ctx->xml, resp, "SyncHdr");
- body = get_node(ctx->xml, resp, "SyncBody");
- if (hdr == NULL || body == NULL) {
- wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody");
- return NULL;
- }
-
- xml_node_for_each_child(ctx->xml, child, hdr) {
- xml_node_for_each_check(ctx->xml, child);
- name = xml_node_get_localname(ctx->xml, child);
- wpa_printf(MSG_INFO, "SyncHdr %s", name);
- if (os_strcasecmp(name, "RespURI") == 0) {
- tmp = xml_node_get_text(ctx->xml, child);
- if (tmp)
- resp_uri = os_strdup(tmp);
- xml_node_get_text_free(ctx->xml, tmp);
- } else if (os_strcasecmp(name, "MsgID") == 0) {
- tmp = xml_node_get_text(ctx->xml, child);
- if (tmp)
- server_msgid = atoi(tmp);
- xml_node_get_text_free(ctx->xml, tmp);
- }
- }
-
- wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid);
- if (resp_uri)
- wpa_printf(MSG_INFO, "RespURI: %s", resp_uri);
-
- syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid);
- if (syncml == NULL) {
- os_free(resp_uri);
- return NULL;
- }
-
- syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
- cmdid++;
- add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr",
- DM_RESP_AUTH_ACCEPTED, NULL);
-
- xml_node_for_each_child(ctx->xml, child, body) {
- xml_node_for_each_check(ctx->xml, child);
- server_cmdid = oma_dm_get_cmdid(ctx, child);
- name = xml_node_get_localname(ctx->xml, child);
- wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s",
- server_cmdid, name);
- if (os_strcasecmp(name, "Exec") == 0) {
- int res = oma_dm_exec(ctx, child);
- cmdid++;
- locuri = oma_dm_get_target_locuri(ctx, child);
- if (locuri == NULL)
- res = DM_RESP_BAD_REQUEST;
- add_status(ctx, syncbody, server_msgid, server_cmdid,
- cmdid, name, res, locuri);
- os_free(locuri);
- resp_needed = 1;
- } else if (os_strcasecmp(name, "Add") == 0) {
- int res = oma_dm_add(ctx, child, pps, pps_fname);
- cmdid++;
- locuri = oma_dm_get_target_locuri(ctx, child);
- if (locuri == NULL)
- res = DM_RESP_BAD_REQUEST;
- add_status(ctx, syncbody, server_msgid, server_cmdid,
- cmdid, name, res, locuri);
- os_free(locuri);
- resp_needed = 1;
- } else if (os_strcasecmp(name, "Replace") == 0) {
- int res;
- res = oma_dm_replace(ctx, child, pps, pps_fname);
- cmdid++;
- locuri = oma_dm_get_target_locuri(ctx, child);
- if (locuri == NULL)
- res = DM_RESP_BAD_REQUEST;
- add_status(ctx, syncbody, server_msgid, server_cmdid,
- cmdid, name, res, locuri);
- os_free(locuri);
- resp_needed = 1;
- } else if (os_strcasecmp(name, "Status") == 0) {
- /* TODO: Verify success */
- } else if (os_strcasecmp(name, "Get") == 0) {
- int res;
- char *value;
- res = oma_dm_get(ctx, child, pps, pps_fname, &value);
- cmdid++;
- locuri = oma_dm_get_target_locuri(ctx, child);
- if (locuri == NULL)
- res = DM_RESP_BAD_REQUEST;
- add_status(ctx, syncbody, server_msgid, server_cmdid,
- cmdid, name, res, locuri);
- if (res == DM_RESP_OK && value) {
- cmdid++;
- add_results(ctx, syncbody, server_msgid,
- server_cmdid, cmdid, locuri, value);
- }
- os_free(locuri);
- xml_node_get_text_free(ctx->xml, value);
- resp_needed = 1;
-#if 0 /* TODO: MUST support */
- } else if (os_strcasecmp(name, "Delete") == 0) {
-#endif
-#if 0 /* TODO: MUST support */
- } else if (os_strcasecmp(name, "Sequence") == 0) {
-#endif
- } else if (os_strcasecmp(name, "Final") == 0) {
- final = 1;
- break;
- } else {
- locuri = oma_dm_get_target_locuri(ctx, child);
- add_status(ctx, syncbody, server_msgid, server_cmdid,
- cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED,
- locuri);
- os_free(locuri);
- resp_needed = 1;
- }
- }
-
- if (!final) {
- wpa_printf(MSG_INFO, "Final node not found");
- xml_node_free(ctx->xml, syncml);
- os_free(resp_uri);
- return NULL;
- }
-
- if (!resp_needed) {
- wpa_printf(MSG_INFO, "Exchange completed - no response needed");
- xml_node_free(ctx->xml, syncml);
- os_free(resp_uri);
- return NULL;
- }
-
- xml_node_create(ctx->xml, syncbody, NULL, "Final");
-
- debug_dump_node(ctx, "OMA-DM Package 3", syncml);
-
- *ret_resp_uri = resp_uri;
- return syncml;
-}
-
-
-int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url)
-{
- xml_node_t *syncml, *resp;
- char *resp_uri = NULL;
- int msgid = 0;
-
- if (url == NULL) {
- wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
- return -1;
- }
-
- wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested");
- write_summary(ctx, "OMA-DM credential provisioning");
-
- msgid++;
- syncml = build_oma_dm_1_sub_reg(ctx, url, msgid);
- if (syncml == NULL)
- return -1;
-
- while (syncml) {
- resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
- syncml, NULL, NULL, NULL, NULL, NULL);
- if (resp == NULL)
- return -1;
-
- msgid++;
- syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
- NULL, NULL);
- xml_node_free(ctx->xml, resp);
- }
-
- os_free(resp_uri);
-
- return ctx->pps_cred_set ? 0 : -1;
-}
-
-
-int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
-{
- xml_node_t *syncml, *resp;
- char *resp_uri = NULL;
- int msgid = 0;
-
- if (url == NULL) {
- wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
- return -1;
- }
-
- wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested");
- ctx->no_reconnect = 2;
-
- wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
- write_summary(ctx, "Wait for IP address before starting SIM provisioning");
-
- if (wait_ip_addr(ctx->ifname, 15) < 0) {
- wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
- }
- write_summary(ctx, "OMA-DM SIM provisioning");
-
- msgid++;
- syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
- if (syncml == NULL)
- return -1;
-
- while (syncml) {
- resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
- syncml, NULL, NULL, NULL, NULL, NULL);
- if (resp == NULL)
- return -1;
-
- msgid++;
- syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
- NULL, NULL);
- xml_node_free(ctx->xml, resp);
- }
-
- os_free(resp_uri);
-
- if (ctx->pps_cred_set) {
- wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
- cmd_set_pps(ctx, ctx->pps_fname);
-
- wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
- write_summary(ctx, "Requesting reconnection with updated configuration");
- if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
- wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
- write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
- return -1;
- }
- }
-
- return ctx->pps_cred_set ? 0 : -1;
-}
-
-
-void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps)
-{
- xml_node_t *syncml, *resp;
- char *resp_uri = NULL;
- int msgid = 0;
-
- wpa_printf(MSG_INFO, "OMA-DM policy update");
- write_summary(ctx, "OMA-DM policy update");
-
- msgid++;
- syncml = build_oma_dm_1_pol_upd(ctx, address, msgid);
- if (syncml == NULL)
- return;
-
- while (syncml) {
- resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
- syncml, NULL, cred_username,
- cred_password, client_cert, client_key);
- if (resp == NULL)
- return;
-
- msgid++;
- syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
- pps, pps_fname);
- xml_node_free(ctx->xml, resp);
- }
-
- os_free(resp_uri);
-
- if (ctx->pps_updated) {
- wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO");
- write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection");
- cmd_set_pps(ctx, pps_fname);
- if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
- wpa_printf(MSG_INFO,
- "Failed to request wpa_supplicant to reconnect");
- write_summary(ctx,
- "Failed to request wpa_supplicant to reconnect");
- }
- }
-}
-
-
-void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps)
-{
- xml_node_t *syncml, *resp;
- char *resp_uri = NULL;
- int msgid = 0;
-
- wpa_printf(MSG_INFO, "OMA-DM subscription remediation");
- write_summary(ctx, "OMA-DM subscription remediation");
-
- msgid++;
- syncml = build_oma_dm_1_sub_rem(ctx, address, msgid);
- if (syncml == NULL)
- return;
-
- while (syncml) {
- resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
- syncml, NULL, cred_username,
- cred_password, client_cert, client_key);
- if (resp == NULL)
- return;
-
- msgid++;
- syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
- pps, pps_fname);
- xml_node_free(ctx->xml, resp);
- }
-
- os_free(resp_uri);
-
- wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
- write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
- cmd_set_pps(ctx, pps_fname);
- if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
- wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
- write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
- }
-}
-
-
-void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
- const char *add_fname)
-{
- xml_node_t *pps, *add;
- int res;
-
- ctx->fqdn = os_strdup("wi-fi.org");
-
- pps = node_from_file(ctx->xml, pps_fname);
- if (pps == NULL) {
- wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
- pps_fname);
- return;
- }
-
- add = node_from_file(ctx->xml, add_fname);
- if (add == NULL) {
- wpa_printf(MSG_INFO, "Add file %s could not be parsed",
- add_fname);
- xml_node_free(ctx->xml, pps);
- return;
- }
-
- res = oma_dm_add(ctx, add, pps, pps_fname);
- wpa_printf(MSG_INFO, "oma_dm_add --> %d", res);
-
- xml_node_free(ctx->xml, pps);
- xml_node_free(ctx->xml, add);
-}
-
-
-void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
- const char *replace_fname)
-{
- xml_node_t *pps, *replace;
- int res;
-
- ctx->fqdn = os_strdup("wi-fi.org");
-
- pps = node_from_file(ctx->xml, pps_fname);
- if (pps == NULL) {
- wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
- pps_fname);
- return;
- }
-
- replace = node_from_file(ctx->xml, replace_fname);
- if (replace == NULL) {
- wpa_printf(MSG_INFO, "Replace file %s could not be parsed",
- replace_fname);
- xml_node_free(ctx->xml, pps);
- return;
- }
-
- res = oma_dm_replace(ctx, replace, pps, pps_fname);
- wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res);
-
- xml_node_free(ctx->xml, pps);
- xml_node_free(ctx->xml, replace);
-}
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 2ca85f9..f679df4 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -9,9 +9,6 @@
#include "includes.h"
#include <time.h>
#include <sys/stat.h>
-#ifdef ANDROID
-#include "private/android_filesystem_config.h"
-#endif /* ANDROID */
#include "common.h"
#include "utils/browser.h"
@@ -25,10 +22,9 @@
#include "crypto/sha256.h"
#include "osu_client.h"
-const char *spp_xsd_fname = "spp.xsd";
+static void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...);
-
-void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
+static void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
{
va_list ap;
FILE *f;
@@ -54,7 +50,7 @@
}
-void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
+static void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
{
va_list ap;
FILE *f;
@@ -74,231 +70,6 @@
}
-void debug_dump_node(struct hs20_osu_client *ctx, const char *title,
- xml_node_t *node)
-{
- char *str = xml_node_to_str(ctx->xml, node);
- wpa_printf(MSG_DEBUG, "[hs20] %s: '%s'", title, str);
- free(str);
-}
-
-
-static int valid_fqdn(const char *fqdn)
-{
- const char *pos;
-
- /* TODO: could make this more complete.. */
- if (strchr(fqdn, '.') == 0 || strlen(fqdn) > 255)
- return 0;
- for (pos = fqdn; *pos; pos++) {
- if (*pos >= 'a' && *pos <= 'z')
- continue;
- if (*pos >= 'A' && *pos <= 'Z')
- continue;
- if (*pos >= '0' && *pos <= '9')
- continue;
- if (*pos == '-' || *pos == '.' || *pos == '_')
- continue;
- return 0;
- }
- return 1;
-}
-
-
-static int android_update_permission(const char *path, mode_t mode)
-{
-#ifdef ANDROID
- /* we need to change file/folder permission for Android */
-
- if (!path) {
- wpa_printf(MSG_ERROR, "file path null");
- return -1;
- }
-
- /* Allow processes running with Group ID as AID_WIFI,
- * to read files from SP, SP/<fqdn>, Cert and osu-info directories */
- if (lchown(path, -1, AID_WIFI)) {
- wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s",
- strerror(errno));
- return -1;
- }
-
- if (chmod(path, mode) < 0) {
- wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
- strerror(errno));
- return -1;
- }
-#endif /* ANDROID */
-
- return 0;
-}
-
-
-int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
-{
- xml_node_t *node;
- char *url, *user = NULL, *pw = NULL;
- char *proto;
- int ret = -1;
-
- proto = xml_node_get_attr_value(ctx->xml, getcert,
- "enrollmentProtocol");
- if (!proto)
- return -1;
- wpa_printf(MSG_INFO, "getCertificate - enrollmentProtocol=%s", proto);
- write_summary(ctx, "getCertificate - enrollmentProtocol=%s", proto);
- if (os_strcasecmp(proto, "EST") != 0) {
- wpa_printf(MSG_INFO, "Unsupported enrollmentProtocol");
- xml_node_get_attr_value_free(ctx->xml, proto);
- return -1;
- }
- xml_node_get_attr_value_free(ctx->xml, proto);
-
- node = get_node(ctx->xml, getcert, "enrollmentServerURI");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "Could not find enrollmentServerURI node");
- xml_node_get_attr_value_free(ctx->xml, proto);
- return -1;
- }
- url = xml_node_get_text(ctx->xml, node);
- if (url == NULL) {
- wpa_printf(MSG_INFO, "Could not get URL text");
- return -1;
- }
- wpa_printf(MSG_INFO, "enrollmentServerURI: %s", url);
- write_summary(ctx, "enrollmentServerURI: %s", url);
-
- node = get_node(ctx->xml, getcert, "estUserID");
- if (node == NULL && !ctx->client_cert_present) {
- wpa_printf(MSG_INFO, "Could not find estUserID node");
- goto fail;
- }
- if (node) {
- user = xml_node_get_text(ctx->xml, node);
- if (user == NULL) {
- wpa_printf(MSG_INFO, "Could not get estUserID text");
- goto fail;
- }
- wpa_printf(MSG_INFO, "estUserID: %s", user);
- write_summary(ctx, "estUserID: %s", user);
- }
-
- node = get_node(ctx->xml, getcert, "estPassword");
- if (node == NULL && !ctx->client_cert_present) {
- wpa_printf(MSG_INFO, "Could not find estPassword node");
- goto fail;
- }
- if (node) {
- pw = xml_node_get_base64_text(ctx->xml, node, NULL);
- if (pw == NULL) {
- wpa_printf(MSG_INFO, "Could not get estPassword text");
- goto fail;
- }
- wpa_printf(MSG_INFO, "estPassword: %s", pw);
- }
-
- mkdir("Cert", S_IRWXU);
- android_update_permission("Cert", S_IRWXU | S_IRWXG);
-
- if (est_load_cacerts(ctx, url) < 0 ||
- est_build_csr(ctx, url) < 0 ||
- est_simple_enroll(ctx, url, user, pw) < 0)
- goto fail;
-
- ret = 0;
-fail:
- xml_node_get_text_free(ctx->xml, url);
- xml_node_get_text_free(ctx->xml, user);
- xml_node_get_text_free(ctx->xml, pw);
-
- return ret;
-}
-
-
-static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert,
- const char *fqdn)
-{
- u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN];
- char *der, *pem;
- size_t der_len, pem_len;
- char *fingerprint;
- char buf[200];
-
- wpa_printf(MSG_INFO, "PPS for certificate credential - fqdn=%s", fqdn);
-
- fingerprint = xml_node_get_text(ctx->xml, cert);
- if (fingerprint == NULL)
- return -1;
- if (hexstr2bin(fingerprint, digest1, SHA256_MAC_LEN) < 0) {
- wpa_printf(MSG_INFO, "Invalid SHA256 hash value");
- write_result(ctx, "Invalid client certificate SHA256 hash value in PPS");
- xml_node_get_text_free(ctx->xml, fingerprint);
- return -1;
- }
- xml_node_get_text_free(ctx->xml, fingerprint);
-
- der = os_readfile("Cert/est_cert.der", &der_len);
- if (der == NULL) {
- wpa_printf(MSG_INFO, "Could not find client certificate from EST");
- write_result(ctx, "Could not find client certificate from EST");
- return -1;
- }
-
- if (sha256_vector(1, (const u8 **) &der, &der_len, digest2) < 0) {
- os_free(der);
- return -1;
- }
- os_free(der);
-
- if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) {
- wpa_printf(MSG_INFO, "Client certificate from EST does not match fingerprint from PPS MO");
- write_result(ctx, "Client certificate from EST does not match fingerprint from PPS MO");
- return -1;
- }
-
- wpa_printf(MSG_INFO, "Client certificate from EST matches PPS MO");
- unlink("Cert/est_cert.der");
-
- os_snprintf(buf, sizeof(buf), "SP/%s/client-ca.pem", fqdn);
- if (rename("Cert/est-cacerts.pem", buf) < 0) {
- wpa_printf(MSG_INFO, "Could not move est-cacerts.pem to client-ca.pem: %s",
- strerror(errno));
- return -1;
- }
- pem = os_readfile(buf, &pem_len);
-
- os_snprintf(buf, sizeof(buf), "SP/%s/client-cert.pem", fqdn);
- if (rename("Cert/est_cert.pem", buf) < 0) {
- wpa_printf(MSG_INFO, "Could not move est_cert.pem to client-cert.pem: %s",
- strerror(errno));
- os_free(pem);
- return -1;
- }
-
- if (pem) {
- FILE *f = fopen(buf, "a");
- if (f) {
- fwrite(pem, pem_len, 1, f);
- fclose(f);
- }
- os_free(pem);
- }
-
- os_snprintf(buf, sizeof(buf), "SP/%s/client-key.pem", fqdn);
- if (rename("Cert/privkey-plain.pem", buf) < 0) {
- wpa_printf(MSG_INFO, "Could not move privkey-plain.pem to client-key.pem: %s",
- strerror(errno));
- return -1;
- }
-
- unlink("Cert/est-req.b64");
- unlink("Cert/est-req.pem");
- rmdir("Cert");
-
- return 0;
-}
-
-
#define TMP_CERT_DL_FILE "tmp-cert-download"
static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
@@ -337,12 +108,10 @@
xml_node_get_text_free(ctx->xml, hash);
write_summary(ctx, "Download certificate from %s", url);
- ctx->no_osu_cert_validation = 1;
http_ocsp_set(ctx->http, 1);
res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL);
http_ocsp_set(ctx->http,
(ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
- ctx->no_osu_cert_validation = 0;
xml_node_get_text_free(ctx->xml, url);
if (res < 0)
return -1;
@@ -392,60 +161,6 @@
}
-static int cmd_dl_osu_ca(struct hs20_osu_client *ctx, const char *pps_fname,
- const char *ca_fname)
-{
- xml_node_t *pps, *node;
- int ret;
-
- pps = node_from_file(ctx->xml, pps_fname);
- if (pps == NULL) {
- wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
- return -1;
- }
-
- node = get_child_node(ctx->xml, pps,
- "SubscriptionUpdate/TrustRoot");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No SubscriptionUpdate/TrustRoot/CertURL found from PPS");
- xml_node_free(ctx->xml, pps);
- return -1;
- }
-
- ret = download_cert(ctx, node, ca_fname);
- xml_node_free(ctx->xml, pps);
-
- return ret;
-}
-
-
-static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
- const char *ca_fname)
-{
- xml_node_t *pps, *node;
- int ret;
-
- pps = node_from_file(ctx->xml, pps_fname);
- if (pps == NULL) {
- wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
- return -1;
- }
-
- node = get_child_node(ctx->xml, pps,
- "Policy/PolicyUpdate/TrustRoot");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
- xml_node_free(ctx->xml, pps);
- return -2;
- }
-
- ret = download_cert(ctx, node, ca_fname);
- xml_node_free(ctx->xml, pps);
-
- return ret;
-}
-
-
static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname,
const char *ca_fname)
{
@@ -480,298 +195,6 @@
}
-static int download_trust_roots(struct hs20_osu_client *ctx,
- const char *pps_fname)
-{
- char *dir, *pos;
- char fname[300];
- int ret, ret1;
-
- dir = os_strdup(pps_fname);
- if (dir == NULL)
- return -1;
- pos = os_strrchr(dir, '/');
- if (pos == NULL) {
- os_free(dir);
- return -1;
- }
- *pos = '\0';
-
- snprintf(fname, sizeof(fname), "%s/ca.pem", dir);
- ret = cmd_dl_osu_ca(ctx, pps_fname, fname);
- snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir);
- ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname);
- if (ret == 0 && ret1 == -1)
- ret = -1;
- snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
- ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname);
- if (ret == 0 && ret1 == -1)
- ret = -1;
-
- os_free(dir);
-
- return ret;
-}
-
-
-static int server_dnsname_suffix_match(struct hs20_osu_client *ctx,
- const char *fqdn)
-{
- size_t match_len, len, i;
- const char *val;
-
- match_len = os_strlen(fqdn);
-
- for (i = 0; i < ctx->server_dnsname_count; i++) {
- wpa_printf(MSG_INFO,
- "Checking suffix match against server dNSName %s",
- ctx->server_dnsname[i]);
- val = ctx->server_dnsname[i];
- len = os_strlen(val);
-
- if (match_len > len)
- continue;
-
- if (os_strncasecmp(val + len - match_len, fqdn, match_len) != 0)
- continue; /* no match */
-
- if (match_len == len)
- return 1; /* exact match */
-
- if (val[len - match_len - 1] == '.')
- return 1; /* full label match completes suffix match */
-
- /* Reject due to incomplete label match */
- }
-
- /* None of the dNSName(s) matched */
- return 0;
-}
-
-
-int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
- xml_node_t *add_mo, char *fname, size_t fname_len)
-{
- char *str;
- char *fqdn, *pos;
- xml_node_t *tnds, *mo, *cert;
- const char *name;
- int ret;
-
- if (strncmp(uri, "./Wi-Fi/", 8) != 0) {
- wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO: '%s'",
- uri);
- write_result(ctx, "Unsupported location for addMO to add PPS MO: '%s'",
- uri);
- return -1;
- }
-
- fqdn = strdup(uri + 8);
- if (fqdn == NULL)
- return -1;
- pos = strchr(fqdn, '/');
- if (pos) {
- if (os_strcasecmp(pos, "/PerProviderSubscription") != 0) {
- wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO (extra directory): '%s'",
- uri);
- write_result(ctx, "Unsupported location for addMO to "
- "add PPS MO (extra directory): '%s'", uri);
- free(fqdn);
- return -1;
- }
- *pos = '\0'; /* remove trailing slash and PPS node name */
- }
- wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn);
-
- if (!server_dnsname_suffix_match(ctx, fqdn)) {
- wpa_printf(MSG_INFO,
- "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d",
- fqdn, (int) ctx->server_dnsname_count);
- write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
- fqdn);
- free(fqdn);
- return -1;
- }
-
- if (!valid_fqdn(fqdn)) {
- wpa_printf(MSG_INFO, "Invalid FQDN '%s'", fqdn);
- write_result(ctx, "Invalid FQDN '%s'", fqdn);
- free(fqdn);
- return -1;
- }
-
- mkdir("SP", S_IRWXU);
- snprintf(fname, fname_len, "SP/%s", fqdn);
- if (mkdir(fname, S_IRWXU) < 0) {
- if (errno != EEXIST) {
- int err = errno;
- wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
- fname, strerror(err));
- free(fqdn);
- return -1;
- }
- }
-
- android_update_permission("SP", S_IRWXU | S_IRWXG);
- android_update_permission(fname, S_IRWXU | S_IRWXG);
-
- snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
-
- if (os_file_exists(fname)) {
- wpa_printf(MSG_INFO, "PPS file '%s' exists - reject addMO",
- fname);
- write_result(ctx, "PPS file '%s' exists - reject addMO",
- fname);
- free(fqdn);
- return -2;
- }
- wpa_printf(MSG_INFO, "Using PPS file: %s", fname);
-
- str = xml_node_get_text(ctx->xml, add_mo);
- if (str == NULL) {
- wpa_printf(MSG_INFO, "Could not extract MO text");
- free(fqdn);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "[hs20] addMO text: '%s'", str);
-
- tnds = xml_node_from_buf(ctx->xml, str);
- xml_node_get_text_free(ctx->xml, str);
- if (tnds == NULL) {
- wpa_printf(MSG_INFO, "[hs20] Could not parse addMO text");
- free(fqdn);
- return -1;
- }
-
- mo = tnds_to_mo(ctx->xml, tnds);
- if (mo == NULL) {
- wpa_printf(MSG_INFO, "[hs20] Could not parse addMO TNDS text");
- free(fqdn);
- return -1;
- }
-
- debug_dump_node(ctx, "Parsed TNDS", mo);
-
- name = xml_node_get_localname(ctx->xml, mo);
- if (os_strcasecmp(name, "PerProviderSubscription") != 0) {
- wpa_printf(MSG_INFO, "[hs20] Unexpected PPS MO root node name '%s'",
- name);
- free(fqdn);
- return -1;
- }
-
- cert = get_child_node(ctx->xml, mo,
- "Credential/DigitalCertificate/"
- "CertSHA256Fingerprint");
- if (cert && process_est_cert(ctx, cert, fqdn) < 0) {
- xml_node_free(ctx->xml, mo);
- free(fqdn);
- return -1;
- }
- free(fqdn);
-
- if (node_to_file(ctx->xml, fname, mo) < 0) {
- wpa_printf(MSG_INFO, "Could not write MO to file");
- xml_node_free(ctx->xml, mo);
- return -1;
- }
- xml_node_free(ctx->xml, mo);
-
- wpa_printf(MSG_INFO, "A new PPS MO added as '%s'", fname);
- write_summary(ctx, "A new PPS MO added as '%s'", fname);
-
- ret = download_trust_roots(ctx, fname);
- if (ret < 0) {
- wpa_printf(MSG_INFO, "Remove invalid PPS MO file");
- write_summary(ctx, "Remove invalid PPS MO file");
- unlink(fname);
- }
-
- return ret;
-}
-
-
-int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
- xml_node_t *pps)
-{
- char *str;
- FILE *f;
- char backup[300];
-
- if (ctx->client_cert_present) {
- xml_node_t *cert;
- cert = get_child_node(ctx->xml, pps,
- "Credential/DigitalCertificate/"
- "CertSHA256Fingerprint");
- if (cert && os_file_exists("Cert/est_cert.der") &&
- process_est_cert(ctx, cert, ctx->fqdn) < 0) {
- wpa_printf(MSG_INFO, "EST certificate update processing failed on PPS MO update");
- return -1;
- }
- }
-
- wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname);
-
- str = xml_node_to_str(ctx->xml, pps);
- if (str == NULL) {
- wpa_printf(MSG_ERROR, "No node found");
- return -1;
- }
- wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str);
-
- snprintf(backup, sizeof(backup), "%s.bak", pps_fname);
- rename(pps_fname, backup);
- f = fopen(pps_fname, "w");
- if (f == NULL) {
- wpa_printf(MSG_INFO, "Could not write PPS");
- rename(backup, pps_fname);
- free(str);
- return -1;
- }
- fprintf(f, "%s\n", str);
- fclose(f);
-
- free(str);
-
- return 0;
-}
-
-
-void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps,
- const char *alt_loc, char **user, char **pw)
-{
- xml_node_t *node;
-
- node = get_child_node(ctx->xml, pps,
- "Credential/UsernamePassword/Username");
- if (node)
- *user = xml_node_get_text(ctx->xml, node);
-
- node = get_child_node(ctx->xml, pps,
- "Credential/UsernamePassword/Password");
- if (node)
- *pw = xml_node_get_base64_text(ctx->xml, node, NULL);
-
- node = get_child_node(ctx->xml, pps, alt_loc);
- if (node) {
- xml_node_t *a;
- a = get_node(ctx->xml, node, "Username");
- if (a) {
- xml_node_get_text_free(ctx->xml, *user);
- *user = xml_node_get_text(ctx->xml, a);
- wpa_printf(MSG_INFO, "Use OSU username '%s'", *user);
- }
-
- a = get_node(ctx->xml, node, "Password");
- if (a) {
- free(*pw);
- *pw = xml_node_get_base64_text(ctx->xml, a, NULL);
- wpa_printf(MSG_INFO, "Use OSU password");
- }
- }
-}
-
-
/* Remove old credentials based on HomeSP/FQDN */
static void remove_sp_creds(struct hs20_osu_client *ctx, const char *fqdn)
{
@@ -1874,14 +1297,13 @@
wpa_printf(MSG_INFO, "Failed to set provisioning_sp");
wpa_printf(MSG_INFO, "credential localname: '%s'", name);
set_pps_credential(ctx, id, child, fqdn);
- ctx->pps_cred_set = 1;
}
xml_node_get_text_free(ctx->xml, update_identifier);
}
-void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname)
+static void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname)
{
xml_node_t *pps;
const char *fqdn;
@@ -1988,1167 +1410,20 @@
}
-struct osu_icon {
- int id;
- char lang[4];
- char mime_type[256];
- char filename[256];
-};
-
-struct osu_data {
- char bssid[20];
- char url[256];
- unsigned int methods;
- char osu_ssid[33];
- char osu_ssid2[33];
- char osu_nai[256];
- char osu_nai2[256];
- struct osu_lang_text friendly_name[MAX_OSU_VALS];
- size_t friendly_name_count;
- struct osu_lang_text serv_desc[MAX_OSU_VALS];
- size_t serv_desc_count;
- struct osu_icon icon[MAX_OSU_VALS];
- size_t icon_count;
-};
-
-
-static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
-{
- FILE *f;
- char buf[1000];
- struct osu_data *osu = NULL, *last = NULL;
- size_t osu_count = 0;
- char *pos, *end;
- int res;
-
- f = fopen(fname, "r");
- if (f == NULL) {
- wpa_printf(MSG_ERROR, "Could not open %s", fname);
- return NULL;
- }
-
- while (fgets(buf, sizeof(buf), f)) {
- pos = strchr(buf, '\n');
- if (pos)
- *pos = '\0';
-
- if (strncmp(buf, "OSU-PROVIDER ", 13) == 0) {
- last = realloc(osu, (osu_count + 1) * sizeof(*osu));
- if (last == NULL)
- break;
- osu = last;
- last = &osu[osu_count++];
- memset(last, 0, sizeof(*last));
- res = os_snprintf(last->bssid, sizeof(last->bssid),
- "%s", buf + 13);
- if (os_snprintf_error(sizeof(last->bssid), res))
- break;
- continue;
- }
- if (!last)
- continue;
-
- if (strncmp(buf, "uri=", 4) == 0) {
- res = os_snprintf(last->url, sizeof(last->url),
- "%s", buf + 4);
- if (os_snprintf_error(sizeof(last->url), res))
- break;
- continue;
- }
-
- if (strncmp(buf, "methods=", 8) == 0) {
- last->methods = strtol(buf + 8, NULL, 16);
- continue;
- }
-
- if (strncmp(buf, "osu_ssid=", 9) == 0) {
- res = os_snprintf(last->osu_ssid,
- sizeof(last->osu_ssid),
- "%s", buf + 9);
- if (os_snprintf_error(sizeof(last->osu_ssid), res))
- break;
- continue;
- }
-
- if (strncmp(buf, "osu_ssid2=", 10) == 0) {
- res = os_snprintf(last->osu_ssid2,
- sizeof(last->osu_ssid2),
- "%s", buf + 10);
- if (os_snprintf_error(sizeof(last->osu_ssid2), res))
- break;
- continue;
- }
-
- if (os_strncmp(buf, "osu_nai=", 8) == 0) {
- res = os_snprintf(last->osu_nai, sizeof(last->osu_nai),
- "%s", buf + 8);
- if (os_snprintf_error(sizeof(last->osu_nai), res))
- break;
- continue;
- }
-
- if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
- res = os_snprintf(last->osu_nai2,
- sizeof(last->osu_nai2),
- "%s", buf + 9);
- if (os_snprintf_error(sizeof(last->osu_nai2), res))
- break;
- continue;
- }
-
- if (strncmp(buf, "friendly_name=", 14) == 0) {
- struct osu_lang_text *txt;
- if (last->friendly_name_count == MAX_OSU_VALS)
- continue;
- pos = strchr(buf + 14, ':');
- if (pos == NULL)
- continue;
- *pos++ = '\0';
- txt = &last->friendly_name[last->friendly_name_count++];
- res = os_snprintf(txt->lang, sizeof(txt->lang),
- "%s", buf + 14);
- if (os_snprintf_error(sizeof(txt->lang), res))
- break;
- res = os_snprintf(txt->text, sizeof(txt->text),
- "%s", pos);
- if (os_snprintf_error(sizeof(txt->text), res))
- break;
- }
-
- if (strncmp(buf, "desc=", 5) == 0) {
- struct osu_lang_text *txt;
- if (last->serv_desc_count == MAX_OSU_VALS)
- continue;
- pos = strchr(buf + 5, ':');
- if (pos == NULL)
- continue;
- *pos++ = '\0';
- txt = &last->serv_desc[last->serv_desc_count++];
- res = os_snprintf(txt->lang, sizeof(txt->lang),
- "%s", buf + 5);
- if (os_snprintf_error(sizeof(txt->lang), res))
- break;
- res = os_snprintf(txt->text, sizeof(txt->text),
- "%s", pos);
- if (os_snprintf_error(sizeof(txt->text), res))
- break;
- }
-
- if (strncmp(buf, "icon=", 5) == 0) {
- struct osu_icon *icon;
- if (last->icon_count == MAX_OSU_VALS)
- continue;
- icon = &last->icon[last->icon_count++];
- icon->id = atoi(buf + 5);
- pos = strchr(buf, ':');
- if (pos == NULL)
- continue;
- pos = strchr(pos + 1, ':');
- if (pos == NULL)
- continue;
- pos = strchr(pos + 1, ':');
- if (pos == NULL)
- continue;
- pos++;
- end = strchr(pos, ':');
- if (!end)
- continue;
- *end = '\0';
- res = os_snprintf(icon->lang, sizeof(icon->lang),
- "%s", pos);
- if (os_snprintf_error(sizeof(icon->lang), res))
- break;
- pos = end + 1;
-
- end = strchr(pos, ':');
- if (end)
- *end = '\0';
- res = os_snprintf(icon->mime_type,
- sizeof(icon->mime_type), "%s", pos);
- if (os_snprintf_error(sizeof(icon->mime_type), res))
- break;
- if (!end)
- continue;
- pos = end + 1;
-
- end = strchr(pos, ':');
- if (end)
- *end = '\0';
- res = os_snprintf(icon->filename,
- sizeof(icon->filename), "%s", pos);
- if (os_snprintf_error(sizeof(icon->filename), res))
- break;
- continue;
- }
- }
-
- fclose(f);
-
- *count = osu_count;
- return osu;
-}
-
-
-static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
- const char *ssid, const char *ssid2, const char *url,
- unsigned int methods, int no_prod_assoc,
- const char *osu_nai, const char *osu_nai2)
-{
- int id;
- const char *ifname = ctx->ifname;
- char buf[200];
- struct wpa_ctrl *mon;
- int res;
-
- if (ssid2 && ssid2[0] == '\0')
- ssid2 = NULL;
-
- if (ctx->osu_ssid) {
- if (os_strcmp(ssid, ctx->osu_ssid) == 0) {
- wpa_printf(MSG_DEBUG,
- "Enforced OSU SSID matches ANQP info");
- ssid2 = NULL;
- } else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) {
- wpa_printf(MSG_DEBUG,
- "Enforced OSU SSID matches RSN[OSEN] info");
- ssid = ssid2;
- } else {
- wpa_printf(MSG_INFO, "Enforced OSU SSID did not match");
- write_summary(ctx, "Enforced OSU SSID did not match");
- return -1;
- }
- }
-
- id = add_network(ifname);
- if (id < 0)
- return -1;
- if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
- return -1;
- if (ssid2)
- osu_nai = osu_nai2;
- if (osu_nai && os_strlen(osu_nai) > 0) {
- char dir[255], fname[300];
- if (getcwd(dir, sizeof(dir)) == NULL)
- return -1;
- os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir);
-
- if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0)
- return -1;
-
- if (set_network(ifname, id, "proto", "OSEN") < 0 ||
- set_network(ifname, id, "key_mgmt", "OSEN") < 0 ||
- set_network(ifname, id, "pairwise", "CCMP") < 0 ||
- set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 ||
- set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 ||
- set_network(ifname, id, "ocsp", "2") < 0 ||
- set_network_quoted(ifname, id, "identity", osu_nai) < 0 ||
- set_network_quoted(ifname, id, "ca_cert", fname) < 0)
- return -1;
- } else if (ssid2) {
- wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]");
- write_summary(ctx, "No OSU_NAI set for RSN[OSEN]");
- return -1;
- } else {
- if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
- return -1;
- }
-
- mon = open_wpa_mon(ifname);
- if (mon == NULL)
- return -1;
-
- wpa_printf(MSG_INFO, "Associate with OSU SSID");
- write_summary(ctx, "Associate with OSU SSID");
- snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", id);
- if (wpa_command(ifname, buf) < 0)
- return -1;
-
- res = get_wpa_cli_event(mon, "CTRL-EVENT-CONNECTED",
- buf, sizeof(buf));
-
- wpa_ctrl_detach(mon);
- wpa_ctrl_close(mon);
-
- if (res < 0) {
- wpa_printf(MSG_INFO, "Could not connect to OSU network");
- write_summary(ctx, "Could not connect to OSU network");
- wpa_printf(MSG_INFO, "Remove OSU network connection");
- snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
- wpa_command(ifname, buf);
- return -1;
- }
-
- write_summary(ctx, "Waiting for IP address for subscription registration");
- if (wait_ip_addr(ifname, 15) < 0) {
- wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
- }
-
- if (no_prod_assoc) {
- if (res < 0)
- return -1;
- wpa_printf(MSG_INFO, "No production connection used for testing purposes");
- write_summary(ctx, "No production connection used for testing purposes");
- return 0;
- }
-
- ctx->no_reconnect = 1;
- if (methods & 0x02) {
- wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect");
- res = cmd_prov(ctx, url);
- } else if (methods & 0x01) {
- wpa_printf(MSG_DEBUG,
- "Calling cmd_oma_dm_prov from osu_connect");
- res = cmd_oma_dm_prov(ctx, url);
- }
-
- wpa_printf(MSG_INFO, "Remove OSU network connection");
- write_summary(ctx, "Remove OSU network connection");
- snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
- wpa_command(ifname, buf);
-
- if (res < 0)
- return -1;
-
- wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
- write_summary(ctx, "Requesting reconnection with updated configuration");
- if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
- wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
- write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
- return -1;
- }
-
- return 0;
-}
-
-
-static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
- int connect, int no_prod_assoc,
- const char *friendly_name)
-{
- char fname[255];
- FILE *f;
- struct osu_data *osu = NULL, *last = NULL;
- size_t osu_count = 0, i, j;
- int ret;
-
- write_summary(ctx, "OSU provider selection");
-
- if (dir == NULL) {
- wpa_printf(MSG_INFO, "Missing dir parameter to osu_select");
- return -1;
- }
-
- snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir);
- osu = parse_osu_providers(fname, &osu_count);
- if (osu == NULL) {
- wpa_printf(MSG_INFO, "Could not find any OSU providers from %s",
- fname);
- write_result(ctx, "No OSU providers available");
- return -1;
- }
-
- if (friendly_name) {
- for (i = 0; i < osu_count; i++) {
- last = &osu[i];
- for (j = 0; j < last->friendly_name_count; j++) {
- if (os_strcmp(last->friendly_name[j].text,
- friendly_name) == 0)
- break;
- }
- if (j < last->friendly_name_count)
- break;
- }
- if (i == osu_count) {
- wpa_printf(MSG_INFO, "Requested operator friendly name '%s' not found in the list of available providers",
- friendly_name);
- write_summary(ctx, "Requested operator friendly name '%s' not found in the list of available providers",
- friendly_name);
- free(osu);
- return -1;
- }
-
- wpa_printf(MSG_INFO, "OSU Provider selected based on requested operator friendly name '%s'",
- friendly_name);
- write_summary(ctx, "OSU Provider selected based on requested operator friendly name '%s'",
- friendly_name);
- ret = i + 1;
- goto selected;
- }
-
- snprintf(fname, sizeof(fname), "%s/osu-providers.html", dir);
- f = fopen(fname, "w");
- if (f == NULL) {
- wpa_printf(MSG_INFO, "Could not open %s", fname);
- free(osu);
- return -1;
- }
-
- fprintf(f, "<html><head>"
- "<meta http-equiv=\"Content-type\" content=\"text/html; "
- "charset=utf-8\"<title>Select service operator</title>"
- "</head><body><h1>Select service operator</h1>\n");
-
- if (osu_count == 0)
- fprintf(f, "No online signup available\n");
-
- for (i = 0; i < osu_count; i++) {
- last = &osu[i];
-#ifdef ANDROID
- fprintf(f, "<p>\n"
- "<a href=\"http://localhost:12345/osu/%d\">"
- "<table><tr><td>", (int) i + 1);
-#else /* ANDROID */
- fprintf(f, "<p>\n"
- "<a href=\"osu://%d\">"
- "<table><tr><td>", (int) i + 1);
-#endif /* ANDROID */
- for (j = 0; j < last->icon_count; j++) {
- fprintf(f, "<img src=\"osu-icon-%d.%s\">\n",
- last->icon[j].id,
- strcasecmp(last->icon[j].mime_type,
- "image/png") == 0 ? "png" : "icon");
- }
- fprintf(f, "<td>");
- for (j = 0; j < last->friendly_name_count; j++) {
- fprintf(f, "<small>[%s]</small> %s<br>\n",
- last->friendly_name[j].lang,
- last->friendly_name[j].text);
- }
- fprintf(f, "<tr><td colspan=2>");
- for (j = 0; j < last->serv_desc_count; j++) {
- fprintf(f, "<small>[%s]</small> %s<br>\n",
- last->serv_desc[j].lang,
- last->serv_desc[j].text);
- }
- fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
- "SSID: %s<br>\n",
- last->bssid, last->osu_ssid);
- if (last->osu_ssid2[0])
- fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2);
- if (last->osu_nai[0])
- fprintf(f, "NAI: %s<br>\n", last->osu_nai);
- if (last->osu_nai2[0])
- fprintf(f, "NAI2: %s<br>\n", last->osu_nai2);
- fprintf(f, "URL: %s<br>\n"
- "methods:%s%s<br>\n"
- "</small></p>\n",
- last->url,
- last->methods & 0x01 ? " OMA-DM" : "",
- last->methods & 0x02 ? " SOAP-XML-SPP" : "");
- }
-
- fprintf(f, "</body></html>\n");
-
- fclose(f);
-
- snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
- write_summary(ctx, "Start web browser with OSU provider selection page");
- ret = hs20_web_browser(fname, 0);
-
-selected:
- if (ret > 0 && (size_t) ret <= osu_count) {
- char *data;
- size_t data_len;
-
- wpa_printf(MSG_INFO, "Selected OSU id=%d", ret);
- last = &osu[ret - 1];
- ret = 0;
- wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
- wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
- if (last->osu_ssid2[0])
- wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2);
- wpa_printf(MSG_INFO, "URL: %s", last->url);
- write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s",
- ret, last->bssid, last->osu_ssid, last->url);
-
- ctx->friendly_name_count = last->friendly_name_count;
- for (j = 0; j < last->friendly_name_count; j++) {
- wpa_printf(MSG_INFO, "FRIENDLY_NAME: [%s]%s",
- last->friendly_name[j].lang,
- last->friendly_name[j].text);
- os_strlcpy(ctx->friendly_name[j].lang,
- last->friendly_name[j].lang,
- sizeof(ctx->friendly_name[j].lang));
- os_strlcpy(ctx->friendly_name[j].text,
- last->friendly_name[j].text,
- sizeof(ctx->friendly_name[j].text));
- }
-
- ctx->icon_count = last->icon_count;
- for (j = 0; j < last->icon_count; j++) {
- char fname[256];
-
- os_snprintf(fname, sizeof(fname), "%s/osu-icon-%d.%s",
- dir, last->icon[j].id,
- strcasecmp(last->icon[j].mime_type,
- "image/png") == 0 ?
- "png" : "icon");
- wpa_printf(MSG_INFO, "ICON: %s (%s)",
- fname, last->icon[j].filename);
- os_strlcpy(ctx->icon_filename[j],
- last->icon[j].filename,
- sizeof(ctx->icon_filename[j]));
-
- data = os_readfile(fname, &data_len);
- if (data) {
- sha256_vector(1, (const u8 **) &data, &data_len,
- ctx->icon_hash[j]);
- os_free(data);
- }
- }
-
- if (connect == 2) {
- if (last->methods & 0x02) {
- wpa_printf(MSG_DEBUG,
- "Calling cmd_prov from cmd_osu_select");
- ret = cmd_prov(ctx, last->url);
- } else if (last->methods & 0x01) {
- wpa_printf(MSG_DEBUG,
- "Calling cmd_oma_dm_prov from cmd_osu_select");
- ret = cmd_oma_dm_prov(ctx, last->url);
- } else {
- wpa_printf(MSG_DEBUG,
- "No supported OSU provisioning method");
- ret = -1;
- }
- } else if (connect) {
- ret = osu_connect(ctx, last->bssid, last->osu_ssid,
- last->osu_ssid2,
- last->url, last->methods,
- no_prod_assoc, last->osu_nai,
- last->osu_nai2);
- }
- } else
- ret = -1;
-
- free(osu);
-
- return ret;
-}
-
-
-static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
- const char *friendly_name)
-{
- char dir[255];
- char fname[300], buf[400];
- struct wpa_ctrl *mon;
- const char *ifname;
- int res;
-
- ifname = ctx->ifname;
-
- if (getcwd(dir, sizeof(dir)) == NULL)
- return -1;
-
- snprintf(fname, sizeof(fname), "%s/osu-info", dir);
- if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 &&
- errno != EEXIST) {
- wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
- fname, strerror(errno));
- return -1;
- }
-
- android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
-
- snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
- if (wpa_command(ifname, buf) < 0) {
- wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant");
- return -1;
- }
-
- mon = open_wpa_mon(ifname);
- if (mon == NULL)
- return -1;
-
- wpa_printf(MSG_INFO, "Starting OSU fetch");
- write_summary(ctx, "Starting OSU provider information fetch");
- if (wpa_command(ifname, "FETCH_OSU") < 0) {
- wpa_printf(MSG_INFO, "Could not start OSU fetch");
- wpa_ctrl_detach(mon);
- wpa_ctrl_close(mon);
- return -1;
- }
- res = get_wpa_cli_event(mon, "OSU provider fetch completed",
- buf, sizeof(buf));
-
- wpa_ctrl_detach(mon);
- wpa_ctrl_close(mon);
-
- if (res < 0) {
- wpa_printf(MSG_INFO, "OSU fetch did not complete");
- write_summary(ctx, "OSU fetch did not complete");
- return -1;
- }
- wpa_printf(MSG_INFO, "OSU provider fetch completed");
-
- return cmd_osu_select(ctx, fname, 1, no_prod_assoc, friendly_name);
-}
-
-
-static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname, const char *ca_fname)
-{
- xml_node_t *pps, *node;
- char pps_fname_buf[300];
- char ca_fname_buf[200];
- char *cred_username = NULL;
- char *cred_password = NULL;
- char *sub_rem_uri = NULL;
- char client_cert_buf[200];
- char *client_cert = NULL;
- char client_key_buf[200];
- char *client_key = NULL;
- int spp;
-
- wpa_printf(MSG_INFO, "Subscription remediation requested with Server URL: %s",
- address);
-
- if (!pps_fname) {
- char buf[256];
- wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
- if (os_strncmp(address, "fqdn=", 5) == 0) {
- wpa_printf(MSG_INFO, "Use requested FQDN from command line");
- os_snprintf(buf, sizeof(buf), "%s", address + 5);
- address = NULL;
- } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
- sizeof(buf)) < 0) {
- wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
- return -1;
- }
- os_free(ctx->fqdn);
- ctx->fqdn = os_strdup(buf);
- if (ctx->fqdn == NULL)
- return -1;
- wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
- buf);
- os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
- "SP/%s/pps.xml", ctx->fqdn);
- pps_fname = pps_fname_buf;
-
- os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem",
- ctx->fqdn);
- ca_fname = ca_fname_buf;
- }
-
- if (!os_file_exists(pps_fname)) {
- wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
- pps_fname);
- return -1;
- }
- wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
-
- if (ca_fname && !os_file_exists(ca_fname)) {
- wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
- ca_fname);
- return -1;
- }
- wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
- ctx->ca_fname = ca_fname;
-
- pps = node_from_file(ctx->xml, pps_fname);
- if (pps == NULL) {
- wpa_printf(MSG_INFO, "Could not read PPS MO");
- return -1;
- }
-
- if (!ctx->fqdn) {
- char *tmp;
- node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
- return -1;
- }
- tmp = xml_node_get_text(ctx->xml, node);
- if (tmp == NULL) {
- wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
- return -1;
- }
- ctx->fqdn = os_strdup(tmp);
- xml_node_get_text_free(ctx->xml, tmp);
- if (!ctx->fqdn) {
- wpa_printf(MSG_INFO, "No FQDN known");
- return -1;
- }
- }
-
- node = get_child_node(ctx->xml, pps,
- "SubscriptionUpdate/UpdateMethod");
- if (node) {
- char *tmp;
- tmp = xml_node_get_text(ctx->xml, node);
- if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0)
- spp = 0;
- else
- spp = 1;
- } else {
- wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP");
- spp = 1;
- }
-
- get_user_pw(ctx, pps, "SubscriptionUpdate/UsernamePassword",
- &cred_username, &cred_password);
- if (cred_username)
- wpa_printf(MSG_INFO, "Using username: %s", cred_username);
- if (cred_password)
- wpa_printf(MSG_DEBUG, "Using password: %s", cred_password);
-
- if (cred_username == NULL && cred_password == NULL &&
- get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) {
- wpa_printf(MSG_INFO, "Using client certificate");
- os_snprintf(client_cert_buf, sizeof(client_cert_buf),
- "SP/%s/client-cert.pem", ctx->fqdn);
- client_cert = client_cert_buf;
- os_snprintf(client_key_buf, sizeof(client_key_buf),
- "SP/%s/client-key.pem", ctx->fqdn);
- client_key = client_key_buf;
- ctx->client_cert_present = 1;
- }
-
- node = get_child_node(ctx->xml, pps, "SubscriptionUpdate/URI");
- if (node) {
- sub_rem_uri = xml_node_get_text(ctx->xml, node);
- if (sub_rem_uri &&
- (!address || os_strcmp(address, sub_rem_uri) != 0)) {
- wpa_printf(MSG_INFO, "Override sub rem URI based on PPS: %s",
- sub_rem_uri);
- address = sub_rem_uri;
- }
- }
- if (!address) {
- wpa_printf(MSG_INFO, "Server URL not known");
- return -1;
- }
-
- write_summary(ctx, "Wait for IP address for subscriptiom remediation");
- wpa_printf(MSG_INFO, "Wait for IP address before starting subscription remediation");
-
- if (wait_ip_addr(ctx->ifname, 15) < 0) {
- wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
- }
-
- if (spp)
- spp_sub_rem(ctx, address, pps_fname,
- client_cert, client_key,
- cred_username, cred_password, pps);
- else
- oma_dm_sub_rem(ctx, address, pps_fname,
- client_cert, client_key,
- cred_username, cred_password, pps);
-
- xml_node_get_text_free(ctx->xml, sub_rem_uri);
- xml_node_get_text_free(ctx->xml, cred_username);
- str_clear_free(cred_password);
- xml_node_free(ctx->xml, pps);
- return 0;
-}
-
-
-static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname, const char *ca_fname)
-{
- xml_node_t *pps;
- xml_node_t *node;
- char pps_fname_buf[300];
- char ca_fname_buf[200];
- char *uri = NULL;
- char *cred_username = NULL;
- char *cred_password = NULL;
- char client_cert_buf[200];
- char *client_cert = NULL;
- char client_key_buf[200];
- char *client_key = NULL;
- int spp;
-
- wpa_printf(MSG_INFO, "Policy update requested");
-
- if (!pps_fname) {
- char buf[256];
- int res;
-
- wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
- if (address && os_strncmp(address, "fqdn=", 5) == 0) {
- wpa_printf(MSG_INFO, "Use requested FQDN from command line");
- os_snprintf(buf, sizeof(buf), "%s", address + 5);
- address = NULL;
- } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
- sizeof(buf)) < 0) {
- wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
- return -1;
- }
- os_free(ctx->fqdn);
- ctx->fqdn = os_strdup(buf);
- if (ctx->fqdn == NULL)
- return -1;
- wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
- buf);
- os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
- "SP/%s/pps.xml", ctx->fqdn);
- pps_fname = pps_fname_buf;
-
- res = os_snprintf(ca_fname_buf, sizeof(ca_fname_buf),
- "SP/%s/ca.pem", buf);
- if (os_snprintf_error(sizeof(ca_fname_buf), res)) {
- os_free(ctx->fqdn);
- ctx->fqdn = NULL;
- return -1;
- }
- ca_fname = ca_fname_buf;
- }
-
- if (!os_file_exists(pps_fname)) {
- wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
- pps_fname);
- return -1;
- }
- wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
-
- if (ca_fname && !os_file_exists(ca_fname)) {
- wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
- ca_fname);
- return -1;
- }
- wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
- ctx->ca_fname = ca_fname;
-
- pps = node_from_file(ctx->xml, pps_fname);
- if (pps == NULL) {
- wpa_printf(MSG_INFO, "Could not read PPS MO");
- return -1;
- }
-
- if (!ctx->fqdn) {
- char *tmp;
- node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
- if (node == NULL) {
- wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
- return -1;
- }
- tmp = xml_node_get_text(ctx->xml, node);
- if (tmp == NULL) {
- wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
- return -1;
- }
- ctx->fqdn = os_strdup(tmp);
- xml_node_get_text_free(ctx->xml, tmp);
- if (!ctx->fqdn) {
- wpa_printf(MSG_INFO, "No FQDN known");
- return -1;
- }
- }
-
- node = get_child_node(ctx->xml, pps,
- "Policy/PolicyUpdate/UpdateMethod");
- if (node) {
- char *tmp;
- tmp = xml_node_get_text(ctx->xml, node);
- if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0)
- spp = 0;
- else
- spp = 1;
- } else {
- wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP");
- spp = 1;
- }
-
- get_user_pw(ctx, pps, "Policy/PolicyUpdate/UsernamePassword",
- &cred_username, &cred_password);
- if (cred_username)
- wpa_printf(MSG_INFO, "Using username: %s", cred_username);
- if (cred_password)
- wpa_printf(MSG_DEBUG, "Using password: %s", cred_password);
-
- if (cred_username == NULL && cred_password == NULL &&
- get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) {
- wpa_printf(MSG_INFO, "Using client certificate");
- os_snprintf(client_cert_buf, sizeof(client_cert_buf),
- "SP/%s/client-cert.pem", ctx->fqdn);
- client_cert = client_cert_buf;
- os_snprintf(client_key_buf, sizeof(client_key_buf),
- "SP/%s/client-key.pem", ctx->fqdn);
- client_key = client_key_buf;
- }
-
- if (!address) {
- node = get_child_node(ctx->xml, pps, "Policy/PolicyUpdate/URI");
- if (node) {
- uri = xml_node_get_text(ctx->xml, node);
- wpa_printf(MSG_INFO, "URI based on PPS: %s", uri);
- address = uri;
- }
- }
- if (!address) {
- wpa_printf(MSG_INFO, "Server URL not known");
- return -1;
- }
-
- if (spp)
- spp_pol_upd(ctx, address, pps_fname,
- client_cert, client_key,
- cred_username, cred_password, pps);
- else
- oma_dm_pol_upd(ctx, address, pps_fname,
- client_cert, client_key,
- cred_username, cred_password, pps);
-
- xml_node_get_text_free(ctx->xml, uri);
- xml_node_get_text_free(ctx->xml, cred_username);
- str_clear_free(cred_password);
- xml_node_free(ctx->xml, pps);
-
- return 0;
-}
-
-
-static char * get_hostname(const char *url)
-{
- const char *pos, *end, *end2;
- char *ret;
-
- if (url == NULL)
- return NULL;
-
- pos = os_strchr(url, '/');
- if (pos == NULL)
- return NULL;
- pos++;
- if (*pos != '/')
- return NULL;
- pos++;
-
- end = os_strchr(pos, '/');
- end2 = os_strchr(pos, ':');
- if ((end && end2 && end2 < end) || (!end && end2))
- end = end2;
- if (end)
- end--;
- else {
- end = pos;
- while (*end)
- end++;
- if (end > pos)
- end--;
- }
-
- ret = os_malloc(end - pos + 2);
- if (ret == NULL)
- return NULL;
-
- os_memcpy(ret, pos, end - pos + 1);
- ret[end - pos + 1] = '\0';
-
- return ret;
-}
-
-
-static int osu_cert_cb(void *_ctx, struct http_cert *cert)
-{
- struct hs20_osu_client *ctx = _ctx;
- size_t i, j;
- int found;
- char *host = NULL;
-
- wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)",
- !ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A",
- ctx->server_url);
-
- if (ctx->no_osu_cert_validation && cert->url)
- host = get_hostname(cert->url);
- else
- host = get_hostname(ctx->server_url);
-
- if (!ctx->no_osu_cert_validation) {
- for (i = 0; i < ctx->server_dnsname_count; i++)
- os_free(ctx->server_dnsname[i]);
- os_free(ctx->server_dnsname);
- ctx->server_dnsname = os_calloc(cert->num_dnsname,
- sizeof(char *));
- ctx->server_dnsname_count = 0;
- }
-
- found = 0;
- for (i = 0; i < cert->num_dnsname; i++) {
- if (!ctx->no_osu_cert_validation && ctx->server_dnsname) {
- ctx->server_dnsname[ctx->server_dnsname_count] =
- os_strdup(cert->dnsname[i]);
- if (ctx->server_dnsname[ctx->server_dnsname_count])
- ctx->server_dnsname_count++;
- }
- if (host && os_strcasecmp(host, cert->dnsname[i]) == 0)
- found = 1;
- wpa_printf(MSG_INFO, "dNSName '%s'", cert->dnsname[i]);
- }
-
- if (host && !found) {
- wpa_printf(MSG_INFO, "Server name from URL (%s) did not match any dNSName - abort connection",
- host);
- write_result(ctx, "Server name from URL (%s) did not match any dNSName - abort connection",
- host);
- os_free(host);
- return -1;
- }
-
- os_free(host);
-
- for (i = 0; i < cert->num_othername; i++) {
- if (os_strcmp(cert->othername[i].oid,
- "1.3.6.1.4.1.40808.1.1.1") == 0) {
- wpa_hexdump_ascii(MSG_INFO,
- "id-wfa-hotspot-friendlyName",
- cert->othername[i].data,
- cert->othername[i].len);
- }
- }
-
- for (j = 0; !ctx->no_osu_cert_validation &&
- j < ctx->friendly_name_count; j++) {
- int found = 0;
- for (i = 0; i < cert->num_othername; i++) {
- if (os_strcmp(cert->othername[i].oid,
- "1.3.6.1.4.1.40808.1.1.1") != 0)
- continue;
- if (cert->othername[i].len < 3)
- continue;
- if (os_strncasecmp((char *) cert->othername[i].data,
- ctx->friendly_name[j].lang, 3) != 0)
- continue;
- if (os_strncmp((char *) cert->othername[i].data + 3,
- ctx->friendly_name[j].text,
- cert->othername[i].len - 3) == 0) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- wpa_printf(MSG_INFO, "No friendly name match found for '[%s]%s'",
- ctx->friendly_name[j].lang,
- ctx->friendly_name[j].text);
- write_result(ctx, "No friendly name match found for '[%s]%s'",
- ctx->friendly_name[j].lang,
- ctx->friendly_name[j].text);
- return -1;
- }
- }
-
- for (i = 0; i < cert->num_logo; i++) {
- struct http_logo *logo = &cert->logo[i];
-
- wpa_printf(MSG_INFO, "logo hash alg %s uri '%s'",
- logo->alg_oid, logo->uri);
- wpa_hexdump_ascii(MSG_INFO, "hashValue",
- logo->hash, logo->hash_len);
- }
-
- for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
- int found = 0;
- char *name = ctx->icon_filename[j];
- size_t name_len = os_strlen(name);
-
- wpa_printf(MSG_INFO,
- "[%zu] Looking for icon file name '%s' match",
- j, name);
- for (i = 0; i < cert->num_logo; i++) {
- struct http_logo *logo = &cert->logo[i];
- size_t uri_len = os_strlen(logo->uri);
- char *pos;
-
- wpa_printf(MSG_INFO,
- "[%zu] Comparing to '%s' uri_len=%d name_len=%d",
- i, logo->uri, (int) uri_len, (int) name_len);
- if (uri_len < 1 + name_len) {
- wpa_printf(MSG_INFO, "URI Length is too short");
- continue;
- }
- pos = &logo->uri[uri_len - name_len - 1];
- if (*pos != '/')
- continue;
- pos++;
- if (os_strcmp(pos, name) == 0) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- wpa_printf(MSG_INFO, "No icon filename match found for '%s'",
- name);
- write_result(ctx,
- "No icon filename match found for '%s'",
- name);
- return -1;
- }
- }
-
- for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
- int found = 0;
-
- for (i = 0; i < cert->num_logo; i++) {
- struct http_logo *logo = &cert->logo[i];
-
- if (logo->hash_len != 32) {
- wpa_printf(MSG_INFO,
- "[%zu][%zu] Icon hash length invalid (should be 32): %d",
- j, i, (int) logo->hash_len);
- continue;
- }
- if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
- found = 1;
- break;
- }
-
- wpa_printf(MSG_DEBUG,
- "[%zu][%zu] Icon hash did not match", j, i);
- wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
- logo->hash, 32);
- wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
- ctx->icon_hash[j], 32);
- }
-
- if (!found) {
- wpa_printf(MSG_INFO,
- "No icon hash match (by hash) found");
- write_result(ctx,
- "No icon hash match (by hash) found");
- return -1;
- }
- }
-
- return 0;
-}
-
-
static int init_ctx(struct hs20_osu_client *ctx)
{
- xml_node_t *devinfo, *devid;
-
os_memset(ctx, 0, sizeof(*ctx));
ctx->ifname = "wlan0";
ctx->xml = xml_node_init_ctx(ctx, NULL);
if (ctx->xml == NULL)
return -1;
- devinfo = node_from_file(ctx->xml, "devinfo.xml");
- if (devinfo) {
- devid = get_node(ctx->xml, devinfo, "DevId");
- if (devid) {
- char *tmp = xml_node_get_text(ctx->xml, devid);
-
- if (tmp) {
- ctx->devid = os_strdup(tmp);
- xml_node_get_text_free(ctx->xml, tmp);
- }
- }
- xml_node_free(ctx->xml, devinfo);
- }
-
ctx->http = http_init_ctx(ctx, ctx->xml);
if (ctx->http == NULL) {
xml_node_deinit_ctx(ctx->xml);
return -1;
}
http_ocsp_set(ctx->http, 2);
- http_set_cert_cb(ctx->http, osu_cert_cb, ctx);
return 0;
}
@@ -3156,17 +1431,8 @@
static void deinit_ctx(struct hs20_osu_client *ctx)
{
- size_t i;
-
http_deinit_ctx(ctx->http);
xml_node_deinit_ctx(ctx->xml);
- os_free(ctx->fqdn);
- os_free(ctx->server_url);
- os_free(ctx->devid);
-
- for (i = 0; i < ctx->server_dnsname_count; i++)
- os_free(ctx->server_dnsname[i]);
- os_free(ctx->server_dnsname);
}
@@ -3209,19 +1475,8 @@
"- from_tnds <XML MO in TNDS format> <XML MO>\n"
"- set_pps <PerProviderSubscription XML file name>\n"
"- get_fqdn <PerProviderSubscription XML file name>\n"
- "- pol_upd [Server URL] [PPS] [CA cert]\n"
- "- sub_rem <Server URL> [PPS] [CA cert]\n"
- "- prov <Server URL> [CA cert]\n"
- "- oma_dm_prov <Server URL> [CA cert]\n"
- "- sim_prov <Server URL> [CA cert]\n"
- "- oma_dm_sim_prov <Server URL> [CA cert]\n"
- "- signup [CA cert]\n"
- "- dl_osu_ca <PPS> <CA file>\n"
- "- dl_polupd_ca <PPS> <CA file>\n"
"- dl_aaa_ca <PPS> <CA file>\n"
- "- browser <URL>\n"
- "- parse_cert <X.509 certificate (DER)>\n"
- "- osu_select <OSU info directory> [CA cert]\n");
+ "- browser <URL>\n");
}
@@ -3230,8 +1485,6 @@
struct hs20_osu_client ctx;
int c;
int ret = 0;
- int no_prod_assoc = 0;
- const char *friendly_name = NULL;
const char *wpa_debug_file_path = NULL;
extern char *wpas_ctrl_path;
extern int wpa_debug_level;
@@ -3242,7 +1495,7 @@
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
+ c = getopt(argc, argv, "df:hKqr:s:S:tTw:");
if (c < 0)
break;
switch (c) {
@@ -3256,15 +1509,6 @@
case 'K':
wpa_debug_show_keys++;
break;
- case 'N':
- no_prod_assoc = 1;
- break;
- case 'o':
- ctx.osu_ssid = optarg;
- break;
- case 'O':
- friendly_name = optarg;
- break;
case 'q':
wpa_debug_level++;
break;
@@ -3286,9 +1530,6 @@
case 'w':
wpas_ctrl_path = optarg;
break;
- case 'x':
- spp_xsd_fname = optarg;
- break;
case 'h':
default:
usage();
@@ -3335,62 +1576,12 @@
exit(0);
}
cmd_from_tnds(&ctx, argv[optind + 1], argv[optind + 2]);
- } else if (strcmp(argv[optind], "sub_rem") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ret = cmd_sub_rem(&ctx, argv[optind + 1],
- argc > optind + 2 ? argv[optind + 2] : NULL,
- argc > optind + 3 ? argv[optind + 3] : NULL);
- } else if (strcmp(argv[optind], "pol_upd") == 0) {
- ret = cmd_pol_upd(&ctx,
- argc > optind + 1 ? argv[optind + 1] : NULL,
- argc > optind + 2 ? argv[optind + 2] : NULL,
- argc > optind + 3 ? argv[optind + 3] : NULL);
- } else if (strcmp(argv[optind], "prov") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ctx.ca_fname = argv[optind + 2];
- wpa_printf(MSG_DEBUG, "Calling cmd_prov from main");
- cmd_prov(&ctx, argv[optind + 1]);
- } else if (strcmp(argv[optind], "sim_prov") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ctx.ca_fname = argv[optind + 2];
- cmd_sim_prov(&ctx, argv[optind + 1]);
- } else if (strcmp(argv[optind], "dl_osu_ca") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- cmd_dl_osu_ca(&ctx, argv[optind + 1], argv[optind + 2]);
- } else if (strcmp(argv[optind], "dl_polupd_ca") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- cmd_dl_polupd_ca(&ctx, argv[optind + 1], argv[optind + 2]);
} else if (strcmp(argv[optind], "dl_aaa_ca") == 0) {
if (argc - optind < 2) {
usage();
exit(0);
}
cmd_dl_aaa_ca(&ctx, argv[optind + 1], argv[optind + 2]);
- } else if (strcmp(argv[optind], "osu_select") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ctx.ca_fname = argc > optind + 2 ? argv[optind + 2] : NULL;
- cmd_osu_select(&ctx, argv[optind + 1], 2, 1, NULL);
- } else if (strcmp(argv[optind], "signup") == 0) {
- ctx.ca_fname = argc > optind + 1 ? argv[optind + 1] : NULL;
- ret = cmd_signup(&ctx, no_prod_assoc, friendly_name);
} else if (strcmp(argv[optind], "set_pps") == 0) {
if (argc - optind < 2) {
usage();
@@ -3403,42 +1594,6 @@
exit(0);
}
ret = cmd_get_fqdn(&ctx, argv[optind + 1]);
- } else if (strcmp(argv[optind], "oma_dm_prov") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ctx.ca_fname = argv[optind + 2];
- cmd_oma_dm_prov(&ctx, argv[optind + 1]);
- } else if (strcmp(argv[optind], "oma_dm_sim_prov") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- ctx.ca_fname = argv[optind + 2];
- if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1]) < 0) {
- write_summary(&ctx, "Failed to complete OMA DM SIM provisioning");
- return -1;
- }
- } else if (strcmp(argv[optind], "oma_dm_add") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- cmd_oma_dm_add(&ctx, argv[optind + 1], argv[optind + 2]);
- } else if (strcmp(argv[optind], "oma_dm_replace") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- cmd_oma_dm_replace(&ctx, argv[optind + 1], argv[optind + 2]);
- } else if (strcmp(argv[optind], "est_csr") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
- mkdir("Cert", S_IRWXU);
- est_build_csr(&ctx, argv[optind + 1]);
} else if (strcmp(argv[optind], "browser") == 0) {
int ret;
@@ -3451,15 +1606,6 @@
argv[optind + 1]);
ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
wpa_printf(MSG_INFO, "Web browser result: %d", ret);
- } else if (strcmp(argv[optind], "parse_cert") == 0) {
- if (argc - optind < 2) {
- usage();
- exit(0);
- }
-
- wpa_debug_level = MSG_MSGDUMP;
- http_parse_x509_certificate(ctx.http, argv[optind + 1]);
- wpa_debug_level = MSG_INFO;
} else {
wpa_printf(MSG_INFO, "Unknown command '%s'", argv[optind]);
}
diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h
index 9b45b03..3bfbb0d 100644
--- a/hs20/client/osu_client.h
+++ b/hs20/client/osu_client.h
@@ -9,113 +9,16 @@
#ifndef OSU_CLIENT_H
#define OSU_CLIENT_H
-#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
-
-#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
-#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
-#define URN_HS20_DEVDETAIL_EXT "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0"
-#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
-
-
-#define MAX_OSU_VALS 10
-
-struct osu_lang_text {
- char lang[4];
- char text[253];
-};
-
struct hs20_osu_client {
struct xml_node_ctx *xml;
struct http_ctx *http;
- int no_reconnect;
- char pps_fname[300];
- char *devid;
const char *result_file;
const char *summary_file;
const char *ifname;
- const char *ca_fname;
- int no_osu_cert_validation; /* for EST operations */
- char *fqdn;
- char *server_url;
- struct osu_lang_text friendly_name[MAX_OSU_VALS];
- size_t friendly_name_count;
- size_t icon_count;
- char icon_filename[MAX_OSU_VALS][256];
- u8 icon_hash[MAX_OSU_VALS][32];
- int pps_cred_set;
- int pps_updated;
- int client_cert_present;
- char **server_dnsname;
- size_t server_dnsname_count;
- const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
unsigned long int workarounds;
int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
* server certificate */
};
-
-/* osu_client.c */
-
-void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
- __attribute__ ((format (printf, 2, 3)));
-void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
- __attribute__ ((format (printf, 2, 3)));
-
-void debug_dump_node(struct hs20_osu_client *ctx, const char *title,
- xml_node_t *node);
-int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert);
-int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
- xml_node_t *add_mo, char *fname, size_t fname_len);
-void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps,
- const char *alt_loc, char **user, char **pw);
-int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
- xml_node_t *pps);
-void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname);
-
-
-/* spp_client.c */
-
-void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps);
-void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps);
-int cmd_prov(struct hs20_osu_client *ctx, const char *url);
-int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url);
-
-
-/* oma_dm_client.c */
-
-int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url);
-int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url);
-void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps);
-void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps);
-void cmd_oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname);
-void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
- const char *add_fname);
-void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
- const char *replace_fname);
-
-/* est.c */
-
-int est_load_cacerts(struct hs20_osu_client *ctx, const char *url);
-int est_build_csr(struct hs20_osu_client *ctx, const char *url);
-int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
- const char *user, const char *pw);
-
#endif /* OSU_CLIENT_H */
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
deleted file mode 100644
index 194518e..0000000
--- a/hs20/client/spp_client.c
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * Hotspot 2.0 SPP client
- * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <sys/stat.h>
-
-#include "common.h"
-#include "browser.h"
-#include "wpa_ctrl.h"
-#include "wpa_helpers.h"
-#include "xml-utils.h"
-#include "http-utils.h"
-#include "utils/base64.h"
-#include "crypto/crypto.h"
-#include "crypto/sha256.h"
-#include "osu_client.h"
-
-
-extern const char *spp_xsd_fname;
-
-static int hs20_spp_update_response(struct hs20_osu_client *ctx,
- const char *session_id,
- const char *spp_status,
- const char *error_code);
-static void hs20_policy_update_complete(
- struct hs20_osu_client *ctx, const char *pps_fname);
-
-
-static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
- char *attr_name)
-{
- return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
-}
-
-
-static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
- const char *expected_name)
-{
- struct xml_node_ctx *xctx = ctx->xml;
- const char *name;
- char *err;
- int ret;
-
- if (!xml_node_is_element(xctx, node))
- return -1;
-
- name = xml_node_get_localname(xctx, node);
- if (name == NULL)
- return -1;
-
- if (strcmp(expected_name, name) != 0) {
- wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
- name, expected_name);
- write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
- name, expected_name);
- return -1;
- }
-
- ret = xml_validate(xctx, node, spp_xsd_fname, &err);
- if (ret < 0) {
- wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
- write_summary(ctx, "SPP XML schema validation failed");
- os_free(err);
- }
- return ret;
-}
-
-
-static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
- xml_node_t *parent, const char *urn,
- const char *fname)
-{
- xml_node_t *node;
- xml_node_t *fnode, *tnds;
- char *str;
-
- errno = 0;
- fnode = node_from_file(ctx, fname);
- if (!fnode) {
- wpa_printf(MSG_ERROR,
- "Failed to create XML node from file: %s, possible error: %s",
- fname, strerror(errno));
- return;
- }
- tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
- xml_node_free(ctx, fnode);
- if (!tnds)
- return;
-
- str = xml_node_to_str(ctx, tnds);
- xml_node_free(ctx, tnds);
- if (str == NULL)
- return;
-
- node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
- if (node)
- xml_node_add_attr(ctx, node, ns, "moURN", urn);
- os_free(str);
-}
-
-
-static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
- xml_namespace_t **ret_ns,
- const char *session_id,
- const char *reason)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node;
-
- write_summary(ctx, "Building sppPostDevData requestReason='%s'",
- reason);
- spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
- "sppPostDevData");
- if (spp_node == NULL)
- return NULL;
- if (ret_ns)
- *ret_ns = ns;
-
- xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
- xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
- if (session_id)
- xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
- session_id);
- xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
- "http://localhost:12345/");
-
- xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
- "1.0");
- xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
- URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
- URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
-
- add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
- "devinfo.xml");
- add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
- "devdetail.xml");
-
- return spp_node;
-}
-
-
-static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
- xml_node_t *update)
-{
- xml_node_t *node, *parent, *tnds, *unode;
- char *str;
- const char *name;
- char *uri, *pos;
- char *cdata, *cdata_end;
- size_t fqdn_len;
-
- wpa_printf(MSG_INFO, "Processing updateNode");
- debug_dump_node(ctx, "updateNode", update);
-
- uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
- if (uri == NULL) {
- wpa_printf(MSG_INFO, "No managementTreeURI present");
- return -1;
- }
- wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
-
- name = os_strrchr(uri, '/');
- if (name == NULL) {
- wpa_printf(MSG_INFO, "Unexpected URI");
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
- name++;
- wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
-
- str = xml_node_get_text(ctx->xml, update);
- if (str == NULL) {
- wpa_printf(MSG_INFO, "Could not extract MO text");
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
- cdata = strstr(str, "<![CDATA[");
- cdata_end = strstr(str, "]]>");
- if (cdata && cdata_end && cdata_end > cdata &&
- cdata < strstr(str, "MgmtTree") &&
- cdata_end > strstr(str, "/MgmtTree")) {
- char *tmp;
- wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
- tmp = strdup(cdata + 9);
- if (tmp) {
- cdata_end = strstr(tmp, "]]>");
- if (cdata_end)
- *cdata_end = '\0';
- wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
- tmp);
- tnds = xml_node_from_buf(ctx->xml, tmp);
- free(tmp);
- } else
- tnds = NULL;
- } else
- tnds = xml_node_from_buf(ctx->xml, str);
- xml_node_get_text_free(ctx->xml, str);
- if (tnds == NULL) {
- wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
-
- unode = tnds_to_mo(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (unode == NULL) {
- wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
-
- debug_dump_node(ctx, "Parsed TNDS", unode);
-
- if (get_node_uri(ctx->xml, unode, name) == NULL) {
- wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
- xml_node_free(ctx->xml, unode);
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
-
- if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
- wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
- xml_node_free(ctx->xml, unode);
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
- pos = uri + 8;
-
- if (ctx->fqdn == NULL) {
- wpa_printf(MSG_INFO, "FQDN not known");
- xml_node_free(ctx->xml, unode);
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
- fqdn_len = os_strlen(ctx->fqdn);
- if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
- pos[fqdn_len] != '/') {
- wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
- ctx->fqdn);
- xml_node_free(ctx->xml, unode);
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
- pos += fqdn_len + 1;
-
- if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
- wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
- ctx->fqdn);
- xml_node_free(ctx->xml, unode);
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
- pos += 24;
-
- wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
-
- node = get_node(ctx->xml, pps, pos);
- if (node) {
- parent = xml_node_get_parent(ctx->xml, node);
- xml_node_detach(ctx->xml, node);
- wpa_printf(MSG_INFO, "Replace '%s' node", name);
- } else {
- char *pos2;
- pos2 = os_strrchr(pos, '/');
- if (pos2 == NULL) {
- parent = pps;
- } else {
- *pos2 = '\0';
- parent = get_node(ctx->xml, pps, pos);
- }
- if (parent == NULL) {
- wpa_printf(MSG_INFO, "Could not find parent %s", pos);
- xml_node_free(ctx->xml, unode);
- xml_node_get_attr_value_free(ctx->xml, uri);
- return -1;
- }
- wpa_printf(MSG_INFO, "Add '%s' node", name);
- }
- xml_node_add_child(ctx->xml, parent, unode);
-
- xml_node_get_attr_value_free(ctx->xml, uri);
-
- return 0;
-}
-
-
-static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
- const char *pps_fname, xml_node_t *pps)
-{
- wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
- xml_node_for_each_sibling(ctx->xml, update) {
- xml_node_for_each_check(ctx->xml, update);
- if (process_update_node(ctx, pps, update) < 0)
- return -1;
- }
-
- return update_pps_file(ctx, pps_fname, pps);
-}
-
-
-static void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
- const char *pps_fname)
-{
- /*
- * Update wpa_supplicant credentials and reconnect using updated
- * information.
- */
- wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
- cmd_set_pps(ctx, pps_fname);
-
- if (ctx->no_reconnect)
- return;
-
- wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
- if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
- wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
-}
-
-
-static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
- xml_node_t *cmd,
- const char *session_id,
- const char *pps_fname)
-{
- xml_namespace_t *ns;
- xml_node_t *node, *ret_node;
- char *urn;
-
- urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
- if (!urn) {
- wpa_printf(MSG_INFO, "No URN included");
- return NULL;
- }
- wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
- if (strcasecmp(urn, URN_HS20_PPS) != 0) {
- wpa_printf(MSG_INFO, "Unsupported moURN");
- xml_node_get_attr_value_free(ctx->xml, urn);
- return NULL;
- }
- xml_node_get_attr_value_free(ctx->xml, urn);
-
- if (!pps_fname) {
- wpa_printf(MSG_INFO, "PPS file name no known");
- return NULL;
- }
-
- node = build_spp_post_dev_data(ctx, &ns, session_id,
- "MO upload");
- if (node == NULL)
- return NULL;
- add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
-
- ret_node = soap_send_receive(ctx->http, node);
- if (ret_node == NULL)
- return NULL;
-
- debug_dump_node(ctx, "Received response to MO upload", ret_node);
-
- if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
- wpa_printf(MSG_INFO, "SPP validation failed");
- xml_node_free(ctx->xml, ret_node);
- return NULL;
- }
-
- return ret_node;
-}
-
-
-static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
- char *fname, size_t fname_len)
-{
- char *uri, *urn;
- int ret;
-
- debug_dump_node(ctx, "Received addMO", add_mo);
-
- urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
- if (urn == NULL) {
- wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
- return -1;
- }
- wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
- if (strcasecmp(urn, URN_HS20_PPS) != 0) {
- wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
- xml_node_get_attr_value_free(ctx->xml, urn);
- return -1;
- }
- xml_node_get_attr_value_free(ctx->xml, urn);
-
- uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
- if (uri == NULL) {
- wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
- return -1;
- }
- wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
-
- ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
- xml_node_get_attr_value_free(ctx->xml, uri);
- return ret;
-}
-
-
-static int process_spp_user_input_response(struct hs20_osu_client *ctx,
- const char *session_id,
- xml_node_t *add_mo)
-{
- int ret;
- char fname[300];
-
- debug_dump_node(ctx, "addMO", add_mo);
-
- wpa_printf(MSG_INFO, "Subscription registration completed");
-
- if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
- wpa_printf(MSG_INFO, "Could not add MO");
- ret = hs20_spp_update_response(
- ctx, session_id,
- "Error occurred",
- "MO addition or update failed");
- return 0;
- }
-
- ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
- if (ret == 0)
- hs20_sub_rem_complete(ctx, fname);
-
- return 0;
-}
-
-
-static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
- const char *session_id)
-{
- xml_node_t *node, *ret_node;
-
- node = build_spp_post_dev_data(ctx, NULL, session_id,
- "User input completed");
- if (node == NULL)
- return NULL;
-
- ret_node = soap_send_receive(ctx->http, node);
- if (!ret_node) {
- if (soap_reinit_client(ctx->http) < 0)
- return NULL;
- wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
- node = build_spp_post_dev_data(ctx, NULL, session_id,
- "User input completed");
- if (node == NULL)
- return NULL;
- ret_node = soap_send_receive(ctx->http, node);
- if (ret_node == NULL)
- return NULL;
- wpa_printf(MSG_INFO, "Continue with new connection");
- }
-
- if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
- wpa_printf(MSG_INFO, "SPP validation failed");
- xml_node_free(ctx->xml, ret_node);
- return NULL;
- }
-
- return ret_node;
-}
-
-
-static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
- xml_node_t *cmd,
- const char *session_id,
- const char *pps_fname)
-{
- xml_namespace_t *ns;
- xml_node_t *node, *ret_node;
- int res;
-
- wpa_printf(MSG_INFO, "Client certificate enrollment");
-
- res = osu_get_certificate(ctx, cmd);
- if (res < 0)
- wpa_printf(MSG_INFO, "EST simpleEnroll failed");
-
- node = build_spp_post_dev_data(ctx, &ns, session_id,
- res == 0 ?
- "Certificate enrollment completed" :
- "Certificate enrollment failed");
- if (node == NULL)
- return NULL;
-
- ret_node = soap_send_receive(ctx->http, node);
- if (ret_node == NULL)
- return NULL;
-
- debug_dump_node(ctx, "Received response to certificate enrollment "
- "completed", ret_node);
-
- if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
- wpa_printf(MSG_INFO, "SPP validation failed");
- xml_node_free(ctx->xml, ret_node);
- return NULL;
- }
-
- return ret_node;
-}
-
-
-static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
- const char *session_id, const char *pps_fname,
- xml_node_t *pps, xml_node_t **ret_node)
-{
- xml_node_t *cmd;
- const char *name;
- char *uri;
- char *id = strdup(session_id);
-
- if (id == NULL)
- return -1;
-
- *ret_node = NULL;
-
- debug_dump_node(ctx, "exec", exec);
-
- xml_node_for_each_child(ctx->xml, cmd, exec) {
- xml_node_for_each_check(ctx->xml, cmd);
- break;
- }
- if (!cmd) {
- wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
- cmd);
- free(id);
- return -1;
- }
-
- name = xml_node_get_localname(ctx->xml, cmd);
-
- if (strcasecmp(name, "launchBrowserToURI") == 0) {
- int res;
- uri = xml_node_get_text(ctx->xml, cmd);
- if (!uri) {
- wpa_printf(MSG_INFO, "No URI found");
- free(id);
- return -1;
- }
- wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
- write_summary(ctx, "Launch browser to URI '%s'", uri);
- res = hs20_web_browser(uri, 1);
- xml_node_get_text_free(ctx->xml, uri);
- if (res > 0) {
- wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
- id);
- write_summary(ctx, "User response in browser completed successfully");
- *ret_node = hs20_spp_user_input_completed(ctx, id);
- free(id);
- return *ret_node ? 0 : -1;
- } else {
- wpa_printf(MSG_INFO, "Failed to receive user response");
- write_summary(ctx, "Failed to receive user response");
- hs20_spp_update_response(
- ctx, id, "Error occurred", "Other");
- free(id);
- return -1;
- }
- }
-
- if (strcasecmp(name, "uploadMO") == 0) {
- if (pps_fname == NULL)
- return -1;
- *ret_node = hs20_spp_upload_mo(ctx, cmd, id,
- pps_fname);
- free(id);
- return *ret_node ? 0 : -1;
- }
-
- if (strcasecmp(name, "getCertificate") == 0) {
- *ret_node = hs20_spp_get_certificate(ctx, cmd, id,
- pps_fname);
- free(id);
- return *ret_node ? 0 : -1;
- }
-
- wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
- free(id);
- return -1;
-}
-
-
-enum spp_post_dev_data_use {
- SPP_SUBSCRIPTION_REMEDIATION,
- SPP_POLICY_UPDATE,
- SPP_SUBSCRIPTION_REGISTRATION,
-};
-
-static void process_spp_post_dev_data_response(
- struct hs20_osu_client *ctx,
- enum spp_post_dev_data_use use, xml_node_t *node,
- const char *pps_fname, xml_node_t *pps)
-{
- xml_node_t *child;
- char *status = NULL;
- xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
- char *session_id = NULL;
-
- debug_dump_node(ctx, "sppPostDevDataResponse node", node);
-
- status = get_spp_attr_value(ctx->xml, node, "sppStatus");
- if (status == NULL) {
- wpa_printf(MSG_INFO, "No sppStatus attribute");
- goto out;
- }
- write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
- status);
-
- session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
- if (session_id == NULL) {
- wpa_printf(MSG_INFO, "No sessionID attribute");
- goto out;
- }
-
- wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s' sessionID: '%s'",
- status, session_id);
-
- xml_node_for_each_child(ctx->xml, child, node) {
- const char *name;
- xml_node_for_each_check(ctx->xml, child);
- debug_dump_node(ctx, "child", child);
- name = xml_node_get_localname(ctx->xml, child);
- wpa_printf(MSG_INFO, "localname: '%s'", name);
- if (!update && strcasecmp(name, "updateNode") == 0)
- update = child;
- if (!exec && strcasecmp(name, "exec") == 0)
- exec = child;
- if (!add_mo && strcasecmp(name, "addMO") == 0)
- add_mo = child;
- if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
- no_mo = child;
- }
-
- if (use == SPP_SUBSCRIPTION_REMEDIATION &&
- strcasecmp(status,
- "Remediation complete, request sppUpdateResponse") == 0)
- {
- int res, ret;
- if (!update && !no_mo) {
- wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
- goto out;
- }
- wpa_printf(MSG_INFO, "Subscription remediation completed");
- res = update_pps(ctx, update, pps_fname, pps);
- if (res < 0)
- wpa_printf(MSG_INFO, "Failed to update PPS MO");
- ret = hs20_spp_update_response(
- ctx, session_id,
- res < 0 ? "Error occurred" : "OK",
- res < 0 ? "MO addition or update failed" : NULL);
- if (res == 0 && ret == 0)
- hs20_sub_rem_complete(ctx, pps_fname);
- goto out;
- }
-
- if (use == SPP_SUBSCRIPTION_REMEDIATION &&
- strcasecmp(status, "Exchange complete, release TLS connection") ==
- 0) {
- if (!no_mo) {
- wpa_printf(MSG_INFO, "No noMOUpdate element");
- goto out;
- }
- wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
- goto out;
- }
-
- if (use == SPP_POLICY_UPDATE &&
- strcasecmp(status, "Update complete, request sppUpdateResponse") ==
- 0) {
- int res, ret;
- wpa_printf(MSG_INFO, "Policy update received - update PPS");
- res = update_pps(ctx, update, pps_fname, pps);
- ret = hs20_spp_update_response(
- ctx, session_id,
- res < 0 ? "Error occurred" : "OK",
- res < 0 ? "MO addition or update failed" : NULL);
- if (res == 0 && ret == 0)
- hs20_policy_update_complete(ctx, pps_fname);
- goto out;
- }
-
- if (use == SPP_SUBSCRIPTION_REGISTRATION &&
- strcasecmp(status, "Provisioning complete, request "
- "sppUpdateResponse") == 0) {
- if (!add_mo) {
- wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
- goto out;
- }
- process_spp_user_input_response(ctx, session_id, add_mo);
- node = NULL;
- goto out;
- }
-
- if (strcasecmp(status, "No update available at this time") == 0) {
- wpa_printf(MSG_INFO, "No update available at this time");
- goto out;
- }
-
- if (strcasecmp(status, "OK") == 0) {
- int res;
- xml_node_t *ret;
-
- if (!exec) {
- wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
- goto out;
- }
- res = hs20_spp_exec(ctx, exec, session_id,
- pps_fname, pps, &ret);
- /* xml_node_free(ctx->xml, node); */
- node = NULL;
- if (res == 0 && ret)
- process_spp_post_dev_data_response(ctx, use,
- ret, pps_fname, pps);
- goto out;
- }
-
- if (strcasecmp(status, "Error occurred") == 0) {
- xml_node_t *err;
- char *code = NULL;
- err = get_node(ctx->xml, node, "sppError");
- if (err)
- code = xml_node_get_attr_value(ctx->xml, err,
- "errorCode");
- wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
- code ? code : "N/A");
- xml_node_get_attr_value_free(ctx->xml, code);
- goto out;
- }
-
- wpa_printf(MSG_INFO,
- "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
- status);
-out:
- xml_node_get_attr_value_free(ctx->xml, status);
- xml_node_get_attr_value_free(ctx->xml, session_id);
- xml_node_free(ctx->xml, node);
-}
-
-
-static int spp_post_dev_data(struct hs20_osu_client *ctx,
- enum spp_post_dev_data_use use,
- const char *reason,
- const char *pps_fname, xml_node_t *pps)
-{
- xml_node_t *payload;
- xml_node_t *ret_node;
-
- payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
- if (payload == NULL)
- return -1;
-
- ret_node = soap_send_receive(ctx->http, payload);
- if (!ret_node) {
- const char *err = http_get_err(ctx->http);
- if (err) {
- wpa_printf(MSG_INFO, "HTTP error: %s", err);
- write_result(ctx, "HTTP error: %s", err);
- } else {
- write_summary(ctx, "Failed to send SOAP message");
- }
- return -1;
- }
-
- if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
- wpa_printf(MSG_INFO, "SPP validation failed");
- xml_node_free(ctx->xml, ret_node);
- return -1;
- }
-
- process_spp_post_dev_data_response(ctx, use, ret_node,
- pps_fname, pps);
- return 0;
-}
-
-
-void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps)
-{
- wpa_printf(MSG_INFO, "SPP subscription remediation");
- write_summary(ctx, "SPP subscription remediation");
-
- os_free(ctx->server_url);
- ctx->server_url = os_strdup(address);
-
- if (soap_init_client(ctx->http, address, ctx->ca_fname,
- cred_username, cred_password, client_cert,
- client_key) == 0) {
- spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
- "Subscription remediation", pps_fname, pps);
- }
-}
-
-
-static void hs20_policy_update_complete(struct hs20_osu_client *ctx,
- const char *pps_fname)
-{
- wpa_printf(MSG_INFO, "Policy update completed");
-
- /*
- * Update wpa_supplicant credentials and reconnect using updated
- * information.
- */
- wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
- cmd_set_pps(ctx, pps_fname);
-
- wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
- if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
- wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
-}
-
-
-static int process_spp_exchange_complete(struct hs20_osu_client *ctx,
- xml_node_t *node)
-{
- char *status, *session_id;
-
- debug_dump_node(ctx, "sppExchangeComplete", node);
-
- status = get_spp_attr_value(ctx->xml, node, "sppStatus");
- if (status == NULL) {
- wpa_printf(MSG_INFO, "No sppStatus attribute");
- return -1;
- }
- write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
- status);
-
- session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
- if (session_id == NULL) {
- wpa_printf(MSG_INFO, "No sessionID attribute");
- xml_node_get_attr_value_free(ctx->xml, status);
- return -1;
- }
-
- wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s' sessionID: '%s'",
- status, session_id);
- xml_node_get_attr_value_free(ctx->xml, session_id);
-
- if (strcasecmp(status, "Exchange complete, release TLS connection") ==
- 0) {
- xml_node_get_attr_value_free(ctx->xml, status);
- return 0;
- }
-
- wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
- write_summary(ctx, "Unexpected sppStatus '%s'", status);
- xml_node_get_attr_value_free(ctx->xml, status);
- return -1;
-}
-
-
-static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
- const char *session_id,
- const char *spp_status,
- const char *error_code)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *node;
-
- spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
- "sppUpdateResponse");
- if (spp_node == NULL)
- return NULL;
-
- xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
- xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
- xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
-
- if (error_code) {
- node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
- if (node)
- xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
- error_code);
- }
-
- return spp_node;
-}
-
-
-static int hs20_spp_update_response(struct hs20_osu_client *ctx,
- const char *session_id,
- const char *spp_status,
- const char *error_code)
-{
- xml_node_t *node, *ret_node;
- int ret;
-
- write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
- spp_status, error_code);
- node = build_spp_update_response(ctx, session_id, spp_status,
- error_code);
- if (node == NULL)
- return -1;
- ret_node = soap_send_receive(ctx->http, node);
- if (!ret_node) {
- if (soap_reinit_client(ctx->http) < 0)
- return -1;
- wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
- node = build_spp_update_response(ctx, session_id, spp_status,
- error_code);
- if (node == NULL)
- return -1;
- ret_node = soap_send_receive(ctx->http, node);
- if (ret_node == NULL)
- return -1;
- wpa_printf(MSG_INFO, "Continue with new connection");
- }
-
- if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
- wpa_printf(MSG_INFO, "SPP validation failed");
- xml_node_free(ctx->xml, ret_node);
- return -1;
- }
-
- ret = process_spp_exchange_complete(ctx, ret_node);
- xml_node_free(ctx->xml, ret_node);
- return ret;
-}
-
-
-void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname,
- const char *client_cert, const char *client_key,
- const char *cred_username, const char *cred_password,
- xml_node_t *pps)
-{
- wpa_printf(MSG_INFO, "SPP policy update");
- write_summary(ctx, "SPP policy update");
-
- os_free(ctx->server_url);
- ctx->server_url = os_strdup(address);
-
- if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
- cred_password, client_cert, client_key) == 0) {
- spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
- pps_fname, pps);
- }
-}
-
-
-int cmd_prov(struct hs20_osu_client *ctx, const char *url)
-{
- unlink("Cert/est_cert.der");
- unlink("Cert/est_cert.pem");
-
- if (url == NULL) {
- wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
- return -1;
- }
-
- wpa_printf(MSG_INFO,
- "Credential provisioning requested - URL: %s ca_fname: %s",
- url, ctx->ca_fname ? ctx->ca_fname : "N/A");
-
- os_free(ctx->server_url);
- ctx->server_url = os_strdup(url);
-
- if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
- NULL) < 0)
- return -1;
- spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
- "Subscription registration", NULL, NULL);
-
- return ctx->pps_cred_set ? 0 : -1;
-}
-
-
-int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
-{
- if (url == NULL) {
- wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
- return -1;
- }
-
- wpa_printf(MSG_INFO, "SIM provisioning requested");
-
- os_free(ctx->server_url);
- ctx->server_url = os_strdup(url);
-
- wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
-
- if (wait_ip_addr(ctx->ifname, 15) < 0) {
- wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
- }
-
- if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
- NULL) < 0)
- return -1;
- spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
- "Subscription provisioning", NULL, NULL);
-
- return ctx->pps_cred_set ? 0 : -1;
-}
diff --git a/hs20/server/.gitignore b/hs20/server/.gitignore
deleted file mode 100644
index fecb096..0000000
--- a/hs20/server/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-hs20_spp_server
diff --git a/hs20/server/Makefile b/hs20/server/Makefile
deleted file mode 100644
index 0cab6d6..0000000
--- a/hs20/server/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-ALL=hs20_spp_server
-
-include ../../src/build.rules
-
-CFLAGS += -I../../src
-CFLAGS += -I../../src/utils
-CFLAGS += -I../../src/crypto
-
-LIBS += -lsqlite3
-
-# Using glibc < 2.17 requires -lrt for clock_gettime()
-LIBS += -lrt
-
-ifndef CONFIG_NO_GITVER
-# Add VERSION_STR postfix for builds from a git repository
-ifeq ($(wildcard ../../.git),../../.git)
-GITVER := $(shell git describe --dirty=+)
-ifneq ($(GITVER),)
-CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
-endif
-endif
-endif
-
-OBJS=spp_server.o
-OBJS += hs20_spp_server.o
-OBJS += ../../src/utils/xml-utils.o
-OBJS += ../../src/utils/base64.o
-OBJS += ../../src/utils/common.o
-OBJS += ../../src/utils/os_unix.o
-OBJS += ../../src/utils/wpa_debug.o
-OBJS += ../../src/crypto/md5-internal.o
-CFLAGS += $(shell xml2-config --cflags)
-LIBS += $(shell xml2-config --libs)
-OBJS += ../../src/utils/xml_libxml2.o
-
-_OBJS_VAR := OBJS
-include ../../src/objs.mk
-hs20_spp_server: $(OBJS)
- $(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS)
-
-clean: common-clean
- rm -f core *~
diff --git a/hs20/server/ca/clean.sh b/hs20/server/ca/clean.sh
deleted file mode 100755
index c72dcbd..0000000
--- a/hs20/server/ca/clean.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-
-for i in server-client server server-revoked user ocsp; do
- rm -f $i.csr $i.key $i.pem
-done
-
-rm -f openssl.cnf.tmp
-if [ -d demoCA ]; then
- rm -r demoCA
-fi
-rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der
-rm -f my-openssl.cnf my-openssl-root.cnf
-#rm -r rootCA
diff --git a/hs20/server/ca/est-csrattrs.cnf b/hs20/server/ca/est-csrattrs.cnf
deleted file mode 100644
index b50ea00..0000000
--- a/hs20/server/ca/est-csrattrs.cnf
+++ /dev/null
@@ -1,17 +0,0 @@
-asn1 = SEQUENCE:attrs
-
-[attrs]
-#oid1 = OID:challengePassword
-attr1 = SEQUENCE:extreq
-oid2 = OID:sha256WithRSAEncryption
-
-[extreq]
-oid = OID:extensionRequest
-vals = SET:extreqvals
-
-[extreqvals]
-
-oid1 = OID:macAddress
-#oid2 = OID:imei
-#oid3 = OID:meid
-#oid4 = OID:DevId
diff --git a/hs20/server/ca/est-csrattrs.sh b/hs20/server/ca/est-csrattrs.sh
deleted file mode 100644
index 0b73a04..0000000
--- a/hs20/server/ca/est-csrattrs.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-openssl asn1parse -genconf est-csrattrs.cnf -out est-csrattrs.der -oid hs20.oid
-base64 est-csrattrs.der > est-attrs.b64
diff --git a/hs20/server/ca/hs20.oid b/hs20/server/ca/hs20.oid
deleted file mode 100644
index a829ff2..0000000
--- a/hs20/server/ca/hs20.oid
+++ /dev/null
@@ -1,7 +0,0 @@
-1.3.6.1.1.1.1.22 macAddress
-1.2.840.113549.1.9.14 extensionRequest
-1.3.6.1.4.1.40808.1.1.1 id-wfa-hotspot-friendlyName
-1.3.6.1.4.1.40808.1.1.2 id-kp-HS2.0Auth
-1.3.6.1.4.1.40808.1.1.3 imei
-1.3.6.1.4.1.40808.1.1.4 meid
-1.3.6.1.4.1.40808.1.1.5 DevId
diff --git a/hs20/server/ca/ocsp-req.sh b/hs20/server/ca/ocsp-req.sh
deleted file mode 100644
index 931a206..0000000
--- a/hs20/server/ca/ocsp-req.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-for i in *.pem; do
- echo "===[ $i ]==================="
- openssl ocsp -text -CAfile ca.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
-
-# openssl ocsp -text -CAfile rootCA/cacert.pem -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
-
-# openssl ocsp -text -CAfile rootCA/cacert.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
-# openssl ocsp -text -CAfile rootCA/cacert.pem -VAfile ca.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/
-done
diff --git a/hs20/server/ca/ocsp-responder-ica.sh b/hs20/server/ca/ocsp-responder-ica.sh
deleted file mode 100644
index 116c6e1..0000000
--- a/hs20/server/ca/ocsp-responder-ica.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner demoCA/cacert.pem -rkey demoCA/private/cakey-plain.pem -CA demoCA/cacert.pem -resp_no_certs -text
diff --git a/hs20/server/ca/ocsp-responder.sh b/hs20/server/ca/ocsp-responder.sh
deleted file mode 100644
index 620947d..0000000
--- a/hs20/server/ca/ocsp-responder.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err
diff --git a/hs20/server/ca/ocsp-update-cache.sh b/hs20/server/ca/ocsp-update-cache.sh
deleted file mode 100644
index f2b2325..0000000
--- a/hs20/server/ca/ocsp-update-cache.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-# NOTE: You may need to replace 'localhost' with your OCSP server hostname.
-openssl ocsp \
- -no_nonce \
- -CAfile ca.pem \
- -verify_other demoCA/cacert.pem \
- -issuer demoCA/cacert.pem \
- -cert server.pem \
- -url http://localhost:8888/ \
- -respout ocsp-server-cache.der
diff --git a/hs20/server/ca/openssl-root.cnf b/hs20/server/ca/openssl-root.cnf
deleted file mode 100644
index 5bc50be..0000000
--- a/hs20/server/ca/openssl-root.cnf
+++ /dev/null
@@ -1,125 +0,0 @@
-# OpenSSL configuration file for Hotspot 2.0 PKI (Root CA)
-
-HOME = .
-RANDFILE = $ENV::HOME/.rnd
-oid_section = new_oids
-
-[ new_oids ]
-
-#logotypeoid=1.3.6.1.5.5.7.1.12
-
-####################################################################
-[ ca ]
-default_ca = CA_default # The default ca section
-
-####################################################################
-[ CA_default ]
-
-dir = ./rootCA # Where everything is kept
-certs = $dir/certs # Where the issued certs are kept
-crl_dir = $dir/crl # Where the issued crl are kept
-database = $dir/index.txt # database index file.
-#unique_subject = no # Set to 'no' to allow creation of
- # several certificates with same subject
-new_certs_dir = $dir/newcerts # default place for new certs.
-
-certificate = $dir/cacert.pem # The CA certificate
-serial = $dir/serial # The current serial number
-crlnumber = $dir/crlnumber # the current crl number
- # must be commented out to leave a V1 CRL
-crl = $dir/crl.pem # The current CRL
-private_key = $dir/private/cakey.pem# The private key
-RANDFILE = $dir/private/.rand # private random number file
-
-x509_extensions = usr_cert # The extentions to add to the cert
-
-name_opt = ca_default # Subject Name options
-cert_opt = ca_default # Certificate field options
-
-default_days = 365 # how long to certify for
-default_crl_days= 30 # how long before next CRL
-default_md = default # use public key default MD
-preserve = no # keep passed DN ordering
-
-policy = policy_match
-
-# For the CA policy
-[ policy_match ]
-countryName = match
-stateOrProvinceName = optional
-organizationName = match
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-[ policy_anything ]
-countryName = optional
-stateOrProvinceName = optional
-localityName = optional
-organizationName = optional
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-####################################################################
-[ req ]
-default_bits = 2048
-default_keyfile = privkey.pem
-distinguished_name = req_distinguished_name
-attributes = req_attributes
-x509_extensions = v3_ca # The extentions to add to the self signed cert
-
-input_password = @PASSWORD@
-output_password = @PASSWORD@
-
-string_mask = utf8only
-
-[ req_distinguished_name ]
-countryName = Country Name (2 letter code)
-countryName_default = US
-countryName_min = 2
-countryName_max = 2
-
-localityName = Locality Name (eg, city)
-localityName_default = Tuusula
-
-0.organizationName = Organization Name (eg, company)
-0.organizationName_default = WFA Hotspot 2.0
-
-##organizationalUnitName = Organizational Unit Name (eg, section)
-#organizationalUnitName_default =
-#@OU@
-
-commonName = Common Name (e.g. server FQDN or YOUR name)
-#@CN@
-commonName_max = 64
-
-emailAddress = Email Address
-emailAddress_max = 64
-
-[ req_attributes ]
-
-[ v3_req ]
-
-# Extensions to add to a certificate request
-basicConstraints = CA:FALSE
-keyUsage = nonRepudiation, digitalSignature, keyEncipherment
-subjectAltName=DNS:example.com,DNS:another.example.com
-
-[ v3_ca ]
-
-# Hotspot 2.0 PKI requirements
-subjectKeyIdentifier=hash
-basicConstraints = critical,CA:true
-keyUsage = critical, cRLSign, keyCertSign
-
-[ crl_ext ]
-
-# issuerAltName=issuer:copy
-authorityKeyIdentifier=keyid:always
-
-[ v3_OCSP ]
-
-basicConstraints = CA:FALSE
-keyUsage = nonRepudiation, digitalSignature, keyEncipherment
-extendedKeyUsage = OCSPSigning
diff --git a/hs20/server/ca/openssl.cnf b/hs20/server/ca/openssl.cnf
deleted file mode 100644
index 6141013..0000000
--- a/hs20/server/ca/openssl.cnf
+++ /dev/null
@@ -1,200 +0,0 @@
-# OpenSSL configuration file for Hotspot 2.0 PKI (Intermediate CA)
-
-HOME = .
-RANDFILE = $ENV::HOME/.rnd
-oid_section = new_oids
-
-[ new_oids ]
-
-#logotypeoid=1.3.6.1.5.5.7.1.12
-
-####################################################################
-[ ca ]
-default_ca = CA_default # The default ca section
-
-####################################################################
-[ CA_default ]
-
-dir = ./demoCA # Where everything is kept
-certs = $dir/certs # Where the issued certs are kept
-crl_dir = $dir/crl # Where the issued crl are kept
-database = $dir/index.txt # database index file.
-#unique_subject = no # Set to 'no' to allow creation of
- # several certificates with same subject
-new_certs_dir = $dir/newcerts # default place for new certs.
-
-certificate = $dir/cacert.pem # The CA certificate
-serial = $dir/serial # The current serial number
-crlnumber = $dir/crlnumber # the current crl number
- # must be commented out to leave a V1 CRL
-crl = $dir/crl.pem # The current CRL
-private_key = $dir/private/cakey.pem# The private key
-RANDFILE = $dir/private/.rand # private random number file
-
-x509_extensions = ext_client # The extentions to add to the cert
-
-name_opt = ca_default # Subject Name options
-cert_opt = ca_default # Certificate field options
-
-# Extension copying option: use with caution.
-copy_extensions = copy
-
-default_days = 365 # how long to certify for
-default_crl_days= 30 # how long before next CRL
-default_md = default # use public key default MD
-preserve = no # keep passed DN ordering
-
-policy = policy_match
-
-# For the CA policy
-[ policy_match ]
-countryName = supplied
-stateOrProvinceName = optional
-organizationName = supplied
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-[ policy_osu_server ]
-countryName = match
-stateOrProvinceName = optional
-organizationName = match
-organizationalUnitName = supplied
-commonName = supplied
-emailAddress = optional
-
-[ policy_anything ]
-countryName = optional
-stateOrProvinceName = optional
-localityName = optional
-organizationName = optional
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-####################################################################
-[ req ]
-default_bits = 2048
-default_keyfile = privkey.pem
-distinguished_name = req_distinguished_name
-attributes = req_attributes
-x509_extensions = v3_ca # The extentions to add to the self signed cert
-
-input_password = @PASSWORD@
-output_password = @PASSWORD@
-
-string_mask = utf8only
-
-[ req_distinguished_name ]
-countryName = Country Name (2 letter code)
-countryName_default = FI
-countryName_min = 2
-countryName_max = 2
-
-localityName = Locality Name (eg, city)
-localityName_default = Tuusula
-
-0.organizationName = Organization Name (eg, company)
-0.organizationName_default = @DOMAIN@
-
-##organizationalUnitName = Organizational Unit Name (eg, section)
-#organizationalUnitName_default =
-#@OU@
-
-commonName = Common Name (e.g. server FQDN or YOUR name)
-#@CN@
-commonName_max = 64
-
-emailAddress = Email Address
-emailAddress_max = 64
-
-[ req_attributes ]
-
-[ v3_ca ]
-
-# Hotspot 2.0 PKI requirements
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid:always,issuer
-basicConstraints = critical, CA:true, pathlen:0
-keyUsage = critical, cRLSign, keyCertSign
-authorityInfoAccess = OCSP;URI:@OCSP_URI@
-# For SP intermediate CA
-#subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU
-#nameConstraints=permitted;DNS:.@DOMAIN@
-#1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
-
-[ v3_osu_server ]
-
-basicConstraints = critical, CA:true, pathlen:0
-keyUsage = critical, keyEncipherment
-#@ALTNAME@
-
-#logotypeoid=ASN1:SEQUENCE:LogotypeExtn
-1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
-[LogotypeExtn]
-communityLogos=EXP:0,SEQUENCE:LogotypeInfo
-[LogotypeInfo]
-# note: implicit tag converted to explicit for CHOICE
-direct=EXP:0,SEQUENCE:LogotypeData
-[LogotypeData]
-image=SEQUENCE:LogotypeImage
-[LogotypeImage]
-imageDetails=SEQUENCE:LogotypeDetails
-imageInfo=SEQUENCE:LogotypeImageInfo
-[LogotypeDetails]
-mediaType=IA5STRING:image/png
-logotypeHash=SEQUENCE:HashAlgAndValues
-logotypeURI=SEQUENCE:URI
-[HashAlgAndValues]
-value1=SEQUENCE:HashAlgAndValueSHA256
-#value2=SEQUENCE:HashAlgAndValueSHA1
-[HashAlgAndValueSHA256]
-hashAlg=SEQUENCE:sha256_alg
-hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@
-[HashAlgAndValueSHA1]
-hashAlg=SEQUENCE:sha1_alg
-hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@
-[sha256_alg]
-algorithm=OID:sha256
-[sha1_alg]
-algorithm=OID:sha1
-[URI]
-uri=IA5STRING:@LOGO_URI@
-[LogotypeImageInfo]
-# default value color(1), component optional
-#type=IMP:0,INTEGER:1
-fileSize=INTEGER:7549
-xSize=INTEGER:128
-ySize=INTEGER:80
-language=IMP:4,IA5STRING:zxx
-
-[ crl_ext ]
-
-# issuerAltName=issuer:copy
-authorityKeyIdentifier=keyid:always
-
-[ v3_OCSP ]
-
-basicConstraints = CA:FALSE
-keyUsage = nonRepudiation, digitalSignature, keyEncipherment
-extendedKeyUsage = OCSPSigning
-
-[ ext_client ]
-
-basicConstraints=CA:FALSE
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid,issuer
-authorityInfoAccess = OCSP;URI:@OCSP_URI@
-#@ALTNAME@
-extendedKeyUsage = clientAuth
-
-[ ext_server ]
-
-# Hotspot 2.0 PKI requirements
-basicConstraints=critical, CA:FALSE
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid,issuer
-authorityInfoAccess = OCSP;URI:@OCSP_URI@
-#@ALTNAME@
-extendedKeyUsage = critical, serverAuth
-keyUsage = critical, keyEncipherment
diff --git a/hs20/server/ca/setup.sh b/hs20/server/ca/setup.sh
deleted file mode 100755
index 78abccc..0000000
--- a/hs20/server/ca/setup.sh
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/bin/sh
-
-if [ -z "$OPENSSL" ]; then
- OPENSSL=openssl
-fi
-export OPENSSL_CONF=$PWD/openssl.cnf
-PASS=whatever
-if [ -z "$DOMAIN" ]; then
- DOMAIN=w1.fi
-fi
-COMPANY=w1.fi
-OPER_ENG="engw1.fi TESTING USE"
-OPER_FI="finw1.fi TESTIKÄYTTÖ"
-CNR="Hotspot 2.0 Trust Root CA - 99"
-CNO="ocsp.$DOMAIN"
-CNV="osu-revoked.$DOMAIN"
-CNOC="osu-client.$DOMAIN"
-OSU_SERVER_HOSTNAME="osu.$DOMAIN"
-DEBUG=0
-OCSP_URI="http://$CNO:8888/"
-LOGO_URI="http://osu.w1.fi/w1fi_logo.png"
-LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d"
-LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b"
-
-# Command line overrides
-USAGE=$( cat <<EOF
-Usage:\n
-# -c: Company name, used to generate Subject name CN for Intermediate CA\n
-# -C: Subject name CN of the Root CA ($CNR)\n
-# -D: Enable debugging (set -x, etc)\n
-# -g: Logo sha1 hash ($LOGO_HASH1)\n
-# -G: Logo sha256 hash ($LOGO_HASH256)\n
-# -h: Show this help message\n
-# -l: Logo URI ($LOGO_URI)\n
-# -m: Domain ($DOMAIN)\n
-# -o: Subject name CN for OSU-Client Server ($CNOC)\n
-# -O: Subject name CN for OCSP Server ($CNO)\n
-# -p: passphrase for private keys ($PASS)\n
-# -r: Operator-english ($OPER_ENG)\n
-# -R: Operator-finish ($OPER_FI)\n
-# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n
-# -u: OCSP-URI ($OCSP_URI)\n
-# -V: Subject name CN for OSU-Revoked Server ($CNV)\n
-EOF
-)
-
-while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag
- do
- case $flag in
- c) COMPANY=$OPTARG;;
- C) CNR=$OPTARG;;
- D) DEBUG=1;;
- g) LOGO_HASH1=$OPTARG;;
- G) LOGO_HASH256=$OPTARG;;
- h) echo -e $USAGE; exit 0;;
- l) LOGO_URI=$OPTARG;;
- m) DOMAIN=$OPTARG;;
- o) CNOC=$OPTARG;;
- O) CNO=$OPTARG;;
- p) PASS=$OPTARG;;
- r) OPER_ENG=$OPTARG;;
- R) OPER_FI=$OPTARG;;
- S) OSU_SERVER_HOSTNAME=$OPTARG;;
- u) OCSP_URI=$OPTARG;;
- V) CNV=$OPTARG;;
- *) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;;
- esac
-done
-
-fail()
-{
- echo "$*"
- exit 1
-}
-
-echo
-echo "---[ Root CA ]----------------------------------------------------------"
-echo
-
-if [ $DEBUG = 1 ]
-then
- set -x
-fi
-
-# Set the passphrase and some other common config accordingly.
-cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \
- > my-openssl-root.cnf
-
-cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" |
-sed "s,@OCSP_URI@,$OCSP_URI," |
-sed "s,@LOGO_URI@,$LOGO_URI," |
-sed "s,@LOGO_HASH1@,$LOGO_HASH1," |
-sed "s,@LOGO_HASH256@,$LOGO_HASH256," |
-sed "s/@DOMAIN@/$DOMAIN/" \
- > my-openssl.cnf
-
-
-cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp
-mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private
-touch rootCA/index.txt
-if [ -e rootCA/private/cakey.pem ]; then
- echo " * Use existing Root CA"
-else
- echo " * Generate Root CA private key"
- $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key"
- echo " * Sign Root CA certificate"
- $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate"
- $OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER"
- sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint"
-fi
-if [ ! -e rootCA/crlnumber ]; then
- echo 00 > rootCA/crlnumber
-fi
-
-echo
-echo "---[ Intermediate CA ]--------------------------------------------------"
-echo
-
-cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
-mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private
-touch demoCA/index.txt
-if [ -e demoCA/private/cakey.pem ]; then
- echo " * Use existing Intermediate CA"
-else
- echo " * Generate Intermediate CA private key"
- $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -keyout demoCA/private/cakey.pem -out demoCA/careq.pem || fail "Failed to generate Intermediate CA private key"
- echo " * Sign Intermediate CA certificate"
- $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate"
- # horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin
- openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS
- $OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER."
- sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint"
-fi
-if [ ! -e demoCA/crlnumber ]; then
- echo 00 > demoCA/crlnumber
-fi
-
-echo
-echo "OCSP responder"
-echo
-
-cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem"
-
-echo
-echo "---[ Server - to be revoked ] ------------------------------------------"
-echo
-
-cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server
-$OPENSSL ca -revoke server-revoked.pem -key $PASS
-
-echo
-echo "---[ Server - with client ext key use ] ---------------------------------"
-echo "---[ Only used for negative-testing for OSU-client implementation ] -----"
-echo
-
-cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key"
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem"
-
-echo
-echo "---[ User ]-------------------------------------------------------------"
-echo
-
-cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key"
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem"
-
-echo
-echo "---[ Server ]-----------------------------------------------------------"
-echo
-
-ALT="DNS:$OSU_SERVER_HOSTNAME"
-ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG"
-ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI"
-
-cat my-openssl.cnf |
- sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" |
- sed "s/^##organizationalUnitName/organizationalUnitName/" |
- sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" |
- sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \
- > openssl.cnf.tmp
-echo $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server || fail "Failed to generate server request"
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server.csr -out server.pem -key $PASS -days 730 -extensions ext_server -policy policy_osu_server || fail "Failed to sign server certificate"
-
-#dump logotype details for debugging
-$OPENSSL x509 -in server.pem -out server.der -outform DER
-openssl asn1parse -in server.der -inform DER | grep HEX | tail -1 | sed 's/.*://' | xxd -r -p > logo.der
-openssl asn1parse -in logo.der -inform DER > logo.asn1
-
-
-echo
-echo "---[ CRL ]---------------------------------------------------------------"
-echo
-
-$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
-
-echo
-echo "---[ Verify ]------------------------------------------------------------"
-echo
-
-$OPENSSL verify -CAfile rootCA/cacert.pem demoCA/cacert.pem
-$OPENSSL verify -CAfile rootCA/cacert.pem -untrusted demoCA/cacert.pem *.pem
-
-cat rootCA/cacert.pem demoCA/cacert.pem > ca.pem
diff --git a/hs20/server/ca/w1fi_logo.png b/hs20/server/ca/w1fi_logo.png
deleted file mode 100644
index ac7c259..0000000
--- a/hs20/server/ca/w1fi_logo.png
+++ /dev/null
Binary files differ
diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt
deleted file mode 100644
index 22478ad..0000000
--- a/hs20/server/hs20-osu-server.txt
+++ /dev/null
@@ -1,262 +0,0 @@
-Hotspot 2.0 OSU server
-======================
-
-The information in this document is based on the assumption that Ubuntu
-16.04 server (64-bit) distribution is used and the web server is
-Apache2. Neither of these are requirements for the installation, but if
-other combinations are used, the package names and configuration
-parameters may need to be adjusted.
-
-NOTE: This implementation and the example configuration here is meant
-only for testing purposes in a lab environment. This design is not
-secure to be installed in a publicly available Internet server without
-considerable amount of modification and review for security issues.
-
-
-Build dependencies
-------------------
-
-Ubuntu 16.04 server
-- default installation
-- upgraded to latest package versions
- sudo apt-get update
- sudo apt-get upgrade
-
-Packages needed for running the service:
- sudo apt-get install sqlite3
- sudo apt-get install apache2
- sudo apt-get install php-sqlite3 php-xml libapache2-mod-php
-
-Additional packages needed for building the components:
- sudo apt-get install build-essential
- sudo apt-get install libsqlite3-dev
- sudo apt-get install libssl-dev
- sudo apt-get install libxml2-dev
-
-
-Installation location
----------------------
-
-Select a location for the installation root directory. The example here
-assumes /home/user/hs20-server to be used, but this can be changed by
-editing couple of files as indicated below.
-
-sudo mkdir -p /home/user/hs20-server
-sudo chown $USER /home/user/hs20-server
-mkdir -p /home/user/hs20-server/spp
-mkdir -p /home/user/hs20-server/AS
-
-
-Build
------
-
-# hostapd as RADIUS server
-cd hostapd
-
-#example build configuration
-cat > .config <<EOF
-CONFIG_DRIVER_NONE=y
-CONFIG_PKCS12=y
-CONFIG_RADIUS_SERVER=y
-CONFIG_EAP=y
-CONFIG_EAP_TLS=y
-CONFIG_EAP_MSCHAPV2=y
-CONFIG_EAP_PEAP=y
-CONFIG_EAP_GTC=y
-CONFIG_EAP_TTLS=y
-CONFIG_EAP_SIM=y
-CONFIG_EAP_AKA=y
-CONFIG_EAP_AKA_PRIME=y
-CONFIG_SQLITE=y
-CONFIG_HS20=y
-EOF
-
-make hostapd hlr_auc_gw
-cp hostapd hlr_auc_gw /home/user/hs20-server/AS
-
-# build hs20_spp_server
-cd ../hs20/server
-make clean
-make
-cp hs20_spp_server /home/user/hs20-server/spp
-# prepare database (web server user/group needs to have write access)
-mkdir -p /home/user/hs20-server/AS/DB
-sudo chgrp www-data /home/user/hs20-server/AS/DB
-sudo chmod g+w /home/user/hs20-server/AS/DB
-sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql.txt
-sudo chgrp www-data /home/user/hs20-server/AS/DB/eap_user.db
-sudo chmod g+w /home/user/hs20-server/AS/DB/eap_user.db
-# add example configuration (note: need to update URLs to match the system)
-sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql-example.txt
-
-# copy PHP scripts
-# Modify config.php if different installation directory is used.
-# Modify PHP scripts to get the desired behavior for user interaction (or use
-# the examples as-is for initial testing).
-cp -r www /home/user/hs20-server
-
-# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be
-# inserted within the BODY section of the page).
-cat > /home/user/hs20-server/terms-and-conditions <<EOF
-<P>Terms and conditions..</P>
-EOF
-
-# Build local keys and certs
-cd ca
-# Display help options.
-./setup.sh -h
-
-# Remove old keys, fill in appropriate values, and generate your keys.
-# For instance:
-./clean.sh
-rm -fr rootCA"
-old_hostname=myserver.local
-./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \
- -o $old_hostname-osu-client \
- -O $old_hostname-oscp -p lanforge -S $old_hostname \
- -V $old_hostname-osu-revoked \
- -m local -u http://$old_hostname:8888/
-
-# Configure subscription policies
-mkdir -p /home/user/hs20-server/spp/policy
-cat > /home/user/hs20-server/spp/policy/default.xml <<EOF
-<Policy>
- <PolicyUpdate>
- <UpdateInterval>30</UpdateInterval>
- <UpdateMethod>ClientInitiated</UpdateMethod>
- <Restriction>Unrestricted</Restriction>
- <URI>https://policy-server.osu.example.com/hs20/spp.php</URI>
- </PolicyUpdate>
-</Policy>
-EOF
-
-
-# Install Hotspot 2.0 SPP and OMA DM XML schema/DTD files
-
-# XML schema for SPP
-# Copy the latest XML schema into /home/user/hs20-server/spp/spp.xsd
-
-# OMA DM Device Description Framework DTD
-# Copy into /home/user/hs20-server/spp/dm_ddf-v1_2.dtd
-# http://www.openmobilealliance.org/tech/DTD/dm_ddf-v1_2.dtd
-
-
-# Configure RADIUS authentication service
-# Note: Change the URL to match the setup
-# Note: Install AAA server key/certificate and root CA in Key directory
-
-cat > /home/user/hs20-server/AS/as-sql.conf <<EOF
-driver=none
-radius_server_clients=as.radius_clients
-eap_server=1
-eap_user_file=sqlite:DB/eap_user.db
-ca_cert=Key/ca.pem
-server_cert=Key/server.pem
-private_key=Key/server.key
-private_key_passwd=passphrase
-eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=eap_sim.db
-subscr_remediation_url=https://subscription-server.osu.example.com/hs20/spp.php
-EOF
-
-# Set RADIUS passphrase for the APs
-# Note: Modify to match the setup
-cat > /home/user/hs20-server/AS/as.radius_clients <<EOF
-0.0.0.0/0 radius
-EOF
-
-
-Start RADIUS authentication server
-----------------------------------
-
-cd /home/user/hs20-server/AS
-./hostapd -B as-sql.conf
-
-
-OSEN RADIUS server configuration notes
-
-The OSEN RADIUS server config file should have the 'ocsp_stapling_response'
-configuration in it. For example:
-
-# hostapd-radius config for the radius used by the OSEN AP
-interface=eth0#0
-driver=none
-logger_syslog=-1
-logger_syslog_level=2
-logger_stdout=-1
-logger_stdout_level=2
-ctrl_interface=/var/run/hostapd
-ctrl_interface_group=0
-eap_server=1
-eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user
-server_id=ben-ota-2-osen
-radius_server_auth_port=1811
-radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients
-
-ca_cert=/home/user/hs20-server/ca/ca.pem
-server_cert=/home/user/hs20-server/ca/server.pem
-private_key=/home/user/hs20-server/ca/server.key
-private_key_passwd=whatever
-
-ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der
-
-The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look
-similar to this, and should coorelate with the osu_nai entry in
-the non-OSEN VAP config file. For instance:
-
-# cat hostapd-osen.eap_user
-# For OSEN authentication (Hotspot 2.0 Release 2)
-"osen@w1.fi" WFA-UNAUTH-TLS
-
-
-# Run OCSP server:
-cd /home/user/hs20-server/ca
-./ocsp-responder.sh&
-
-# Update cache (This should be run periodically)
-./ocsp-update-cache.sh
-
-
-Configure web server
---------------------
-
-Edit /etc/apache2/sites-available/default-ssl
-
-Add following block just before "SSL Engine Switch" line":
-
- Alias /hs20/ "/home/user/hs20-server/www/"
- <Directory "/home/user/hs20-server/www/">
- Options Indexes MultiViews FollowSymLinks
- AllowOverride None
- Require all granted
- SSLOptions +StdEnvVars
- </Directory>
-
-Update SSL configuration to use the OSU server certificate/key.
-They keys and certs are called 'server.key' and 'server.pem' from
-ca/setup.sh.
-
-To support subscription remediation using client certificates, set
-"SSLVerifyClient optional" and configure the trust root CA(s) for the
-client certificates with SSLCACertificateFile.
-
-Enable default-ssl site and restart Apache2:
- sudo a2ensite default-ssl
- sudo a2enmod ssl
- sudo service apache2 restart
-
-
-Management UI
--------------
-
-The sample PHP scripts include a management UI for testing
-purposes. That is available at https://<server>/hs20/users.php
-
-
-AP configuration
-----------------
-
-APs can now be configured to use the OSU server as the RADIUS
-authentication server. In addition, the OSU Provider List ANQP element
-should be configured to use the SPP (SOAP+XML) option and with the
-following Server URL:
-https://<server>/hs20/spp.php/signup?realm=example.com
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
deleted file mode 100644
index 347c40a..0000000
--- a/hs20/server/hs20_spp_server.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Hotspot 2.0 SPP server - standalone version
- * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <time.h>
-#include <sqlite3.h>
-
-#include "common.h"
-#include "common/version.h"
-#include "xml-utils.h"
-#include "spp_server.h"
-
-
-static void write_timestamp(FILE *f)
-{
- time_t t;
- struct tm *tm;
-
- time(&t);
- tm = localtime(&t);
-
- fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
-}
-
-
-void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
-{
- va_list ap;
-
- if (ctx->debug_log == NULL)
- return;
-
- write_timestamp(ctx->debug_log);
- va_start(ap, fmt);
- vfprintf(ctx->debug_log, fmt, ap);
- va_end(ap);
-
- fprintf(ctx->debug_log, "\n");
-}
-
-
-void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node)
-{
- char *str;
-
- if (ctx->debug_log == NULL)
- return;
- str = xml_node_to_str(ctx->xml, node);
- if (str == NULL)
- return;
-
- write_timestamp(ctx->debug_log);
- fprintf(ctx->debug_log, "%s: '%s'\n", title, str);
- os_free(str);
-}
-
-
-static int process(struct hs20_svc *ctx)
-{
- int dmacc = 0;
- xml_node_t *soap, *spp, *resp;
- char *user, *realm, *post, *str;
-
- ctx->addr = getenv("HS20ADDR");
- if (ctx->addr)
- debug_print(ctx, 1, "Connection from %s", ctx->addr);
- ctx->test = getenv("HS20TEST");
- if (ctx->test)
- debug_print(ctx, 1, "Requested test functionality: %s",
- ctx->test);
-
- user = getenv("HS20USER");
- if (user && strlen(user) == 0)
- user = NULL;
- realm = getenv("HS20REALM");
- if (realm == NULL) {
- debug_print(ctx, 1, "HS20REALM not set");
- return -1;
- }
- post = getenv("HS20POST");
- if (post == NULL) {
- debug_print(ctx, 1, "HS20POST not set");
- return -1;
- }
-
- ctx->imsi = getenv("HS20IMSI");
- if (ctx->imsi)
- debug_print(ctx, 1, "IMSI %s", ctx->imsi);
-
- ctx->eap_method = getenv("HS20EAPMETHOD");
- if (ctx->eap_method)
- debug_print(ctx, 1, "EAP method %s", ctx->eap_method);
-
- ctx->id_hash = getenv("HS20IDHASH");
- if (ctx->id_hash)
- debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash);
-
- soap = xml_node_from_buf(ctx->xml, post);
- if (soap == NULL) {
- debug_print(ctx, 1, "Could not parse SOAP data");
- return -1;
- }
- debug_dump_node(ctx, "Received SOAP message", soap);
- spp = soap_get_body(ctx->xml, soap);
- if (spp == NULL) {
- debug_print(ctx, 1, "Could not get SPP message");
- xml_node_free(ctx->xml, soap);
- return -1;
- }
- debug_dump_node(ctx, "Received SPP message", spp);
-
- resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc);
- xml_node_free(ctx->xml, soap);
- if (resp == NULL && user == NULL) {
- debug_print(ctx, 1, "Request HTTP authentication");
- return 2; /* Request authentication */
- }
- if (resp == NULL) {
- debug_print(ctx, 1, "No response");
- return -1;
- }
-
- soap = soap_build_envelope(ctx->xml, resp);
- if (soap == NULL) {
- debug_print(ctx, 1, "SOAP envelope building failed");
- return -1;
- }
- str = xml_node_to_str(ctx->xml, soap);
- xml_node_free(ctx->xml, soap);
- if (str == NULL) {
- debug_print(ctx, 1, "Could not get node string");
- return -1;
- }
- printf("%s", str);
- free(str);
-
- return 0;
-}
-
-
-static void usage(void)
-{
- printf("usage:\n"
- "hs20_spp_server -r<root directory> [-f<debug log>]\n");
-}
-
-
-int main(int argc, char *argv[])
-{
- struct hs20_svc ctx;
- int ret;
-
- os_memset(&ctx, 0, sizeof(ctx));
- for (;;) {
- int c = getopt(argc, argv, "f:r:v");
- if (c < 0)
- break;
- switch (c) {
- case 'f':
- if (ctx.debug_log)
- break;
- ctx.debug_log = fopen(optarg, "a");
- if (ctx.debug_log == NULL) {
- printf("Could not write to %s\n", optarg);
- return -1;
- }
- break;
- case 'r':
- ctx.root_dir = optarg;
- break;
- case 'v':
- printf("hs20_spp_server v%s\n", VERSION_STR);
- return 0;
- default:
- usage();
- return -1;
- }
- }
- if (ctx.root_dir == NULL) {
- usage();
- return -1;
- }
- ctx.xml = xml_node_init_ctx(&ctx, NULL);
- if (ctx.xml == NULL)
- return -1;
- if (hs20_spp_server_init(&ctx) < 0) {
- xml_node_deinit_ctx(ctx.xml);
- return -1;
- }
-
- ret = process(&ctx);
- debug_print(&ctx, 1, "process() --> %d", ret);
-
- xml_node_deinit_ctx(ctx.xml);
- hs20_spp_server_deinit(&ctx);
- if (ctx.debug_log)
- fclose(ctx.debug_log);
-
- return ret;
-}
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
deleted file mode 100644
index 72694be..0000000
--- a/hs20/server/spp_server.c
+++ /dev/null
@@ -1,2936 +0,0 @@
-/*
- * Hotspot 2.0 SPP server
- * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#include <errno.h>
-#include <sqlite3.h>
-
-#include "common.h"
-#include "base64.h"
-#include "md5_i.h"
-#include "xml-utils.h"
-#include "spp_server.h"
-
-
-#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
-
-#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
-#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
-#define URN_OMA_DM_DMACC "urn:oma:mo:oma-dm-dmacc:1.0"
-#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
-
-
-/* TODO: timeout to expire sessions */
-
-enum hs20_session_operation {
- NO_OPERATION,
- UPDATE_PASSWORD,
- CONTINUE_SUBSCRIPTION_REMEDIATION,
- CONTINUE_POLICY_UPDATE,
- USER_REMEDIATION,
- SUBSCRIPTION_REGISTRATION,
- POLICY_REMEDIATION,
- POLICY_UPDATE,
- FREE_REMEDIATION,
- CLEAR_REMEDIATION,
- CERT_REENROLL,
-};
-
-
-static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *session_id,
- const char *field);
-static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
- const char *field);
-static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
- const char *realm, int use_dmacc);
-static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
- const char *session_id,
- const char *user,
- const char *realm,
- int add_est_user);
-
-
-static int db_add_session(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *sessionid, const char *pw,
- const char *redirect_uri,
- enum hs20_session_operation operation,
- const u8 *mac_addr)
-{
- char *sql;
- int ret = 0;
- char addr[20];
-
- if (mac_addr)
- snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr));
- else
- addr[0] = '\0';
- sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm,"
- "operation,password,redirect_uri,mac_addr,test) "
- "VALUES "
- "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
- "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
- sessionid, user ? user : "", realm ? realm : "",
- operation, pw ? pw : "",
- redirect_uri ? redirect_uri : "",
- addr, ctx->test);
- if (sql == NULL)
- return -1;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add session entry into sqlite "
- "database: %s", sqlite3_errmsg(ctx->db));
- ret = -1;
- }
- sqlite3_free(sql);
- return ret;
-}
-
-
-static void db_update_session_password(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *sessionid,
- const char *pw)
-{
- char *sql;
-
- sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND "
- "user=%Q AND realm=%Q",
- pw, sessionid, user, realm);
- if (sql == NULL)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to update session password: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_update_session_machine_managed(struct hs20_svc *ctx,
- const char *user,
- const char *realm,
- const char *sessionid,
- const int pw_mm)
-{
- char *sql;
-
- sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
- pw_mm ? "1" : "0", sessionid, user, realm);
- if (sql == NULL)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1,
- "Failed to update session machine_managed: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *sessionid,
- xml_node_t *node)
-{
- char *str;
- char *sql;
-
- str = xml_node_to_str(ctx->xml, node);
- if (str == NULL)
- return;
- sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND "
- "user=%Q AND realm=%Q",
- str, sessionid, user, realm);
- free(str);
- if (sql == NULL)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add session pps: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid,
- xml_node_t *node)
-{
- char *str;
- char *sql;
-
- str = xml_node_to_str(ctx->xml, node);
- if (str == NULL)
- return;
- sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q",
- str, sessionid);
- free(str);
- if (sql == NULL)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add session devinfo: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_add_session_devdetail(struct hs20_svc *ctx,
- const char *sessionid,
- xml_node_t *node)
-{
- char *str;
- char *sql;
-
- str = xml_node_to_str(ctx->xml, node);
- if (str == NULL)
- return;
- sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q",
- str, sessionid);
- free(str);
- if (sql == NULL)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add session devdetail: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid,
- const char *username, const char *password)
-{
- char *sql;
-
- sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q",
- username, password, sessionid);
- if (!sql)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add session DMAcc: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_add_session_eap_method(struct hs20_svc *ctx,
- const char *sessionid,
- const char *method)
-{
- char *sql;
-
- sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q",
- method, sessionid);
- if (!sql)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add session EAP method: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid,
- const char *id_hash)
-{
- char *sql;
-
- sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q",
- id_hash, sessionid);
- if (!sql)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add session ID hash: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_remove_session(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *sessionid)
-{
- char *sql;
-
- if (user == NULL || realm == NULL) {
- sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
- "id=%Q", sessionid);
- } else {
- sql = sqlite3_mprintf("DELETE FROM sessions WHERE "
- "user=%Q AND realm=%Q AND id=%Q",
- user, realm, sessionid);
- }
- if (sql == NULL)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to delete session entry from "
- "sqlite database: %s", sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void hs20_eventlog(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *sessionid, const char *notes,
- const char *dump)
-{
- char *sql;
- char *user_buf = NULL, *realm_buf = NULL;
-
- debug_print(ctx, 1, "eventlog: %s", notes);
-
- if (user == NULL) {
- user_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
- "user");
- user = user_buf;
- realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid,
- "realm");
- realm = realm_buf;
- }
-
- sql = sqlite3_mprintf("INSERT INTO eventlog"
- "(user,realm,sessionid,timestamp,notes,dump,addr)"
- " VALUES (%Q,%Q,%Q,"
- "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now'),"
- "%Q,%Q,%Q)",
- user, realm, sessionid, notes,
- dump ? dump : "", ctx->addr ? ctx->addr : "");
- free(user_buf);
- free(realm_buf);
- if (sql == NULL)
- return;
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add eventlog entry into sqlite "
- "database: %s", sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void hs20_eventlog_node(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *sessionid, const char *notes,
- xml_node_t *node)
-{
- char *str;
-
- if (node)
- str = xml_node_to_str(ctx->xml, node);
- else
- str = NULL;
- hs20_eventlog(ctx, user, realm, sessionid, notes, str);
- free(str);
-}
-
-
-static void db_update_mo_str(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *name,
- const char *str)
-{
- char *sql;
- if (user == NULL || realm == NULL || name == NULL)
- return;
- sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
- name, str, user, realm);
- if (sql == NULL)
- return;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to update user MO entry in sqlite "
- "database: %s", sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
-}
-
-
-static void db_update_mo(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *name, xml_node_t *mo)
-{
- char *str;
-
- str = xml_node_to_str(ctx->xml, mo);
- if (str == NULL)
- return;
-
- db_update_mo_str(ctx, user, realm, name, str);
- free(str);
-}
-
-
-static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent,
- const char *name, const char *value)
-{
- xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : "");
-}
-
-
-static void add_text_node_conf(struct hs20_svc *ctx, const char *realm,
- xml_node_t *parent, const char *name,
- const char *field)
-{
- char *val;
- val = db_get_osu_config_val(ctx, realm, field);
- xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
- os_free(val);
-}
-
-
-static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm,
- xml_node_t *parent, const char *name,
- const char *field)
-{
- char *val;
-
- val = db_get_osu_config_val(ctx, realm, field);
- if (val) {
- size_t len;
-
- len = os_strlen(val);
- if (len > 0) {
- if (val[len - 1] == '0')
- val[len - 1] = '1';
- else
- val[len - 1] = '0';
- }
- }
- xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : "");
- os_free(val);
-}
-
-
-static int new_password(char *buf, int buflen)
-{
- int i;
-
- if (buflen < 1)
- return -1;
- buf[buflen - 1] = '\0';
- if (os_get_random((unsigned char *) buf, buflen - 1) < 0)
- return -1;
-
- for (i = 0; i < buflen - 1; i++) {
- unsigned char val = buf[i];
- val %= 2 * 26 + 10;
- if (val < 26)
- buf[i] = 'a' + val;
- else if (val < 2 * 26)
- buf[i] = 'A' + val - 26;
- else
- buf[i] = '0' + val - 2 * 26;
- }
-
- return 0;
-}
-
-
-struct get_db_field_data {
- const char *field;
- char *value;
-};
-
-
-static int get_db_field(void *ctx, int argc, char *argv[], char *col[])
-{
- struct get_db_field_data *data = ctx;
- int i;
-
- for (i = 0; i < argc; i++) {
- if (os_strcmp(col[i], data->field) == 0 && argv[i]) {
- os_free(data->value);
- data->value = os_strdup(argv[i]);
- break;
- }
- }
-
- return 0;
-}
-
-
-static char * db_get_val(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *field, int dmacc)
-{
- char *cmd;
- struct get_db_field_data data;
-
- cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
- field, dmacc ? "osu_user" : "identity",
- user, realm);
- if (cmd == NULL)
- return NULL;
- memset(&data, 0, sizeof(data));
- data.field = field;
- if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
- {
- debug_print(ctx, 1, "Could not find user '%s'", user);
- sqlite3_free(cmd);
- return NULL;
- }
- sqlite3_free(cmd);
-
- debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> "
- "value='%s'", user, realm, field, dmacc, data.value);
-
- return data.value;
-}
-
-
-static int db_update_val(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *field,
- const char *val, int dmacc)
-{
- char *cmd;
- int ret;
-
- cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
- field, val, dmacc ? "osu_user" : "identity", user,
- realm);
- if (cmd == NULL)
- return -1;
- debug_print(ctx, 1, "DB: %s", cmd);
- if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1,
- "Failed to update user in sqlite database: %s",
- sqlite3_errmsg(ctx->db));
- ret = -1;
- } else {
- debug_print(ctx, 1,
- "DB: user='%s' realm='%s' field='%s' set to '%s'",
- user, realm, field, val);
- ret = 0;
- }
- sqlite3_free(cmd);
-
- return ret;
-}
-
-
-static char * db_get_session_val(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *session_id,
- const char *field)
-{
- char *cmd;
- struct get_db_field_data data;
-
- if (user == NULL || realm == NULL) {
- cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
- "id=%Q", field, session_id);
- } else {
- cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE "
- "user=%Q AND realm=%Q AND id=%Q",
- field, user, realm, session_id);
- }
- if (cmd == NULL)
- return NULL;
- debug_print(ctx, 1, "DB: %s", cmd);
- memset(&data, 0, sizeof(data));
- data.field = field;
- if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
- {
- debug_print(ctx, 1, "DB: Could not find session %s: %s",
- session_id, sqlite3_errmsg(ctx->db));
- sqlite3_free(cmd);
- return NULL;
- }
- sqlite3_free(cmd);
-
- debug_print(ctx, 1, "DB: return '%s'", data.value);
- return data.value;
-}
-
-
-static int update_password(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *pw, int dmacc)
-{
- char *cmd;
-
- cmd = sqlite3_mprintf("UPDATE users SET password=%Q, "
- "remediation='' "
- "WHERE %s=%Q AND phase2=1",
- pw, dmacc ? "osu_user" : "identity",
- user);
- if (cmd == NULL)
- return -1;
- debug_print(ctx, 1, "DB: %s", cmd);
- if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to update database for user '%s'",
- user);
- }
- sqlite3_free(cmd);
-
- return 0;
-}
-
-
-static int clear_remediation(struct hs20_svc *ctx, const char *user,
- const char *realm, int dmacc)
-{
- char *cmd;
-
- cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q",
- dmacc ? "osu_user" : "identity",
- user);
- if (cmd == NULL)
- return -1;
- debug_print(ctx, 1, "DB: %s", cmd);
- if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to update database for user '%s'",
- user);
- }
- sqlite3_free(cmd);
-
- return 0;
-}
-
-
-static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent)
-{
- xml_node_t *node;
-
- node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod");
- if (node == NULL)
- return -1;
-
- add_text_node(ctx, node, "EAPType", "21");
- add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2");
-
- return 0;
-}
-
-
-static xml_node_t * build_username_password(struct hs20_svc *ctx,
- xml_node_t *parent,
- const char *user, const char *pw)
-{
- xml_node_t *node;
- char *b64;
- size_t len;
-
- node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
- if (node == NULL)
- return NULL;
-
- add_text_node(ctx, node, "Username", user);
-
- b64 = base64_encode(pw, strlen(pw), NULL);
- if (b64 == NULL)
- return NULL;
- len = os_strlen(b64);
- if (len > 0 && b64[len - 1] == '\n')
- b64[len - 1] = '\0';
- add_text_node(ctx, node, "Password", b64);
- free(b64);
-
- return node;
-}
-
-
-static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred,
- const char *user, const char *pw,
- int machine_managed)
-{
- xml_node_t *node;
-
- node = build_username_password(ctx, cred, user, pw);
- if (node == NULL)
- return -1;
-
- add_text_node(ctx, node, "MachineManaged",
- machine_managed ? "TRUE" : "FALSE");
- add_text_node(ctx, node, "SoftTokenApp", "");
- add_eap_ttls(ctx, node);
-
- return 0;
-}
-
-
-static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred)
-{
- char str[30];
- time_t now;
- struct tm tm;
-
- time(&now);
- gmtime_r(&now, &tm);
- snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ",
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
- xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str);
-}
-
-
-static xml_node_t * build_credential_pw(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *pw, int machine_managed)
-{
- xml_node_t *cred;
-
- cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
- if (cred == NULL) {
- debug_print(ctx, 1, "Failed to create Credential node");
- return NULL;
- }
- add_creation_date(ctx, cred);
- if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) {
- xml_node_free(ctx->xml, cred);
- return NULL;
- }
- add_text_node(ctx, cred, "Realm", realm);
-
- return cred;
-}
-
-
-static xml_node_t * build_credential(struct hs20_svc *ctx,
- const char *user, const char *realm,
- char *new_pw, size_t new_pw_len)
-{
- if (new_password(new_pw, new_pw_len) < 0)
- return NULL;
- debug_print(ctx, 1, "Update password to '%s'", new_pw);
- return build_credential_pw(ctx, user, realm, new_pw, 1);
-}
-
-
-static xml_node_t * build_credential_cert(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *cert_fingerprint)
-{
- xml_node_t *cred, *cert;
-
- cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential");
- if (cred == NULL) {
- debug_print(ctx, 1, "Failed to create Credential node");
- return NULL;
- }
- add_creation_date(ctx, cred);
- cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate");
- add_text_node(ctx, cert, "CertificateType", "x509v3");
- add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint);
- add_text_node(ctx, cred, "Realm", realm);
-
- return cred;
-}
-
-
-static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx,
- xml_namespace_t **ret_ns,
- const char *session_id,
- const char *status,
- const char *error_code)
-{
- xml_node_t *spp_node = NULL;
- xml_namespace_t *ns;
-
- spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
- "sppPostDevDataResponse");
- if (spp_node == NULL)
- return NULL;
- if (ret_ns)
- *ret_ns = ns;
-
- xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
- xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
- xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
-
- if (error_code) {
- xml_node_t *node;
- node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
- if (node)
- xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
- error_code);
- }
-
- return spp_node;
-}
-
-
-static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node,
- xml_namespace_t *ns, const char *uri,
- xml_node_t *upd_node)
-{
- xml_node_t *node, *tnds;
- char *str;
-
- tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL);
- if (!tnds)
- return -1;
-
- str = xml_node_to_str(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (str == NULL)
- return -1;
- node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str);
- free(str);
-
- xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri);
-
- return 0;
-}
-
-
-static xml_node_t * read_subrem_file(struct hs20_svc *ctx,
- const char *subrem_id,
- char *uri, size_t uri_size)
-{
- char fname[200];
- char *buf, *buf2, *pos;
- size_t len;
- xml_node_t *node;
-
- os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s",
- ctx->root_dir, subrem_id);
- debug_print(ctx, 1, "Use subrem file %s", fname);
-
- buf = os_readfile(fname, &len);
- if (!buf)
- return NULL;
- buf2 = os_realloc(buf, len + 1);
- if (!buf2) {
- os_free(buf);
- return NULL;
- }
- buf = buf2;
- buf[len] = '\0';
-
- pos = os_strchr(buf, '\n');
- if (!pos) {
- os_free(buf);
- return NULL;
- }
- *pos++ = '\0';
- os_strlcpy(uri, buf, uri_size);
-
- node = xml_node_from_buf(ctx->xml, pos);
- os_free(buf);
-
- return node;
-}
-
-
-static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *session_id,
- int machine_rem, int dmacc)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *cred;
- char buf[400];
- char new_pw[33];
- char *status;
- char *cert;
-
- cert = db_get_val(ctx, user, realm, "cert", dmacc);
- if (cert && cert[0] == '\0') {
- os_free(cert);
- cert = NULL;
- }
- if (cert) {
- char *subrem;
-
- /* No change needed in PPS MO unless specifically asked to */
- cred = NULL;
- buf[0] = '\0';
-
- subrem = db_get_val(ctx, user, realm, "subrem", dmacc);
- if (subrem && subrem[0]) {
- cred = read_subrem_file(ctx, subrem, buf, sizeof(buf));
- if (!cred) {
- debug_print(ctx, 1,
- "Could not create updateNode from subrem file");
- os_free(subrem);
- os_free(cert);
- return NULL;
- }
- }
- os_free(subrem);
- } else {
- char *real_user = NULL;
- char *pw;
-
- if (dmacc) {
- real_user = db_get_val(ctx, user, realm, "identity",
- dmacc);
- if (!real_user) {
- debug_print(ctx, 1,
- "Could not find user identity for dmacc user '%s'",
- user);
- return NULL;
- }
- }
-
- pw = db_get_session_val(ctx, user, realm, session_id,
- "password");
- if (pw && pw[0]) {
- debug_print(ctx, 1, "New password from the user: '%s'",
- pw);
- snprintf(new_pw, sizeof(new_pw), "%s", pw);
- free(pw);
- cred = build_credential_pw(ctx,
- real_user ? real_user : user,
- realm, new_pw, 0);
- } else {
- cred = build_credential(ctx,
- real_user ? real_user : user,
- realm, new_pw, sizeof(new_pw));
- }
-
- free(real_user);
- if (!cred) {
- debug_print(ctx, 1, "Could not build credential");
- os_free(cert);
- return NULL;
- }
-
- snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
- realm);
- }
-
- status = "Remediation complete, request sppUpdateResponse";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (spp_node == NULL) {
- debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
- os_free(cert);
- return NULL;
- }
-
- if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) ||
- (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) {
- debug_print(ctx, 1, "Could not add update node");
- xml_node_free(ctx->xml, spp_node);
- os_free(cert);
- return NULL;
- }
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- machine_rem ? "machine remediation" :
- "user remediation", cred);
- xml_node_free(ctx->xml, cred);
-
- if (cert) {
- debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)");
- db_add_session(ctx, user, realm, session_id, NULL, NULL,
- CLEAR_REMEDIATION, NULL);
- } else {
- debug_print(ctx, 1, "Request DB password update on success "
- "notification");
- db_add_session(ctx, user, realm, session_id, new_pw, NULL,
- UPDATE_PASSWORD, NULL);
- }
- os_free(cert);
-
- return spp_node;
-}
-
-
-static xml_node_t * machine_remediation(struct hs20_svc *ctx,
- const char *user,
- const char *realm,
- const char *session_id, int dmacc)
-{
- return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc);
-}
-
-
-static xml_node_t * cert_reenroll(struct hs20_svc *ctx,
- const char *user,
- const char *realm,
- const char *session_id)
-{
- db_add_session(ctx, user, realm, session_id, NULL, NULL,
- CERT_REENROLL, NULL);
- return spp_exec_get_certificate(ctx, session_id, user, realm, 0);
-}
-
-
-static xml_node_t * policy_remediation(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *session_id, int dmacc)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *policy;
- char buf[400];
- const char *status;
-
- hs20_eventlog(ctx, user, realm, session_id,
- "requires policy remediation", NULL);
-
- db_add_session(ctx, user, realm, session_id, NULL, NULL,
- POLICY_REMEDIATION, NULL);
-
- policy = build_policy(ctx, user, realm, dmacc);
- if (!policy) {
- return build_post_dev_data_response(
- ctx, NULL, session_id,
- "No update available at this time", NULL);
- }
-
- status = "Remediation complete, request sppUpdateResponse";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
- realm);
-
- if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
- xml_node_free(ctx->xml, spp_node);
- xml_node_free(ctx->xml, policy);
- return NULL;
- }
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- "policy update (sub rem)", policy);
- xml_node_free(ctx->xml, policy);
-
- return spp_node;
-}
-
-
-static xml_node_t * browser_remediation(struct hs20_svc *ctx,
- const char *session_id,
- const char *redirect_uri,
- const char *uri)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *exec_node;
-
- if (redirect_uri == NULL) {
- debug_print(ctx, 1, "Missing redirectURI attribute for user "
- "remediation");
- return NULL;
- }
- debug_print(ctx, 1, "redirectURI %s", redirect_uri);
-
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
- xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
- uri);
- return spp_node;
-}
-
-
-static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user,
- const char *realm, const char *session_id,
- const char *redirect_uri)
-{
- char uri[300], *val;
-
- hs20_eventlog(ctx, user, realm, session_id,
- "requires user remediation", NULL);
- val = db_get_osu_config_val(ctx, realm, "remediation_url");
- if (val == NULL)
- return NULL;
-
- db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
- USER_REMEDIATION, NULL);
-
- snprintf(uri, sizeof(uri), "%s%s", val, session_id);
- os_free(val);
- return browser_remediation(ctx, session_id, redirect_uri, uri);
-}
-
-
-static xml_node_t * free_remediation(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *session_id,
- const char *redirect_uri)
-{
- char uri[300], *val;
-
- hs20_eventlog(ctx, user, realm, session_id,
- "requires free/public account remediation", NULL);
- val = db_get_osu_config_val(ctx, realm, "free_remediation_url");
- if (val == NULL)
- return NULL;
-
- db_add_session(ctx, user, realm, session_id, NULL, redirect_uri,
- FREE_REMEDIATION, NULL);
-
- snprintf(uri, sizeof(uri), "%s%s", val, session_id);
- os_free(val);
- return browser_remediation(ctx, session_id, redirect_uri, uri);
-}
-
-
-static xml_node_t * no_sub_rem(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *session_id)
-{
- const char *status;
-
- hs20_eventlog(ctx, user, realm, session_id,
- "no subscription mediation available", NULL);
-
- status = "No update available at this time";
- return build_post_dev_data_response(ctx, NULL, session_id, status,
- NULL);
-}
-
-
-static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx,
- const char *user,
- const char *realm,
- const char *session_id,
- int dmacc,
- const char *redirect_uri)
-{
- char *type, *identity;
- xml_node_t *ret;
- char *free_account;
-
- identity = db_get_val(ctx, user, realm, "identity", dmacc);
- if (identity == NULL || strlen(identity) == 0) {
- hs20_eventlog(ctx, user, realm, session_id,
- "user not found in database for remediation",
- NULL);
- os_free(identity);
- return build_post_dev_data_response(ctx, NULL, session_id,
- "Error occurred",
- "Not found");
- }
- os_free(identity);
-
- free_account = db_get_osu_config_val(ctx, realm, "free_account");
- if (free_account && strcmp(free_account, user) == 0) {
- free(free_account);
- return no_sub_rem(ctx, user, realm, session_id);
- }
- free(free_account);
-
- type = db_get_val(ctx, user, realm, "remediation", dmacc);
- if (type && strcmp(type, "free") != 0) {
- char *val;
- int shared = 0;
- val = db_get_val(ctx, user, realm, "shared", dmacc);
- if (val)
- shared = atoi(val);
- free(val);
- if (shared) {
- free(type);
- return no_sub_rem(ctx, user, realm, session_id);
- }
- }
- if (type && strcmp(type, "user") == 0)
- ret = user_remediation(ctx, user, realm, session_id,
- redirect_uri);
- else if (type && strcmp(type, "free") == 0)
- ret = free_remediation(ctx, user, realm, session_id,
- redirect_uri);
- else if (type && strcmp(type, "policy") == 0)
- ret = policy_remediation(ctx, user, realm, session_id, dmacc);
- else if (type && strcmp(type, "machine") == 0)
- ret = machine_remediation(ctx, user, realm, session_id, dmacc);
- else if (type && strcmp(type, "reenroll") == 0)
- ret = cert_reenroll(ctx, user, realm, session_id);
- else
- ret = no_sub_rem(ctx, user, realm, session_id);
- free(type);
-
- return ret;
-}
-
-
-static xml_node_t * read_policy_file(struct hs20_svc *ctx,
- const char *policy_id)
-{
- char fname[200];
-
- snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
- ctx->root_dir, policy_id);
- debug_print(ctx, 1, "Use policy file %s", fname);
-
- return node_from_file(ctx->xml, fname);
-}
-
-
-static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm,
- xml_node_t *policy)
-{
- xml_node_t *node;
- char *url;
-
- node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
- if (!node)
- return;
-
- url = db_get_osu_config_val(ctx, realm, "policy_url");
- if (!url)
- return;
- xml_node_set_text(ctx->xml, node, url);
- free(url);
-}
-
-
-static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user,
- const char *realm, int use_dmacc)
-{
- char *policy_id;
- xml_node_t *policy, *node;
-
- policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
- if (policy_id == NULL || strlen(policy_id) == 0) {
- free(policy_id);
- policy_id = strdup("default");
- if (policy_id == NULL)
- return NULL;
- }
- policy = read_policy_file(ctx, policy_id);
- free(policy_id);
- if (policy == NULL)
- return NULL;
-
- update_policy_update_uri(ctx, realm, policy);
-
- node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
- if (node && use_dmacc) {
- char *pw;
- pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc);
- if (pw == NULL ||
- build_username_password(ctx, node, user, pw) == NULL) {
- debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/"
- "UsernamePassword");
- free(pw);
- xml_node_free(ctx->xml, policy);
- return NULL;
- }
- free(pw);
- }
-
- return policy;
-}
-
-
-static xml_node_t * hs20_policy_update(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *session_id, int dmacc)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node;
- xml_node_t *policy;
- char buf[400];
- const char *status;
- char *identity;
-
- identity = db_get_val(ctx, user, realm, "identity", dmacc);
- if (identity == NULL || strlen(identity) == 0) {
- hs20_eventlog(ctx, user, realm, session_id,
- "user not found in database for policy update",
- NULL);
- os_free(identity);
- return build_post_dev_data_response(ctx, NULL, session_id,
- "Error occurred",
- "Not found");
- }
- os_free(identity);
-
- policy = build_policy(ctx, user, realm, dmacc);
- if (!policy) {
- return build_post_dev_data_response(
- ctx, NULL, session_id,
- "No update available at this time", NULL);
- }
-
- db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE,
- NULL);
-
- status = "Update complete, request sppUpdateResponse";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy",
- realm);
-
- if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) {
- xml_node_free(ctx->xml, spp_node);
- xml_node_free(ctx->xml, policy);
- return NULL;
- }
-
- hs20_eventlog_node(ctx, user, realm, session_id, "policy update",
- policy);
- xml_node_free(ctx->xml, policy);
-
- return spp_node;
-}
-
-
-static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node,
- const char *urn, int *valid, char **ret_err)
-{
- xml_node_t *child, *tnds, *mo;
- const char *name;
- char *mo_urn;
- char *str;
- char fname[200];
-
- *valid = -1;
- if (ret_err)
- *ret_err = NULL;
-
- xml_node_for_each_child(ctx->xml, child, node) {
- xml_node_for_each_check(ctx->xml, child);
- name = xml_node_get_localname(ctx->xml, child);
- if (strcmp(name, "moContainer") != 0)
- continue;
- mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI,
- "moURN");
- if (strcasecmp(urn, mo_urn) == 0) {
- xml_node_get_attr_value_free(ctx->xml, mo_urn);
- break;
- }
- xml_node_get_attr_value_free(ctx->xml, mo_urn);
- }
-
- if (child == NULL)
- return NULL;
-
- debug_print(ctx, 1, "moContainer text for %s", urn);
- debug_dump_node(ctx, "moContainer", child);
-
- str = xml_node_get_text(ctx->xml, child);
- debug_print(ctx, 1, "moContainer payload: '%s'", str);
- tnds = xml_node_from_buf(ctx->xml, str);
- xml_node_get_text_free(ctx->xml, str);
- if (tnds == NULL) {
- debug_print(ctx, 1, "could not parse moContainer text");
- return NULL;
- }
-
- snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir);
- if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0)
- *valid = 1;
- else if (ret_err && *ret_err &&
- os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) {
- free(*ret_err);
- debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute");
- *ret_err = NULL;
- *valid = 1;
- } else
- *valid = 0;
-
- mo = tnds_to_mo(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (mo == NULL) {
- debug_print(ctx, 1, "invalid moContainer for %s", urn);
- }
-
- return mo;
-}
-
-
-static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx,
- const char *session_id, const char *urn)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *node, *exec_node;
-
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
-
- node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO");
- xml_node_add_attr(ctx->xml, node, ns, "moURN", urn);
-
- return spp_node;
-}
-
-
-static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx,
- const char *realm,
- const char *session_id,
- const char *redirect_uri,
- const u8 *mac_addr)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *exec_node;
- char uri[300], *val;
-
- if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri,
- SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
- return NULL;
- val = db_get_osu_config_val(ctx, realm, "signup_url");
- if (!val) {
- hs20_eventlog(ctx, NULL, realm, session_id,
- "signup_url not configured in osu_config", NULL);
- return NULL;
- }
-
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
-
- snprintf(uri, sizeof(uri), "%s%s", val, session_id);
- os_free(val);
- xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI",
- uri);
- return spp_node;
-}
-
-
-static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx,
- const char *user,
- const char *realm, int dmacc,
- const char *session_id)
-{
- return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc);
-}
-
-
-static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm,
- const char *field)
-{
- char *cmd;
- struct get_db_field_data data;
-
- cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND "
- "field=%Q", realm, field);
- if (cmd == NULL)
- return NULL;
- debug_print(ctx, 1, "DB: %s", cmd);
- memset(&data, 0, sizeof(data));
- data.field = "value";
- if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK)
- {
- debug_print(ctx, 1, "DB: Could not find osu_config %s: %s",
- realm, sqlite3_errmsg(ctx->db));
- sqlite3_free(cmd);
- return NULL;
- }
- sqlite3_free(cmd);
-
- debug_print(ctx, 1, "DB: return '%s'", data.value);
- return data.value;
-}
-
-
-static xml_node_t * build_pps(struct hs20_svc *ctx,
- const char *user, const char *realm,
- const char *pw, const char *cert,
- int machine_managed, const char *test,
- const char *imsi, const char *dmacc_username,
- const char *dmacc_password,
- xml_node_t *policy_node)
-{
- xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p;
- xml_node_t *cred, *eap, *userpw;
-
- pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
- "PerProviderSubscription");
- if (!pps) {
- xml_node_free(ctx->xml, policy_node);
- return NULL;
- }
-
- add_text_node(ctx, pps, "UpdateIdentifier", "1");
-
- c = xml_node_create(ctx->xml, pps, NULL, "Cred01");
-
- add_text_node(ctx, c, "CredentialPriority", "1");
-
- if (imsi)
- goto skip_aaa_trust_root;
- aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot");
- aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1");
- add_text_node_conf(ctx, realm, aaa1, "CertURL",
- "aaa_trust_root_cert_url");
- if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) {
- debug_print(ctx, 1,
- "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint");
- add_text_node_conf_corrupt(ctx, realm, aaa1,
- "CertSHA256Fingerprint",
- "aaa_trust_root_cert_fingerprint");
- } else {
- add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint",
- "aaa_trust_root_cert_fingerprint");
- }
-
- if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) {
- debug_print(ctx, 1,
- "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint");
- p = xml_node_create(ctx->xml, c, NULL, "Policy");
- upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate");
- add_text_node(ctx, upd, "UpdateInterval", "30");
- add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
- add_text_node(ctx, upd, "Restriction", "Unrestricted");
- add_text_node_conf(ctx, realm, upd, "URI", "policy_url");
- trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
- add_text_node_conf(ctx, realm, trust, "CertURL",
- "policy_trust_root_cert_url");
- add_text_node_conf_corrupt(ctx, realm, trust,
- "CertSHA256Fingerprint",
- "policy_trust_root_cert_fingerprint");
- }
-skip_aaa_trust_root:
-
- upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate");
- add_text_node(ctx, upd, "UpdateInterval", "4294967295");
- add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated");
- add_text_node(ctx, upd, "Restriction", "HomeSP");
- add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url");
- trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot");
- add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url");
- if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) {
- debug_print(ctx, 1,
- "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint");
- add_text_node_conf_corrupt(ctx, realm, trust,
- "CertSHA256Fingerprint",
- "trust_root_cert_fingerprint");
- } else {
- add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint",
- "trust_root_cert_fingerprint");
- }
-
- if (dmacc_username &&
- !build_username_password(ctx, upd, dmacc_username,
- dmacc_password)) {
- xml_node_free(ctx->xml, pps);
- xml_node_free(ctx->xml, policy_node);
- return NULL;
- }
-
- if (policy_node)
- xml_node_add_child(ctx->xml, c, policy_node);
-
- homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP");
- add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name");
- add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn");
-
- xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters");
-
- cred = xml_node_create(ctx->xml, c, NULL, "Credential");
- add_creation_date(ctx, cred);
- if (imsi) {
- xml_node_t *sim;
- const char *type = "18"; /* default to EAP-SIM */
-
- sim = xml_node_create(ctx->xml, cred, NULL, "SIM");
- add_text_node(ctx, sim, "IMSI", imsi);
- if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0)
- type = "23";
- else if (ctx->eap_method &&
- os_strcmp(ctx->eap_method, "AKA'") == 0)
- type = "50";
- add_text_node(ctx, sim, "EAPType", type);
- } else if (cert) {
- xml_node_t *dc;
- dc = xml_node_create(ctx->xml, cred, NULL,
- "DigitalCertificate");
- add_text_node(ctx, dc, "CertificateType", "x509v3");
- add_text_node(ctx, dc, "CertSHA256Fingerprint", cert);
- } else {
- userpw = build_username_password(ctx, cred, user, pw);
- add_text_node(ctx, userpw, "MachineManaged",
- machine_managed ? "TRUE" : "FALSE");
- eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod");
- add_text_node(ctx, eap, "EAPType", "21");
- add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2");
- }
- add_text_node(ctx, cred, "Realm", realm);
-
- return pps;
-}
-
-
-static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
- const char *session_id,
- const char *user,
- const char *realm,
- int add_est_user)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *enroll, *exec_node;
- char *val;
- char password[11];
- char *b64;
-
- if (add_est_user && new_password(password, sizeof(password)) < 0)
- return NULL;
-
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec");
-
- enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate");
- xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST");
-
- val = db_get_osu_config_val(ctx, realm, "est_url");
- xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI",
- val ? val : "");
- os_free(val);
-
- if (!add_est_user)
- return spp_node;
-
- xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user);
-
- b64 = base64_encode(password, strlen(password), NULL);
- if (b64 == NULL) {
- xml_node_free(ctx->xml, spp_node);
- return NULL;
- }
- xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64);
- free(b64);
-
- db_update_session_password(ctx, user, realm, session_id, password);
-
- return spp_node;
-}
-
-
-static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx,
- const char *session_id,
- int enrollment_done)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *node = NULL;
- xml_node_t *pps, *tnds;
- char buf[400];
- char *str;
- char *user, *realm, *pw, *type, *mm, *test;
- const char *status;
- int cert = 0;
- int machine_managed = 0;
- char *fingerprint;
-
- user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
- realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
- pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
-
- if (!user || !realm || !pw) {
- debug_print(ctx, 1, "Could not find session info from DB for "
- "the new subscription");
- free(user);
- free(realm);
- free(pw);
- return NULL;
- }
-
- mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed");
- if (mm && atoi(mm))
- machine_managed = 1;
- free(mm);
-
- type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
- if (type && strcmp(type, "cert") == 0)
- cert = 1;
- free(type);
-
- if (cert && !enrollment_done) {
- xml_node_t *ret;
- hs20_eventlog(ctx, user, realm, session_id,
- "request client certificate enrollment", NULL);
- ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
- free(user);
- free(realm);
- free(pw);
- return ret;
- }
-
- if (!cert && strlen(pw) == 0) {
- machine_managed = 1;
- free(pw);
- pw = malloc(11);
- if (pw == NULL || new_password(pw, 11) < 0) {
- free(user);
- free(realm);
- free(pw);
- return NULL;
- }
- }
-
- status = "Provisioning complete, request sppUpdateResponse";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
- test = db_get_session_val(ctx, NULL, NULL, session_id, "test");
- if (test)
- debug_print(ctx, 1, "TEST: Requested special behavior: %s",
- test);
- pps = build_pps(ctx, user, realm, pw,
- fingerprint ? fingerprint : NULL, machine_managed,
- test, NULL, NULL, NULL, NULL);
- free(fingerprint);
- free(test);
- if (!pps) {
- xml_node_free(ctx->xml, spp_node);
- free(user);
- free(realm);
- free(pw);
- return NULL;
- }
-
- debug_print(ctx, 1, "Request DB subscription registration on success "
- "notification");
- if (machine_managed) {
- db_update_session_password(ctx, user, realm, session_id, pw);
- db_update_session_machine_managed(ctx, user, realm, session_id,
- machine_managed);
- }
- db_add_session_pps(ctx, user, realm, session_id, pps);
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- "new subscription", pps);
- free(user);
- free(pw);
-
- tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
- xml_node_free(ctx->xml, pps);
- if (!tnds) {
- xml_node_free(ctx->xml, spp_node);
- free(realm);
- return NULL;
- }
-
- str = xml_node_to_str(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (str == NULL) {
- xml_node_free(ctx->xml, spp_node);
- free(realm);
- return NULL;
- }
-
- node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
- free(str);
- snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
- free(realm);
- xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
- xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
-
- return spp_node;
-}
-
-
-static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx,
- const char *user,
- const char *realm,
- const char *session_id)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node;
- xml_node_t *cred;
- char buf[400];
- char *status;
- char *free_account, *pw;
-
- free_account = db_get_osu_config_val(ctx, realm, "free_account");
- if (free_account == NULL)
- return NULL;
- pw = db_get_val(ctx, free_account, realm, "password", 0);
- if (pw == NULL) {
- free(free_account);
- return NULL;
- }
-
- cred = build_credential_pw(ctx, free_account, realm, pw, 1);
- free(free_account);
- free(pw);
- if (!cred) {
- xml_node_free(ctx->xml, cred);
- return NULL;
- }
-
- status = "Remediation complete, request sppUpdateResponse";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (spp_node == NULL)
- return NULL;
-
- snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
- realm);
-
- if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
- xml_node_free(ctx->xml, spp_node);
- return NULL;
- }
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- "free/public remediation", cred);
- xml_node_free(ctx->xml, cred);
-
- return spp_node;
-}
-
-
-static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx,
- const char *user,
- const char *realm, int dmacc,
- const char *session_id)
-{
- char *val;
- enum hs20_session_operation oper;
-
- val = db_get_session_val(ctx, user, realm, session_id, "operation");
- if (val == NULL) {
- debug_print(ctx, 1, "No session %s found to continue",
- session_id);
- return NULL;
- }
- oper = atoi(val);
- free(val);
-
- if (oper == USER_REMEDIATION) {
- return hs20_user_input_remediation(ctx, user, realm, dmacc,
- session_id);
- }
-
- if (oper == FREE_REMEDIATION) {
- return hs20_user_input_free_remediation(ctx, user, realm,
- session_id);
- }
-
- if (oper == SUBSCRIPTION_REGISTRATION) {
- return hs20_user_input_registration(ctx, session_id, 0);
- }
-
- debug_print(ctx, 1, "User session %s not in state for user input "
- "completion", session_id);
- return NULL;
-}
-
-
-static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx,
- const char *session_id)
-{
- char *user, *realm, *cert;
- char *status;
- xml_namespace_t *ns;
- xml_node_t *spp_node, *cred;
- char buf[400];
-
- user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
- realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
- cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
- if (!user || !realm || !cert) {
- debug_print(ctx, 1,
- "Could not find session info from DB for certificate reenrollment");
- free(user);
- free(realm);
- free(cert);
- return NULL;
- }
-
- cred = build_credential_cert(ctx, user, realm, cert);
- if (!cred) {
- debug_print(ctx, 1, "Could not build credential");
- free(user);
- free(realm);
- free(cert);
- return NULL;
- }
-
- status = "Remediation complete, request sppUpdateResponse";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (spp_node == NULL) {
- debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
- free(user);
- free(realm);
- free(cert);
- xml_node_free(ctx->xml, cred);
- return NULL;
- }
-
- snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
- realm);
-
- if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
- debug_print(ctx, 1, "Could not add update node");
- xml_node_free(ctx->xml, spp_node);
- free(user);
- free(realm);
- free(cert);
- return NULL;
- }
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- "certificate reenrollment", cred);
- xml_node_free(ctx->xml, cred);
-
- free(user);
- free(realm);
- free(cert);
- return spp_node;
-}
-
-
-static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx,
- const char *user,
- const char *realm, int dmacc,
- const char *session_id)
-{
- char *val;
- enum hs20_session_operation oper;
-
- val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
- if (val == NULL) {
- debug_print(ctx, 1, "No session %s found to continue",
- session_id);
- return NULL;
- }
- oper = atoi(val);
- free(val);
-
- if (oper == SUBSCRIPTION_REGISTRATION)
- return hs20_user_input_registration(ctx, session_id, 1);
- if (oper == CERT_REENROLL)
- return hs20_cert_reenroll_complete(ctx, session_id);
-
- debug_print(ctx, 1, "User session %s not in state for certificate "
- "enrollment completion", session_id);
- return NULL;
-}
-
-
-static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx,
- const char *user,
- const char *realm, int dmacc,
- const char *session_id)
-{
- char *val;
- enum hs20_session_operation oper;
- xml_node_t *spp_node, *node;
- char *status;
- xml_namespace_t *ns;
-
- val = db_get_session_val(ctx, user, realm, session_id, "operation");
- if (val == NULL) {
- debug_print(ctx, 1, "No session %s found to continue",
- session_id);
- return NULL;
- }
- oper = atoi(val);
- free(val);
-
- if (oper != SUBSCRIPTION_REGISTRATION) {
- debug_print(ctx, 1, "User session %s not in state for "
- "enrollment failure", session_id);
- return NULL;
- }
-
- status = "Error occurred";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (spp_node == NULL)
- return NULL;
- node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
- xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
- "Credentials cannot be provisioned at this time");
- db_remove_session(ctx, user, realm, session_id);
-
- return spp_node;
-}
-
-
-static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx,
- const char *user,
- const char *realm, int dmacc,
- const char *session_id)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *node = NULL;
- xml_node_t *pps, *tnds;
- char buf[400];
- char *str;
- const char *status;
- char dmacc_username[32];
- char dmacc_password[32];
- char *policy;
- xml_node_t *policy_node = NULL;
-
- if (!ctx->imsi) {
- debug_print(ctx, 1, "IMSI not available for SIM provisioning");
- return NULL;
- }
-
- if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 ||
- new_password(dmacc_password, sizeof(dmacc_password)) < 0) {
- debug_print(ctx, 1,
- "Failed to generate DMAcc username/password");
- return NULL;
- }
-
- status = "Provisioning complete, request sppUpdateResponse";
- spp_node = build_post_dev_data_response(ctx, &ns, session_id, status,
- NULL);
- if (!spp_node)
- return NULL;
-
- policy = db_get_osu_config_val(ctx, realm, "sim_policy");
- if (policy) {
- policy_node = read_policy_file(ctx, policy);
- os_free(policy);
- if (!policy_node) {
- xml_node_free(ctx->xml, spp_node);
- return NULL;
- }
- update_policy_update_uri(ctx, realm, policy_node);
- node = get_node_uri(ctx->xml, policy_node,
- "Policy/PolicyUpdate");
- if (node)
- build_username_password(ctx, node, dmacc_username,
- dmacc_password);
- }
-
- pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi,
- dmacc_username, dmacc_password, policy_node);
- if (!pps) {
- xml_node_free(ctx->xml, spp_node);
- return NULL;
- }
-
- debug_print(ctx, 1,
- "Request DB subscription registration on success notification");
- if (!user || !user[0])
- user = ctx->imsi;
- db_add_session(ctx, user, realm, session_id, NULL, NULL,
- SUBSCRIPTION_REGISTRATION, NULL);
- db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password);
- if (ctx->eap_method)
- db_add_session_eap_method(ctx, session_id, ctx->eap_method);
- if (ctx->id_hash)
- db_add_session_id_hash(ctx, session_id, ctx->id_hash);
- db_add_session_pps(ctx, user, realm, session_id, pps);
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- "new subscription", pps);
-
- tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL);
- xml_node_free(ctx->xml, pps);
- if (!tnds) {
- xml_node_free(ctx->xml, spp_node);
- return NULL;
- }
-
- str = xml_node_to_str(ctx->xml, tnds);
- xml_node_free(ctx->xml, tnds);
- if (!str) {
- xml_node_free(ctx->xml, spp_node);
- return NULL;
- }
-
- node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str);
- free(str);
- snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm);
- xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf);
- xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS);
-
- return spp_node;
-}
-
-
-static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx,
- xml_node_t *node,
- const char *user,
- const char *realm,
- const char *session_id,
- int dmacc)
-{
- const char *req_reason;
- char *redirect_uri = NULL;
- char *req_reason_buf = NULL;
- char str[200];
- xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL;
- xml_node_t *mo, *macaddr;
- char *version;
- int valid;
- char *supp, *pos;
- char *err;
- u8 wifi_mac_addr[ETH_ALEN];
-
- version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
- "sppVersion");
- if (version == NULL || strstr(version, "1.0") == NULL) {
- ret = build_post_dev_data_response(
- ctx, NULL, session_id, "Error occurred",
- "SPP version not supported");
- hs20_eventlog_node(ctx, user, realm, session_id,
- "Unsupported sppVersion", ret);
- xml_node_get_attr_value_free(ctx->xml, version);
- return ret;
- }
- xml_node_get_attr_value_free(ctx->xml, version);
-
- mo = get_node(ctx->xml, node, "supportedMOList");
- if (mo == NULL) {
- ret = build_post_dev_data_response(
- ctx, NULL, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm, session_id,
- "No supportedMOList element", ret);
- return ret;
- }
- supp = xml_node_get_text(ctx->xml, mo);
- for (pos = supp; pos && *pos; pos++)
- *pos = tolower(*pos);
- if (supp == NULL ||
- strstr(supp, URN_OMA_DM_DEVINFO) == NULL ||
- strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL ||
- strstr(supp, URN_HS20_PPS) == NULL) {
- xml_node_get_text_free(ctx->xml, supp);
- ret = build_post_dev_data_response(
- ctx, NULL, session_id, "Error occurred",
- "One or more mandatory MOs not supported");
- hs20_eventlog_node(ctx, user, realm, session_id,
- "Unsupported MOs", ret);
- return ret;
- }
- xml_node_get_text_free(ctx->xml, supp);
-
- req_reason_buf = xml_node_get_attr_value(ctx->xml, node,
- "requestReason");
- if (req_reason_buf == NULL) {
- debug_print(ctx, 1, "No requestReason attribute");
- return NULL;
- }
- req_reason = req_reason_buf;
-
- redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI");
-
- debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s",
- req_reason, session_id, redirect_uri);
- snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s",
- req_reason);
- hs20_eventlog(ctx, user, realm, session_id, str, NULL);
-
- devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err);
- if (devinfo == NULL) {
- ret = build_post_dev_data_response(ctx, NULL, session_id,
- "Error occurred", "Other");
- hs20_eventlog_node(ctx, user, realm, session_id,
- "No DevInfo moContainer in sppPostDevData",
- ret);
- os_free(err);
- goto out;
- }
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- "Received DevInfo MO", devinfo);
- if (valid == 0) {
- hs20_eventlog(ctx, user, realm, session_id,
- "OMA-DM DDF DTD validation errors in DevInfo MO",
- err);
- ret = build_post_dev_data_response(ctx, NULL, session_id,
- "Error occurred", "Other");
- os_free(err);
- goto out;
- }
- os_free(err);
- if (user)
- db_update_mo(ctx, user, realm, "devinfo", devinfo);
-
- devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err);
- if (devdetail == NULL) {
- ret = build_post_dev_data_response(ctx, NULL, session_id,
- "Error occurred", "Other");
- hs20_eventlog_node(ctx, user, realm, session_id,
- "No DevDetail moContainer in sppPostDevData",
- ret);
- os_free(err);
- goto out;
- }
-
- hs20_eventlog_node(ctx, user, realm, session_id,
- "Received DevDetail MO", devdetail);
- if (valid == 0) {
- hs20_eventlog(ctx, user, realm, session_id,
- "OMA-DM DDF DTD validation errors "
- "in DevDetail MO", err);
- ret = build_post_dev_data_response(ctx, NULL, session_id,
- "Error occurred", "Other");
- os_free(err);
- goto out;
- }
- os_free(err);
-
- os_memset(wifi_mac_addr, 0, ETH_ALEN);
- macaddr = get_node(ctx->xml, devdetail,
- "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress");
- if (macaddr) {
- char *addr, buf[50];
-
- addr = xml_node_get_text(ctx->xml, macaddr);
- if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) {
- snprintf(buf, sizeof(buf), "DevDetail MAC address: "
- MACSTR, MAC2STR(wifi_mac_addr));
- hs20_eventlog(ctx, user, realm, session_id, buf, NULL);
- xml_node_get_text_free(ctx->xml, addr);
- } else {
- hs20_eventlog(ctx, user, realm, session_id,
- "Could not extract MAC address from DevDetail",
- NULL);
- }
- } else {
- hs20_eventlog(ctx, user, realm, session_id,
- "No MAC address in DevDetail", NULL);
- }
-
- if (user)
- db_update_mo(ctx, user, realm, "devdetail", devdetail);
-
- if (user)
- mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err);
- else {
- mo = NULL;
- err = NULL;
- }
- if (user && mo) {
- hs20_eventlog_node(ctx, user, realm, session_id,
- "Received PPS MO", mo);
- if (valid == 0) {
- hs20_eventlog(ctx, user, realm, session_id,
- "OMA-DM DDF DTD validation errors "
- "in PPS MO", err);
- xml_node_get_attr_value_free(ctx->xml, redirect_uri);
- os_free(err);
- return build_post_dev_data_response(
- ctx, NULL, session_id,
- "Error occurred", "Other");
- }
- db_update_mo(ctx, user, realm, "pps", mo);
- db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc);
- xml_node_free(ctx->xml, mo);
- }
- os_free(err);
-
- if (user && !mo) {
- char *fetch;
- int fetch_pps;
-
- fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc);
- fetch_pps = fetch ? atoi(fetch) : 0;
- free(fetch);
-
- if (fetch_pps) {
- enum hs20_session_operation oper;
- if (strcasecmp(req_reason, "Subscription remediation")
- == 0)
- oper = CONTINUE_SUBSCRIPTION_REMEDIATION;
- else if (strcasecmp(req_reason, "Policy update") == 0)
- oper = CONTINUE_POLICY_UPDATE;
- else
- oper = NO_OPERATION;
- if (db_add_session(ctx, user, realm, session_id, NULL,
- NULL, oper, NULL) < 0)
- goto out;
-
- ret = spp_exec_upload_mo(ctx, session_id,
- URN_HS20_PPS);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "request PPS MO upload",
- ret);
- goto out;
- }
- }
-
- if (user && strcasecmp(req_reason, "MO upload") == 0) {
- char *val = db_get_session_val(ctx, user, realm, session_id,
- "operation");
- enum hs20_session_operation oper;
- if (!val) {
- debug_print(ctx, 1, "No session %s found to continue",
- session_id);
- goto out;
- }
- oper = atoi(val);
- free(val);
- if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION)
- req_reason = "Subscription remediation";
- else if (oper == CONTINUE_POLICY_UPDATE)
- req_reason = "Policy update";
- else {
- debug_print(ctx, 1,
- "No pending operation in session %s",
- session_id);
- goto out;
- }
- }
-
- if (strcasecmp(req_reason, "Subscription registration") == 0) {
- ret = hs20_subscription_registration(ctx, realm, session_id,
- redirect_uri,
- wifi_mac_addr);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "subscription registration response",
- ret);
- goto out;
- }
- if (user && strcasecmp(req_reason, "Subscription remediation") == 0) {
- ret = hs20_subscription_remediation(ctx, user, realm,
- session_id, dmacc,
- redirect_uri);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "subscription remediation response",
- ret);
- goto out;
- }
- if (user && strcasecmp(req_reason, "Policy update") == 0) {
- ret = hs20_policy_update(ctx, user, realm, session_id, dmacc);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "policy update response",
- ret);
- goto out;
- }
-
- if (strcasecmp(req_reason, "User input completed") == 0) {
- db_add_session_devinfo(ctx, session_id, devinfo);
- db_add_session_devdetail(ctx, session_id, devdetail);
- ret = hs20_user_input_complete(ctx, user, realm, dmacc,
- session_id);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "user input completed response", ret);
- goto out;
- }
-
- if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) {
- ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc,
- session_id);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "certificate enrollment response", ret);
- goto out;
- }
-
- if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) {
- ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc,
- session_id);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "certificate enrollment failed response",
- ret);
- goto out;
- }
-
- if (strcasecmp(req_reason, "Subscription provisioning") == 0) {
- ret = hs20_sim_provisioning(ctx, user, realm, dmacc,
- session_id);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "subscription provisioning response",
- ret);
- goto out;
- }
-
- debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'",
- req_reason, user);
-out:
- xml_node_get_attr_value_free(ctx->xml, req_reason_buf);
- xml_node_get_attr_value_free(ctx->xml, redirect_uri);
- if (devinfo)
- xml_node_free(ctx->xml, devinfo);
- if (devdetail)
- xml_node_free(ctx->xml, devdetail);
- return ret;
-}
-
-
-static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx,
- const char *session_id,
- const char *status,
- const char *error_code)
-{
- xml_namespace_t *ns;
- xml_node_t *spp_node, *node;
-
- spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
- "sppExchangeComplete");
-
-
- xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
- xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
- xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status);
-
- if (error_code) {
- node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
- xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
- error_code);
- }
-
- return spp_node;
-}
-
-
-static int add_subscription(struct hs20_svc *ctx, const char *session_id)
-{
- char *user, *realm, *pw, *pw_mm, *pps, *str;
- char *osu_user, *osu_password, *eap_method;
- char *policy = NULL;
- char *sql;
- int ret = -1;
- char *free_account;
- int free_acc;
- char *type;
- int cert = 0;
- char *cert_pem, *fingerprint;
- const char *method;
-
- user = db_get_session_val(ctx, NULL, NULL, session_id, "user");
- realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm");
- pw = db_get_session_val(ctx, NULL, NULL, session_id, "password");
- pw_mm = db_get_session_val(ctx, NULL, NULL, session_id,
- "machine_managed");
- pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps");
- cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem");
- fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert");
- type = db_get_session_val(ctx, NULL, NULL, session_id, "type");
- if (type && strcmp(type, "cert") == 0)
- cert = 1;
- free(type);
- osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user");
- osu_password = db_get_session_val(ctx, NULL, NULL, session_id,
- "osu_password");
- eap_method = db_get_session_val(ctx, NULL, NULL, session_id,
- "eap_method");
-
- if (!user || !realm || !pw) {
- debug_print(ctx, 1, "Could not find session info from DB for "
- "the new subscription");
- goto out;
- }
-
- free_account = db_get_osu_config_val(ctx, realm, "free_account");
- free_acc = free_account && strcmp(free_account, user) == 0;
- free(free_account);
-
- policy = db_get_osu_config_val(ctx, realm, "sim_policy");
-
- debug_print(ctx, 1,
- "New subscription: user='%s' realm='%s' free_acc=%d",
- user, realm, free_acc);
- debug_print(ctx, 1, "New subscription: pps='%s'", pps);
-
- sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE "
- "sessionid=%Q AND (user='' OR user IS NULL)",
- user, realm, session_id);
- if (sql) {
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to update eventlog in "
- "sqlite database: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
- }
-
- if (free_acc) {
- hs20_eventlog(ctx, user, realm, session_id,
- "completed shared free account registration",
- NULL);
- ret = 0;
- goto out;
- }
-
- str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
-
- if (eap_method && eap_method[0])
- method = eap_method;
- else
- method = cert ? "TLS" : "TTLS-MSCHAPV2";
- sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)",
- user, realm, cert ? 0 : 1,
- method,
- fingerprint ? fingerprint : "",
- cert_pem ? cert_pem : "",
- pw_mm && atoi(pw_mm) ? 1 : 0,
- str ? str : "",
- osu_user ? osu_user : "",
- osu_password ? osu_password : "",
- policy ? policy : "");
- free(str);
- if (sql == NULL)
- goto out;
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
- debug_print(ctx, 1, "Failed to add user in sqlite database: %s",
- sqlite3_errmsg(ctx->db));
- sqlite3_free(sql);
- goto out;
- }
- sqlite3_free(sql);
-
- if (cert)
- ret = 0;
- else
- ret = update_password(ctx, user, realm, pw, 0);
- if (ret < 0) {
- sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')",
- user, realm);
- if (sql) {
- debug_print(ctx, 1, "DB: %s", sql);
- sqlite3_exec(ctx->db, sql, NULL, NULL, NULL);
- sqlite3_free(sql);
- }
- }
-
- if (pps)
- db_update_mo_str(ctx, user, realm, "pps", pps);
-
- str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo");
- if (str) {
- db_update_mo_str(ctx, user, realm, "devinfo", str);
- free(str);
- }
-
- str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail");
- if (str) {
- db_update_mo_str(ctx, user, realm, "devdetail", str);
- free(str);
- }
-
- if (cert && user) {
- const char *serialnum;
-
- str = db_get_session_val(ctx, NULL, NULL, session_id,
- "mac_addr");
-
- if (os_strncmp(user, "cert-", 5) == 0)
- serialnum = user + 5;
- else
- serialnum = "";
- sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)",
- str ? str : "", user, realm ? realm : "",
- serialnum);
- free(str);
- if (sql) {
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
- SQLITE_OK) {
- debug_print(ctx, 1,
- "Failed to add cert_enroll entry into sqlite database: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
- }
- }
-
- str = db_get_session_val(ctx, NULL, NULL, session_id,
- "mobile_identifier_hash");
- if (str) {
- sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q",
- str);
- if (sql) {
- debug_print(ctx, 1, "DB: %s", sql);
- if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) !=
- SQLITE_OK) {
- debug_print(ctx, 1,
- "Failed to delete pending sim_provisioning entry: %s",
- sqlite3_errmsg(ctx->db));
- }
- sqlite3_free(sql);
- }
- os_free(str);
- }
-
- if (ret == 0) {
- hs20_eventlog(ctx, user, realm, session_id,
- "completed subscription registration", NULL);
- }
-
-out:
- free(user);
- free(realm);
- free(pw);
- free(pw_mm);
- free(pps);
- free(cert_pem);
- free(fingerprint);
- free(osu_user);
- free(osu_password);
- free(eap_method);
- os_free(policy);
- return ret;
-}
-
-
-static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx,
- xml_node_t *node,
- const char *user,
- const char *realm,
- const char *session_id,
- int dmacc)
-{
- char *status;
- xml_node_t *ret;
- char *val;
- enum hs20_session_operation oper;
-
- status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
- "sppStatus");
- if (status == NULL) {
- debug_print(ctx, 1, "No sppStatus attribute");
- return NULL;
- }
-
- debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
- status, session_id);
-
- val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
- if (!val) {
- debug_print(ctx, 1,
- "No session active for sessionID: %s",
- session_id);
- oper = NO_OPERATION;
- } else
- oper = atoi(val);
-
- if (strcasecmp(status, "OK") == 0) {
- char *new_pw = NULL;
-
- xml_node_get_attr_value_free(ctx->xml, status);
-
- if (oper == USER_REMEDIATION) {
- new_pw = db_get_session_val(ctx, user, realm,
- session_id, "password");
- if (new_pw == NULL || strlen(new_pw) == 0) {
- free(new_pw);
- ret = build_spp_exchange_complete(
- ctx, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm,
- session_id, "No password "
- "had been assigned for "
- "session", ret);
- db_remove_session(ctx, user, realm, session_id);
- return ret;
- }
- oper = UPDATE_PASSWORD;
- }
- if (oper == UPDATE_PASSWORD) {
- if (!new_pw) {
- new_pw = db_get_session_val(ctx, user, realm,
- session_id,
- "password");
- if (!new_pw) {
- db_remove_session(ctx, user, realm,
- session_id);
- return NULL;
- }
- }
- debug_print(ctx, 1, "Update user '%s' password in DB",
- user);
- if (update_password(ctx, user, realm, new_pw, dmacc) <
- 0) {
- debug_print(ctx, 1, "Failed to update user "
- "'%s' password in DB", user);
- ret = build_spp_exchange_complete(
- ctx, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm,
- session_id, "Failed to "
- "update database", ret);
- db_remove_session(ctx, user, realm, session_id);
- return ret;
- }
- hs20_eventlog(ctx, user, realm,
- session_id, "Updated user password "
- "in database", NULL);
- }
- if (oper == CLEAR_REMEDIATION) {
- debug_print(ctx, 1,
- "Clear remediation requirement for user '%s' in DB",
- user);
- if (clear_remediation(ctx, user, realm, dmacc) < 0) {
- debug_print(ctx, 1,
- "Failed to clear remediation requirement for user '%s' in DB",
- user);
- ret = build_spp_exchange_complete(
- ctx, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm,
- session_id,
- "Failed to update database",
- ret);
- db_remove_session(ctx, user, realm, session_id);
- return ret;
- }
- hs20_eventlog(ctx, user, realm,
- session_id,
- "Cleared remediation requirement in database",
- NULL);
- }
- if (oper == SUBSCRIPTION_REGISTRATION) {
- if (add_subscription(ctx, session_id) < 0) {
- debug_print(ctx, 1, "Failed to add "
- "subscription into DB");
- ret = build_spp_exchange_complete(
- ctx, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm,
- session_id, "Failed to "
- "update database", ret);
- db_remove_session(ctx, user, realm, session_id);
- return ret;
- }
- }
- if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) {
- char *val;
- val = db_get_val(ctx, user, realm, "remediation",
- dmacc);
- if (val && strcmp(val, "policy") == 0)
- db_update_val(ctx, user, realm, "remediation",
- "", dmacc);
- free(val);
- }
- if (oper == POLICY_UPDATE)
- db_update_val(ctx, user, realm, "polupd_done", "1",
- dmacc);
- if (oper == CERT_REENROLL) {
- char *new_user;
- char event[200];
-
- new_user = db_get_session_val(ctx, NULL, NULL,
- session_id, "user");
- if (!new_user) {
- debug_print(ctx, 1,
- "Failed to find new user name (cert-serialnum)");
- ret = build_spp_exchange_complete(
- ctx, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm,
- session_id,
- "Failed to find new user name (cert reenroll)",
- ret);
- db_remove_session(ctx, NULL, NULL, session_id);
- return ret;
- }
-
- debug_print(ctx, 1,
- "Update certificate user entry to use the new serial number (old=%s new=%s)",
- user, new_user);
- os_snprintf(event, sizeof(event), "renamed user to: %s",
- new_user);
- hs20_eventlog(ctx, user, realm, session_id, event,
- NULL);
-
- if (db_update_val(ctx, user, realm, "identity",
- new_user, 0) < 0 ||
- db_update_val(ctx, new_user, realm, "remediation",
- "", 0) < 0) {
- debug_print(ctx, 1,
- "Failed to update user name (cert-serialnum)");
- ret = build_spp_exchange_complete(
- ctx, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm,
- session_id,
- "Failed to update user name (cert reenroll)",
- ret);
- db_remove_session(ctx, NULL, NULL, session_id);
- os_free(new_user);
- return ret;
- }
-
- os_free(new_user);
- }
- ret = build_spp_exchange_complete(
- ctx, session_id,
- "Exchange complete, release TLS connection", NULL);
- hs20_eventlog_node(ctx, user, realm, session_id,
- "Exchange completed", ret);
- db_remove_session(ctx, NULL, NULL, session_id);
- return ret;
- }
-
- ret = build_spp_exchange_complete(ctx, session_id, "Error occurred",
- "Other");
- hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret);
- db_remove_session(ctx, user, realm, session_id);
- xml_node_get_attr_value_free(ctx->xml, status);
- return ret;
-}
-
-
-#define SPP_SESSION_ID_LEN 16
-
-static char * gen_spp_session_id(void)
-{
- FILE *f;
- int i;
- char *session;
-
- session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1);
- if (session == NULL)
- return NULL;
-
- f = fopen("/dev/urandom", "r");
- if (f == NULL) {
- os_free(session);
- return NULL;
- }
- for (i = 0; i < SPP_SESSION_ID_LEN; i++)
- os_snprintf(session + i * 2, 3, "%02x", fgetc(f));
-
- fclose(f);
- return session;
-}
-
-xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
- const char *auth_user,
- const char *auth_realm, int dmacc)
-{
- xml_node_t *ret = NULL;
- char *session_id;
- const char *op_name;
- char *xml_err;
- char fname[200];
-
- debug_dump_node(ctx, "received request", node);
-
- if (!dmacc && auth_user && auth_realm) {
- char *real;
- real = db_get_val(ctx, auth_user, auth_realm, "identity", 0);
- if (!real) {
- real = db_get_val(ctx, auth_user, auth_realm,
- "identity", 1);
- if (real)
- dmacc = 1;
- }
- os_free(real);
- }
-
- snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir);
- if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) {
- /*
- * We may not be able to extract the sessionID from invalid
- * input, but well, we can try.
- */
- session_id = xml_node_get_attr_value_ns(ctx->xml, node,
- SPP_NS_URI,
- "sessionID");
- debug_print(ctx, 1,
- "SPP message failed validation, xsd file: %s xml-error: %s",
- fname, xml_err);
- hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
- "SPP message failed validation", node);
- hs20_eventlog(ctx, auth_user, auth_realm, session_id,
- "Validation errors", xml_err);
- os_free(xml_err);
- xml_node_get_attr_value_free(ctx->xml, session_id);
- /* TODO: what to return here? */
- ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
- "SppValidationError");
- return ret;
- }
-
- session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI,
- "sessionID");
- if (session_id) {
- char *tmp;
- debug_print(ctx, 1, "Received sessionID %s", session_id);
- tmp = os_strdup(session_id);
- xml_node_get_attr_value_free(ctx->xml, session_id);
- if (tmp == NULL)
- return NULL;
- session_id = tmp;
- } else {
- session_id = gen_spp_session_id();
- if (session_id == NULL) {
- debug_print(ctx, 1, "Failed to generate sessionID");
- return NULL;
- }
- debug_print(ctx, 1, "Generated sessionID %s", session_id);
- }
-
- op_name = xml_node_get_localname(ctx->xml, node);
- if (op_name == NULL) {
- debug_print(ctx, 1, "Could not get op_name");
- return NULL;
- }
-
- if (strcmp(op_name, "sppPostDevData") == 0) {
- hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
- "sppPostDevData received and validated",
- node);
- ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm,
- session_id, dmacc);
- } else if (strcmp(op_name, "sppUpdateResponse") == 0) {
- hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
- "sppUpdateResponse received and validated",
- node);
- ret = hs20_spp_update_response(ctx, node, auth_user,
- auth_realm, session_id, dmacc);
- } else {
- hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
- "Unsupported SPP message received and "
- "validated", node);
- debug_print(ctx, 1, "Unsupported operation '%s'", op_name);
- /* TODO: what to return here? */
- ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
- "SppUnknownCommandError");
- }
- os_free(session_id);
-
- if (ret == NULL) {
- /* TODO: what to return here? */
- ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL,
- "SppInternalError");
- }
-
- return ret;
-}
-
-
-int hs20_spp_server_init(struct hs20_svc *ctx)
-{
- char fname[200];
- ctx->db = NULL;
- snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir);
- if (sqlite3_open(fname, &ctx->db)) {
- printf("Failed to open sqlite database: %s\n",
- sqlite3_errmsg(ctx->db));
- sqlite3_close(ctx->db);
- return -1;
- }
-
- return 0;
-}
-
-
-void hs20_spp_server_deinit(struct hs20_svc *ctx)
-{
- sqlite3_close(ctx->db);
- ctx->db = NULL;
-}
diff --git a/hs20/server/spp_server.h b/hs20/server/spp_server.h
deleted file mode 100644
index 421974c..0000000
--- a/hs20/server/spp_server.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Hotspot 2.0 SPP server
- * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef SPP_SERVER_H
-#define SPP_SERVER_H
-
-struct hs20_svc {
- const void *ctx;
- struct xml_node_ctx *xml;
- char *root_dir;
- FILE *debug_log;
- sqlite3 *db;
- const char *addr;
- const char *test;
- const char *imsi;
- const char *eap_method;
- const char *id_hash;
-};
-
-
-void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...)
- __attribute__ ((format (printf, 3, 4)));
-void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node);
-
-xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node,
- const char *auth_user,
- const char *auth_realm, int dmacc);
-int hs20_spp_server_init(struct hs20_svc *ctx);
-void hs20_spp_server_deinit(struct hs20_svc *ctx);
-
-#endif /* SPP_SERVER_H */
diff --git a/hs20/server/sql-example.txt b/hs20/server/sql-example.txt
deleted file mode 100644
index 20dcf2f..0000000
--- a/hs20/server/sql-example.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','fqdn','example.com');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','friendly_name','Example Operator');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','remediation_url','https://subscription-server.osu.example.com/hs20/remediation.php?session_id=');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_remediation_url','https://subscription-server.osu.example.com/hs20/free-remediation.php?session_id=');
-INSERT INTO osu_config(realm,field,value) VALUES('example.com','signup_url','https://subscription-server.osu.example.com/hs20/signup.php?session_id=');
-
-
-INSERT INTO users(identity,realm,methods,password,phase2,shared) VALUES('free','example.com','TTLS-MSCHAPV2','free',1,1);
-
-INSERT INTO wildcards(identity,methods) VALUES('','TTLS,TLS');
diff --git a/hs20/server/sql.txt b/hs20/server/sql.txt
deleted file mode 100644
index 2cc6ede..0000000
--- a/hs20/server/sql.txt
+++ /dev/null
@@ -1,108 +0,0 @@
-CREATE TABLE eventlog(
- user TEXT,
- realm TEXT,
- sessionid TEXT COLLATE NOCASE,
- timestamp TEXT,
- notes TEXT,
- dump TEXT,
- addr TEXT
-);
-
-CREATE TABLE sessions(
- timestamp TEXT,
- id TEXT COLLATE NOCASE,
- user TEXT,
- realm TEXT,
- password TEXT,
- machine_managed BOOLEAN,
- operation INTEGER,
- type TEXT,
- pps TEXT,
- redirect_uri TEXT,
- devinfo TEXT,
- devdetail TEXT,
- cert TEXT,
- cert_pem TEXT,
- mac_addr TEXT,
- osu_user TEXT,
- osu_password TEXT,
- eap_method TEXT,
- mobile_identifier_hash TEXT,
- test TEXT
-);
-
-CREATE index sessions_id_index ON sessions(id);
-
-CREATE TABLE osu_config(
- realm TEXT,
- field TEXT,
- value TEXT
-);
-
-CREATE TABLE users(
- identity TEXT PRIMARY KEY,
- methods TEXT,
- password TEXT,
- machine_managed BOOLEAN,
- remediation TEXT,
- phase2 INTEGER,
- realm TEXT,
- policy TEXT,
- devinfo TEXT,
- devdetail TEXT,
- pps TEXT,
- fetch_pps INTEGER,
- osu_user TEXT,
- osu_password TEXT,
- shared INTEGER,
- cert TEXT,
- cert_pem TEXT,
- t_c_timestamp INTEGER,
- mac_addr TEXT,
- last_msk TEXT,
- polupd_done TEXT,
- subrem TEXT
-);
-
-CREATE TABLE wildcards(
- identity TEXT PRIMARY KEY,
- methods TEXT
-);
-
-CREATE TABLE authlog(
- timestamp TEXT,
- session TEXT,
- nas_ip TEXT,
- username TEXT,
- note TEXT
-);
-
-CREATE TABLE pending_tc(
- mac_addr TEXT PRIMARY KEY,
- identity TEXT
-);
-
-CREATE TABLE current_sessions(
- mac_addr TEXT PRIMARY KEY,
- identity TEXT,
- start_time TEXT,
- nas TEXT,
- hs20_t_c_filtering BOOLEAN,
- waiting_coa_ack BOOLEAN,
- coa_ack_received BOOLEAN
-);
-
-CREATE TABLE cert_enroll(
- mac_addr TEXT PRIMARY KEY,
- user TEXT,
- realm TEXT,
- serialnum TEXT
-);
-
-CREATE TABLE sim_provisioning(
- mobile_identifier_hash TEXT PRIMARY KEY,
- imsi TEXT,
- mac_addr TEXT,
- eap_method TEXT,
- timestamp TEXT
-);
diff --git a/hs20/server/www/add-free.php b/hs20/server/www/add-free.php
deleted file mode 100644
index 1efc655..0000000
--- a/hs20/server/www/add-free.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (isset($_POST["id"]))
- $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
-else
- die("Missing session id");
-if (strlen($id) < 32)
- die("Invalid session id");
-
-$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
-if ($row == false) {
- die("Session not found");
-}
-
-$uri = $row['redirect_uri'];
-$rowid = $row['rowid'];
-$realm = $row['realm'];
-
-$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
-if (!$row || strlen($row['value']) == 0) {
- die("Free account disabled");
-}
-
-$user = $row['value'];
-
-$row = $db->query("SELECT password FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
-if (!$row)
- die("Free account not found");
-
-$pw = $row['password'];
-
-if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', machine_managed='1' WHERE rowid=$rowid")) {
- die("Failed to update session database");
-}
-
-$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
- "VALUES ('$user', '$realm', '$id', " .
- "strftime('%Y-%m-%d %H:%M:%f','now'), " .
- "'completed user input response for a new PPS MO')");
-
-header("Location: $uri", true, 302);
-
-?>
diff --git a/hs20/server/www/add-mo.php b/hs20/server/www/add-mo.php
deleted file mode 100644
index a3b4513..0000000
--- a/hs20/server/www/add-mo.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (isset($_POST["id"]))
- $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
-else
- die("Missing session id");
-
-$user = $_POST["user"];
-$pw = $_POST["password"];
-if (strlen($id) < 32 || !isset($user) || !isset($pw)) {
- die("Invalid POST data");
-}
-
-if (strlen($user) < 1 || strncasecmp($user, "cert-", 5) == 0) {
- echo "<html><body><p><red>Invalid username</red></p>\n";
- echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
- echo "</body></html>\n";
- exit;
-}
-
-$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
-if ($row == false) {
- die("Session not found");
-}
-$realm = $row['realm'];
-
-$userrow = $db->query("SELECT identity FROM users WHERE identity='$user' AND realm='$realm'")->fetch();
-if ($userrow) {
- echo "<html><body><p><red>Selected username is not available</red></p>\n";
- echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n";
- echo "</body></html>\n";
- exit;
-}
-
-$uri = $row['redirect_uri'];
-$rowid = $row['rowid'];
-
-if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', type='password' WHERE rowid=$rowid")) {
- die("Failed to update session database");
-}
-
-$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
- "VALUES ('$user', '$realm', '$id', " .
- "strftime('%Y-%m-%d %H:%M:%f','now'), " .
- "'completed user input response for a new PPS MO')");
-
-header("Location: $uri", true, 302);
-
-?>
diff --git a/hs20/server/www/cert-enroll.php b/hs20/server/www/cert-enroll.php
deleted file mode 100644
index f023ca5..0000000
--- a/hs20/server/www/cert-enroll.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (isset($_GET["id"]))
- $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
-else
- die("Missing session id");
-if (strlen($id) < 32)
- die("Invalid session id");
-
-$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
-if ($row == false) {
- die("Session not found");
-}
-
-$uri = $row['redirect_uri'];
-$rowid = $row['rowid'];
-$realm = $row['realm'];
-
-$user = sha1(mt_rand());
-
-if (!$db->exec("UPDATE sessions SET user='$user', type='cert' WHERE rowid=$rowid")) {
- die("Failed to update session database");
-}
-
-$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
- "VALUES ('', '$realm', '$id', " .
- "strftime('%Y-%m-%d %H:%M:%f','now'), " .
- "'completed user input response for client certificate enrollment')");
-
-header("Location: $uri", true, 302);
-
-?>
diff --git a/hs20/server/www/config.php b/hs20/server/www/config.php
deleted file mode 100644
index 4272b10..0000000
--- a/hs20/server/www/config.php
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-$osu_root = "/home/user/hs20-server";
-$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db";
-$t_c_file = "$osu_root/terms-and-conditions";
-$t_c_timestamp = 123456789;
-$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as"
-?>
diff --git a/hs20/server/www/est.php b/hs20/server/www/est.php
deleted file mode 100644
index b7fb260..0000000
--- a/hs20/server/www/est.php
+++ /dev/null
@@ -1,232 +0,0 @@
-<?php
-
-require('config.php');
-
-$params = explode("/", $_SERVER["PATH_INFO"], 3);
-$realm = $params[1];
-$cmd = $params[2];
-$method = $_SERVER["REQUEST_METHOD"];
-
-unset($user);
-unset($rowid);
-
-$db = new PDO($osu_db);
-if (!$db) {
- error_log("EST: Could not access database");
- die("Could not access database");
-}
-
-if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
- $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
- 'uri'=>1, 'response'=>1);
- $data = array();
- $keys = implode('|', array_keys($needed));
- preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
- $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
- foreach ($matches as $m) {
- $data[$m[1]] = $m[3] ? $m[3] : $m[4];
- unset($needed[$m[1]]);
- }
- if ($needed) {
- error_log("EST: Missing auth parameter");
- die('Authentication failed');
- }
- $user = $data['username'];
- if (strlen($user) < 1) {
- error_log("EST: Empty username");
- die('Authentication failed');
- }
-
- $sql = "SELECT rowid,password,operation FROM sessions " .
- "WHERE user='$user' AND realm='$realm'";
- $q = $db->query($sql);
- if (!$q) {
- error_log("EST: Session not found for user=$user realm=$realm");
- die("Session not found");
- }
- $row = $q->fetch();
- if (!$row) {
- error_log("EST: Session fetch failed for user=$user realm=$realm");
- die('Session not found');
- }
- $rowid = $row['rowid'];
-
- $oper = $row['operation'];
- if ($oper != '5') {
- error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
- die("Session not found");
- }
- $pw = $row['password'];
- if (strlen($pw) < 1) {
- error_log("EST: Empty password for user=$user realm=$realm");
- die('Authentication failed');
- }
-
- $A1 = md5($user . ':' . $realm . ':' . $pw);
- $A2 = md5($method . ':' . $data['uri']);
- $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
- $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
- if ($data['response'] != $resp) {
- error_log("EST: Incorrect authentication response for user=$user realm=$realm");
- die('Authentication failed');
- }
-} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
- $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
- isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
- $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
- $sql = "SELECT rowid,password,operation FROM sessions " .
- "WHERE user='$user' AND realm='$realm'";
- $q = $db->query($sql);
- if (!$q) {
- error_log("EST: Session not found for user=$user realm=$realm");
- die("Session not found");
- }
- $row = $q->fetch();
- if (!$row) {
- error_log("EST: Session fetch failed for user=$user realm=$realm");
- die('Session not found');
- }
- $rowid = $row['rowid'];
-
- $oper = $row['operation'];
- if ($oper != '10') {
- error_log("EST: Unexpected operation $oper for user=$user realm=$realm");
- die("Session not found");
- }
-}
-
-
-if ($method == "GET" && $cmd == "cacerts") {
- $fname = "$osu_root/est/$realm-cacerts.pkcs7";
- if (!file_exists($fname)) {
- error_log("EST: cacerts - unknown realm $realm");
- die("Unknown realm");
- }
-
- header("Content-Transfer-Encoding: base64");
- header("Content-Type: application/pkcs7-mime");
-
- $data = file_get_contents($fname);
- echo wordwrap(base64_encode($data), 72, "\n", true);
- echo "\n";
- error_log("EST: cacerts");
-} else if ($method == "GET" && $cmd == "csrattrs") {
- header("Content-Transfer-Encoding: base64");
- header("Content-Type: application/csrattrs");
- readfile("$osu_root/est/est-attrs.b64");
- error_log("EST: csrattrs");
-} else if ($method == "POST" &&
- ($cmd == "simpleenroll" || $cmd == "simplereenroll")) {
- $reenroll = $cmd == "simplereenroll";
- if (!$reenroll && (!isset($user) || strlen($user) == 0)) {
- header('HTTP/1.1 401 Unauthorized');
- header('WWW-Authenticate: Digest realm="'.$realm.
- '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
- error_log("EST: simpleenroll - require authentication");
- die('Authentication required');
- }
- if ($reenroll &&
- (!isset($user) ||
- !isset($_SERVER["SSL_CLIENT_VERIFY"]) ||
- $_SERVER["SSL_CLIENT_VERIFY"] != "SUCCESS")) {
- header('HTTP/1.1 403 Forbidden');
- error_log("EST: simplereenroll - require certificate authentication");
- die('Authentication required');
- }
- if (!isset($_SERVER["CONTENT_TYPE"])) {
- error_log("EST: simpleenroll without Content-Type");
- die("Missing Content-Type");
- }
- if (!stristr($_SERVER["CONTENT_TYPE"], "application/pkcs10")) {
- error_log("EST: simpleenroll - unexpected Content-Type: " .
- $_SERVER["CONTENT_TYPE"]);
- die("Unexpected Content-Type");
- }
-
- $data = file_get_contents("php://input");
- error_log("EST: simpleenroll - POST data from php://input: " . $data);
- $req = base64_decode($data);
- if ($req == FALSE) {
- error_log("EST: simpleenroll - Invalid base64-encoded PKCS#10 data");
- die("Invalid base64-encoded PKCS#10 data");
- }
- $cadir = "$osu_root/est";
- $reqfile = "$cadir/tmp/cert-req.pkcs10";
- $f = fopen($reqfile, "wb");
- fwrite($f, $req);
- fclose($f);
-
- $req_pem = "$reqfile.pem";
- if (file_exists($req_pem))
- unlink($req_pem);
- exec("openssl req -in $reqfile -inform DER -out $req_pem -outform PEM");
- if (!file_exists($req_pem)) {
- error_log("EST: simpleenroll - Failed to parse certificate request");
- die("Failed to parse certificate request");
- }
-
- /* FIX: validate request and add HS 2.0 extensions to cert */
- $cert_pem = "$cadir/tmp/req-signed.pem";
- if (file_exists($cert_pem))
- unlink($cert_pem);
- exec("openssl x509 -req -in $req_pem -CAkey $cadir/cakey.pem -out $cert_pem -CA $cadir/cacert.pem -CAserial $cadir/serial -days 365 -text");
- if (!file_exists($cert_pem)) {
- error_log("EST: simpleenroll - Failed to sign certificate");
- die("Failed to sign certificate");
- }
-
- $cert = file_get_contents($cert_pem);
- $handle = popen("openssl x509 -in $cert_pem -serial -noout", "r");
- $serial = fread($handle, 200);
- pclose($handle);
- $pattern = "/serial=(?P<snhex>[0-9a-fA-F:]*)/m";
- preg_match($pattern, $serial, $matches);
- if (!isset($matches['snhex']) || strlen($matches['snhex']) < 1) {
- error_log("EST: simpleenroll - Could not get serial number");
- die("Could not get serial number");
- }
- $sn = str_replace(":", "", strtoupper($matches['snhex']));
-
- $user = "cert-$sn";
- error_log("EST: user = $user");
-
- $cert_der = "$cadir/tmp/req-signed.der";
- if (file_exists($cert_der))
- unlink($cert_der);
- exec("openssl x509 -in $cert_pem -inform PEM -out $cert_der -outform DER");
- if (!file_exists($cert_der)) {
- error_log("EST: simpleenroll - Failed to convert certificate");
- die("Failed to convert certificate");
- }
- $der = file_get_contents($cert_der);
- $fingerprint = hash("sha256", $der);
- error_log("EST: sha256(DER cert): $fingerprint");
-
- $pkcs7 = "$cadir/tmp/est-client.pkcs7";
- if (file_exists($pkcs7))
- unlink($pkcs7);
- exec("openssl crl2pkcs7 -nocrl -certfile $cert_pem -out $pkcs7 -outform DER");
- if (!file_exists($pkcs7)) {
- error_log("EST: simpleenroll - Failed to prepare PKCS#7 file");
- die("Failed to prepare PKCS#7 file");
- }
-
- if (!$db->exec("UPDATE sessions SET user='$user', cert='$fingerprint', cert_pem='$cert' WHERE rowid=$rowid")) {
- error_log("EST: simpleenroll - Failed to update session database");
- die("Failed to update session database");
- }
-
- header("Content-Transfer-Encoding: base64");
- header("Content-Type: application/pkcs7-mime");
-
- $data = file_get_contents($pkcs7);
- $resp = wordwrap(base64_encode($data), 72, "\n", true);
- echo $resp . "\n";
- error_log("EST: simpleenroll - PKCS#7 response: " . $resp);
-} else {
- header("HTTP/1.0 404 Not Found");
- error_log("EST: Unexpected method or path");
- die("Unexpected method or path");
-}
-
-?>
diff --git a/hs20/server/www/free-remediation.php b/hs20/server/www/free-remediation.php
deleted file mode 100644
index 5648b30..0000000
--- a/hs20/server/www/free-remediation.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<html>
-<head>
-<title>Hotspot 2.0 - public and free hotspot - remediation</title>
-</head>
-<body>
-
-<h3>Hotspot 2.0 - public and free hotspot</h3>
-
-<p>Terms and conditions have changed. You need to accept the new terms
-to continue using this network.</p>
-
-<p>Terms and conditions..</p>
-
-<?php
-echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Accept</a><br>\n";
-?>
-
-</body>
-</html>
diff --git a/hs20/server/www/free.php b/hs20/server/www/free.php
deleted file mode 100644
index 8195069..0000000
--- a/hs20/server/www/free.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<html>
-<head>
-<title>Hotspot 2.0 - public and free hotspot</title>
-</head>
-<body>
-
-<?php
-
-$id = $_GET["session_id"];
-
-echo "<h3>Hotspot 2.0 - public and free hotspot</h3>\n";
-
-echo "<form action=\"add-free.php\" method=\"POST\">\n";
-echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
-
-?>
-
-<p>Terms and conditions..</p>
-<input type="submit" value="Accept">
-</form>
-
-</body>
-</html>
diff --git a/hs20/server/www/redirect.php b/hs20/server/www/redirect.php
deleted file mode 100644
index 8fc9cd6..0000000
--- a/hs20/server/www/redirect.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (isset($_GET["id"]))
- $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]);
-else
- $id = 0;
-
-$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
-if ($row == false) {
- die("Session not found");
-}
-
-$uri = $row['redirect_uri'];
-
-header("Location: $uri", true, 302);
-
-$user = $row['user'];
-$realm = $row['realm'];
-
-$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
- "VALUES ('$user', '$realm', '$id', " .
- "strftime('%Y-%m-%d %H:%M:%f','now'), " .
- "'redirected after user input')");
-
-?>
diff --git a/hs20/server/www/remediation-pw.php b/hs20/server/www/remediation-pw.php
deleted file mode 100644
index 76fdccb..0000000
--- a/hs20/server/www/remediation-pw.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (isset($_POST["id"]))
- $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]);
-else
- die("Missing session id");
-
-$pw = $_POST["password"];
-if (strlen($id) < 32 || !isset($pw)) {
- die("Invalid POST data");
-}
-
-$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch();
-if ($row == false) {
- die("Session not found");
-}
-$user = $row['user'];
-$realm = $row['realm'];
-
-$uri = $row['redirect_uri'];
-$rowid = $row['rowid'];
-
-if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) {
- die("Failed to update session database");
-}
-
-$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " .
- "VALUES ('$user', '$realm', '$id', " .
- "strftime('%Y-%m-%d %H:%M:%f','now'), " .
- "'completed user input response for subscription remediation')");
-
-header("Location: $uri", true, 302);
-
-?>
diff --git a/hs20/server/www/remediation.php b/hs20/server/www/remediation.php
deleted file mode 100644
index 3628065..0000000
--- a/hs20/server/www/remediation.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<html>
-<head>
-<title>Hotspot 2.0 subscription remediation</title>
-</head>
-<body>
-
-<?php
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (isset($_GET["session_id"]))
- $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]);
-else
- $id = 0;
-echo "SessionID: " . $id . "<br>\n";
-
-$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch();
-if ($row == false) {
- die("Session not found");
-}
-
-$username = $row['user'];
-echo "User: " . $username . "@" . $row['realm'] . "<br>\n";
-
-$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch();
-if ($user == false) {
- die("User not found");
-}
-
-echo "<hr><br>\n";
-
-$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0;
-
-if ($cert) {
- echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
-} else if ($user['machine_managed'] == "1") {
- echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n";
- echo "This will provide a new machine-generated password.<br>\n";
-} else {
- echo "<form action=\"remediation-pw.php\" method=\"POST\">\n";
- echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
- echo "New password: <input type=\"password\" name=\"password\"><br>\n";
- echo "<input type=\"submit\" value=\"Change password\">\n";
- echo "</form>\n";
-}
-
-?>
-
-</body>
-</html>
diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php
deleted file mode 100644
index 80a9d40..0000000
--- a/hs20/server/www/signup.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<html>
-<head>
-<title>Hotspot 2.0 signup</title>
-</head>
-<body>
-
-<?php
-
-$id = $_GET["session_id"];
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch();
-if ($row == false) {
- die("Session not found for id: $id");
-}
-$realm = $row['realm'];
-$test = $row['test'];
-
-if (strlen($test) > 0) {
- echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n";
-}
-
-echo "<h3>Sign up for a subscription - $realm</h3>\n";
-
-echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n";
-
-echo "<h4>Option 1 - shared free access credential</h4>\n";
-
-$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch();
-if ($row && strlen($row['value']) > 0) {
- echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n";
-}
-
-echo "<h4>Option 2 - username/password credential</h4>\n";
-
-echo "<form action=\"add-mo.php\" method=\"POST\">\n";
-echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
-?>
-Select a username and password. Leave password empty to get automatically
-generated and machine managed password.<br>
-Username: <input type="text" name="user"><br>
-Password: <input type="password" name="password"><br>
-<input type="submit" value="Complete subscription registration">
-</form>
-
-<?php
-echo "<h4>Option 3 - client certificate credential</h4>\n";
-
-echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n"
-?>
-
-</body>
-</html>
diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php
deleted file mode 100644
index c56d3d6..0000000
--- a/hs20/server/www/spp.php
+++ /dev/null
@@ -1,168 +0,0 @@
-<?php
-
-require('config.php');
-
-if (!stristr($_SERVER["CONTENT_TYPE"], "application/soap+xml")) {
- error_log("spp.php - Unexpected Content-Type " . $_SERVER["CONTENT_TYPE"]);
- die("Unexpected Content-Type");
-}
-
-if ($_SERVER["REQUEST_METHOD"] != "POST") {
- error_log("spp.php - Unexpected method " . $_SERVER["REQUEST_METHOD"]);
- die("Unexpected method");
-}
-
-if (isset($_GET["realm"])) {
- $realm = $_GET["realm"];
- $realm = PREG_REPLACE("/[^0-9a-zA-Z\.\-]/i", '', $realm);
-} else {
- error_log("spp.php - Realm not specified");
- die("Realm not specified");
-}
-
-if (isset($_GET["test"]))
- $test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]);
-else
- $test = "";
-
-unset($user);
-putenv("HS20CERT");
-
-if (!empty($_SERVER['PHP_AUTH_DIGEST'])) {
- $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1,
- 'uri'=>1, 'response'=>1);
- $data = array();
- $keys = implode('|', array_keys($needed));
- preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@',
- $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
- foreach ($matches as $m) {
- $data[$m[1]] = $m[3] ? $m[3] : $m[4];
- unset($needed[$m[1]]);
- }
- if ($needed) {
- error_log("spp.php - Authentication failed - missing: " . print_r($needed));
- die('Authentication failed');
- }
- $user = $data['username'];
- if (strlen($user) < 1) {
- error_log("spp.php - Authentication failed - empty username");
- die('Authentication failed');
- }
-
-
- $db = new PDO($osu_db);
- if (!$db) {
- error_log("spp.php - Could not access database");
- die("Could not access database");
- }
- $row = $db->query("SELECT password FROM users " .
- "WHERE identity='$user' AND realm='$realm'")->fetch();
- if (!$row) {
- $row = $db->query("SELECT osu_password FROM users " .
- "WHERE osu_user='$user' AND realm='$realm'")->fetch();
- $pw = $row['osu_password'];
- } else
- $pw = $row['password'];
- if (!$row) {
- error_log("spp.php - Authentication failed - user '$user' not found");
- die('Authentication failed');
- }
- if (strlen($pw) < 1) {
- error_log("spp.php - Authentication failed - empty password");
- die('Authentication failed');
- }
-
- $A1 = md5($user . ':' . $realm . ':' . $pw);
- $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
- $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' .
- $data['cnonce'] . ':' . $data['qop'] . ':' . $A2);
- if ($data['response'] != $resp) {
- error_log("Authentication failure - response mismatch");
- die('Authentication failed');
- }
-} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) &&
- $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" &&
- isset($_SERVER["SSL_CLIENT_M_SERIAL"])) {
- $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"];
- putenv("HS20CERT=yes");
-} else if (isset($_GET["hotspot2dot0-mobile-identifier-hash"])) {
- $id_hash = $_GET["hotspot2dot0-mobile-identifier-hash"];
- $id_hash = PREG_REPLACE("/[^0-9a-h]/i", '', $id_hash);
-
- $db = new PDO($osu_db);
- if (!$db) {
- error_log("spp.php - Could not access database");
- die("Could not access database");
- }
-
- $row = $db->query("SELECT * FROM sim_provisioning " .
- "WHERE mobile_identifier_hash='$id_hash'")->fetch();
- if (!$row) {
- error_log("spp.php - SIM provisioning failed - mobile_identifier_hash not found");
- die('SIM provisioning failed - mobile_identifier_hash not found');
- }
-
- $imsi = $row['imsi'];
- $mac_addr = $row['mac_addr'];
- $eap_method = $row['eap_method'];
-
- $row = $db->query("SELECT COUNT(*) FROM osu_config " .
- "WHERE realm='$realm'")->fetch();
- if (!$row || intval($row[0]) < 1) {
- error_log("spp.php - SIM provisioning failed - realm $realm not found");
- die('SIM provisioning failed');
- }
-
- error_log("spp.php - SIM provisioning for IMSI $imsi");
- putenv("HS20SIMPROV=yes");
- putenv("HS20IMSI=$imsi");
- putenv("HS20MACADDR=$mac_addr");
- putenv("HS20EAPMETHOD=$eap_method");
- putenv("HS20IDHASH=$id_hash");
-} else if (!isset($_SERVER["PATH_INFO"]) ||
- $_SERVER["PATH_INFO"] != "/signup") {
- header('HTTP/1.1 401 Unauthorized');
- header('WWW-Authenticate: Digest realm="'.$realm.
- '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
- error_log("spp.php - Authentication required (not signup)");
- die('Authentication required (not signup)');
-}
-
-
-if (isset($user) && strlen($user) > 0)
- putenv("HS20USER=$user");
-else
- putenv("HS20USER");
-
-putenv("HS20REALM=$realm");
-$postdata = file_get_contents("php://input");
-putenv("HS20POST=$postdata");
-$addr = $_SERVER["REMOTE_ADDR"];
-putenv("HS20ADDR=$addr");
-putenv("HS20TEST=$test");
-
-$last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret);
-
-if ($ret == 2) {
- if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
- header('HTTP/1.1 401 Unauthorized');
- header('WWW-Authenticate: Digest realm="'.$realm.
- '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
- error_log("spp.php - Authentication required (ret 2)");
- die('Authentication required');
- } else {
- error_log("spp.php - Unexpected authentication error");
- die("Unexpected authentication error");
- }
-}
-if ($ret != 0) {
- error_log("spp.php - Failed to process SPP request");
- die("Failed to process SPP request");
-}
-//error_log("spp.php: Response: " . implode($output));
-
-header("Content-Type: application/soap+xml");
-
-echo implode($output);
-
-?>
diff --git a/hs20/server/www/terms.php b/hs20/server/www/terms.php
deleted file mode 100644
index acba23e..0000000
--- a/hs20/server/www/terms.php
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-
-require('config.php');
-
-function print_header()
-{
- echo "<html>\n";
- echo "<head><title>HS 2.0 Terms and Conditions</title></head>\n";
- echo "<body>\n";
-}
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (!isset($_GET["addr"])) {
- die("Missing addr parameter");
-}
-$addr = $_GET["addr"];
-
-$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes";
-
-$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?");
-$res->execute(array($addr));
-$row = $res->fetch();
-if (!$row) {
- die("No pending session for the specified MAC address");
-}
-$identity = $row[0];
-
-if (!$accept) {
- print_header();
-
- echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n";
- readfile($t_c_file);
-} else {
- $res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?");
- if (!$res->execute(array($t_c_timestamp, $identity))) {
- die("Failed to update user account.");
- }
-
- $res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?");
- $res->execute(array($addr));
-
- $fp = fsockopen($hostapd_ctrl);
- if (!$fp) {
- die("Could not connect to hostapd(AS)");
- }
-
- fwrite($fp, "DAC_REQUEST coa $addr t_c_clear");
- fclose($fp);
-
- $waiting = true;
- $ack = false;
- for ($i = 1; $i <= 10; $i++) {
- $res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?");
- $res->execute(array($addr));
- $row = $res->fetch();
- if (!$row) {
- die("No current session for the specified MAC address");
- }
- if (strlen($row[0]) > 0)
- $waiting = $row[0] == 1;
- if (strlen($row[1]) > 0)
- $ack = $row[1] == 1;
- $res->closeCursor();
- if (!$waiting)
- break;
- sleep(1);
- }
- if ($ack) {
- header('X-WFA-Hotspot20-Filtering: removed');
- print_header();
- echo "<p>Terms and conditions were accepted.</p>\n";
-
- echo "<P>Filtering disabled.</P>\n";
- } else {
- print_header();
- echo "<P>Failed to disable filtering.</P>\n";
- }
-}
-
-?>
-
-</body>
-</html>
diff --git a/hs20/server/www/users.php b/hs20/server/www/users.php
deleted file mode 100644
index 2bd5552..0000000
--- a/hs20/server/www/users.php
+++ /dev/null
@@ -1,377 +0,0 @@
-<?php
-
-require('config.php');
-
-$db = new PDO($osu_db);
-if (!$db) {
- die($sqliteerror);
-}
-
-if (isset($_GET["id"])) {
- $id = $_GET["id"];
- if (!is_numeric($id))
- $id = 0;
-} else
- $id = 0;
-if (isset($_GET["cmd"]))
- $cmd = $_GET["cmd"];
-else
- $cmd = '';
-
-if ($cmd == 'eventlog' && $id > 0) {
- $row = $db->query("SELECT dump FROM eventlog WHERE rowid=$id")->fetch();
- $dump = $row['dump'];
- if ($dump[0] == '<') {
- header("Content-type: text/xml");
- echo "<?xml version=\"1.0\"?>\n";
- echo $dump;
- } else {
- header("Content-type: text/plain");
- echo $dump;
- }
- exit;
-}
-
-if ($cmd == 'mo' && $id > 0) {
- $mo = $_GET["mo"];
- if (!isset($mo))
- exit;
- if ($mo != "devinfo" && $mo != "devdetail" && $mo != "pps")
- exit;
- $row = $db->query("SELECT $mo FROM users WHERE rowid=$id")->fetch();
- header("Content-type: text/xml");
- echo "<?xml version=\"1.0\"?>\n";
- echo $row[$mo];
- exit;
-}
-
-if ($cmd == 'cert' && $id > 0) {
- $row = $db->query("SELECT cert_pem FROM users WHERE rowid=$id")->fetch();
- header("Content-type: text/plain");
- echo $row['cert_pem'];
- exit;
-}
-
-?>
-
-<html>
-<head><title>HS 2.0 users</title></head>
-<body>
-
-<?php
-
-if ($cmd == 'subrem-clear' && $id > 0) {
- $db->exec("UPDATE users SET remediation='' WHERE rowid=$id");
-}
-if ($cmd == 'subrem-add-user' && $id > 0) {
- $db->exec("UPDATE users SET remediation='user' WHERE rowid=$id");
-}
-if ($cmd == 'subrem-add-machine' && $id > 0) {
- $db->exec("UPDATE users SET remediation='machine' WHERE rowid=$id");
-}
-if ($cmd == 'subrem-add-reenroll' && $id > 0) {
- $db->exec("UPDATE users SET remediation='reenroll' WHERE rowid=$id");
-}
-if ($cmd == 'subrem-add-policy' && $id > 0) {
- $db->exec("UPDATE users SET remediation='policy' WHERE rowid=$id");
-}
-if ($cmd == 'subrem-add-free' && $id > 0) {
- $db->exec("UPDATE users SET remediation='free' WHERE rowid=$id");
-}
-if ($cmd == 'fetch-pps-on' && $id > 0) {
- $db->exec("UPDATE users SET fetch_pps=1 WHERE rowid=$id");
-}
-if ($cmd == 'fetch-pps-off' && $id > 0) {
- $db->exec("UPDATE users SET fetch_pps=0 WHERE rowid=$id");
-}
-if ($cmd == 'reset-pw' && $id > 0) {
- $db->exec("UPDATE users SET password='ChangeMe' WHERE rowid=$id");
-}
-if ($cmd == "policy" && $id > 0 && isset($_GET["policy"])) {
- $policy = $_GET["policy"];
- if ($policy == "no-policy" ||
- is_readable("$osu_root/spp/policy/$policy.xml")) {
- $db->exec("UPDATE users SET policy='$policy' WHERE rowid=$id");
- }
-}
-if ($cmd == "account-type" && $id > 0 && isset($_GET["type"])) {
- $type = $_GET["type"];
- if ($type == "shared")
- $db->exec("UPDATE users SET shared=1 WHERE rowid=$id");
- if ($type == "default")
- $db->exec("UPDATE users SET shared=0 WHERE rowid=$id");
-}
-
-if ($cmd == "set-osu-cred" && $id > 0) {
- $osu_user = $_POST["osu_user"];
- $osu_password = $_POST["osu_password"];
- if (strlen($osu_user) == 0)
- $osu_password = "";
- $db->exec("UPDATE users SET osu_user='$osu_user', osu_password='$osu_password' WHERE rowid=$id");
-}
-
-if ($cmd == 'clear-t-c' && $id > 0) {
- $db->exec("UPDATE users SET t_c_timestamp=NULL WHERE rowid=$id");
-}
-
-$dump = 0;
-
-if ($id > 0) {
-
-if (isset($_GET["dump"])) {
- $dump = $_GET["dump"];
- if (!is_numeric($dump))
- $dump = 0;
-} else
- $dump = 0;
-
-echo "[<a href=\"users.php\">All users</a>] ";
-if ($dump == 0)
- echo "[<a href=\"users.php?id=$id&dump=1\">Include debug dump</a>] ";
-else
- echo "[<a href=\"users.php?id=$id\">Without debug dump</a>] ";
-echo "<br>\n";
-
-$row = $db->query("SELECT rowid,* FROM users WHERE rowid=$id")->fetch();
-
-echo "<H3>" . $row['identity'] . "@" . $row['realm'] . "</H3>\n";
-
-echo "MO: ";
-if (strlen($row['devinfo']) > 0) {
- echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devinfo\">DevInfo</a>]\n";
-}
-if (strlen($row['devdetail']) > 0) {
- echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devdetail\">DevDetail</a>]\n";
-}
-if (strlen($row['pps']) > 0) {
- echo "[<a href=\"users.php?cmd=mo&id=$id&mo=pps\">PPS</a>]\n";
-}
-if (strlen($row['cert_pem']) > 0) {
- echo "[<a href=\"users.php?cmd=cert&id=$id\">Certificate</a>]\n";
-}
-echo "<BR>\n";
-
-echo "Fetch PPS MO: ";
-if ($row['fetch_pps'] == "1") {
- echo "On next connection " .
- "[<a href=\"users.php?cmd=fetch-pps-off&id=$id\">" .
- "do not fetch</a>]<br>\n";
-} else {
- echo "Do not fetch " .
- "[<a href=\"users.php?cmd=fetch-pps-on&id=$id\">" .
- "request fetch</a>]<br>\n";
-}
-
-$cert = $row['cert'];
-if (strlen($cert) > 0) {
- echo "Certificate fingerprint: $cert<br>\n";
-}
-
-echo "Remediation: ";
-$rem = $row['remediation'];
-if ($rem == "") {
- echo "Not required";
- echo " [<a href=\"users.php?cmd=subrem-add-user&id=" .
- $row['rowid'] . "\">add:user</a>]";
- echo " [<a href=\"users.php?cmd=subrem-add-machine&id=" .
- $row['rowid'] . "\">add:machine</a>]";
- if ($row['methods'] == 'TLS') {
- echo " [<a href=\"users.php?cmd=subrem-add-reenroll&id=" .
- $row['rowid'] . "\">add:reenroll</a>]";
- }
- echo " [<a href=\"users.php?cmd=subrem-add-policy&id=" .
- $row['rowid'] . "\">add:policy</a>]";
- echo " [<a href=\"users.php?cmd=subrem-add-free&id=" .
- $row['rowid'] . "\">add:free</a>]";
-} else if ($rem == "user") {
- echo "User [<a href=\"users.php?cmd=subrem-clear&id=" .
- $row['rowid'] . "\">clear</a>]";
-} else if ($rem == "policy") {
- echo "Policy [<a href=\"users.php?cmd=subrem-clear&id=" .
- $row['rowid'] . "\">clear</a>]";
-} else if ($rem == "free") {
- echo "Free [<a href=\"users.php?cmd=subrem-clear&id=" .
- $row['rowid'] . "\">clear</a>]";
-} else if ($rem == "reenroll") {
- echo "Reenroll [<a href=\"users.php?cmd=subrem-clear&id=" .
- $row['rowid'] . "\">clear</a>]";
-} else {
- echo "Machine [<a href=\"users.php?cmd=subrem-clear&id=" .
- $row['rowid'] . "\">clear</a>]";
-}
-echo "<br>\n";
-
-if (strncmp($row['identity'], "cert-", 5) != 0)
- echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n";
-
-echo "<form>Policy: <select name=\"policy\" " .
- "onChange=\"window.location='users.php?cmd=policy&id=" .
- $row['rowid'] . "&policy=' + this.value;\">\n";
-echo "<option value=\"" . $row['policy'] . "\" selected>" . $row['policy'] .
- "</option>\n";
-$files = scandir("$osu_root/spp/policy");
-foreach ($files as $file) {
- if (!preg_match("/.xml$/", $file))
- continue;
- if ($file == $row['policy'] . ".xml")
- continue;
- $p = substr($file, 0, -4);
- echo "<option value=\"$p\">$p</option>\n";
-}
-echo "<option value=\"no-policy\">no policy</option>\n";
-echo "</select></form>\n";
-
-echo "<form>Account type: <select name=\"type\" " .
- "onChange=\"window.location='users.php?cmd=account-type&id=" .
- $row['rowid'] . "&type=' + this.value;\">\n";
-if ($row['shared'] > 0) {
- $default_sel = "";
- $shared_sel = " selected";
-} else {
- $default_sel = " selected";
- $shared_sel = "";
-}
-echo "<option value=\"default\"$default_sel>default</option>\n";
-echo "<option value=\"shared\"$shared_sel>shared</option>\n";
-echo "</select></form>\n";
-
-echo "Phase 2 method(s): " . $row['methods'] . "<br>\n";
-
-echo "<br>\n";
-echo "<a href=\"users.php?cmd=reset-pw&id=" .
- $row['rowid'] . "\">Reset AAA password</a><br>\n";
-
-echo "<br>\n";
-echo "<form action=\"users.php?cmd=set-osu-cred&id=" . $row['rowid'] .
- "\" method=\"POST\">\n";
-echo "OSU credentials (if username empty, AAA credentials are used):<br>\n";
-echo "username: <input type=\"text\" name=\"osu_user\" value=\"" .
- $row['osu_user'] . "\">\n";
-echo "password: <input type=\"password\" name=\"osu_password\">\n";
-echo "<input type=\"submit\" value=\"Set OSU credentials\">\n";
-echo "</form>\n";
-
-if (strlen($row['t_c_timestamp']) > 0) {
- echo "<br>\n";
- echo "<a href=\"users.php?cmd=clear-t-c&id=" .
- $row['rowid'] .
- "\">Clear Terms and Conditions acceptance</a><br>\n";
-}
-
-echo "<hr>\n";
-
-$user = $row['identity'];
-$osu_user = $row['osu_user'];
-$realm = $row['realm'];
-}
-
-if ($id > 0 || ($id == 0 && $cmd == 'eventlog')) {
-
- if ($id == 0) {
- echo "[<a href=\"users.php\">All users</a>] ";
- echo "<br>\n";
- }
-
-echo "<table border=1>\n";
-echo "<tr>";
-if ($id == 0) {
- echo "<th>user<th>realm";
-}
-echo "<th>time<th>address<th>sessionID<th>notes";
-if ($dump > 0)
- echo "<th>dump";
-echo "\n";
-if (isset($_GET["limit"])) {
- $limit = $_GET["limit"];
- if (!is_numeric($limit))
- $limit = 20;
-} else
- $limit = 20;
-if ($id == 0)
- $res = $db->query("SELECT rowid,* FROM eventlog ORDER BY timestamp DESC LIMIT $limit");
-else if (strlen($osu_user) > 0)
- $res = $db->query("SELECT rowid,* FROM eventlog WHERE (user='$user' OR user='$osu_user') AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
-else
- $res = $db->query("SELECT rowid,* FROM eventlog WHERE user='$user' AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit");
-foreach ($res as $row) {
- echo "<tr>";
- if ($id == 0) {
- echo "<td>" . $row['user'] . "\n";
- echo "<td>" . $row['realm'] . "\n";
- }
- echo "<td>" . $row['timestamp'] . "\n";
- echo "<td>" . $row['addr'] . "\n";
- echo "<td>" . $row['sessionid'] . "\n";
- echo "<td>" . $row['notes'] . "\n";
- $d = $row['dump'];
- if (strlen($d) > 0) {
- echo "[<a href=\"users.php?cmd=eventlog&id=" . $row['rowid'] .
- "\">";
- if ($d[0] == '<')
- echo "XML";
- else
- echo "txt";
- echo "</a>]\n";
- if ($dump > 0)
- echo "<td>" . htmlspecialchars($d) . "\n";
- }
-}
-echo "</table>\n";
-
-}
-
-
-if ($id == 0 && $cmd != 'eventlog') {
-
-echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] ";
-echo "<br>\n";
-
-echo "<table border=1 cellspacing=0 cellpadding=0>\n";
-echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n";
-
-$res = $db->query('SELECT rowid,* FROM users WHERE (phase2=1 OR methods=\'TLS\') ORDER BY identity');
-foreach ($res as $row) {
- echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " .
- $row['identity'] . " </a>";
- echo "<td>" . $row['realm'];
- $rem = $row['remediation'];
- echo "<td>";
- if ($rem == "") {
- echo "-";
- } else if ($rem == "user") {
- echo "User";
- } else if ($rem == "policy") {
- echo "Policy";
- } else if ($rem == "free") {
- echo "Free";
- } else if ($rem == "reenroll") {
- echo "Reenroll";
- } else {
- echo "Machine";
- }
- echo "<td>" . $row['policy'];
- if ($row['shared'] > 0)
- echo "<td>shared";
- else
- echo "<td>default";
- echo "<td><small>" . $row['methods'] . "</small>";
- echo "<td>";
- $xml = xml_parser_create();
- xml_parse_into_struct($xml, $row['devinfo'], $devinfo);
- foreach($devinfo as $k) {
- if ($k['tag'] == 'DEVID') {
- echo "<small>" . $k['value'] . "</small>";
- break;
- }
- }
- echo "<td><small>" . $row['mac_addr'] . "</small>";
- echo "<td><small>" . $row['t_c_timestamp'] . "</small>";
- echo "\n";
-}
-echo "</table>\n";
-
-}
-
-?>
-
-</html>
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)
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 1b5ea81..205d8b7 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -181,7 +181,7 @@
LDFLAGS += -rdynamic
L_CFLAGS += -funwind-tables
ifdef CONFIG_WPA_TRACE_BFD
-L_CFLAGS += -DWPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD -fno-inline -fno-optimize-sibling-calls
LIBS += -lbfd
LIBS_p += -lbfd
LIBS_c += -lbfd
@@ -820,8 +820,10 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_ECC=y
NEED_DRAGONFLY=y
+ifndef CONFIG_FIPS
MS_FUNCS=y
endif
+endif
ifdef CONFIG_EAP_EKE
# EAP-EKE
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 49c1793..7718f94 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -151,7 +151,7 @@
LDFLAGS += -rdynamic
CFLAGS += -funwind-tables
ifdef CONFIG_WPA_TRACE_BFD
-CFLAGS += -DPACKAGE="wpa_supplicant" -DWPA_TRACE_BFD
+CFLAGS += -DPACKAGE="wpa_supplicant" -DWPA_TRACE_BFD -fno-inline -fno-optimize-sibling-calls
LIBS += -lbfd -ldl -liberty -lz
LIBS_p += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz
@@ -832,8 +832,10 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_ECC=y
NEED_DRAGONFLY=y
+ifndef CONFIG_FIPS
MS_FUNCS=y
endif
+endif
ifdef CONFIG_EAP_EKE
# EAP-EKE
@@ -1194,6 +1196,7 @@
endif
ifeq ($(CONFIG_TLS), wolfssl)
+CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
ifdef TLS_FUNCS
CFLAGS += -DWOLFSSL_DER_LOAD
OBJS += ../src/crypto/tls_wolfssl.o
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 7d30e23..f5488f2 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -618,28 +618,6 @@
<3>ANQP fetch completed
-Hotspot 2.0 Rel 2 online signup and OSEN
-----------------------------------------
-
-Following parameters can be used to create a network profile for
-link-layer protected Hotspot 2.0 online signup connection with
-OSEN. Note that ssid and identify (NAI) values need to be set based on
-the information for the selected provider in the OSU Providers list
-ANQP-element.
-
-network={
- ssid="HS 2.0 OSU"
- proto=OSEN
- key_mgmt=OSEN
- pairwise=CCMP
- group=GTK_NOT_USED
- eap=WFA-UNAUTH-TLS
- identity="anonymous@example.com"
- ca_cert="osu-ca.pem"
- ocsp=2
-}
-
-
Hotspot 2.0 connection with external network selection
------------------------------------------------------
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.cpp b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
index 24e5a56..c306e53 100644
--- a/wpa_supplicant/aidl/vendor/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
@@ -708,8 +708,6 @@
return KeyMgmtMask::WAPI_PSK;
case WPA_KEY_MGMT_WAPI_CERT:
return KeyMgmtMask::WAPI_CERT;
- case WPA_KEY_MGMT_OSEN:
- return KeyMgmtMask::OSEN;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
return KeyMgmtMask::SUITE_B_192;
@@ -945,8 +943,7 @@
misc_utils::convertWpaBufToVector(
anqp->hs20_connection_capability);
aidl_hs20_anqp_data.osuProvidersList =
- misc_utils::convertWpaBufToVector(
- anqp->hs20_osu_providers_list);
+ misc_utils::convertWpaBufToVector(NULL);
#else
aidl_hs20_anqp_data.operatorFriendlyName =
misc_utils::convertWpaBufToVector(NULL);
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.h b/wpa_supplicant/aidl/vendor/aidl_manager.h
index 667422f..73f77fa 100644
--- a/wpa_supplicant/aidl/vendor/aidl_manager.h
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.h
@@ -352,10 +352,6 @@
WPA_KEY_MGMT_FT_PSK,
"KeyMgmt value mismatch");
static_assert(
- static_cast<uint32_t>(KeyMgmtMask::OSEN) ==
- WPA_KEY_MGMT_OSEN,
- "KeyMgmt value mismatch");
-static_assert(
static_cast<uint32_t>(KeyMgmtMask::SAE) ==
WPA_KEY_MGMT_SAE,
"KeyMgmt value mismatch");
@@ -392,10 +388,6 @@
WPA_PROTO_RSN,
"Proto value mismatch");
static_assert(
- static_cast<uint32_t>(ProtoMask::OSEN) ==
- WPA_PROTO_OSEN,
- "Proto value mismatch");
-static_assert(
static_cast<uint32_t>(ProtoMask::WAPI) ==
WPA_PROTO_WAPI,
"Proto value mismatch");
@@ -512,11 +504,6 @@
Hs20AnqpSubtypes::CONNECTION_CAPABILITY) ==
HS20_STYPE_CONNECTION_CAPABILITY,
"HS Subtype value mismatch");
-static_assert(
- static_cast<uint32_t>(
- Hs20AnqpSubtypes::OSU_PROVIDERS_LIST) ==
- HS20_STYPE_OSU_PROVIDERS_LIST,
- "HS Subtype value mismatch");
static_assert(
static_cast<uint16_t>(
diff --git a/wpa_supplicant/aidl/vendor/p2p_iface.cpp b/wpa_supplicant/aidl/vendor/p2p_iface.cpp
index 16c5536..695cc0b 100644
--- a/wpa_supplicant/aidl/vendor/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/p2p_iface.cpp
@@ -1260,7 +1260,7 @@
}
// TODO Handle pairing bootstrapping method when supplicant implementation is ready
if (wpas_p2p_prov_disc(
- wpa_s, peer_address.data(), config_method_str,
+ wpa_s, peer_address.data(), config_method_str, 0,
WPAS_P2P_PD_FOR_GO_NEG, nullptr)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
diff --git a/wpa_supplicant/aidl/vendor/sta_iface.cpp b/wpa_supplicant/aidl/vendor/sta_iface.cpp
index f6868d0..3fe0030 100644
--- a/wpa_supplicant/aidl/vendor/sta_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/sta_iface.cpp
@@ -1345,22 +1345,7 @@
ndk::ScopedAStatus StaIface::initiateHs20IconQueryInternal(
const std::vector<uint8_t> &mac_address, const std::string &file_name)
{
-#ifdef CONFIG_HS20
- struct wpa_supplicant *wpa_s = retrieveIfacePtr();
- if (mac_address.size() != ETH_ALEN) {
- return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
- }
- wpa_s->fetch_osu_icon_in_progress = 0;
- if (hs20_anqp_send_req(
- wpa_s, mac_address.data(), BIT(HS20_STYPE_ICON_REQUEST),
- reinterpret_cast<const uint8_t *>(file_name.c_str()),
- file_name.size(), true)) {
- return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
- }
- return ndk::ScopedAStatus::ok();
-#else
return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
-#endif /* CONFIG_HS20 */
}
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus>
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 10ebab0..0afac49 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -91,9 +91,6 @@
ANQP_DUP(hs20_wan_metrics);
ANQP_DUP(hs20_connection_capability);
ANQP_DUP(hs20_operating_class);
- ANQP_DUP(hs20_osu_providers_list);
- ANQP_DUP(hs20_operator_icon_metadata);
- ANQP_DUP(hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
#undef ANQP_DUP
@@ -176,9 +173,6 @@
wpabuf_free(anqp->hs20_wan_metrics);
wpabuf_free(anqp->hs20_connection_capability);
wpabuf_free(anqp->hs20_operating_class);
- wpabuf_free(anqp->hs20_osu_providers_list);
- wpabuf_free(anqp->hs20_operator_icon_metadata);
- wpabuf_free(anqp->hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
os_free(anqp);
@@ -220,6 +214,7 @@
const char *reason)
{
struct wpa_connect_work *cwork;
+ unsigned int j;
if (wpa_s->last_scan_res) {
unsigned int i;
@@ -245,6 +240,45 @@
wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
wpa_bss_anqp_free(bss->anqp);
+
+ if (wpa_s->current_bss == bss) {
+ wpa_printf(MSG_DEBUG,
+ "BSS: Clear current_bss due to bss removal");
+ wpa_s->current_bss = NULL;
+ }
+
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->interworking_gas_bss == bss) {
+ wpa_printf(MSG_DEBUG,
+ "BSS: Clear interworking_gas_bss due to bss removal");
+ wpa_s->interworking_gas_bss = NULL;
+ }
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WNM
+ if (wpa_s->wnm_target_bss == bss) {
+ wpa_printf(MSG_DEBUG,
+ "BSS: Clear wnm_target_bss due to bss removal");
+ wpa_s->wnm_target_bss = NULL;
+ }
+#endif /* CONFIG_WNM */
+
+ if (wpa_s->ml_connect_probe_bss == bss) {
+ wpa_printf(MSG_DEBUG,
+ "BSS: Clear ml_connect_probe_bss due to bss removal");
+ wpa_s->ml_connect_probe_bss = NULL;
+ }
+
+ for (j = 0; j < MAX_NUM_MLD_LINKS; j++) {
+ if (wpa_s->links[j].bss == bss) {
+ wpa_printf(MSG_DEBUG,
+ "BSS: Clear links[%d].bss due to bss removal",
+ j);
+ wpa_s->valid_links &= ~BIT(j);
+ wpa_s->links[j].bss = NULL;
+ }
+ }
+
os_free(bss);
}
@@ -423,6 +457,28 @@
}
+#ifdef CONFIG_OWE
+static int wpa_bss_owe_trans_known(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss,
+ const u8 *entry_ssid, size_t entry_ssid_len)
+{
+ const u8 *owe, *owe_bssid, *owe_ssid;
+ size_t owe_ssid_len;
+
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (!owe)
+ return 0;
+
+ if (wpas_get_owe_trans_network(owe, &owe_bssid, &owe_ssid,
+ &owe_ssid_len))
+ return 0;
+
+ return entry_ssid_len == owe_ssid_len &&
+ os_memcmp(owe_ssid, entry_ssid, owe_ssid_len) == 0;
+}
+#endif /* CONFIG_OWE */
+
+
static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_ssid *ssid;
@@ -436,6 +492,11 @@
if (ssid->ssid_len == bss->ssid_len &&
os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
return 1;
+#ifdef CONFIG_OWE
+ if (wpa_bss_owe_trans_known(wpa_s, bss, ssid->ssid,
+ ssid->ssid_len))
+ return 1;
+#endif /* CONFIG_OWE */
}
return 0;
@@ -486,6 +547,7 @@
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!wpa_bss_known(wpa_s, bss) &&
+ !wpa_bss_in_use(wpa_s, bss) &&
!wpa_bss_is_wps_candidate(wpa_s, bss)) {
wpa_bss_remove(wpa_s, bss, __func__);
return 0;
@@ -796,9 +858,17 @@
struct wpa_bss *nbss;
struct dl_list *prev = bss->list_id.prev;
struct wpa_connect_work *cwork;
- unsigned int i;
+ unsigned int i, j;
bool update_current_bss = wpa_s->current_bss == bss;
bool update_ml_probe_bss = wpa_s->ml_connect_probe_bss == bss;
+ int update_link_bss = -1;
+
+ for (j = 0; j < MAX_NUM_MLD_LINKS; j++) {
+ if (wpa_s->links[j].bss == bss) {
+ update_link_bss = j;
+ break;
+ }
+ }
cwork = wpa_bss_check_pending_connect(wpa_s, bss);
@@ -820,6 +890,9 @@
if (update_ml_probe_bss)
wpa_s->ml_connect_probe_bss = nbss;
+ if (update_link_bss >= 0)
+ wpa_s->links[update_link_bss].bss = nbss;
+
if (cwork)
wpa_bss_update_pending_connect(cwork, nbss);
@@ -1591,12 +1664,9 @@
pos += sizeof(*ap_info);
for (i = 0; i < count; i++, pos += ap_info->tbtt_info_len) {
- u8 bss_params;
-
if (end - pos < ap_info->tbtt_info_len)
break;
- bss_params = pos[1 + ETH_ALEN + 4];
mld_params = pos + mld_params_offset;
link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK;
@@ -1623,10 +1693,8 @@
if (!neigh_bss) {
*missing |= BIT(link_id);
} else if ((!ssid ||
- (bss_params & (RNR_BSS_PARAM_SAME_SSID |
- RNR_BSS_PARAM_CO_LOCATED)) ||
wpa_scan_res_match(wpa_s, 0, neigh_bss,
- ssid, 1, 0)) &&
+ ssid, 1, 0, true)) &&
!wpa_bssid_ignore_is_listed(
wpa_s, neigh_bss->bssid)) {
struct mld_link *l;
@@ -1865,8 +1933,9 @@
const u8 *pos = wpa_bss_ie_ptr(bss);
size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
const struct ieee80211_eht_ml *ml;
+ const struct eht_ml_reconf_common_info *common_info;
u16 removed_links = 0;
- u8 ml_common_len;
+ u8 expected_ml_common_len;
if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
return 0;
@@ -1881,22 +1950,33 @@
ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
len = wpabuf_len(mlbuf);
- if (len < sizeof(*ml))
+ /* There must be at least one octet for the Common Info Length subfield
+ */
+ if (len < sizeof(*ml) + 1UL)
goto out;
- ml_common_len = 1;
- if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR)
- ml_common_len += ETH_ALEN;
+ expected_ml_common_len = 1;
+ if (le_to_host16(ml->ml_control) &
+ RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR)
+ expected_ml_common_len += ETH_ALEN;
- if (len < sizeof(*ml) + ml_common_len) {
+ common_info = (const struct eht_ml_reconf_common_info *) ml->variable;
+ if (len < sizeof(*ml) + common_info->len) {
wpa_printf(MSG_DEBUG,
"MLD: Unexpected Reconfiguration ML element length: (%zu < %zu)",
- len, sizeof(*ml) + ml_common_len);
+ len, sizeof(*ml) + common_info->len);
goto out;
}
- pos = ml->variable + ml_common_len;
- len -= sizeof(*ml) + ml_common_len;
+ if (common_info->len < expected_ml_common_len) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: Invalid common info len=%u; min expected=%u",
+ common_info->len, expected_ml_common_len);
+ goto out;
+ }
+
+ pos = ml->variable + common_info->len;
+ len -= sizeof(*ml) + common_info->len;
while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) {
size_t sub_elem_len = *(pos + 1);
@@ -1908,7 +1988,8 @@
goto out;
}
- if (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) {
+ if (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE &&
+ sub_elem_len >= 2) {
const struct ieee80211_eht_per_sta_profile *sta_prof =
(const struct ieee80211_eht_per_sta_profile *)
(pos + 2);
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 31688fa..74ef3c8 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -61,9 +61,6 @@
struct wpabuf *hs20_wan_metrics;
struct wpabuf *hs20_connection_capability;
struct wpabuf *hs20_operating_class;
- struct wpabuf *hs20_osu_providers_list;
- struct wpabuf *hs20_operator_icon_metadata;
- struct wpabuf *hs20_osu_providers_nai_list;
#endif /* CONFIG_HS20 */
};
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 9fe83a5..47d9e6d 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -693,8 +693,6 @@
else if (os_strcmp(start, "RSN") == 0 ||
os_strcmp(start, "WPA2") == 0)
val |= WPA_PROTO_RSN;
- else if (os_strcmp(start, "OSEN") == 0)
- val |= WPA_PROTO_OSEN;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
line, start);
@@ -749,14 +747,6 @@
pos += ret;
}
- if (ssid->proto & WPA_PROTO_OSEN) {
- ret = os_snprintf(pos, end - pos, "%sOSEN",
- pos == buf ? "" : " ");
- if (os_snprintf_error(end - pos, ret))
- return buf;
- pos += ret;
- }
-
if (pos == buf) {
os_free(buf);
buf = NULL;
@@ -831,10 +821,6 @@
else if (os_strcmp(start, "FT-SAE-EXT-KEY") == 0)
val |= WPA_KEY_MGMT_FT_SAE_EXT_KEY;
#endif /* CONFIG_SAE */
-#ifdef CONFIG_HS20
- else if (os_strcmp(start, "OSEN") == 0)
- val |= WPA_KEY_MGMT_OSEN;
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_SUITEB
else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
@@ -1071,18 +1057,6 @@
}
#endif /* CONFIG_SAE */
-#ifdef CONFIG_HS20
- if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) {
- ret = os_snprintf(pos, end - pos, "%sOSEN",
- pos == buf ? "" : " ");
- if (os_snprintf_error(end - pos, ret)) {
- end[-1] = '\0';
- return buf;
- }
- pos += ret;
- }
-#endif /* CONFIG_HS20 */
-
#ifdef CONFIG_SUITEB
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
@@ -2138,7 +2112,27 @@
}
+static int wpa_config_parse_p2p2_client_list(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ int *ids = wpa_config_parse_int_array(value);
+
+ if (!ids) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid p2p2_client_list '%s'",
+ line, value);
+ return -1;
+ }
+
+ os_free(ssid->p2p2_client_list);
+ ssid->p2p2_client_list = ids;
+
+ return 0;
+}
+
+
#ifndef NO_CONFIG_WRITE
+
static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
struct wpa_ssid *ssid)
{
@@ -2146,6 +2140,14 @@
ssid->num_p2p_clients,
"p2p_client_list");
}
+
+
+static char * wpa_config_write_p2p2_client_list(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_freqs(data, ssid->p2p2_client_list);
+}
+
#endif /* NO_CONFIG_WRITE */
@@ -2672,7 +2674,9 @@
#ifdef CONFIG_P2P
{ FUNC(go_p2p_dev_addr) },
{ FUNC(p2p_client_list) },
+ { FUNC(p2p2_client_list) },
{ FUNC(psk_list) },
+ { INT(go_dik_id) },
#endif /* CONFIG_P2P */
#ifdef CONFIG_HT_OVERRIDES
{ INT_RANGE(disable_ht, 0, 1) },
@@ -2723,6 +2727,7 @@
{ INT_RANGE(macsec_port, 1, 65534) },
{ INT_RANGE(mka_priority, 0, 255) },
{ INT_RANGE(macsec_csindex, 0, 1) },
+ { INT_RANGE(macsec_icv_indicator, 0, 1) },
{ FUNC_KEY(mka_cak) },
{ FUNC_KEY(mka_ckn) },
#endif /* CONFIG_MACSEC */
@@ -2939,6 +2944,7 @@
os_free(ssid->freq_list);
os_free(ssid->bgscan);
os_free(ssid->p2p_client_list);
+ os_free(ssid->p2p2_client_list);
os_free(ssid->bssid_ignore);
os_free(ssid->bssid_accept);
#ifdef CONFIG_HT_OVERRIDES
@@ -3094,7 +3100,6 @@
os_free(config->sae_groups);
wpabuf_free(config->ap_vendor_elements);
wpabuf_free(config->ap_assocresp_elements);
- os_free(config->osu_dir);
os_free(config->bgscan);
os_free(config->wowlan_triggers);
os_free(config->fst_group_id);
@@ -3160,6 +3165,35 @@
}
+#ifdef CONFIG_P2P
+/**
+ * wpa_config_get_network_with_dik_id - Get configured network based on ID of
+ * device identity block
+ * @config: Configuration data from wpa_config_read()
+ * @dik_id: DIK ID to search for
+ * Returns: Network configuration or %NULL if not found
+ */
+struct wpa_ssid * wpa_config_get_network_with_dik_id(struct wpa_config *config,
+ int dik_id)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = config->ssid; ssid; ssid = ssid->next) {
+ if (ssid->disabled != 2)
+ continue;
+
+ if (ssid->go_dik_id == dik_id)
+ return ssid;
+
+ if (int_array_includes(ssid->p2p2_client_list, dik_id))
+ return ssid;
+ }
+
+ return NULL;
+}
+#endif /* CONFIG_P2P */
+
+
/**
* wpa_config_add_network - Add a new network with empty configuration
* @config: Configuration data from wpa_config_read()
@@ -4841,6 +4875,46 @@
}
+static int wpa_global_config_parse_bool(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *pos)
+{
+ int val;
+ bool *dst;
+ char *end;
+ bool same;
+
+ dst = (bool *) (((u8 *) config) + (long) data->param1);
+ val = strtol(pos, &end, 0);
+ if (*end) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+ line, pos);
+ return -1;
+ }
+
+ if (val < 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: too small %s (value=%d min_value=0)",
+ line, data->name, val);
+ return -1;
+ }
+
+ if (val > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: too large %s (value=%d max_value=1)",
+ line, data->name, val);
+ return -1;
+ }
+
+ same = *dst == val;
+ *dst = val;
+
+ wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
+
+ return same;
+}
+
+
static int wpa_global_config_parse_str(const struct global_parse_data *data,
struct wpa_config *config, int line,
const char *pos)
@@ -5331,6 +5405,18 @@
}
+static int wpa_config_get_bool(const char *name, struct wpa_config *config,
+ long offset, char *buf, size_t buflen,
+ int pretty_print)
+{
+ bool *val = (bool*) (((u8 *) config) + (long) offset);
+
+ if (pretty_print)
+ return os_snprintf(buf, buflen, "%s=%d\n", name, *val);
+ return os_snprintf(buf, buflen, "%d", *val);
+}
+
+
static int wpa_config_get_str(const char *name, struct wpa_config *config,
long offset, char *buf, size_t buflen,
int pretty_print)
@@ -5406,6 +5492,8 @@
#define INT(f) _INT(f), NULL, NULL
#define INT_RANGE(f, min, max) #f, wpa_global_config_parse_int_range, \
wpa_config_get_int, OFFSET(f), (void *) min, (void *) max
+#define BOOL(f) #f, wpa_global_config_parse_bool, wpa_config_get_bool, \
+ OFFSET(f), NULL, NULL
#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f)
#define STR(f) _STR(f), NULL, NULL
#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
@@ -5510,13 +5598,13 @@
{ INT(p2p_interface_random_mac_addr), 0 },
{ INT(p2p_6ghz_disable), 0 },
{ INT(p2p_dfs_chan_enable), 0 },
- { INT_RANGE(p2p_pairing_setup, 0, 1), 0 },
- { INT_RANGE(p2p_pairing_cache, 0, 1), 0 },
+ { BOOL(p2p_pairing_setup), 0 },
+ { BOOL(p2p_pairing_cache), 0 },
{ INT(p2p_bootstrap_methods), 0 },
{ INT(p2p_pasn_type), 0 },
{ INT(p2p_comeback_after), 0 },
- { INT_RANGE(p2p_twt_power_mgmt, 0, 1), 0 },
- { INT_RANGE(p2p_chan_switch_req_enable, 0, 1), 0 },
+ { BOOL(p2p_twt_power_mgmt), 0 },
+ { BOOL(p2p_chan_switch_req_enable), 0 },
{ INT(p2p_reg_info), 0 },
{ INT(dik_cipher), 0},
{ BIN(dik), 0 },
@@ -5569,7 +5657,6 @@
{ INT(sched_scan_interval), 0 },
{ INT(sched_scan_start_delay), 0 },
{ INT(tdls_external_control), 0},
- { STR(osu_dir), 0 },
{ STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS },
{ INT(p2p_search_delay), 0},
{ INT_RANGE(mac_addr, 0, 2), 0 },
@@ -5598,7 +5685,7 @@
{ INT(gas_address3), 0 },
{ INT_RANGE(ftm_responder, 0, 1), 0 },
{ INT_RANGE(ftm_initiator, 0, 1), 0 },
- { INT_RANGE(twt_requester, 0, 1), 0 },
+ { BOOL(twt_requester), 0 },
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
#ifdef CONFIG_DPP
@@ -5628,7 +5715,7 @@
{ INT_RANGE(mld_connect_band_pref, 0, MLD_CONNECT_BAND_PREF_MAX), 0 },
{ FUNC(mld_connect_bssid_pref), 0 },
#endif /* CONFIG_TESTING_OPTIONS */
- { INT_RANGE(ft_prepend_pmkid, 0, 1), CFG_CHANGED_FT_PREPEND_PMKID },
+ { BOOL(ft_prepend_pmkid), CFG_CHANGED_FT_PREPEND_PMKID },
{ INT_RANGE(wfa_gen_capa, 0, 2), 0},
{ BIN(wfa_gen_capa_supp), 0 },
{ BIN(wfa_gen_capa_cert), 0 },
@@ -5638,9 +5725,11 @@
};
#undef FUNC
+#undef FUNC_NO_VAR
#undef _INT
#undef INT
#undef INT_RANGE
+#undef BOOL
#undef _STR
#undef STR
#undef STR_RANGE
@@ -5873,7 +5962,7 @@
int id;
struct wpa_dev_ik *identity, *last = NULL;
- id = -1;
+ id = 0;
identity = config->identity;
while (identity) {
if (identity->id > id)
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 0643114..c8859ea 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1450,15 +1450,6 @@
u8 ip_addr_end[4];
/**
- * osu_dir - OSU provider information directory
- *
- * If set, allow FETCH_OSU control interface command to be used to fetch
- * OSU provider information into all APs and store the results in this
- * directory.
- */
- char *osu_dir;
-
- /**
* wowlan_triggers - Wake-on-WLAN triggers
*
* If set, these wowlan triggers will be configured.
@@ -1950,6 +1941,8 @@
void (*func)(void *, struct wpa_ssid *),
void *arg);
struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
+struct wpa_ssid * wpa_config_get_network_with_dik_id(struct wpa_config *config,
+ int dik_id);
struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
int wpa_config_remove_network(struct wpa_config *config, int id);
void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 4029d49..331726c 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -367,7 +367,7 @@
struct wpa_config *config;
static int id = 0;
static int cred_id = 0;
- static int identity_id = 0;
+ static int identity_id = 1;
if (name == NULL)
return NULL;
@@ -698,6 +698,17 @@
}
+static void write_p2p2_client_list(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "p2p2_client_list");
+
+ if (!value)
+ return;
+ fprintf(f, "\tp2p2_client_list=%s\n", value);
+ os_free(value);
+}
+
+
static void write_psk_list(FILE *f, struct wpa_ssid *ssid)
{
struct psk_list_entry *psk;
@@ -856,7 +867,7 @@
#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(no_auto_peer);
- INT(mesh_fwding);
+ INT_DEF(mesh_fwding, DEFAULT_MESH_FWDING);
INT(frequency);
INT(enable_edmg);
INT(edmg_channel);
@@ -883,7 +894,9 @@
#ifdef CONFIG_P2P
write_go_p2p_dev_addr(f, ssid);
write_p2p_client_list(f, ssid);
+ write_p2p2_client_list(f, ssid);
write_psk_list(f, ssid);
+ INT(go_dik_id);
#endif /* CONFIG_P2P */
INT(ap_max_inactivity);
INT(dtim_period);
@@ -899,6 +912,7 @@
INT(macsec_port);
INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
INT(macsec_csindex);
+ INT(macsec_icv_indicator);
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
INT(update_identifier);
@@ -1673,9 +1687,6 @@
if (config->twt_requester)
fprintf(f, "twt_requester=%d\n", config->twt_requester);
- if (config->osu_dir)
- fprintf(f, "osu_dir=%s\n", config->osu_dir);
-
if (config->fst_group_id)
fprintf(f, "fst_group_id=%s\n", config->fst_group_id);
if (config->fst_priority)
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 92ee234..7d275cd 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -695,6 +695,15 @@
*/
size_t num_p2p_clients;
+ /**
+ * p2p2_client_list - Array of P2P2 Clients in a persistent group (GO)
+ *
+ * This is an int_array of P2P2 Clients (ID of device Identity block)
+ * that have joined the persistent group. This is maintained on the GO
+ *for persistent group entries (disabled == 2).
+ */
+ int *p2p2_client_list;
+
#ifndef P2P_MAX_STORED_CLIENTS
#define P2P_MAX_STORED_CLIENTS 100
#endif /* P2P_MAX_STORED_CLIENTS */
@@ -982,6 +991,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
@@ -1312,6 +1329,12 @@
* p2p_mode - P2P R1 only, P2P R2 only, or PCC mode
*/
enum wpa_p2p_mode p2p_mode;
+
+ /**
+ * go_dik_id - ID of Device Identity block of group owner
+ */
+ int go_dik_id;
+
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 43d1a66..94fcec5 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -3014,14 +3014,6 @@
}
#endif /* CONFIG_DPP */
- if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
- ret = os_snprintf(pos, end - pos, "%sOSEN",
- pos == start ? "" : "+");
- if (os_snprintf_error(end - pos, ret))
- return pos;
- pos += ret;
- }
-
#ifdef CONFIG_SHA384
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA384",
@@ -3099,7 +3091,7 @@
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *osen_ie, *p2p, *mesh, *owe, *rsnxe;
+ const u8 *ie, *ie2, *p2p, *mesh, *owe, *rsnxe;
mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
@@ -3139,10 +3131,6 @@
return -1;
pos += ret;
}
- osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- if (osen_ie)
- pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
- osen_ie, 2 + osen_ie[1]);
owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
if (owe) {
ret = os_snprintf(pos, end - pos,
@@ -3152,7 +3140,7 @@
pos += ret;
}
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
- if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) {
+ if (!ie && !ie2 && (bss->caps & IEEE80211_CAP_PRIVACY)) {
ret = os_snprintf(pos, end - pos, "[WEP]");
if (os_snprintf_error(end - pos, ret))
return -1;
@@ -4462,14 +4450,6 @@
pos += ret;
}
#endif /* CONFIG_SHA256 */
-#ifdef CONFIG_HS20
- if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OSEN) {
- ret = os_snprintf(pos, end - pos, " OSEN");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
-#endif /* CONFIG_HS20 */
return pos - buf;
}
@@ -4962,6 +4942,28 @@
return res;
}
+#ifdef CONFIG_P2P
+ if (os_strcmp(field, "p2p2") == 0) {
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_P2P_FEATURE_V2)
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+
+ if (os_strcmp(field, "pcc_mode") == 0) {
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_P2P_FEATURE_PCC_MODE)
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_P2P */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -5331,7 +5333,7 @@
size_t i;
int ret;
char *pos, *end;
- const u8 *ie, *ie2, *osen_ie, *mesh, *owe, *rsnxe;
+ const u8 *ie, *ie2, *mesh, *owe, *rsnxe;
pos = buf;
end = buf + buflen;
@@ -5464,10 +5466,6 @@
return 0;
pos += ret;
}
- osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- if (osen_ie)
- pos = wpa_supplicant_ie_txt(pos, end, "OSEN",
- osen_ie, 2 + osen_ie[1]);
owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
if (owe) {
ret = os_snprintf(
@@ -5478,7 +5476,7 @@
pos += ret;
}
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
- if (!ie && !ie2 && !osen_ie &&
+ if (!ie && !ie2 &&
(bss->caps & IEEE80211_CAP_PRIVACY)) {
ret = os_snprintf(pos, end - pos, "[WEP]");
if (os_snprintf_error(end - pos, ret))
@@ -5666,12 +5664,6 @@
anqp->hs20_connection_capability);
pos = anqp_add_hex(pos, end, "hs20_operating_class",
anqp->hs20_operating_class);
- pos = anqp_add_hex(pos, end, "hs20_osu_providers_list",
- anqp->hs20_osu_providers_list);
- pos = anqp_add_hex(pos, end, "hs20_operator_icon_metadata",
- anqp->hs20_operator_icon_metadata);
- pos = anqp_add_hex(pos, end, "hs20_osu_providers_nai_list",
- anqp->hs20_osu_providers_nai_list);
#endif /* CONFIG_HS20 */
dl_list_for_each(elem, &anqp->anqp_elems,
@@ -6322,7 +6314,7 @@
return -1;
}
- return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+ return wpas_p2p_prov_disc(wpa_s, addr, NULL, 0, WPAS_P2P_PD_FOR_ASP,
p2ps_prov);
}
@@ -6351,7 +6343,7 @@
p2ps_prov->pd_seeker = 1;
- return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+ return wpas_p2p_prov_disc(wpa_s, addr, NULL, 0, WPAS_P2P_PD_FOR_ASP,
p2ps_prov);
}
@@ -6531,7 +6523,6 @@
if (pos2) {
pos2 += 13;
bootstrap = atoi(pos2);
- pd = true;
}
while ((token = str_token(pos, " ", &context))) {
@@ -6590,10 +6581,11 @@
static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
{
u8 addr[ETH_ALEN];
- char *pos;
+ char *pos, *pos2;
enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
+ u16 bootstrap = 0;
- /* <addr> <config method> [join|auto] */
+ /* <addr> <config method> [join|auto] [bstrapmethod=<value>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -6608,7 +6600,13 @@
else if (os_strstr(pos, " auto") != NULL)
use = WPAS_P2P_PD_AUTO;
- return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
+ pos2 = os_strstr(pos, "bstrapmethod=");
+ if (pos2) {
+ pos2 += 13;
+ bootstrap = atoi(pos2);
+ }
+
+ return wpas_p2p_prov_disc(wpa_s, addr, pos, bootstrap, use, NULL);
}
@@ -6626,6 +6624,52 @@
}
+static int p2p_ctrl_validate_dira(struct wpa_supplicant *wpa_s, char *cmd,
+ char *buf, size_t buflen)
+{
+ char *pos, *pos2;
+ u8 addr[ETH_ALEN];
+ u8 nonce[DEVICE_IDENTITY_NONCE_LEN];
+ u8 tag[DEVICE_IDENTITY_TAG_LEN];
+ int id;
+ int res;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+
+ pos2 = os_strstr(pos, "nonce=");
+ if (pos2) {
+ pos2 += 6;
+ if (hexstr2bin(pos2, nonce, sizeof(nonce)) < 0)
+ return -1;
+ } else {
+ return -1;
+ }
+
+ pos2 = os_strstr(pos, "tag=");
+ if (pos2) {
+ pos2 += 4;
+ if (hexstr2bin(pos2, tag, sizeof(tag)) < 0)
+ return -1;
+ } else {
+ return -1;
+ }
+
+ id = wpas_p2p_validate_dira(wpa_s, addr, 0, nonce, tag);
+ if (id <= 0)
+ return -1;
+
+ res = os_snprintf(buf, buflen, "%u", id);
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+}
+
+
static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
@@ -7099,7 +7143,7 @@
{
char *pos;
int id;
- struct wpa_ssid *ssid;
+ struct wpa_ssid *ssid = NULL;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
@@ -7107,7 +7151,8 @@
bool allow_6ghz;
bool p2p2;
- id = atoi(cmd);
+ p2p2 = os_strstr(cmd, " p2p2") != NULL;
+
pos = os_strstr(cmd, " peer=");
if (pos) {
pos += 6;
@@ -7115,11 +7160,19 @@
return -1;
_peer = peer;
}
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL || ssid->disabled != 2) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
- "for persistent P2P group",
- id);
+
+ if (os_strncmp(cmd, "persistent=", 11) == 0) {
+ id = atoi(cmd + 11);
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (!ssid || ssid->disabled != 2) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: Could not find SSID id=%d for persistent P2P group",
+ id);
+ return -1;
+ }
+ } else if (p2p2 && !_peer) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: Could not find peer for persistent P2P group");
return -1;
}
@@ -7162,8 +7215,6 @@
if (allow_6ghz && chwidth == 40)
max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
- p2p2 = os_strstr(cmd, " p2p2") != NULL;
-
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
max_oper_chwidth, pref_freq, he, edmg,
allow_6ghz, p2p2);
@@ -7206,8 +7257,8 @@
static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
{
- if (os_strncmp(cmd, "persistent=", 11) == 0)
- return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
+ if (os_strncmp(cmd, "persistent", 10) == 0)
+ return p2p_ctrl_invite_persistent(wpa_s, cmd);
if (os_strncmp(cmd, "group=", 6) == 0)
return p2p_ctrl_invite_group(wpa_s, cmd + 6);
@@ -8258,7 +8309,7 @@
if (subtypes == 0)
return -1;
- return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0, 0);
+ return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
}
@@ -8281,7 +8332,7 @@
ret = hs20_anqp_send_req(wpa_s, addr,
BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
- buf, len, 0);
+ buf, len);
os_free(buf);
@@ -8327,77 +8378,12 @@
ret = hs20_anqp_send_req(wpa_s, dst_addr,
BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
- buf, len, 0);
+ buf, len);
os_free(buf);
return ret;
}
-
-static int get_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd, char *reply,
- int buflen)
-{
- u8 dst_addr[ETH_ALEN];
- int used;
- char *ctx = NULL, *icon, *poffset, *psize;
-
- used = hwaddr_aton2(cmd, dst_addr);
- if (used < 0)
- return -1;
- cmd += used;
-
- icon = str_token(cmd, " ", &ctx);
- poffset = str_token(cmd, " ", &ctx);
- psize = str_token(cmd, " ", &ctx);
- if (!icon || !poffset || !psize)
- return -1;
-
- wpa_s->fetch_osu_icon_in_progress = 0;
- return hs20_get_icon(wpa_s, dst_addr, icon, atoi(poffset), atoi(psize),
- reply, buflen);
-}
-
-
-static int del_hs20_icon(struct wpa_supplicant *wpa_s, char *cmd)
-{
- u8 dst_addr[ETH_ALEN];
- int used;
- char *icon;
-
- if (!cmd[0])
- return hs20_del_icon(wpa_s, NULL, NULL);
-
- used = hwaddr_aton2(cmd, dst_addr);
- if (used < 0)
- return -1;
-
- while (cmd[used] == ' ')
- used++;
- icon = cmd[used] ? &cmd[used] : NULL;
-
- return hs20_del_icon(wpa_s, dst_addr, icon);
-}
-
-
-static int hs20_icon_request(struct wpa_supplicant *wpa_s, char *cmd, int inmem)
-{
- u8 dst_addr[ETH_ALEN];
- int used;
- char *icon;
-
- used = hwaddr_aton2(cmd, dst_addr);
- if (used < 0)
- return -1;
-
- while (cmd[used] == ' ')
- used++;
- icon = &cmd[used];
-
- wpa_s->fetch_osu_icon_in_progress = 0;
- return hs20_anqp_send_req(wpa_s, dst_addr, BIT(HS20_STYPE_ICON_REQUEST),
- (u8 *) icon, os_strlen(icon), inmem);
-}
-
#endif /* CONFIG_HS20 */
@@ -9024,13 +9010,6 @@
wnm_btm_reset(wpa_s);
-#ifdef CONFIG_INTERWORKING
-#ifdef CONFIG_HS20
- hs20_cancel_fetch_osu(wpa_s);
- hs20_del_icon(wpa_s, NULL, NULL);
-#endif /* CONFIG_HS20 */
-#endif /* CONFIG_INTERWORKING */
-
wpa_s->ext_mgmt_frame_handling = 0;
wpa_s->ext_eapol_frame_io = 0;
#ifdef CONFIG_TESTING_OPTIONS
@@ -10506,6 +10485,7 @@
params.key_mgmt_suite = wpa_s->key_mgmt;
params.wpa_proto = wpa_s->wpa_proto;
params.mgmt_frame_protection = wpa_s->sme.mfp;
+ params.spp_amsdu = wpa_s->sme.spp_amsdu;
params.rrm_used = wpa_s->rrm.rrm_used;
if (wpa_s->sme.prev_bssid_set)
params.prev_bssid = wpa_s->sme.prev_bssid;
@@ -12727,6 +12707,53 @@
return ret;
}
+
+static int wpas_ctrl_nan_unpause_publish(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *token, *context = NULL;
+ int publish_id = 0;
+ int peer_instance_id = 0;
+ u8 peer_addr[ETH_ALEN];
+
+ os_memset(peer_addr, 0, ETH_ALEN);
+
+ while ((token = str_token(cmd, " ", &context))) {
+ if (sscanf(token, "publish_id=%i", &publish_id) == 1)
+ continue;
+
+ if (sscanf(token, "peer_instance_id=%i",
+ &peer_instance_id) == 1)
+ continue;
+
+ if (os_strncmp(token, "peer=", 5) == 0) {
+ if (hwaddr_aton(token + 5, peer_addr) < 0)
+ return -1;
+ continue;
+ }
+
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid NAN_UNPAUSE_PUBLISH parameter: %s",
+ token);
+ return -1;
+ }
+
+ if (publish_id <= 0) {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid or missing NAN_UNPAUSE_PUBLIH publish_id");
+ return -1;
+ }
+
+ if (is_zero_ether_addr(peer_addr)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid or missing NAN_UNPAUSE_PUBLISH address");
+ return -1;
+ }
+
+ return wpas_nan_usd_unpause_publish(wpa_s, publish_id, peer_instance_id,
+ peer_addr);
+}
+
#endif /* CONFIG_NAN_USD */
@@ -13029,6 +13056,11 @@
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
+ } else if (os_strcmp(buf, "P2P_GET_DIRA") == 0) {
+ reply_len = wpas_p2p_get_dira(wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "P2P_VALIDATE_DIRA ", 18) == 0) {
+ reply_len = p2p_ctrl_validate_dira(wpa_s, buf + 18,
+ reply, reply_size);
#ifdef CONFIG_PASN
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcmp(buf, "P2P_GET_PASNPTK") == 0) {
@@ -13160,25 +13192,6 @@
} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
reply_len = -1;
- } else if (os_strncmp(buf, "HS20_ICON_REQUEST ", 18) == 0) {
- if (hs20_icon_request(wpa_s, buf + 18, 0) < 0)
- reply_len = -1;
- } else if (os_strncmp(buf, "REQ_HS20_ICON ", 14) == 0) {
- if (hs20_icon_request(wpa_s, buf + 14, 1) < 0)
- reply_len = -1;
- } else if (os_strncmp(buf, "GET_HS20_ICON ", 14) == 0) {
- reply_len = get_hs20_icon(wpa_s, buf + 14, reply, reply_size);
- } else if (os_strncmp(buf, "DEL_HS20_ICON ", 14) == 0) {
- if (del_hs20_icon(wpa_s, buf + 14) < 0)
- reply_len = -1;
- } else if (os_strcmp(buf, "FETCH_OSU") == 0) {
- if (hs20_fetch_osu(wpa_s, 0) < 0)
- reply_len = -1;
- } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
- if (hs20_fetch_osu(wpa_s, 1) < 0)
- reply_len = -1;
- } else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
- hs20_cancel_fetch_osu(wpa_s);
#endif /* CONFIG_HS20 */
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
{
@@ -13768,6 +13781,9 @@
} else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) {
if (wpas_ctrl_nan_transmit(wpa_s, buf + 13) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "NAN_UNPAUSE_PUBLISH ", 20) == 0) {
+ if (wpas_ctrl_nan_unpause_publish(wpa_s, buf + 20) < 0)
+ reply_len = -1;
} else if (os_strcmp(buf, "NAN_FLUSH") == 0) {
wpas_nan_usd_flush(wpa_s);
#endif /* CONFIG_NAN_USD */
@@ -14133,6 +14149,8 @@
#ifdef CONFIG_AP
"STA-FIRST",
#endif /* CONFIG_AP */
+ "P2P_GET_DIRA",
+ "P2P_VALIDATE_DIRA",
NULL
};
static const char * prefix[] = {
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index ff7e003..7893f35 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -2386,17 +2386,18 @@
/**
- * wpas_dbus_signal_p2p_bootstrap_completed - Signals BootstrappingCompleted event
- * event
+ * wpas_dbus_signal_p2p_bootstrap_rsp - Signals BootstrappingResponse event
* @wpa_s: %wpa_supplicant network interface data
* @src: Source address of the peer with which bootstrapping is done
* @status: Status of Bootstrapping handshake
+ * @bootstrap_method: Peer's bootstrap method if status is success
*
* Sends a signal to notify that a peer P2P Device is requesting bootstrapping
* negotiation with us.
*/
-void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
- const u8 *src, int status)
+void wpas_dbus_signal_p2p_bootstrap_rsp(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status,
+ u16 bootstrap_method)
{
DBusMessage *msg;
DBusMessageIter iter;
@@ -2430,7 +2431,9 @@
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
&path) ||
!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
- &status))
+ &status) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+ &bootstrap_method))
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
else
dbus_connection_send(iface->con, msg, NULL);
@@ -2604,41 +2607,6 @@
/**
- * wpas_dbus_sta_signal_prop_changed - Signals change of STA property
- * @wpa_s: %wpa_supplicant network interface data
- * @property: indicates which property has changed
- * @address: unique BSS identifier
- *
- * Sends PropertyChanged signals with path, interface, and arguments depending
- * on which property has changed.
- */
-void wpas_dbus_sta_signal_prop_changed(struct wpa_supplicant *wpa_s,
- enum wpas_dbus_bss_prop property,
- u8 address[ETH_ALEN])
-{
- char path[WPAS_DBUS_OBJECT_PATH_MAX];
- char *prop;
-
- switch (property) {
- case WPAS_DBUS_STA_PROP_ADDRESS:
- prop = "Address";
- break;
- default:
- wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
- __func__, property);
- return;
- }
-
- os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
- wpa_s->dbus_new_path, MAC2STR(address));
-
- wpa_dbus_mark_property_changed(wpa_s->global->dbus, path,
- WPAS_DBUS_NEW_IFACE_STA, prop);
-}
-
-
-/**
* wpas_dbus_signal_debug_level_changed - Signals change of debug param
* @global: wpa_global structure
*
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index f9ff636..d648435 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -268,8 +268,9 @@
int op_freq);
void wpas_dbus_signal_p2p_bootstrap_req(struct wpa_supplicant *wpa_s,
const u8 *src, u16 bootstrap_method);
-void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
- const u8 *src, int status);
+void wpas_dbus_signal_p2p_bootstrap_rsp(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status,
+ u16 bootstrap_method);
void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s,
@@ -650,8 +651,9 @@
}
static inline
-void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
- const u8 *src, int status)
+void wpas_dbus_signal_p2p_bootstrap_rsp(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status,
+ u16 bootstrap_method)
{
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 2fad8dd..e43bf83 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -5901,24 +5901,6 @@
wpabuf_head(anqp->hs20_operating_class),
wpabuf_len(anqp->hs20_operating_class)))
goto nomem;
- if (anqp->hs20_osu_providers_list &&
- !wpa_dbus_dict_append_byte_array(
- &iter_dict, "HS20OSUProvidersList",
- wpabuf_head(anqp->hs20_osu_providers_list),
- wpabuf_len(anqp->hs20_osu_providers_list)))
- goto nomem;
- if (anqp->hs20_operator_icon_metadata &&
- !wpa_dbus_dict_append_byte_array(
- &iter_dict, "HS20OperatorIconMetadata",
- wpabuf_head(anqp->hs20_operator_icon_metadata),
- wpabuf_len(anqp->hs20_operator_icon_metadata)))
- goto nomem;
- if (anqp->hs20_osu_providers_nai_list &&
- !wpa_dbus_dict_append_byte_array(
- &iter_dict, "HS20OSUProvidersNAIList",
- wpabuf_head(anqp->hs20_osu_providers_nai_list),
- wpabuf_len(anqp->hs20_osu_providers_nai_list)))
- goto nomem;
#endif /* CONFIG_HS20 */
dl_list_for_each(elem, &anqp->anqp_elems,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index ce49bce..fc59947 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -929,7 +929,7 @@
if (!wpa_s)
return wpas_dbus_error_no_p2p_mgmt_iface(message);
- if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
+ if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0,
WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to send provision discovery request");
diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c
index 3f018c4..794ec19 100644
--- a/wpa_supplicant/eap_register.c
+++ b/wpa_supplicant/eap_register.c
@@ -40,13 +40,6 @@
ret = eap_peer_unauth_tls_register();
#endif /* EAP_UNAUTH_TLS */
-#ifdef EAP_TLS
-#ifdef CONFIG_HS20
- if (ret == 0)
- ret = eap_peer_wfa_unauth_tls_register();
-#endif /* CONFIG_HS20 */
-#endif /* EAP_TLS */
-
#ifdef EAP_MSCHAPv2
if (ret == 0)
ret = eap_peer_mschapv2_register();
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 30176a0..6808956 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -443,7 +443,7 @@
}
-static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s, bool authorized)
+static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
{
struct wpa_ie_data ie;
int pmksa_set = -1;
@@ -468,8 +468,7 @@
true);
if (pmksa_set == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
- if (authorized)
- wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+ wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
break;
}
}
@@ -641,9 +640,6 @@
if (wpa_key_mgmt_wpa(ssid->key_mgmt))
privacy = 1;
- if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)
- privacy = 1;
-
if (bss->caps & IEEE80211_CAP_PRIVACY)
return privacy;
return !privacy;
@@ -683,7 +679,7 @@
return 0;
}
- while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
+ while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
proto_match++;
if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
@@ -718,8 +714,7 @@
}
#endif /* CONFIG_WEP */
- if (!(ie.proto & ssid->proto) &&
- !(ssid->proto & WPA_PROTO_OSEN)) {
+ if (!(ie.proto & ssid->proto)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
" skip RSN IE - proto mismatch");
@@ -921,13 +916,6 @@
return 0;
}
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) &&
- wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN");
- return 1;
- }
-
if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
@@ -1225,7 +1213,7 @@
static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
const u8 *match_ssid, size_t match_ssid_len,
struct wpa_bss *bss, int bssid_ignore_count,
- bool debug_print);
+ bool debug_print, bool link);
#ifdef CONFIG_SAE_PK
@@ -1255,7 +1243,7 @@
count = wpa_bssid_ignore_is_listed(wpa_s, bss->bssid);
if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
- bss, count, 0))
+ bss, count, false, false))
return true;
}
@@ -1267,13 +1255,10 @@
static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
const u8 *match_ssid, size_t match_ssid_len,
struct wpa_bss *bss, int bssid_ignore_count,
- bool debug_print)
+ bool debug_print, bool link)
{
int res;
- bool wpa, check_ssid, osen, rsn_osen = false;
-#ifndef CONFIG_NO_WPA
- struct wpa_ie_data data;
-#endif /* CONFIG_NO_WPA */
+ bool wpa, check_ssid = false;
#ifdef CONFIG_MBO
const u8 *assoc_disallow;
#endif /* CONFIG_MBO */
@@ -1287,13 +1272,6 @@
wpa = ie && ie[1];
ie = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
wpa |= ie && ie[1];
-#ifndef CONFIG_NO_WPA
- if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
- (data.key_mgmt & WPA_KEY_MGMT_OSEN))
- rsn_osen = true;
-#endif /* CONFIG_NO_WPA */
- ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- osen = ie != NULL;
#ifdef CONFIG_SAE
ie = wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
@@ -1352,7 +1330,7 @@
return false;
}
- if (ssid->bssid_set &&
+ if (!link && ssid->bssid_set &&
!ether_addr_equal(bss->bssid, ssid->bssid)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
@@ -1382,7 +1360,7 @@
if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss, debug_print))
return false;
- if (!osen && !wpa &&
+ if (!wpa &&
!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
@@ -1402,13 +1380,6 @@
}
#endif /* CONFIG_WEP */
- if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && !rsn_osen) {
- if (debug_print)
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - non-OSEN network not allowed");
- return false;
- }
-
if (!wpa_supplicant_match_privacy(bss, ssid)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy mismatch");
@@ -1629,7 +1600,7 @@
return false;
}
- if (!wpas_valid_ml_bss(wpa_s, bss)) {
+ if (!link && !wpas_valid_ml_bss(wpa_s, bss)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
" skip - ML BSS going to be removed");
@@ -1644,12 +1615,12 @@
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
- int only_first_ssid, int debug_print)
+ int only_first_ssid, int debug_print,
+ bool link)
{
u8 wpa_ie_len, rsn_ie_len;
const u8 *ie;
struct wpa_ssid *ssid;
- int osen;
const u8 *match_ssid;
size_t match_ssid_len;
int bssid_ignore_count;
@@ -1660,12 +1631,9 @@
ie = wpa_bss_get_rsne(wpa_s, bss, NULL, false);
rsn_ie_len = ie ? ie[1] : 0;
- ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- osen = ie != NULL;
-
if (debug_print) {
wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR
- " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
+ " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s",
i, MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len),
wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
@@ -1674,8 +1642,7 @@
" wps" : "",
(wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE))
- ? " p2p" : "",
- osen ? " osen=1" : "");
+ ? " p2p" : "");
}
bssid_ignore_count = wpa_bssid_ignore_is_listed(wpa_s, bss->bssid);
@@ -1738,7 +1705,7 @@
for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) {
if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len,
- bss, bssid_ignore_count, debug_print))
+ bss, bssid_ignore_count, debug_print, link))
return ssid;
}
@@ -1764,7 +1731,7 @@
struct wpa_bss *bss = wpa_s->last_scan_res[i];
ssid = wpa_scan_res_match(wpa_s, i, bss, group,
- only_first_ssid, 0);
+ only_first_ssid, 0, false);
if (ssid != wpa_s->current_ssid)
continue;
wpa_dbg(wpa_s, MSG_DEBUG, "%u: " MACSTR
@@ -1786,7 +1753,7 @@
wpa_s->owe_transition_select = 1;
*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
- only_first_ssid, 1);
+ only_first_ssid, 1, false);
wpa_s->owe_transition_select = 0;
if (!*selected_ssid)
continue;
@@ -3116,7 +3083,7 @@
goto fail;
}
wpa_s->enabled_4addr_mode = 1;
- wpa_msg(wpa_s, MSG_INFO, "Successfully set 4addr mode");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Successfully set 4addr mode");
return;
fail:
@@ -3277,8 +3244,7 @@
wpa_s->wpa_proto = ie.proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, wpa_s->wpa_proto);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
- !!(wpa_s->wpa_proto &
- (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
+ !!(wpa_s->wpa_proto & WPA_PROTO_RSN));
/* Update AKMP suite from (Re)Association Request frame info */
sel = ie.key_mgmt;
@@ -3359,7 +3325,7 @@
/* Update GTK and IGTK from AP's RSNE */
found = false;
- if (wpa_s->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) {
+ if (wpa_s->wpa_proto & WPA_PROTO_RSN) {
const u8 *bss_rsn;
bss_rsn = wpa_bss_get_rsne(wpa_s, bss, ssid,
@@ -3597,8 +3563,7 @@
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
- wpa_find_assoc_pmkid(wpa_s,
- data->assoc_info.authorized);
+ wpa_find_assoc_pmkid(wpa_s);
}
#ifndef CONFIG_NO_WPA
if (!found_x && p[0] == WLAN_EID_RSNX) {
@@ -4025,10 +3990,9 @@
struct eht_ml_basic_common_info *common_info;
const u8 *pos;
u16 eml_capa = 0, mld_capa = 0;
- const u16 control =
- host_to_le16(MULTI_LINK_CONTROL_TYPE_BASIC |
- BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
- BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT);
+ const u16 control = MULTI_LINK_CONTROL_TYPE_BASIC |
+ BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
+ BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT;
u8 expected_common_info_len = 9;
unsigned int i = 0;
u16 ml_control;
@@ -4085,7 +4049,7 @@
}
common_info = (struct eht_ml_basic_common_info *) ml->variable;
- if (common_info->len != expected_common_info_len) {
+ if (common_info->len < expected_common_info_len) {
wpa_printf(MSG_DEBUG,
"MLD: Invalid common info len=%u. expected=%u",
common_info->len, expected_common_info_len);
@@ -4134,7 +4098,7 @@
ml_len -= sizeof(*ml) + common_info->len;
while (ml_len > 2 && i < MAX_NUM_MLD_LINKS) {
u8 sub_elem_len = pos[1];
- u8 sta_info_len;
+ u8 sta_info_len, sta_info_len_min;
u8 nstr_bitmap_len = 0;
u16 ctrl;
const u8 *end;
@@ -4223,15 +4187,21 @@
goto out;
}
- sta_info_len = 1 + ETH_ALEN + 8 + 2 + 2 + 1 + nstr_bitmap_len;
- if (sta_info_len > ml_len || sta_info_len > end - pos ||
- sta_info_len + 2 > sub_elem_len ||
- sta_info_len != *pos) {
+ sta_info_len_min = 1 + ETH_ALEN + 8 + 2 + 2 + 1 +
+ nstr_bitmap_len;
+ if (sta_info_len_min > ml_len || sta_info_len_min > end - pos ||
+ sta_info_len_min + 2 > sub_elem_len ||
+ sta_info_len_min > *pos) {
wpa_printf(MSG_DEBUG,
- "MLD: Invalid STA info len=%u, len=%u",
- sta_info_len, *pos);
+ "MLD: Invalid STA info min len=%u, len=%u",
+ sta_info_len_min, *pos);
goto out;
}
+ sta_info_len = *pos;
+ /* Make static analyzers happier with an explicit check even
+ * though this was already checked above with *pos.. */
+ if (sta_info_len < sta_info_len_min)
+ goto out;
/* Get the link address */
wpa_printf(MSG_DEBUG,
@@ -4870,10 +4840,6 @@
return; /* P2P group removed */
wpas_auth_failed(wpa_s, "WRONG_KEY", wpa_s->pending_bssid);
wpas_notify_psk_mismatch(wpa_s);
-#ifdef CONFIG_DPP2
- wpas_dpp_send_conn_status_result(wpa_s,
- DPP_STATUS_AUTH_FAILURE);
-#endif /* CONFIG_DPP2 */
}
if (!wpa_s->disconnected &&
(!wpa_s->auto_reconnect_disabled ||
@@ -4928,6 +4894,9 @@
else
wpa_s->disconnect_reason = reason_code;
wpas_notify_disconnect_reason(wpa_s);
+#ifdef CONFIG_DPP2
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_AUTH_FAILURE);
+#endif /* CONFIG_DPP2 */
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
wpa_clear_keys(wpa_s, wpa_s->bssid);
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 7d29931..88564d5 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -147,6 +147,10 @@
gas->work = NULL;
}
+ eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
+ eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
+
wpabuf_free(query->req);
wpabuf_free(query->adv_proto);
wpabuf_free(query->resp);
@@ -166,9 +170,6 @@
gas->current = NULL;
if (query->offchannel_tx_started)
offchannel_send_action_done(gas->wpa_s);
- eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
- eloop_cancel_timeout(gas_query_timeout, gas, query);
- eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
dl_list_del(&query->list);
query->cb(query->ctx, query->addr, query->dialog_token, result,
query->adv_proto, query->resp, query->status_code);
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index f14e6cb..d287b70 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -30,42 +30,6 @@
#include "notify.h"
-#define OSU_MAX_ITEMS 10
-
-struct osu_lang_string {
- char lang[4];
- char text[253];
-};
-
-struct osu_icon {
- u16 width;
- u16 height;
- char lang[4];
- char icon_type[256];
- char filename[256];
- unsigned int id;
- unsigned int failed:1;
-};
-
-struct osu_provider {
- u8 bssid[ETH_ALEN];
- u8 osu_ssid[SSID_MAX_LEN];
- u8 osu_ssid_len;
- u8 osu_ssid2[SSID_MAX_LEN];
- u8 osu_ssid2_len;
- char server_uri[256];
- u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
- char osu_nai[256];
- char osu_nai2[256];
- struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
- size_t friendly_name_count;
- struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
- size_t serv_desc_count;
- struct osu_icon icon[OSU_MAX_ITEMS];
- size_t icon_count;
-};
-
-
void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss = wpa_s->current_bss;
@@ -234,11 +198,6 @@
wpabuf_put_u8(buf, 0); /* Reserved */
if (payload)
wpabuf_put_data(buf, payload, payload_len);
- } else if (stypes == BIT(HS20_STYPE_ICON_REQUEST)) {
- wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
- wpabuf_put_u8(buf, 0); /* Reserved */
- if (payload)
- wpabuf_put_data(buf, payload, payload_len);
} else {
u8 i;
wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
@@ -270,14 +229,13 @@
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
- const u8 *payload, size_t payload_len, int inmem)
+ const u8 *payload, size_t payload_len)
{
struct wpabuf *buf;
int ret = 0;
int freq;
struct wpa_bss *bss;
int res;
- struct icon_entry *icon_entry;
bss = wpa_bss_get_bssid(wpa_s, dst);
if (!bss) {
@@ -307,299 +265,10 @@
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
- if (inmem) {
- icon_entry = os_zalloc(sizeof(struct icon_entry));
- if (!icon_entry)
- return -1;
- os_memcpy(icon_entry->bssid, dst, ETH_ALEN);
- icon_entry->file_name = os_malloc(payload_len + 1);
- if (!icon_entry->file_name) {
- os_free(icon_entry);
- return -1;
- }
- os_memcpy(icon_entry->file_name, payload, payload_len);
- icon_entry->file_name[payload_len] = '\0';
- icon_entry->dialog_token = res;
-
- dl_list_add(&wpa_s->icon_head, &icon_entry->list);
- }
-
return ret;
}
-static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s,
- const u8 *bssid,
- const char *file_name)
-{
- struct icon_entry *icon;
-
- dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
- if (ether_addr_equal(icon->bssid, bssid) &&
- os_strcmp(icon->file_name, file_name) == 0 && icon->image)
- return icon;
- }
-
- return NULL;
-}
-
-
-int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *file_name, size_t offset, size_t size,
- char *reply, size_t buf_len)
-{
- struct icon_entry *icon;
- size_t out_size;
- char *b64;
- size_t b64_size;
- int reply_size;
-
- wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)",
- MAC2STR(bssid), file_name, (unsigned int) offset,
- (unsigned int) size, (unsigned int) buf_len);
-
- icon = hs20_find_icon(wpa_s, bssid, file_name);
- if (!icon || !icon->image || offset >= icon->image_len)
- return -1;
- if (size > icon->image_len - offset)
- size = icon->image_len - offset;
- out_size = buf_len - 3 /* max base64 padding */;
- if (size * 4 > out_size * 3)
- size = out_size * 3 / 4;
- if (size == 0)
- return -1;
-
- b64 = base64_encode(&icon->image[offset], size, &b64_size);
- if (b64 && buf_len >= b64_size) {
- os_memcpy(reply, b64, b64_size);
- reply_size = b64_size;
- } else {
- reply_size = -1;
- }
- os_free(b64);
- return reply_size;
-}
-
-
-static void hs20_free_icon_entry(struct icon_entry *icon)
-{
- wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR
- " dialog_token=%u file_name=%s image_len=%u",
- MAC2STR(icon->bssid), icon->dialog_token,
- icon->file_name ? icon->file_name : "N/A",
- (unsigned int) icon->image_len);
- os_free(icon->file_name);
- os_free(icon->image);
- os_free(icon);
-}
-
-
-int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *file_name)
-{
- struct icon_entry *icon, *tmp;
- int count = 0;
-
- if (!bssid)
- wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons");
- else if (!file_name)
- wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for "
- MACSTR, MAC2STR(bssid));
- else
- wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for "
- MACSTR " file name %s", MAC2STR(bssid), file_name);
-
- dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
- list) {
- if ((!bssid || ether_addr_equal(icon->bssid, bssid)) &&
- (!file_name ||
- os_strcmp(icon->file_name, file_name) == 0)) {
- dl_list_del(&icon->list);
- hs20_free_icon_entry(icon);
- count++;
- }
- }
- return count == 0 ? -1 : 0;
-}
-
-
-static void hs20_set_osu_access_permission(const char *osu_dir,
- const char *fname)
-{
- struct stat statbuf;
-
- /* Get OSU directory information */
- if (stat(osu_dir, &statbuf) < 0) {
- wpa_printf(MSG_WARNING, "Cannot stat the OSU directory %s",
- osu_dir);
- return;
- }
-
- if (chmod(fname, statbuf.st_mode) < 0) {
- wpa_printf(MSG_WARNING,
- "Cannot change the permissions for %s", fname);
- return;
- }
-
- if (lchown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
- wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
- fname);
- }
-}
-
-
-static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s,
- struct icon_entry *new_icon)
-{
- struct icon_entry *icon, *tmp;
-
- dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
- list) {
- if (icon == new_icon)
- continue;
- if (ether_addr_equal(icon->bssid, new_icon->bssid) &&
- os_strcmp(icon->file_name, new_icon->file_name) == 0) {
- dl_list_del(&icon->list);
- hs20_free_icon_entry(icon);
- }
- }
-}
-
-
-static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
- const u8 *sa, const u8 *pos,
- size_t slen, u8 dialog_token)
-{
- char fname[256];
- int png;
- FILE *f;
- u16 data_len;
- struct icon_entry *icon;
-
- dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
- if (icon->dialog_token == dialog_token && !icon->image &&
- ether_addr_equal(icon->bssid, sa)) {
- icon->image = os_memdup(pos, slen);
- if (!icon->image)
- return -1;
- icon->image_len = slen;
- hs20_remove_duplicate_icons(wpa_s, icon);
- wpa_msg(wpa_s, MSG_INFO,
- RX_HS20_ICON MACSTR " %s %u",
- MAC2STR(sa), icon->file_name,
- (unsigned int) icon->image_len);
- wpas_notify_hs20_icon_query_done(wpa_s, sa,
- icon->file_name,
- icon->image,
- icon->image_len);
- return 0;
- }
- }
-
- wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
- MAC2STR(sa));
-
- if (slen < 4) {
- wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
- "value from " MACSTR, MAC2STR(sa));
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos);
- if (*pos != 0)
- return -1;
- pos++;
- slen--;
-
- if ((size_t) 1 + pos[0] > slen) {
- wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
- "value from " MACSTR, MAC2STR(sa));
- return -1;
- }
- wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]);
- png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0;
- slen -= 1 + pos[0];
- pos += 1 + pos[0];
-
- if (slen < 2) {
- wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
- "value from " MACSTR, MAC2STR(sa));
- return -1;
- }
- data_len = WPA_GET_LE16(pos);
- pos += 2;
- slen -= 2;
-
- if (data_len > slen) {
- wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
- "value from " MACSTR, MAC2STR(sa));
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len);
- if (wpa_s->conf->osu_dir == NULL)
- return -1;
-
- wpa_s->osu_icon_id++;
- if (wpa_s->osu_icon_id == 0)
- wpa_s->osu_icon_id++;
- snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s",
- wpa_s->conf->osu_dir, wpa_s->osu_icon_id,
- png ? "png" : "icon");
- f = fopen(fname, "wb");
- if (f == NULL)
- return -1;
-
- hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
-
- if (fwrite(pos, slen, 1, f) != 1) {
- fclose(f);
- unlink(fname);
- return -1;
- }
- fclose(f);
-
- wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
- return 0;
-}
-
-
-static void hs20_continue_icon_fetch(void *eloop_ctx, void *sock_ctx)
-{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- if (wpa_s->fetch_osu_icon_in_progress)
- hs20_next_osu_icon(wpa_s);
-}
-
-
-static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
-{
- size_t i, j;
- struct os_reltime now, tmp;
- int dur;
-
- os_get_reltime(&now);
- os_reltime_sub(&now, &wpa_s->osu_icon_fetch_start, &tmp);
- dur = tmp.sec * 1000 + tmp.usec / 1000;
- wpa_printf(MSG_DEBUG, "HS 2.0: Icon fetch dur=%d ms res=%d",
- dur, res);
-
- for (i = 0; i < wpa_s->osu_prov_count; i++) {
- struct osu_provider *osu = &wpa_s->osu_prov[i];
- for (j = 0; j < osu->icon_count; j++) {
- struct osu_icon *icon = &osu->icon[j];
- if (icon->id || icon->failed)
- continue;
- if (res < 0)
- icon->failed = 1;
- else
- icon->id = wpa_s->osu_icon_id;
- return;
- }
- }
-}
-
-
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, const u8 *sa,
const u8 *data, size_t slen, u8 dialog_token)
@@ -607,7 +276,6 @@
const u8 *pos = data;
u8 subtype;
struct wpa_bss_anqp *anqp = NULL;
- int ret;
if (slen < 2)
return;
@@ -678,46 +346,6 @@
wpabuf_alloc_copy(pos, slen);
}
break;
- case HS20_STYPE_OSU_PROVIDERS_LIST:
- wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
- " OSU Providers list", MAC2STR(sa));
- wpa_s->num_prov_found++;
- if (anqp) {
- wpabuf_free(anqp->hs20_osu_providers_list);
- anqp->hs20_osu_providers_list =
- wpabuf_alloc_copy(pos, slen);
- }
- break;
- case HS20_STYPE_ICON_BINARY_FILE:
- ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen,
- dialog_token);
- if (wpa_s->fetch_osu_icon_in_progress) {
- hs20_osu_icon_fetch_result(wpa_s, ret);
- eloop_cancel_timeout(hs20_continue_icon_fetch,
- wpa_s, NULL);
- eloop_register_timeout(0, 0, hs20_continue_icon_fetch,
- wpa_s, NULL);
- }
- break;
- case HS20_STYPE_OPERATOR_ICON_METADATA:
- wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
- " Operator Icon Metadata", MAC2STR(sa));
- wpa_hexdump(MSG_DEBUG, "Operator Icon Metadata", pos, slen);
- if (anqp) {
- wpabuf_free(anqp->hs20_operator_icon_metadata);
- anqp->hs20_operator_icon_metadata =
- wpabuf_alloc_copy(pos, slen);
- }
- break;
- case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
- wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
- " OSU Providers NAI List", MAC2STR(sa));
- if (anqp) {
- wpabuf_free(anqp->hs20_osu_providers_nai_list);
- anqp->hs20_osu_providers_nai_list =
- wpabuf_alloc_copy(pos, slen);
- }
- break;
default:
wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
break;
@@ -725,582 +353,6 @@
}
-void hs20_notify_parse_done(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s->fetch_osu_icon_in_progress)
- return;
- if (eloop_is_timeout_registered(hs20_continue_icon_fetch, wpa_s, NULL))
- return;
- /*
- * We are going through icon fetch, but no icon response was received.
- * Assume this means the current AP could not provide an answer to avoid
- * getting stuck in fetch iteration.
- */
- hs20_icon_fetch_failed(wpa_s);
-}
-
-
-static void hs20_free_osu_prov_entry(struct osu_provider *prov)
-{
-}
-
-
-void hs20_free_osu_prov(struct wpa_supplicant *wpa_s)
-{
- size_t i;
- for (i = 0; i < wpa_s->osu_prov_count; i++)
- hs20_free_osu_prov_entry(&wpa_s->osu_prov[i]);
- os_free(wpa_s->osu_prov);
- wpa_s->osu_prov = NULL;
- wpa_s->osu_prov_count = 0;
-}
-
-
-static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
-{
- char fname[256];
- FILE *f;
- size_t i, j;
-
- wpa_s->fetch_osu_info = 0;
- wpa_s->fetch_osu_icon_in_progress = 0;
-
- if (wpa_s->conf->osu_dir == NULL) {
- hs20_free_osu_prov(wpa_s);
- wpa_s->fetch_anqp_in_progress = 0;
- return;
- }
-
- snprintf(fname, sizeof(fname), "%s/osu-providers.txt",
- wpa_s->conf->osu_dir);
- f = fopen(fname, "w");
- if (f == NULL) {
- wpa_msg(wpa_s, MSG_INFO,
- "Could not write OSU provider information");
- hs20_free_osu_prov(wpa_s);
- wpa_s->fetch_anqp_in_progress = 0;
- return;
- }
-
- hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
-
- for (i = 0; i < wpa_s->osu_prov_count; i++) {
- struct osu_provider *osu = &wpa_s->osu_prov[i];
- if (i > 0)
- fprintf(f, "\n");
- fprintf(f, "OSU-PROVIDER " MACSTR "\n"
- "uri=%s\n"
- "methods=%08x\n",
- MAC2STR(osu->bssid), osu->server_uri, osu->osu_methods);
- if (osu->osu_ssid_len) {
- fprintf(f, "osu_ssid=%s\n",
- wpa_ssid_txt(osu->osu_ssid,
- osu->osu_ssid_len));
- }
- if (osu->osu_ssid2_len) {
- fprintf(f, "osu_ssid2=%s\n",
- wpa_ssid_txt(osu->osu_ssid2,
- osu->osu_ssid2_len));
- }
- if (osu->osu_nai[0])
- fprintf(f, "osu_nai=%s\n", osu->osu_nai);
- if (osu->osu_nai2[0])
- fprintf(f, "osu_nai2=%s\n", osu->osu_nai2);
- for (j = 0; j < osu->friendly_name_count; j++) {
- fprintf(f, "friendly_name=%s:%s\n",
- osu->friendly_name[j].lang,
- osu->friendly_name[j].text);
- }
- for (j = 0; j < osu->serv_desc_count; j++) {
- fprintf(f, "desc=%s:%s\n",
- osu->serv_desc[j].lang,
- osu->serv_desc[j].text);
- }
- for (j = 0; j < osu->icon_count; j++) {
- struct osu_icon *icon = &osu->icon[j];
- if (icon->failed)
- continue; /* could not fetch icon */
- fprintf(f, "icon=%u:%u:%u:%s:%s:%s\n",
- icon->id, icon->width, icon->height, icon->lang,
- icon->icon_type, icon->filename);
- }
- }
- fclose(f);
- hs20_free_osu_prov(wpa_s);
-
- wpa_msg(wpa_s, MSG_INFO, "OSU provider fetch completed");
- wpa_s->fetch_anqp_in_progress = 0;
-}
-
-
-void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
-{
- size_t i, j;
-
- wpa_printf(MSG_DEBUG, "HS 2.0: Ready to fetch next icon");
-
- for (i = 0; i < wpa_s->osu_prov_count; i++) {
- struct osu_provider *osu = &wpa_s->osu_prov[i];
- for (j = 0; j < osu->icon_count; j++) {
- struct osu_icon *icon = &osu->icon[j];
- if (icon->id || icon->failed)
- continue;
-
- wpa_printf(MSG_DEBUG, "HS 2.0: Try to fetch icon '%s' "
- "from " MACSTR, icon->filename,
- MAC2STR(osu->bssid));
- os_get_reltime(&wpa_s->osu_icon_fetch_start);
- if (hs20_anqp_send_req(wpa_s, osu->bssid,
- BIT(HS20_STYPE_ICON_REQUEST),
- (u8 *) icon->filename,
- os_strlen(icon->filename),
- 0) < 0) {
- icon->failed = 1;
- continue;
- }
- return;
- }
- }
-
- wpa_printf(MSG_DEBUG, "HS 2.0: No more icons to fetch");
- hs20_osu_fetch_done(wpa_s);
-}
-
-
-static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- const u8 *osu_ssid, u8 osu_ssid_len,
- const u8 *osu_ssid2, u8 osu_ssid2_len,
- const u8 *pos, size_t len)
-{
- struct osu_provider *prov;
- const u8 *end = pos + len;
- u16 len2;
- const u8 *pos2;
- u8 uri_len, osu_method_len, osu_nai_len;
-
- wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len);
- prov = os_realloc_array(wpa_s->osu_prov,
- wpa_s->osu_prov_count + 1,
- sizeof(*prov));
- if (prov == NULL)
- return;
- wpa_s->osu_prov = prov;
- prov = &prov[wpa_s->osu_prov_count];
- os_memset(prov, 0, sizeof(*prov));
-
- os_memcpy(prov->bssid, bss->bssid, ETH_ALEN);
- os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len);
- prov->osu_ssid_len = osu_ssid_len;
- if (osu_ssid2)
- os_memcpy(prov->osu_ssid2, osu_ssid2, osu_ssid2_len);
- prov->osu_ssid2_len = osu_ssid2_len;
-
- /* OSU Friendly Name Length */
- if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
- "Friendly Name Length");
- return;
- }
- len2 = WPA_GET_LE16(pos);
- pos += 2;
- if (len2 > end - pos) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
- "Friendly Name Duples");
- return;
- }
- pos2 = pos;
- pos += len2;
-
- /* OSU Friendly Name Duples */
- while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) {
- struct osu_lang_string *f;
- u8 slen;
-
- slen = pos2[0];
- if (1 + slen > pos - pos2) {
- wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
- break;
- }
- if (slen < 3) {
- wpa_printf(MSG_DEBUG,
- "Invalid OSU Friendly Name (no room for language)");
- break;
- }
- f = &prov->friendly_name[prov->friendly_name_count++];
- pos2++;
- os_memcpy(f->lang, pos2, 3);
- pos2 += 3;
- slen -= 3;
- os_memcpy(f->text, pos2, slen);
- pos2 += slen;
- }
-
- /* OSU Server URI */
- if (end - pos < 1) {
- wpa_printf(MSG_DEBUG,
- "HS 2.0: Not enough room for OSU Server URI length");
- return;
- }
- uri_len = *pos++;
- if (uri_len > end - pos) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server "
- "URI");
- return;
- }
- os_memcpy(prov->server_uri, pos, uri_len);
- pos += uri_len;
-
- /* OSU Method list */
- if (end - pos < 1) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
- "list length");
- return;
- }
- osu_method_len = pos[0];
- if (osu_method_len > end - pos - 1) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
- "list");
- return;
- }
- pos2 = pos + 1;
- pos += 1 + osu_method_len;
- while (pos2 < pos) {
- if (*pos2 < 32)
- prov->osu_methods |= BIT(*pos2);
- pos2++;
- }
-
- /* Icons Available Length */
- if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
- "Available Length");
- return;
- }
- len2 = WPA_GET_LE16(pos);
- pos += 2;
- if (len2 > end - pos) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
- "Available");
- return;
- }
- pos2 = pos;
- pos += len2;
-
- /* Icons Available */
- while (pos2 < pos) {
- struct osu_icon *icon = &prov->icon[prov->icon_count];
- u8 flen;
-
- if (2 + 2 + 3 + 1 + 1 > pos - pos2) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
- break;
- }
-
- icon->width = WPA_GET_LE16(pos2);
- pos2 += 2;
- icon->height = WPA_GET_LE16(pos2);
- pos2 += 2;
- os_memcpy(icon->lang, pos2, 3);
- pos2 += 3;
-
- flen = *pos2++;
- if (flen > pos - pos2) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
- break;
- }
- os_memcpy(icon->icon_type, pos2, flen);
- pos2 += flen;
-
- if (pos - pos2 < 1) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
- "Filename length");
- break;
- }
- flen = *pos2++;
- if (flen > pos - pos2) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
- "Filename");
- break;
- }
- os_memcpy(icon->filename, pos2, flen);
- pos2 += flen;
-
- prov->icon_count++;
- }
-
- /* OSU_NAI */
- if (end - pos < 1) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
- return;
- }
- osu_nai_len = *pos++;
- if (osu_nai_len > end - pos) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
- return;
- }
- os_memcpy(prov->osu_nai, pos, osu_nai_len);
- pos += osu_nai_len;
-
- /* OSU Service Description Length */
- if (end - pos < 2) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
- "Service Description Length");
- return;
- }
- len2 = WPA_GET_LE16(pos);
- pos += 2;
- if (len2 > end - pos) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
- "Service Description Duples");
- return;
- }
- pos2 = pos;
- pos += len2;
-
- /* OSU Service Description Duples */
- while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) {
- struct osu_lang_string *f;
- u8 descr_len;
-
- descr_len = *pos2++;
- if (descr_len > pos - pos2 || descr_len < 3) {
- wpa_printf(MSG_DEBUG, "Invalid OSU Service "
- "Description");
- break;
- }
- f = &prov->serv_desc[prov->serv_desc_count++];
- os_memcpy(f->lang, pos2, 3);
- os_memcpy(f->text, pos2 + 3, descr_len - 3);
- pos2 += descr_len;
- }
-
- wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
- MAC2STR(bss->bssid));
- wpa_s->osu_prov_count++;
-}
-
-
-void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
-{
- struct wpa_bss *bss;
- struct wpabuf *prov_anqp;
- const u8 *pos, *end;
- u16 len;
- const u8 *osu_ssid, *osu_ssid2;
- u8 osu_ssid_len, osu_ssid2_len;
- u8 num_providers;
-
- hs20_free_osu_prov(wpa_s);
-
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- struct wpa_ie_data data;
- const u8 *ie;
-
- if (bss->anqp == NULL)
- continue;
- prov_anqp = bss->anqp->hs20_osu_providers_list;
- if (prov_anqp == NULL)
- continue;
- ie = wpa_bss_get_rsne(wpa_s, bss, NULL, false);
- if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &data) == 0 &&
- (data.key_mgmt & WPA_KEY_MGMT_OSEN)) {
- osu_ssid2 = bss->ssid;
- osu_ssid2_len = bss->ssid_len;
- } else {
- osu_ssid2 = NULL;
- osu_ssid2_len = 0;
- }
- wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from "
- MACSTR, MAC2STR(bss->bssid));
- wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list",
- prov_anqp);
- pos = wpabuf_head(prov_anqp);
- end = pos + wpabuf_len(prov_anqp);
-
- /* OSU SSID */
- if (end - pos < 1)
- continue;
- if (1 + pos[0] > end - pos) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
- "OSU SSID");
- continue;
- }
- osu_ssid_len = *pos++;
- if (osu_ssid_len > SSID_MAX_LEN) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Invalid OSU SSID "
- "Length %u", osu_ssid_len);
- continue;
- }
- osu_ssid = pos;
- pos += osu_ssid_len;
-
- if (end - pos < 1) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
- "Number of OSU Providers");
- continue;
- }
- num_providers = *pos++;
- wpa_printf(MSG_DEBUG, "HS 2.0: Number of OSU Providers: %u",
- num_providers);
-
- /* OSU Providers */
- while (end - pos > 2 && num_providers > 0) {
- num_providers--;
- len = WPA_GET_LE16(pos);
- pos += 2;
- if (len > (unsigned int) (end - pos))
- break;
- hs20_osu_add_prov(wpa_s, bss, osu_ssid,
- osu_ssid_len, osu_ssid2,
- osu_ssid2_len, pos, len);
- pos += len;
- }
-
- if (pos != end) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Ignored %d bytes of "
- "extra data after OSU Providers",
- (int) (end - pos));
- }
-
- prov_anqp = bss->anqp->hs20_osu_providers_nai_list;
- if (!prov_anqp)
- continue;
- wpa_printf(MSG_DEBUG,
- "HS 2.0: Parsing OSU Providers NAI List from "
- MACSTR, MAC2STR(bss->bssid));
- wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers NAI List",
- prov_anqp);
- pos = wpabuf_head(prov_anqp);
- end = pos + wpabuf_len(prov_anqp);
- num_providers = 0;
- while (end - pos > 0) {
- len = *pos++;
- if (end - pos < len) {
- wpa_printf(MSG_DEBUG,
- "HS 2.0: Not enough room for OSU_NAI");
- break;
- }
- if (num_providers >= wpa_s->osu_prov_count) {
- wpa_printf(MSG_DEBUG,
- "HS 2.0: Ignore unexpected OSU Provider NAI List entries");
- break;
- }
- os_memcpy(wpa_s->osu_prov[num_providers].osu_nai2,
- pos, len);
- pos += len;
- num_providers++;
- }
- }
-
- wpa_s->fetch_osu_icon_in_progress = 1;
- hs20_next_osu_icon(wpa_s);
-}
-
-
-static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *scan_res)
-{
- wpa_printf(MSG_DEBUG, "OSU provisioning fetch scan completed");
- if (!wpa_s->fetch_osu_waiting_scan) {
- wpa_printf(MSG_DEBUG, "OSU fetch have been canceled");
- return;
- }
- wpa_s->network_select = 0;
- wpa_s->fetch_all_anqp = 1;
- wpa_s->fetch_osu_info = 1;
- wpa_s->fetch_osu_icon_in_progress = 0;
-
- interworking_start_fetch_anqp(wpa_s);
-}
-
-
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
-{
- if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
- "interface disabled");
- return -1;
- }
-
- if (wpa_s->scanning) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
- "scanning");
- return -1;
- }
-
- if (wpa_s->conf->osu_dir == NULL) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
- "osu_dir not configured");
- return -1;
- }
-
- if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
- "fetch in progress (%d, %d)",
- wpa_s->fetch_anqp_in_progress,
- wpa_s->network_select);
- return -1;
- }
-
- wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
- wpa_s->num_osu_scans = 0;
- wpa_s->num_prov_found = 0;
- if (skip_scan) {
- wpa_s->network_select = 0;
- wpa_s->fetch_all_anqp = 1;
- wpa_s->fetch_osu_info = 1;
- wpa_s->fetch_osu_icon_in_progress = 0;
-
- interworking_start_fetch_anqp(wpa_s);
- } else {
- hs20_start_osu_scan(wpa_s);
- }
-
- return 0;
-}
-
-
-void hs20_start_osu_scan(struct wpa_supplicant *wpa_s)
-{
- wpa_s->fetch_osu_waiting_scan = 1;
- wpa_s->num_osu_scans++;
- wpa_s->scan_req = MANUAL_SCAN_REQ;
- wpa_s->scan_res_handler = hs20_osu_scan_res_handler;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
-}
-
-
-void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s)
-{
- wpa_printf(MSG_DEBUG, "Cancel OSU fetch");
- interworking_stop_fetch_anqp(wpa_s);
- wpa_s->fetch_osu_waiting_scan = 0;
- wpa_s->network_select = 0;
- wpa_s->fetch_osu_info = 0;
- wpa_s->fetch_osu_icon_in_progress = 0;
-}
-
-
-void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s)
-{
- hs20_osu_icon_fetch_result(wpa_s, -1);
- eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
- eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL);
-}
-
-
-void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
- const char *url, u8 osu_method)
-{
- if (url)
- wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION "%u %s",
- osu_method, url);
- else
- wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION);
- wpas_notify_hs20_rx_subscription_remediation(wpa_s, url, osu_method);
-}
-
-
void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
u16 reauth_delay, const char *url)
{
@@ -1355,18 +407,3 @@
wpas_notify_hs20_t_c_acceptance(wpa_s, url);
}
-
-
-void hs20_init(struct wpa_supplicant *wpa_s)
-{
- dl_list_init(&wpa_s->icon_head);
-}
-
-
-void hs20_deinit(struct wpa_supplicant *wpa_s)
-{
- eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
- hs20_free_osu_prov(wpa_s);
- if (wpa_s->icon_head.next)
- hs20_del_icon(wpa_s, NULL, NULL);
-}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 2d478f4..3ff766e 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -15,7 +15,7 @@
const struct wpa_ssid *ssid);
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
- const u8 *payload, size_t payload_len, int inmem);
+ const u8 *payload, size_t payload_len);
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
@@ -26,27 +26,10 @@
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
-void hs20_notify_parse_done(struct wpa_supplicant *wpa_s);
-void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
- const char *url, u8 osu_method);
void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
u16 reauth_delay, const char *url);
void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url);
-void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
-void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
-void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s);
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan);
-void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s);
-void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s);
-void hs20_start_osu_scan(struct wpa_supplicant *wpa_s);
-void hs20_init(struct wpa_supplicant *wpa_s);
-void hs20_deinit(struct wpa_supplicant *wpa_s);
-int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *file_name, size_t offset, size_t size,
- char *reply, size_t buf_len);
-int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *file_name);
#endif /* HS20_SUPPLICANT_H */
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 25039a0..06228d0 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -150,6 +150,12 @@
{
struct ibss_rsn_peer *peer = ctx;
+ if (key_flag & KEY_FLAG_NEXT) {
+ wpa_printf(MSG_DEBUG,
+ "SUPP: Ignore set_key with KEY_FLAG_NEXT");
+ return 0;
+ }
+
wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
"set_tx=%d)",
__func__, alg, MAC2STR(addr), key_idx, set_tx);
@@ -320,6 +326,12 @@
struct ibss_rsn *ibss_rsn = ctx;
u8 seq[6];
+ if (key_flag & KEY_FLAG_NEXT) {
+ wpa_printf(MSG_DEBUG,
+ "AUTH: Ignore set_key with KEY_FLAG_NEXT");
+ return 0;
+ }
+
os_memset(seq, 0, sizeof(seq));
if (addr) {
@@ -485,7 +497,7 @@
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
"\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0,
- NULL) != WPA_IE_OK) {
+ NULL, false) != WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 651907b..bc26006 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -303,10 +303,6 @@
wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
if (all)
wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
- if (all) {
- wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST);
- wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
- }
gas_anqp_set_element_len(extra, len_pos);
}
#endif /* CONFIG_HS20 */
@@ -1502,18 +1498,18 @@
char *anon;
/* Use anonymous NAI in Phase 1 */
pos = os_strchr(cred->username, '@');
- if (pos) {
- size_t buflen = 9 + os_strlen(pos) + 1;
- anon = os_malloc(buflen);
- if (anon == NULL)
- return -1;
- os_snprintf(anon, buflen, "anonymous%s", pos);
- } else if (cred->realm) {
+ if (cred->realm) {
size_t buflen = 10 + os_strlen(cred->realm) + 1;
anon = os_malloc(buflen);
if (anon == NULL)
return -1;
os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
+ } else if (pos) {
+ size_t buflen = 9 + os_strlen(pos) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ return -1;
+ os_snprintf(anon, buflen, "anonymous%s", pos);
} else {
anon = os_strdup("anonymous");
if (anon == NULL)
@@ -2698,23 +2694,14 @@
int found = 0;
wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
- "fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
- wpa_s->fetch_anqp_in_progress,
- wpa_s->fetch_osu_icon_in_progress);
+ "fetch_anqp_in_progress=%d",
+ wpa_s->fetch_anqp_in_progress);
if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress) {
wpa_printf(MSG_DEBUG, "Interworking: Stop next-ANQP-fetch");
return;
}
-#ifdef CONFIG_HS20
- if (wpa_s->fetch_osu_icon_in_progress) {
- wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
- hs20_next_osu_icon(wpa_s);
- return;
- }
-#endif /* CONFIG_HS20 */
-
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!(bss->caps & IEEE80211_CAP_ESS))
continue;
@@ -2747,20 +2734,6 @@
}
if (found == 0) {
-#ifdef CONFIG_HS20
- if (wpa_s->fetch_osu_info) {
- if (wpa_s->num_prov_found == 0 &&
- wpa_s->fetch_osu_waiting_scan &&
- wpa_s->num_osu_scans < 3) {
- wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again");
- hs20_start_osu_scan(wpa_s);
- return;
- }
- wpa_printf(MSG_DEBUG, "Interworking: Next icon");
- hs20_osu_icon_fetch(wpa_s);
- return;
- }
-#endif /* CONFIG_HS20 */
wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
wpa_s->fetch_anqp_in_progress = 0;
if (wpa_s->network_select)
@@ -2793,7 +2766,6 @@
wpa_s->network_select = 0;
wpa_s->fetch_all_anqp = 1;
- wpa_s->fetch_osu_info = 0;
interworking_start_fetch_anqp(wpa_s);
@@ -3141,10 +3113,6 @@
" dialog_token=%u result=%d status_code=%u",
MAC2STR(dst), dialog_token, result, status_code);
if (result != GAS_QUERY_SUCCESS) {
-#ifdef CONFIG_HS20
- if (wpa_s->fetch_osu_icon_in_progress)
- hs20_icon_fetch_failed(wpa_s);
-#endif /* CONFIG_HS20 */
anqp_result = "FAILURE";
goto out;
}
@@ -3154,10 +3122,6 @@
pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
wpa_msg(wpa_s, MSG_DEBUG,
"ANQP: Unexpected Advertisement Protocol in response");
-#ifdef CONFIG_HS20
- if (wpa_s->fetch_osu_icon_in_progress)
- hs20_icon_fetch_failed(wpa_s);
-#endif /* CONFIG_HS20 */
anqp_result = "INVALID_FRAME";
goto out;
}
@@ -3208,9 +3172,6 @@
out_parse_done:
if (bss)
wpas_notify_bss_anqp_changed(wpa_s, bss->id);
-#ifdef CONFIG_HS20
- hs20_notify_parse_done(wpa_s);
-#endif /* CONFIG_HS20 */
out:
wpas_notify_anqp_query_done(wpa_s, dst, anqp_result, bss ? bss->anqp : NULL);
}
@@ -3233,7 +3194,6 @@
wpa_s->auto_network_select = 0;
wpa_s->auto_select = !!auto_select;
wpa_s->fetch_all_anqp = 0;
- wpa_s->fetch_osu_info = 0;
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Start scan for network selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c
index 577c8ac..946d62f 100644
--- a/wpa_supplicant/nan_usd.c
+++ b/wpa_supplicant/nan_usd.c
@@ -369,7 +369,7 @@
return -1;
if (p2p) {
- elems = wpas_p2p_usd_elems(wpa_s);
+ elems = wpas_p2p_usd_elems(wpa_s, service_name);
addr = wpa_s->global->p2p_dev_addr;
} else {
addr = wpa_s->own_addr;
@@ -417,6 +417,16 @@
}
+int wpas_nan_usd_unpause_publish(struct wpa_supplicant *wpa_s, int publish_id,
+ u8 peer_instance_id, const u8 *peer_addr)
+{
+ if (!wpa_s->nan_de)
+ return -1;
+ return nan_de_unpause_publish(wpa_s->nan_de, publish_id,
+ peer_instance_id, peer_addr);
+}
+
+
int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s,
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
@@ -431,7 +441,7 @@
return -1;
if (p2p) {
- elems = wpas_p2p_usd_elems(wpa_s);
+ elems = wpas_p2p_usd_elems(wpa_s, service_name);
addr = wpa_s->global->p2p_dev_addr;
} else {
addr = wpa_s->own_addr;
diff --git a/wpa_supplicant/nan_usd.h b/wpa_supplicant/nan_usd.h
index 59c0989..6a43fb2 100644
--- a/wpa_supplicant/nan_usd.h
+++ b/wpa_supplicant/nan_usd.h
@@ -26,6 +26,8 @@
void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id);
int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id,
const struct wpabuf *ssi);
+int wpas_nan_usd_unpause_publish(struct wpa_supplicant *wpa_s, int publish_id,
+ u8 peer_instance_id, const u8 *peer_addr);
int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s,
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index ea6fc69..b5d4c21 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -931,10 +931,12 @@
wpas_dbus_signal_p2p_bootstrap_req(wpa_s, src, bootstrap_method);
}
-void wpas_notify_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
- const u8 *src, int status)
+void wpas_notify_p2p_bootstrap_rsp(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status,
+ u16 bootstrap_method)
{
- wpas_dbus_signal_p2p_bootstrap_completed(wpa_s, src, status);
+ wpas_dbus_signal_p2p_bootstrap_rsp(wpa_s, src, status,
+ bootstrap_method);
}
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 5775e37..dc8ceaf 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -168,8 +168,9 @@
const u8 *bssid, int id, int op_freq);
void wpas_notify_p2p_bootstrap_req(struct wpa_supplicant *wpa_s,
const u8 *src, u16 bootstrap_method);
-void wpas_notify_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
- const u8 *src, int status);
+void wpas_notify_p2p_bootstrap_rsp(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status,
+ u16 bootstrap_method);
void wpas_notify_mesh_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 0c88e17..f924dde 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -156,7 +156,8 @@
static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
enum wpa_driver_if_type type);
static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
- int already_deleted);
+ int already_deleted,
+ const char *reason);
static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
struct wpa_used_freq_data *freqs,
unsigned int num);
@@ -1016,7 +1017,7 @@
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
"timeout");
wpa_s->p2p_in_provisioning = 0;
- wpas_p2p_group_formation_failed(wpa_s, 1);
+ wpas_p2p_group_formation_failed(wpa_s, 1, reason);
}
wpa_s->p2p_in_invitation = 0;
@@ -1182,7 +1183,7 @@
static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- const u8 *go_dev_addr)
+ const u8 *go_dev_addr, int dik_id)
{
struct wpa_ssid *s;
int changed = 0;
@@ -1195,6 +1196,9 @@
s->ssid_len == ssid->ssid_len &&
os_memcmp(ssid->ssid, s->ssid, ssid->ssid_len) == 0)
break;
+
+ if (dik_id && s->go_dik_id == dik_id)
+ break;
}
if (s) {
@@ -1238,6 +1242,7 @@
s->pmk_valid = ssid->pmk_valid;
s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
s->export_keys = 1;
+ s->go_dik_id = dik_id;
if (ssid->sae_password) {
os_free(s->sae_password);
@@ -1276,8 +1281,43 @@
}
+static void wpas_p2p2_add_group_client_dik_id(struct wpa_ssid *s, int dik_id)
+{
+ size_t i;
+ bool found = false;
+ size_t num = int_array_len(s->p2p2_client_list);
+
+ for (i = 0; i < num; i++) {
+ if (s->p2p2_client_list[i] != dik_id)
+ continue;
+
+ if (i == num - 1)
+ return; /* already the most recent entry */
+
+ /* Move the entry to mark it most recent */
+ os_memmove(s->p2p2_client_list + i,
+ s->p2p2_client_list + i + 1,
+ (num - i - 1) * sizeof(int));
+ s->p2p2_client_list[num - 1] = dik_id;
+ found = true;
+ break;
+ }
+
+ if (!found && num < P2P_MAX_STORED_CLIENTS) {
+ int_array_add_unique(&s->p2p2_client_list, dik_id);
+ } else if (!found && s->p2p2_client_list) {
+ /* Not enough room for an additional entry - drop the oldest
+ * entry
+ */
+ os_memmove(s->p2p2_client_list, s->p2p2_client_list + 1,
+ (num - 1) * sizeof(int));
+ s->p2p2_client_list[num - 1] = dik_id;
+ }
+}
+
+
static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
- const u8 *addr)
+ const u8 *addr, int dik_id)
{
struct wpa_ssid *ssid, *s;
u8 *n;
@@ -1302,6 +1342,11 @@
if (s == NULL)
return;
+ if (dik_id) {
+ wpas_p2p2_add_group_client_dik_id(s, dik_id);
+ goto done;
+ }
+
for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
if (!ether_addr_equal(s->p2p_client_list + i * 2 * ETH_ALEN,
addr))
@@ -1349,6 +1394,7 @@
0xff, ETH_ALEN);
}
+done:
if (p2p_wpa_s->conf->update_config &&
wpa_config_write(p2p_wpa_s->confname, p2p_wpa_s->conf))
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
@@ -1416,10 +1462,10 @@
}
-static void wpas_p2p_store_identity(struct wpa_supplicant *wpa_s, u8 cipher,
- const u8 *dik_data, size_t dik_len,
- const u8 *pmk, size_t pmk_len,
- const u8 *pmkid)
+static int wpas_p2p_store_identity(struct wpa_supplicant *wpa_s, u8 cipher,
+ const u8 *dik_data, size_t dik_len,
+ const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid)
{
struct wpa_dev_ik *ik;
@@ -1436,7 +1482,7 @@
wpa_printf(MSG_DEBUG, "P2P: Create a new device identity entry");
ik = wpa_config_add_identity(wpa_s->conf);
if (!ik)
- return;
+ return 0;
ik->dik = wpabuf_alloc_copy(dik_data, dik_len);
if (!ik->dik)
@@ -1451,17 +1497,20 @@
ik->dik_cipher = cipher;
if (wpa_s->conf->update_config &&
- wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_config_write(wpa_s->confname, wpa_s->conf)) {
wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
- return;
+ return 0;
+ }
+ return ik->id;
fail:
wpa_config_remove_identity(wpa_s->conf, ik->id);
+ return 0;
}
-static void wpas_p2p_store_go_identity(struct wpa_supplicant *wpa_s,
- const u8 *go_dev_addr, const u8 *bssid)
+static int wpas_p2p_store_go_identity(struct wpa_supplicant *wpa_s,
+ const u8 *go_dev_addr, const u8 *bssid)
{
int ret;
u8 cipher;
@@ -1471,12 +1520,12 @@
struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s;
if (!wpa_s->p2p2)
- return;
+ return 0;
ret = p2p_get_dev_identity_key(p2p_wpa_s->global->p2p, go_dev_addr,
&dik_data, &dik_len, &cipher);
if (ret)
- return;
+ return 0;
ret = p2p_get_interface_addr(p2p_wpa_s->global->p2p, go_dev_addr,
iface_addr);
@@ -1489,19 +1538,20 @@
ret = wpa_sm_pmksa_get_pmk(wpa_s->wpa, iface_addr, &pmk, &pmk_len,
&pmkid);
if (ret)
- return;
+ return 0;
wpa_printf(MSG_DEBUG,
"P2P: Storing Device identity of GO (Interface Addr " MACSTR
")",
MAC2STR(iface_addr));
- wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len, pmk,
- pmk_len, pmkid);
+ return wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len,
+ pmk, pmk_len, pmkid);
}
static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
- int success, int already_deleted)
+ int already_deleted,
+ const char *failure_reason)
{
struct wpa_ssid *ssid;
int client;
@@ -1518,7 +1568,7 @@
if (wpa_s->p2p_go_group_formation_completed) {
wpa_s->global->p2p_group_formation = NULL;
wpa_s->p2p_in_provisioning = 0;
- } else if (wpa_s->p2p_in_provisioning && !success) {
+ } else if (wpa_s->p2p_in_provisioning && failure_reason) {
wpa_msg(wpa_s, MSG_DEBUG,
"P2P: Stop provisioning state due to failure");
wpa_s->p2p_in_provisioning = 0;
@@ -1527,10 +1577,10 @@
wpa_s->p2p_retry_limit = 0;
wpa_s->group_formation_reported = 1;
- if (!success) {
+ if (failure_reason) {
wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
- wpas_notify_p2p_group_formation_failure(wpa_s, "");
+ wpas_notify_p2p_group_formation_failure(wpa_s, failure_reason);
if (already_deleted)
return;
wpas_p2p_group_delete(wpa_s,
@@ -1589,7 +1639,7 @@
if (persistent)
wpas_p2p_store_persistent_group(wpa_s->p2pdev,
- ssid, go_dev_addr);
+ ssid, go_dev_addr, 0);
else {
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
@@ -2211,7 +2261,8 @@
wpa_auth_pmksa_add_sae(hapd->wpa_auth,
params->peer_device_addr,
params->pmk, params->pmk_len,
- params->pmkid, WPA_KEY_MGMT_SAE);
+ params->pmkid, WPA_KEY_MGMT_SAE,
+ false);
hostapd_add_pmkid(hapd, params->peer_device_addr,
params->pmk, params->pmk_len,
params->pmkid, WPA_KEY_MGMT_SAE);
@@ -2255,7 +2306,7 @@
if (params->persistent_group) {
wpas_p2p_store_persistent_group(
wpa_s->p2pdev, ssid,
- wpa_s->global->p2p_dev_addr);
+ wpa_s->global->p2p_dev_addr, 0);
wpas_p2p_add_psk_list(wpa_s, ssid);
}
@@ -2290,7 +2341,7 @@
}
if (params->p2p2) {
- wpas_group_formation_completed(wpa_s, 1, 0);
+ wpas_group_formation_completed(wpa_s, 0, NULL);
wpa_printf(MSG_DEBUG,
"P2P2: Group formation completed - first connection in progress");
goto out;
@@ -2771,18 +2822,25 @@
#endif /* CONFIG_PASN */
wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
- wpas_p2p_group_formation_failed(wpa_s, 0);
+ wpas_p2p_group_formation_failed(wpa_s, 0, "Group formation timed out");
}
static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
- int already_deleted)
+ int already_deleted,
+ const char *reason)
{
+ /* reason == NULL would indicate success in
+ * wpas_group_formation_completed(), so make sure that is not the case
+ * here. */
+ if (!reason)
+ reason = "";
+
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->p2pdev, NULL);
if (wpa_s->global->p2p)
p2p_group_formation_failed(wpa_s->global->p2p);
- wpas_group_formation_completed(wpa_s, 0, already_deleted);
+ wpas_group_formation_completed(wpa_s, already_deleted, reason);
}
@@ -2859,7 +2917,8 @@
wpa_auth_pmksa_add_sae(hapd->wpa_auth,
params->peer_device_addr,
params->pmk, params->pmk_len,
- params->pmkid, WPA_KEY_MGMT_SAE);
+ params->pmkid, WPA_KEY_MGMT_SAE,
+ false);
hostapd_add_pmkid(hapd, params->peer_device_addr,
params->pmk, params->pmk_len,
params->pmkid, WPA_KEY_MGMT_SAE);
@@ -2940,7 +2999,8 @@
wpas_p2p_remove_pending_group_interface(wpa_s);
eloop_cancel_timeout(wpas_p2p_long_listen_timeout,
wpa_s, NULL);
- wpas_p2p_group_formation_failed(wpa_s, 1);
+ wpas_p2p_group_formation_failed(wpa_s, 1,
+ "Could not initialize group interface");
return;
}
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
@@ -3164,7 +3224,7 @@
unsigned int duration;
if (deinit) {
- if (work->started) {
+ if (work->started && !wpa_s->p2p_removing_listen_work) {
wpa_s->p2p_listen_work = NULL;
wpas_stop_listen(wpa_s);
}
@@ -3179,6 +3239,7 @@
if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
"report received Probe Request frames");
+ p2p_listen_failed(wpa_s->global->p2p, lwork->freq);
wpas_p2p_listen_work_done(wpa_s);
return;
}
@@ -3199,6 +3260,7 @@
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
"to remain on channel (%u MHz) for Listen "
"state", lwork->freq);
+ p2p_listen_failed(wpa_s->global->p2p, lwork->freq);
wpas_p2p_listen_work_done(wpa_s);
wpa_s->pending_listen_freq = 0;
return;
@@ -3651,7 +3713,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)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
@@ -3721,7 +3784,41 @@
break;
}
- if (!s) {
+ if (p2p2) {
+ int dik_id;
+ u8 go_ssid[SSID_MAX_LEN];
+
+ dik_id = p2p_get_dik_id(wpa_s->global->p2p, sa);
+ s = wpa_config_get_network_with_dik_id(wpa_s->conf, dik_id);
+ if (!s) {
+ wpa_printf(MSG_DEBUG, "P2P2: Invitation from " MACSTR
+ " requested reinvocation of an unknown group",
+ MAC2STR(sa));
+ return P2P_SC_FAIL_UNKNOWN_GROUP;
+ }
+ os_free(s->ssid);
+ if (s->mode == WPAS_MODE_P2P_GO) {
+ p2p_build_ssid(wpa_s->global->p2p, go_ssid,
+ &s->ssid_len);
+ s->ssid = os_memdup(go_ssid, s->ssid_len);
+ if (!s->ssid) {
+ s->ssid_len = 0;
+ return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+ }
+ wpa_printf(MSG_DEBUG,
+ "P2P: New random SSID for the group: %s",
+ wpa_ssid_txt(s->ssid, s->ssid_len));
+ *new_ssid = s->ssid;
+ *new_ssid_len = s->ssid_len;
+ } else {
+ s->ssid_len = ssid_len;
+ s->ssid = os_memdup(ssid, ssid_len);
+ if (!s->ssid) {
+ s->ssid_len = 0;
+ return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
+ }
+ }
+ } else if (!s) {
wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR
" requested reinvocation of an unknown group",
MAC2STR(sa));
@@ -3828,19 +3925,25 @@
" was accepted; op_freq=%d MHz, SSID=%s",
MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
if (s) {
+ const char *ssid_txt;
+
+ ssid_txt = wpa_ssid_txt(s->ssid, s->ssid_len);
int go = s->mode == WPAS_MODE_P2P_GO;
if (go) {
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_INVITATION_ACCEPTED
"sa=" MACSTR
- " persistent=%d freq=%d",
- MAC2STR(sa), s->id, op_freq);
+ " persistent=%d freq=%d ssid=\"%s\" go_dev_addr="
+ MACSTR, MAC2STR(sa), s->id,
+ op_freq, ssid_txt,
+ MAC2STR(go_dev_addr));
} else {
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_INVITATION_ACCEPTED
"sa=" MACSTR
- " persistent=%d",
- MAC2STR(sa), s->id);
+ " persistent=%d ssid=\"%s\" go_dev_addr=" MACSTR,
+ MAC2STR(sa), s->id, ssid_txt,
+ MAC2STR(go_dev_addr));
}
wpas_p2p_group_add_persistent(
wpa_s, s, go, 0, op_freq, 0,
@@ -3966,11 +4069,73 @@
}
-static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
+static void wpas_msg_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+ int status, const u8 *new_ssid,
+ size_t new_ssid_len, const u8 *bssid,
+ const u8 *go_dev_addr)
+{
+ int res;
+ char buf[500];
+ char *pos, *end;
+ const char *ssid_txt = NULL;
+
+ pos = buf;
+ end = buf + sizeof(buf);
+
+ if (go_dev_addr && new_ssid && new_ssid_len) {
+ ssid_txt = wpa_ssid_txt(new_ssid, new_ssid_len);
+ } else if (go_dev_addr) {
+ struct wpa_ssid *ssid;
+
+ ssid = wpa_config_get_network(wpa_s->conf,
+ wpa_s->pending_invite_ssid_id);
+ if (ssid)
+ ssid_txt = wpa_ssid_txt(ssid->ssid, ssid->ssid_len);
+ }
+
+ res = os_snprintf(pos, end - pos, "status=%d", status);
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+
+ if (bssid) {
+ res = os_snprintf(pos, end - pos, " " MACSTR, MAC2STR(bssid));
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+ }
+
+ if (ssid_txt) {
+ res = os_snprintf(pos, end - pos, " ssid=\"%s\"", ssid_txt);
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+ }
+
+ if (go_dev_addr) {
+ res = os_snprintf(pos, end - pos, " go_dev_addr=" MACSTR,
+ MAC2STR(go_dev_addr));
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT "%s", buf);
+ return;
+
+fail:
+ wpa_printf(MSG_DEBUG,
+ "P2P: Failed to send P2P-INVITATION-RESULT message");
+}
+
+
+static void wpas_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 *peer, int neg_freq,
int peer_oper_freq, const u8 *pmkid,
- const u8 *pmk, size_t pmk_len)
+ const u8 *pmk, size_t pmk_len,
+ const u8 *go_dev_addr)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
@@ -3983,14 +4148,8 @@
}
#endif /* CONFIG_PASN */
- if (bssid) {
- wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
- "status=%d " MACSTR,
- status, MAC2STR(bssid));
- } else {
- wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
- "status=%d ", status);
- }
+ wpas_msg_p2p_invitation_result(wpa_s, status, new_ssid, new_ssid_len,
+ bssid, go_dev_addr);
wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
@@ -4053,6 +4212,16 @@
return;
}
+ if (new_ssid && new_ssid_len) {
+ os_free(ssid->ssid);
+ ssid->ssid = os_memdup(new_ssid, new_ssid_len);
+ if (!ssid->ssid) {
+ ssid->ssid_len = 0;
+ return;
+ }
+ ssid->ssid_len = new_ssid_len;
+ }
+
/*
* The peer could have missed our ctrl::ack frame for Invitation
* Response and continue retransmitting the frame. To reduce the
@@ -5313,19 +5482,27 @@
struct wpa_supplicant *wpa_s = eloop_ctx;
wpa_printf(MSG_DEBUG, "P2P2: Send bootstrapping comeback PD Request");
- wpas_p2p_connect(wpa_s, wpa_s->p2p_bootstrap_dev_addr, wpa_s->p2p_pin,
- wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
- 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
- wpa_s->p2p_go_vht_center_freq2,
- wpa_s->p2p_persistent_id,
- wpa_s->p2p_pd_before_go_neg,
- wpa_s->p2p_go_ht40,
- wpa_s->p2p_go_vht,
- wpa_s->p2p_go_max_oper_chwidth,
- wpa_s->p2p_go_he,
- wpa_s->p2p_go_edmg,
- NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p),
- wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL, false);
+
+ if (wpa_s->p2p_pd_before_go_neg) {
+ wpas_p2p_connect(wpa_s, wpa_s->p2p_bootstrap_dev_addr,
+ wpa_s->p2p_pin, wpa_s->p2p_wps_method,
+ wpa_s->p2p_persistent_group, 0, 0, 0,
+ wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+ wpa_s->p2p_go_vht_center_freq2,
+ wpa_s->p2p_persistent_id, 1,
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
+ NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p),
+ wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL,
+ false);
+ } else {
+ p2p_prov_disc_req(wpa_s->global->p2p,
+ wpa_s->p2p_bootstrap_dev_addr, NULL,
+ 0, 0, 0, 1);
+ }
}
@@ -5356,12 +5533,13 @@
}
-static void wpas_bootstrap_completed(void *ctx, const u8 *addr,
- enum p2p_status_code status, int freq)
+static void wpas_bootstrap_rsp_rx(void *ctx, const u8 *addr,
+ enum p2p_status_code status, int freq,
+ u16 bootstrap_method)
{
struct wpa_supplicant *wpa_s = ctx;
- wpas_notify_p2p_bootstrap_completed(wpa_s, addr, status);
+ wpas_notify_p2p_bootstrap_rsp(wpa_s, addr, status, bootstrap_method);
if (status) {
wpa_msg_global(wpa_s, MSG_INFO,
@@ -5375,13 +5553,14 @@
MAC2STR(addr), status);
#ifdef CONFIG_PASN
- wpas_p2p_initiate_pasn_auth(wpa_s, addr, freq);
+ if (wpa_s->p2p_pd_before_go_neg)
+ wpas_p2p_initiate_pasn_auth(wpa_s, addr, freq);
#endif /* CONFIG_PASN */
}
-static void wpas_validate_dira(void *ctx, const u8 *peer_addr,
- const u8 *dira, size_t dira_len)
+static int wpas_validate_dira(void *ctx, const u8 *peer_addr,
+ const u8 *dira_nonce, const u8 *dira_tag)
{
struct wpa_supplicant *wpa_s = ctx;
int ret;
@@ -5391,24 +5570,11 @@
size_t len[3];
const char *label = "DIR";
- if (dira_len < 1 || dira[0] != DIRA_CIPHER_VERSION_128) {
- wpa_printf(MSG_ERROR,
- "P2P2: Unsupported DIRA cipher version %d", dira[0]);
- return;
- }
-
- if (dira_len < 1 + DEVICE_IDENTITY_NONCE_LEN + DEVICE_IDENTITY_TAG_LEN)
- {
- wpa_printf(MSG_INFO, "P2P2: Truncated DIRA (length %zu)",
- dira_len);
- return;
- }
-
addr[0] = (const u8 *) label;
len[0] = DIR_STR_LEN;
addr[1] = peer_addr;
len[1] = ETH_ALEN;
- addr[2] = &dira[1];
+ addr[2] = dira_nonce;
len[2] = DEVICE_IDENTITY_NONCE_LEN;
for (ik = wpa_s->conf->identity; ik; ik = ik->next) {
@@ -5422,18 +5588,17 @@
if (ret < 0) {
wpa_printf(MSG_ERROR,
"P2P2: Failed to derive DIRA Tag");
- return;
+ return 0;
}
- if (os_memcmp(tag, &dira[1 + DEVICE_IDENTITY_NONCE_LEN],
- DEVICE_IDENTITY_TAG_LEN) == 0) {
+ if (os_memcmp(tag, dira_tag, DEVICE_IDENTITY_TAG_LEN) == 0) {
wpa_printf(MSG_DEBUG, "P2P2: DIRA Tag matched");
break;
}
}
if (!ik)
- return;
+ return 0;
#ifdef CONFIG_PASN
p2p_pasn_pmksa_set_pmk(wpa_s->global->p2p, wpa_s->global->p2p_dev_addr,
@@ -5441,6 +5606,8 @@
wpabuf_head(ik->pmk), wpabuf_len(ik->pmk),
wpabuf_head(ik->pmkid));
#endif /* CONFIG_PASN */
+
+ return ik->id;
}
@@ -5527,6 +5694,16 @@
return p2p_parse_data_element(p2p, data, len);
}
+
+static int wpas_p2p_pasn_validate_pmkid(void *ctx, const u8 *addr,
+ const u8 *rsn_pmkid)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return p2p_pasn_validate_and_update_pmkid(wpa_s->global->p2p, addr,
+ rsn_pmkid);
+}
+
#endif /* CONFIG_PASN */
@@ -5657,12 +5834,13 @@
p2p.p2p_dfs_chan_enable = wpa_s->conf->p2p_dfs_chan_enable;
p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback;
p2p.bootstrap_req_rx = wpas_bootstrap_req_rx;
- p2p.bootstrap_completed = wpas_bootstrap_completed;
+ p2p.bootstrap_rsp_rx = wpas_bootstrap_rsp_rx;
p2p.validate_dira = wpas_validate_dira;
#ifdef CONFIG_PASN
p2p.pasn_send_mgmt = wpas_p2p_pasn_send_mgmt;
p2p.prepare_data_element = wpas_p2p_prepare_data_element;
p2p.parse_data_element = wpas_p2p_parse_data_element;
+ p2p.pasn_validate_pmkid = wpas_p2p_pasn_validate_pmkid;
#endif /* CONFIG_PASN */
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
@@ -7036,6 +7214,12 @@
wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
}
+
+#ifdef CONFIG_PASN
+ if (wpa_s->p2p2 && !wpa_s->p2p_pd_before_go_neg)
+ wpas_p2p_initiate_pasn_auth(wpa_s, peer_addr, force_freq);
+#endif /* CONFIG_PASN */
+
return ret;
}
@@ -8302,7 +8486,7 @@
}
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
- wpas_group_formation_completed(wpa_s, 1, 0);
+ wpas_group_formation_completed(wpa_s, 0, NULL);
}
@@ -8351,7 +8535,7 @@
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- const char *config_method,
+ const char *config_method, u16 bootstrap,
enum wpas_p2p_prov_disc_use use,
struct p2ps_provision *p2ps_prov)
{
@@ -8373,6 +8557,12 @@
p2ps_prov->status, p2ps_prov->info);
config_methods = 0;
+ } else if (bootstrap) {
+ wpa_s->p2p2 = true;
+ config_methods = 0;
+ wpa_s->p2p_bootstrap = bootstrap;
+ p2p_set_req_bootstrap_method(wpa_s->global->p2p, peer_addr,
+ bootstrap);
} else if (os_strncmp(config_method, "display", 7) == 0)
config_methods = WPS_CONFIG_DISPLAY;
else if (os_strncmp(config_method, "keypad", 6) == 0)
@@ -8702,6 +8892,22 @@
else
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ if (wpa_s->global->p2p && p2p2 && !ssid && peer_addr) {
+ int dik_id;
+
+ dik_id = p2p_get_dik_id(wpa_s->global->p2p, peer_addr);
+ ssid = wpa_config_get_network_with_dik_id(wpa_s->conf, dik_id);
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Could not find SSID for P2P2 peer "
+ MACSTR, MAC2STR(peer_addr));
+ return -1;
+ }
+ }
+
+ if (!ssid)
+ return -1;
+
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
wpa_s->p2p_go_vht = !!vht;
@@ -8766,7 +8972,8 @@
#ifdef CONFIG_PASN
if (p2p2) {
- if (wpas_p2p_initiate_pasn_verify(wpa_s, peer_addr, role, bssid,
+ if (peer_addr &&
+ wpas_p2p_initiate_pasn_verify(wpa_s, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len,
force_freq, go_dev_addr,
pref_freq) < 0) {
@@ -8873,7 +9080,7 @@
struct wpa_ssid *ssid = wpa_s->current_ssid;
const u8 *bssid;
u8 go_dev_addr[ETH_ALEN];
- int persistent;
+ int persistent, dik_id;
int freq;
u8 ip[3 * 4], *ip_ptr = NULL;
char ip_addr[100];
@@ -8938,9 +9145,9 @@
ip_addr);
if (persistent) {
+ dik_id = wpas_p2p_store_go_identity(wpa_s, go_dev_addr, bssid);
wpas_p2p_store_persistent_group(wpa_s->p2pdev,
- ssid, go_dev_addr);
- wpas_p2p_store_go_identity(wpa_s, go_dev_addr, bssid);
+ ssid, go_dev_addr, dik_id);
}
wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip_ptr);
@@ -9407,7 +9614,7 @@
"session overlap");
if (wpa_s != wpa_s->p2pdev)
wpa_msg_ctrl(wpa_s->p2pdev, MSG_INFO, WPS_EVENT_OVERLAP);
- wpas_p2p_group_formation_failed(wpa_s, 0);
+ wpas_p2p_group_formation_failed(wpa_s, 0, "WPS PBC session overlap");
return 1;
}
@@ -9516,7 +9723,8 @@
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->p2pdev, NULL);
if (wpa_s->p2p_in_provisioning) {
- wpas_group_formation_completed(wpa_s, 0, 0);
+ wpas_group_formation_completed(wpa_s, 0,
+ "Canceled");
break;
}
wpas_p2p_group_delete(wpa_s,
@@ -9526,7 +9734,7 @@
wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling",
wpa_s->ifname);
found = 1;
- wpas_p2p_group_formation_failed(wpa_s, 0);
+ wpas_p2p_group_formation_failed(wpa_s, 0, "Canceled");
break;
}
}
@@ -9700,8 +9908,8 @@
}
-static void wpas_p2p_store_client_identity(struct wpa_supplicant *wpa_s,
- const u8 *addr)
+static int wpas_p2p_store_client_identity(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
{
u8 cipher;
size_t dik_len;
@@ -9713,15 +9921,15 @@
struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s;
if (!wpa_s->p2p2 || !wpa_s->ap_iface)
- return;
+ return 0;
hapd = wpa_s->ap_iface->bss[0];
if (!hapd)
- return;
+ return 0;
if (p2p_get_dev_identity_key(p2p_wpa_s->global->p2p, addr,
&dik_data, &dik_len, &cipher))
- return;
+ return 0;
wpa_printf(MSG_DEBUG, "P2P: Fetch PMK from client (Device Addr " MACSTR
")", MAC2STR(addr));
@@ -9729,26 +9937,28 @@
&pmkid)) {
if (p2p_get_interface_addr(p2p_wpa_s->global->p2p, addr,
iface_addr))
- return;
+ return 0;
wpa_printf(MSG_DEBUG,
"P2P: Fetch PMK from client (Interface Addr " MACSTR
")", MAC2STR(iface_addr));
if (wpa_auth_pmksa_get_pmk(hapd->wpa_auth, iface_addr, &pmk,
&pmk_len, &pmkid))
- return;
+ return 0;
}
wpa_printf(MSG_DEBUG,
"P2P: Storing device identity of client (Device Addr "
MACSTR ")", MAC2STR(addr));
- wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len, pmk,
- pmk_len, pmkid);
+ return wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len,
+ pmk, pmk_len, pmkid);
}
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
+ int dik_id;
+
if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->p2pdev, NULL) > 0) {
/*
@@ -9773,7 +9983,7 @@
*/
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, addr);
- wpas_group_formation_completed(wpa_s, 1, 0);
+ wpas_group_formation_completed(wpa_s, 0, NULL);
}
}
if (!wpa_s->p2p_go_group_formation_completed) {
@@ -9788,8 +9998,8 @@
if (addr == NULL)
return;
- wpas_p2p_store_client_identity(wpa_s, addr);
- wpas_p2p_add_persistent_group_client(wpa_s, addr);
+ dik_id = wpas_p2p_store_client_identity(wpa_s, addr);
+ wpas_p2p_add_persistent_group_client(wpa_s, addr, dik_id);
}
@@ -11331,12 +11541,14 @@
}
-struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
+struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s,
+ const char *service_name)
{
struct p2p_data *p2p = wpa_s->global->p2p;
if (wpa_s->global->p2p_disabled || !p2p)
return NULL;
+ p2p_usd_service_hash(p2p, service_name);
return p2p_usd_elems(p2p);
}
@@ -11397,6 +11609,29 @@
#endif /* CONFIG_PASN */
+int wpas_p2p_get_dira(struct wpa_supplicant *wpa_s, char *buf, size_t buf_len)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ if (wpa_s->global->p2p_disabled || !p2p)
+ return 0;
+ return p2p_get_dira_info(p2p, buf, buf_len);
+}
+
+
+int wpas_p2p_validate_dira(struct wpa_supplicant *wpa_s, const u8 *addr,
+ u8 cipher, const u8 *nonce, const u8 *tag)
+{
+ if (cipher != DIRA_CIPHER_VERSION_128) {
+ wpa_printf(MSG_INFO, "P2P2: Unsupported DIRA cipher version %d",
+ cipher);
+ return 0;
+ }
+
+ return wpas_validate_dira(wpa_s, addr, nonce, tag);
+}
+
+
void wpas_p2p_update_dev_addr(struct wpa_supplicant *wpa_s)
{
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 888bce5..c5f2f9c 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -67,7 +67,7 @@
WPAS_P2P_PD_FOR_ASP
};
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- const char *config_method,
+ const char *config_method, u16 bootstrap,
enum wpas_p2p_prov_disc_use use,
struct p2ps_provision *p2ps_prov);
void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
@@ -236,13 +236,17 @@
unsigned int count);
int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s);
-struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s,
+ const char *service_name);
void wpas_p2p_update_dev_addr(struct wpa_supplicant *wpa_s);
int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len,
int freq);
int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk,
size_t *ptk_len);
+int wpas_p2p_get_dira(struct wpa_supplicant *wpa_s, char *buf, size_t buf_len);
+int wpas_p2p_validate_dira(struct wpa_supplicant *wpa_s, const u8 *addr,
+ u8 cipher, const u8 *nonce, const u8 *tag);
#else /* CONFIG_P2P */
@@ -369,7 +373,8 @@
return 0;
}
-static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
+static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s,
+ const char *service_name)
{
return NULL;
}
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index a46fe46..b290e30 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -251,13 +251,13 @@
#endif /* CONFIG_SHA384 */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
- } else if ((sel & WPA_KEY_MGMT_SAE_EXT_KEY) &&
+ } else if ((sel & WPA_KEY_MGMT_SAE_EXT_KEY) && ssid &&
(ieee802_11_rsnx_capab(rsnxe,
WLAN_RSNX_CAPAB_SAE_H2E)) &&
(wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE (ext key)");
- } else if ((sel & WPA_KEY_MGMT_SAE) &&
+ } else if ((sel & WPA_KEY_MGMT_SAE) && ssid &&
(ieee802_11_rsnx_capab(rsnxe,
WLAN_RSNX_CAPAB_SAE_H2E)) &&
(wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
@@ -583,6 +583,10 @@
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
+ if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SPP_AMSDU) &&
+ ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SPP_A_MSDU))
+ capab |= BIT(WLAN_RSNX_CAPAB_SPP_A_MSDU);
+
pasn_set_rsnxe_caps(pasn, capab);
pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
ssid = wpa_config_get_network(wpa_s->conf, awork->network_id);
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
index 658103d..9156dae 100644
--- a/wpa_supplicant/robust_av.c
+++ b/wpa_supplicant/robust_av.c
@@ -541,7 +541,7 @@
if (wpa_s->connection_eht && eht_ie &&
eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN) {
eht = (const struct ieee80211_eht_capabilities *) &eht_ie[3];
- if (eht->mac_cap & EHT_MACCAP_SCS_TRAFFIC_DESC)
+ if (le_to_host16(eht->mac_cap) & EHT_MACCAP_SCS_TRAFFIC_DESC)
allow_scs_traffic_desc = true;
}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 0a0a50f..c6b4242 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -551,6 +551,28 @@
}
+static void sme_add_assoc_req_ie(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *buf)
+{
+ size_t len;
+ u8 *pos, *end;
+
+ if (!buf)
+ return;
+
+ pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
+ end = wpa_s->sme.assoc_req_ie + sizeof(wpa_s->sme.assoc_req_ie);
+ if (pos >= end)
+ return;
+
+ len = wpabuf_len(buf);
+ if (len < (size_t) (end - pos)) {
+ os_memcpy(pos, wpabuf_head(buf), len);
+ wpa_s->sme.assoc_req_ie_len += len;
+ }
+}
+
+
static void sme_send_authentication(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
int start)
@@ -719,21 +741,6 @@
wpas_connect_work_done(wpa_s);
return;
}
-#ifdef CONFIG_HS20
- } else if (wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
- (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
- /* No PMKSA caching, but otherwise similar to RSN/WPA */
- wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
- if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
- wpa_s->sme.assoc_req_ie,
- &wpa_s->sme.assoc_req_ie_len,
- false)) {
- wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
- "key management and encryption suites");
- wpas_connect_work_done(wpa_s);
- return;
- }
-#endif /* CONFIG_HS20 */
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
/*
@@ -758,14 +765,10 @@
#ifdef CONFIG_WPS
} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
struct wpabuf *wps_ie;
+
+ wpa_s->sme.assoc_req_ie_len = 0;
wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
- if (wps_ie && wpabuf_len(wps_ie) <=
- sizeof(wpa_s->sme.assoc_req_ie)) {
- wpa_s->sme.assoc_req_ie_len = wpabuf_len(wps_ie);
- os_memcpy(wpa_s->sme.assoc_req_ie, wpabuf_head(wps_ie),
- wpa_s->sme.assoc_req_ie_len);
- } else
- wpa_s->sme.assoc_req_ie_len = 0;
+ sme_add_assoc_req_ie(wpa_s, wps_ie);
wpabuf_free(wps_ie);
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
#endif /* CONFIG_WPS */
@@ -854,6 +857,8 @@
}
}
+ wpa_s->sme.spp_amsdu = wpa_sm_uses_spp_amsdu(wpa_s->wpa);
+
#ifdef CONFIG_P2P
if (wpa_s->global->p2p) {
u8 *pos;
@@ -870,18 +875,7 @@
#endif /* CONFIG_P2P */
#ifdef CONFIG_FST
- if (wpa_s->fst_ies) {
- int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
-
- if (wpa_s->sme.assoc_req_ie_len + fst_ies_len <=
- sizeof(wpa_s->sme.assoc_req_ie)) {
- os_memcpy(wpa_s->sme.assoc_req_ie +
- wpa_s->sme.assoc_req_ie_len,
- wpabuf_head(wpa_s->fst_ies),
- fst_ies_len);
- wpa_s->sme.assoc_req_ie_len += fst_ies_len;
- }
- }
+ sme_add_assoc_req_ie(wpa_s, wpa_s->fst_ies);
#endif /* CONFIG_FST */
sme_auth_handle_rrm(wpa_s, bss);
@@ -924,15 +918,9 @@
}
#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->rsnxe_override_assoc &&
- wpabuf_len(wpa_s->rsnxe_override_assoc) <=
- sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ if (wpa_s->rsnxe_override_assoc) {
wpa_printf(MSG_DEBUG, "TESTING: RSNXE AssocReq override");
- os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
- wpabuf_head(wpa_s->rsnxe_override_assoc),
- wpabuf_len(wpa_s->rsnxe_override_assoc));
- wpa_s->sme.assoc_req_ie_len +=
- wpabuf_len(wpa_s->rsnxe_override_assoc);
+ sme_add_assoc_req_ie(wpa_s, wpa_s->rsnxe_override_assoc);
} else
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->rsnxe_len > 0 &&
@@ -944,6 +932,22 @@
wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
}
+ if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION &&
+ wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_KNOWN_STA_IDENTIFICATION)) {
+ struct wpabuf *e;
+
+ e = wpa_sm_known_sta_identification(
+ wpa_s->wpa,
+ params.mld ? params.ap_mld_addr : bss->bssid,
+ bss->tsf);
+ if (e) {
+ wpa_printf(MSG_DEBUG,
+ "SME: Add Known STA Identification element");
+ sme_add_assoc_req_ie(wpa_s, e);
+ wpabuf_free(e);
+ }
+ }
+
#ifdef CONFIG_HS20
if (is_hs20_network(wpa_s, ssid, bss)
#ifndef ANDROID /* Android does not use the native HS 2.0 config */
@@ -955,19 +959,11 @@
hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
if (hs20) {
int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
- size_t len;
wpas_hs20_add_indication(hs20, pps_mo_id,
get_hs20_version(bss));
wpas_hs20_add_roam_cons_sel(hs20, ssid);
- len = sizeof(wpa_s->sme.assoc_req_ie) -
- wpa_s->sme.assoc_req_ie_len;
- if (wpabuf_len(hs20) <= len) {
- os_memcpy(wpa_s->sme.assoc_req_ie +
- wpa_s->sme.assoc_req_ie_len,
- wpabuf_head(hs20), wpabuf_len(hs20));
- wpa_s->sme.assoc_req_ie_len += wpabuf_len(hs20);
- }
+ sme_add_assoc_req_ie(wpa_s, hs20);
wpabuf_free(hs20);
}
}
@@ -993,19 +989,7 @@
os_free(wpa_ie);
}
- if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
- struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
- size_t len;
-
- len = sizeof(wpa_s->sme.assoc_req_ie) -
- wpa_s->sme.assoc_req_ie_len;
- if (wpabuf_len(buf) <= len) {
- os_memcpy(wpa_s->sme.assoc_req_ie +
- wpa_s->sme.assoc_req_ie_len,
- wpabuf_head(buf), wpabuf_len(buf));
- wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
- }
- }
+ sme_add_assoc_req_ie(wpa_s, wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]);
#ifdef CONFIG_MBO
mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
@@ -2664,6 +2648,7 @@
#endif /* CONFIG_IEEE80211R */
params.mode = mode;
params.mgmt_frame_protection = wpa_s->sme.mfp;
+ params.spp_amsdu = wpa_s->sme.spp_amsdu;
params.rrm_used = wpa_s->rrm.rrm_used;
if (wpa_s->sme.prev_bssid_set)
params.prev_bssid = wpa_s->sme.prev_bssid;
@@ -2689,10 +2674,6 @@
params.wpa_proto = WPA_PROTO_WPA;
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
elems.wpa_ie_len + 2);
- } else if (elems.osen) {
- params.wpa_proto = WPA_PROTO_OSEN;
- wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.osen - 2,
- elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
if (elems.rsnxe)
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 31d1007..0ae27a7 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -847,7 +847,7 @@
struct wpa_bss *bss = wpa_s->last_scan_res[i];
int res;
- if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) {
+ if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0, false)) {
res = wnm_nei_rep_add_bss(wpa_s, bss, buf, pref--);
if (res == -2)
continue; /* could not build entry for BSS */
@@ -1101,7 +1101,7 @@
/* Apply normal roaming rules if we can stay with the current BSS */
if (current_bss && bss != current_bss &&
wpa_scan_res_match(wpa_s, 0, current_bss, wpa_s->current_ssid,
- 1, 0) &&
+ 1, 0, false) &&
!wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss, bss,
true))
bss = current_bss;
@@ -1700,45 +1700,6 @@
WPA_GET_BE24(pos), pos[3]);
#ifdef CONFIG_HS20
- if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 &&
- WPA_GET_BE24(pos) == OUI_WFA &&
- pos[3] == HS20_WNM_SUB_REM_NEEDED) {
- /* Subscription Remediation subelement */
- const u8 *ie_end;
- u8 url_len;
- char *url;
- u8 osu_method;
-
- wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation "
- "subelement");
- ie_end = pos + ie_len;
- pos += 4;
- url_len = *pos++;
- if (url_len == 0) {
- wpa_printf(MSG_DEBUG, "WNM: No Server URL included");
- url = NULL;
- osu_method = 1;
- } else {
- if (url_len + 1 > ie_end - pos) {
- wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)",
- url_len,
- (int) (ie_end - pos));
- break;
- }
- url = os_malloc(url_len + 1);
- if (url == NULL)
- break;
- os_memcpy(url, pos, url_len);
- url[url_len] = '\0';
- osu_method = pos[url_len];
- }
- hs20_rx_subscription_remediation(wpa_s, url,
- osu_method);
- os_free(url);
- pos = next;
- continue;
- }
-
if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 &&
WPA_GET_BE24(pos) == OUI_WFA &&
pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) {
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 2f57be8..2ab2917 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -507,7 +507,7 @@
"ap_vendor_elements", "ignore_old_scan_res", "freq_list",
"scan_cur_freq", "scan_res_valid_for_connect",
"sched_scan_interval",
- "tdls_external_control", "osu_dir", "wowlan_triggers",
+ "tdls_external_control", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
"reassoc_same_bss_optim", "wps_priority",
@@ -614,7 +614,7 @@
"scan_cur_freq", "scan_res_valid_for_connect",
"sched_scan_interval",
"sched_scan_start_delay",
- "tdls_external_control", "osu_dir", "wowlan_triggers",
+ "tdls_external_control", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
"reassoc_same_bss_optim", "extended_key_id"
@@ -2778,37 +2778,6 @@
return wpa_ctrl_command(ctrl, cmd);
}
-
-static int wpa_cli_cmd_hs20_icon_request(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
-{
- char cmd[512];
-
- if (argc < 2) {
- printf("Command needs two arguments (dst mac addr and "
- "icon name)\n");
- return -1;
- }
-
- if (write_cmd(cmd, sizeof(cmd), "HS20_ICON_REQUEST", argc, argv) < 0)
- return -1;
-
- return wpa_ctrl_command(ctrl, cmd);
-}
-
-
-static int wpa_cli_cmd_fetch_osu(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
- return wpa_ctrl_command(ctrl, "FETCH_OSU");
-}
-
-
-static int wpa_cli_cmd_cancel_fetch_osu(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
-{
- return wpa_ctrl_command(ctrl, "CANCEL_FETCH_OSU");
-}
-
#endif /* CONFIG_HS20 */
@@ -3922,14 +3891,6 @@
{ "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
wpa_cli_complete_bss, cli_cmd_flag_none,
"<addr> <home realm> = get HS20 nai home realm list" },
- { "hs20_icon_request", wpa_cli_cmd_hs20_icon_request,
- wpa_cli_complete_bss, cli_cmd_flag_none,
- "<addr> <icon name> = get Hotspot 2.0 OSU icon" },
- { "fetch_osu", wpa_cli_cmd_fetch_osu, NULL, cli_cmd_flag_none,
- "= fetch OSU provider information from all APs" },
- { "cancel_fetch_osu", wpa_cli_cmd_cancel_fetch_osu, NULL,
- cli_cmd_flag_none,
- "= cancel fetch_osu command" },
#endif /* CONFIG_HS20 */
{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
cli_cmd_flag_none,
@@ -4495,8 +4456,6 @@
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, ESS_DISASSOC_IMMINENT)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_starts(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
- wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
wpa_cli_exec(action_file, ifname, pos);
} else if (str_starts(pos, HS20_T_C_ACCEPTANCE)) {
diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/wpa_supplicant/wpa_gui-qt4/eventhistory.h
index afd7b63..2122ab4 100644
--- a/wpa_supplicant/wpa_gui-qt4/eventhistory.h
+++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.h
@@ -40,7 +40,7 @@
public:
EventHistory(QWidget *parent = 0, const char *name = 0,
- bool modal = false, Qt::WindowFlags fl = 0);
+ bool modal = false, Qt::WindowFlags fl = Qt::Widget);
~EventHistory();
public slots:
diff --git a/wpa_supplicant/wpa_gui-qt4/main.cpp b/wpa_supplicant/wpa_gui-qt4/main.cpp
index bbd45c6..d395aa1 100644
--- a/wpa_supplicant/wpa_gui-qt4/main.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/main.cpp
@@ -40,10 +40,10 @@
int ret;
locale = QLocale::system().name();
- resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
- if (!translator.load("wpa_gui_" + locale, resourceDir))
- translator.load("wpa_gui_" + locale, "lang");
- app.installTranslator(&translator);
+ resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
+ if (translator.load("wpa_gui_" + locale, resourceDir) ||
+ translator.load("wpa_gui_" + locale, "lang"))
+ app.installTranslator(&translator);
WpaGui w(&app);
diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
index 2727318..59af845 100644
--- a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
@@ -37,7 +37,7 @@
SLOT(authChanged(int)));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
- connect(encrSelect, SIGNAL(activated(const QString &)), this,
+ connect(encrSelect, SIGNAL(textActivated(const QString &)), this,
SLOT(encrChanged(const QString &)));
connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork()));
connect(eapSelect, SIGNAL(activated(int)), this,
@@ -204,8 +204,8 @@
}
if (idstrEdit->isEnabled() && !idstrEdit->text().isEmpty()) {
- QRegExp rx("^(\\w|-)+$");
- if (rx.indexIn(idstrEdit->text()) < 0) {
+ QRegularExpression rx("^(\\w|-)+$");
+ if (!rx.match(idstrEdit->text()).hasMatch()) {
QMessageBox::warning(
this, tr("Network ID Error"),
tr("Network ID String contains non-word "
@@ -797,7 +797,7 @@
tr("This will permanently remove the network\n"
"from the configuration. Do you really want\n"
"to remove this network?"),
- tr("Yes"), tr("No")) != 0)
+ QMessageBox::Yes, QMessageBox::No) != 0)
return;
snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/wpa_supplicant/wpa_gui-qt4/networkconfig.h
index fd09dec..a3a7d97 100644
--- a/wpa_supplicant/wpa_gui-qt4/networkconfig.h
+++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.h
@@ -20,7 +20,7 @@
public:
NetworkConfig(QWidget *parent = 0, const char *name = 0,
- bool modal = false, Qt::WindowFlags fl = 0);
+ bool modal = false, Qt::WindowFlags fl = Qt::Widget);
~NetworkConfig();
virtual void paramsFromScanResults(QTreeWidgetItem *sel);
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp
index 0a0b3ff..268aba8 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp
@@ -403,7 +403,7 @@
void Peers::add_station(QString info)
{
- QStringList lines = info.split(QRegExp("\\n"));
+ QStringList lines = info.split(QRegularExpression("\\n"));
QString name;
for (QStringList::Iterator it = lines.begin();
@@ -518,7 +518,7 @@
*/
QStringList items =
- params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
+ params.split(QRegularExpression(" (?=[^']*('[^']*'[^']*)*$)"));
QString addr = "";
QString name = "";
int config_methods = 0;
@@ -591,7 +591,7 @@
QString ssid, bssid, flags, wps_name, pri_dev_type;
int id = -1;
- QStringList lines = bss.split(QRegExp("\\n"));
+ QStringList lines = bss.split(QRegularExpression("\\n"));
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
int pos = (*it).indexOf('=') + 1;
@@ -643,7 +643,7 @@
item->setData(ssid, peer_role_ssid);
model.appendRow(item);
- lines = bss.split(QRegExp("\\n"));
+ lines = bss.split(QRegularExpression("\\n"));
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
if ((*it).startsWith("p2p_group_client:"))
@@ -903,7 +903,7 @@
* group_capab=0x0
*/
QStringList items =
- text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)"));
+ text.split(QRegularExpression(" (?=[^']*('[^']*'[^']*)*$)"));
QString addr = items[1];
QString name = "";
QString pri_dev_type;
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.h b/wpa_supplicant/wpa_gui-qt4/peers.h
index bb73737..c44bba9 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.h
+++ b/wpa_supplicant/wpa_gui-qt4/peers.h
@@ -22,7 +22,7 @@
public:
Peers(QWidget *parent = 0, const char *name = 0,
- bool modal = false, Qt::WindowFlags fl = 0);
+ bool modal = false, Qt::WindowFlags fl = Qt::Widget);
~Peers();
void setWpaGui(WpaGui *_wpagui);
void event_notify(WpaMsg msg);
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
index a2e3072..ba04b4f 100644
--- a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
@@ -77,7 +77,7 @@
QString ssid, bssid, freq, signal, flags;
- QStringList lines = bss.split(QRegExp("\\n"));
+ QStringList lines = bss.split(QRegularExpression("\\n"));
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
int pos = (*it).indexOf('=') + 1;
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.h b/wpa_supplicant/wpa_gui-qt4/scanresults.h
index 2cddd13..39bba90 100644
--- a/wpa_supplicant/wpa_gui-qt4/scanresults.h
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.h
@@ -20,7 +20,7 @@
public:
ScanResults(QWidget *parent = 0, const char *name = 0,
- bool modal = false, Qt::WindowFlags fl = 0);
+ bool modal = false, Qt::WindowFlags fl = Qt::Widget);
~ScanResults();
public slots:
diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
index b6d1ad2..3f7dccb 100644
--- a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
+++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
@@ -20,7 +20,7 @@
public:
UserDataRequest(QWidget *parent = 0, const char *name = 0,
- bool modal = false, Qt::WindowFlags fl = 0);
+ bool modal = false, Qt::WindowFlags fl = Qt::Widget);
~UserDataRequest();
int setParams(WpaGui *_wpagui, const char *reqMsg);
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 9404ab4..0c125d9 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -99,9 +99,9 @@
connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
- connect(adapterSelect, SIGNAL(activated(const QString&)), this,
+ connect(adapterSelect, SIGNAL(textActivated(const QString&)), this,
SLOT(selectAdapter(const QString&)));
- connect(networkSelect, SIGNAL(activated(const QString&)), this,
+ connect(networkSelect, SIGNAL(textActivated(const QString&)), this,
SLOT(selectNetwork(const QString&)));
connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
connect(editNetworkButton, SIGNAL(clicked()), this,
@@ -1078,7 +1078,7 @@
char reply[10];
size_t reply_len = sizeof(reply);
- if (cmd.contains(QRegExp("^\\d+:")))
+ if (cmd.contains(QRegularExpression("^\\d+:")))
cmd.truncate(cmd.indexOf(':'));
else
cmd = "any";
@@ -1095,7 +1095,7 @@
char reply[10];
size_t reply_len = sizeof(reply);
- if (cmd.contains(QRegExp("^\\d+:")))
+ if (cmd.contains(QRegularExpression("^\\d+:")))
cmd.truncate(cmd.indexOf(':'));
else if (!cmd.startsWith("all")) {
debug("Invalid editNetwork '%s'",
@@ -1114,7 +1114,7 @@
char reply[10];
size_t reply_len = sizeof(reply);
- if (cmd.contains(QRegExp("^\\d+:")))
+ if (cmd.contains(QRegularExpression("^\\d+:")))
cmd.truncate(cmd.indexOf(':'));
else if (!cmd.startsWith("all")) {
debug("Invalid editNetwork '%s'",
@@ -1132,7 +1132,7 @@
QString cmd(sel);
int id = -1;
- if (cmd.contains(QRegExp("^\\d+:"))) {
+ if (cmd.contains(QRegularExpression("^\\d+:"))) {
cmd.truncate(cmd.indexOf(':'));
id = cmd.toInt();
}
@@ -1204,7 +1204,7 @@
char reply[10];
size_t reply_len = sizeof(reply);
- if (cmd.contains(QRegExp("^\\d+:")))
+ if (cmd.contains(QRegularExpression("^\\d+:")))
cmd.truncate(cmd.indexOf(':'));
else if (!cmd.startsWith("all")) {
debug("Invalid editNetwork '%s'",
@@ -1476,7 +1476,7 @@
QString msg, status(buf);
- QStringList lines = status.split(QRegExp("\\n"));
+ QStringList lines = status.split(QRegularExpression("\\n"));
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
int pos = (*it).indexOf('=') + 1;
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h
index f0a34c9..898722b 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.h
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h
@@ -49,7 +49,7 @@
};
WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0,
- Qt::WindowFlags fl = 0);
+ Qt::WindowFlags fl = Qt::Widget);
~WpaGui();
virtual int ctrlRequest(const char *cmd, char *buf, size_t *buflen);
diff --git a/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/wpa_supplicant/wpa_gui-qt4/wpamsg.h
index 8f2fcdc..fe36e20 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpamsg.h
+++ b/wpa_supplicant/wpa_gui-qt4/wpamsg.h
@@ -10,7 +10,7 @@
#define WPAMSG_H
#include <QDateTime>
-#include <QLinkedList>
+#include <QList>
class WpaMsg {
public:
@@ -30,6 +30,6 @@
QDateTime timestamp;
};
-typedef QLinkedList<WpaMsg> WpaMsgList;
+typedef QList<WpaMsg> WpaMsgList;
#endif /* WPAMSG_H */
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 9843679..b8c6f55 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -799,7 +799,6 @@
#ifdef CONFIG_HS20
if (wpa_s->drv_priv)
wpa_drv_configure_frame_filters(wpa_s, 0);
- hs20_deinit(wpa_s);
#endif /* CONFIG_HS20 */
for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
@@ -1060,6 +1059,13 @@
if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
return;
+ /* wpa->current_bss might have changed due to memory reallocation, so
+ * need to update ssid/ssid_len */
+ if (!wpa_s->current_bss)
+ return;
+ ssid = wpa_s->current_bss->ssid;
+ ssid_len = wpa_s->current_bss->ssid_len;
+
bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid);
if (!bss)
return;
@@ -1816,16 +1822,15 @@
#ifdef CONFIG_SAE
enum sae_pwe sae_pwe;
#endif /* CONFIG_SAE */
- const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
+ const u8 *bss_wpa, *bss_rsn, *bss_rsnx;
bool wmm;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
bss_rsnx = wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
- bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
} else {
- bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+ bss_wpa = bss_rsn = bss_rsnx = NULL;
}
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
@@ -1841,34 +1846,17 @@
(ie.key_mgmt & ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
-#ifdef CONFIG_HS20
- } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) &&
- wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 &&
- (ie.group_cipher & ssid->group_cipher) &&
- (ie.pairwise_cipher & ssid->pairwise_cipher) &&
- (ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN");
- proto = WPA_PROTO_OSEN;
- } else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) &&
- wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
- (ie.group_cipher & ssid->group_cipher) &&
- (ie.pairwise_cipher & ssid->pairwise_cipher) &&
- (ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)");
- proto = WPA_PROTO_RSN;
-#endif /* CONFIG_HS20 */
} else if (bss) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
ssid->key_mgmt);
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s",
MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len),
bss_wpa ? " WPA" : "",
- bss_rsn ? " RSN" : "",
- bss_osen ? " OSEN" : "");
+ bss_rsn ? " RSN" : "");
if (bss_rsn) {
wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
@@ -1895,9 +1883,7 @@
}
return -1;
} else {
- if (ssid->proto & WPA_PROTO_OSEN)
- proto = WPA_PROTO_OSEN;
- else if (ssid->proto & WPA_PROTO_RSN)
+ if (ssid->proto & WPA_PROTO_RSN)
proto = WPA_PROTO_RSN;
else
proto = WPA_PROTO_WPA;
@@ -1927,7 +1913,7 @@
#ifdef CONFIG_OWE
if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
!ssid->owe_only &&
- !bss_wpa && !bss_rsn && !bss_osen) {
+ !bss_wpa && !bss_rsn) {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
wpa_s->wpa_proto = 0;
*wpa_ie_len = 0;
@@ -1951,7 +1937,7 @@
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
- !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
+ !!(ssid->proto & WPA_PROTO_RSN));
if (bss || !wpa_s->ap_ies_from_associnfo) {
const u8 *rsnoe = NULL, *rsno2e = NULL, *rsnxoe = NULL;
@@ -2139,11 +2125,6 @@
} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
-#ifdef CONFIG_HS20
- } else if (sel & WPA_KEY_MGMT_OSEN) {
- wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
- wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_OWE
} else if (sel & WPA_KEY_MGMT_OWE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
@@ -2277,6 +2258,16 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, false);
}
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SPP_AMSDU,
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SPP_AMSDU) &&
+ ieee802_11_rsnx_capab(bss_rsnx,
+ WLAN_RSNX_CAPAB_SPP_A_MSDU) &&
+ wpa_s->pairwise_cipher & (WPA_CIPHER_CCMP_256 |
+ WPA_CIPHER_GCMP_256 |
+ WPA_CIPHER_CCMP |
+ WPA_CIPHER_GCMP) &&
+ (wpa_s->wpa_proto & WPA_PROTO_RSN));
+
if (!skip_default_rsne) {
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
wpa_ie_len)) {
@@ -2592,7 +2583,8 @@
if (style == WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS) {
/* Pregenerated addresses do not expire but their value
* might have changed, so let's check that. */
- if (ether_addr_equal(wpa_s->own_addr, ssid->mac_value))
+ if (ssid &&
+ ether_addr_equal(wpa_s->own_addr, ssid->mac_value))
return 0;
} else if ((wpa_s->last_mac_addr_change.sec != 0 ||
wpa_s->last_mac_addr_change.usec != 0) &&
@@ -3727,19 +3719,6 @@
os_free(wpa_ie);
return NULL;
}
-#ifdef CONFIG_HS20
- } else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
- (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
- /* No PMKSA caching, but otherwise similar to RSN/WPA */
- wpa_ie_len = max_wpa_ie_len;
- if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
- wpa_ie, &wpa_ie_len, false)) {
- wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
- "key management and encryption suites");
- os_free(wpa_ie);
- return NULL;
- }
-#endif /* CONFIG_HS20 */
} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
/*
@@ -6390,6 +6369,12 @@
#endif /* CONFIG_NO_ROBUST_AV */
wpa_s->ml_probe_mld_id = -1;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+ dl_list_init(&wpa_s->mesh_external_pmksa_cache);
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
return wpa_s;
}
@@ -6605,7 +6590,7 @@
htcaps_mask->ht_capabilities_info |= msk;
htcaps->ht_capabilities_info &= ~msk;
- htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk;
+ htcaps->ht_capabilities_info |= host_to_le16(tx_stbc << 7) & msk;
return 0;
}
@@ -6631,7 +6616,7 @@
htcaps_mask->ht_capabilities_info |= msk;
htcaps->ht_capabilities_info &= ~msk;
- htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk;
+ htcaps->ht_capabilities_info |= host_to_le16(rx_stbc << 8) & msk;
return 0;
}
@@ -6698,13 +6683,15 @@
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_sgi) {
- vhtcaps_mask->vht_capabilities_info |= (VHT_CAP_SHORT_GI_80 |
- VHT_CAP_SHORT_GI_160);
- vhtcaps->vht_capabilities_info &= ~(VHT_CAP_SHORT_GI_80 |
- VHT_CAP_SHORT_GI_160);
+ vhtcaps_mask->vht_capabilities_info |=
+ host_to_le32(VHT_CAP_SHORT_GI_80 |
+ VHT_CAP_SHORT_GI_160);
+ vhtcaps->vht_capabilities_info &=
+ host_to_le32(~(VHT_CAP_SHORT_GI_80 |
+ VHT_CAP_SHORT_GI_160));
wpa_msg(wpa_s, MSG_DEBUG,
"disable-sgi override specified, vht-caps: 0x%x",
- vhtcaps->vht_capabilities_info);
+ le_to_host32(vhtcaps->vht_capabilities_info));
}
/* if max ampdu is <= 3, we have to make the HT cap the same */
@@ -7901,12 +7888,6 @@
if (wpa_bss_init(wpa_s) < 0)
return -1;
-#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
-#ifdef CONFIG_MESH
- dl_list_init(&wpa_s->mesh_external_pmksa_cache);
-#endif /* CONFIG_MESH */
-#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
-
/*
* Set Wake-on-WLAN triggers, if configured.
* Note: We don't restore/remove the triggers on shutdown (it doesn't
@@ -7942,9 +7923,6 @@
wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
-#ifdef CONFIG_HS20
- hs20_init(wpa_s);
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
if ((wpa_s->conf->oce & OCE_STA) &&
@@ -9179,7 +9157,7 @@
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
(!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
!(wpa_key_mgmt_sae(ssid->key_mgmt) &&
- (ssid->sae_password || ssid->pmk_valid)) &&
+ (ssid->passphrase || ssid->sae_password || ssid->pmk_valid)) &&
!ssid->mem_only_psk)
return 1;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index ae181ee..cf10118 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1256,6 +1256,10 @@
# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being
# default priority
#
+# macsec_icv_indicator: Always include ICV indicator
+# 0 = ICV Indicator is not included when ICV has default length (default)
+# 1 = ICV Indicator is always included (compatibility mode)
+#
# mixed_cell: This option can be used to configure whether so called mixed
# cells, i.e., networks that use both plaintext and encryption in the same
# SSID, are allowed when selecting a BSS from scan results.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d27ff1a..8965bfa 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -470,15 +470,6 @@
WPAS_TEST_FAILURE_SCAN_TRIGGER,
};
-struct icon_entry {
- struct dl_list list;
- u8 bssid[ETH_ALEN];
- u8 dialog_token;
- char *file_name;
- u8 *image;
- size_t image_len;
-};
-
struct wpa_bss_tmp_disallowed {
struct dl_list list;
u8 bssid[ETH_ALEN];
@@ -1057,6 +1048,7 @@
u8 sched_obss_scan;
u16 obss_scan_int;
u16 bss_max_idle_period;
+ bool spp_amsdu;
#ifdef CONFIG_SAE
struct sae_data sae;
struct wpabuf *sae_token;
@@ -1273,17 +1265,7 @@
unsigned int auto_network_select:1;
unsigned int interworking_fast_assoc_tried:1;
unsigned int fetch_all_anqp:1;
- unsigned int fetch_osu_info:1;
- unsigned int fetch_osu_waiting_scan:1;
- unsigned int fetch_osu_icon_in_progress:1;
struct wpa_bss *interworking_gas_bss;
- unsigned int osu_icon_id;
- struct dl_list icon_head; /* struct icon_entry */
- struct osu_provider *osu_prov;
- size_t osu_prov_count;
- struct os_reltime osu_icon_fetch_start;
- unsigned int num_osu_scans;
- unsigned int num_prov_found;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
@@ -2024,7 +2006,8 @@
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
- int only_first_ssid, int debug_print);
+ int only_first_ssid, int debug_print,
+ bool link);
struct wpa_bss * wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
struct wpa_ssid *group,
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index 600b3bc..7893a39 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -249,6 +249,7 @@
ssid->macsec_replay_window,
ssid->macsec_offload, ssid->macsec_port,
ssid->mka_priority, ssid->macsec_csindex,
+ ssid->macsec_icv_indicator,
wpa_s->ifname, wpa_s->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
if (res == NULL)