Snap for 13256841 from 719425812aa0b50b49677a850788aa92e8375c57 to 25Q2-release
Change-Id: Ib11947c6a8d46630ee4426c818454eb220bea694
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.bp b/wpa_supplicant/Android.bp
index a29093f..5a08fa1 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -163,10 +163,12 @@
"-DCONFIG_NO_RADIUS",
"-DCONFIG_NO_RADIUS",
"-DCONFIG_NO_RANDOM_POOL",
+ "-DCONFIG_NO_ROAMING",
"-DCONFIG_NO_VLAN",
"-DCONFIG_OFFCHANNEL",
"-DCONFIG_OWE",
"-DCONFIG_P2P",
+ "-DCONFIG_PASN",
"-DCONFIG_SAE",
"-DCONFIG_SAE_PK",
"-DCONFIG_SHA256",
@@ -233,21 +235,6 @@
any @ driver: ["-D" + driver],
// Flag is optional, so no default value provided.
default: [],
- }) +
- select(soong_config_variable("wpa_supplicant", "roaming"), {
- true: [],
- default: ["-DCONFIG_NO_ROAMING"],
- }) +
- select(soong_config_variable("wpa_supplicant", "pasn"), {
- false: [],
- default: ["-DCONFIG_PASN"],
- }) +
- select(soong_config_variable("wpa_supplicant", "bgscan_simple"), {
- true: [
- "-DCONFIG_BGSCAN",
- "-DCONFIG_BGSCAN_SIMPLE",
- ],
- default: [],
}),
// Similar to suppressing clang compiler warnings, here we
// suppress clang-tidy warnings to reduce noises in Android build.log.
@@ -305,6 +292,7 @@
"op_classes.c",
"p2p_supplicant.c",
"p2p_supplicant_sd.c",
+ "pasn_supplicant.c",
"robust_av.c",
"rrm.c",
"scan.c",
@@ -436,6 +424,9 @@
"src/p2p/p2p_pd.c",
"src/p2p/p2p_sd.c",
"src/p2p/p2p_utils.c",
+ "src/pasn/pasn_initiator.c",
+ "src/pasn/pasn_responder.c",
+ "src/pasn/pasn_common.c",
"src/rsn_supp/pmksa_cache.c",
"src/rsn_supp/preauth.c",
"src/rsn_supp/tdls.c",
@@ -483,24 +474,7 @@
"wpas_glue.c",
"wpa_supplicant.c",
"wps_supplicant.c",
- ] +
- select(soong_config_variable("wpa_supplicant", "bgscan_simple"), {
- true: [
- "bgscan.c",
- "bgscan_simple.c",
- ],
- default: [],
- }) +
- select(soong_config_variable("wpa_supplicant", "pasn"), {
- false: [],
- default: [
- "pasn_supplicant.c",
- "src/pasn/pasn_initiator.c",
- "src/pasn/pasn_responder.c",
- "src/pasn/pasn_common.c",
- ],
- }),
-
+ ],
}
// Generated by building wpa_cli and printing LOCAL_SRC_FILES
@@ -840,12 +814,10 @@
"-DCONFIG_NO_RADIUS",
"-DCONFIG_NO_RADIUS",
"-DCONFIG_NO_RANDOM_POOL",
- "-DCONFIG_NO_ROAMING",
"-DCONFIG_NO_VLAN",
"-DCONFIG_OFFCHANNEL",
"-DCONFIG_OWE",
"-DCONFIG_P2P",
- "-DCONFIG_PASN",
"-DCONFIG_PTKSA_CACHE",
"-DCONFIG_SAE",
"-DCONFIG_SAE_PK",
@@ -919,6 +891,18 @@
}) + select(soong_config_variable("wpa_supplicant_8", "wpa_supplicant_11be"), {
true: ["-DCONFIG_IEEE80211BE"],
default: [],
+ }) + select(soong_config_variable("wpa_supplicant", "roaming"), {
+ true: [],
+ default: ["-DCONFIG_NO_ROAMING"],
+ }) + select(soong_config_variable("wpa_supplicant", "pasn"), {
+ false: [],
+ default: ["-DCONFIG_PASN"],
+ }) + select(soong_config_variable("wpa_supplicant", "bgscan_simple"), {
+ true: [
+ "-DCONFIG_BGSCAN",
+ "-DCONFIG_BGSCAN_SIMPLE",
+ ],
+ default: [],
}),
arch: {
arm: {
@@ -1013,7 +997,6 @@
"op_classes.c",
"p2p_supplicant.c",
"p2p_supplicant_sd.c",
- "pasn_supplicant.c",
"robust_av.c",
"rrm.c",
"scan.c",
@@ -1148,9 +1131,6 @@
"src/p2p/p2p_pd.c",
"src/p2p/p2p_sd.c",
"src/p2p/p2p_utils.c",
- "src/pasn/pasn_common.c",
- "src/pasn/pasn_initiator.c",
- "src/pasn/pasn_responder.c",
"src/rsn_supp/pmksa_cache.c",
"src/rsn_supp/preauth.c",
"src/rsn_supp/tdls.c",
@@ -1197,6 +1177,20 @@
}) + select(soong_config_variable("wpa_supplicant_8", "wpa_supplicant_11be"), {
true: ["src/ap/ieee802_11_eht.c"],
default: [],
+ }) + select(soong_config_variable("wpa_supplicant", "bgscan_simple"), {
+ true: [
+ "bgscan.c",
+ "bgscan_simple.c",
+ ],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant", "pasn"), {
+ false: [],
+ default: [
+ "pasn_supplicant.c",
+ "src/pasn/pasn_initiator.c",
+ "src/pasn/pasn_responder.c",
+ "src/pasn/pasn_common.c",
+ ],
}),
defaults: [
"wpa_supplicant_driver_srcs_default",
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/mainline/Android.bp b/wpa_supplicant/aidl/mainline/Android.bp
index a2f5370..43c9c1a 100644
--- a/wpa_supplicant/aidl/mainline/Android.bp
+++ b/wpa_supplicant/aidl/mainline/Android.bp
@@ -31,6 +31,7 @@
"libbinder_ndk",
],
cppflags: [
+ "-DMAINLINE_SUPPLICANT",
"-Wall",
"-Werror",
"-Wno-unused-parameter",
diff --git a/wpa_supplicant/aidl/mainline/callback_bridge.cpp b/wpa_supplicant/aidl/mainline/callback_bridge.cpp
new file mode 100644
index 0000000..a7b284b
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/callback_bridge.cpp
@@ -0,0 +1,100 @@
+/*
+ * WPA Supplicant - Interface to receive callbacks from the core supplicant
+ * Copyright (c) 2025, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils.h"
+#include "usd_utils.h"
+
+extern "C"
+{
+#include "callback_bridge.h"
+}
+
+using ::aidl::android::system::wifi::mainline_supplicant::UsdMessageInfo;
+
+void mainline_aidl_notify_usd_service_discovered(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+ bool fsd, const u8 *ssi, size_t ssi_len) {
+ if (!wpa_s || !peer_addr)
+ return;
+
+ auto callback = getStaIfaceCallback(wpa_s->ifname);
+ if (!callback)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD service discovered");
+ auto serviceDiscoveryInfo = createUsdServiceDiscoveryInfo(
+ srv_proto_type, subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
+ callback->onUsdServiceDiscovered(serviceDiscoveryInfo);
+}
+
+void mainline_aidl_notify_usd_publish_replied(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int publish_id, int peer_subscribe_id,
+ const u8 *peer_addr, const u8 *ssi, size_t ssi_len) {
+ if (!wpa_s || !peer_addr)
+ return;
+
+ auto callback = getStaIfaceCallback(wpa_s->ifname);
+ if (!callback)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD publish replied");
+ auto serviceDiscoveryInfo = createUsdServiceDiscoveryInfo(
+ srv_proto_type, publish_id, peer_subscribe_id, peer_addr, false /* fsd */,
+ ssi, ssi_len);
+ callback->onUsdPublishReplied(serviceDiscoveryInfo);
+}
+
+void mainline_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len) {
+ if (!wpa_s || !peer_addr)
+ return;
+
+ auto callback = getStaIfaceCallback(wpa_s->ifname);
+ if (!callback)
+ return;
+
+ UsdMessageInfo messageInfo;
+ messageInfo.ownId = id;
+ messageInfo.peerId = peer_instance_id;
+ messageInfo.peerMacAddress = macAddrBytesToArray(peer_addr);
+ messageInfo.message = message ? byteArrToVec(message, message_len) : std::vector<uint8_t>();
+
+ wpa_printf(MSG_DEBUG, "Notifying USD message received");
+ callback->onUsdMessageReceived(messageInfo);
+}
+
+void mainline_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason) {
+ if (!wpa_s)
+ return;
+
+ auto callback = getStaIfaceCallback(wpa_s->ifname);
+ if (!callback)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD publish terminated");
+ callback->onUsdPublishTerminated(
+ publish_id, convertInternalUsdTerminateReasonCodeToAidl(reason));
+}
+
+void mainline_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason) {
+ if (!wpa_s)
+ return;
+
+ auto callback = getStaIfaceCallback(wpa_s->ifname);
+ if (!callback)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD subscribe terminated");
+ callback->onUsdSubscribeTerminated(
+ subscribe_id, convertInternalUsdTerminateReasonCodeToAidl(reason));
+}
diff --git a/wpa_supplicant/aidl/mainline/callback_bridge.h b/wpa_supplicant/aidl/mainline/callback_bridge.h
new file mode 100644
index 0000000..c35bf37
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/callback_bridge.h
@@ -0,0 +1,70 @@
+/*
+ * WPA Supplicant - Interface to receive callbacks from the core supplicant
+ * Copyright (c) 2025, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_CALLBACK_BRIDGE_H
+#define MAINLINE_SUPPLICANT_CALLBACK_BRIDGE_H
+
+/**
+ * Intermediary layer to receive callbacks from the core supplicant.
+ *
+ * For each callback, we provide a full implementation if the MAINLINE_SUPPLICANT
+ * flag is enabled. Otherwise, we provide an empty default implementation for builds
+ * that do not have the flag enabled (ex. the vendor supplicant).
+ */
+#ifdef _cplusplus
+extern "C"
+{
+#endif // _cplusplus
+
+#include "utils/common.h"
+#include "src/common/nan_de.h"
+#include "wpa_supplicant_i.h"
+
+#ifdef MAINLINE_SUPPLICANT
+
+void mainline_aidl_notify_usd_service_discovered(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+ bool fsd, const u8 *ssi, size_t ssi_len);
+void mainline_aidl_notify_usd_publish_replied(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int publish_id, int peer_subscribe_id,
+ const u8 *peer_addr, const u8 *ssi, size_t ssi_len);
+void mainline_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len);
+void mainline_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason);
+void mainline_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason);
+
+#else // MAINLINE_SUPPLICANT
+
+static void mainline_aidl_notify_usd_service_discovered(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int subscribe_id, int peer_publish_id, const u8 *peer_addr,
+ bool fsd, const u8 *ssi, size_t ssi_len) {}
+static void mainline_aidl_notify_usd_publish_replied(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int publish_id, int peer_subscribe_id,
+ const u8 *peer_addr, const u8 *ssi, size_t ssi_len) {}
+static void mainline_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len) {}
+static void mainline_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason) {}
+static void mainline_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason) {}
+
+#endif // MAINLINE_SUPPLICANT
+
+#ifdef _cplusplus
+}
+#endif // _cplusplus
+
+#endif // MAINLINE_SUPPLICANT_CALLBACK_BRIDGE_H
diff --git a/wpa_supplicant/aidl/mainline/callback_manager.cpp b/wpa_supplicant/aidl/mainline/callback_manager.cpp
new file mode 100644
index 0000000..4922ce1
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/callback_manager.cpp
@@ -0,0 +1,90 @@
+/*
+ * WPA Supplicant - Manager for callback objects
+ * Copyright (c) 2025, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "callback_manager.h"
+
+extern "C"
+{
+#include "utils/common.h"
+#include "wpa_supplicant_i.h"
+}
+
+// Raw pointer to the global structure maintained by the core
+// Declared here to be accessible to onDeath()
+struct wpa_global* wpa_global_;
+
+void onDeath(void* cookie) {
+ wpa_printf(MSG_ERROR, "Client died. Terminating...");
+ wpa_supplicant_terminate_proc(wpa_global_);
+}
+
+CallbackManager* CallbackManager::instance_ = NULL;
+
+void CallbackManager::initialize(struct wpa_global* wpa_global) {
+ wpa_printf(MSG_INFO, "Initializing the callback manager");
+ wpa_global_ = wpa_global;
+ instance_ = new CallbackManager();
+ instance_->death_notifier_ = AIBinder_DeathRecipient_new(onDeath);
+}
+
+CallbackManager* CallbackManager::getInstance() {
+ return instance_;
+}
+
+bool CallbackManager::registerStaIfaceCallback(std::string ifaceName,
+ const std::shared_ptr<IStaInterfaceCallback>& callback) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!callback) {
+ wpa_printf(MSG_ERROR, "Attempted to register a null callback for STA iface %s",
+ ifaceName.c_str());
+ return false;
+ }
+ if (callbackRegisteredForStaIface(ifaceName)) {
+ wpa_printf(MSG_ERROR, "Callback is already registered for STA iface %s",
+ ifaceName.c_str());
+ return false;
+ }
+ binder_status_t status = AIBinder_linkToDeath(callback->asBinder().get(),
+ death_notifier_, nullptr /* cookie */);
+ if (status != STATUS_OK) {
+ wpa_printf(MSG_ERROR, "Received code %d when linking death recipient"
+ " for callback on STA iface %s", status, ifaceName.c_str());
+ return false;
+ }
+ wpa_printf(MSG_INFO, "Registered callback for STA iface %s", ifaceName.c_str());
+ sta_iface_callbacks_[ifaceName] = callback;
+ return true;
+}
+
+void CallbackManager::unregisterStaIfaceCallback(std::string ifaceName) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ wpa_printf(MSG_INFO, "Unregistering callback for STA iface %s",
+ ifaceName.c_str());
+ if (!callbackRegisteredForStaIface(ifaceName)) {
+ wpa_printf(MSG_INFO, "Callback does not need to be unregistered"
+ " for STA iface %s", ifaceName.c_str());
+ return;
+ }
+ auto callback = sta_iface_callbacks_[ifaceName];
+ binder_status_t status = AIBinder_unlinkToDeath(callback->asBinder().get(),
+ death_notifier_, nullptr /* cookie */);
+ if (status != STATUS_OK) {
+ wpa_printf(MSG_ERROR, "Received code %d when unlinking death recipient"
+ " for callback on STA iface %s", status, ifaceName.c_str());
+ }
+ sta_iface_callbacks_.erase(ifaceName);
+}
+
+std::shared_ptr<IStaInterfaceCallback> CallbackManager::getStaIfaceCallback(
+ std::string ifaceName) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!callbackRegisteredForStaIface(ifaceName)) {
+ return nullptr;
+ }
+ return sta_iface_callbacks_[ifaceName];
+}
diff --git a/wpa_supplicant/aidl/mainline/callback_manager.h b/wpa_supplicant/aidl/mainline/callback_manager.h
new file mode 100644
index 0000000..788c7b3
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/callback_manager.h
@@ -0,0 +1,52 @@
+/*
+ * WPA Supplicant - Manager for callback objects
+ * Copyright (c) 2025, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_CALLBACK_MANAGER_H
+#define MAINLINE_SUPPLICANT_CALLBACK_MANAGER_H
+
+#include <map>
+#include <mutex>
+#include <string>
+
+#include <aidl/android/system/wifi/mainline_supplicant/IStaInterfaceCallback.h>
+
+using ::aidl::android::system::wifi::mainline_supplicant::IStaInterfaceCallback;
+
+/**
+ * Class to manage all registered callback objects.
+ *
+ * On startup, a singleton instance should be created using initialize().
+ * Subsequent callers should retrieve the singleton using getInstance().
+ */
+class CallbackManager {
+ public:
+ // Singleton access
+ static void initialize(struct wpa_global* wpa_global);
+ static CallbackManager* getInstance();
+
+ // Member functions
+ bool registerStaIfaceCallback(std::string ifaceName,
+ const std::shared_ptr<IStaInterfaceCallback>& callback);
+ void unregisterStaIfaceCallback(std::string ifaceName);
+ std::shared_ptr<IStaInterfaceCallback> getStaIfaceCallback(std::string ifaceName);
+
+ private:
+ inline bool callbackRegisteredForStaIface(std::string ifaceName) {
+ return sta_iface_callbacks_.find(ifaceName) != sta_iface_callbacks_.end();
+ }
+
+ // Singleton instance of this class
+ static CallbackManager* instance_;
+
+ // Member variables
+ std::mutex mutex_;
+ AIBinder_DeathRecipient* death_notifier_;
+ std::map<std::string, std::shared_ptr<IStaInterfaceCallback>> sta_iface_callbacks_;
+};
+
+#endif // MAINLINE_SUPPLICANT_CALLBACK_MANAGER_H
diff --git a/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp b/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp
index 09021fe..ff5c388 100644
--- a/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp
+++ b/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp
@@ -7,6 +7,7 @@
*/
#include "aidl/shared/shared_utils.h"
+#include "callback_manager.h"
#include "mainline_supplicant.h"
#include "utils.h"
@@ -80,8 +81,13 @@
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
- wpa_printf(MSG_INFO, "Interface %s was removed successfully", ifaceName.c_str());
+ // Remove interface and callback from the internal maps
+ CallbackManager* callbackManager = CallbackManager::getInstance();
+ WPA_ASSERT(callbackManager);
+ callbackManager->unregisterStaIfaceCallback(ifaceName);
active_sta_ifaces_.erase(ifaceName);
+
+ wpa_printf(MSG_INFO, "Interface %s was removed successfully", ifaceName.c_str());
return ndk::ScopedAStatus::ok();
}
diff --git a/wpa_supplicant/aidl/mainline/service.cpp b/wpa_supplicant/aidl/mainline/service.cpp
index da343ea..002abbb 100644
--- a/wpa_supplicant/aidl/mainline/service.cpp
+++ b/wpa_supplicant/aidl/mainline/service.cpp
@@ -9,6 +9,7 @@
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include "callback_manager.h"
#include "mainline_supplicant.h"
extern "C"
@@ -80,6 +81,7 @@
}
wpa_printf(MSG_INFO, "AIDL setup is complete");
+ CallbackManager::initialize(global);
return priv;
}
diff --git a/wpa_supplicant/aidl/mainline/sta_iface.cpp b/wpa_supplicant/aidl/mainline/sta_iface.cpp
index 08d2b04..0eaa199 100644
--- a/wpa_supplicant/aidl/mainline/sta_iface.cpp
+++ b/wpa_supplicant/aidl/mainline/sta_iface.cpp
@@ -6,6 +6,7 @@
* See README for more details.
*/
+#include "callback_manager.h"
#include "sta_iface.h"
#include "usd_utils.h"
@@ -24,8 +25,14 @@
}
::ndk::ScopedAStatus StaIface::registerCallback(
- const std::shared_ptr<IStaInterfaceCallback>& in_callback) {
- return ndk::ScopedAStatus::ok();
+ const std::shared_ptr<IStaInterfaceCallback>& callback) {
+ CallbackManager* callbackManager = CallbackManager::getInstance();
+ WPA_ASSERT(callbackManager);
+ if (callbackManager->registerStaIfaceCallback(iface_name_, callback)) {
+ return ndk::ScopedAStatus::ok();
+ } else {
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
}
::ndk::ScopedAStatus StaIface::getUsdCapabilities(UsdCapabilities* _aidl_return) {
@@ -64,7 +71,18 @@
convertAidlServiceProtoTypeToInternal(
publishConfig.baseConfig.serviceProtoType),
ssiBuffer.get(), &nanPublishParams, false /* p2p */);
- // TODO: Return status code in a callback
+
+ // Core supplicant does not have an internal callback for USD publish,
+ // so invoke the failure callback directly if needed.
+ if (publishId < 0) {
+ wpa_printf(MSG_INFO, "Failed to configure USD publish");
+ auto callback = getStaIfaceCallback(iface_name_);
+ if (callback) {
+ callback->onUsdPublishConfigFailed(
+ cmdId, IStaInterfaceCallback::UsdConfigErrorCode::FAILURE_UNKNOWN);
+ }
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
return ndk::ScopedAStatus::ok();
}
@@ -91,7 +109,18 @@
convertAidlServiceProtoTypeToInternal(
subscribeConfig.baseConfig.serviceProtoType),
ssiBuffer.get(), &nanSubscribeParams, false /* p2p */);
- // TODO: Return status code in a callback
+
+ // Core supplicant does not have an internal callback for USD subscribe,
+ // so invoke the failure callback directly if needed.
+ if (subscribeId < 0) {
+ wpa_printf(MSG_INFO, "Failed to configure USD subscribe");
+ auto callback = getStaIfaceCallback(iface_name_);
+ if (callback) {
+ callback->onUsdSubscribeConfigFailed(
+ cmdId, IStaInterfaceCallback::UsdConfigErrorCode::FAILURE_UNKNOWN);
+ }
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
return ndk::ScopedAStatus::ok();
}
diff --git a/wpa_supplicant/aidl/mainline/usd_utils.h b/wpa_supplicant/aidl/mainline/usd_utils.h
index 428a599..4d8a52f 100644
--- a/wpa_supplicant/aidl/mainline/usd_utils.h
+++ b/wpa_supplicant/aidl/mainline/usd_utils.h
@@ -150,4 +150,47 @@
};
}
+static UsdServiceProtoType convertInternalUsdServiceProtoTypeToAidl(
+ nan_service_protocol_type protocolType) {
+ switch (protocolType) {
+ case NAN_SRV_PROTO_GENERIC:
+ return UsdServiceProtoType::GENERIC;
+ case NAN_SRV_PROTO_CSA_MATTER:
+ return UsdServiceProtoType::CSA_MATTER;
+ default:
+ wpa_printf(MSG_ERROR, "Received invalid USD proto type %d from internal",
+ static_cast<int>(protocolType));
+ return UsdServiceProtoType::GENERIC;
+ }
+}
+
+static IStaInterfaceCallback::UsdServiceDiscoveryInfo createUsdServiceDiscoveryInfo(
+ enum nan_service_protocol_type srv_proto_type,
+ int own_id, int peer_id, const u8 *peer_addr,
+ bool fsd, const u8 *ssi, size_t ssi_len) {
+ IStaInterfaceCallback::UsdServiceDiscoveryInfo discoveryInfo;
+ discoveryInfo.ownId = own_id;
+ discoveryInfo.peerId = peer_id;
+ // TODO: Fill the matchFilter field in the AIDL struct
+ discoveryInfo.matchFilter = std::vector<uint8_t>();
+ discoveryInfo.peerMacAddress = macAddrBytesToArray(peer_addr);
+ discoveryInfo.serviceProtoType = convertInternalUsdServiceProtoTypeToAidl(srv_proto_type);
+ discoveryInfo.serviceSpecificInfo = ssi ? byteArrToVec(ssi, ssi_len) : std::vector<uint8_t>();
+ discoveryInfo.isFsd = fsd;
+ return discoveryInfo;
+}
+
+static IStaInterfaceCallback::UsdTerminateReasonCode convertInternalUsdTerminateReasonCodeToAidl(
+ nan_de_reason terminateReason) {
+ switch (terminateReason) {
+ case NAN_DE_REASON_TIMEOUT:
+ return IStaInterfaceCallback::UsdTerminateReasonCode::TIMEOUT;
+ case NAN_DE_REASON_USER_REQUEST:
+ return IStaInterfaceCallback::UsdTerminateReasonCode::USER_REQUESTED;
+ case NAN_DE_REASON_FAILURE:
+ default:
+ return IStaInterfaceCallback::UsdTerminateReasonCode::FAILURE_UNKNOWN;
+ }
+}
+
#endif // MAINLINE_SUPPLICANT_USD_UTILS_H
diff --git a/wpa_supplicant/aidl/mainline/utils.h b/wpa_supplicant/aidl/mainline/utils.h
index 8b1fd19..bf7b9fb 100644
--- a/wpa_supplicant/aidl/mainline/utils.h
+++ b/wpa_supplicant/aidl/mainline/utils.h
@@ -9,6 +9,8 @@
#ifndef MAINLINE_SUPPLICANT_UTILS_H
#define MAINLINE_SUPPLICANT_UTILS_H
+#include "callback_manager.h"
+
#include <aidl/android/system/wifi/mainline_supplicant/SupplicantStatusCode.h>
extern "C"
@@ -60,4 +62,26 @@
return createWpaBufUniquePtr(wpabuf_alloc_copy(data.data(), data.size()));
}
+// Convert a byte array representation of a MAC address to an std::array
+inline std::array<uint8_t, ETH_ALEN> macAddrBytesToArray(const uint8_t* mac_addr) {
+ std::array<uint8_t, ETH_ALEN> arr;
+ std::copy(mac_addr, mac_addr + ETH_ALEN, std::begin(arr));
+ return arr;
+}
+
+// Convert a byte array to an std::vector
+inline std::vector<uint8_t> byteArrToVec(const uint8_t* arr, int len) {
+ return std::vector<uint8_t>{arr, arr + len};
+}
+
+// Wrapper to retrieve a STA iface callback registered with the callback manager
+static std::shared_ptr<IStaInterfaceCallback> getStaIfaceCallback(
+ std::string ifaceName) {
+ CallbackManager* callback_manager = CallbackManager::getInstance();
+ if (!callback_manager) {
+ return nullptr;
+ }
+ return callback_manager->getStaIfaceCallback(ifaceName);
+}
+
#endif // MAINLINE_SUPPLICANT_UTILS_H
diff --git a/wpa_supplicant/aidl/vendor/aidl.cpp b/wpa_supplicant/aidl/vendor/aidl.cpp
index afda33f..462e118 100644
--- a/wpa_supplicant/aidl/vendor/aidl.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl.cpp
@@ -629,7 +629,7 @@
aidl_manager->notifyP2pProvisionDiscovery(
wpa_s, dev_addr, request, status, config_methods,
- generated_pin, group_ifname);
+ generated_pin, group_ifname, 0);
}
void wpas_aidl_notify_p2p_sd_response(
@@ -1194,3 +1194,56 @@
wpa_printf(MSG_DEBUG, "Notifying USD subscribe terminated");
aidl_manager->notifyUsdSubscribeTerminated(wpa_s, subscribe_id, reason);
}
+
+static enum p2p_prov_disc_status convert_p2p_status_code_to_p2p_prov_disc_status(int status) {
+ switch (status) {
+ case P2P_SC_SUCCESS:
+ return P2P_PROV_DISC_SUCCESS;
+ case P2P_SC_COMEBACK:
+ return P2P_PROV_DISC_INFO_UNAVAILABLE;
+ default:
+ return P2P_PROV_DISC_REJECTED;
+ }
+}
+
+void wpas_aidl_notify_p2p_bootstrap_request(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ int status, u16 bootstrap_method, const char *group_ifname)
+{
+ if (!wpa_s || !dev_addr)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P P2P bootstrap request to aidl control " MACSTR,
+ MAC2STR(dev_addr));
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ aidl_manager->notifyP2pProvisionDiscovery(
+ wpa_s, dev_addr, true, convert_p2p_status_code_to_p2p_prov_disc_status(status),
+ WPS_NOT_READY, 0, group_ifname, bootstrap_method);
+}
+
+void wpas_aidl_notify_p2p_bootstrap_response(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ int status, u16 bootstrap_method, const char *group_ifname)
+{
+ if (!wpa_s || !dev_addr)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P bootstrap response to aidl control " MACSTR,
+ MAC2STR(dev_addr));
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ aidl_manager->notifyP2pProvisionDiscovery(
+ wpa_s, dev_addr, false, convert_p2p_status_code_to_p2p_prov_disc_status(status),
+ WPS_NOT_READY, 0, group_ifname, bootstrap_method);
+}
diff --git a/wpa_supplicant/aidl/vendor/aidl.h b/wpa_supplicant/aidl/vendor/aidl.h
index a8f38cb..039c6e1 100644
--- a/wpa_supplicant/aidl/vendor/aidl.h
+++ b/wpa_supplicant/aidl/vendor/aidl.h
@@ -96,6 +96,12 @@
struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
enum p2p_prov_disc_status status, u16 config_methods,
unsigned int generated_pin, const char *group_ifname);
+ void wpas_aidl_notify_p2p_bootstrap_request(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ int status, u16 bootstrap_method, const char *group_ifname);
+ void wpas_aidl_notify_p2p_bootstrap_response(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ int status, u16 bootstrap_method, const char *group_ifname);
void wpas_aidl_notify_p2p_sd_response(
struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
const u8 *tlvs, size_t tlvs_len);
@@ -274,6 +280,14 @@
enum p2p_prov_disc_status status, u16 config_methods,
unsigned int generated_pin, const char *group_ifname)
{}
+static void wpas_aidl_notify_p2p_bootstrap_request(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ int status, u16 bootstrap_method, const char *group_ifname)
+{}
+static void wpas_aidl_notify_p2p_bootstrap_response(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr,
+ int status, u16 bootstrap_method, const char *group_ifname)
+{}
static void wpas_aidl_notify_p2p_sd_response(
struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
const u8 *tlvs, size_t tlvs_len)
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.cpp b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
index 24e5a56..ec895a0 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);
@@ -1402,9 +1399,15 @@
params.wfdR2DeviceInfo = aidl_peer_wfd_r2_device_info;
params.vendorElemBytes = aidl_vendor_elems;
if (areAidlServiceAndClientAtLeastVersion(4)) {
- // TODO Fill the DIRA info when supplicant implementation is ready
params.pairingBootstrappingMethods = convertP2pPairingBootstrappingMethodsToAidl(
info->pairing_config.bootstrap_methods);
+ if (info->nonce_tag_valid) {
+ params.dirInfo->cipherVersion =
+ P2pDirInfo::CipherVersion::DIRA_CIPHER_VERSION_128_BIT;
+ params.dirInfo->deviceInterfaceMacAddress = macAddrToArray(info->p2p_device_addr);
+ params.dirInfo->nonce = byteArrToVec(info->nonce, DEVICE_IDENTITY_NONCE_LEN);
+ params.dirInfo->dirTag = byteArrToVec(info->tag, DEVICE_IDENTITY_TAG_LEN);
+ }
}
callWithEachP2pIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname),
@@ -1657,7 +1660,8 @@
void AidlManager::notifyP2pProvisionDiscovery(
struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin, const char *group_ifname)
+ unsigned int generated_pin, const char *group_ifname,
+ u16 pairing_bootstrapping_method)
{
if (!wpa_s || !dev_addr)
return;
@@ -1666,6 +1670,17 @@
p2p_iface_object_map_.end())
return;
+ int32_t aidl_pairing_bootstrapping_method = 0;
+ if (pairing_bootstrapping_method > 0) {
+ aidl_pairing_bootstrapping_method = convertP2pPairingBootstrappingMethodsToAidl(
+ pairing_bootstrapping_method);
+ if (aidl_pairing_bootstrapping_method == 0 || !areAidlServiceAndClientAtLeastVersion(4)) {
+ wpa_printf(MSG_ERROR, "Drop pairing bootstrapping message - method %d",
+ pairing_bootstrapping_method);
+ return;
+ }
+ }
+
std::string aidl_generated_pin;
if (generated_pin > 0) {
aidl_generated_pin =
@@ -1680,6 +1695,9 @@
params.status = static_cast<P2pProvDiscStatusCode>(status);
params.configMethods = config_methods;
params.generatedPin = aidl_generated_pin;
+ if (areAidlServiceAndClientAtLeastVersion(4)) {
+ params.pairingBootstrappingMethod = aidl_pairing_bootstrapping_method;
+ }
if (group_ifname != NULL) {
params.groupInterfaceName = misc_utils::charBufToString(group_ifname);
}
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.h b/wpa_supplicant/aidl/vendor/aidl_manager.h
index 667422f..3c18789 100644
--- a/wpa_supplicant/aidl/vendor/aidl_manager.h
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.h
@@ -116,7 +116,8 @@
void notifyP2pProvisionDiscovery(
struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
enum p2p_prov_disc_status status, u16 config_methods,
- unsigned int generated_pin, const char *group_ifname);
+ unsigned int generated_pin, const char *group_ifname,
+ u16 pairing_bootstrapping_method);
void notifyP2pSdResponse(
struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
const u8 *tlvs, size_t tlvs_len);
@@ -352,10 +353,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 +389,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 +505,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..2d8fa81 100644
--- a/wpa_supplicant/aidl/vendor/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/p2p_iface.cpp
@@ -496,8 +496,8 @@
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
- &P2pIface::reinvokeInternal, in_persistentNetworkId,
- in_peerAddress);
+ &P2pIface::reinvokeInternal, in_peerAddress, in_persistentNetworkId,
+ -1);
}
::ndk::ScopedAStatus P2pIface::configureExtListen(
@@ -1236,10 +1236,11 @@
ndk::ScopedAStatus P2pIface::provisionDiscoveryInternal(
const std::vector<uint8_t>& peer_address,
WpsProvisionMethod provision_method,
- uint32_t pairingBootstrappingMethod)
+ uint32_t pairing_bootstrapping_method)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
p2ps_provision* prov_param;
+ u16 bootstrap = 0;
const char* config_method_str = nullptr;
if (peer_address.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
@@ -1258,9 +1259,14 @@
config_method_str = kConfigMethodStrNone;
break;
}
- // TODO Handle pairing bootstrapping method when supplicant implementation is ready
+ if (provision_method == WpsProvisionMethod::NONE) {
+ bootstrap = convertAidlPairingBootstrappingMethodToWpa(pairing_bootstrapping_method);
+ if (bootstrap == 0) {
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+ }
if (wpas_p2p_prov_disc(
- wpa_s, peer_address.data(), config_method_str,
+ wpa_s, peer_address.data(), config_method_str, bootstrap,
WPAS_P2P_PD_FOR_GO_NEG, nullptr)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
@@ -1314,25 +1320,29 @@
}
ndk::ScopedAStatus P2pIface::reinvokeInternal(
+ const std::vector<uint8_t>& peer_address,
int32_t persistent_network_id,
- const std::vector<uint8_t>& peer_address)
+ int32_t device_identity_entry_id)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ struct wpa_ssid* ssid = NULL;
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
int edmg = wpa_s->conf->p2p_go_edmg;
- struct wpa_ssid* ssid =
- wpa_config_get_network(wpa_s->conf, persistent_network_id);
- if (ssid == NULL || ssid->disabled != 2) {
- return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
- }
+ bool p2p2 = device_identity_entry_id >= 0 && persistent_network_id == -1;
if (peer_address.size() != ETH_ALEN) {
return {createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
+ if (!p2p2) {
+ ssid = wpa_config_get_network(wpa_s->conf, persistent_network_id);
+ if (ssid == NULL || ssid->disabled != 2) {
+ return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
+ }
+ }
if (wpas_p2p_invite(
wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
- CONF_OPER_CHWIDTH_USE_HT, 0, he, edmg, is6GhzAllowed(wpa_s), false)) {
+ CONF_OPER_CHWIDTH_USE_HT, 0, he, edmg, is6GhzAllowed(wpa_s), p2p2)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
@@ -2125,8 +2135,16 @@
std::pair<int64_t, ndk::ScopedAStatus> P2pIface::getFeatureSetInternal()
{
- // TODO Fill the field when supplicant implementation is ready
- return {0, ndk::ScopedAStatus::ok()};
+ int64_t featureSet = 0;
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_P2P_FEATURE_V2) {
+ featureSet |= ISupplicantP2pIface::P2P_FEATURE_V2;
+ }
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_P2P_FEATURE_PCC_MODE) {
+ featureSet |= ISupplicantP2pIface::P2P_FEATURE_PCC_MODE_WPA3_COMPATIBILITY;
+ }
+ return {featureSet, ndk::ScopedAStatus::ok()};
}
std::pair<uint32_t, ndk::ScopedAStatus>
@@ -2250,23 +2268,74 @@
std::pair<P2pDirInfo, ndk::ScopedAStatus> P2pIface::getDirInfoInternal()
{
- // TODO Fill the field when supplicant implementation is ready
P2pDirInfo dirInfo = {};
+ char dir_info_buffer[100] = {0};
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int id = wpas_p2p_get_dira(wpa_s, dir_info_buffer, sizeof(dir_info_buffer));
+ if (id < 0) {
+ return {dirInfo, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+ }
+
+ std::istringstream dir_info_ss(dir_info_buffer);
+ std::string mac_str, nonce_str, dir_tag_str;
+ std::vector<uint8_t> mac_addr = std::vector<uint8_t>(ETH_ALEN);
+ std::vector<uint8_t> nonce = std::vector<uint8_t>(DEVICE_IDENTITY_NONCE_LEN);
+ std::vector<uint8_t> dir_tag = std::vector<uint8_t>(DEVICE_IDENTITY_TAG_LEN);
+ // Extract MAC address
+ std::getline(dir_info_ss, mac_str, ' ');
+ if (hexstr2bin(mac_str.c_str(), mac_addr.data(), ETH_ALEN)) {
+ wpa_printf(MSG_ERROR, "Failed to get MAC address from DIR Info");
+ return {dirInfo, createStatusWithMsg(SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Failed to parse MAC address.")};
+ }
+ // Extract nonce
+ std::getline(dir_info_ss, nonce_str, ' ');
+ if (hexstr2bin(nonce_str.c_str(), nonce.data(), DEVICE_IDENTITY_NONCE_LEN)) {
+ return {dirInfo, createStatusWithMsg(SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Failed to parse nonce.")};
+ }
+ // Extract dir tag
+ std::getline(dir_info_ss, dir_tag_str, ' ');
+ if (hexstr2bin(dir_tag_str.c_str(), dir_tag.data(), DEVICE_IDENTITY_TAG_LEN)) {
+ return {dirInfo, createStatusWithMsg(SupplicantStatusCode::FAILURE_UNKNOWN,
+ "Failed to parse dir tag.")};
+ }
+
+ std::copy_n(mac_addr.begin(), ETH_ALEN, dirInfo.deviceInterfaceMacAddress.begin());
+ dirInfo.nonce = nonce;
+ dirInfo.dirTag = dir_tag;
+ dirInfo.cipherVersion = P2pDirInfo::CipherVersion::DIRA_CIPHER_VERSION_128_BIT;
+
return {dirInfo, ndk::ScopedAStatus::ok()};
}
std::pair<int32_t, ndk::ScopedAStatus> P2pIface::validateDirInfoInternal(
const P2pDirInfo& dirInfo)
{
- // TODO Fill the field when supplicant implementation is ready
- return {0, ndk::ScopedAStatus::ok()};
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (dirInfo.cipherVersion != P2pDirInfo::CipherVersion::DIRA_CIPHER_VERSION_128_BIT ||
+ dirInfo.deviceInterfaceMacAddress.size() != ETH_ALEN ||
+ dirInfo.nonce.size() != DEVICE_IDENTITY_NONCE_LEN ||
+ dirInfo.dirTag.size() != DEVICE_IDENTITY_TAG_LEN) {
+ return {-1, createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
+ }
+
+ int32_t id = wpas_p2p_validate_dira(wpa_s, dirInfo.deviceInterfaceMacAddress.data(),
+ DIRA_CIPHER_VERSION_128, dirInfo.nonce.data(), dirInfo.dirTag.data());
+ if (id >= 0) {
+ return {id, ndk::ScopedAStatus::ok()};
+ }
+ return {-1, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
ndk::ScopedAStatus P2pIface::reinvokePersistentGroupInternal(
const P2pReinvokePersistentGroupParams& reinvokeGroupParams)
{
- // TODO Fill the field when supplicant implementation is ready
- return ndk::ScopedAStatus::ok();
+ std::vector<uint8_t> peerMacAddressVec {
+ reinvokeGroupParams.peerMacAddress.begin(),
+ reinvokeGroupParams.peerMacAddress.end()};
+ return reinvokeInternal(peerMacAddressVec, reinvokeGroupParams.persistentNetworkId,
+ reinvokeGroupParams.deviceIdentityEntryId);
}
/**
diff --git a/wpa_supplicant/aidl/vendor/p2p_iface.h b/wpa_supplicant/aidl/vendor/p2p_iface.h
index 1c38437..9bc7874 100644
--- a/wpa_supplicant/aidl/vendor/p2p_iface.h
+++ b/wpa_supplicant/aidl/vendor/p2p_iface.h
@@ -253,8 +253,9 @@
const std::vector<uint8_t>& go_device_address,
const std::vector<uint8_t>& peer_address);
ndk::ScopedAStatus reinvokeInternal(
+ const std::vector<uint8_t>& peer_address,
int32_t persistent_network_id,
- const std::vector<uint8_t>& peer_address);
+ int32_t device_identity_entry_id);
ndk::ScopedAStatus configureExtListenInternal(
uint32_t period_in_millis, uint32_t interval_in_millis);
ndk::ScopedAStatus setListenChannelInternal(
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..57bfbed 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,9 @@
#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(no_auto_peer);
- INT(mesh_fwding);
+#ifdef CONFIG_MESH
+ INT_DEF(mesh_fwding, DEFAULT_MESH_FWDING);
+#endif /* CONFIG_MESH */
INT(frequency);
INT(enable_edmg);
INT(edmg_channel);
@@ -883,7 +896,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 +914,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 +1689,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 d5a34c5..aeff965 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -27,6 +27,7 @@
#include "sme.h"
#include "notify.h"
#include "aidl/vendor/aidl.h"
+#include "aidl/mainline/callback_bridge.h"
#ifdef MAINLINE_SUPPLICANT
#include "aidl/mainline/service.h"
@@ -928,12 +929,16 @@
const u8 *src, u16 bootstrap_method)
{
wpas_dbus_signal_p2p_bootstrap_req(wpa_s, src, bootstrap_method);
+ wpas_aidl_notify_p2p_bootstrap_request(wpa_s, src, P2P_SC_SUCCESS, bootstrap_method, NULL);
}
-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);
+ wpas_aidl_notify_p2p_bootstrap_response(wpa_s, src, status, bootstrap_method, NULL);
}
#endif /* CONFIG_P2P */
@@ -1533,6 +1538,8 @@
wpas_aidl_notify_usd_service_discovered(wpa_s, srv_proto_type,
subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
+ mainline_aidl_notify_usd_service_discovered(wpa_s, srv_proto_type,
+ subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
wpas_dbus_signal_nan_discovery_result(wpa_s, srv_proto_type,
subscribe_id, peer_publish_id,
@@ -1563,6 +1570,8 @@
wpas_aidl_notify_usd_publish_replied(wpa_s, srv_proto_type,
publish_id, peer_subscribe_id, peer_addr, ssi, ssi_len);
+ mainline_aidl_notify_usd_publish_replied(wpa_s, srv_proto_type,
+ publish_id, peer_subscribe_id, peer_addr, ssi, ssi_len);
wpas_dbus_signal_nan_replied(wpa_s, srv_proto_type, publish_id,
peer_subscribe_id, peer_addr,
@@ -1588,6 +1597,8 @@
wpas_aidl_notify_usd_message_received(wpa_s, id, peer_instance_id,
peer_addr, ssi, ssi_len);
+ mainline_aidl_notify_usd_message_received(wpa_s, id, peer_instance_id,
+ peer_addr, ssi, ssi_len);
wpas_dbus_signal_nan_receive(wpa_s, id, peer_instance_id, peer_addr,
ssi, ssi_len);
@@ -1616,8 +1627,9 @@
wpa_msg_global(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED
"publish_id=%d reason=%s",
publish_id, nan_reason_txt(reason));
-
+
wpas_aidl_notify_usd_publish_terminated(wpa_s, publish_id, reason);
+ mainline_aidl_notify_usd_publish_terminated(wpa_s, publish_id, reason);
wpas_dbus_signal_nan_publish_terminated(wpa_s, publish_id,
nan_reason_txt(reason));
@@ -1633,6 +1645,7 @@
subscribe_id, nan_reason_txt(reason));
wpas_aidl_notify_usd_subscribe_terminated(wpa_s, subscribe_id, reason);
+ mainline_aidl_notify_usd_subscribe_terminated(wpa_s, subscribe_id, reason);
wpas_dbus_signal_nan_subscribe_terminated(wpa_s, subscribe_id,
nan_reason_txt(reason));
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)