[wpa_supplicant] Cumulative patch from fe468b071
Bug: 124017368
Test: Device boots up and connects to WPA3/OWE wifi networks, run traffic.
Test: Able to turn on/off softap, associate wifi STA, run traffic.
Test: DPP functional test.
Test: Regression test passed (Bug: 124301325)
fe468b071 HE: Fix set_he_cap() parsing of config options for MU EDCA Params
f3a841bbf Do not disassociate not-associated STA on timeout
91205c8eb OpenSSL: Fix uninitialized variable in CRL reloading corner case
092a19222 Use for_each_element() in ieee802_11_parse_elems()
b50a63896 common: Use for_each_element_id/_extid for get_ie/get_ie_ext/get_vendor_ie
b64479742 common: Use for_each_element_id() in mb_ies_info_by_ies()
9008048f0 common: Use for_each_element_id() in ieee802_11_vendor_ie_concat()
eb84238df common: Use for_each_element() in ieee802_11_ie_count()
0e0c31bdc common: Add strongly typed element iteration macros
525923b1d tests: EAPOL-Key fuzzing tool
02a0a2393 RSN: Do not start preauthentication timer without candidates
1e5506588 JSON: Fix string parsing when \\ escape is at the end of buffer
0dedcb315 JSON: Fix parsing of a number from the end of the buffer
79fa1b453 tests: JSON parser fuzzer
62269c8d8 TLS: Fix X.509 certificate name conversion into empty string
3eae9766b TLS: Fix ASN.1 parsing with no room for the header
fbc2123a1 TLS: Fix AlertDescription for missing partial processing case
1ac9c020b tests: TLS fuzzing tool
f3cca8b1e TLS server: Check credentials have been configured before using them
19dd7a736 TLS server: Local failure information on verify_data mismatch
f08ab18bf TLS server: Add internal callbacks get_failed, get_*_alerts
b642ab406 TLS server: More complete logging of ClientHello decode errors
fdd8a2f0b TLS client: Fix peer certificate event checking for probing
e5bffe1aa OpenSSL: Add more handshake message names to debug
21cd8f831 nl80211: Use wpa_ssid_txt() for debug messages more consistently
bbdb50146 Note HT overrides in debug log only if set
f2a6ac63e P2P: Update find_start timer only when p2p_scan is started.
c4e90da6d MBO: Move the WNM-Notification subtype definitions to common location
105b14f54 HS 2.0: Update the T&C Acceptance subtype value
65b487ae5 HS 2.0: Add QUIET=1 support for building hs20-osu-client
73f285dad Add FT-PSK to GET_CAPABILITY key_mgmt
6110753b1 nl80211: Clear PMKID add command message buffer
0fa33e05b nl80211: Clear connect command message buffer
b14e8ea1d nl80211: Request kernel to trim off payload of netlink requests from acks
789b48bb4 EAP peer: Clear temporary message buffers before freeing
8f99a3c26 Clear config item writing buffer before freeing it
a68e9b698 D-Bus: Fix P2P DeleteService dict iteration
0607346f1 D-Bus: Fix a memory leak in DeleteService handler
d05dda61d PEAP: Explicitly clear temporary keys from memory when using CMK
4e1cd3468 EAP-PEAP: Derive EMSK and use 128-octet derivation for MSK
d8c20ec59 DPP: Clear dpp_listen_freq on remain-on-channel failure
59fa20538 P2P: Allow the avoid channels for P2P discovery/negotiation
e34cd9f06 WNM: Fix WNM-Sleep Mode Request bounds checking
159a7fbde crl_reload_interval: Add CRL reloading support
83c860813 AP: Add wpa_psk_file reloading in runtime
ec5c39a55 AP: Allow identifying which passphrase station used with wpa_psk_file
b08c9ad0c AP: Expose PMK outside of wpa_auth module
89896c000 tests: Use python3 compatible print statement
bab493b90 tests: Use python3 compatible "except" statement
0dab47733 Write multi_ap_backhaul_sta to wpa_supplicant config
98251c6f2 dbus: Document more possible BSS/RSA/KeyMgmt values
1e591df06 Check supported types in wpas_mac_addr_rand_scan_set()
c85249aa1 Fix test compilation error related to sme_event_unprot_disconnect()
42d308635 SAE: Advertise Password Identifier use
59c693064 HS 2.0 server: Command line option to fetch the version information
2d1762fa4 HS 2.0 server: Alternative subrem updateNode for certificate credentials
d97cf2a11 HS 2.0 server: Use noMOUpdate in client certificate subrem
13a200a92 FILS: Remove notes about experimental implementation
86d4e0537 dbus: Expose support of SAE key management in BSS properties
Change-Id: Id507b73f1f4a2e356cbcd3bfcfb9dcd23c8fd9e0
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index 1dc7547..c81ad64 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -140,7 +140,7 @@
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 945bdc0..5d0115c 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/README b/README
index 43b684c..a9f8069 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These programs are licensed under the BSD license (the one with
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 9be3613..c769bc7 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -246,6 +246,12 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+L_CFLAGS += -DCONFIG_OCV
+OBJS += src/common/ocv.c
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index d2b669b..f1366b4 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,60 @@
ChangeLog for hostapd
+2018-12-02 - v2.7
+ * fixed WPA packet number reuse with replayed messages and key
+ reinstallation
+ [http://w1.fi/security/2017-1/] (CVE-2017-13082)
+ * added support for FILS (IEEE 802.11ai) shared key authentication
+ * added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
+ and transition mode defined by WFA)
+ * added support for DPP (Wi-Fi Device Provisioning Protocol)
+ * FT:
+ - added local generation of PMK-R0/PMK-R1 for FT-PSK
+ (ft_psk_generate_local=1)
+ - replaced inter-AP protocol with a cleaner design that is more
+ easily extensible; this breaks backward compatibility and requires
+ all APs in the ESS to be updated at the same time to maintain FT
+ functionality
+ - added support for wildcard R0KH/R1KH
+ - replaced r0_key_lifetime (minutes) parameter with
+ ft_r0_key_lifetime (seconds)
+ - fixed wpa_psk_file use for FT-PSK
+ - fixed FT-SAE PMKID matching
+ - added expiration to PMK-R0 and PMK-R1 cache
+ - added IEEE VLAN support (including tagged VLANs)
+ - added support for SHA384 based AKM
+ * SAE
+ - fixed some PMKSA caching cases with SAE
+ - added support for configuring SAE password separately of the
+ WPA2 PSK/passphrase
+ - added option to require MFP for SAE associations
+ (sae_require_pmf=1)
+ - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
+ for SAE;
+ note: this is not backwards compatible, i.e., both the AP and
+ station side implementations will need to be update at the same
+ time to maintain interoperability
+ - added support for Password Identifier
+ * hostapd_cli: added support for command history and completion
+ * added support for requesting beacon report
+ * large number of other fixes, cleanup, and extensions
+ * added option to configure EAPOL-Key retry limits
+ (wpa_group_update_count and wpa_pairwise_update_count)
+ * removed all PeerKey functionality
+ * fixed nl80211 AP mode configuration regression with Linux 4.15 and
+ newer
+ * added support for using wolfSSL cryptographic library
+ * fixed some 20/40 MHz coexistence cases where the BSS could drop to
+ 20 MHz even when 40 MHz would be allowed
+ * Hotspot 2.0
+ - added support for setting Venue URL ANQP-element (venue_url)
+ - added support for advertising Hotspot 2.0 operator icons
+ - added support for Roaming Consortium Selection element
+ - added support for Terms and Conditions
+ - added support for OSEN connection in a shared RSN BSS
+ * added support for using OpenSSL 1.1.1
+ * added EAP-pwd server support for salted passwords
+
2016-10-02 - v2.6
* fixed EAP-pwd last fragment validation
[http://w1.fi/security/2015-7/] (CVE-2015-5314)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 2ce8b7d..dd3816e 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -278,6 +278,12 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+CFLAGS += -DCONFIG_OCV
+OBJS += ../src/common/ocv.o
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -1095,6 +1101,9 @@
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
OBJS += ../src/crypto/random.o
HOBJS += ../src/crypto/random.o
HOBJS += ../src/utils/eloop.o
diff --git a/hostapd/README b/hostapd/README
index 298391b..1f30d7e 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/hostapd/android.config b/hostapd/android.config
index 49cfe94..4502a60 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -50,6 +50,9 @@
# Driver support is also needed for IEEE 802.11w.
CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Integrated EAP server
#CONFIG_EAP=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index b26da71..c8ff7a0 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -37,7 +37,7 @@
const char *fname)
{
FILE *f;
- char buf[128], *pos, *pos2;
+ char buf[128], *pos, *pos2, *pos3;
int line = 0, vlan_id;
struct hostapd_vlan *vlan;
@@ -82,7 +82,10 @@
pos2 = pos;
while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
pos2++;
- *pos2 = '\0';
+
+ if (*pos2 != '\0')
+ *(pos2++) = '\0';
+
if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
"in '%s'", line, fname);
@@ -90,6 +93,13 @@
return -1;
}
+ while (*pos2 == ' ' || *pos2 == '\t')
+ pos2++;
+ pos3 = pos2;
+ while (*pos3 != ' ' && *pos3 != '\t' && *pos3 != '\0')
+ pos3++;
+ *pos3 = '\0';
+
vlan = os_zalloc(sizeof(*vlan));
if (vlan == NULL) {
wpa_printf(MSG_ERROR, "Out of memory while reading "
@@ -102,6 +112,7 @@
vlan->vlan_desc.untagged = vlan_id;
vlan->vlan_desc.notempty = !!vlan_id;
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+ os_strlcpy(vlan->bridge, pos2, sizeof(vlan->bridge));
vlan->next = bss->vlan;
bss->vlan = vlan;
}
@@ -1368,6 +1379,30 @@
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+
+static u8 find_bit_offset(u8 val)
+{
+ u8 res = 0;
+
+ for (; val; val >>= 1) {
+ if (val & 1)
+ break;
+ res++;
+ }
+
+ return res;
+}
+
+
+static u8 set_he_cap(int val, u8 mask)
+{
+ return (u8) (mask & (val << find_bit_offset(mask)));
+}
+
+#endif /* CONFIG_IEEE80211AX */
+
+
#ifdef CONFIG_INTERWORKING
static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
int line)
@@ -2254,10 +2289,16 @@
flags |= TLS_CONN_DISABLE_TIME_CHECKS;
if (os_strstr(val, "[DISABLE-TLSv1.0]"))
flags |= TLS_CONN_DISABLE_TLSv1_0;
+ if (os_strstr(val, "[ENABLE-TLSv1.0]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_0;
if (os_strstr(val, "[DISABLE-TLSv1.1]"))
flags |= TLS_CONN_DISABLE_TLSv1_1;
+ if (os_strstr(val, "[ENABLE-TLSv1.1]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_1;
if (os_strstr(val, "[DISABLE-TLSv1.2]"))
flags |= TLS_CONN_DISABLE_TLSv1_2;
+ if (os_strstr(val, "[ENABLE-TLSv1.2]"))
+ flags |= TLS_CONN_ENABLE_TLSv1_2;
if (os_strstr(val, "[DISABLE-TLSv1.3]"))
flags |= TLS_CONN_DISABLE_TLSv1_3;
if (os_strstr(val, "[ENABLE-TLSv1.3]"))
@@ -2478,6 +2519,10 @@
bss->private_key_passwd = os_strdup(pos);
} else if (os_strcmp(buf, "check_crl") == 0) {
bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "check_crl_strict") == 0) {
+ bss->check_crl_strict = atoi(pos);
+ } else if (os_strcmp(buf, "crl_reload_interval") == 0) {
+ bss->crl_reload_interval = atoi(pos);
} else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "tls_flags") == 0) {
@@ -2494,6 +2539,9 @@
} else if (os_strcmp(buf, "openssl_ciphers") == 0) {
os_free(bss->openssl_ciphers);
bss->openssl_ciphers = os_strdup(pos);
+ } else if (os_strcmp(buf, "openssl_ecdh_curves") == 0) {
+ os_free(bss->openssl_ecdh_curves);
+ bss->openssl_ecdh_curves = os_strdup(pos);
} else if (os_strcmp(buf, "fragment_size") == 0) {
bss->fragment_size = atoi(pos);
#ifdef EAP_SERVER_FAST
@@ -3148,7 +3196,7 @@
line, val);
return 1;
}
- conf->send_probe_response = val;
+ bss->send_probe_response = val;
} else if (os_strcmp(buf, "supported_rates") == 0) {
if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
@@ -3316,6 +3364,12 @@
return 1;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ } else if (os_strcmp(buf, "ocv") == 0) {
+ bss->ocv = atoi(pos);
+ if (bss->ocv && !bss->ieee80211w)
+ bss->ieee80211w = 1;
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211N
} else if (os_strcmp(buf, "ieee80211n") == 0) {
conf->ieee80211n = atoi(pos);
@@ -3369,6 +3423,90 @@
conf->he_op.he_twt_required = atoi(pos);
} else if (os_strcmp(buf, "he_rts_threshold") == 0) {
conf->he_op.he_rts_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_EDCA_PARAM_SET_COUNT);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_q_ack") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_Q_ACK);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_queue_request") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_QUEUE_REQUEST);
+ } else if (os_strcmp(buf, "he_mu_edca_qos_info_txop_request") == 0) {
+ conf->he_mu_edca.he_qos_info |=
+ set_he_cap(atoi(pos), HE_QOS_INFO_TXOP_REQUEST);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_be_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_be_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_bk_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_bk_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vi_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_vi_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aifsn") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_AIFSN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_acm") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACM);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_aci") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ACI_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ACI);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmin") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMIN);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_ecwmax") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_ECW_IDX] |=
+ set_he_cap(atoi(pos), HE_MU_AC_PARAM_ECWMAX);
+ } else if (os_strcmp(buf, "he_mu_edca_ac_vo_timer") == 0) {
+ conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
+ atoi(pos) & 0xff;
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -3717,6 +3855,16 @@
#ifdef CONFIG_HS20
} else if (os_strcmp(buf, "hs20") == 0) {
bss->hs20 = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_release") == 0) {
+ int val = atoi(pos);
+
+ if (val < 1 || val > (HS20_VERSION >> 4) + 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Unsupported hs20_release: %s",
+ line, pos);
+ return 1;
+ }
+ bss->hs20_release = val;
} else if (os_strcmp(buf, "disable_dgaf") == 0) {
bss->disable_dgaf = atoi(pos);
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
@@ -3807,6 +3955,9 @@
} 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) {
@@ -4111,6 +4262,22 @@
} else if (os_strcmp(buf, "coloc_intf_reporting") == 0) {
bss->coloc_intf_reporting = atoi(pos);
#endif /* CONFIG_OWE */
+ } else if (os_strcmp(buf, "multi_ap") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 3) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid multi_ap '%s'",
+ line, buf);
+ return -1;
+ }
+
+ bss->multi_ap = val;
+ } else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) {
+ conf->rssi_reject_assoc_rssi = atoi(pos);
+ } else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
+ conf->rssi_reject_assoc_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "pbss") == 0) {
+ bss->pbss = atoi(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index e539a09..df2524a 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1488,6 +1488,63 @@
}
+static int
+hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ struct hostapd_wpa_psk *psk;
+ const u8 *pmk;
+ int pmk_len;
+ int pmk_match;
+ int sta_match;
+ int bss_match;
+ int reason;
+
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+
+ for (psk = hapd->conf->ssid.wpa_psk; pmk && psk; psk = psk->next) {
+ pmk_match = PMK_LEN == pmk_len &&
+ os_memcmp(psk->psk, pmk, pmk_len) == 0;
+ sta_match = psk->group == 0 &&
+ os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0;
+ bss_match = psk->group == 1;
+
+ if (pmk_match && (sta_match || bss_match))
+ return 0;
+ }
+
+ wpa_printf(MSG_INFO, "STA " MACSTR
+ " PSK/passphrase no longer valid - disconnect",
+ MAC2STR(sta->addr));
+ reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
+ hostapd_drv_sta_deauth(hapd, sta->addr, reason);
+ ap_sta_deauthenticate(hapd, sta, reason);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ int err;
+
+ hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
+
+ err = hostapd_setup_wpa_psk(conf);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "Reloading WPA-PSK passwords failed: %d",
+ err);
+ return -1;
+ }
+
+ ap_for_each_sta(hapd, hostapd_ctrl_iface_kick_mismatch_psk_sta_iter,
+ NULL);
+
+ return 0;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd)
@@ -2134,7 +2191,7 @@
if (!pos)
return -1;
pos++;
- if (hexstr2bin(pos, seq, sizeof(6)) < 0)
+ if (hexstr2bin(pos, seq, sizeof(seq)) < 0)
return -1;
pos += 2 * 6;
if (*pos != ' ')
@@ -3013,6 +3070,9 @@
} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
if (hostapd_ctrl_iface_enable(hapd->iface))
reply_len = -1;
+ } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) {
+ if (hostapd_ctrl_iface_reload_wpa_psk(hapd))
+ reply_len = -1;
} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
if (hostapd_ctrl_iface_reload(hapd->iface))
reply_len = -1;
@@ -3229,7 +3289,7 @@
if (hostapd_dpp_configurator_remove(hapd, buf + 24) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
- if (hostapd_dpp_configurator_sign(hapd, buf + 22) < 0)
+ if (hostapd_dpp_configurator_sign(hapd, buf + 21) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
reply_len = hostapd_dpp_configurator_get_key(hapd,
@@ -3506,18 +3566,18 @@
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(hapd->conf->ctrl_interface, -1,
- hapd->conf->ctrl_interface_gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(hapd->conf->ctrl_interface, -1,
+ hapd->conf->ctrl_interface_gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
return -1;
}
if (!hapd->conf->ctrl_interface_gid_set &&
hapd->iface->interfaces->ctrl_iface_group &&
- chown(hapd->conf->ctrl_interface, -1,
- hapd->iface->interfaces->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(hapd->conf->ctrl_interface, -1,
+ hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
return -1;
}
@@ -3590,16 +3650,16 @@
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ lchown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
strerror(errno));
goto fail;
}
if (!hapd->conf->ctrl_interface_gid_set &&
hapd->iface->interfaces->ctrl_iface_group &&
- chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ lchown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface/ifname]: %s",
strerror(errno));
goto fail;
}
@@ -4273,9 +4333,9 @@
goto fail;
}
} else if (interface->ctrl_iface_group &&
- chown(interface->global_iface_path, -1,
- interface->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(interface->global_iface_path, -1,
+ interface->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
goto fail;
}
@@ -4332,8 +4392,8 @@
}
if (interface->ctrl_iface_group &&
- chown(fname, -1, interface->ctrl_iface_group) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ lchown(fname, -1, interface->ctrl_iface_group) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface]: %s",
strerror(errno));
goto fail;
}
diff --git a/hostapd/defconfig b/hostapd/defconfig
index c67c662..ea5e2c9 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -31,7 +31,7 @@
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
-#CONFIG_LIBNL32=y
+CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
@@ -53,6 +53,9 @@
# IEEE 802.11w (management frame protection)
CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Integrated EAP server
CONFIG_EAP=y
@@ -249,6 +252,11 @@
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
@@ -356,8 +364,6 @@
#CONFIG_TAXONOMY=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-# Note: This is an experimental and not yet complete implementation. This
-# should not be enabled for production use.
#CONFIG_FILS=y
# FILS shared key authentication with PFS
#CONFIG_FILS_SK_PFS=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index a005217..ab37f03 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -438,6 +438,13 @@
wmm_ac_vo_acm=0
# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+# Enable Multi-AP functionality
+# 0 = disabled (default)
+# 1 = AP support backhaul BSS
+# 2 = AP support fronthaul BSS
+# 3 = AP supports both backhaul BSS and fronthaul BSS
+#multi_ap=0
+
# Static WEP key configuration
#
# The key number to use when transmitting.
@@ -794,6 +801,30 @@
# unsigned integer = duration in units of 16 us
#he_rts_threshold=0
+#he_mu_edca_qos_info_param_count
+#he_mu_edca_qos_info_q_ack
+#he_mu_edca_qos_info_queue_request=1
+#he_mu_edca_qos_info_txop_request
+#he_mu_edca_ac_be_aifsn=0
+#he_mu_edca_ac_be_ecwmin=15
+#he_mu_edca_ac_be_ecwmax=15
+#he_mu_edca_ac_be_timer=255
+#he_mu_edca_ac_bk_aifsn=0
+#he_mu_edca_ac_bk_aci=1
+#he_mu_edca_ac_bk_ecwmin=15
+#he_mu_edca_ac_bk_ecwmax=15
+#he_mu_edca_ac_bk_timer=255
+#he_mu_edca_ac_vi_ecwmin=15
+#he_mu_edca_ac_vi_ecwmax=15
+#he_mu_edca_ac_vi_aifsn=0
+#he_mu_edca_ac_vi_aci=2
+#he_mu_edca_ac_vi_timer=255
+#he_mu_edca_ac_vo_aifsn=0
+#he_mu_edca_ac_vo_aci=3
+#he_mu_edca_ac_vo_ecwmin=15
+#he_mu_edca_ac_vo_ecwmax=15
+#he_mu_edca_ac_vo_timer=255
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -891,18 +922,57 @@
# valid CRL signed by the CA is required to be included in the ca_cert file.
# This can be done by using PEM format for CA certificate and CRL and
# concatenating these into one file. Whenever CRL changes, hostapd needs to be
-# restarted to take the new CRL into use.
+# restarted to take the new CRL into use. Alternatively, crl_reload_interval can
+# be used to configure periodic updating of the loaded CRL information.
# 0 = do not verify CRLs (default)
# 1 = check the CRL of the user certificate
# 2 = check all CRLs in the certificate path
#check_crl=1
+# Specify whether to ignore certificate CRL validity time mismatches with
+# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID.
+#
+# 0 = ignore errors
+# 1 = do not ignore errors (default)
+#check_crl_strict=1
+
+# CRL reload interval in seconds
+# This can be used to reload ca_cert file and the included CRL on every new TLS
+# session if difference between last reload and the current reload time in
+# seconds is greater than crl_reload_interval.
+# Note: If interval time is very short, CPU overhead may be negatively affected
+# and it is advised to not go below 300 seconds.
+# This is applicable only with check_crl values 1 and 2.
+# 0 = do not reload CRLs (default)
+# crl_reload_interval = 300
+
# TLS Session Lifetime in seconds
# This can be used to allow TLS sessions to be cached and resumed with an
# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
# (default: 0 = session caching and resumption disabled)
#tls_session_lifetime=3600
+# TLS flags
+# [ALLOW-SIGN-RSA-MD5] = allow MD5-based certificate signatures (depending on
+# the TLS library, these may be disabled by default to enforce stronger
+# security)
+# [DISABLE-TIME-CHECKS] = ignore certificate validity time (this requests
+# the TLS library to accept certificates even if they are not currently
+# valid, i.e., have expired or have not yet become valid; this should be
+# used only for testing purposes)
+# [DISABLE-TLSv1.0] = disable use of TLSv1.0
+# [ENABLE-TLSv1.0] = explicitly enable use of TLSv1.0 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.1] = disable use of TLSv1.1
+# [ENABLE-TLSv1.1] = explicitly enable use of TLSv1.1 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.2] = disable use of TLSv1.2
+# [ENABLE-TLSv1.2] = explicitly enable use of TLSv1.2 (this allows
+# systemwide TLS policies to be overridden)
+# [DISABLE-TLSv1.3] = disable use of TLSv1.3
+# [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default)
+#tls_flags=[flag1][flag2]...
+
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@@ -1104,8 +1174,8 @@
# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
# VLANID as a string). Optionally, the local MAC ACL list (accept_mac_file) can
# be used to set static client MAC address to VLAN ID mapping.
-# 0 = disabled (default)
-# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# 0 = disabled (default); only VLAN IDs from accept_mac_file will be used
+# 1 = optional; use default interface if RADIUS server does not include VLAN ID
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
#dynamic_vlan=0
@@ -1128,6 +1198,7 @@
# white space (space or tab).
# If no entries are provided by this file, the station is statically mapped
# to <bss-iface>.<vlan-id> interfaces.
+# Each line can optionally also contain the name of a bridge to add the VLAN to
#vlan_file=/etc/hostapd.vlan
# Interface where 802.1q tagged packets should appear when a RADIUS server is
@@ -1418,6 +1489,13 @@
# dot11AssociationSAQueryRetryTimeout, 1...4294967295
#assoc_sa_query_retry_timeout=201
+# ocv: Operating Channel Validation
+# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this automatically also enables ieee80211w, if not yet enabled.
+# 0 = disabled (default)
+# 1 = enabled
+#ocv=1
+
# disable_pmksa_caching: Disable PMKSA caching
# This parameter can be used to disable caching of PMKSA created through EAP
# authentication. RSN preauthentication may still end up using PMKSA caching if
@@ -2273,6 +2351,21 @@
# Default is 0 = OCE disabled
#oce=0
+# RSSI-based assocition rejection
+#
+# Reject STA association if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+# Note: This rejection happens based on a signal strength detected while
+# receiving a single frame and as such, there is significant risk of the value
+# not being accurate and this resulting in valid stations being rejected. As
+# such, this functionality is not recommended to be used for purposes other than
+# testing.
+#rssi_reject_assoc_rssi=-75
+#
+# Association retry delay in seconds allowed by the STA if RSSI has not met the
+# threshold (range: 0..255, default=30).
+#rssi_reject_assoc_timeout=30
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk
index 0a9499a..834d441 100644
--- a/hostapd/hostapd.wpa_psk
+++ b/hostapd/hostapd.wpa_psk
@@ -3,7 +3,10 @@
# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
# characters or as a 256-bit hex PSK (64 hex digits).
+# An optional key identifier can be added by prefixing the line with
+# keyid=<keyid_string>
00:00:00:00:00:00 secret passphrase
00:11:22:33:44:55 another passphrase
00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+keyid=example_id 00:11:22:33:44:77 passphrase with keyid
00:00:00:00:00:00 another passphrase for all STAs
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index fbec5d2..23c592a 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
/*
* hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,7 +21,7 @@
static const char *const hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
@@ -1443,6 +1443,13 @@
}
+static int hostapd_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
+}
+
+
static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1480,6 +1487,20 @@
}
+static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "REQ_BEACON", 2, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "RELOAD_WPA_PSK");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1637,9 +1658,11 @@
{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
NULL,
"*|<id> = remove DPP configurator" },
- { "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_get_key,
+ { "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
NULL,
"<id> = Get DPP configurator's private key" },
+ { "dpp_configurator_sign", hostapd_cli_cmd_dpp_configurator_sign, NULL,
+ "conf=<role> configurator=<id> = generate self DPP configuration" },
{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
"add PKEX code" },
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
@@ -1651,6 +1674,10 @@
"=Add/Delete/Show/Clear deny MAC ACL" },
{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
"<addr> = poll a STA to check connectivity with a QoS null frame" },
+ { "req_beacon", hostapd_cli_cmd_req_beacon, NULL,
+ "<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
+ { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
+ "= reload wpa_psk_file only" },
{ NULL, NULL, NULL, NULL }
};
diff --git a/hostapd/main.c b/hostapd/main.c
index dbe065e..e613c04 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -255,7 +255,7 @@
*
* This function is used to parse configuration file for a full interface (one
* or more BSSes sharing the same radio) and allocate memory for the BSS
- * interfaces. No actiual driver operations are started.
+ * interfaces. No actual driver operations are started.
*/
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
@@ -458,7 +458,7 @@
"hostapd v" VERSION_STR "\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
- "Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -877,27 +877,8 @@
*/
interfaces.terminate_on_error = interfaces.count;
for (i = 0; i < interfaces.count; i++) {
- if (hostapd_driver_init(interfaces.iface[i]))
- goto out;
-#ifdef CONFIG_MBO
- for (j = 0; j < interfaces.iface[i]->num_bss; j++) {
- struct hostapd_data *hapd = interfaces.iface[i]->bss[j];
-
- if (hapd && (hapd->conf->oce & OCE_STA_CFON) &&
- (interfaces.iface[i]->drv_flags &
- WPA_DRIVER_FLAGS_OCE_STA_CFON))
- hapd->enable_oce = OCE_STA_CFON;
-
- if (hapd && (hapd->conf->oce & OCE_AP) &&
- (interfaces.iface[i]->drv_flags &
- WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
- /* TODO: Need to add OCE-AP support */
- wpa_printf(MSG_ERROR,
- "OCE-AP feature is not yet supported");
- }
- }
-#endif /* CONFIG_MBO */
- if (hostapd_setup_interface(interfaces.iface[i]))
+ if (hostapd_driver_init(interfaces.iface[i]) ||
+ hostapd_setup_interface(interfaces.iface[i]))
goto out;
}
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
index 2fc3012..258d841 100755
--- a/hostapd/wps-ap-nfc.py
+++ b/hostapd/wps-ap-nfc.py
@@ -26,7 +26,7 @@
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -42,19 +42,19 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find hostapd: ", error
+ except OSError as error:
+ print("Could not find hostapd: ", error)
return None
if len(ifaces) < 1:
- print "No hostapd control interface found"
+ print("No hostapd control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -133,23 +133,23 @@
def process_request(self, request):
summary("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
- print str(request).encode("hex")
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
+ print(str(request).encode("hex"))
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel()
if data is None:
summary("Could not get handover select carrier record from hostapd")
continue
- print "Handover select carrier record from hostapd:"
- print data.encode("hex")
+ print("Handover select carrier record from hostapd:")
+ print(data.encode("hex"))
if "OK" in wpas_report_handover(carrier.record, data):
success_report("Handover reported successfully")
else:
@@ -158,12 +158,12 @@
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -174,7 +174,7 @@
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to hostapd")
success = wpas_tag_read(tag.ndef.message)
@@ -193,7 +193,7 @@
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -211,7 +211,7 @@
summary("Could not get WPS config token from hostapd")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -224,7 +224,7 @@
summary("Could not get WPS password token from hostapd")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -233,11 +233,11 @@
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = wps_tag_read(tag)
if only_one and success:
global continue_loop
@@ -250,13 +250,13 @@
def llcp_startup(clf, llc):
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global srv
@@ -304,7 +304,7 @@
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-config":
@@ -317,15 +317,15 @@
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
llcp={'on-startup': llcp_startup,
'on-connect': llcp_connected}):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/hs20/client/.gitignore b/hs20/client/.gitignore
new file mode 100644
index 0000000..d2fd60f
--- /dev/null
+++ b/hs20/client/.gitignore
@@ -0,0 +1 @@
+hs20-osu-client
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index fc9b619..67f6f55 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -8,12 +8,17 @@
LDO=$(CC)
endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+else
Q=@
E=echo
ifeq ($(V), 1)
Q=
E=true
endif
+endif
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
diff --git a/hs20/client/est.c b/hs20/client/est.c
index b1aacb8..db65334 100644
--- a/hs20/client/est.c
+++ b/hs20/client/est.c
@@ -16,6 +16,7 @@
#include <openssl/asn1t.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include <openssl/opensslv.h>
#ifdef OPENSSL_IS_BORINGSSL
#include <openssl/buf.h>
#endif /* OPENSSL_IS_BORINGSSL */
@@ -219,6 +220,10 @@
} d;
} AttrOrOID;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+DEFINE_STACK_OF(AttrOrOID)
+#endif
+
typedef struct {
int type;
STACK_OF(AttrOrOID) *attrs;
@@ -352,9 +357,17 @@
}
}
#else /* OPENSSL_IS_BORINGSSL */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+ 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 && !defined(OPENSSL_IS_BORINGSSL)
+ 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);
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index 5854b72..d75c845 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -111,6 +111,12 @@
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");
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 9e1b0c7..b48903d 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -117,8 +117,8 @@
/* Allow processes running with Group ID as AID_WIFI,
* to read files from SP, SP/<fqdn>, Cert and osu-info directories */
- if (chown(path, -1, AID_WIFI)) {
- wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
+ if (lchown(path, -1, AID_WIFI)) {
+ wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s",
strerror(errno));
return -1;
}
@@ -3068,24 +3068,17 @@
return -1;
devinfo = node_from_file(ctx->xml, "devinfo.xml");
- if (!devinfo) {
- wpa_printf(MSG_ERROR, "devinfo.xml not found");
- return -1;
- }
+ if (devinfo) {
+ devid = get_node(ctx->xml, devinfo, "DevId");
+ if (devid) {
+ char *tmp = xml_node_get_text(ctx->xml, devid);
- 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);
+ if (tmp) {
+ ctx->devid = os_strdup(tmp);
+ xml_node_get_text_free(ctx->xml, tmp);
+ }
}
- }
- xml_node_free(ctx->xml, devinfo);
-
- if (ctx->devid == NULL) {
- wpa_printf(MSG_ERROR, "Could not fetch DevId from devinfo.xml");
- return -1;
+ xml_node_free(ctx->xml, devinfo);
}
ctx->http = http_init_ctx(ctx, ctx->xml);
diff --git a/hs20/server/Makefile b/hs20/server/Makefile
index 248ed5c..9b73727 100644
--- a/hs20/server/Makefile
+++ b/hs20/server/Makefile
@@ -21,6 +21,16 @@
# 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
diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt
index 70f1313..22478ad 100644
--- a/hs20/server/hs20-osu-server.txt
+++ b/hs20/server/hs20-osu-server.txt
@@ -228,12 +228,17 @@
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
diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c
index abd6867..6c74f54 100644
--- a/hs20/server/hs20_spp_server.c
+++ b/hs20/server/hs20_spp_server.c
@@ -11,6 +11,7 @@
#include <sqlite3.h>
#include "common.h"
+#include "common/version.h"
#include "xml-utils.h"
#include "spp_server.h"
@@ -89,6 +90,18 @@
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");
@@ -146,7 +159,7 @@
os_memset(&ctx, 0, sizeof(ctx));
for (;;) {
- int c = getopt(argc, argv, "f:r:");
+ int c = getopt(argc, argv, "f:r:v");
if (c < 0)
break;
switch (c) {
@@ -162,6 +175,9 @@
case 'r':
ctx.root_dir = optarg;
break;
+ case 'v':
+ printf("hs20_spp_server v" VERSION_STR "\n");
+ return 0;
default:
usage();
return -1;
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index e5af4c2..4bef0ff 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -41,6 +41,8 @@
POLICY_REMEDIATION,
POLICY_UPDATE,
FREE_REMEDIATION,
+ CLEAR_REMEDIATION,
+ CERT_REENROLL,
};
@@ -51,6 +53,11 @@
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,
@@ -204,6 +211,61 @@
}
+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)
@@ -290,8 +352,7 @@
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",
+ 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;
@@ -413,8 +474,7 @@
char *cmd;
struct get_db_field_data data;
- cmd = sqlite3_mprintf("SELECT %s FROM users WHERE "
- "%s=%Q AND realm=%Q AND phase2=1",
+ 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)
@@ -443,8 +503,7 @@
char *cmd;
int ret;
- cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE "
- "%s=%Q AND realm=%Q AND phase2=1",
+ 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)
@@ -524,6 +583,27 @@
}
+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;
@@ -545,6 +625,7 @@
{
xml_node_t *node;
char *b64;
+ size_t len;
node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword");
if (node == NULL)
@@ -555,6 +636,9 @@
b64 = (char *) base64_encode((unsigned char *) 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);
@@ -706,6 +790,45 @@
}
+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,
@@ -715,28 +838,48 @@
xml_node_t *spp_node, *cred;
char buf[400];
char new_pw[33];
- char *real_user = NULL;
char *status;
char *cert;
- if (dmacc) {
- real_user = db_get_val(ctx, user, realm, "identity", dmacc);
- if (real_user == NULL) {
- debug_print(ctx, 1, "Could not find user identity for "
- "dmacc user '%s'", user);
- return NULL;
- }
- }
-
cert = db_get_val(ctx, user, realm, "cert", dmacc);
- if (cert && cert[0] == '\0')
+ if (cert && cert[0] == '\0') {
+ os_free(cert);
cert = NULL;
+ }
if (cert) {
- cred = build_credential_cert(ctx, real_user ? real_user : user,
- realm, 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]) {
@@ -752,11 +895,17 @@
real_user ? real_user : user,
realm, new_pw, sizeof(new_pw));
}
- }
- free(real_user);
- if (!cred) {
- debug_print(ctx, 1, "Could not build credential");
- return NULL;
+
+ 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";
@@ -764,16 +913,15 @@
NULL);
if (spp_node == NULL) {
debug_print(ctx, 1, "Could not build sppPostDevDataResponse");
+ os_free(cert);
return NULL;
}
- snprintf(buf, sizeof(buf),
- "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential",
- realm);
-
- if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) {
+ 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;
}
@@ -783,14 +931,16 @@
xml_node_free(ctx->xml, cred);
if (cert) {
- debug_print(ctx, 1, "Certificate credential - no need for DB "
- "password update on success notification");
+ 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;
}
@@ -805,6 +955,17 @@
}
+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)
@@ -989,6 +1150,8 @@
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);
@@ -997,11 +1160,41 @@
}
+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;
- char fname[200];
xml_node_t *policy, *node;
policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc);
@@ -1011,27 +1204,12 @@
if (policy_id == NULL)
return NULL;
}
-
- snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml",
- ctx->root_dir, policy_id);
+ policy = read_policy_file(ctx, policy_id);
free(policy_id);
- debug_print(ctx, 1, "Use policy file %s", fname);
-
- policy = node_from_file(ctx->xml, fname);
if (policy == NULL)
return NULL;
- node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI");
- if (node) {
- char *url;
- url = db_get_osu_config_val(ctx, realm, "policy_url");
- if (url == NULL) {
- xml_node_free(ctx->xml, policy);
- return NULL;
- }
- xml_node_set_text(ctx->xml, node, url);
- free(url);
- }
+ update_policy_update_uri(ctx, realm, policy);
node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate");
if (node && use_dmacc) {
@@ -1264,15 +1442,20 @@
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)
+ 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 == NULL)
+ if (!pps) {
+ xml_node_free(ctx->xml, policy_node);
return NULL;
+ }
add_text_node(ctx, pps, "UpdateIdentifier", "1");
@@ -1280,6 +1463,8 @@
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",
@@ -1311,6 +1496,7 @@
"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");
@@ -1330,6 +1516,17 @@
"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");
@@ -1338,7 +1535,19 @@
cred = xml_node_create(ctx->xml, c, NULL, "Credential");
add_creation_date(ctx, cred);
- if (cert) {
+ 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");
@@ -1361,7 +1570,8 @@
static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx,
const char *session_id,
const char *user,
- const char *realm)
+ const char *realm,
+ int add_est_user)
{
xml_namespace_t *ns;
xml_node_t *spp_node, *enroll, *exec_node;
@@ -1369,7 +1579,7 @@
char password[11];
char *b64;
- if (new_password(password, sizeof(password)) < 0)
+ if (add_est_user && new_password(password, sizeof(password)) < 0)
return NULL;
spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
@@ -1386,6 +1596,10 @@
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 = (char *) base64_encode((unsigned char *) password,
@@ -1445,7 +1659,7 @@
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);
+ ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1);
free(user);
free(realm);
free(pw);
@@ -1477,7 +1691,7 @@
test);
pps = build_pps(ctx, user, realm, pw,
fingerprint ? fingerprint : NULL, machine_managed,
- test);
+ test, NULL, NULL, NULL, NULL);
free(fingerprint);
free(test);
if (!pps) {
@@ -1618,6 +1832,72 @@
}
+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,
@@ -1626,7 +1906,7 @@
char *val;
enum hs20_session_operation oper;
- val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ 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);
@@ -1637,6 +1917,8 @@
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);
@@ -1684,6 +1966,103 @@
}
+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,
@@ -1964,6 +2343,15 @@
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:
@@ -2006,6 +2394,8 @@
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;
@@ -2013,6 +2403,7 @@
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");
@@ -2026,6 +2417,11 @@
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 "
@@ -2037,6 +2433,8 @@
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);
@@ -2065,12 +2463,20 @@
str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr");
- sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr) VALUES (%Q,%Q,1,%Q,%Q,%Q,%d,%Q)",
- user, realm, cert ? "TLS" : "TTLS-MSCHAPV2",
+ 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 : "");
+ str ? str : "",
+ osu_user ? osu_user : "",
+ osu_password ? osu_password : "",
+ policy ? policy : "");
free(str);
if (sql == NULL)
goto out;
@@ -2088,8 +2494,7 @@
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",
+ 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);
@@ -2139,6 +2544,24 @@
}
}
+ 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);
@@ -2152,6 +2575,10 @@
free(pps);
free(cert_pem);
free(fingerprint);
+ free(osu_user);
+ free(osu_password);
+ free(eap_method);
+ os_free(policy);
return ret;
}
@@ -2178,11 +2605,11 @@
debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s",
status, session_id);
- val = db_get_session_val(ctx, user, realm, session_id, "operation");
+ val = db_get_session_val(ctx, NULL, NULL, session_id, "operation");
if (!val) {
debug_print(ctx, 1,
- "No session active for user: %s sessionID: %s",
- user, session_id);
+ "No session active for sessionID: %s",
+ session_id);
oper = NO_OPERATION;
} else
oper = atoi(val);
@@ -2239,6 +2666,29 @@
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 "
@@ -2265,12 +2715,60 @@
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, user, realm, session_id);
+ db_remove_session(ctx, NULL, NULL, session_id);
return ret;
}
diff --git a/hs20/server/spp_server.h b/hs20/server/spp_server.h
index 3556f5c..421974c 100644
--- a/hs20/server/spp_server.h
+++ b/hs20/server/spp_server.h
@@ -17,6 +17,9 @@
sqlite3 *db;
const char *addr;
const char *test;
+ const char *imsi;
+ const char *eap_method;
+ const char *id_hash;
};
diff --git a/hs20/server/sql.txt b/hs20/server/sql.txt
index 666ef13..2cc6ede 100644
--- a/hs20/server/sql.txt
+++ b/hs20/server/sql.txt
@@ -24,6 +24,10 @@
cert TEXT,
cert_pem TEXT,
mac_addr TEXT,
+ osu_user TEXT,
+ osu_password TEXT,
+ eap_method TEXT,
+ mobile_identifier_hash TEXT,
test TEXT
);
@@ -57,6 +61,7 @@
mac_addr TEXT,
last_msk TEXT,
polupd_done TEXT,
+ subrem TEXT
);
CREATE TABLE wildcards(
@@ -93,3 +98,11 @@
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/est.php b/hs20/server/www/est.php
index 6983ec9..b7fb260 100644
--- a/hs20/server/www/est.php
+++ b/hs20/server/www/est.php
@@ -10,6 +10,12 @@
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);
@@ -31,12 +37,6 @@
die('Authentication failed');
}
- $db = new PDO($osu_db);
- if (!$db) {
- error_log("EST: Could not access database");
- die("Could not access database");
- }
-
$sql = "SELECT rowid,password,operation FROM sessions " .
"WHERE user='$user' AND realm='$realm'";
$q = $db->query($sql);
@@ -70,6 +70,29 @@
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");
+ }
}
@@ -92,14 +115,24 @@
header("Content-Type: application/csrattrs");
readfile("$osu_root/est/est-attrs.b64");
error_log("EST: csrattrs");
-} else if ($method == "POST" && $cmd == "simpleenroll") {
- if (!isset($user) || strlen($user) == 0) {
+} 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");
@@ -167,6 +200,7 @@
}
$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))
diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php
index f10e5ab..c56d3d6 100644
--- a/hs20/server/www/spp.php
+++ b/hs20/server/www/spp.php
@@ -85,6 +85,40 @@
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');
diff --git a/hs20/server/www/users.php b/hs20/server/www/users.php
index f546de3..2bd5552 100644
--- a/hs20/server/www/users.php
+++ b/hs20/server/www/users.php
@@ -69,6 +69,9 @@
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");
}
@@ -172,6 +175,10 @@
$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=" .
@@ -185,6 +192,9 @@
} 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>]";
@@ -319,7 +329,7 @@
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 ORDER BY identity');
+$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>";
@@ -334,6 +344,8 @@
echo "Policy";
} else if ($rem == "free") {
echo "Free";
+ } else if ($rem == "reenroll") {
+ echo "Reenroll";
} else {
echo "Machine";
}
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 6d4c041..3b45075 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
#include "drivers/driver.h"
#include "hostapd.h"
@@ -362,7 +363,7 @@
}
-static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
+static int acs_usable_ht40_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
157, 184, 192 };
@@ -376,7 +377,7 @@
}
-static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
+static int acs_usable_vht80_chan(const struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 52, 100, 116, 132, 149 };
unsigned int i;
@@ -389,6 +390,19 @@
}
+static int acs_usable_vht160_chan(const struct hostapd_channel_data *chan)
+{
+ const int allowed[] = { 36, 100 };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(allowed); i++)
+ if (chan->chan == allowed[i])
+ return 1;
+
+ return 0;
+}
+
+
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
@@ -565,6 +579,7 @@
long double factor, ideal_factor = 0;
int i, j;
int n_chans = 1;
+ u32 bw;
unsigned int k;
/* TODO: HT40- support */
@@ -579,16 +594,23 @@
iface->conf->secondary_channel)
n_chans = 2;
- if (iface->conf->ieee80211ac &&
- iface->conf->vht_oper_chwidth == 1)
- n_chans = 4;
+ if (iface->conf->ieee80211ac) {
+ switch (iface->conf->vht_oper_chwidth) {
+ case VHT_CHANWIDTH_80MHZ:
+ n_chans = 4;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ n_chans = 8;
+ break;
+ }
+ }
- /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */
+ bw = num_chan_to_bw(n_chans);
- wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
- n_chans == 1 ? 20 :
- n_chans == 2 ? 40 :
- 80);
+ /* TODO: VHT80+80. Update acs_adjust_vht_center_freq() too. */
+
+ wpa_printf(MSG_DEBUG,
+ "ACS: Survey analysis for selected bandwidth %d MHz", bw);
for (i = 0; i < iface->current_mode->num_channels; i++) {
double total_weight;
@@ -596,12 +618,23 @@
chan = &iface->current_mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ /* Since in the current ACS implementation the first channel is
+ * always a primary channel, skip channels not available as
+ * primary until more sophisticated channel selection is
+ * implemented. */
+ if (!chan_pri_allowed(chan))
continue;
if (!is_in_chanlist(iface, chan))
continue;
+ if (!chan_bw_allowed(chan, bw, 1, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: BW %u is not supported",
+ chan->chan, bw);
+ continue;
+ }
+
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
@@ -614,12 +647,24 @@
}
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
- iface->conf->ieee80211ac &&
- iface->conf->vht_oper_chwidth == 1 &&
- !acs_usable_vht80_chan(chan)) {
- wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80",
- chan->chan);
- continue;
+ iface->conf->ieee80211ac) {
+ if (iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_80MHZ &&
+ !acs_usable_vht80_chan(chan)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: not allowed as primary channel for VHT80",
+ chan->chan);
+ continue;
+ }
+
+ if (iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_160MHZ &&
+ !acs_usable_vht160_chan(chan)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: Channel %d: not allowed as primary channel for VHT160",
+ chan->chan);
+ continue;
+ }
}
factor = 0;
@@ -632,6 +677,13 @@
if (!adj_chan)
break;
+ if (!chan_bw_allowed(adj_chan, bw, 1, 0)) {
+ wpa_printf(MSG_DEBUG,
+ "ACS: PRI Channel %d: secondary channel %d BW %u is not supported",
+ chan->chan, adj_chan->chan, bw);
+ break;
+ }
+
if (acs_usable_chan(adj_chan)) {
factor += adj_chan->interference_factor;
total_weight += 1;
@@ -744,10 +796,14 @@
case VHT_CHANWIDTH_80MHZ:
offset = 6;
break;
+ case VHT_CHANWIDTH_160MHZ:
+ offset = 14;
+ break;
default:
/* TODO: How can this be calculated? Adjust
* acs_find_ideal_chan() */
- wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now");
+ wpa_printf(MSG_INFO,
+ "ACS: Only VHT20/40/80/160 is supported now");
return;
}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index f9b6f29..9611dc0 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -131,6 +131,15 @@
* This can be enabled by default once the implementation has been fully
* completed and tested with other implementations. */
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
+
+ bss->send_probe_response = 1;
+
+#ifdef CONFIG_HS20
+ bss->hs20_release = (HS20_VERSION >> 4) + 1;
+#endif /* CONFIG_HS20 */
+
+ /* Default to strict CRL checking. */
+ bss->check_crl_strict = 1;
}
@@ -193,7 +202,6 @@
conf->beacon_int = 100;
conf->rts_threshold = -1; /* use driver default: 2347 */
conf->fragm_threshold = -1; /* user driver default: 2346 */
- conf->send_probe_response = 1;
/* Set to invalid value means do not add Power Constraint IE */
conf->local_pwr_constraint = -1;
@@ -233,6 +241,9 @@
* environments for the current frequency band in the country. */
conf->country[2] = ' ';
+ conf->rssi_reject_assoc_rssi = 0;
+ conf->rssi_reject_assoc_timeout = 30;
+
return conf;
}
@@ -248,6 +259,12 @@
{
FILE *f;
char buf[128], *pos;
+ const char *keyid;
+ char *context;
+ char *context2;
+ char *token;
+ char *name;
+ char *value;
int line = 0, ret = 0, len, ok;
u8 addr[ETH_ALEN];
struct hostapd_wpa_psk *psk;
@@ -277,9 +294,35 @@
if (buf[0] == '\0')
continue;
- if (hwaddr_aton(buf, addr)) {
+ context = NULL;
+ keyid = NULL;
+ while ((token = str_token(buf, " ", &context))) {
+ if (!os_strchr(token, '='))
+ break;
+ context2 = NULL;
+ name = str_token(token, "=", &context2);
+ value = str_token(token, "", &context2);
+ if (!value)
+ value = "";
+ if (!os_strcmp(name, "keyid")) {
+ keyid = value;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "Unrecognized '%s=%s' on line %d in '%s'",
+ name, value, line, fname);
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret == -1)
+ break;
+
+ if (!token)
+ token = "";
+ if (hwaddr_aton(token, addr)) {
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
- "line %d in '%s'", buf, line, fname);
+ "line %d in '%s'", token, line, fname);
ret = -1;
break;
}
@@ -295,15 +338,14 @@
else
os_memcpy(psk->addr, addr, ETH_ALEN);
- pos = buf + 17;
- if (*pos == '\0') {
+ pos = str_token(buf, "", &context);
+ if (!pos) {
wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
line, fname);
os_free(psk);
ret = -1;
break;
}
- pos++;
ok = 0;
len = os_strlen(pos);
@@ -322,6 +364,18 @@
break;
}
+ if (keyid) {
+ len = os_strlcpy(psk->keyid, keyid, sizeof(psk->keyid));
+ if ((size_t) len >= sizeof(psk->keyid)) {
+ wpa_printf(MSG_ERROR,
+ "PSK keyid too long on line %d in '%s'",
+ line, fname);
+ os_free(psk);
+ ret = -1;
+ break;
+ }
+ }
+
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
@@ -538,6 +592,7 @@
os_free(conf->ocsp_stapling_response_multi);
os_free(conf->dh_file);
os_free(conf->openssl_ciphers);
+ os_free(conf->openssl_ecdh_curves);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
@@ -644,6 +699,7 @@
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 */
@@ -1003,6 +1059,15 @@
}
#endif /* CONFIG_MBO */
+#ifdef CONFIG_OCV
+ if (full_config && bss->ieee80211w == NO_MGMT_FRAME_PROTECTION &&
+ bss->ocv) {
+ wpa_printf(MSG_ERROR,
+ "OCV: PMF needs to be enabled whenever using OCV");
+ return -1;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
@@ -1146,3 +1211,26 @@
}
}
}
+
+
+int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf)
+{
+ int with_id = 0, without_id = 0;
+ struct sae_password_entry *pw;
+
+ if (conf->ssid.wpa_passphrase)
+ without_id = 1;
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->identifier)
+ with_id = 1;
+ else
+ without_id = 1;
+ if (with_id && without_id)
+ break;
+ }
+
+ if (with_id && !without_id)
+ return 2;
+ return with_id;
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 778366d..6963df4 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -42,6 +42,7 @@
#define MESH_CONF_SEC_AMPE BIT(2)
unsigned int security;
enum mfp_options ieee80211w;
+ int ocv;
unsigned int pairwise_cipher;
unsigned int group_cipher;
unsigned int mgmt_group_cipher;
@@ -122,6 +123,7 @@
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
struct vlan_description vlan_desc;
char ifname[IFNAMSIZ + 1];
+ char bridge[IFNAMSIZ + 1];
int configured;
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -132,6 +134,7 @@
};
#define PMK_LEN 32
+#define KEYID_LEN 32
#define MIN_PASSPHRASE_LEN 8
#define MAX_PASSPHRASE_LEN 63
struct hostapd_sta_wpa_psk_short {
@@ -145,6 +148,7 @@
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
+ char keyid[KEYID_LEN];
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
@@ -335,6 +339,9 @@
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ int ocv; /* Operating Channel Validation */
+#endif /* CONFIG_OCV */
enum {
PSK_RADIUS_IGNORED = 0,
PSK_RADIUS_ACCEPTED = 1,
@@ -384,12 +391,15 @@
char *private_key;
char *private_key_passwd;
int check_crl;
+ int check_crl_strict;
+ unsigned int crl_reload_interval;
unsigned int tls_session_lifetime;
unsigned int tls_flags;
char *ocsp_stapling_response;
char *ocsp_stapling_response_multi;
char *dh_file;
char *openssl_ciphers;
+ char *openssl_ecdh_curves;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@@ -557,6 +567,7 @@
int na_mcast_to_ucast;
#ifdef CONFIG_HS20
int hs20;
+ int hs20_release;
int disable_dgaf;
u16 anqp_domain_id;
unsigned int hs20_oper_friendly_name_count;
@@ -596,6 +607,7 @@
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;
@@ -686,6 +698,12 @@
#endif /* CONFIG_OWE */
int coloc_intf_reporting;
+
+ u8 send_probe_response;
+
+#define BACKHAUL_BSS 1
+#define FRONTHAUL_BSS 2
+ int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */
};
/**
@@ -717,7 +735,6 @@
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
- u8 send_probe_response;
u8 channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
@@ -829,12 +846,16 @@
#ifdef CONFIG_IEEE80211AX
struct he_phy_capabilities_info he_phy_capab;
struct he_operation he_op;
+ struct ieee80211_he_mu_edca_parameter_set he_mu_edca;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
#define CH_SWITCH_VHT_ENABLED BIT(0)
#define CH_SWITCH_VHT_DISABLED BIT(1)
unsigned int ch_switch_vht_config;
+
+ int rssi_reject_assoc_rssi;
+ int rssi_reject_assoc_timeout;
};
@@ -862,5 +883,6 @@
int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
+int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 728d7f0..067cf86 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -176,7 +176,8 @@
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
- if (hapd->conf->mbo_enabled || hapd->enable_oce) {
+ if (hapd->conf->mbo_enabled ||
+ OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
add_buf_data(&proberesp, buf, pos - buf) < 0 ||
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index db93fde..d45ab84 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -356,4 +356,12 @@
return hapd->driver->stop_ap(hapd->drv_priv);
}
+static inline int hostapd_drv_channel_info(struct hostapd_data *hapd,
+ struct wpa_channel_info *ci)
+{
+ if (!hapd->driver || !hapd->driver->channel_info)
+ return -1;
+ return hapd->driver->channel_info(hapd->drv_priv, ci);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 95d004e..1bb3d9f 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -136,6 +136,7 @@
#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 = conf->eap_server_erp;
@@ -200,6 +201,16 @@
os_memset(&conf, 0, sizeof(conf));
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ if (hapd->conf->crl_reload_interval > 0 &&
+ hapd->conf->check_crl <= 0) {
+ wpa_printf(MSG_INFO,
+ "Cannot enable CRL reload functionality - it depends on check_crl being set");
+ } else if (hapd->conf->crl_reload_interval > 0) {
+ conf.crl_reload_interval =
+ hapd->conf->crl_reload_interval;
+ wpa_printf(MSG_INFO,
+ "Enabled CRL reload functionality");
+ }
conf.tls_flags = hapd->conf->tls_flags;
conf.event_cb = authsrv_tls_event;
conf.cb_ctx = hapd;
@@ -217,6 +228,7 @@
params.private_key_passwd = hapd->conf->private_key_passwd;
params.dh_file = hapd->conf->dh_file;
params.openssl_ciphers = hapd->conf->openssl_ciphers;
+ params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
params.ocsp_stapling_response_multi =
@@ -229,7 +241,8 @@
}
if (tls_global_set_verify(hapd->ssl_ctx,
- hapd->conf->check_crl)) {
+ hapd->conf->check_crl,
+ hapd->conf->check_crl_strict)) {
wpa_printf(MSG_ERROR, "Failed to enable check_crl");
authsrv_deinit(hapd);
return -1;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 59bd4af..3e62991 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -397,7 +397,8 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
- 3 + sizeof(struct ieee80211_he_operation);
+ 3 + sizeof(struct ieee80211_he_operation) +
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
}
#endif /* CONFIG_IEEE80211AX */
@@ -510,6 +511,7 @@
if (hapd->iconf->ieee80211ax) {
pos = hostapd_eid_he_capab(hapd, pos);
pos = hostapd_eid_he_operation(hapd, pos);
+ pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -767,7 +769,7 @@
ie, ie_len, ssi_signal) > 0)
return;
- if (!hapd->iconf->send_probe_response)
+ if (!hapd->conf->send_probe_response)
return;
if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
@@ -1085,7 +1087,8 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
- 3 + sizeof(struct ieee80211_he_operation);
+ 3 + sizeof(struct ieee80211_he_operation) +
+ 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1222,6 +1225,7 @@
if (hapd->iconf->ieee80211ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
+ tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
@@ -1357,6 +1361,18 @@
#endif /* CONFIG_HS20 */
params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
params->pbss = hapd->conf->pbss;
+
+ if (hapd->conf->ftm_responder) {
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_FTM_RESPONDER) {
+ params->ftm_responder = 1;
+ params->lci = hapd->iface->conf->lci;
+ params->civic = hapd->iface->conf->civic;
+ } else {
+ wpa_printf(MSG_WARNING,
+ "Not configuring FTM responder as the driver doesn't advertise support for it");
+ }
+ }
+
return 0;
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 21b813e..3128aed 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -207,6 +207,7 @@
char *buf, size_t buflen)
{
int len, res, ret, i;
+ const char *keyid;
if (!sta)
return 0;
@@ -341,6 +342,13 @@
len += ret;
}
+ keyid = ap_sta_wpa_get_keyid(hapd, sta);
+ if (keyid) {
+ ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
+ }
+
return len;
}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 993dd19..79cd00f 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -142,18 +142,30 @@
{
struct hostapd_channel_data *first_chan, *chan;
int i;
+ u32 bw = num_chan_to_bw(num_chans);
if (first_chan_idx + num_chans > mode->num_channels)
return 0;
first_chan = &mode->channels[first_chan_idx];
+ /* hostapd DFS implementation assumes the first channel as primary.
+ * If it's not allowed to use the first channel as primary, decline the
+ * whole channel range. */
+ if (!chan_pri_allowed(first_chan))
+ return 0;
+
for (i = 0; i < num_chans; i++) {
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
if (!chan)
return 0;
+ /* HT 40 MHz secondary channel availability checked only for
+ * primary channel */
+ if (!chan_bw_allowed(chan, bw, 1, !i))
+ return 0;
+
if (!dfs_channel_available(chan, skip_radar))
return 0;
}
@@ -197,7 +209,8 @@
/* Skip HT40/VHT incompatible channels */
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
- !dfs_is_chan_allowed(chan, n_chans))
+ (!dfs_is_chan_allowed(chan, n_chans) ||
+ !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)))
continue;
/* Skip incompatible chandefs */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index 6d8c2f4..ed37fc8 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -88,6 +88,15 @@
}
}
+ if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ continue;
+ x_snoop_mcast_to_ucast_convert_send(hapd, sta,
+ (u8 *) buf, len);
+ }
+ }
+
if (msgtype == DHCPACK) {
if (b->your_ip == 0)
return;
@@ -124,15 +133,6 @@
}
sta->ipaddr = b->your_ip;
}
-
- if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!(sta->flags & WLAN_STA_AUTHORIZED))
- continue;
- x_snoop_mcast_to_ucast_convert_send(hapd, sta,
- (u8 *) buf, len);
- }
- }
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 4ec044e..149f389 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -505,9 +505,9 @@
}
-static void hostapd_dpp_set_configurator(struct hostapd_data *hapd,
- struct dpp_authentication *auth,
- const char *cmd)
+static int hostapd_dpp_set_configurator(struct hostapd_data *hapd,
+ struct dpp_authentication *auth,
+ const char *cmd)
{
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
@@ -521,7 +521,7 @@
char *group_id = NULL;
if (!cmd)
- return;
+ return 0;
wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
pos = os_strstr(cmd, " ssid=");
@@ -618,10 +618,12 @@
conf_ap->akm = DPP_AKM_PSK;
if (psk_set) {
os_memcpy(conf_ap->psk, psk, PMK_LEN);
- } else {
+ } else if (pass_len > 0) {
conf_ap->passphrase = os_strdup(pass);
if (!conf_ap->passphrase)
goto fail;
+ } else {
+ goto fail;
}
} else if (os_strstr(cmd, " conf=ap-dpp")) {
conf_ap->akm = DPP_AKM_DPP;
@@ -663,13 +665,15 @@
auth->conf_ap = conf_ap;
auth->conf = conf;
os_free(group_id);
- return;
+ return 0;
fail:
- wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "DPP: Failed to set configurator parameters");
dpp_configuration_free(conf_sta);
dpp_configuration_free(conf_ap);
os_free(group_id);
+ return -1;
}
@@ -842,7 +846,11 @@
if (!hapd->dpp_auth)
goto fail;
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd);
+ if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth, cmd) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ goto fail;
+ }
hapd->dpp_auth->neg_freq = neg_freq;
@@ -967,8 +975,12 @@
return;
}
hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth);
- hostapd_dpp_set_configurator(hapd, hapd->dpp_auth,
- hapd->dpp_configurator_params);
+ if (hostapd_dpp_set_configurator(hapd, hapd->dpp_auth,
+ hapd->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(hapd->dpp_auth);
+ hapd->dpp_auth = NULL;
+ return;
+ }
os_memcpy(hapd->dpp_auth->peer_mac_addr, src, ETH_ALEN);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
@@ -1892,9 +1904,9 @@
return -1;
curve = get_param(cmd, " curve=");
- hostapd_dpp_set_configurator(hapd, auth, cmd);
-
- if (dpp_configurator_own_config(auth, curve, 1) == 0) {
+ hostapd_dpp_set_testing_options(hapd, auth);
+ if (hostapd_dpp_set_configurator(hapd, auth, cmd) == 0 &&
+ dpp_configurator_own_config(auth, curve, 1) == 0) {
hostapd_dpp_handle_config_obj(hapd, auth);
ret = 0;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 1135aea..54be3b5 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -38,6 +38,7 @@
#include "mbo_ap.h"
#include "dpp_hostapd.h"
#include "fils_hlp.h"
+#include "neighbor_db.h"
#ifdef CONFIG_FILS
@@ -739,9 +740,12 @@
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2)
{
+ /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
+
#ifdef NEED_AP_MLME
int channel, chwidth, is_dfs;
u8 seg0_idx = 0, seg1_idx = 0;
+ size_t i;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
@@ -824,6 +828,9 @@
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
}
+
+ for (i = 0; i < hapd->iface->num_bss; i++)
+ hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
#endif /* NEED_AP_MLME */
}
@@ -1072,19 +1079,23 @@
struct sta_info *sta;
size_t plen __maybe_unused;
u16 fc;
+ u8 *action __maybe_unused;
- if (drv_mgmt->frame_len < 24 + 1)
+ if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
return;
- plen = drv_mgmt->frame_len - 24 - 1;
+ plen = drv_mgmt->frame_len - IEEE80211_HDRLEN - 1;
mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
fc = le_to_host16(mgmt->frame_control);
if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
return; /* handled by the driver */
- wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
- mgmt->u.action.category, (int) plen);
+ action = (u8 *) &mgmt->u.action.u;
+ wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
+ " da " MACSTR " plen %d",
+ mgmt->u.action.category, *action,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
@@ -1100,10 +1111,7 @@
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
- ieee802_11_sa_query_action(
- hapd, mgmt->sa,
- mgmt->u.action.u.sa_query_resp.action,
- mgmt->u.action.u.sa_query_resp.trans_id);
+ ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WNM_AP
@@ -1721,6 +1729,11 @@
hostapd_reconfig_encryption(hapd);
hapd->reenable_beacon = 1;
ieee802_11_set_beacon(hapd);
+#ifdef NEED_AP_MLME
+ } else if (hapd->disabled && hapd->iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
+ hostapd_handle_dfs(hapd->iface);
+#endif /* NEED_AP_MLME */
}
break;
case EVENT_INTERFACE_DISABLED:
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index fab307f..a510ee3 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -92,7 +92,7 @@
} 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], 0, 10);
+ user->t_c_timestamp = strtol(argv[i], NULL, 10);
}
}
@@ -139,6 +139,7 @@
struct hostapd_eap_user *user = NULL;
char id_str[256], cmd[300];
size_t i;
+ int res;
if (identity_len >= sizeof(id_str)) {
wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
@@ -174,6 +175,7 @@
if (hapd->tmp_eap_user.identity == NULL)
return NULL;
os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+ hapd->tmp_eap_user.identity_len = identity_len;
if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
@@ -182,9 +184,12 @@
return NULL;
}
- os_snprintf(cmd, sizeof(cmd),
- "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
- id_str, phase2);
+ res = os_snprintf(cmd, sizeof(cmd),
+ "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
+ id_str, phase2);
+ if (os_snprintf_error(sizeof(cmd), res))
+ goto fail;
+
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
@@ -214,6 +219,7 @@
}
}
+fail:
sqlite3_close(db);
return user;
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
index 2a359ab..6da514a 100644
--- a/src/ap/fils_hlp.c
+++ b/src/ap/fils_hlp.c
@@ -580,6 +580,19 @@
u8 *tmp, *tmp_pos;
int ret = 0;
+ if (sta->fils_pending_assoc_req &&
+ eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta)) {
+ /* Do not process FILS HLP request again if the station
+ * retransmits (Re)Association Request frame before the previous
+ * HLP response has either been received or timed out. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Do not relay another HLP request from "
+ MACSTR
+ " before processing of the already pending one has been completed",
+ MAC2STR(sta->addr));
+ return 1;
+ }
+
/* Old DHCPDISCOVER is not needed anymore, if it was still pending */
wpabuf_free(sta->hlp_dhcp_discover);
sta->hlp_dhcp_discover = NULL;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 117ee08..342585f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -176,8 +176,27 @@
}
+static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
+ struct hostapd_config *oldconf)
+{
+ size_t i;
+
+ if (newconf->num_bss != oldconf->num_bss)
+ return 1;
+
+ for (i = 0; i < newconf->num_bss; i++) {
+ if (os_strcmp(newconf->bss[i]->iface,
+ oldconf->bss[i]->iface) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
int hostapd_reload_config(struct hostapd_iface *iface)
{
+ struct hapd_interfaces *interfaces = iface->interfaces;
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_config *newconf, *oldconf;
size_t j;
@@ -200,6 +219,35 @@
hostapd_clear_old(iface);
oldconf = hapd->iconf;
+ if (hostapd_iface_conf_changed(newconf, oldconf)) {
+ char *fname;
+ int res;
+
+ wpa_printf(MSG_DEBUG,
+ "Configuration changes include interface/BSS modification - force full disable+enable sequence");
+ fname = os_strdup(iface->config_fname);
+ if (!fname) {
+ hostapd_config_free(newconf);
+ return -1;
+ }
+ hostapd_remove_iface(interfaces, hapd->conf->iface);
+ iface = hostapd_init(interfaces, fname);
+ os_free(fname);
+ hostapd_config_free(newconf);
+ if (!iface) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize interface on config reload");
+ return -1;
+ }
+ iface->interfaces = interfaces;
+ interfaces->iface[interfaces->count] = iface;
+ interfaces->count++;
+ res = hostapd_enable_iface(iface);
+ if (res < 0)
+ wpa_printf(MSG_ERROR,
+ "Failed to enable interface on config reload");
+ return res;
+ }
iface->conf = newconf;
for (j = 0; j < iface->num_bss; j++) {
@@ -1620,127 +1668,6 @@
#endif /* CONFIG_FST */
-
-#ifdef NEED_AP_MLME
-static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
- int ht, int vht)
-{
- if (!ht && !vht)
- return NR_CHAN_WIDTH_20;
- if (!hapd->iconf->secondary_channel)
- return NR_CHAN_WIDTH_20;
- if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
- return NR_CHAN_WIDTH_40;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
- return NR_CHAN_WIDTH_80;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
- return NR_CHAN_WIDTH_160;
- if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
- return NR_CHAN_WIDTH_80P80;
- return NR_CHAN_WIDTH_20;
-}
-#endif /* NEED_AP_MLME */
-
-
-static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
-{
-#ifdef NEED_AP_MLME
- u16 capab = hostapd_own_capab_info(hapd);
- int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
- int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
- struct wpa_ssid_value ssid;
- u8 channel, op_class;
- u8 center_freq1_idx = 0, center_freq2_idx = 0;
- enum nr_chan_width width;
- u32 bssid_info;
- struct wpabuf *nr;
-
- if (!(hapd->conf->radio_measurements[0] &
- WLAN_RRM_CAPS_NEIGHBOR_REPORT))
- return;
-
- bssid_info = 3; /* AP is reachable */
- bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
- bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
-
- if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
- bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
-
- bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
-
- if (hapd->conf->wmm_enabled) {
- bssid_info |= NEI_REP_BSSID_INFO_QOS;
-
- if (hapd->conf->wmm_uapsd &&
- (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
- bssid_info |= NEI_REP_BSSID_INFO_APSD;
- }
-
- if (ht) {
- bssid_info |= NEI_REP_BSSID_INFO_HT |
- NEI_REP_BSSID_INFO_DELAYED_BA;
-
- /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
- if (vht)
- bssid_info |= NEI_REP_BSSID_INFO_VHT;
- }
-
- /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
-
- if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
- hapd->iconf->secondary_channel,
- hapd->iconf->vht_oper_chwidth,
- &op_class, &channel) ==
- NUM_HOSTAPD_MODES)
- return;
- width = hostapd_get_nr_chan_width(hapd, ht, vht);
- if (vht) {
- center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
- if (width == NR_CHAN_WIDTH_80P80)
- center_freq2_idx =
- hapd->iconf->vht_oper_centr_freq_seg1_idx;
- } else if (ht) {
- ieee80211_freq_to_chan(hapd->iface->freq +
- 10 * hapd->iconf->secondary_channel,
- ¢er_freq1_idx);
- }
-
- ssid.ssid_len = hapd->conf->ssid.ssid_len;
- os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
-
- /*
- * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
- * phy type + wide bandwidth channel subelement.
- */
- nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
- if (!nr)
- return;
-
- wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
- wpabuf_put_le32(nr, bssid_info);
- wpabuf_put_u8(nr, op_class);
- wpabuf_put_u8(nr, channel);
- wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
-
- /*
- * Wide Bandwidth Channel subelement may be needed to allow the
- * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
- * Figure 9-301.
- */
- wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
- wpabuf_put_u8(nr, 3);
- wpabuf_put_u8(nr, width);
- wpabuf_put_u8(nr, center_freq1_idx);
- wpabuf_put_u8(nr, center_freq2_idx);
-
- hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
- hapd->iconf->civic, hapd->iconf->stationary_ap);
-
- wpabuf_free(nr);
-#endif /* NEED_AP_MLME */
-}
-
-
#ifdef CONFIG_OWE
static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
@@ -2037,7 +1964,7 @@
iface->interfaces->terminate_on_error--;
for (j = 0; j < iface->num_bss; j++)
- hostapd_set_own_neighbor_report(iface->bss[j]);
+ hostapd_neighbor_set_own_report(iface->bss[j]);
return 0;
@@ -2682,7 +2609,7 @@
if (conf == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
"configuration", __func__);
- return NULL;
+ return NULL;
}
if (driver) {
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 28b3a1c..85e63d3 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -14,6 +14,13 @@
#include "ap_config.h"
#include "drivers/driver.h"
+#define OCE_STA_CFON_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_STA_CFON) && \
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON))
+#define OCE_AP_ENABLED(hapd) \
+ ((hapd->conf->oce & OCE_AP) && \
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_AP))
+
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
@@ -324,11 +331,6 @@
#ifdef CONFIG_MBO
unsigned int mbo_assoc_disallow;
- /**
- * enable_oce - Enable OCE if it is enabled by user and device also
- * supports OCE.
- */
- u8 enable_oce;
#endif /* CONFIG_MBO */
struct dl_list nr_db;
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 98d016d..532580e 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -25,17 +25,20 @@
if (!hapd->conf->hs20)
return eid;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
- *eid++ = 7;
+ *eid++ = hapd->conf->hs20_release < 2 ? 5 : 7;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = HS20_INDICATION_OUI_TYPE;
- conf = HS20_VERSION; /* Release Number */
- conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
+ conf = (hapd->conf->hs20_release - 1) << 4; /* Release Number */
+ if (hapd->conf->hs20_release >= 2)
+ conf |= HS20_ANQP_DOMAIN_ID_PRESENT;
if (hapd->conf->disable_dgaf)
conf |= HS20_DGAF_DISABLED;
*eid++ = conf;
- WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
- eid += 2;
+ if (hapd->conf->hs20_release >= 2) {
+ WPA_PUT_LE16(eid, hapd->conf->anqp_domain_id);
+ eid += 2;
+ }
return eid;
}
@@ -84,6 +87,10 @@
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (hapd->conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
eid += 2;
@@ -184,13 +191,14 @@
{
struct wpabuf *buf;
int ret;
- size_t url_len = os_strlen(url);
+ size_t url_len;
if (!url) {
wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available");
return -1;
}
+ url_len = os_strlen(url);
if (5 + url_len > 255) {
wpa_printf(MSG_INFO,
"HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'",
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 5279abc..9d3d990 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -229,9 +229,6 @@
{
int pri_chan, sec_chan;
- if (!iface->conf->secondary_channel)
- return 1; /* HT40 not used */
-
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
@@ -697,30 +694,25 @@
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
{
- int i;
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
- for (i = 0; i < iface->current_mode->num_channels; i++) {
- chan = &iface->current_mode->channels[i];
- if (chan->chan != channel)
- continue;
+ chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+ if (!chan)
+ return 0;
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
- return 1;
+ if ((primary && chan_pri_allowed(chan)) ||
+ (!primary && !(chan->flag & HOSTAPD_CHAN_DISABLED)))
+ return 1;
- wpa_printf(MSG_DEBUG,
- "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
- primary ? "" : "Configured HT40 secondary ",
- i, chan->chan, chan->flag,
- chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
- chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
- }
-
- wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
- channel, primary ? "primary" : "secondary");
+ wpa_printf(MSG_INFO,
+ "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s",
+ channel, primary ? "primary" : "secondary",
+ chan->flag,
+ chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
+ chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
return 0;
}
@@ -728,6 +720,12 @@
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_chan;
+ struct hostapd_channel_data *pri_chan;
+
+ pri_chan = hw_get_channel_chan(iface->current_mode,
+ iface->conf->channel, NULL);
+ if (!pri_chan)
+ return 0;
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
return 0;
@@ -742,13 +740,15 @@
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
secondary_chan = iface->conf->channel + 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
iface->conf->secondary_channel = 1;
return 1;
}
secondary_chan = iface->conf->channel - 4;
- if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+ if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+ (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
iface->conf->secondary_channel = -1;
return 1;
}
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 90788de..376bbd8 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -21,6 +21,7 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/sae.h"
+#include "common/ocv.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -62,6 +63,22 @@
int *is_pub);
#endif /* CONFIG_FILS */
+
+u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 multi_ap_val = 0;
+
+ if (!hapd->conf->multi_ap)
+ return eid;
+ if (hapd->conf->multi_ap & BACKHAUL_BSS)
+ multi_ap_val |= MULTI_AP_BACKHAUL_BSS;
+ if (hapd->conf->multi_ap & FRONTHAUL_BSS)
+ multi_ap_val |= MULTI_AP_FRONTHAUL_BSS;
+
+ return eid + add_multi_ap_ie(eid, 9, multi_ap_val);
+}
+
+
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
@@ -1743,7 +1760,8 @@
static void handle_auth(struct hostapd_data *hapd,
- const struct ieee80211_mgmt *mgmt, size_t len)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int rssi)
{
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
@@ -1925,6 +1943,7 @@
sta = ap_get_sta(hapd, mgmt->sa);
if (sta) {
sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ sta->ft_over_ds = 0;
if ((fc & WLAN_FC_RETRY) &&
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
sta->last_seq_ctrl == seq_ctrl &&
@@ -1973,6 +1992,9 @@
}
sta->last_seq_ctrl = seq_ctrl;
sta->last_subtype = WLAN_FC_STYPE_AUTH;
+#ifdef CONFIG_MBO
+ sta->auth_rssi = rssi;
+#endif /* CONFIG_MBO */
res = ieee802_11_set_radius_info(
hapd, sta, res, session_timeout, acct_interim_interval,
@@ -2210,6 +2232,57 @@
return WLAN_STATUS_SUCCESS;
}
+static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *multi_ap_ie, size_t multi_ap_len)
+{
+ u8 multi_ap_value = 0;
+
+ sta->flags &= ~WLAN_STA_MULTI_AP;
+
+ if (!hapd->conf->multi_ap)
+ return WLAN_STATUS_SUCCESS;
+
+ if (multi_ap_ie) {
+ const u8 *multi_ap_subelem;
+
+ multi_ap_subelem = get_ie(multi_ap_ie + 4,
+ multi_ap_len - 4,
+ MULTI_AP_SUB_ELEM_TYPE);
+ if (multi_ap_subelem && multi_ap_subelem[1] == 1) {
+ multi_ap_value = multi_ap_subelem[2];
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Multi-AP IE has missing or invalid Multi-AP subelement");
+ return WLAN_STATUS_INVALID_IE;
+ }
+ }
+
+ if (multi_ap_value == MULTI_AP_BACKHAUL_STA)
+ sta->flags |= WLAN_STA_MULTI_AP;
+
+ if ((hapd->conf->multi_ap & BACKHAUL_BSS) &&
+ multi_ap_value == MULTI_AP_BACKHAUL_STA)
+ return WLAN_STATUS_SUCCESS;
+
+ if (hapd->conf->multi_ap & FRONTHAUL_BSS) {
+ if (multi_ap_value == MULTI_AP_BACKHAUL_STA) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Backhaul STA tries to associate with fronthaul-only BSS");
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+ }
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Non-Multi-AP STA tries to associate with backhaul-only BSS");
+ return WLAN_STATUS_ASSOC_DENIED_UNSPEC;
+}
+
static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
struct ieee802_11_elems *elems)
@@ -2466,6 +2539,11 @@
resp = copy_supp_rates(hapd, sta, &elems);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+
+ resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
@@ -2485,6 +2563,10 @@
if (resp != WLAN_STATUS_SUCCESS)
return resp;
+ resp = copy_sta_vht_oper(hapd, sta, elems.vht_operation);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -2713,10 +2795,20 @@
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
if (elems.hs20 && elems.hs20_len > 4) {
+ int release;
+
sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
elems.hs20_len - 4);
- } else
+ release = ((elems.hs20[4] >> 4) & 0x0f) + 1;
+ if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: PMF not negotiated by release %d station "
+ MACSTR, release, MAC2STR(sta->addr));
+ return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ }
+ } else {
sta->hs20_ie = NULL;
+ }
wpabuf_free(sta->roaming_consortium);
if (elems.roaming_cons_sel)
@@ -2747,6 +2839,35 @@
}
#endif /* CONFIG_MBO */
+#if defined(CONFIG_FILS) && defined(CONFIG_OCV)
+ if (wpa_auth_uses_ocv(sta->wpa_sm) &&
+ (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (get_sta_tx_parameters(sta->wpa_sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ }
+#endif /* CONFIG_FILS && CONFIG_OCV */
+
ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
elems.supp_op_classes_len);
@@ -2791,7 +2912,7 @@
static int add_associated_sta(struct hostapd_data *hapd,
- struct sta_info *sta)
+ struct sta_info *sta, int reassoc)
{
struct ieee80211_ht_capabilities ht_cap;
struct ieee80211_vht_capabilities vht_cap;
@@ -2807,14 +2928,36 @@
* Skip this if the STA has already completed FT reassociation and the
* TK has been configured since the TX/RX PN must not be reset to 0 for
* the same key.
+ *
+ * FT-over-the-DS has a special case where the STA entry (and as such,
+ * the TK) has not yet been configured to the driver depending on which
+ * driver interface is used. For that case, allow add-STA operation to
+ * be used (instead of set-STA). This is needed to allow mac80211-based
+ * drivers to accept the STA parameter configuration. Since this is
+ * after a new FT-over-DS exchange, a new TK has been derived, so key
+ * reinstallation is not a concern for this case.
*/
+ wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR
+ " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)",
+ MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg,
+ sta->ft_over_ds, reassoc,
+ !!(sta->flags & WLAN_STA_AUTHORIZED),
+ wpa_auth_sta_ft_tk_already_set(sta->wpa_sm),
+ wpa_auth_sta_fils_tk_already_set(sta->wpa_sm));
+
if (!sta->added_unassoc &&
(!(sta->flags & WLAN_STA_AUTHORIZED) ||
+ (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) ||
(!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) &&
!wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) {
hostapd_drv_sta_remove(hapd, sta->addr);
wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED);
set = 0;
+
+ /* Do not allow the FT-over-DS exception to be used more than
+ * once per authentication exchange to guarantee a new TK is
+ * used here */
+ sta->ft_over_ds = 0;
}
#ifdef CONFIG_IEEE80211N
@@ -2860,7 +3003,7 @@
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 status_code, int reassoc,
- const u8 *ies, size_t ies_len)
+ const u8 *ies, size_t ies_len, int rssi)
{
int send_len;
u8 *buf;
@@ -2905,6 +3048,16 @@
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
+#ifdef CONFIG_MBO
+ if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+ rssi != 0) {
+ int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi;
+
+ p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p,
+ delta);
+ }
+#endif /* CONFIG_MBO */
+
#ifdef CONFIG_IEEE80211R_AP
if (sta && status_code == WLAN_STATUS_SUCCESS) {
/* IEEE 802.11r: Mobility Domain Information, Fast BSS
@@ -2922,7 +3075,8 @@
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_OWE
- if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
+ if (sta && status_code == WLAN_STATUS_SUCCESS &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE))
p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p,
buf + buflen - p,
ies, ies_len);
@@ -2995,6 +3149,9 @@
}
#endif /* CONFIG_WPS */
+ if (sta && (sta->flags & WLAN_STA_MULTI_AP))
+ p = hostapd_eid_multi_ap(hapd, p);
+
#ifdef CONFIG_P2P
if (sta && sta->p2p_ie && hapd->p2p_group) {
struct wpabuf *p2p_resp_ie;
@@ -3069,7 +3226,7 @@
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
- sta && sta->owe_ecdh &&
+ sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) {
struct wpabuf *pub;
@@ -3172,7 +3329,7 @@
reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
sta->fils_pending_assoc_is_reassoc,
sta->fils_pending_assoc_req,
- sta->fils_pending_assoc_req_len);
+ sta->fils_pending_assoc_req_len, 0);
os_free(sta->fils_pending_assoc_req);
sta->fils_pending_assoc_req = NULL;
sta->fils_pending_assoc_req_len = 0;
@@ -3209,7 +3366,7 @@
static void handle_assoc(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
- int reassoc)
+ int reassoc, int rssi)
{
u16 capab_info, listen_interval, seq_ctrl, fc;
u16 resp = WLAN_STATUS_SUCCESS, reply_res;
@@ -3392,6 +3549,14 @@
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
}
+
+ if (hapd->iconf->rssi_reject_assoc_rssi && rssi &&
+ rssi < hapd->iconf->rssi_reject_assoc_rssi &&
+ (sta->auth_rssi == 0 ||
+ sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) {
+ resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS;
+ goto fail;
+ }
#endif /* CONFIG_MBO */
/*
@@ -3549,10 +3714,24 @@
* issues with processing other non-Data Class 3 frames during this
* window.
*/
- if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta))
+ if (resp == WLAN_STATUS_SUCCESS && sta &&
+ add_associated_sta(hapd, sta, reassoc))
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
#ifdef CONFIG_FILS
+ if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS &&
+ eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) &&
+ sta->fils_pending_assoc_req) {
+ /* Do not reschedule fils_hlp_timeout in case the station
+ * retransmits (Re)Association Request frame while waiting for
+ * the previously started FILS HLP wait, so that the timeout can
+ * be determined from the first pending attempt. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to "
+ MACSTR, MAC2STR(sta->addr));
+ os_free(tmp);
+ return;
+ }
if (sta) {
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
os_free(sta->fils_pending_assoc_req);
@@ -3577,7 +3756,7 @@
#endif /* CONFIG_FILS */
reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
- left);
+ left, rssi);
os_free(tmp);
/*
@@ -3732,9 +3911,7 @@
return 0;
}
- ieee802_11_sa_query_action(hapd, mgmt->sa,
- mgmt->u.action.u.sa_query_resp.action,
- mgmt->u.action.u.sa_query_resp.trans_id);
+ ieee802_11_sa_query_action(hapd, mgmt, len);
return 1;
}
@@ -3752,9 +3929,9 @@
unsigned int freq)
{
struct sta_info *sta;
- sta = ap_get_sta(hapd, mgmt->sa);
+ u8 *action __maybe_unused;
- if (len < IEEE80211_HDRLEN + 1) {
+ if (len < IEEE80211_HDRLEN + 2 + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"handle_action - too short payload (len=%lu)",
@@ -3762,6 +3939,14 @@
return 0;
}
+ action = (u8 *) &mgmt->u.action.u;
+ wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
+ " da " MACSTR " len %d freq %u",
+ mgmt->u.action.category, *action,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq);
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
(sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
@@ -4011,17 +4196,17 @@
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
- handle_auth(hapd, mgmt, len);
+ handle_auth(hapd, mgmt, len, ssi_signal);
ret = 1;
break;
case WLAN_FC_STYPE_ASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
- handle_assoc(hapd, mgmt, len, 0);
+ handle_assoc(hapd, mgmt, len, 0, ssi_signal);
ret = 1;
break;
case WLAN_FC_STYPE_REASSOC_REQ:
wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
- handle_assoc(hapd, mgmt, len, 1);
+ handle_assoc(hapd, mgmt, len, 1, ssi_signal);
ret = 1;
break;
case WLAN_FC_STYPE_DISASSOC:
@@ -4233,7 +4418,7 @@
sta->flags |= WLAN_STA_WDS;
}
- if (sta->flags & WLAN_STA_WDS) {
+ if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) {
int ret;
char ifname_wds[IFNAMSIZ + 1];
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 2f3b4da..5082226 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -59,6 +59,7 @@
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@@ -80,6 +81,8 @@
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab);
+u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
@@ -91,8 +94,8 @@
u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
struct sta_info *sta, u8 *eid);
void ieee802_11_sa_query_action(struct hostapd_data *hapd,
- const u8 *sa, const u8 action_type,
- const u8 *trans_id);
+ const struct ieee80211_mgmt *mgmt,
+ size_t len);
u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
@@ -120,6 +123,9 @@
u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+ size_t len, int delta);
+
#else /* CONFIG_MBO */
static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
@@ -166,4 +172,7 @@
char **identity, char **radius_cui,
int is_probe_req);
+int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx);
+
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 5cb7fb1..931d4d0 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -289,6 +289,9 @@
return HOSTAPD_ACL_ACCEPT;
};
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ vlan_id = NULL;
+
/* Check whether ACL cache has an entry for this station */
res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval, vlan_id, psk,
@@ -516,7 +519,6 @@
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
- int *untagged, *tagged, *notempty;
query = hapd->acl_queries;
prev = NULL;
@@ -574,12 +576,10 @@
cache->acct_interim_interval = 0;
}
- notempty = &cache->vlan_id.notempty;
- untagged = &cache->vlan_id.untagged;
- tagged = cache->vlan_id.tagged;
- *notempty = !!radius_msg_get_vlanid(msg, untagged,
- MAX_NUM_TAGGED_VLAN,
- tagged);
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
+ cache->vlan_id.notempty = !!radius_msg_get_vlanid(
+ msg, &cache->vlan_id.untagged,
+ MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged);
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
msg, req, cache);
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 1a8d469..0721358 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -86,3 +86,34 @@
return pos;
}
+
+
+u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_mu_edca_parameter_set *edca;
+ u8 *pos;
+ size_t i;
+
+ pos = (u8 *) &hapd->iface->conf->he_mu_edca;
+ for (i = 0; i < sizeof(*edca); i++) {
+ if (pos[i])
+ break;
+ }
+ if (i == sizeof(*edca))
+ return eid; /* no MU EDCA Parameters configured */
+
+ pos = eid;
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + sizeof(*edca);
+ *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS;
+
+ edca = (struct ieee80211_he_mu_edca_parameter_set *) pos;
+ os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca));
+
+ wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element",
+ pos, sizeof(*edca));
+
+ pos += sizeof(*edca);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index c481399..d70d6c1 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -10,10 +10,12 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ocv.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "wpa_auth.h"
#include "ieee802_11.h"
@@ -49,7 +51,12 @@
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id)
{
- struct ieee80211_mgmt mgmt;
+#ifdef CONFIG_OCV
+ struct sta_info *sta;
+#endif /* CONFIG_OCV */
+ struct ieee80211_mgmt *mgmt;
+ u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
@@ -57,19 +64,61 @@
wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
trans_id, WLAN_SA_QUERY_TR_ID_LEN);
- os_memset(&mgmt, 0, sizeof(mgmt));
- mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(mgmt.da, addr, ETH_ALEN);
- os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
- mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
- mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
- os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+#ifdef CONFIG_OCV
+ sta = ap_get_sta(hapd, addr);
+ if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Request");
+ return;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for OCI element in SA Query Request");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(oci_ie);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ mgmt = os_zalloc(sizeof(*mgmt) + oci_ie_len);
+ if (!mgmt) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate buffer for SA Query Response frame");
+ os_free(oci_ie);
+ return;
+ }
+
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
+ mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+ os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
- end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+ end = mgmt->u.action.u.sa_query_req.variable;
+#ifdef CONFIG_OCV
+ if (oci_ie_len > 0) {
+ os_memcpy(end, oci_ie, oci_ie_len);
+ end += oci_ie_len;
+ }
+#endif /* CONFIG_OCV */
+ if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0)
wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed");
+
+ os_free(mgmt);
+ os_free(oci_ie);
}
@@ -77,7 +126,9 @@
const u8 *sa, const u8 *trans_id)
{
struct sta_info *sta;
- struct ieee80211_mgmt resp;
+ struct ieee80211_mgmt *resp;
+ u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
u8 *end;
wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
@@ -92,30 +143,115 @@
return;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Response");
+ return;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for for OCI element in SA Query Response");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(oci_ie);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ resp = os_zalloc(sizeof(*resp) + oci_ie_len);
+ if (!resp) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to allocate buffer for SA Query Response frame");
+ os_free(oci_ie);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
MACSTR, MAC2STR(sa));
- os_memset(&resp, 0, sizeof(resp));
- resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
- WLAN_FC_STYPE_ACTION);
- os_memcpy(resp.da, sa, ETH_ALEN);
- os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
- os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
- resp.u.action.category = WLAN_ACTION_SA_QUERY;
- resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
- os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(resp->da, sa, ETH_ALEN);
+ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+ resp->u.action.category = WLAN_ACTION_SA_QUERY;
+ resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+ os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id,
WLAN_SA_QUERY_TR_ID_LEN);
- end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
- if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+ end = resp->u.action.u.sa_query_req.variable;
+#ifdef CONFIG_OCV
+ if (oci_ie_len > 0) {
+ os_memcpy(end, oci_ie, oci_ie_len);
+ end += oci_ie_len;
+ }
+#endif /* CONFIG_OCV */
+ if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0)
wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed");
+
+ os_free(resp);
+ os_free(oci_ie);
}
-void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
- const u8 action_type, const u8 *trans_id)
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
{
struct sta_info *sta;
int i;
+ const u8 *sa = mgmt->sa;
+ const u8 action_type = mgmt->u.action.u.sa_query_resp.action;
+ const u8 *trans_id = mgmt->u.action.u.sa_query_resp.trans_id;
+
+ sta = ap_get_sta(hapd, sa);
+
+#ifdef CONFIG_OCV
+ if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct ieee802_11_elems elems;
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+ size_t ies_len;
+ const u8 *ies;
+
+ ies = mgmt->u.action.u.sa_query_resp.variable;
+ ies_len = len - (ies - (u8 *) mgmt);
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "SA Query: Failed to parse elements");
+ return;
+ }
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in SA Query Action frame");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sta->wpa_sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
if (action_type == WLAN_SA_QUERY_REQUEST) {
ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
@@ -135,7 +271,6 @@
/* MLME-SAQuery.confirm */
- sta = ap_get_sta(hapd, sa);
if (sta == NULL || sta->sa_query_trans_id == NULL) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
"pending SA Query request found");
@@ -237,6 +372,21 @@
*pos |= 0x01;
#endif /* CONFIG_FILS */
break;
+ case 10: /* Bits 80-87 */
+#ifdef CONFIG_SAE
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) {
+ int in_use = hostapd_sae_pw_id_in_use(hapd->conf);
+
+ if (in_use)
+ *pos |= 0x02; /* Bit 81 - SAE Password
+ * Identifiers In Use */
+ if (in_use == 2)
+ *pos |= 0x04; /* Bit 82 - SAE Password
+ * Identifiers Used Exclusively */
+ }
+#endif /* CONFIG_SAE */
+ break;
}
}
@@ -276,6 +426,12 @@
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
len = 10;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_SAE
+ if (len < 11 && hapd->conf->wpa &&
+ wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ hostapd_sae_pw_id_in_use(hapd->conf))
+ len = 11;
+#endif /* CONFIG_SAE */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -547,12 +703,29 @@
#ifdef CONFIG_MBO
+u8 * hostapd_eid_mbo_rssi_assoc_rej(struct hostapd_data *hapd, u8 *eid,
+ size_t len, int delta)
+{
+ u8 mbo[4];
+
+ mbo[0] = OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT;
+ mbo[1] = 2;
+ /* Delta RSSI */
+ mbo[2] = delta;
+ /* Retry delay */
+ mbo[3] = hapd->iconf->rssi_reject_assoc_timeout;
+
+ return eid + mbo_add_ie(eid, len, mbo, 4);
+}
+
+
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 mbo[9], *mbo_pos = mbo;
u8 *pos = eid;
- if (!hapd->conf->mbo_enabled && !hapd->enable_oce)
+ if (!hapd->conf->mbo_enabled &&
+ !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
return eid;
if (hapd->conf->mbo_enabled) {
@@ -568,12 +741,11 @@
*mbo_pos++ = hapd->mbo_assoc_disallow;
}
- if (hapd->enable_oce & (OCE_AP | OCE_STA_CFON)) {
+ if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
u8 ctrl;
ctrl = OCE_RELEASE;
- if ((hapd->enable_oce & (OCE_AP | OCE_STA_CFON)) ==
- OCE_STA_CFON)
+ if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
ctrl |= OCE_IS_STA_CFON;
*mbo_pos++ = OCE_ATTR_ID_CAPA_IND;
@@ -591,7 +763,8 @@
{
u8 len;
- if (!hapd->conf->mbo_enabled && !hapd->enable_oce)
+ if (!hapd->conf->mbo_enabled &&
+ !OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
return 0;
/*
@@ -603,7 +776,7 @@
len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
/* OCE capability indication attribute (3) */
- if (hapd->enable_oce & (OCE_AP | OCE_STA_CFON))
+ if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd))
len += 3;
return len;
@@ -751,3 +924,71 @@
return pos;
}
+
+
+#ifdef CONFIG_OCV
+int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx)
+{
+ int ht_40mhz = 0;
+ int vht_80p80 = 0;
+ int requested_bw;
+
+ if (sta->ht_capabilities)
+ ht_40mhz = !!(sta->ht_capabilities->ht_capabilities_info &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
+
+ if (sta->vht_operation) {
+ struct ieee80211_vht_operation *oper = sta->vht_operation;
+
+ /*
+ * If a VHT Operation element was present, use it to determine
+ * the supported channel bandwidth.
+ */
+ if (oper->vht_op_info_chwidth == 0) {
+ requested_bw = ht_40mhz ? 40 : 20;
+ } else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) {
+ requested_bw = 80;
+ } else {
+ int diff;
+
+ requested_bw = 160;
+ diff = abs((int)
+ oper->vht_op_info_chan_center_freq_seg0_idx -
+ (int)
+ oper->vht_op_info_chan_center_freq_seg1_idx);
+ vht_80p80 = oper->vht_op_info_chan_center_freq_seg1_idx
+ != 0 && diff > 16;
+ }
+ } else if (sta->vht_capabilities) {
+ struct ieee80211_vht_capabilities *capab;
+ int vht_chanwidth;
+
+ capab = sta->vht_capabilities;
+
+ /*
+ * If only the VHT Capabilities element is present (e.g., for
+ * normal clients), use it to determine the supported channel
+ * bandwidth.
+ */
+ vht_chanwidth = capab->vht_capabilities_info &
+ VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+ vht_80p80 = capab->vht_capabilities_info &
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+
+ /* TODO: Also take into account Extended NSS BW Support field */
+ requested_bw = vht_chanwidth ? 160 : 80;
+ } else {
+ requested_bw = ht_40mhz ? 40 : 20;
+ }
+
+ *bandwidth = requested_bw < ap_max_chanwidth ?
+ requested_bw : ap_max_chanwidth;
+
+ *seg1_idx = 0;
+ if (ap_seg1_idx && vht_80p80)
+ *seg1_idx = ap_seg1_idx;
+
+ return 0;
+}
+#endif /* CONFIG_OCV */
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 8d06620..54ee080 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -357,6 +357,29 @@
}
+u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_oper)
+{
+ if (!vht_oper) {
+ os_free(sta->vht_operation);
+ sta->vht_operation = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (!sta->vht_operation) {
+ sta->vht_operation =
+ os_zalloc(sizeof(struct ieee80211_vht_operation));
+ if (!sta->vht_operation)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ os_memcpy(sta->vht_operation, vht_oper,
+ sizeof(struct ieee80211_vht_operation));
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ie, size_t len)
{
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 985f8b7..a56c82e 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -682,7 +682,8 @@
#ifdef CONFIG_HS20
if (hapd->conf->hs20) {
- u8 ver = 1; /* Release 2 */
+ u8 ver = hapd->conf->hs20_release - 1;
+
if (!radius_msg_add_wfa(
msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION,
&ver, 1)) {
@@ -1741,6 +1742,45 @@
}
+#ifndef CONFIG_NO_VLAN
+static int ieee802_1x_update_vlan(struct radius_msg *msg,
+ struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct vlan_description vlan_desc;
+
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged,
+ MAX_NUM_TAGGED_VLAN,
+ vlan_desc.tagged);
+
+ if (vlan_desc.notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_desc.untagged,
+ vlan_desc.tagged[0] ? "+" : "");
+ os_memset(&vlan_desc, 0, sizeof(vlan_desc));
+ ap_sta_set_vlan(hapd, sta, &vlan_desc);
+ return -1;
+ }
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+ !vlan_desc.notempty) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_INFO,
+ "authentication server did not include required VLAN ID in Access-Accept");
+ return -1;
+ }
+
+ return ap_sta_set_vlan(hapd, sta, &vlan_desc);
+}
+#endif /* CONFIG_NO_VLAN */
+
+
/**
* ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
* @msg: RADIUS response message
@@ -1763,12 +1803,6 @@
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
- struct vlan_description vlan_desc;
-#ifndef CONFIG_NO_VLAN
- int *untagged, *tagged, *notempty;
-#endif /* CONFIG_NO_VLAN */
-
- os_memset(&vlan_desc, 0, sizeof(vlan_desc));
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
if (sm == NULL) {
@@ -1833,56 +1867,21 @@
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
#ifndef CONFIG_NO_VLAN
- if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
- notempty = &vlan_desc.notempty;
- untagged = &vlan_desc.untagged;
- tagged = vlan_desc.tagged;
- *notempty = !!radius_msg_get_vlanid(msg, untagged,
- MAX_NUM_TAGGED_VLAN,
- tagged);
- }
-
- if (vlan_desc.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
- sta->eapol_sm->authFail = TRUE;
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO,
- "Invalid VLAN %d%s received from RADIUS server",
- vlan_desc.untagged,
- vlan_desc.tagged[0] ? "+" : "");
- os_memset(&vlan_desc, 0, sizeof(vlan_desc));
- ap_sta_set_vlan(hapd, sta, &vlan_desc);
- break;
- }
-
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
- !vlan_desc.notempty) {
- sta->eapol_sm->authFail = TRUE;
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE8021X,
- HOSTAPD_LEVEL_INFO, "authentication "
- "server did not include required VLAN "
- "ID in Access-Accept");
- break;
- }
-#endif /* CONFIG_NO_VLAN */
-
- if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
+ if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+ ieee802_1x_update_vlan(msg, hapd, sta) < 0)
break;
-#ifndef CONFIG_NO_VLAN
if (sta->vlan_id > 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"VLAN ID %d", sta->vlan_id);
}
-#endif /* CONFIG_NO_VLAN */
if ((sta->flags & WLAN_STA_ASSOC) &&
ap_sta_bind_vlan(hapd, sta) < 0)
break;
+#endif /* CONFIG_NO_VLAN */
sta->session_timeout_set = !!session_timeout_set;
os_get_reltime(&sta->session_timeout);
@@ -2595,6 +2594,7 @@
struct os_reltime diff;
const char *name1;
const char *name2;
+ char *identity_buf = NULL;
if (sm == NULL)
return 0;
@@ -2710,6 +2710,14 @@
/* dot1xAuthSessionStatsTable */
os_reltime_age(&sta->acct_session_start, &diff);
+ if (sm->eap && !sm->identity) {
+ const u8 *id;
+ size_t id_len;
+
+ id = eap_get_identity(sm->eap, &id_len);
+ if (id)
+ identity_buf = dup_binstr(id, id_len);
+ }
ret = os_snprintf(buf + len, buflen - len,
/* TODO: dot1xAuthSessionOctetsRx */
/* TODO: dot1xAuthSessionOctetsTx */
@@ -2725,7 +2733,8 @@
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
1 : 2,
(unsigned int) diff.sec,
- sm->identity);
+ sm->identity ? (char *) sm->identity : identity_buf);
+ os_free(identity_buf);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index b8fd592..2b6f727 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "hostapd.h"
+#include "ieee802_11.h"
#include "neighbor_db.h"
@@ -123,7 +124,7 @@
}
-void hostpad_free_neighbor_db(struct hostapd_data *hapd)
+void hostapd_free_neighbor_db(struct hostapd_data *hapd)
{
struct hostapd_neighbor_entry *nr, *prev;
@@ -134,3 +135,123 @@
os_free(nr);
}
}
+
+
+#ifdef NEED_AP_MLME
+static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
+ int ht, int vht)
+{
+ if (!ht && !vht)
+ return NR_CHAN_WIDTH_20;
+ if (!hapd->iconf->secondary_channel)
+ return NR_CHAN_WIDTH_20;
+ if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
+ return NR_CHAN_WIDTH_40;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ return NR_CHAN_WIDTH_80;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
+ return NR_CHAN_WIDTH_160;
+ if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
+ return NR_CHAN_WIDTH_80P80;
+ return NR_CHAN_WIDTH_20;
+}
+#endif /* NEED_AP_MLME */
+
+
+void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
+{
+#ifdef NEED_AP_MLME
+ u16 capab = hostapd_own_capab_info(hapd);
+ int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
+ int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
+ struct wpa_ssid_value ssid;
+ u8 channel, op_class;
+ u8 center_freq1_idx = 0, center_freq2_idx = 0;
+ enum nr_chan_width width;
+ u32 bssid_info;
+ struct wpabuf *nr;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+ return;
+
+ bssid_info = 3; /* AP is reachable */
+ bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
+ bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
+
+ if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
+ bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
+
+ bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
+
+ if (hapd->conf->wmm_enabled) {
+ bssid_info |= NEI_REP_BSSID_INFO_QOS;
+
+ if (hapd->conf->wmm_uapsd &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+ bssid_info |= NEI_REP_BSSID_INFO_APSD;
+ }
+
+ if (ht) {
+ bssid_info |= NEI_REP_BSSID_INFO_HT |
+ NEI_REP_BSSID_INFO_DELAYED_BA;
+
+ /* VHT bit added in IEEE P802.11-REVmc/D4.3 */
+ if (vht)
+ bssid_info |= NEI_REP_BSSID_INFO_VHT;
+ }
+
+ /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
+
+ if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ &op_class, &channel) ==
+ NUM_HOSTAPD_MODES)
+ return;
+ width = hostapd_get_nr_chan_width(hapd, ht, vht);
+ if (vht) {
+ center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ if (width == NR_CHAN_WIDTH_80P80)
+ center_freq2_idx =
+ hapd->iconf->vht_oper_centr_freq_seg1_idx;
+ } else if (ht) {
+ ieee80211_freq_to_chan(hapd->iface->freq +
+ 10 * hapd->iconf->secondary_channel,
+ ¢er_freq1_idx);
+ }
+
+ ssid.ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+
+ /*
+ * Neighbor Report element size = BSSID + BSSID info + op_class + chan +
+ * phy type + wide bandwidth channel subelement.
+ */
+ nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
+ if (!nr)
+ return;
+
+ wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
+ wpabuf_put_le32(nr, bssid_info);
+ wpabuf_put_u8(nr, op_class);
+ wpabuf_put_u8(nr, channel);
+ wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
+
+ /*
+ * Wide Bandwidth Channel subelement may be needed to allow the
+ * receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
+ * Figure 9-301.
+ */
+ wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
+ wpabuf_put_u8(nr, 3);
+ wpabuf_put_u8(nr, width);
+ wpabuf_put_u8(nr, center_freq1_idx);
+ wpabuf_put_u8(nr, center_freq2_idx);
+
+ hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
+ hapd->iconf->civic, hapd->iconf->stationary_ap);
+
+ wpabuf_free(nr);
+#endif /* NEED_AP_MLME */
+}
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
index ba46d88..9c8f4f2 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -17,8 +17,9 @@
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,
const struct wpabuf *civic, int stationary);
+void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
-void hostpad_free_neighbor_db(struct hostapd_data *hapd);
+void hostapd_free_neighbor_db(struct hostapd_data *hapd);
#endif /* NEIGHBOR_DB_H */
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
index 56ed29c..f2d5cd1 100644
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
@@ -558,7 +558,7 @@
void hostapd_clean_rrm(struct hostapd_data *hapd)
{
- hostpad_free_neighbor_db(hapd);
+ hostapd_free_neighbor_db(hapd);
eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
hapd->lci_req_active = 0;
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 179cf43..4a7722c 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -166,7 +166,7 @@
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
- if (sta->flags & WLAN_STA_WDS)
+ if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
if (sta->ipaddr)
@@ -328,6 +328,7 @@
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
+ os_free(sta->vht_operation);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -500,6 +501,13 @@
} else if (sta->timeout_next != STA_REMOVE) {
int deauth = sta->timeout_next == STA_DEAUTH;
+ if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) {
+ /* Cannot disassociate not-associated STA, so move
+ * directly to deauthentication. */
+ sta->timeout_next = STA_DEAUTH;
+ deauth = 1;
+ }
+
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
"Timeout, sending %s info to STA " MACSTR,
deauth ? "deauthentication" : "disassociation",
@@ -896,9 +904,6 @@
struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
int old_vlan_id, vlan_id = 0, ret = 0;
- if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- vlan_desc = NULL;
-
/* Check if there is something to do */
if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
/* This sta is lacking its own vif */
@@ -1165,6 +1170,32 @@
#endif /* CONFIG_IEEE80211W */
+const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct hostapd_wpa_psk *psk;
+ struct hostapd_ssid *ssid;
+ const u8 *pmk;
+ int pmk_len;
+
+ ssid = &hapd->conf->ssid;
+
+ pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
+ if (!pmk || pmk_len != PMK_LEN)
+ return NULL;
+
+ for (psk = ssid->wpa_psk; psk; psk = psk->next)
+ if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
+ break;
+ if (!psk)
+ return NULL;
+ if (!psk || !psk->keyid[0])
+ return NULL;
+
+ return psk->keyid;
+}
+
+
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
@@ -1203,7 +1234,11 @@
sta->addr, authorized, dev_addr);
if (authorized) {
+ const char *keyid;
+ char keyid_buf[100];
char ip_addr[100];
+
+ keyid_buf[0] = '\0';
ip_addr[0] = '\0';
#ifdef CONFIG_P2P
if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
@@ -1214,14 +1249,20 @@
}
#endif /* CONFIG_P2P */
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
- buf, ip_addr);
+ keyid = ap_sta_wpa_get_keyid(hapd, sta);
+ if (keyid) {
+ os_snprintf(keyid_buf, sizeof(keyid_buf),
+ " keyid=%s", keyid);
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
+ buf, ip_addr, keyid_buf);
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
- AP_STA_CONNECTED "%s%s",
- buf, ip_addr);
+ AP_STA_CONNECTED "%s%s%s",
+ buf, ip_addr, keyid_buf);
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9cac6f1..ee3f628 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -36,6 +36,7 @@
#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_FILS_ERP BIT(22)
+#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -117,6 +118,7 @@
unsigned int power_capab:1;
unsigned int agreed_to_steer:1;
unsigned int hs20_t_c_filtering:1;
+ unsigned int ft_over_ds:1;
u16 auth_alg;
@@ -162,6 +164,7 @@
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
+ struct ieee80211_vht_operation *vht_operation;
u8 vht_opmode;
#ifdef CONFIG_IEEE80211W
@@ -215,6 +218,7 @@
u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise,
* enum mbo_cellular_capa values */
struct mbo_non_pref_chan_info *non_pref_chan;
+ int auth_rssi; /* Last Authentication frame RSSI */
#endif /* CONFIG_MBO */
u8 *supp_op_classes; /* Supported Operating Classes element, if
@@ -320,6 +324,8 @@
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
+const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
+ struct sta_info *sta);
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason);
diff --git a/src/ap/vlan_full.c b/src/ap/vlan_full.c
index aa42335..19aa3c6 100644
--- a/src/ap/vlan_full.c
+++ b/src/ap/vlan_full.c
@@ -16,6 +16,7 @@
#include "utils/common.h"
#include "drivers/priv_netlink.h"
+#include "drivers/linux_ioctl.h"
#include "common/linux_bridge.h"
#include "common/linux_vlan.h"
#include "utils/eloop.h"
@@ -143,6 +144,9 @@
return -1;
}
+ if (linux_br_del_if(fd, br_name, if_name) == 0)
+ goto done;
+
if_index = if_nametoindex(if_name);
if (if_index == 0) {
@@ -168,6 +172,7 @@
return -1;
}
+done:
close(fd);
return 0;
}
@@ -194,6 +199,14 @@
return -1;
}
+ if (linux_br_add_if(fd, br_name, if_name) == 0)
+ goto done;
+ if (errno == EBUSY) {
+ /* The interface is already added. */
+ close(fd);
+ return 1;
+ }
+
if_index = if_nametoindex(if_name);
if (if_index == 0) {
@@ -224,6 +237,7 @@
return -1;
}
+done:
close(fd);
return 0;
}
@@ -241,6 +255,9 @@
return -1;
}
+ if (linux_br_del(fd, br_name) == 0)
+ goto done;
+
arg[0] = BRCTL_DEL_BRIDGE;
arg[1] = (unsigned long) br_name;
@@ -252,6 +269,7 @@
return -1;
}
+done:
close(fd);
return 0;
}
@@ -277,11 +295,19 @@
return -1;
}
+ if (linux_br_add(fd, br_name) == 0)
+ goto done;
+ if (errno == EEXIST) {
+ /* The bridge is already added. */
+ close(fd);
+ return 1;
+ }
+
arg[0] = BRCTL_ADD_BRIDGE;
arg[1] = (unsigned long) br_name;
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
- if (errno == EEXIST) {
+ if (errno == EEXIST) {
/* The bridge is already added. */
close(fd);
return 1;
@@ -294,6 +320,7 @@
}
}
+done:
/* Decrease forwarding delay to avoid EAPOL timeouts. */
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
@@ -363,12 +390,18 @@
{
char vlan_ifname[IFNAMSIZ];
int clean;
+ int ret;
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
- tagged_interface, vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
else
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
+ vid);
+ if (ret >= (int) sizeof(vlan_ifname))
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan_ifname);
clean = 0;
ifconfig_up(tagged_interface);
@@ -384,19 +417,28 @@
}
-static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
+static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd,
+ struct hostapd_vlan *vlan, int vid)
{
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int ret;
- if (hapd->conf->vlan_bridge[0]) {
- os_snprintf(br_name, IFNAMSIZ, "%s%d",
- hapd->conf->vlan_bridge, vid);
+ if (vlan->bridge[0]) {
+ os_strlcpy(br_name, vlan->bridge, IFNAMSIZ);
+ ret = 0;
+ } else if (hapd->conf->vlan_bridge[0]) {
+ ret = os_snprintf(br_name, IFNAMSIZ, "%s%d",
+ hapd->conf->vlan_bridge, vid);
} else if (tagged_interface) {
- os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
- tagged_interface, vid);
+ ret = os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
+ tagged_interface, vid);
} else {
- os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
+ ret = os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
}
+ if (ret >= IFNAMSIZ)
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ br_name);
}
@@ -445,7 +487,7 @@
!br_addif(hapd->conf->bridge, ifname))
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
- vlan_bridge_name(br_name, hapd, untagged);
+ vlan_bridge_name(br_name, hapd, vlan, untagged);
vlan_get_bridge(br_name, hapd, untagged);
@@ -458,7 +500,7 @@
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
(i > 0 && tagged[i] == tagged[i - 1]))
continue;
- vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
vlan_get_bridge(br_name, hapd, tagged[i]);
vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
ifname, br_name, tagged[i], hapd);
@@ -474,12 +516,19 @@
{
char vlan_ifname[IFNAMSIZ];
int clean;
+ int ret;
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
- tagged_interface, vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
else
- os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+ ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d",
+ vid);
+ if (ret >= (int) sizeof(vlan_ifname))
+ wpa_printf(MSG_WARNING,
+ "VLAN: Interface name was truncated to %s",
+ vlan_ifname);
+
clean = dyn_iface_put(hapd, vlan_ifname);
@@ -543,7 +592,7 @@
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
(i > 0 && tagged[i] == tagged[i - 1]))
continue;
- vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_bridge_name(br_name, hapd, vlan, tagged[i]);
vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
ifname, br_name, tagged[i], hapd);
vlan_put_bridge(br_name, hapd, tagged[i]);
@@ -555,7 +604,7 @@
(vlan->clean & DVLAN_CLEAN_WLAN_PORT))
br_delif(hapd->conf->bridge, ifname);
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
- vlan_bridge_name(br_name, hapd, untagged);
+ vlan_bridge_name(br_name, hapd, vlan, untagged);
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
br_delif(br_name, vlan->ifname);
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 01fecee..e293a00 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -187,6 +187,7 @@
{
struct hostapd_vlan *n;
char ifname[IFNAMSIZ + 1], *pos;
+ int ret;
if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
return NULL;
@@ -208,8 +209,13 @@
n->vlan_desc = *vlan_desc;
n->dynamic_vlan = 1;
- os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
- pos);
+ ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
+ ifname, vlan_id, pos);
+ if (os_snprintf_error(sizeof(n->ifname), ret)) {
+ os_free(n);
+ return NULL;
+ }
+ os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
n->next = hapd->conf->vlan;
hapd->conf->vlan = n;
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 61d2f65..27c69d3 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/ocv.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ap_config.h"
@@ -54,8 +55,8 @@
size_t gtk_elem_len = 0;
size_t igtk_elem_len = 0;
struct wnm_sleep_element wnmsleep_ie;
- u8 *wnmtfs_ie;
- u8 wnmsleep_ie_len;
+ u8 *wnmtfs_ie, *oci_ie;
+ u8 wnmsleep_ie_len, oci_ie_len;
u16 wnmtfs_ie_len;
u8 *pos;
struct sta_info *sta;
@@ -88,10 +89,42 @@
wnmtfs_ie = NULL;
}
+ oci_ie = NULL;
+ oci_ie_len = 0;
+#ifdef CONFIG_OCV
+ if (action_type == WNM_SLEEP_MODE_EXIT &&
+ wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(wnmtfs_ie);
+ os_free(oci_ie);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
#define MAX_GTK_SUBELEM_LEN 45
#define MAX_IGTK_SUBELEM_LEN 26
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
- MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+ MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
+ oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Response action frame");
@@ -134,11 +167,18 @@
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
pos += wnmsleep_ie_len;
- if (wnmtfs_ie)
+ if (wnmtfs_ie) {
os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+ pos += wnmtfs_ie_len;
+ }
+#ifdef CONFIG_OCV
+ /* copy OCV OCI here */
+ if (oci_ie_len > 0)
+ os_memcpy(pos, oci_ie, oci_ie_len);
+#endif /* CONFIG_OCV */
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
- igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+ igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
/* In driver, response frame should be forced to sent when STA is in
* PS mode */
@@ -185,6 +225,7 @@
#undef MAX_IGTK_SUBELEM_LEN
fail:
os_free(wnmtfs_ie);
+ os_free(oci_ie);
os_free(mgmt);
return res;
}
@@ -201,6 +242,11 @@
u8 *tfsreq_ie_start = NULL;
u8 *tfsreq_ie_end = NULL;
u16 tfsreq_ie_len = 0;
+#ifdef CONFIG_OCV
+ struct sta_info *sta;
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
if (!hapd->conf->wnm_sleep_mode) {
wpa_printf(MSG_DEBUG, "Ignore WNM-Sleep Mode Request from "
@@ -228,6 +274,12 @@
if (!tfsreq_ie_start)
tfsreq_ie_start = (u8 *) pos;
tfsreq_ie_end = (u8 *) pos;
+#ifdef CONFIG_OCV
+ } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+ pos[2] == WLAN_EID_EXT_OCV_OCI) {
+ oci_ie = pos + 3;
+ oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
} else
wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
*pos);
@@ -239,6 +291,27 @@
return;
}
+#ifdef CONFIG_OCV
+ sta = ap_get_sta(hapd, addr);
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+ sta && wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+
+ if (hostapd_drv_channel_info(hapd, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+ return;
+ }
+
+ if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(hapd, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
tfsreq_ie_start && tfsreq_ie_end &&
tfsreq_ie_end - tfsreq_ie_start >= 0) {
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 34969e7..3021a8c 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -13,6 +13,7 @@
#include "utils/state_machine.h"
#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
+#include "common/ocv.h"
#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes_siv.h"
@@ -22,6 +23,7 @@
#include "crypto/sha384.h"
#include "crypto/random.h"
#include "eapol_auth/eapol_auth_sm.h"
+#include "drivers/driver.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
@@ -238,6 +240,17 @@
}
+#ifdef CONFIG_OCV
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+ struct wpa_channel_info *ci)
+{
+ if (!wpa_auth->cb->channel_info)
+ return -1;
+ return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
+}
+#endif /* CONFIG_OCV */
+
+
static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
@@ -332,6 +345,10 @@
wpa_get_ntp_timestamp(buf + ETH_ALEN);
ptr = (unsigned long) group;
os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
+#ifdef TEST_FUZZ
+ os_memset(buf + ETH_ALEN, 0xab, 8);
+ os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
+#endif /* TEST_FUZZ */
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
@@ -860,6 +877,8 @@
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
data, data_len) == 0) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
ok = 1;
break;
}
@@ -1202,6 +1221,11 @@
wpa_try_alt_snonce(sm, data, data_len))) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
return;
}
#ifdef CONFIG_FILS
@@ -1210,9 +1234,17 @@
&key_data_length) < 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
return;
}
#endif /* CONFIG_FILS */
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
sm->MICVerified = TRUE;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
@@ -1317,6 +1349,9 @@
os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
pos = data + ETH_ALEN + WPA_NONCE_LEN;
wpa_get_ntp_timestamp(pos);
+#ifdef TEST_FUZZ
+ os_memset(pos, 0xef, 8);
+#endif /* TEST_FUZZ */
pos += 8;
if (random_get_bytes(pos, gtk_len) < 0)
ret = -1;
@@ -1596,6 +1631,9 @@
timeout_ms = eapol_key_timeout_no_retrans;
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
sm->pending_1_of_4_timeout = 1;
+#ifdef TEST_FUZZ
+ timeout_ms = 1;
+#endif /* TEST_FUZZ */
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
"counter %u)", timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
@@ -2559,6 +2597,27 @@
wpabuf_put(plain, tmp2 - tmp);
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
+
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "FILS: Failed to get channel info for OCI element");
+ wpabuf_free(plain);
+ return NULL;
+ }
+
+ pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0) {
+ wpabuf_free(plain);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
+
return plain;
}
@@ -2624,6 +2683,21 @@
#endif /* CONFIG_FILS */
+#ifdef CONFIG_OCV
+int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx)
+{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+
+ if (!wpa_auth->cb->get_sta_tx_params)
+ return -1;
+ return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr,
+ ap_max_chanwidth, ap_seg1_idx,
+ bandwidth, seg1_idx);
+}
+#endif /* CONFIG_OCV */
+
+
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_authenticator *wpa_auth = sm->wpa_auth;
@@ -2675,6 +2749,8 @@
wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
ok = 1;
break;
}
@@ -2746,6 +2822,32 @@
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(wpa_auth, &ci) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
wpa_sta_disconnect(wpa_auth, sm->addr,
@@ -2883,6 +2985,36 @@
#endif /* CONFIG_IEEE80211W */
+static int ocv_oci_len(struct wpa_state_machine *sm)
+{
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm))
+ return OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
+ return 0;
+}
+
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
+{
+#ifdef CONFIG_OCV
+ struct wpa_channel_info ci;
+
+ if (!wpa_auth_uses_ocv(sm))
+ return 0;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element");
+ return -1;
+ }
+
+ return ocv_insert_oci_kde(&ci, argpos);
+#else /* CONFIG_OCV */
+ return 0;
+#endif /* CONFIG_OCV */
+}
+
+
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
@@ -2966,7 +3098,7 @@
}
}
- kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -3011,6 +3143,10 @@
gtk, gtk_len);
}
pos = ieee80211w_kde_add(sm, pos);
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde);
+ return;
+ }
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -3322,7 +3458,7 @@
}
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
- ieee80211w_kde_len(sm);
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
if (kde_buf == NULL)
return;
@@ -3333,6 +3469,10 @@
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde_buf);
+ return;
+ }
kde_len = pos - kde;
} else {
kde = gtk;
@@ -3353,8 +3493,67 @@
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
+#ifdef CONFIG_OCV
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ const u8 *key_data, *mic;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ struct wpa_eapol_ie_parse kde;
+ size_t mic_len;
+ u16 key_data_length;
+#endif /* CONFIG_OCV */
+
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
sm->EAPOLKeyReceived = FALSE;
+
+#ifdef CONFIG_OCV
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+
+ /*
+ * Note: last_rx_eapol_key length fields have already been validated in
+ * wpa_receive().
+ */
+ hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ mic = (u8 *) (key + 1);
+ key_data = mic + mic_len + 2;
+ key_data_length = WPA_GET_BE16(mic + mic_len);
+ if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
+ sizeof(*key) - mic_len - 2)
+ return;
+
+ if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key group msg 2/2 with invalid Key Data contents");
+ return;
+ }
+
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(wpa_auth, &ci) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
@@ -3963,6 +4162,15 @@
}
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
+{
+ if (!sm)
+ return NULL;
+ *len = sm->pmk_len;
+ return sm->PMK;
+}
+
+
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
if (sm == NULL)
@@ -4666,7 +4874,7 @@
}
}
- kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
#ifdef CONFIG_IEEE80211R_AP
@@ -4715,6 +4923,10 @@
os_memset(opos, 0, 6); /* clear PN */
}
#endif /* CONFIG_IEEE80211W */
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde);
+ return -1;
+ }
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -4796,7 +5008,7 @@
gtk = gsm->GTK[gsm->GN - 1];
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
- ieee80211w_kde_len(sm);
+ ieee80211w_kde_len(sm) + ocv_oci_len(sm);
kde_buf = os_malloc(kde_len);
if (kde_buf == NULL)
return -1;
@@ -4816,6 +5028,10 @@
os_memset(opos, 0, 6); /* clear PN */
}
#endif /* CONFIG_IEEE80211W */
+ if (ocv_oci_add(sm, &pos) < 0) {
+ os_free(kde_buf);
+ return -1;
+ }
kde_len = pos - kde;
} else {
kde = gtk;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index fad5536..e61648d 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -145,6 +145,7 @@
struct rsn_pmksa_cache_entry;
struct eapol_state_machine;
struct ft_remote_seq;
+struct wpa_channel_info;
struct ft_remote_r0kh {
@@ -191,6 +192,9 @@
int group_mgmt_cipher;
int sae_require_mfp;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ int ocv; /* Operating Channel Validation */
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
@@ -265,6 +269,10 @@
size_t data_len);
int (*send_oui)(void *ctx, const u8 *dst, u8 oui_suffix, const u8 *data,
size_t data_len);
+ int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
+ int (*get_sta_tx_params)(void *ctx, const u8 *addr,
+ int ap_max_chanwidth, int ap_seg1_idx,
+ int *bandwidth, int *seg1_idx);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*set_vlan)(void *ctx, const u8 *sta_addr,
@@ -316,6 +324,8 @@
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
int wpa_auth_uses_mfp(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 *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *p2p_dev_addr);
@@ -339,6 +349,7 @@
void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
@@ -449,6 +460,9 @@
int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len);
+int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
+ int ap_seg1_idx, int *bandwidth, int *seg1_idx);
+
int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384,
u8 *buf, size_t len);
void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e8d46ab..ac736f0 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -13,6 +13,8 @@
#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
#include "crypto/aes.h"
#include "crypto/aes_siv.h"
#include "crypto/aes_wrap.h"
@@ -727,6 +729,17 @@
}
+#ifdef CONFIG_OCV
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+ struct wpa_channel_info *ci)
+{
+ if (!wpa_auth->cb->channel_info)
+ return -1;
+ return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
+}
+#endif /* CONFIG_OCV */
+
+
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
@@ -1451,7 +1464,7 @@
now.sec;
else if (session_timeout && r1->session_timeout)
*session_timeout = 1;
- else
+ else if (session_timeout)
*session_timeout = 0;
return 0;
}
@@ -2430,6 +2443,35 @@
os_free(igtk);
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ u8 *nbuf, *ocipos;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element");
+ os_free(subelem);
+ return NULL;
+ }
+
+ subelem_len += 2 + OCV_OCI_LEN;
+ nbuf = os_realloc(subelem, subelem_len);
+ if (!nbuf) {
+ os_free(subelem);
+ return NULL;
+ }
+ subelem = nbuf;
+
+ ocipos = subelem + subelem_len - 2 - OCV_OCI_LEN;
+ *ocipos++ = FTIE_SUBELEM_OCI;
+ *ocipos++ = OCV_OCI_LEN;
+ if (ocv_insert_oci(&ci, &ocipos) < 0) {
+ os_free(subelem);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
} else {
r0kh_id = conf->r0_key_holder;
r0kh_id_len = conf->r0_key_holder_len;
@@ -2596,6 +2638,8 @@
os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN);
if (out_pairwise)
*out_pairwise = pairwise;
+ os_memcpy(sm->PMK, pmk, PMK_LEN);
+ sm->pmk_len = PMK_LEN;
if (out_vlan &&
wpa_ft_get_vlan(sm->wpa_auth, sm->addr, out_vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: vlan not available for STA "
@@ -3178,6 +3222,32 @@
return WLAN_STATUS_INVALID_FTIE;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in (Re)Assoc Request");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ }
+#endif /* CONFIG_OCV */
+
return WLAN_STATUS_SUCCESS;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 8127403..9091f43 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -27,6 +27,7 @@
#include "tkip_countermeasures.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
+#include "ieee802_11.h"
#include "pmksa_cache_auth.h"
#include "wpa_auth.h"
#include "wpa_auth_glue.h"
@@ -55,6 +56,9 @@
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
+#ifdef CONFIG_OCV
+ wconf->ocv = conf->ocv;
+#endif /* CONFIG_OCV */
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
@@ -776,6 +780,35 @@
}
+static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hostapd_drv_channel_info(hapd, ci);
+}
+
+
+#ifdef CONFIG_OCV
+static int hostapd_get_sta_tx_params(void *ctx, const u8 *addr,
+ int ap_max_chanwidth, int ap_seg1_idx,
+ int *bandwidth, int *seg1_idx)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta) {
+ hostapd_wpa_auth_logger(hapd, addr, LOGGER_INFO,
+ "Failed to get STA info to validate received OCI");
+ return -1;
+ }
+
+ return get_tx_parameters(sta, ap_max_chanwidth, ap_seg1_idx, bandwidth,
+ seg1_idx);
+}
+#endif /* CONFIG_OCV */
+
+
#ifdef CONFIG_IEEE80211R_AP
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
@@ -814,12 +847,18 @@
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
+ " based on WPA authenticator callback",
+ MAC2STR(sta_addr));
if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
+ if (hapd->driver && hapd->driver->add_sta_node)
+ sta->added_unassoc = 1;
+ sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
return sta->wpa_sm;
@@ -1189,6 +1228,10 @@
.for_each_auth = hostapd_wpa_auth_for_each_auth,
.send_ether = hostapd_wpa_auth_send_ether,
.send_oui = hostapd_wpa_auth_send_oui,
+ .channel_info = hostapd_channel_info,
+#ifdef CONFIG_OCV
+ .get_sta_tx_params = hostapd_get_sta_tx_params,
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
.send_ft_action = hostapd_wpa_auth_send_ft_action,
.add_sta = hostapd_wpa_auth_add_sta,
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index b1cea1b..a349304 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -92,6 +92,9 @@
#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+#ifdef CONFIG_OCV
+ unsigned int ocv_enabled:1;
+#endif /* CONFIG_OCV */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 253fe6e..3bcbef7 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -293,9 +293,13 @@
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing)
- capab |= BIT(8) | BIT(14) | BIT(15);
+ capab |= BIT(8) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -414,6 +418,10 @@
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
eid += 2;
@@ -553,6 +561,19 @@
if (version == WPA_PROTO_RSN) {
res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
+ if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie &&
+ !wpa_key_mgmt_only_ft(data.key_mgmt)) {
+ /* Workaround for some HP and Epson printers that seem
+ * to incorrectly copy the FT-PSK + WPA-PSK AKMs from AP
+ * advertised RSNE to Association Request frame. */
+ wpa_printf(MSG_DEBUG,
+ "RSN: FT set in RSNE AKM but MDE is missing from "
+ MACSTR
+ " - ignore FT AKM(s) because there's also a non-FT AKM",
+ MAC2STR(sm->addr));
+ data.key_mgmt &= ~WPA_KEY_MGMT_FT;
+ }
+
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
@@ -760,6 +781,17 @@
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OCV
+ if ((data.capabilities & WPA_CAPABILITY_OCVC) &&
+ !(data.capabilities & WPA_CAPABILITY_MFPC)) {
+ wpa_printf(MSG_DEBUG,
+ "Management frame protection required with OCV, but client did not enable it");
+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+ }
+ wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
+ (data.capabilities & WPA_CAPABILITY_OCVC));
+#endif /* CONFIG_OCV */
+
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
!(data.capabilities & WPA_CAPABILITY_MFPC))
sm->mgmt_frame_prot = 0;
@@ -995,6 +1027,15 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
@@ -1062,13 +1103,34 @@
}
+#ifdef CONFIG_OCV
+
+void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv)
+{
+ if (sm)
+ sm->ocv_enabled = ocv;
+}
+
+
+int wpa_auth_uses_ocv(struct wpa_state_machine *sm)
+{
+ return sm ? sm->ocv_enabled : 0;
+}
+
+#endif /* CONFIG_OCV */
+
+
#ifdef CONFIG_OWE
u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len)
{
int res;
- struct wpa_auth_config *conf = &sm->wpa_auth->conf;
+ struct wpa_auth_config *conf;
+
+ if (!sm)
+ return pos;
+ conf = &sm->wpa_auth->conf;
#ifdef CONFIG_TESTING_OPTIONS
if (conf->own_ie_override_len) {
@@ -1082,7 +1144,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len,
+ res = wpa_write_rsn_ie(conf, pos, max_len,
sm->pmksa ? sm->pmksa->pmkid : NULL);
if (res < 0)
return pos;
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index 73e4333..a38b206 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -33,6 +33,10 @@
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
const u8 *osen;
size_t osen_len;
diff --git a/src/common/defs.h b/src/common/defs.h
index c968cd6..4faf1c8 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -59,6 +59,13 @@
#define WPA_KEY_MGMT_DPP BIT(23)
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
+#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
+ WPA_KEY_MGMT_FT_IEEE8021X | \
+ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \
+ WPA_KEY_MGMT_FT_SAE | \
+ WPA_KEY_MGMT_FT_FILS_SHA256 | \
+ WPA_KEY_MGMT_FT_FILS_SHA384)
+
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
@@ -86,12 +93,14 @@
static inline int wpa_key_mgmt_ft(int akm)
{
- return !!(akm & (WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
- WPA_KEY_MGMT_FT_SAE |
- WPA_KEY_MGMT_FT_FILS_SHA256 |
- WPA_KEY_MGMT_FT_FILS_SHA384));
+ return !!(akm & WPA_KEY_MGMT_FT);
+}
+
+static inline int wpa_key_mgmt_only_ft(int akm)
+{
+ int ft = wpa_key_mgmt_ft(akm);
+ akm &= ~WPA_KEY_MGMT_FT;
+ return ft && !akm;
}
static inline int wpa_key_mgmt_ft_psk(int akm)
@@ -399,4 +408,15 @@
#define OCE_STA_CFON BIT(1)
#define OCE_AP BIT(2)
+/* enum chan_width - Channel width definitions */
+enum chan_width {
+ CHAN_WIDTH_20_NOHT,
+ CHAN_WIDTH_20,
+ CHAN_WIDTH_40,
+ CHAN_WIDTH_80,
+ CHAN_WIDTH_80P80,
+ CHAN_WIDTH_160,
+ CHAN_WIDTH_UNKNOWN
+};
+
#endif /* DEFS_H */
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 677f586..bcb694b 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -813,7 +813,9 @@
const unsigned char *pk;
int ppklen;
X509_ALGOR *pa;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20800000L)
ASN1_OBJECT *pa_oid;
#else
const ASN1_OBJECT *pa_oid;
@@ -2854,7 +2856,7 @@
i_pubkey_hash = test_hash;
} else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
- status = -1;
+ status = 255;
} else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
i_nonce = NULL;
@@ -3457,7 +3459,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (!auth->initiator) {
+ if (!auth->initiator || !auth->peer_bi) {
dpp_auth_fail(auth, "Unexpected Authentication Response");
return NULL;
}
@@ -3638,7 +3640,7 @@
goto fail;
}
- if (auth->own_bi && auth->peer_bi) {
+ if (auth->own_bi) {
/* Mutual authentication */
if (dpp_auth_derive_l_initiator(auth) < 0)
goto fail;
@@ -3846,7 +3848,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (auth->initiator) {
+ if (auth->initiator || !auth->own_bi) {
dpp_auth_fail(auth, "Unexpected Authentication Confirm");
return -1;
}
@@ -3904,7 +3906,7 @@
"Initiator Bootstrapping Key Hash mismatch");
return -1;
}
- } else if (auth->own_bi && auth->peer_bi) {
+ } else if (auth->peer_bi) {
/* Mutual authentication and peer did not include its
* Bootstrapping Key Hash attribute. */
dpp_auth_fail(auth,
@@ -4757,7 +4759,7 @@
goto fail;
}
if (os_strcmp(token->string, "EC") != 0) {
- wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s",
+ wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
token->string);
goto fail;
}
@@ -6586,6 +6588,32 @@
}
+static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
+ const char *identifier)
+{
+ if (!attr_id && identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No PKEX code identifier received, but expected one");
+ return 0;
+ }
+
+ if (attr_id && !identifier) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: PKEX code identifier received, but not expecting one");
+ return 0;
+ }
+
+ if (attr_id && identifier &&
+ (os_strlen(identifier) != attr_id_len ||
+ os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
+ wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
+ return 0;
+ }
+
+ return 1;
+}
+
+
struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
struct dpp_bootstrap_info *bi,
const u8 *own_mac,
@@ -6630,19 +6658,11 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
+ attr_id_len = 0;
attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
&attr_id_len);
- if (!attr_id && identifier) {
- wpa_printf(MSG_DEBUG,
- "DPP: No PKEX code identifier received, but expected one");
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
return NULL;
- }
- if (attr_id && identifier &&
- (os_strlen(identifier) != attr_id_len ||
- os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
- wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
- return NULL;
- }
attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
&attr_group_len);
@@ -7014,16 +7034,11 @@
return NULL;
}
+ attr_id_len = 0;
attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
&attr_id_len);
- if (!attr_id && pkex->identifier) {
- wpa_printf(MSG_DEBUG,
- "DPP: No PKEX code identifier received, but expected one");
- return NULL;
- }
- if (attr_id && pkex->identifier &&
- (os_strlen(pkex->identifier) != attr_id_len ||
- os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) {
+ if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
+ pkex->identifier)) {
dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
return NULL;
}
diff --git a/src/common/gas_server.c b/src/common/gas_server.c
index b258675..ca46758 100644
--- a/src/common/gas_server.c
+++ b/src/common/gas_server.c
@@ -97,8 +97,10 @@
return;
response = os_zalloc(sizeof(*response));
- if (!response)
+ if (!response) {
+ wpabuf_free(query_resp);
return;
+ }
wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response);
response->freq = freq;
response->handler = handler;
@@ -119,6 +121,7 @@
handler->adv_proto_id_len +
resp_frag_len);
if (!resp) {
+ wpabuf_free(query_resp);
gas_server_free_response(response);
return;
}
@@ -257,6 +260,7 @@
handler->adv_proto_id_len +
resp_frag_len);
if (!resp) {
+ dl_list_del(&response->list);
gas_server_free_response(response);
return;
}
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index db40379..49ed806 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -87,13 +87,29 @@
int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
int sec_chan)
{
- int ok, j, first;
+ int ok, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
149, 157, 165, 184, 192 };
size_t k;
+ struct hostapd_channel_data *p_chan, *s_chan;
+ const int ht40_plus = pri_chan < sec_chan;
- if (pri_chan == sec_chan || !sec_chan)
- return 1; /* HT40 not used */
+ p_chan = hw_get_channel_chan(mode, pri_chan, NULL);
+ if (!p_chan)
+ return 0;
+
+ if (pri_chan == sec_chan || !sec_chan) {
+ if (chan_pri_allowed(p_chan))
+ return 1; /* HT40 not used */
+
+ wpa_printf(MSG_ERROR, "Channel %d is not allowed as primary",
+ pri_chan);
+ return 0;
+ }
+
+ s_chan = hw_get_channel_chan(mode, sec_chan, NULL);
+ if (!s_chan)
+ return 0;
wpa_printf(MSG_DEBUG,
"HT40: control channel: %d secondary channel: %d",
@@ -101,16 +117,9 @@
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
- ok = 0;
- for (j = 0; j < mode->num_channels; j++) {
- struct hostapd_channel_data *chan = &mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- chan->chan == sec_chan) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
+ if ((s_chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ (ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) ||
+ (!ht40_plus && !(p_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))) {
wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
sec_chan);
return 0;
@@ -553,3 +562,59 @@
}
#endif /* CONFIG_IEEE80211AC */
+
+
+u32 num_chan_to_bw(int num_chans)
+{
+ switch (num_chans) {
+ case 2:
+ case 4:
+ case 8:
+ return num_chans * 20;
+ default:
+ return 20;
+ }
+}
+
+
+/* check if BW is applicable for channel */
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri)
+{
+ u32 bw_mask;
+
+ switch (bw) {
+ case 20:
+ bw_mask = HOSTAPD_CHAN_WIDTH_20;
+ break;
+ case 40:
+ /* HT 40 MHz support declared only for primary channel,
+ * just skip 40 MHz secondary checking */
+ if (pri && ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40P;
+ else if (pri && !ht40_plus)
+ bw_mask = HOSTAPD_CHAN_WIDTH_40M;
+ else
+ bw_mask = 0;
+ break;
+ case 80:
+ bw_mask = HOSTAPD_CHAN_WIDTH_80;
+ break;
+ case 160:
+ bw_mask = HOSTAPD_CHAN_WIDTH_160;
+ break;
+ default:
+ bw_mask = 0;
+ break;
+ }
+
+ return (chan->allowed_bw & bw_mask) == bw_mask;
+}
+
+
+/* check if channel is allowed to be used as primary */
+int chan_pri_allowed(const struct hostapd_channel_data *chan)
+{
+ return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 9cddbd5..eb1f1c5 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -39,4 +39,9 @@
int disabled);
int ieee80211ac_cap_check(u32 hw, u32 conf);
+u32 num_chan_to_bw(int num_chans);
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+ int ht40_plus, int pri);
+int chan_pri_allowed(const struct hostapd_channel_data *chan);
+
#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 4fd3357..51e4e0c 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -126,6 +126,10 @@
elems->roaming_cons_sel = pos;
elems->roaming_cons_sel_len = elen;
break;
+ case MULTI_AP_OUI_TYPE:
+ elems->multi_ap = pos;
+ elems->multi_ap_len = elen;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -266,6 +270,10 @@
elems->password_id = pos;
elems->password_id_len = elen;
break;
+ case WLAN_EID_EXT_OCV_OCI:
+ elems->oci = pos;
+ elems->oci_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -291,29 +299,17 @@
struct ieee802_11_elems *elems,
int show_errors)
{
- size_t left = len;
- const u8 *pos = start;
+ const struct element *elem;
int unknown = 0;
os_memset(elems, 0, sizeof(*elems));
- while (left >= 2) {
- u8 id, elen;
+ if (!start)
+ return ParseOK;
- id = *pos++;
- elen = *pos++;
- left -= 2;
-
- if (elen > left) {
- if (show_errors) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
- "parse failed (id=%d elen=%d "
- "left=%lu)",
- id, elen, (unsigned long) left);
- wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
- }
- return ParseFailed;
- }
+ for_each_element(elem, start, len) {
+ u8 id = elem->id, elen = elem->datalen;
+ const u8 *pos = elem->data;
switch (id) {
case WLAN_EID_SSID:
@@ -461,8 +457,7 @@
elems->mic = pos;
elems->mic_len = elen;
/* after mic everything is encrypted, so stop. */
- left = elen;
- break;
+ goto done;
case WLAN_EID_MULTI_BAND:
if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
wpa_printf(MSG_MSGDUMP,
@@ -521,35 +516,33 @@
id, elen);
break;
}
-
- left -= elen;
- pos += elen;
}
- if (left)
+ if (!for_each_element_completed(elem, start, len)) {
+ if (show_errors) {
+ wpa_printf(MSG_DEBUG,
+ "IEEE 802.11 element parse failed @%d",
+ (int) (start + len - (const u8 *) elem));
+ wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
+ }
return ParseFailed;
+ }
+done:
return unknown ? ParseUnknown : ParseOK;
}
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
{
+ const struct element *elem;
int count = 0;
- const u8 *pos, *end;
if (ies == NULL)
return 0;
- pos = ies;
- end = ies + ies_len;
-
- while (end - pos >= 2) {
- if (2 + pos[1] > end - pos)
- break;
+ for_each_element(elem, ies, ies_len)
count++;
- pos += 2 + pos[1];
- }
return count;
}
@@ -559,24 +552,17 @@
u32 oui_type)
{
struct wpabuf *buf;
- const u8 *end, *pos, *ie;
+ const struct element *elem, *found = NULL;
- pos = ies;
- end = ies + ies_len;
- ie = NULL;
-
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- return NULL;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- WPA_GET_BE32(&pos[2]) == oui_type) {
- ie = pos;
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
+ if (elem->datalen >= 4 &&
+ WPA_GET_BE32(elem->data) == oui_type) {
+ found = elem;
break;
}
- pos += 2 + pos[1];
}
- if (ie == NULL)
+ if (!found)
return NULL; /* No specified vendor IE found */
buf = wpabuf_alloc(ies_len);
@@ -587,13 +573,9 @@
* There may be multiple vendor IEs in the message, so need to
* concatenate their data fields.
*/
- while (end - pos > 1) {
- if (2 + pos[1] > end - pos)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- WPA_GET_BE32(&pos[2]) == oui_type)
- wpabuf_put_data(buf, pos + 6, pos[1] - 4);
- pos += 2 + pos[1];
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, ies_len) {
+ if (elem->datalen >= 4 && WPA_GET_BE32(elem->data) == oui_type)
+ wpabuf_put_data(buf, elem->data + 4, elem->datalen - 4);
}
return buf;
@@ -898,6 +880,41 @@
}
+int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
+ int sec_channel, u8 *op_class, u8 *channel)
+{
+ int vht = CHAN_WIDTH_UNKNOWN;
+
+ switch (chanwidth) {
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ case CHAN_WIDTH_40:
+ vht = VHT_CHANWIDTH_USE_HT;
+ break;
+ case CHAN_WIDTH_80:
+ vht = VHT_CHANWIDTH_80MHZ;
+ break;
+ case CHAN_WIDTH_80P80:
+ vht = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ case CHAN_WIDTH_160:
+ vht = VHT_CHANWIDTH_160MHZ;
+ break;
+ }
+
+ if (ieee80211_freq_to_channel_ext(freq, sec_channel, vht, op_class,
+ channel) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "Cannot determine operating class and channel (freq=%u chanwidth=%d sec_channel=%d)",
+ freq, chanwidth, sec_channel);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static const char *const us_op_class_cc[] = {
"US", "CA", NULL
};
@@ -1299,27 +1316,27 @@
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
size_t ies_len)
{
+ const struct element *elem;
+
os_memset(info, 0, sizeof(*info));
- while (ies_buf && ies_len >= 2 &&
- info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
- size_t len = 2 + ies_buf[1];
+ if (!ies_buf)
+ return 0;
- if (len > ies_len) {
- wpa_hexdump(MSG_DEBUG, "Truncated IEs",
- ies_buf, ies_len);
- return -1;
- }
+ for_each_element_id(elem, WLAN_EID_MULTI_BAND, ies_buf, ies_len) {
+ if (info->nof_ies >= MAX_NOF_MB_IES_SUPPORTED)
+ return 0;
- if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
- wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
- info->ies[info->nof_ies].ie = ies_buf + 2;
- info->ies[info->nof_ies].ie_len = ies_buf[1];
- info->nof_ies++;
- }
+ wpa_printf(MSG_DEBUG, "MB IE of %u bytes found",
+ elem->datalen + 2);
+ info->ies[info->nof_ies].ie = elem->data;
+ info->ies[info->nof_ies].ie_len = elem->datalen;
+ info->nof_ies++;
+ }
- ies_len -= len;
- ies_buf += len;
+ if (!for_each_element_completed(elem, ies_buf, ies_len)) {
+ wpa_hexdump(MSG_DEBUG, "Truncated IEs", ies_buf, ies_len);
+ return -1;
}
return 0;
@@ -1442,22 +1459,13 @@
*/
const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
{
- const u8 *end;
+ const struct element *elem;
if (!ies)
return NULL;
- end = ies + len;
-
- while (end - ies > 1) {
- if (2 + ies[1] > end - ies)
- break;
-
- if (ies[0] == eid)
- return ies;
-
- ies += 2 + ies[1];
- }
+ for_each_element_id(elem, eid, ies, len)
+ return &elem->id;
return NULL;
}
@@ -1475,22 +1483,26 @@
*/
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
{
- const u8 *end;
+ const struct element *elem;
if (!ies)
return NULL;
- end = ies + len;
+ for_each_element_extid(elem, ext, ies, len)
+ return &elem->id;
- while (end - ies > 1) {
- if (2 + ies[1] > end - ies)
- break;
+ return NULL;
+}
- if (ies[0] == WLAN_EID_EXTENSION && ies[1] >= 1 &&
- ies[2] == ext)
- return ies;
- ies += 2 + ies[1];
+const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
+{
+ const struct element *elem;
+
+ for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
+ if (elem->datalen >= 4 &&
+ vendor_type == WPA_GET_BE32(elem->data))
+ return &elem->id;
}
return NULL;
@@ -1521,6 +1533,26 @@
}
+size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value)
+{
+ u8 *pos = buf;
+
+ if (len < 9)
+ return 0;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 7; /* len */
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = MULTI_AP_OUI_TYPE;
+ *pos++ = MULTI_AP_SUB_ELEM_TYPE;
+ *pos++ = 1; /* len */
+ *pos++ = value;
+
+ return pos - buf;
+}
+
+
static const struct country_op_class us_op_class[] = {
{ 1, 115 },
{ 2, 118 },
@@ -1666,6 +1698,27 @@
}
+int oper_class_bw_to_int(const struct oper_class_map *map)
+{
+ switch (map->bw) {
+ case BW20:
+ return 20;
+ case BW40PLUS:
+ case BW40MINUS:
+ return 40;
+ case BW80:
+ return 80;
+ case BW80P80:
+ case BW160:
+ return 160;
+ case BW2160:
+ return 2160;
+ default:
+ return 0;
+ }
+}
+
+
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len)
{
@@ -1766,3 +1819,11 @@
return nei_pos - nei_rep;
}
+
+
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
+{
+ if (!ie || ie[1] <= capab / 8)
+ return 0;
+ return !!(ie[2 + capab / 8] & BIT(capab % 8));
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ff7e51d..4e35b79 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,13 @@
#define IEEE802_11_COMMON_H
#include "defs.h"
+#include "ieee802_11_defs.h"
+
+struct element {
+ u8 id;
+ u8 datalen;
+ u8 data[];
+} STRUCT_PACKED;
struct hostapd_hw_modes;
@@ -84,6 +91,8 @@
const u8 *power_capab;
const u8 *roaming_cons_sel;
const u8 *password_id;
+ const u8 *oci;
+ const u8 *multi_ap;
u8 ssid_len;
u8 supp_rates_len;
@@ -130,6 +139,8 @@
u8 power_capab_len;
u8 roaming_cons_sel_len;
u8 password_id_len;
+ u8 oci_len;
+ u8 multi_ap_len;
struct mb_ies_info mb_ies;
};
@@ -160,6 +171,8 @@
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
int sec_channel, int vht,
u8 *op_class, u8 *channel);
+int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
+ int sec_channel, u8 *op_class, u8 *channel);
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
u16 num_modes);
enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
@@ -186,9 +199,12 @@
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
+const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
+size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value);
+
struct country_op_class {
u8 country_op_class;
u8 global_op_class;
@@ -197,8 +213,58 @@
u8 country_to_global_op_class(const char *country, u8 op_class);
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
+int oper_class_bw_to_int(const struct oper_class_map *map);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
+int ieee802_11_ext_capab(const u8 *ie, unsigned int capab);
+
+/* element iteration helpers */
+#define for_each_element(_elem, _data, _datalen) \
+ for (_elem = (const struct element *) (_data); \
+ (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
+ (int) sizeof(*_elem) && \
+ (const u8 *) (_data) + (_datalen) - (const u8 *) _elem >= \
+ (int) sizeof(*_elem) + _elem->datalen; \
+ _elem = (const struct element *) (_elem->data + _elem->datalen))
+
+#define for_each_element_id(element, _id, data, datalen) \
+ for_each_element(element, data, datalen) \
+ if (element->id == (_id))
+
+#define for_each_element_extid(element, extid, _data, _datalen) \
+ for_each_element(element, _data, _datalen) \
+ if (element->id == WLAN_EID_EXTENSION && \
+ element->datalen > 0 && \
+ element->data[0] == (extid))
+
+#define for_each_subelement(sub, element) \
+ for_each_element(sub, (element)->data, (element)->datalen)
+
+#define for_each_subelement_id(sub, id, element) \
+ for_each_element_id(sub, id, (element)->data, (element)->datalen)
+
+#define for_each_subelement_extid(sub, extid, element) \
+ for_each_element_extid(sub, extid, (element)->data, (element)->datalen)
+
+/**
+ * for_each_element_completed - Determine if element parsing consumed all data
+ * @element: Element pointer after for_each_element() or friends
+ * @data: Same data pointer as passed to for_each_element() or friends
+ * @datalen: Same data length as passed to for_each_element() or friends
+ *
+ * This function returns 1 if all the data was parsed or considered
+ * while walking the elements. Only use this if your for_each_element()
+ * loop cannot be broken out of, otherwise it always returns 0.
+ *
+ * If some data was malformed, this returns %false since the last parsed
+ * element will not fill the whole remaining data.
+ */
+static inline int for_each_element_completed(const struct element *element,
+ const void *data, size_t datalen)
+{
+ return (const u8 *) element == (const u8 *) data + datalen;
+}
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 762e731..b285d13 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This software may be distributed under the terms of the BSD license.
@@ -467,7 +467,89 @@
#define WLAN_EID_EXT_PASSWORD_IDENTIFIER 33
#define WLAN_EID_EXT_HE_CAPABILITIES 35
#define WLAN_EID_EXT_HE_OPERATION 36
+#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
+#define WLAN_EID_EXT_OCV_OCI 54
+/* Extended Capabilities field */
+#define WLAN_EXT_CAPAB_20_40_COEX 0
+#define WLAN_EXT_CAPAB_GLK 1
+#define WLAN_EXT_CAPAB_EXT_CHAN_SWITCH 2
+#define WLAN_EXT_CAPAB_GLK_GCR 3
+#define WLAN_EXT_CAPAB_PSMP 4
+/* 5 - Reserved */
+#define WLAN_EXT_CAPAB_S_PSMP 6
+#define WLAN_EXT_CAPAB_EVENT 7
+#define WLAN_EXT_CAPAB_DIAGNOSTICS 8
+#define WLAN_EXT_CAPAB_MULTICAST_DIAGNOSTICS 9
+#define WLAN_EXT_CAPAB_LOCATION_TRACKING 10
+#define WLAN_EXT_CAPAB_FMS 11
+#define WLAN_EXT_CAPAB_PROXY_ARP 12
+#define WLAN_EXT_CAPAB_COLL_INTERF_REP 13
+#define WLAN_EXT_CAPAB_CIVIC_LOCATION 14
+#define WLAN_EXT_CAPAB_GEOSPATIAL_LOCATION 15
+#define WLAN_EXT_CAPAB_TFS 16
+#define WLAN_EXT_CAPAB_WNM_SLEEP_MODE 17
+#define WLAN_EXT_CAPAB_TIM_BROADCAST 18
+#define WLAN_EXT_CAPAB_BSS_TRANSITION 19
+#define WLAN_EXT_CAPAB_QOS_TRAFFIC 20
+#define WLAN_EXT_CAPAB_AC_STA_COUNT 21
+#define WLAN_EXT_CAPAB_MULTIPLE_BSSID 22
+#define WLAN_EXT_CAPAB_TIMING_MEASUREMENT 23
+#define WLAN_EXT_CAPAB_CHANNEL_USAGE 24
+#define WLAN_EXT_CAPAB_SSID_LIST 25
+#define WLAN_EXT_CAPAB_DMS 26
+#define WLAN_EXT_CAPAB_UTF_TSF_OFFSET 27
+#define WLAN_EXT_CAPAB_TPU_BUFFER_STA 28
+#define WLAN_EXT_CAPAB_TDLS_PEER_PSM 29
+#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH 30
+#define WLAN_EXT_CAPAB_INTERWORKING 31
+#define WLAN_EXT_CAPAB_QOS_MAP 32
+#define WLAN_EXT_CAPAB_EBR 33
+#define WLAN_EXT_CAPAB_SSPN_INTERFACE 34
+/* 35 - Reserved */
+#define WLAN_EXT_CAPAB_MSGCF 36
+#define WLAN_EXT_CAPAB_TDLS 37
+#define WLAN_EXT_CAPAB_TDLS_PROHIBITED 38
+#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH_PROHIBITED 39
+#define WLAN_EXT_CAPAB_REJECT_UNADMITTED_FRAME 40
+#define WLAN_EXT_CAPAB_
+/* 41-43 - Service Interval Granularity */
+#define WLAN_EXT_CAPAB_IDENTIFIER_LOCATION 44
+#define WLAN_EXT_CAPAB_U_APSD_COEX 45
+#define WLAN_EXT_CAPAB_WNM_NOTIFCATION 46
+#define WLAN_EXT_CAPAB_QAB 47
+#define WLAN_EXT_CAPAB_UTF_8_SSID 48
+#define WLAN_EXT_CAPAB_QMF 49
+#define WLAN_EXT_CAPAB_QMF_RECONFIG 50
+#define WLAN_EXT_CAPAB_ROBUST_AV_STREAMING 51
+#define WLAN_EXT_CAPAB_ADVANCED_GCR 52
+#define WLAN_EXT_CAPAB_MESH_GCR 53
+#define WLAN_EXT_CAPAB_SCS 54
+#define WLAN_EXT_CAPAB_QLOAD_REPORT 55
+#define WLAN_EXT_CAPAB_ALT_EDCA 56
+#define WLAN_EXT_CAPAB_UNPROT_TXOP_NEG 57
+#define WLAN_EXT_CAPAB_PROT_TXOP_NEG 58
+/* 59 - Reserved */
+#define WLAN_EXT_CAPAB_PROT_QLOAD_REPORT 60
+#define WLAN_EXT_CAPAB_TDLS_WIDER_BW 61
+#define WLAN_EXT_CAPAB_OPMODE_NOTIF 62
+#define WLAN_EXT_CAPAB_
+/* 63-64 - Max Number of MSDUs In A-MSDU */
+#define WLAN_EXT_CAPAB_CHANNEL_SCHEDULE_MGMT 65
+#define WLAN_EXT_CAPAB_GEODB_INBAND_ENABLING_SIGNAL 66
+#define WLAN_EXT_CAPAB_NETWORK_CHANNEL_CTRL 67
+#define WLAN_EXT_CAPAB_WHITE_SPACE_MAP 68
+#define WLAN_EXT_CAPAB_CHANNEL_AVAIL_QUERY 69
+#define WLAN_EXT_CAPAB_FTM_RESPONDER 70
+#define WLAN_EXT_CAPAB_FTM_INITIATOR 71
+#define WLAN_EXT_CAPAB_FILS 72
+#define WLAN_EXT_CAPAB_EXT_SPECTRUM_MGMT 73
+#define WLAN_EXT_CAPAB_FUTURE_CHANNEL_GUIDANCE 74
+#define WLAN_EXT_CAPAB_PAD 75
+/* 76-79 - Reserved */
+#define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80
+#define WLAN_EXT_CAPAB_SAE_PW_ID 81
+#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@@ -865,10 +947,12 @@
struct {
u8 action;
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+ u8 variable[]; /* OCI element */
} STRUCT_PACKED sa_query_req;
struct {
u8 action; /* */
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+ u8 variable[]; /* OCI element */
} STRUCT_PACKED sa_query_resp;
struct {
u8 action;
@@ -1210,6 +1294,13 @@
#define MBO_OUI_TYPE 22
#define OWE_IE_VENDOR_TYPE 0x506f9a1c
#define OWE_OUI_TYPE 28
+#define MULTI_AP_OUI_TYPE 0x1B
+
+#define MULTI_AP_SUB_ELEM_TYPE 0x06
+#define MULTI_AP_TEAR_DOWN BIT(4)
+#define MULTI_AP_FRONTHAUL_BSS BIT(5)
+#define MULTI_AP_BACKHAUL_BSS BIT(6)
+#define MULTI_AP_BACKHAUL_STA BIT(7)
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
@@ -1347,13 +1438,15 @@
#define HS20_PPS_MO_ID_PRESENT 0x02
#define HS20_ANQP_DOMAIN_ID_PRESENT 0x04
#ifndef HS20_VERSION
-#define HS20_VERSION 0x10 /* Release 2 */
+#define HS20_VERSION 0x20 /* Release 3 */
#endif /* HS20_VERSION */
/* WNM-Notification WFA vendors specific subtypes */
#define HS20_WNM_SUB_REM_NEEDED 0
#define HS20_WNM_DEAUTH_IMMINENT_NOTICE 1
-#define HS20_WNM_T_C_ACCEPTANCE 2
+#define WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT 2
+#define WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA 3
+#define HS20_WNM_T_C_ACCEPTANCE 4
#define HS20_DEAUTH_REASON_CODE_BSS 0
#define HS20_DEAUTH_REASON_CODE_ESS 1
@@ -1442,12 +1535,6 @@
MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
};
-/* MBO v0.0_r19, 4.4: WNM-Notification vendor subelements */
-enum wfa_wnm_notif_subelem_id {
- WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT = 2,
- WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3,
-};
-
/* MBO v0.0_r27, 4.3: MBO ANQP-elements */
#define MBO_ANQP_OUI_TYPE 0x12
#define MBO_ANQP_SUBTYPE_QUERY_LIST 1
@@ -1841,11 +1928,14 @@
};
/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-106 - Optional subelement IDs for
+ * Beacon request */
#define WLAN_BEACON_REQUEST_SUBELEM_SSID 0
#define WLAN_BEACON_REQUEST_SUBELEM_INFO 1 /* Beacon Reporting */
#define WLAN_BEACON_REQUEST_SUBELEM_DETAIL 2 /* Reporting Detail */
#define WLAN_BEACON_REQUEST_SUBELEM_REQUEST 10
#define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL 51 /* AP Channel Report */
+#define WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION 164
#define WLAN_BEACON_REQUEST_SUBELEM_VENDOR 221
/*
@@ -1895,9 +1985,21 @@
} STRUCT_PACKED;
/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
+/* IEEE P802.11-REVmd/D2.0, Table 9-130 - Optional subelement IDs for
+ * Beacon report */
#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY 1
+#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID 2
+#define WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION 164
#define WLAN_BEACON_REPORT_SUBELEM_VENDOR 221
+/* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the
+ * Reported Frame Body Fragment ID subelement */
+#define REPORTED_FRAME_BODY_SUBELEM_LEN 4
+#define REPORTED_FRAME_BODY_MORE_FRAGMENTS BIT(7)
+
+/* IEEE P802.11-REVmd/D2.0, 9.4.2.21.7 - Beacon report */
+#define BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN 3
+
/* IEEE Std 802.11ad-2012 - Multi-band element */
struct multi_band_ie {
u8 eid; /* WLAN_EID_MULTI_BAND */
@@ -2000,14 +2102,15 @@
};
struct ieee80211_he_capabilities {
- u8 he_mac_capab_info[5];
- u8 he_phy_capab_info[9];
+ u8 he_mac_capab_info[6];
+ u8 he_phy_capab_info[11];
u8 he_txrx_mcs_support[12]; /* TODO: 4, 8, or 12 octets */
/* PPE Thresholds (optional) */
} STRUCT_PACKED;
struct ieee80211_he_operation {
- u32 he_oper_params;
+ u32 he_oper_params; /* HE Operation Parameters[3] and
+ * BSS Color Information[1] */
u8 he_mcs_nss_set[2];
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg0_idx;
@@ -2024,28 +2127,55 @@
#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
/* HE Operation defines */
+/* HE Operation Parameters and BSS Color Information fields */
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(0) | BIT(1) | \
BIT(2) | BIT(3) | \
BIT(4) | BIT(5)))
-#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(6) | BIT(7) | \
- BIT(8)))
-#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 6
-#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(9))
-#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(10) | BIT(11) | \
- BIT(12) | BIT(13) | \
+#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(6))
+#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(7))
+#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(8) | BIT(9) | \
+ BIT(10)))
+#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 8
+#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(11))
+#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(12) | BIT(13) | \
BIT(14) | BIT(15) | \
BIT(16) | BIT(17) | \
- BIT(18) | BIT(19)))
-#define HE_OPERATION_RTS_THRESHOLD_OFFSET 10
-#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(20))
-#define HE_OPERATION_MAX_BSSID_INDICATOR_MASK ((u32) (BIT(21) | BIT(22) | \
- BIT(23) | BIT(24) | \
- BIT(25) | BIT(26) | \
- BIT(27) | BIT(28)))
-#define HE_OPERATION_MAX_BSSID_INDICATOR_OFFSET 21
-#define HE_OPERATION_TX_BSSID_INDICATOR ((u32) BIT(29))
-#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(30))
-#define HE_OPERATION_BSS_DUAL_BEACON ((u32) BIT(31))
+ BIT(18) | BIT(19) | \
+ BIT(20) | BIT(21)))
+#define HE_OPERATION_RTS_THRESHOLD_OFFSET 12
+
+struct ieee80211_he_mu_edca_parameter_set {
+ u8 he_qos_info;
+ u8 he_mu_ac_be_param[3];
+ u8 he_mu_ac_bk_param[3];
+ u8 he_mu_ac_vi_param[3];
+ u8 he_mu_ac_vo_param[3];
+} STRUCT_PACKED;
+
+/* HE MU AC parameter record field format */
+/* ACI/AIFSN */
+#define HE_MU_AC_PARAM_ACI_IDX 0
+#define HE_MU_AC_PARAM_AIFSN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
+#define HE_MU_AC_PARAM_ACM ((u8) BIT(4))
+#define HE_MU_AC_PARAM_ACI ((u8) (BIT(5) | BIT(6)))
+/* B7: Reserved */
+
+/* ECWmin/ECWmax */
+#define HE_MU_AC_PARAM_ECW_IDX 1
+#define HE_MU_AC_PARAM_ECWMIN ((u8) (BIT(0) | BIT(1) | BIT(2) | BIT(3)))
+#define HE_MU_AC_PARAM_ECWMAX ((u8) (BIT(4) | BIT(5) | BIT(6) | BIT(7)))
+
+/* MU EDCA Timer */
+#define HE_MU_AC_PARAM_TIMER_IDX 2
+
+/* HE QoS Info field */
+#define HE_QOS_INFO_EDCA_PARAM_SET_COUNT ((u8) (BIT(0) | BIT(1) | \
+ BIT(2) | BIT(3)))
+#define HE_QOS_INFO_Q_ACK ((u8) (BIT(4)))
+#define HE_QOS_INFO_QUEUE_REQUEST ((u8) (BIT(5)))
+#define HE_QOS_INFO_TXOP_REQUEST ((u8) (BIT(6)))
+/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
+#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
diff --git a/src/common/linux_bridge.h b/src/common/linux_bridge.h
index 7b76846..84386e6 100644
--- a/src/common/linux_bridge.h
+++ b/src/common/linux_bridge.h
@@ -9,6 +9,21 @@
#ifndef LINUX_BRIDGE_H
#define LINUX_BRIDGE_H
+/* This ioctl is defined in linux/sockios.h */
+
+#ifndef SIOCBRADDBR
+#define SIOCBRADDBR 0x89a0
+#endif
+#ifndef SIOCBRDELBR
+#define SIOCBRDELBR 0x89a1
+#endif
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF 0x89a2
+#endif
+#ifndef SIOCBRDELIF
+#define SIOCBRDELIF 0x89a3
+#endif
+
/* This interface is defined in linux/if_bridge.h */
#define BRCTL_GET_VERSION 0
diff --git a/src/common/ocv.c b/src/common/ocv.c
new file mode 100644
index 0000000..06badfb
--- /dev/null
+++ b/src/common/ocv.c
@@ -0,0 +1,172 @@
+/*
+ * Operating Channel Validation (OCV)
+ * Copyright (c) 2018, Mathy Vanhoef
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_common.h"
+#include "ocv.h"
+
+/**
+ * Caller of OCV functionality may use various debug output functions, so store
+ * the error here and let the caller use an appropriate debug output function.
+ */
+char ocv_errorstr[256];
+
+
+int ocv_derive_all_parameters(struct oci_info *oci)
+{
+ const struct oper_class_map *op_class_map;
+
+ oci->freq = ieee80211_chan_to_freq(NULL, oci->op_class, oci->channel);
+ if (oci->freq < 0) {
+ wpa_printf(MSG_INFO,
+ "Error interpreting OCI: unrecognized opclass/channel pair (%d/%d)",
+ oci->op_class, oci->channel);
+ return -1;
+ }
+
+ op_class_map = get_oper_class(NULL, oci->op_class);
+ if (!op_class_map) {
+ wpa_printf(MSG_INFO,
+ "Error interpreting OCI: Unrecognized opclass (%d)",
+ oci->op_class);
+ return -1;
+ }
+
+ oci->chanwidth = oper_class_bw_to_int(op_class_map);
+ oci->sec_channel = 0;
+ if (op_class_map->bw == BW40PLUS)
+ oci->sec_channel = 1;
+ else if (op_class_map->bw == BW40MINUS)
+ oci->sec_channel = -1;
+
+ return 0;
+}
+
+
+int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos)
+{
+ u8 op_class, channel;
+ u8 *pos = *argpos;
+
+ if (ieee80211_chaninfo_to_channel(ci->frequency, ci->chanwidth,
+ ci->sec_channel,
+ &op_class, &channel) < 0) {
+ wpa_printf(MSG_WARNING,
+ "Cannot determine operating class and channel for OCI element");
+ return -1;
+ }
+
+ *pos++ = op_class;
+ *pos++ = channel;
+ *pos++ = ci->seg1_idx;
+
+ *argpos = pos;
+ return 0;
+}
+
+
+int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos)
+{
+ u8 *pos = *argpos;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 3;
+ RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_OCI);
+ pos += RSN_SELECTOR_LEN;
+
+ *argpos = pos;
+ return ocv_insert_oci(ci, argpos);
+}
+
+
+int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos)
+{
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 1 + OCV_OCI_LEN;
+ *pos++ = WLAN_EID_EXT_OCV_OCI;
+ return ocv_insert_oci(ci, &pos);
+}
+
+
+int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx)
+{
+ struct oci_info oci;
+
+ if (!oci_ie) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: did not receive mandatory OCI");
+ return -1;
+ }
+
+ if (oci_ie_len != 3) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: received OCI of unexpected length (%d)",
+ (int) oci_ie_len);
+ return -1;
+ }
+
+ os_memset(&oci, 0, sizeof(oci));
+ oci.op_class = oci_ie[0];
+ oci.channel = oci_ie[1];
+ oci.seg1_idx = oci_ie[2];
+ if (ocv_derive_all_parameters(&oci) != 0) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: unable to interpret received OCI");
+ return -1;
+ }
+
+ /* Primary frequency used to send frames to STA must match the STA's */
+ if ((int) ci->frequency != oci.freq) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: primary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ ci->frequency, oci.freq);
+ return -1;
+ }
+
+ /* We shouldn't transmit with a higher bandwidth than the STA supports
+ */
+ if (tx_chanwidth > oci.chanwidth) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: channel bandwidth mismatch in received OCI (we use %d but receiver only supports %d)",
+ tx_chanwidth, oci.chanwidth);
+ return -1;
+ }
+
+ /*
+ * Secondary channel only needs be checked for 40 MHz in the 2.4 GHz
+ * band. In the 5 GHz band it's verified through the primary frequency.
+ * Note that the field ci->sec_channel is only filled in when we use
+ * 40 MHz.
+ */
+ if (tx_chanwidth == 40 && ci->frequency < 2500 &&
+ ci->sec_channel != oci.sec_channel) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: secondary channel mismatch in received OCI (we use %d but receiver is using %d)",
+ ci->sec_channel, oci.sec_channel);
+ return -1;
+ }
+
+ /*
+ * When using a 160 or 80+80 MHz channel to transmit, verify that we use
+ * the same segments as the receiver by comparing frequency segment 1.
+ */
+ if ((ci->chanwidth == CHAN_WIDTH_160 ||
+ ci->chanwidth == CHAN_WIDTH_80P80) &&
+ tx_seg1_idx != oci.seg1_idx) {
+ os_snprintf(ocv_errorstr, sizeof(ocv_errorstr),
+ "OCV failed: frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)",
+ tx_seg1_idx, oci.seg1_idx);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/common/ocv.h b/src/common/ocv.h
new file mode 100644
index 0000000..6379d9d
--- /dev/null
+++ b/src/common/ocv.h
@@ -0,0 +1,40 @@
+/*
+ * Operating Channel Validation (OCV)
+ * Copyright (c) 2018, Mathy Vanhoef
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OCV_H
+#define OCV_H
+
+struct wpa_channel_info;
+
+struct oci_info {
+ /* Values in the OCI element */
+ u8 op_class;
+ u8 channel;
+ u8 seg1_idx;
+
+ /* Derived values for easier verification */
+ int freq;
+ int sec_channel;
+ int chanwidth;
+};
+
+#define OCV_OCI_LEN 3
+#define OCV_OCI_EXTENDED_LEN (3 + OCV_OCI_LEN)
+#define OCV_OCI_KDE_LEN (2 + RSN_SELECTOR_LEN + OCV_OCI_LEN)
+
+extern char ocv_errorstr[256];
+
+int ocv_derive_all_parameters(struct oci_info *oci);
+int ocv_insert_oci(struct wpa_channel_info *ci, u8 **argpos);
+int ocv_insert_oci_kde(struct wpa_channel_info *ci, u8 **argpos);
+int ocv_insert_extended_oci(struct wpa_channel_info *ci, u8 *pos);
+int ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len,
+ struct wpa_channel_info *ci, int tx_chanwidth,
+ int tx_seg1_idx);
+
+#endif /* OCV_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 7a4da46..6f5b87e 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -42,8 +42,12 @@
*
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency
* ranges to avoid to reduce issues due to interference or internal
- * co-existence information in the driver. The event data structure is
- * defined in struct qca_avoid_freq_list.
+ * co-existence information in the driver. These frequencies aim to
+ * minimize the traffic but not to totally avoid the traffic. That said
+ * for a P2P use case, these frequencies are allowed for the P2P
+ * discovery/negotiation but avoid the group to get formed on these
+ * frequencies. The event data structure is defined in
+ * struct qca_avoid_freq_list.
*
* @QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: Command to check driver support
* for DFS offloading.
@@ -158,6 +162,11 @@
* timer value. Uses the attributes defines in
* enum qca_wlan_vendor_attr_ocb_get_tsf_resp.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES: Command/event to update the
+ * link properties of the respective interface. As an event, is used
+ * to notify the connected station's status. The attributes for this
+ * command are defined in enum qca_wlan_vendor_attr_link_properties.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to
* start the P2P Listen offload function in device and pass the listen
* channel, period, interval, count, device types, and vendor specific
@@ -474,6 +483,30 @@
* configure parameters per peer to capture Channel Frequency Response
* (CFR) and enable Periodic CFR capture. The attributes for this command
* are defined in enum qca_wlan_vendor_peer_cfr_capture_attr.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT: Event to indicate changes
+ * in throughput dynamically. The driver estimates the throughput based on
+ * number of packets being transmitted/received per second and indicates
+ * the changes in throughput to user space. Userspace tools can use this
+ * information to configure kernel's TCP parameters in order to achieve
+ * peak throughput. Optionally, the driver will also send guidance on
+ * modifications to kernel's TCP parameters which can be referred by
+ * userspace tools. The attributes used with this event are defined in enum
+ * qca_wlan_vendor_attr_throughput_change.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG: This command is used to set
+ * priorities among different types of traffic during coex scenarios.
+ * Current supported prioritization is among WLAN/BT/ZIGBEE with different
+ * profiles mentioned in enum qca_coex_config_profiles. The associated
+ * attributes used with this command are defined in enum
+ * qca_vendor_attr_coex_config.
+ *
+ * Based on the config provided, FW will boost the weight and prioritize
+ * the traffic for that subsystem (WLAN/BT/Zigbee).
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS: This command is used to query
+ * the supported AKM suite selectorss from the driver. It returns the list
+ * of supported AKMs in the attribute NL80211_ATTR_AKM_SUITES.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -636,6 +669,9 @@
QCA_NL80211_VENDOR_SUBCMD_NAN_EXT = 171,
QCA_NL80211_VENDOR_SUBCMD_ROAM_SCAN_EVENT = 172,
QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG = 173,
+ QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT = 174,
+ QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG = 175,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS = 176,
};
enum qca_wlan_vendor_attr {
@@ -816,6 +852,12 @@
* to report the corresponding antenna index to the chain RSSI value
*/
QCA_WLAN_VENDOR_ATTR_ANTENNA_INFO = 40,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command to report
+ * the specific antenna EVM value (unsigned 32 bit value). With a
+ * determinate group of antennas, the driver specifies the EVM value
+ * for each antenna ID, and application extract them in user space.
+ */
+ QCA_WLAN_VENDOR_ATTR_CHAIN_EVM = 41,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
@@ -4406,6 +4448,27 @@
* qca_wlan_vendor_spectral_scan_cap_hw_gen.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN = 5,
+ /* Spectral bin scaling formula ID. u16 attribute.
+ * It uses values defined in enum
+ * qca_wlan_vendor_spectral_scan_cap_formula_id.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID = 6,
+ /* Spectral bin scaling param - low level offset.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_LOW_LEVEL_OFFSET = 7,
+ /* Spectral bin scaling param - high level offset.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HIGH_LEVEL_OFFSET = 8,
+ /* Spectral bin scaling param - RSSI threshold.
+ * s16 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RSSI_THR = 9,
+ /* Spectral bin scaling param - default AGC max gain.
+ * u8 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@@ -4551,6 +4614,20 @@
};
/**
+ * qca_wlan_vendor_spectral_scan_cap_formula_id: Attribute values for
+ * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID in the vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO. This represents the
+ * Spectral bin scaling formula ID.
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING: No scaling
+ * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED: AGC gain
+ * and RSSI threshold based formula.
+ */
+enum qca_wlan_vendor_spectral_scan_cap_formula_id {
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_NO_SCALING = 0,
+ QCA_WLAN_VENDOR_SPECTRAL_SCAN_CAP_AGC_GAIN_RSSI_CORR_BASED = 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_rropavail_info - Specifies whether Representative
* RF Operating Parameter (RROP) information is available, and if so, at which
* point in the application-driver interaction sequence it can be retrieved by
@@ -5413,6 +5490,60 @@
QCA_WLAN_HE_16US_OF_PROCESS_TIME = 2,
};
+/**
+ * enum qca_wlan_he_om_ctrl_ch_bw - HE OM control field BW configuration
+ *
+ * Indicates the HE Operating mode control channel width setting value.
+ *
+ * @QCA_WLAN_HE_OM_CTRL_BW_20M: Primary 20 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_40M: Primary 40 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_80M: Primary 80 MHz
+ * @QCA_WLAN_HE_OM_CTRL_BW_160M: 160 MHz and 80+80 MHz
+ */
+enum qca_wlan_he_om_ctrl_ch_bw {
+ QCA_WLAN_HE_OM_CTRL_BW_20M = 0,
+ QCA_WLAN_HE_OM_CTRL_BW_40M = 1,
+ QCA_WLAN_HE_OM_CTRL_BW_80M = 2,
+ QCA_WLAN_HE_OM_CTRL_BW_160M = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for
+ * HE operating mode control transmit request. These attributes are
+ * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: Mandatory 8-bit unsigned value
+ * indicates the maximum number of spatial streams, NSS, that the STA
+ * supports in reception for PPDU bandwidths less than or equal to 80 MHz
+ * and is set to NSS - 1.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW: Mandatory 8-bit unsigned value
+ * indicates the operating channel width supported by the STA for both
+ * reception and transmission. Uses enum qca_wlan_he_om_ctrl_ch_bw values.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE: Mandatory 8-bit unsigned value
+ * indicates the all trigger based UL MU operations by the STA.
+ * 0 - UL MU operations are enabled by the STA.
+ * 1 - All triggered UL MU transmissions are suspended by the STA.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS: Mandatory 8-bit unsigned value
+ * indicates the maximum number of space-time streams, NSTS, that
+ * the STA supports in transmission and is set to NSTS - 1.
+ */
+enum qca_wlan_vendor_attr_he_omi_tx {
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS = 1,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW = 2,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE = 3,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX =
+ QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1,
+};
+
/* Attributes for data used by
* QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION
*/
@@ -5604,6 +5735,79 @@
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_RESUME = 26,
+ /* 8-bit unsigned value to set the HE operating mode control
+ * (OM CTRL) Channel Width subfield.
+ * The Channel Width subfield indicates the operating channel width
+ * supported by the STA for both reception and transmission.
+ * Uses the enum qca_wlan_he_om_ctrl_ch_bw values.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_BW = 27,
+
+ /* 8-bit unsigned value to configure the number of spatial
+ * streams in HE operating mode control field.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_NSS = 28,
+
+ /* Flag attribute to configure the UL MU disable bit in
+ * HE operating mode control field.
+ * This setting is cleared with the
+ * QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG
+ * flag attribute to reset defaults.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_UL_MU_DISABLE = 29,
+
+ /* Flag attribute to clear the previously set HE operating mode
+ * control field configuration.
+ * This attribute is used to configure the testbed device to reset
+ * defaults to clear any previously set HE operating mode control
+ * field configuration.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG = 30,
+
+ /* 8-bit unsigned value to configure HE single user PPDU
+ * transmission. By default this setting is disabled and it
+ * is disabled in the reset defaults of the device configuration.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_SUPPDU = 31,
+
+ /* 8-bit unsigned value to configure action frame transmission
+ * in HE trigger based PPDU transmission.
+ * By default this setting is disabled and it is disabled in
+ * the reset defaults of the device configuration.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_ACTION_TX_TB_PPDU = 32,
+
+ /* Nested attribute to indicate HE operating mode control field
+ * transmission. It contains operating mode control field Nss,
+ * channel bandwidth, Tx Nsts and UL MU disable attributes.
+ * These nested attributes are used to send HE operating mode control
+ * with configured values.
+ * Uses the enum qca_wlan_vendor_attr_he_omi_tx attributes.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX = 33,
+
+ /* 8-bit unsigned value to configure +HTC_HE support to indicate the
+ * support for the reception of a frame that carries an HE variant
+ * HT Control field.
+ * This attribute is used to configure the testbed device.
+ * 1-enable, 0-disable
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_HTC_HE_SUPP = 34,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -5990,4 +6194,159 @@
QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_throughput_level - Current throughput level
+ *
+ * Indicates the current level of throughput calculated by the driver. The
+ * driver may choose different thresholds to decide whether the throughput level
+ * is low or medium or high based on variety of parameters like physical link
+ * capacity of the current connection, the number of packets being dispatched
+ * per second, etc. The throughput level events might not be consistent with the
+ * actual current throughput value being observed.
+ *
+ * @QCA_WLAN_THROUGHPUT_LEVEL_LOW: Low level of throughput
+ * @QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM: Medium level of throughput
+ * @QCA_WLAN_THROUGHPUT_LEVEL_HIGH: High level of throughput
+ */
+enum qca_wlan_throughput_level {
+ QCA_WLAN_THROUGHPUT_LEVEL_LOW = 0,
+ QCA_WLAN_THROUGHPUT_LEVEL_MEDIUM = 1,
+ QCA_WLAN_THROUGHPUT_LEVEL_HIGH = 2,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_throughput_change - Vendor subcmd attributes to
+ * report throughput changes from the driver to user space. enum values are used
+ * for netlink attributes sent with
+ * %QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT sub command.
+ */
+enum qca_wlan_vendor_attr_throughput_change {
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_INVALID = 0,
+ /* Indicates the direction of throughput in which the change is being
+ * reported. u8 attribute. Value is 0 for TX and 1 for RX.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_DIRECTION = 1,
+ /* Indicates the newly observed throughput level. enum
+ * qca_wlan_throughput_level describes the possible range of values.
+ * u8 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_THROUGHPUT_LEVEL = 2,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_limit_output_bytes. u32 attribute. The
+ * driver may optionally include this attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_LIMIT_OUTPUT_BYTES = 3,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_adv_win_scale. s8 attribute. Possible
+ * values are from -31 to 31. The driver may optionally include this
+ * attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_ADV_WIN_SCALE = 4,
+ /* Indicates the driver's guidance on the new value to be set to
+ * kernel's TCP parameter tcp_delack_seg. u32 attribute. The driver may
+ * optionally include this attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_DELACK_SEG = 5,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_MAX =
+ QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_coex_config_profiles - This enum defines different types of
+ * traffic streams that can be prioritized one over the other during coex
+ * scenarios.
+ * The types defined in this enum are categorized in the below manner.
+ * 0 - 31 values corresponds to WLAN
+ * 32 - 63 values corresponds to BT
+ * 64 - 95 values corresponds to Zigbee
+ * @QCA_WIFI_STA_DISCOVERY: Prioritize discovery frames for WLAN STA
+ * @QCA_WIFI_STA_CONNECTION: Prioritize connection frames for WLAN STA
+ * @QCA_WIFI_STA_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN STA
+ * @QCA_WIFI_STA_DATA : Prioritize data frames for WLAN STA
+ * @QCA_WIFI_STA_ALL: Priritize all frames for WLAN STA
+ * @QCA_WIFI_SAP_DISCOVERY: Prioritize discovery frames for WLAN SAP
+ * @QCA_WIFI_SAP_CONNECTION: Prioritize connection frames for WLAN SAP
+ * @QCA_WIFI_SAP_CLASS_3_MGMT: Prioritize class 3 mgmt frames for WLAN SAP
+ * @QCA_WIFI_SAP_DATA: Prioritize data frames for WLAN SAP
+ * @QCA_WIFI_SAP_ALL: Prioritize all frames for WLAN SAP
+ * @QCA_BT_A2DP: Prioritize BT A2DP
+ * @QCA_BT_BLE: Prioritize BT BLE
+ * @QCA_BT_SCO: Prioritize BT SCO
+ * @QCA_ZB_LOW: Prioritize Zigbee Low
+ * @QCA_ZB_HIGH: Prioritize Zigbee High
+ */
+enum qca_coex_config_profiles {
+ /* 0 - 31 corresponds to WLAN */
+ QCA_WIFI_STA_DISCOVERY = 0,
+ QCA_WIFI_STA_CONNECTION = 1,
+ QCA_WIFI_STA_CLASS_3_MGMT = 2,
+ QCA_WIFI_STA_DATA = 3,
+ QCA_WIFI_STA_ALL = 4,
+ QCA_WIFI_SAP_DISCOVERY = 5,
+ QCA_WIFI_SAP_CONNECTION = 6,
+ QCA_WIFI_SAP_CLASS_3_MGMT = 7,
+ QCA_WIFI_SAP_DATA = 8,
+ QCA_WIFI_SAP_ALL = 9,
+ /* 32 - 63 corresponds to BT */
+ QCA_BT_A2DP = 32,
+ QCA_BT_BLE = 33,
+ QCA_BT_SCO = 34,
+ /* 64 - 95 corresponds to Zigbee */
+ QCA_ZB_LOW = 64,
+ QCA_ZB_HIGH = 65
+};
+
+/**
+ * enum qca_vendor_attr_coex_config - Specifies vendor coex config attributes
+ *
+ * @QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES: This attribute contains variable
+ * length array of 8-bit values from enum qca_coex_config_profiles.
+ * FW will prioritize the profiles in the order given in the array encapsulated
+ * in this attribute.
+ * For example:
+ * -----------------------------------------------------------------------
+ * | 1 | 34 | 32 | 65 |
+ * -----------------------------------------------------------------------
+ * If the attribute contains the values defined in above array then it means
+ * 1) Wifi STA connection has priority over BT_SCO, BT_A2DP and ZIGBEE HIGH.
+ * 2) BT_SCO has priority over BT_A2DP.
+ * 3) BT_A2DP has priority over ZIGBEE HIGH.
+ * Profiles which are not listed in this array shall not be preferred over the
+ * profiles which are listed in the array as a part of this attribute.
+ */
+enum qca_vendor_attr_coex_config {
+ QCA_VENDOR_ATTR_COEX_CONFIG_INVALID = 0,
+ QCA_VENDOR_ATTR_COEX_CONFIG_PROFILES = 1,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST,
+ QCA_VENDOR_ATTR_COEX_CONFIG_MAX =
+ QCA_VENDOR_ATTR_COEX_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_link_properties - Represent the link properties.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR: MAC address of the peer
+ * (STA/AP) for the connected link.
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS: Attribute containing a
+ * &struct nl80211_sta_flag_update for the respective connected link. MAC
+ * address of the peer represented by
+ * QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR.
+ */
+enum qca_wlan_vendor_attr_link_properties {
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID = 0,
+ /* 1 - 3 are reserved */
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR = 4,
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS = 5,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST,
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_MAX =
+ QCA_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/version.h b/src/common/version.h
index 16c1004..eb4f313 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -9,6 +9,6 @@
#define GIT_VERSION_STR_POSTFIX ""
#endif /* GIT_VERSION_STR_POSTFIX */
-#define VERSION_STR "2.7-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.8-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 14c5769..b47f632 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -880,6 +880,12 @@
parse->igtk_len = len;
break;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ case FTIE_SUBELEM_OCI:
+ parse->oci = pos;
+ parse->oci_len = len;
+ break;
+#endif /* CONFIG_OCV */
default:
wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id);
break;
@@ -1202,6 +1208,8 @@
pos = rsn_ie + 6;
left = rsn_ie_len - 6;
+ data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
+ data->key_mgmt = WPA_KEY_MGMT_OSEN;
data->proto = WPA_PROTO_OSEN;
} else {
const struct rsn_ie_hdr *hdr;
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 6261744..37b5834 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -110,6 +110,7 @@
#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4)
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
@@ -148,7 +149,8 @@
#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
#define WPA_CAPABILITY_PBAC BIT(12)
#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
-/* B14-B15: Reserved */
+#define WPA_CAPABILITY_OCVC BIT(14)
+/* B15: Reserved */
/* IEEE 802.11r */
@@ -326,6 +328,7 @@
#define FTIE_SUBELEM_GTK 2
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
+#define FTIE_SUBELEM_OCI 5
struct rsn_rdie {
u8 id;
@@ -451,6 +454,10 @@
size_t tie_len;
const u8 *igtk;
size_t igtk_len;
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
const u8 *ric;
size_t ric_len;
int key_mgmt;
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index a0fe822..8722b19 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -11,6 +11,8 @@
#ifdef CONFIG_CTRL_IFACE
#ifdef CONFIG_CTRL_IFACE_UNIX
+#include <sys/stat.h>
+#include <fcntl.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
@@ -141,6 +143,19 @@
return NULL;
}
tries++;
+#ifdef ANDROID
+ /* Set client socket file permissions so that bind() creates the client
+ * socket with these permissions and there is no need to try to change
+ * them with chmod() after bind() which would have potential issues with
+ * race conditions. These permissions are needed to make sure the server
+ * side (wpa_supplicant or hostapd) can reply to the control interface
+ * messages.
+ *
+ * The lchown() calls below after bind() are also part of the needed
+ * operations to allow the response to go through. Those are using the
+ * no-deference-symlinks version to avoid races. */
+ fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+#endif /* ANDROID */
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
@@ -159,7 +174,6 @@
}
#ifdef ANDROID
- chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
/* Set group even if we do not have privileges to change owner */
grp_wifi = getgrnam("wifi");
gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0;
@@ -171,8 +185,8 @@
os_free(ctrl);
return NULL;
}
- chown(ctrl->local.sun_path, -1, gid_wifi);
- chown(ctrl->local.sun_path, uid_system, gid_wifi);
+ lchown(ctrl->local.sun_path, -1, gid_wifi);
+ lchown(ctrl->local.sun_path, uid_system, gid_wifi);
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
if (socket_local_client_connect(
@@ -558,7 +572,8 @@
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
- if (res > 0 && reply[0] == '<') {
+ if ((res > 0 && reply[0] == '<') ||
+ (res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index ee93e41..ab108da 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -62,7 +62,9 @@
LIB_OBJS += crypto_internal-rsa.o
LIB_OBJS += tls_internal.o
LIB_OBJS += fips_prf_internal.o
+ifndef TEST_FUZZ
LIB_OBJS += random.o
+endif
libcrypto.a: $(LIB_OBJS)
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index f4cff43..f89053a 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -29,6 +29,7 @@
#include "sha1.h"
#include "sha256.h"
#include "sha384.h"
+#include "sha512.h"
#include "md5.h"
#include "aes_wrap.h"
#include "crypto.h"
diff --git a/src/crypto/md4-internal.c b/src/crypto/md4-internal.c
index d9c737a..cf408e8 100644
--- a/src/crypto/md4-internal.c
+++ b/src/crypto/md4-internal.c
@@ -85,7 +85,7 @@
(cp)[1] = (value) >> 8; \
(cp)[0] = (value); } while (0)
-static u8 PADDING[MD4_BLOCK_LENGTH] = {
+static const u8 PADDING[MD4_BLOCK_LENGTH] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 6f4cf81..ca9c0c8 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -25,6 +25,9 @@
#include "utils/includes.h"
#ifdef __linux__
#include <fcntl.h>
+#ifdef CONFIG_GETRANDOM
+#include <sys/random.h>
+#endif /* CONFIG_GETRANDOM */
#endif /* __linux__ */
#include "utils/common.h"
@@ -235,30 +238,52 @@
return 1; /* Already initialized - good to continue */
/*
- * Try to fetch some more data from the kernel high quality
- * /dev/random. There may not be enough data available at this point,
+ * Try to fetch some more data from the kernel high quality RNG.
+ * There may not be enough data available at this point,
* so use non-blocking read to avoid blocking the application
* completely.
*/
- fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(errno));
- return -1;
+
+#ifdef CONFIG_GETRANDOM
+ res = getrandom(dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
+ if (res < 0) {
+ if (errno == ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() not supported, falling back to /dev/random");
+ } else {
+ wpa_printf(MSG_INFO,
+ "random: no data from getrandom(): %s",
+ strerror(errno));
+ res = 0;
+ }
+ }
+#else /* CONFIG_GETRANDOM */
+ res = -1;
+#endif /* CONFIG_GETRANDOM */
+ if (res < 0) {
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot open /dev/random: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = read(fd, dummy_key + dummy_key_avail,
+ sizeof(dummy_key) - dummy_key_avail);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR,
+ "random: Cannot read from /dev/random: %s",
+ strerror(errno));
+ res = 0;
+ }
+ close(fd);
}
- res = read(fd, dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail);
- if (res < 0) {
- wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
- "%s", strerror(errno));
- res = 0;
- }
- wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
- "/dev/random", (unsigned) res,
+ wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
dummy_key_avail += res;
- close(fd);
if (dummy_key_avail == sizeof(dummy_key)) {
if (own_pool_ready < MIN_READY_MARK)
@@ -268,7 +293,7 @@
}
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
- "random data available from /dev/random",
+ "random data available",
(unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
if (own_pool_ready >= MIN_READY_MARK ||
@@ -420,6 +445,19 @@
if (random_fd >= 0)
return;
+#ifdef CONFIG_GETRANDOM
+ {
+ u8 dummy;
+
+ if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
+ errno != ENOSYS) {
+ wpa_printf(MSG_DEBUG,
+ "random: getrandom() support available");
+ return;
+ }
+ }
+#endif /* CONFIG_GETRANDOM */
+
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
diff --git a/src/crypto/sha512-internal.c b/src/crypto/sha512-internal.c
index 76c4fe7..c026394 100644
--- a/src/crypto/sha512-internal.c
+++ b/src/crypto/sha512-internal.c
@@ -109,9 +109,14 @@
/* compress 1024-bits */
static int sha512_compress(struct sha512_state *md, unsigned char *buf)
{
- u64 S[8], W[80], t0, t1;
+ u64 S[8], t0, t1;
+ u64 *W;
int i;
+ W = os_malloc(80 * sizeof(u64));
+ if (!W)
+ return -1;
+
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
@@ -146,6 +151,7 @@
md->state[i] = md->state[i] + S[i];
}
+ os_free(W);
return 0;
}
diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c
new file mode 100644
index 0000000..66311c3
--- /dev/null
+++ b/src/crypto/sha512.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-512 hash implementation and interface functions
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha512.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha512_vector - HMAC-SHA512 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[64];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return -1;
+ }
+
+ /* if key is longer than 128 bytes reset it to key = SHA512(key) */
+ if (key_len > 128) {
+ if (sha512_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 64;
+ }
+
+ /* the HMAC_SHA512 transform looks like:
+ *
+ * SHA512(K XOR opad, SHA512(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 128 times
+ * opad is the byte 0x5c repeated 128 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ if (sha512_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
+
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA512 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA512_MAC_LEN;
+ return sha512_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha512 - HMAC-SHA512 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (64 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 481b346..413cccd 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -82,6 +82,7 @@
int cert_in_cb;
const char *openssl_ciphers;
unsigned int tls_session_lifetime;
+ unsigned int crl_reload_interval;
unsigned int tls_flags;
void (*event_cb)(void *ctx, enum tls_event ev,
@@ -103,6 +104,9 @@
#define TLS_CONN_SUITEB BIT(11)
#define TLS_CONN_SUITEB_NO_ECDH BIT(12)
#define TLS_CONN_DISABLE_TLSv1_3 BIT(13)
+#define TLS_CONN_ENABLE_TLSv1_0 BIT(14)
+#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
+#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -144,6 +148,8 @@
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
* @openssl_ciphers: OpenSSL cipher configuration
+ * @openssl_ecdh_curves: OpenSSL ECDH curve configuration. %NULL for auto if
+ * supported, empty string to disable, or a colon-separated curve list.
* @flags: Parameter options (TLS_CONN_*)
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
* or %NULL if OCSP is not enabled
@@ -187,6 +193,7 @@
const char *cert_id;
const char *ca_cert_id;
const char *openssl_ciphers;
+ const char *openssl_ecdh_curves;
unsigned int flags;
const char *ocsp_stapling_response;
@@ -321,9 +328,11 @@
* @tls_ctx: TLS context data from tls_init()
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
* 2 = verify CRL for all certificates
+ * @strict: 0 = allow CRL time errors, 1 = do not allow CRL time errors
* Returns: 0 on success, -1 on failure
*/
-int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
+int __must_check tls_global_set_verify(void *tls_ctx, int check_crl,
+ int strict);
/**
* tls_connection_set_verify - Set certificate verification options
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 36dafd2..527d01e 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -461,6 +461,12 @@
}
}
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: openssl_ecdh_curves not supported");
+ return -1;
+ }
+
/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
@@ -842,7 +848,7 @@
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
/* TODO */
return 0;
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index d289c94..57b3e63 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -248,6 +248,12 @@
return -1;
}
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO, "TLS: openssl_ecdh_curves not supported");
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
if (tlsv1_set_ca_cert(cred, params->ca_cert,
params->ca_cert_blob, params->ca_cert_blob_len,
params->ca_path)) {
@@ -353,7 +359,7 @@
}
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
{
struct tls_global *global = tls_ctx;
global->check_crl = check_crl;
@@ -720,12 +726,20 @@
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_failed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_read_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
@@ -733,6 +747,10 @@
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_write_alerts(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return 0;
}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 5d0c6bd..108e9aa 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -72,7 +72,7 @@
}
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
{
return -1;
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 5bb14e2..095c096 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -104,7 +104,9 @@
#endif
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x20700000L)
#ifdef CONFIG_SUITEB
static int RSA_bits(const RSA *r)
{
@@ -226,10 +228,16 @@
struct tls_data {
SSL_CTX *ssl;
unsigned int tls_session_lifetime;
+ int check_crl;
+ int check_crl_strict;
+ char *ca_cert;
+ unsigned int crl_reload_interval;
+ struct os_reltime crl_last_reload;
};
struct tls_connection {
struct tls_context *context;
+ struct tls_data *data;
SSL_CTX *ssl_ctx;
SSL *ssl;
BIO *ssl_in, *ssl_out;
@@ -315,6 +323,36 @@
#endif /* CONFIG_NO_STDOUT_DEBUG */
+static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
+{
+ int flags;
+ X509_STORE *store;
+
+ store = X509_STORE_new();
+ if (!store) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: %s - failed to allocate new certificate store",
+ __func__);
+ return NULL;
+ }
+
+ if (ca_cert && X509_STORE_load_locations(store, ca_cert, NULL) != 1) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
+ X509_STORE_free(store);
+ return NULL;
+ }
+
+ flags = check_crl ? X509_V_FLAG_CRL_CHECK : 0;
+ if (check_crl == 2)
+ flags |= X509_V_FLAG_CRL_CHECK_ALL;
+
+ X509_STORE_set_flags(store, flags);
+
+ return store;
+}
+
+
#ifdef CONFIG_NATIVE_WINDOWS
/* Windows CryptoAPI and access to certificate stores */
@@ -1003,8 +1041,10 @@
return NULL;
}
data->ssl = ssl;
- if (conf)
+ if (conf) {
data->tls_session_lifetime = conf->tls_session_lifetime;
+ data->crl_reload_interval = conf->crl_reload_interval;
+ }
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
@@ -1086,6 +1126,7 @@
os_free(context);
if (data->tls_session_lifetime > 0)
SSL_CTX_flush_sessions(ssl, 0);
+ os_free(data->ca_cert);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
@@ -1319,8 +1360,16 @@
return "client hello";
case 2:
return "server hello";
+ case 3:
+ return "hello verify request";
case 4:
return "new session ticket";
+ case 5:
+ return "end of early data";
+ case 6:
+ return "hello retry request";
+ case 8:
+ return "encrypted extensions";
case 11:
return "certificate";
case 12:
@@ -1339,6 +1388,12 @@
return "certificate url";
case 22:
return "certificate status";
+ case 23:
+ return "supplemental data";
+ case 24:
+ return "key update";
+ case 254:
+ return "message hash";
default:
return "?";
}
@@ -1481,11 +1536,32 @@
SSL_CTX *ssl = data->ssl;
struct tls_connection *conn;
long options;
+ X509_STORE *new_cert_store;
+ struct os_reltime now;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ /* Replace X509 store if it is time to update CRL. */
+ if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
+ os_reltime_expired(&now, &data->crl_last_reload,
+ data->crl_reload_interval)) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Flushing X509 store with ca_cert file");
+ new_cert_store = tls_crl_cert_reload(data->ca_cert,
+ data->check_crl);
+ if (!new_cert_store) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Error replacing X509 store with ca_cert file");
+ } else {
+ /* Replace old store */
+ SSL_CTX_set_cert_store(ssl, new_cert_store);
+ data->crl_last_reload = now;
+ }
+ }
+
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->data = data;
conn->ssl_ctx = ssl;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
@@ -2009,6 +2085,13 @@
"time mismatch");
preverify_ok = 1;
}
+ if (!preverify_ok && !conn->data->check_crl_strict &&
+ (err == X509_V_ERR_CRL_HAS_EXPIRED ||
+ err == X509_V_ERR_CRL_NOT_YET_VALID)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Ignore certificate validity CRL time mismatch");
+ preverify_ok = 1;
+ }
err_str = X509_verify_cert_error_string(err);
@@ -2399,13 +2482,16 @@
SSL_CTX_set_client_CA_list(ssl_ctx,
SSL_load_client_CA_file(ca_cert));
#endif /* OPENSSL_NO_STDIO */
+
+ os_free(data->ca_cert);
+ data->ca_cert = os_strdup(ca_cert);
}
return 0;
}
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
{
int flags;
@@ -2422,6 +2508,10 @@
if (check_crl == 2)
flags |= X509_V_FLAG_CRL_CHECK_ALL;
X509_STORE_set_flags(cs, flags);
+
+ data->check_crl = check_crl;
+ data->check_crl_strict = strict;
+ os_get_reltime(&data->crl_last_reload);
}
return 0;
}
@@ -2537,6 +2627,38 @@
else
SSL_clear_options(ssl, SSL_OP_NO_TLSv1_3);
#endif /* SSL_OP_NO_TLSv1_3 */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (flags & (TLS_CONN_ENABLE_TLSv1_0 |
+ TLS_CONN_ENABLE_TLSv1_1 |
+ TLS_CONN_ENABLE_TLSv1_2)) {
+ int version = 0;
+
+ /* Explicit request to enable TLS versions even if needing to
+ * override systemwide policies. */
+ if (flags & TLS_CONN_ENABLE_TLSv1_0) {
+ version = TLS1_VERSION;
+ } else if (flags & TLS_CONN_ENABLE_TLSv1_1) {
+ if (!(flags & TLS_CONN_DISABLE_TLSv1_0))
+ version = TLS1_1_VERSION;
+ } else if (flags & TLS_CONN_ENABLE_TLSv1_2) {
+ if (!(flags & (TLS_CONN_DISABLE_TLSv1_0 |
+ TLS_CONN_DISABLE_TLSv1_1)))
+ version = TLS1_2_VERSION;
+ }
+ if (!version) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Invalid TLS version configuration");
+ return -1;
+ }
+
+ if (SSL_set_min_proto_version(ssl, version) != 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Failed to set minimum TLS version");
+ return -1;
+ }
+ }
+#endif /* >= 1.1.0 */
+
#ifdef CONFIG_SUITEB
#ifdef OPENSSL_IS_BORINGSSL
/* Start with defaults from BoringSSL */
@@ -2639,7 +2761,22 @@
return -1;
}
}
+#else /* OPENSSL_IS_BORINGSSL */
+ if (!(flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) &&
+ openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
#endif /* OPENSSL_IS_BORINGSSL */
+#else /* CONFIG_SUITEB */
+ if (openssl_ciphers && SSL_set_cipher_list(ssl, openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set openssl_ciphers '%s'",
+ openssl_ciphers);
+ return -1;
+ }
#endif /* CONFIG_SUITEB */
return 0;
@@ -2761,6 +2898,15 @@
return 0;
}
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)\
+ && !defined(ANDROID)
+ if (SSL_use_certificate_chain_file(conn->ssl, client_cert) == 1) {
+ ERR_clear_error();
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_chain_file"
+ " --> OK");
+ return 0;
+ }
+#else
if (SSL_use_certificate_file(conn->ssl, client_cert,
SSL_FILETYPE_PEM) == 1) {
ERR_clear_error();
@@ -2768,6 +2914,7 @@
" --> OK");
return 0;
}
+#endif
tls_show_errors(MSG_DEBUG, __func__,
"SSL_use_certificate_file failed");
@@ -4521,6 +4668,40 @@
return -1;
}
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+ if (SSL_set1_curves_list(conn->ssl,
+ params->openssl_ecdh_curves) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
if (tls_set_conn_flags(conn, params->flags,
params->openssl_ciphers) < 0)
return -1;
@@ -4587,6 +4768,41 @@
return -1;
}
+ if (!params->openssl_ecdh_curves) {
+#ifndef OPENSSL_IS_BORINGSSL
+#ifndef OPENSSL_NO_EC
+#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
+ (OPENSSL_VERSION_NUMBER < 0x10100000L)
+ if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves to auto");
+ return -1;
+ }
+#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ } else if (params->openssl_ecdh_curves[0]) {
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ECDH configuration nnot supported");
+ return -1;
+#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#ifndef OPENSSL_NO_EC
+ if (SSL_CTX_set1_curves_list(ssl_ctx,
+ params->openssl_ecdh_curves) !=
+ 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
+ return -1;
+ }
+#else /* OPENSSL_NO_EC */
+ wpa_printf(MSG_INFO, "OpenSSL: ECDH not supported");
+ return -1;
+#endif /* OPENSSL_NO_EC */
+#endif /* OPENSSL_IS_BORINGSSL */
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index cc8c704..b59622e 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -1524,6 +1524,12 @@
return -1;
}
+ if (params->openssl_ecdh_curves) {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: openssl_ecdh_curves not supported");
+ 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))
@@ -1543,7 +1549,7 @@
}
-int tls_global_set_verify(void *tls_ctx, int check_crl)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
{
wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index d34c679..23423d9 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -58,6 +58,16 @@
#define HOSTAPD_CHAN_VHT_130_30 0x04000000
#define HOSTAPD_CHAN_VHT_150_10 0x08000000
+/* Allowed bandwidth mask */
+enum hostapd_chan_width_attr {
+ HOSTAPD_CHAN_WIDTH_10 = BIT(0),
+ HOSTAPD_CHAN_WIDTH_20 = BIT(1),
+ HOSTAPD_CHAN_WIDTH_40P = BIT(2),
+ HOSTAPD_CHAN_WIDTH_40M = BIT(3),
+ HOSTAPD_CHAN_WIDTH_80 = BIT(4),
+ HOSTAPD_CHAN_WIDTH_160 = BIT(5),
+};
+
/* Filter gratuitous ARP */
#define WPA_DATA_FRAME_FILTER_FLAG_ARP BIT(0)
/* Filter unsolicited Neighbor Advertisement */
@@ -111,6 +121,13 @@
int flag;
/**
+ * allowed_bw - Allowed channel width bitmask
+ *
+ * See enum hostapd_chan_width_attr.
+ */
+ u32 allowed_bw;
+
+ /**
* max_tx_power - Regulatory transmit power limit in dBm
*/
u8 max_tx_power;
@@ -914,10 +931,10 @@
* passphrase - RSN passphrase for PSK
*
* This value is made available only for WPA/WPA2-Personal (PSK) and
- * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
- * the 8..63 character ASCII passphrase, if available. Please note that
- * this can be %NULL if passphrase was not used to generate the PSK. In
- * that case, the psk field must be used to fetch the PSK.
+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
+ * is the 8..63 character ASCII passphrase, if available. Please note
+ * that this can be %NULL if passphrase was not used to generate the
+ * PSK. In that case, the psk field must be used to fetch the PSK.
*/
const char *passphrase;
@@ -925,9 +942,9 @@
* psk - RSN PSK (alternative for passphrase for PSK)
*
* This value is made available only for WPA/WPA2-Personal (PSK) and
- * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
- * the 32-octet (256-bit) PSK, if available. The driver wrapper should
- * be prepared to handle %NULL value as an error.
+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK. This
+ * is the 32-octet (256-bit) PSK, if available. The driver wrapper
+ * should be prepared to handle %NULL value as an error.
*/
const u8 *psk;
@@ -1367,6 +1384,23 @@
* service).
*/
int multicast_to_unicast;
+
+ /**
+ * ftm_responder - Whether FTM responder is enabled
+ */
+ int ftm_responder;
+
+ /**
+ * lci - Binary data, the content of an LCI report IE with type 8 as
+ * defined in IEEE Std 802.11-2016, 9.4.2.22.10
+ */
+ const struct wpabuf *lci;
+
+ /**
+ * civic - Binary data, the content of a measurement report IE with
+ * type 11 as defined in IEEE Std 802.11-2016, 9.4.2.22.13
+ */
+ const struct wpabuf *civic;
};
struct wpa_driver_mesh_bss_params {
@@ -1424,6 +1458,7 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 0x00002000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 0x00004000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 0x00008000
+#define WPA_DRIVER_CAPA_KEY_MGMT_SAE 0x00010000
/** Bitfield of supported key management suites */
unsigned int key_mgmt;
@@ -1457,7 +1492,7 @@
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
* struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
-#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008
/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
/** Driver provides separate commands for authentication and association (SME in
@@ -1579,6 +1614,10 @@
#define WPA_DRIVER_FLAGS_MFP_OPTIONAL 0x0040000000000000ULL
/** Driver is a self-managed regulatory device */
#define WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY 0x0080000000000000ULL
+/** Driver supports FTM responder functionality */
+#define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL
+/** Driver support 4-way handshake offload for WPA-Personal */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL
u64 flags;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -1902,19 +1941,21 @@
SMPS_INVALID,
};
-/* enum chan_width - Channel width definitions */
-enum chan_width {
- CHAN_WIDTH_20_NOHT,
- CHAN_WIDTH_20,
- CHAN_WIDTH_40,
- CHAN_WIDTH_80,
- CHAN_WIDTH_80P80,
- CHAN_WIDTH_160,
- CHAN_WIDTH_UNKNOWN
-};
+#define WPA_INVALID_NOISE 9999
/**
* struct wpa_signal_info - Information about channel signal quality
+ * @frequency: control frequency
+ * @above_threshold: true if the above threshold was crossed
+ * (relevant for a CQM event)
+ * @current_signal: in dBm
+ * @avg_signal: in dBm
+ * @avg_beacon_signal: in dBm
+ * @current_noise: %WPA_INVALID_NOISE if not supported
+ * @current_txrate: current TX rate
+ * @chanwidth: channel width
+ * @center_frq1: center frequency for the first segment
+ * @center_frq2: center frequency for the second segment (if relevant)
*/
struct wpa_signal_info {
u32 frequency;
@@ -1930,6 +1971,26 @@
};
/**
+ * struct wpa_channel_info - Information about the current channel
+ * @frequency: Center frequency of the primary 20 MHz channel
+ * @chanwidth: Width of the current operating channel
+ * @sec_channel: Location of the secondary 20 MHz channel (either +1 or -1).
+ * This field is only filled in when using a 40 MHz channel.
+ * @center_frq1: Center frequency of frequency segment 0
+ * @center_frq2: Center frequency of frequency segment 1 (for 80+80 channels)
+ * @seg1_idx: Frequency segment 1 index when using a 80+80 channel. This is
+ * derived from center_frq2 for convenience.
+ */
+struct wpa_channel_info {
+ u32 frequency;
+ enum chan_width chanwidth;
+ int sec_channel;
+ int center_frq1;
+ int center_frq2;
+ u8 seg1_idx;
+};
+
+/**
* struct beacon_data - Beacon data
* @head: Head portion of Beacon frame (before TIM IE)
* @tail: Tail portion of Beacon frame (after TIM IE)
@@ -3365,6 +3426,14 @@
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
/**
+ * channel_info - Get parameters of the current operating channel
+ * @priv: Private driver interface data
+ * @channel_info: Channel info structure
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*channel_info)(void *priv, struct wpa_channel_info *channel_info);
+
+ /**
* set_authmode - Set authentication algorithm(s) for static WEP
* @priv: Private driver interface data
* @authmode: 1=Open System, 2=Shared Key, 3=both
@@ -3645,7 +3714,7 @@
/**
* status - Get driver interface status information
* @priv: Private driver interface data
- * @buf: Buffer for printing tou the status information
+ * @buf: Buffer for printing the status information
* @buflen: Maximum length of the buffer
* Returns: Length of written status information or -1 on failure
*/
@@ -3769,6 +3838,14 @@
int (*set_transmit_next_pn)(void *priv, struct transmit_sa *sa);
/**
+ * set_receive_lowest_pn - Set receive lowest PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+ int (*set_receive_lowest_pn)(void *priv, struct receive_sa *sa);
+
+ /**
* create_receive_sc - create secure channel for receiving
* @priv: Private driver interface data
* @sc: secure channel
@@ -4079,6 +4156,15 @@
*/
int (*send_external_auth_status)(void *priv,
struct external_auth *params);
+
+ /**
+ * set_4addr_mode - Set 4-address mode
+ * @priv: Private driver interface data
+ * @bridge_ifname: Bridge interface name
+ * @val: 0 - disable 4addr mode, 1 - enable 4addr mode
+ * Returns: 0 on success, < 0 on failure
+ */
+ int (*set_4addr_mode)(void *priv, const char *bridge_ifname, int val);
};
/**
@@ -5521,6 +5607,8 @@
/* Convert chan_width to a string for logging and control interfaces */
const char * channel_width_to_string(enum chan_width width);
+int channel_width_to_int(enum chan_width width);
+
int ht_supported(const struct hostapd_hw_modes *mode);
int vht_supported(const struct hostapd_hw_modes *mode);
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 16c2ae9..62f5baa 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1329,11 +1329,11 @@
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
- } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) {
+ } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) {
/* Format: "Manage.auth <frame len>" | zero padding | frame */
int len = atoi(custom + 12);
- if (len < 0 ||
- MGMT_FRAM_TAG_SIZE + len > end - custom) {
+ if (len < 0 ||
+ MGMT_FRAM_TAG_SIZE + len > end - custom) {
wpa_printf(MSG_DEBUG,
"Invalid Manage.auth event length %d", len);
return;
@@ -1342,7 +1342,7 @@
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */
#ifdef ATHEROS_USE_RAW_RECEIVE
- } else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
+ } else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
int len = atoi(custom + 14);
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index ac0916e..e55e6cd 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -115,6 +115,25 @@
}
+int channel_width_to_int(enum chan_width width)
+{
+ switch (width) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ return 20;
+ case CHAN_WIDTH_40:
+ return 40;
+ case CHAN_WIDTH_80:
+ return 80;
+ case CHAN_WIDTH_80P80:
+ case CHAN_WIDTH_160:
+ return 160;
+ default:
+ return 0;
+ }
+}
+
+
int ht_supported(const struct hostapd_hw_modes *mode)
{
if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
@@ -234,7 +253,8 @@
DF2S(DRIVER_IE);
DF2S(SET_KEYS_AFTER_ASSOC);
DF2S(DFS_OFFLOAD);
- DF2S(4WAY_HANDSHAKE);
+ DF2S(4WAY_HANDSHAKE_PSK);
+ DF2S(4WAY_HANDSHAKE_8021X);
DF2S(WIRED);
DF2S(SME);
DF2S(AP);
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 597da33..61b39b1 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -231,7 +231,11 @@
}
memset(&ifr, 0, sizeof(ifr));
- snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
+ if (os_snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap",
+ drv->iface) >= (int) sizeof(ifr.ifr_name)) {
+ wpa_printf(MSG_ERROR, "hostap: AP interface name truncated");
+ return -1;
+ }
if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
strerror(errno));
@@ -348,7 +352,10 @@
struct ifreq ifr;
char ifname[IFNAMSIZ];
- os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface);
+ if (os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface) >= IFNAMSIZ) {
+ wpa_printf(MSG_ERROR, "hostap: AP interface name truncated");
+ return -1;
+ }
if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0)
return -1;
@@ -1124,6 +1131,7 @@
for (i = 0; i < 14; i++) {
mode->channels[i].chan = i + 1;
mode->channels[i].freq = chan2freq[i];
+ mode->channels[i].allowed_bw = HOSTAPD_CHAN_WIDTH_20;
/* TODO: Get allowed channel list from the driver */
if (i >= 11)
mode->channels[i].flag = HOSTAPD_CHAN_DISABLED;
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index e89b3ba..9d981bb 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -177,6 +177,9 @@
if (drv->controlled_port_enabled_set) {
struct rtnl_link *change = rtnl_link_alloc();
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit controlled_port_enabled=%d",
+ drv->ifname, drv->controlled_port_enabled);
if (!change)
return -1;
@@ -196,13 +199,24 @@
drv->controlled_port_enabled_set = FALSE;
}
- if (drv->protect_frames_set)
+ if (drv->protect_frames_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit protect_frames=%d",
+ drv->ifname, drv->protect_frames);
rtnl_link_macsec_set_protect(drv->link, drv->protect_frames);
+ }
- if (drv->encrypt_set)
+ if (drv->encrypt_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: try_commit encrypt=%d",
+ drv->ifname, drv->encrypt);
rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt);
+ }
if (drv->replay_protect_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit replay_protect=%d replay_window=%d",
+ drv->ifname, drv->replay_protect,
+ drv->replay_window);
rtnl_link_macsec_set_replay_protect(drv->link,
drv->replay_protect);
if (drv->replay_protect)
@@ -210,8 +224,12 @@
drv->replay_window);
}
- if (drv->encoding_sa_set)
+ if (drv->encoding_sa_set) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: try_commit encoding_sa=%d",
+ drv->ifname, drv->encoding_sa);
rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
+ }
err = rtnl_link_add(drv->sk, drv->link, 0);
if (err < 0)
@@ -318,6 +336,8 @@
drv->common.ifname);
goto cache;
}
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "ifname=%s parent_ifi=%d",
+ drv->common.ifname, drv->parent_ifi);
err = init_genl_ctx(drv);
if (err < 0)
@@ -639,7 +659,7 @@
DRV_PREFIX "failed to communicate: %d (%s)",
ret, nl_geterror(-ret));
- ctx->cb_arg.pn = 0;
+ ctx->cb_arg.pn = NULL;
out_free_msg:
nlmsg_free(msg);
@@ -670,6 +690,50 @@
/**
+ * macsec_drv_set_receive_lowest_pn - Set receive lowest PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: set_receive_lowest_pn -> %d: %d",
+ drv->ifname, sa->an, sa->next_pn);
+
+ msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
* macsec_drv_get_transmit_next_pn - Get transmit next PN
* @priv: Private driver interface data
* @sa: secure association
@@ -754,8 +818,10 @@
struct nl_msg *msg;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
- SCI2STR(sc->sci.addr, sc->sci.port));
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_receive_sc -> " SCISTR
+ " (conf_offset=%u validation=%d)",
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port),
+ conf_offset, validation);
msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi);
if (!msg)
@@ -790,8 +856,8 @@
struct nl_msg *msg;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
- SCI2STR(sc->sci.addr, sc->sci.port));
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sc -> " SCISTR,
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi);
if (!msg)
@@ -827,8 +893,17 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
- SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: create_receive_sa -> %d on " SCISTR
+ " (enable_receive=%d next_pn=%u)",
+ drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->enable_receive, sa->next_pn);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
+ &sa->pkey->key_identifier,
+ sizeof(sa->pkey->key_identifier));
+ wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
+ sa->pkey->key, sa->pkey->key_len);
msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi);
if (!msg)
@@ -877,7 +952,8 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi);
@@ -954,7 +1030,8 @@
struct macsec_drv_data *drv = priv;
struct macsec_genl_ctx *ctx = &drv->ctx;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
@@ -973,7 +1050,8 @@
struct macsec_drv_data *drv = priv;
struct macsec_genl_ctx *ctx = &drv->ctx;
- wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, sa->an,
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_receive_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_rx_sa(ctx, drv->ifi, mka_sci_u64(&sa->sc->sci),
@@ -1009,7 +1087,7 @@
*/
static int macsec_drv_create_transmit_sc(
void *priv, struct transmit_sc *sc,
- enum confidentiality_offset conf_offset)
+ unsigned int conf_offset)
{
struct macsec_drv_data *drv = priv;
struct rtnl_link *link;
@@ -1017,7 +1095,10 @@
u64 sci;
int err;
- wpa_printf(MSG_DEBUG, "%s", __func__);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)",
+ drv->common.ifname, SCI2STR(sc->sci.addr, sc->sci.port),
+ conf_offset);
if (!drv->sk) {
wpa_printf(MSG_ERROR, DRV_PREFIX "NULL rtnl socket");
@@ -1060,6 +1141,9 @@
drv->ifi = rtnl_link_get_ifindex(link);
ifname = rtnl_link_get_name(link);
+ wpa_printf(MSG_DEBUG,
+ DRV_PREFIX "%s: create_transmit_sc: ifi=%d ifname=%s",
+ drv->common.ifname, drv->ifi, ifname);
os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
rtnl_link_put(link);
@@ -1088,7 +1172,8 @@
struct macsec_drv_data *drv = priv;
int err;
- wpa_printf(MSG_DEBUG, "%s", __func__);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sc -> " SCISTR,
+ drv->ifname, SCI2STR(sc->sci.addr, sc->sci.port));
if (!drv->sk)
return 0;
@@ -1125,7 +1210,16 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_transmit_sa -> %d on "
+ SCISTR " (enable_transmit=%d next_pn=%u)",
+ drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->enable_transmit, sa->next_pn);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA keyid",
+ &sa->pkey->key_identifier,
+ sizeof(sa->pkey->key_identifier));
+ wpa_hexdump_key(MSG_DEBUG, DRV_PREFIX "SA key",
+ sa->pkey->key, sa->pkey->key_len);
msg = msg_prepare(MACSEC_CMD_ADD_TXSA, ctx, drv->ifi);
if (!msg)
@@ -1171,7 +1265,9 @@
struct nlattr *nest;
int ret = -1;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: delete_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
msg = msg_prepare(MACSEC_CMD_DEL_TXSA, ctx, drv->ifi);
if (!msg)
@@ -1243,7 +1339,9 @@
struct macsec_genl_ctx *ctx = &drv->ctx;
int ret;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: enable_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE);
if (ret < 0) {
@@ -1269,12 +1367,38 @@
struct macsec_drv_data *drv = priv;
struct macsec_genl_ctx *ctx = &drv->ctx;
- wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: disable_transmit_sa -> %d on "
+ SCISTR, drv->ifname, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE);
}
+static int macsec_drv_status(void *priv, char *buf, size_t buflen)
+{
+ struct macsec_drv_data *drv = priv;
+ int res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
+ "ifname=%s\n"
+ "ifi=%d\n"
+ "parent_ifname=%s\n"
+ "parent_ifi=%d\n",
+ drv->common.ifname, drv->ifi,
+ drv->ifname, drv->parent_ifi);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
+
const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
.name = "macsec_linux",
.desc = "MACsec Ethernet driver for Linux",
@@ -1293,6 +1417,7 @@
.set_current_cipher_suite = macsec_drv_set_current_cipher_suite,
.enable_controlled_port = macsec_drv_enable_controlled_port,
.get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn,
+ .set_receive_lowest_pn = macsec_drv_set_receive_lowest_pn,
.get_transmit_next_pn = macsec_drv_get_transmit_next_pn,
.set_transmit_next_pn = macsec_drv_set_transmit_next_pn,
.create_receive_sc = macsec_drv_create_receive_sc,
@@ -1307,4 +1432,6 @@
.delete_transmit_sa = macsec_drv_delete_transmit_sa,
.enable_transmit_sa = macsec_drv_enable_transmit_sa,
.disable_transmit_sa = macsec_drv_disable_transmit_sa,
+
+ .status = macsec_drv_status,
};
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index e397950..8372393 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -383,7 +383,7 @@
}
-int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
+static int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 771e766..e0e6fe5 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -40,6 +40,9 @@
#include "driver_nl80211.h"
+#ifndef NETLINK_CAP_ACK
+#define NETLINK_CAP_ACK 10
+#endif /* NETLINK_CAP_ACK */
/* support for extack if compilation headers are too old */
#ifndef NETLINK_EXT_ACK
#define NETLINK_EXT_ACK 11
@@ -406,6 +409,11 @@
setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
NETLINK_EXT_ACK, &opt, sizeof(opt));
+ /* 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));
+
err = nl_send_auto_complete(nl_handle, msg);
if (err < 0)
goto out;
@@ -1469,7 +1477,7 @@
{
struct nl_msg *msg;
- sig->current_signal = -9999;
+ sig->current_signal = -WPA_INVALID_NOISE;
sig->current_txrate = 0;
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
@@ -1531,7 +1539,7 @@
{
struct nl_msg *msg;
- sig_change->current_noise = 9999;
+ sig_change->current_noise = WPA_INVALID_NOISE;
sig_change->frequency = drv->assoc_freq;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
@@ -1539,6 +1547,70 @@
}
+static int get_channel_info(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1] = { 0 };
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_channel_info *chan_info = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ os_memset(chan_info, 0, sizeof(struct wpa_channel_info));
+ chan_info->chanwidth = CHAN_WIDTH_UNKNOWN;
+
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ chan_info->frequency =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ chan_info->chanwidth = convert2width(
+ nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ enum nl80211_channel_type ct =
+ nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+ switch (ct) {
+ case NL80211_CHAN_HT40MINUS:
+ chan_info->sec_channel = -1;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_info->sec_channel = 1;
+ break;
+ default:
+ chan_info->sec_channel = 0;
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ chan_info->center_frq1 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ chan_info->center_frq2 =
+ nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ if (chan_info->center_frq2) {
+ u8 seg1_idx = 0;
+
+ if (ieee80211_freq_to_chan(chan_info->center_frq2, &seg1_idx) !=
+ NUM_HOSTAPD_MODES)
+ chan_info->seg1_idx = seg1_idx;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_channel_info(void *priv, struct wpa_channel_info *ci)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+ return send_and_recv_msgs(drv, msg, get_channel_info, ci);
+}
+
+
static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
void *handle)
{
@@ -2169,6 +2241,11 @@
ret = -1;
#endif /* CONFIG_DPP */
#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_OCV
+ /* SA Query Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x08\x00", 2) < 0)
+ ret = -1;
+#endif /* CONFIG_OCV */
/* SA Query Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
ret = -1;
@@ -2962,7 +3039,7 @@
#endif /* CONFIG_DRIVER_NL80211_QCA */
if (alg == WPA_ALG_PMK &&
- (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return nl80211_set_pmk(drv, key, key_len, addr);
if (alg == WPA_ALG_NONE) {
@@ -3165,7 +3242,8 @@
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
- int local_state_change)
+ int local_state_change,
+ struct nl_handle *nl_connect)
{
int ret;
struct nl_msg *msg;
@@ -3179,7 +3257,10 @@
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (nl_connect)
+ ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+ else
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: MLME command failed: reason=%u ret=%d (%s)",
@@ -3190,7 +3271,8 @@
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- int reason_code)
+ int reason_code,
+ struct nl_handle *nl_connect)
{
int ret;
int drv_associated = drv->associated;
@@ -3199,7 +3281,7 @@
nl80211_mark_disconnected(drv);
/* Disconnect command doesn't need BSSID - it uses cached value */
ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
- reason_code, 0);
+ reason_code, 0, nl_connect);
/*
* For locally generated disconnect, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
@@ -3221,13 +3303,19 @@
nl80211_mark_disconnected(drv);
return nl80211_leave_ibss(drv, 1);
}
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
- return wpa_driver_nl80211_disconnect(drv, reason_code);
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ struct nl_handle *nl_connect = NULL;
+
+ if (bss->use_nl_connect)
+ nl_connect = bss->nl_connect;
+ return wpa_driver_nl80211_disconnect(drv, reason_code,
+ nl_connect);
+ }
wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
__func__, MAC2STR(addr), reason_code);
nl80211_mark_disconnected(drv);
ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
- reason_code, 0);
+ reason_code, 0, NULL);
/*
* For locally generated deauthenticate, supplicant already generates a
* DEAUTH event, so ignore the event from NL80211.
@@ -3389,8 +3477,8 @@
goto fail;
}
if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid))
goto fail;
@@ -3957,7 +4045,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
u8 cmd = NL80211_CMD_NEW_BEACON;
- int ret;
+ int ret = -ENOBUFS;
int beacon_set;
int num_suites;
int smps_mode;
@@ -3986,8 +4074,8 @@
wpa_printf(MSG_DEBUG, "nl80211: beacon_rate=%u", params->beacon_rate);
wpa_printf(MSG_DEBUG, "nl80211: rate_type=%d", params->rate_type);
wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
- wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, "nl80211: ssid=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
params->head) ||
@@ -4163,6 +4251,29 @@
goto fail;
}
+ if (params->ftm_responder) {
+ struct nlattr *ftm;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_FTM_RESPONDER)) {
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ ftm = nla_nest_start(msg, NL80211_ATTR_FTM_RESPONDER);
+ if (!ftm ||
+ nla_put_flag(msg, NL80211_FTM_RESP_ATTR_ENABLED) ||
+ (params->lci &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_LCI,
+ wpabuf_len(params->lci),
+ wpabuf_head(params->lci))) ||
+ (params->civic &&
+ nla_put(msg, NL80211_FTM_RESP_ATTR_CIVICLOC,
+ wpabuf_len(params->civic),
+ wpabuf_head(params->civic))))
+ goto fail;
+ nla_nest_end(msg, ftm);
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -4214,7 +4325,7 @@
return ret;
fail:
nlmsg_free(msg);
- return -ENOBUFS;
+ return ret;
}
@@ -5178,8 +5289,8 @@
params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
goto fail;
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
os_memcpy(drv->ssid, params->ssid, params->ssid_len);
@@ -5340,8 +5451,8 @@
}
if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
- params->ssid, params->ssid_len);
+ wpa_printf(MSG_DEBUG, " * SSID=%s",
+ wpa_ssid_txt(params->ssid, params->ssid_len));
if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
params->ssid))
return -1;
@@ -5465,9 +5576,16 @@
return -1;
}
+ if (params->req_key_mgmt_offload &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) {
+ wpa_printf(MSG_DEBUG, " * WANT_1X_4WAY_HS");
+ if (nla_put_flag(msg, NL80211_ATTR_WANT_1X_4WAY_HS))
+ return -1;
+ }
+
/* Add PSK in case of 4-way handshake offload */
if (params->psk &&
- (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) {
+ (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
wpa_hexdump_key(MSG_DEBUG, " * PSK", params->psk, 32);
if (nla_put(msg, NL80211_ATTR_PMK, 32, params->psk))
return -1;
@@ -5598,9 +5716,10 @@
goto fail;
if (nl_connect)
- ret = send_and_recv(drv->global, nl_connect, msg, NULL, NULL);
+ ret = send_and_recv(drv->global, nl_connect, msg,
+ NULL, (void *) -1);
else
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
msg = NULL;
if (ret) {
@@ -5612,6 +5731,7 @@
}
fail:
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return ret;
@@ -5642,7 +5762,7 @@
"disconnecting before reassociation "
"attempt");
if (wpa_driver_nl80211_disconnect(
- drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+ drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect))
return -1;
ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
}
@@ -5673,8 +5793,13 @@
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
- if (params->auth_alg & WPA_AUTH_ALG_SAE)
+ if (params->auth_alg & WPA_AUTH_ALG_SAE) {
nl_connect = bss->nl_connect;
+ bss->use_nl_connect = 1;
+ } else {
+ bss->use_nl_connect = 0;
+ }
+
return wpa_driver_nl80211_connect(drv, params, nl_connect);
}
@@ -6281,6 +6406,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *txq, *params;
+ int res;
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
if (!msg)
@@ -6326,7 +6452,11 @@
nla_nest_end(msg, txq);
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d",
+ queue, aifs, cw_min, cw_max, burst_time, res);
+ if (res == 0)
return 0;
msg = NULL;
fail:
@@ -6625,9 +6755,12 @@
}
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
- if (bridge_ifname)
- linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
- name);
+ if (bridge_ifname &&
+ linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
+ name) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to remove interface %s from bridge %s: %s",
+ name, bridge_ifname, strerror(errno));
i802_set_sta_vlan(priv, addr, bss->ifname, 0);
nl80211_remove_iface(drv, if_nametoindex(name));
@@ -7796,11 +7929,12 @@
params->fils_cache_id)) ||
(params->pmk_len && params->pmk_len <= PMK_MAX_LEN &&
nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) {
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1);
}
@@ -8572,6 +8706,8 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
int res;
char *pos, *end;
+ struct nl_msg *msg;
+ char alpha2[3] = { 0, 0, 0 };
pos = buf;
end = buf + buflen;
@@ -8716,6 +8852,23 @@
pos += res;
}
+ msg = nlmsg_alloc();
+ if (msg &&
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG) &&
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx) == 0) {
+ if (send_and_recv_msgs(drv, msg, nl80211_get_country,
+ alpha2) == 0 &&
+ alpha2[0]) {
+ res = os_snprintf(pos, end - pos, "country=%s\n",
+ alpha2);
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+ }
+ } else {
+ nlmsg_free(msg);
+ }
+
return pos - buf;
}
@@ -9282,8 +9435,8 @@
size_t mesh_id_len)
{
if (mesh_id) {
- wpa_hexdump_ascii(MSG_DEBUG, " * Mesh ID (SSID)",
- mesh_id, mesh_id_len);
+ wpa_printf(MSG_DEBUG, " * Mesh ID (SSID)=%s",
+ wpa_ssid_txt(mesh_id, mesh_id_len));
return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
}
@@ -10648,6 +10801,49 @@
}
+static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
+ int val)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %s 4addr mode (bridge_ifname: %s)",
+ val ? "Enable" : "Disable", bridge_ifname);
+
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+ if (!msg || nla_put_u8(msg, NL80211_ATTR_4ADDR, val))
+ goto fail;
+
+ if (bridge_ifname[0] && bss->added_if_into_bridge && !val) {
+ if (linux_br_del_if(drv->global->ioctl_sock,
+ bridge_ifname, bss->ifname)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to remove interface %s from bridge %s",
+ bss->ifname, bridge_ifname);
+ return -1;
+ }
+ bss->added_if_into_bridge = 0;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (!ret) {
+ if (bridge_ifname[0] && val &&
+ i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
+ return -1;
+ return 0;
+ }
+
+fail:
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR, "nl80211: Failed to enable/disable 4addr");
+
+ return ret;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -10707,6 +10903,7 @@
.resume = wpa_driver_nl80211_resume,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
+ .channel_info = nl80211_channel_info,
.send_frame = nl80211_send_frame,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
@@ -10776,4 +10973,5 @@
.get_ext_capab = nl80211_get_ext_capab,
.update_connect_params = nl80211_update_connection_params,
.send_external_auth_status = nl80211_send_external_auth_status,
+ .set_4addr_mode = nl80211_set_4addr_mode,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 5ac0c7d..1e7fe7a 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -66,6 +66,7 @@
unsigned int wdev_id_set:1;
unsigned int added_if:1;
unsigned int static_ap:1;
+ unsigned int use_nl_connect:1;
u8 addr[ETH_ALEN];
@@ -165,6 +166,7 @@
unsigned int he_capab_vendor_cmd_avail:1;
unsigned int fetch_bss_trans_status:1;
unsigned int roam_vendor_cmd_avail:1;
+ unsigned int get_supported_akm_suites_avail:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -252,7 +254,8 @@
enum nl80211_iftype nlmode);
int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
const u8 *addr, int cmd, u16 reason_code,
- int local_state_change);
+ int local_state_change,
+ struct nl_handle *nl_connect);
int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 7b360d2..37eeb5e 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -403,10 +403,11 @@
capa->flags |= WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD;
if (ext_feature_isset(ext_features, len,
- NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK) &&
- ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK;
+ if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
- capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_MFP_OPTIONAL))
@@ -428,6 +429,10 @@
NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION))
capa->flags |= WPA_DRIVER_FLAGS_OCE_STA;
#endif /* CONFIG_MBO */
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER))
+ capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER;
}
@@ -782,6 +787,9 @@
case QCA_NL80211_VENDOR_SUBCMD_ROAM:
drv->roam_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS:
+ drv->get_supported_akm_suites_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -954,6 +962,126 @@
}
+static unsigned int get_akm_suites_info(struct nlattr *tb)
+{
+ int i, num;
+ unsigned int key_mgmt = 0;
+ u32 *akms;
+
+ if (!tb)
+ return 0;
+
+ num = nla_len(tb) / sizeof(u32);
+ akms = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ u32 a = akms[i];
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Supported AKM %02x-%02x-%02x:%u",
+ a >> 24, (a >> 16) & 0xff,
+ (a >> 8) & 0xff, a & 0xff);
+ switch (a) {
+ case RSN_AUTH_KEY_MGMT_UNSPEC_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2;
+ break;
+ case RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_802_1X:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_PSK:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B;
+ break;
+ case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+ break;
+ case RSN_AUTH_KEY_MGMT_OWE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OWE;
+ break;
+ case RSN_AUTH_KEY_MGMT_DPP:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA256:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256;
+ break;
+ case RSN_AUTH_KEY_MGMT_FT_FILS_SHA384:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384;
+ break;
+ case RSN_AUTH_KEY_MGMT_SAE:
+ key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SAE;
+ break;
+ }
+ }
+
+ return key_mgmt;
+}
+
+
+static int get_akm_suites_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ unsigned int *key_mgmt = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ struct nlattr *tb_data[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb_data, NL80211_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ *key_mgmt =
+ get_akm_suites_info(tb_data[NL80211_ATTR_AKM_SUITES]);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int qca_nl80211_get_akm_suites(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ unsigned int key_mgmt = 0;
+ int ret;
+
+ if (!drv->get_supported_akm_suites_avail)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, get_akm_suites_handler, &key_mgmt);
+ if (!ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Replace capa.key_mgmt based on driver advertised capabilities: 0x%x",
+ key_mgmt);
+ drv->capa.key_mgmt = key_mgmt;
+ }
+
+ return ret;
+}
+
+
static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1179,11 +1307,18 @@
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256 |
- WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384;
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384 |
+ WPA_DRIVER_CAPA_KEY_MGMT_SAE;
else if (drv->capa.flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ /* Override drv->capa.key_mgmt based on driver advertised capability
+ * constraints, if available. */
+ qca_nl80211_get_akm_suites(drv);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
@@ -1307,6 +1442,7 @@
u8 channel;
chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
chan->flag = 0;
+ chan->allowed_bw = ~0;
chan->dfs_cac_ms = 0;
if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
chan->chan = channel;
@@ -1322,6 +1458,19 @@
if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_10MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_10;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_20;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40P;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_40M;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_80;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_160;
+
if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
enum nl80211_dfs_state state =
nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
@@ -1356,6 +1505,12 @@
[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
[NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_NO_10MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_20MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_HT40_PLUS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_HT40_MINUS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_80MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_160MHZ] = { .type = NLA_FLAG },
};
int new_channels = 0;
struct hostapd_channel_data *channel;
@@ -1932,6 +2087,61 @@
}
+static const char * modestr(enum hostapd_hw_mode mode)
+{
+ switch (mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return "802.11b";
+ case HOSTAPD_MODE_IEEE80211G:
+ return "802.11g";
+ case HOSTAPD_MODE_IEEE80211A:
+ return "802.11a";
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "802.11ad";
+ default:
+ return "?";
+ }
+}
+
+
+static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes,
+ u16 num_modes)
+{
+ int i;
+
+ if (!modes)
+ return;
+
+ for (i = 0; i < num_modes; i++) {
+ struct hostapd_hw_modes *mode = &modes[i];
+ char str[200];
+ char *pos = str;
+ char *end = pos + sizeof(str);
+ int j, res;
+
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan = &mode->channels[j];
+
+ res = os_snprintf(pos, end - pos, " %d%s%s%s",
+ chan->freq,
+ (chan->flag & HOSTAPD_CHAN_DISABLED) ?
+ "[DISABLED]" : "",
+ (chan->flag & HOSTAPD_CHAN_NO_IR) ?
+ "[NO_IR]" : "",
+ (chan->flag & HOSTAPD_CHAN_RADAR) ?
+ "[RADAR]" : "");
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "nl80211: Mode IEEE %s:%s",
+ modestr(mode->mode), str);
+ }
+}
+
+
struct hostapd_hw_modes *
nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags,
u8 *dfs_domain)
@@ -1963,6 +2173,8 @@
}
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ struct hostapd_hw_modes *modes;
+
nl80211_set_regulatory_flags(drv, &result);
if (result.failed) {
int i;
@@ -1978,8 +2190,10 @@
*dfs_domain = result.dfs_domain;
- return wpa_driver_nl80211_postprocess_modes(result.modes,
- num_modes);
+ modes = wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
+ nl80211_dump_chan_list(modes, *num_modes);
+ return modes;
}
return NULL;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 5b8efbc..06e619b 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -754,12 +754,12 @@
* disconnection event for the old AP may show up after
* we have started connection with the new AP.
*/
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore deauth/disassoc event from old AP "
- MACSTR
- " when already connecting with " MACSTR,
- MAC2STR(bssid),
- MAC2STR(drv->auth_attempt_bssid));
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore deauth/disassoc event from old AP "
+ MACSTR
+ " when already connecting with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
return;
}
@@ -2183,6 +2183,54 @@
}
+static void nl80211_dump_freq(const char *title, struct nlattr *nl_freq)
+{
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ };
+ struct nlattr *tb[NL80211_FREQUENCY_ATTR_MAX + 1];
+ u32 freq = 0, max_tx_power = 0;
+
+ nla_parse(tb, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+
+ if (tb[NL80211_FREQUENCY_ATTR_FREQ])
+ freq = nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
+ if (tb[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
+ max_tx_power =
+ nla_get_u32(tb[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Channel (%s): freq=%u max_tx_power=%u%s%s%s",
+ title, freq, max_tx_power,
+ tb[NL80211_FREQUENCY_ATTR_DISABLED] ? " disabled" : "",
+ tb[NL80211_FREQUENCY_ATTR_NO_IR] ? " no-IR" : "",
+ tb[NL80211_FREQUENCY_ATTR_RADAR] ? " radar" : "");
+}
+
+
+static void nl80211_reg_beacon_hint_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+ os_memset(&data, 0, sizeof(data));
+ data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
+
+ if (tb[NL80211_ATTR_FREQ_BEFORE])
+ nl80211_dump_freq("before", tb[NL80211_ATTR_FREQ_BEFORE]);
+ if (tb[NL80211_ATTR_FREQ_AFTER])
+ nl80211_dump_freq("after", tb[NL80211_ATTR_FREQ_AFTER]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb)
{
@@ -2271,7 +2319,7 @@
ed.sta_opmode.addr = nla_data(tb[NL80211_ATTR_MAC]);
if (tb[NL80211_ATTR_SMPS_MODE]) {
- smps_mode = nla_get_u32(tb[NL80211_ATTR_SMPS_MODE]);
+ smps_mode = nla_get_u8(tb[NL80211_ATTR_SMPS_MODE]);
switch (smps_mode) {
case NL80211_SMPS_OFF:
ed.sta_opmode.smps_mode = SMPS_OFF;
@@ -2327,7 +2375,6 @@
struct nlattr **tb)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- union wpa_event_data data;
int external_scan_event = 0;
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
@@ -2480,11 +2527,7 @@
nl80211_reg_change_event(drv, tb);
break;
case NL80211_CMD_REG_BEACON_HINT:
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
- os_memset(&data, 0, sizeof(data));
- data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- &data);
+ nl80211_reg_beacon_hint_event(drv, tb);
break;
case NL80211_CMD_NEW_STATION:
nl80211_new_station_event(drv, bss, tb);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 86501f4..9afa5b3 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -197,9 +197,9 @@
if (ssids == NULL)
goto fail;
for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s",
+ wpa_ssid_txt(params->ssids[i].ssid,
+ params->ssids[i].ssid_len));
if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
params->ssids[i].ssid))
goto fail;
@@ -537,10 +537,10 @@
for (i = 0; i < drv->num_filter_ssids; i++) {
struct nlattr *match_set_ssid;
- wpa_hexdump_ascii(MSG_MSGDUMP,
- "nl80211: Sched scan filter SSID",
- drv->filter_ssids[i].ssid,
- drv->filter_ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan filter SSID %s",
+ wpa_ssid_txt(drv->filter_ssids[i].ssid,
+ drv->filter_ssids[i].ssid_len));
match_set_ssid = nla_nest_start(msg, i + 1);
if (match_set_ssid == NULL ||
@@ -866,7 +866,8 @@
"mismatch (" MACSTR ")", MAC2STR(addr));
wpa_driver_nl80211_mlme(drv, addr,
NL80211_CMD_DEAUTHENTICATE,
- WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+ WLAN_REASON_PREV_AUTH_NOT_VALID, 1,
+ NULL);
}
}
@@ -1097,9 +1098,9 @@
if (ssids == NULL)
goto fail;
for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan SSID %s",
+ wpa_ssid_txt(params->ssids[i].ssid,
+ params->ssids[i].ssid_len));
if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
params->ssids[i].ssid))
goto fail;
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index e94eda0..c06e75c 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -62,7 +62,8 @@
wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
{
os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
+ WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
return 0;
}
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 933b8d9..f7755cc 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -868,14 +868,16 @@
const char *ifname)
{
char buf[200], *res;
- int type;
+ int type, ret;
FILE *f;
if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0)
return -1;
- snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
- drv->ifname, ifname);
+ ret = snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
+ drv->ifname, ifname);
+ if (os_snprintf_error(sizeof(buf), ret))
+ return -1;
f = fopen(buf, "r");
if (!f)
@@ -1645,7 +1647,8 @@
if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
- drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
+ WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
@@ -1676,7 +1679,7 @@
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return 0;
if (!psk)
@@ -2428,8 +2431,8 @@
struct iwreq iwr;
os_memset(si, 0, sizeof(*si));
- si->current_signal = -9999;
- si->current_noise = 9999;
+ si->current_signal = -WPA_INVALID_NOISE;
+ si->current_noise = WPA_INVALID_NOISE;
si->chanwidth = CHAN_WIDTH_UNKNOWN;
os_memset(&iwr, 0, sizeof(iwr));
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 7e09dcf..c7537b7 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -96,16 +96,16 @@
hdr = (struct ieee8023_hdr *) buf;
switch (ntohs(hdr->ethertype)) {
- case ETH_P_PAE:
- wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
- sa = hdr->src;
- os_memset(&event, 0, sizeof(event));
- event.new_sta.addr = sa;
- wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
+ case ETH_P_PAE:
+ wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
+ sa = hdr->src;
+ os_memset(&event, 0, sizeof(event));
+ event.new_sta.addr = sa;
+ wpa_supplicant_event(ctx, EVENT_NEW_STA, &event);
- pos = (u8 *) (hdr + 1);
- left = len - sizeof(*hdr);
- drv_event_eapol_rx(ctx, sa, pos, left);
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+ drv_event_eapol_rx(ctx, sa, pos, left);
break;
default:
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 1496b47..442c59c 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -22,6 +22,7 @@
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
DRV_OBJS += ../src/drivers/driver_macsec_linux.o
NEED_DRV_WIRED_COMMON=1
+NEED_LIBNL=y
CONFIG_LIBNL3_ROUTE=y
endif
@@ -51,37 +52,7 @@
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
NEED_RADIOTAP=y
-
-ifdef CONFIG_LIBNL32
- DRV_LIBS += -lnl-3
- DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
- ifdef LIBNL_INC
- DRV_CFLAGS += -I$(LIBNL_INC)
- else
- PKG_CONFIG ?= pkg-config
- DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0)
- endif
-ifdef CONFIG_LIBNL3_ROUTE
- DRV_LIBS += -lnl-route-3
- DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
-endif
-else
- ifdef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-tiny
- else
- ifndef CONFIG_OSX
- DRV_LIBS += -lnl
- endif
- endif
-
- ifdef CONFIG_LIBNL20
- ifndef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-genl
- endif
- DRV_CFLAGS += -DCONFIG_LIBNL20
- endif
-endif
+NEED_LIBNL=y
endif
ifdef CONFIG_DRIVER_BSD
@@ -183,26 +154,55 @@
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+endif
+
+ifdef NEED_LIBNL
+ifndef CONFIG_LIBNL32
+ifndef CONFIG_LIBNL20
+ifndef CONFIG_LIBNL_TINY
+PKG_CONFIG ?= pkg-config
+HAVE_LIBNL3 := $(shell $(PKG_CONFIG) --exists libnl-3.0; echo $$?)
+ifeq ($(HAVE_LIBNL3),0)
+CONFIG_LIBNL32=y
+endif
+endif
+endif
+endif
+
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_LIBS += -lnl-route-3
DRV_CFLAGS += -DCONFIG_LIBNL20
+ ifdef LIBNL_INC
+ DRV_CFLAGS += -I$(LIBNL_INC)
+ else
+ PKG_CONFIG ?= pkg-config
+ DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0)
+ endif
+ ifdef CONFIG_LIBNL3_ROUTE
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+ endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
else
- DRV_LIBS += -lnl
+ ifndef CONFIG_OSX
+ DRV_LIBS += -lnl
+ endif
endif
ifdef CONFIG_LIBNL20
- DRV_LIBS += -lnl-genl
- DRV_LIBS += -lnl-route
+ ifndef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-genl
+ endif
DRV_CFLAGS += -DCONFIG_LIBNL20
endif
endif
endif
-endif
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index cd25133..599a0b5 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -23,6 +23,7 @@
DRV_OBJS += src/drivers/driver_macsec_linux.c
NEED_DRV_WIRED_COMMON=1
CONFIG_LIBNL3_ROUTE=y
+NEED_LIBNL=y
endif
ifdef NEED_DRV_WIRED_COMMON
@@ -46,29 +47,7 @@
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
NEED_RADIOTAP=y
-
-ifdef CONFIG_LIBNL32
- DRV_LIBS += -lnl-3
- DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
-ifdef CONFIG_LIBNL3_ROUTE
- DRV_LIBS += -lnl-route-3
- DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
-endif
-else
- ifdef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-tiny
- else
- DRV_LIBS += -lnl
- endif
-
- ifdef CONFIG_LIBNL20
- ifndef CONFIG_LIBNL_TINY
- DRV_LIBS += -lnl-genl
- endif
- DRV_CFLAGS += -DCONFIG_LIBNL20
- endif
-endif
+NEED_LIBNL=y
endif
ifdef CONFIG_DRIVER_BSD
@@ -171,11 +150,20 @@
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+endif
+
+ifdef NEED_LIBNL
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
+ifdef CONFIG_LIBNL3_ROUTE
DRV_LIBS += -lnl-route-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
+ DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE
+endif
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
@@ -184,13 +172,13 @@
endif
ifdef CONFIG_LIBNL20
- DRV_LIBS += -lnl-genl
- DRV_LIBS += -lnl-route
+ ifndef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-genl
+ endif
DRV_CFLAGS += -DCONFIG_LIBNL20
endif
endif
endif
-endif
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index e21147a..7edb9df 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -12,6 +12,7 @@
#include <net/if_arp.h>
#include "utils/common.h"
+#include "common/linux_bridge.h"
#include "linux_ioctl.h"
@@ -119,25 +120,14 @@
}
-#ifndef SIOCBRADDBR
-#define SIOCBRADDBR 0x89a0
-#endif
-#ifndef SIOCBRDELBR
-#define SIOCBRDELBR 0x89a1
-#endif
-#ifndef SIOCBRADDIF
-#define SIOCBRADDIF 0x89a2
-#endif
-#ifndef SIOCBRDELIF
-#define SIOCBRDELIF 0x89a3
-#endif
-
-
int linux_br_add(int sock, const char *brname)
{
if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
+ int saved_errno = errno;
+
wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
brname, strerror(errno));
+ errno = saved_errno;
return -1;
}
@@ -170,8 +160,11 @@
os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
ifr.ifr_ifindex = ifindex;
if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
+ int saved_errno = errno;
+
wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
"%s: %s", ifname, brname, strerror(errno));
+ errno = saved_errno;
return -1;
}
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 1766a12..31ae5c7 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1033,6 +1033,38 @@
* %NL80211_ATTR_CHANNEL_WIDTH,%NL80211_ATTR_NSS attributes with its
* address(specified in %NL80211_ATTR_MAC).
*
+ * @NL80211_CMD_GET_FTM_RESPONDER_STATS: Retrieve FTM responder statistics, in
+ * the %NL80211_ATTR_FTM_RESPONDER_STATS attribute.
+ *
+ * @NL80211_CMD_PEER_MEASUREMENT_START: start a (set of) peer measurement(s)
+ * with the given parameters, which are encapsulated in the nested
+ * %NL80211_ATTR_PEER_MEASUREMENTS attribute. Optionally, MAC address
+ * randomization may be enabled and configured by specifying the
+ * %NL80211_ATTR_MAC and %NL80211_ATTR_MAC_MASK attributes.
+ * If a timeout is requested, use the %NL80211_ATTR_TIMEOUT attribute.
+ * A u64 cookie for further %NL80211_ATTR_COOKIE use is is returned in
+ * the netlink extended ack message.
+ *
+ * To cancel a measurement, close the socket that requested it.
+ *
+ * Measurement results are reported to the socket that requested the
+ * measurement using @NL80211_CMD_PEER_MEASUREMENT_RESULT when they
+ * become available, so applications must ensure a large enough socket
+ * buffer size.
+ *
+ * Depending on driver support it may or may not be possible to start
+ * multiple concurrent measurements.
+ * @NL80211_CMD_PEER_MEASUREMENT_RESULT: This command number is used for the
+ * result notification from the driver to the requesting socket.
+ * @NL80211_CMD_PEER_MEASUREMENT_COMPLETE: Notification only, indicating that
+ * the measurement completed, using the measurement cookie
+ * (%NL80211_ATTR_COOKIE).
+ *
+ * @NL80211_CMD_NOTIFY_RADAR: Notify the kernel that a radar signal was
+ * detected and reported by a neighboring device on the channel
+ * indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes
+ * determining the width and type.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1245,6 +1277,14 @@
NL80211_CMD_CONTROL_PORT_FRAME,
+ NL80211_CMD_GET_FTM_RESPONDER_STATS,
+
+ NL80211_CMD_PEER_MEASUREMENT_START,
+ NL80211_CMD_PEER_MEASUREMENT_RESULT,
+ NL80211_CMD_PEER_MEASUREMENT_COMPLETE,
+
+ NL80211_CMD_NOTIFY_RADAR,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1701,7 +1741,7 @@
* the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
* is included in the probe request, but the match attributes
* will never let it go through), -EINVAL may be returned.
- * If ommited, no filtering is done.
+ * If omitted, no filtering is done.
*
* @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
* interface combinations. In each nested item, it contains attributes
@@ -1806,7 +1846,7 @@
*
* @NL80211_ATTR_INACTIVITY_TIMEOUT: timeout value in seconds, this can be
* used by the drivers which has MLME in firmware and does not have support
- * to report per station tx/rx activity to free up the staion entry from
+ * to report per station tx/rx activity to free up the station entry from
* the list. This needs to be used when the driver advertises the
* capability to timeout the stations.
*
@@ -2167,7 +2207,7 @@
*
* @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in
* the specified band is to be adjusted before doing
- * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out
+ * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparison to figure out
* better BSSs. The attribute value is a packed structure
* value as specified by &struct nl80211_bss_select_rssi_adjust.
*
@@ -2241,6 +2281,24 @@
* association request when used with NL80211_CMD_NEW_STATION). Can be set
* only if %NL80211_STA_FLAG_WME is set.
*
+ * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include
+ * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing
+ * measurement (FTM) responder functionality and containing parameters as
+ * possible, see &enum nl80211_ftm_responder_attr
+ *
+ * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder
+ * statistics, see &enum nl80211_ftm_responder_stats.
+ *
+ * @NL80211_ATTR_TIMEOUT: Timeout for the given operation in milliseconds (u32),
+ * if the attribute is not given no timeout is requested. Note that 0 is an
+ * invalid value.
+ *
+ * @NL80211_ATTR_PEER_MEASUREMENTS: peer measurements request (and result)
+ * data, uses nested attributes specified in
+ * &enum nl80211_peer_measurement_attrs.
+ * This is also used for capability advertisement in the wiphy information,
+ * with the appropriate sub-attributes.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2682,6 +2740,14 @@
NL80211_ATTR_HE_CAPABILITY,
+ NL80211_ATTR_FTM_RESPONDER,
+
+ NL80211_ATTR_FTM_RESPONDER_STATS,
+
+ NL80211_ATTR_TIMEOUT,
+
+ NL80211_ATTR_PEER_MEASUREMENTS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3051,6 +3117,14 @@
* @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
* @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
* @NL80211_STA_INFO_ACK_SIGNAL_AVG: avg signal strength of ACK frames (s8, dBm)
+ * @NL80211_STA_INFO_RX_MPDUS: total number of received packets (MPDUs)
+ * (u32, from this station)
+ * @NL80211_STA_INFO_FCS_ERROR_COUNT: total number of packets (MPDUs) received
+ * with an FCS error (u32, from this station). This count may not include
+ * some packets with an FCS error due to TA corruption. Hence this counter
+ * might not be fully accurate.
+ * @NL80211_STA_INFO_CONNECTED_TO_GATE: set to true if STA has a path to a
+ * mesh gate (u8, 0 or 1)
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -3091,6 +3165,9 @@
NL80211_STA_INFO_PAD,
NL80211_STA_INFO_ACK_SIGNAL,
NL80211_STA_INFO_ACK_SIGNAL_AVG,
+ NL80211_STA_INFO_RX_MPDUS,
+ NL80211_STA_INFO_FCS_ERROR_COUNT,
+ NL80211_STA_INFO_CONNECTED_TO_GATE,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -3870,6 +3947,11 @@
* remove it from the STA's list of peers. You may set this to 0 to disable
* the removal of the STA. Default is 30 minutes.
*
+ * @NL80211_MESHCONF_CONNECTED_TO_GATE: If set to true then this mesh STA
+ * will advertise that it is connected to a gate in the mesh formation
+ * field. If left unset then the mesh formation field will only
+ * advertise such if there is an active root mesh path.
+ *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@@ -3902,6 +3984,7 @@
NL80211_MESHCONF_POWER_MODE,
NL80211_MESHCONF_AWAKE_WINDOW,
NL80211_MESHCONF_PLINK_TIMEOUT,
+ NL80211_MESHCONF_CONNECTED_TO_GATE,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -4834,7 +4917,7 @@
* numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
* => allows a STA plus three P2P interfaces
*
- * The list of these four possiblities could completely be contained
+ * The list of these four possibilities could completely be contained
* within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
* that any of these groups must match.
*
@@ -4864,7 +4947,7 @@
* enum nl80211_plink_state - state of a mesh peer link finite state machine
*
* @NL80211_PLINK_LISTEN: initial state, considered the implicit
- * state of non existant mesh peer links
+ * state of non existent mesh peer links
* @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
* this mesh peer
* @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
@@ -5225,6 +5308,13 @@
* @NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT: Driver/device can omit all data
* except for supported rates from the probe request content if requested
* by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
+ * @NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER: Driver supports enabling fine
+ * timing measurement responder role.
+ *
+ * @NL80211_EXT_FEATURE_CAN_REPLACE_PTK0: Driver/device confirm that they are
+ * able to rekey an in-use key correctly. Userspace must not rekey PTK keys
+ * if this flag is not set. Ignoring this can leak clear text packets and/or
+ * freeze the connection.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5263,6 +5353,8 @@
NL80211_EXT_FEATURE_TXQS,
NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -5347,7 +5439,7 @@
* request parameters IE in the probe request
* @NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe responses
* @NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE: send probe request frames at
- * rate of at least 5.5M. In case non OCE AP is dicovered in the channel,
+ * rate of at least 5.5M. In case non OCE AP is discovered in the channel,
* only the first probe req in the channel will be sent in high rate.
* @NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: allow probe request
* tx deferral (dot11FILSProbeDelay shall be set to 15ms)
@@ -5802,4 +5894,458 @@
NL80211_EXTERNAL_AUTH_ABORT,
};
+/**
+ * enum nl80211_ftm_responder_attributes - fine timing measurement
+ * responder attributes
+ * @__NL80211_FTM_RESP_ATTR_INVALID: Invalid
+ * @NL80211_FTM_RESP_ATTR_ENABLED: FTM responder is enabled
+ * @NL80211_FTM_RESP_ATTR_LCI: The content of Measurement Report Element
+ * (9.4.2.22 in 802.11-2016) with type 8 - LCI (9.4.2.22.10),
+ * i.e. starting with the measurement token
+ * @NL80211_FTM_RESP_ATTR_CIVIC: The content of Measurement Report Element
+ * (9.4.2.22 in 802.11-2016) with type 11 - Civic (Section 9.4.2.22.13),
+ * i.e. starting with the measurement token
+ * @__NL80211_FTM_RESP_ATTR_LAST: Internal
+ * @NL80211_FTM_RESP_ATTR_MAX: highest FTM responder attribute.
+ */
+enum nl80211_ftm_responder_attributes {
+ __NL80211_FTM_RESP_ATTR_INVALID,
+
+ NL80211_FTM_RESP_ATTR_ENABLED,
+ NL80211_FTM_RESP_ATTR_LCI,
+ NL80211_FTM_RESP_ATTR_CIVICLOC,
+
+ /* keep last */
+ __NL80211_FTM_RESP_ATTR_LAST,
+ NL80211_FTM_RESP_ATTR_MAX = __NL80211_FTM_RESP_ATTR_LAST - 1,
+};
+
+/*
+ * enum nl80211_ftm_responder_stats - FTM responder statistics
+ *
+ * These attribute types are used with %NL80211_ATTR_FTM_RESPONDER_STATS
+ * when getting FTM responder statistics.
+ *
+ * @__NL80211_FTM_STATS_INVALID: attribute number 0 is reserved
+ * @NL80211_FTM_STATS_SUCCESS_NUM: number of FTM sessions in which all frames
+ * were ssfully answered (u32)
+ * @NL80211_FTM_STATS_PARTIAL_NUM: number of FTM sessions in which part of the
+ * frames were successfully answered (u32)
+ * @NL80211_FTM_STATS_FAILED_NUM: number of failed FTM sessions (u32)
+ * @NL80211_FTM_STATS_ASAP_NUM: number of ASAP sessions (u32)
+ * @NL80211_FTM_STATS_NON_ASAP_NUM: number of non-ASAP sessions (u32)
+ * @NL80211_FTM_STATS_TOTAL_DURATION_MSEC: total sessions durations - gives an
+ * indication of how much time the responder was busy (u64, msec)
+ * @NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM: number of unknown FTM triggers -
+ * triggers from initiators that didn't finish successfully the negotiation
+ * phase with the responder (u32)
+ * @NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM: number of FTM reschedule requests
+ * - initiator asks for a new scheduling although it already has scheduled
+ * FTM slot (u32)
+ * @NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM: number of FTM triggers out of
+ * scheduled window (u32)
+ * @NL80211_FTM_STATS_PAD: used for padding, ignore
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_FTM_STATS_MAX: highest possible FTM responder stats attribute
+ */
+enum nl80211_ftm_responder_stats {
+ __NL80211_FTM_STATS_INVALID,
+ NL80211_FTM_STATS_SUCCESS_NUM,
+ NL80211_FTM_STATS_PARTIAL_NUM,
+ NL80211_FTM_STATS_FAILED_NUM,
+ NL80211_FTM_STATS_ASAP_NUM,
+ NL80211_FTM_STATS_NON_ASAP_NUM,
+ NL80211_FTM_STATS_TOTAL_DURATION_MSEC,
+ NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM,
+ NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM,
+ NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM,
+ NL80211_FTM_STATS_PAD,
+
+ /* keep last */
+ __NL80211_FTM_STATS_AFTER_LAST,
+ NL80211_FTM_STATS_MAX = __NL80211_FTM_STATS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_preamble - frame preamble types
+ * @NL80211_PREAMBLE_LEGACY: legacy (HR/DSSS, OFDM, ERP PHY) preamble
+ * @NL80211_PREAMBLE_HT: HT preamble
+ * @NL80211_PREAMBLE_VHT: VHT preamble
+ * @NL80211_PREAMBLE_DMG: DMG preamble
+ */
+enum nl80211_preamble {
+ NL80211_PREAMBLE_LEGACY,
+ NL80211_PREAMBLE_HT,
+ NL80211_PREAMBLE_VHT,
+ NL80211_PREAMBLE_DMG,
+};
+
+/**
+ * enum nl80211_peer_measurement_type - peer measurement types
+ * @NL80211_PMSR_TYPE_INVALID: invalid/unused, needed as we use
+ * these numbers also for attributes
+ *
+ * @NL80211_PMSR_TYPE_FTM: flight time measurement
+ *
+ * @NUM_NL80211_PMSR_TYPES: internal
+ * @NL80211_PMSR_TYPE_MAX: highest type number
+ */
+enum nl80211_peer_measurement_type {
+ NL80211_PMSR_TYPE_INVALID,
+
+ NL80211_PMSR_TYPE_FTM,
+
+ NUM_NL80211_PMSR_TYPES,
+ NL80211_PMSR_TYPE_MAX = NUM_NL80211_PMSR_TYPES - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_status - peer measurement status
+ * @NL80211_PMSR_STATUS_SUCCESS: measurement completed successfully
+ * @NL80211_PMSR_STATUS_REFUSED: measurement was locally refused
+ * @NL80211_PMSR_STATUS_TIMEOUT: measurement timed out
+ * @NL80211_PMSR_STATUS_FAILURE: measurement failed, a type-dependent
+ * reason may be available in the response data
+ */
+enum nl80211_peer_measurement_status {
+ NL80211_PMSR_STATUS_SUCCESS,
+ NL80211_PMSR_STATUS_REFUSED,
+ NL80211_PMSR_STATUS_TIMEOUT,
+ NL80211_PMSR_STATUS_FAILURE,
+};
+
+/**
+ * enum nl80211_peer_measurement_req - peer measurement request attributes
+ * @__NL80211_PMSR_REQ_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_REQ_ATTR_DATA: This is a nested attribute with measurement
+ * type-specific request data inside. The attributes used are from the
+ * enums named nl80211_peer_measurement_<type>_req.
+ * @NL80211_PMSR_REQ_ATTR_GET_AP_TSF: include AP TSF timestamp, if supported
+ * (flag attribute)
+ *
+ * @NUM_NL80211_PMSR_REQ_ATTRS: internal
+ * @NL80211_PMSR_REQ_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_req {
+ __NL80211_PMSR_REQ_ATTR_INVALID,
+
+ NL80211_PMSR_REQ_ATTR_DATA,
+ NL80211_PMSR_REQ_ATTR_GET_AP_TSF,
+
+ /* keep last */
+ NUM_NL80211_PMSR_REQ_ATTRS,
+ NL80211_PMSR_REQ_ATTR_MAX = NUM_NL80211_PMSR_REQ_ATTRS - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_resp - peer measurement response attributes
+ * @__NL80211_PMSR_RESP_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_RESP_ATTR_DATA: This is a nested attribute with measurement
+ * type-specific results inside. The attributes used are from the enums
+ * named nl80211_peer_measurement_<type>_resp.
+ * @NL80211_PMSR_RESP_ATTR_STATUS: u32 value with the measurement status
+ * (using values from &enum nl80211_peer_measurement_status.)
+ * @NL80211_PMSR_RESP_ATTR_HOST_TIME: host time (%CLOCK_BOOTTIME) when the
+ * result was measured; this value is not expected to be accurate to
+ * more than 20ms. (u64, nanoseconds)
+ * @NL80211_PMSR_RESP_ATTR_AP_TSF: TSF of the AP that the interface
+ * doing the measurement is connected to when the result was measured.
+ * This shall be accurately reported if supported and requested
+ * (u64, usec)
+ * @NL80211_PMSR_RESP_ATTR_FINAL: If results are sent to the host partially
+ * (*e.g. with FTM per-burst data) this flag will be cleared on all but
+ * the last result; if all results are combined it's set on the single
+ * result.
+ * @NL80211_PMSR_RESP_ATTR_PAD: padding for 64-bit attributes, ignore
+ *
+ * @NUM_NL80211_PMSR_RESP_ATTRS: internal
+ * @NL80211_PMSR_RESP_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_resp {
+ __NL80211_PMSR_RESP_ATTR_INVALID,
+
+ NL80211_PMSR_RESP_ATTR_DATA,
+ NL80211_PMSR_RESP_ATTR_STATUS,
+ NL80211_PMSR_RESP_ATTR_HOST_TIME,
+ NL80211_PMSR_RESP_ATTR_AP_TSF,
+ NL80211_PMSR_RESP_ATTR_FINAL,
+ NL80211_PMSR_RESP_ATTR_PAD,
+
+ /* keep last */
+ NUM_NL80211_PMSR_RESP_ATTRS,
+ NL80211_PMSR_RESP_ATTR_MAX = NUM_NL80211_PMSR_RESP_ATTRS - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_peer_attrs - peer attributes for measurement
+ * @__NL80211_PMSR_PEER_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_PEER_ATTR_ADDR: peer's MAC address
+ * @NL80211_PMSR_PEER_ATTR_CHAN: channel definition, nested, using top-level
+ * attributes like %NL80211_ATTR_WIPHY_FREQ etc.
+ * @NL80211_PMSR_PEER_ATTR_REQ: This is a nested attribute indexed by
+ * measurement type, with attributes from the
+ * &enum nl80211_peer_measurement_req inside.
+ * @NL80211_PMSR_PEER_ATTR_RESP: This is a nested attribute indexed by
+ * measurement type, with attributes from the
+ * &enum nl80211_peer_measurement_resp inside.
+ *
+ * @NUM_NL80211_PMSR_PEER_ATTRS: internal
+ * @NL80211_PMSR_PEER_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_peer_attrs {
+ __NL80211_PMSR_PEER_ATTR_INVALID,
+
+ NL80211_PMSR_PEER_ATTR_ADDR,
+ NL80211_PMSR_PEER_ATTR_CHAN,
+ NL80211_PMSR_PEER_ATTR_REQ,
+ NL80211_PMSR_PEER_ATTR_RESP,
+
+ /* keep last */
+ NUM_NL80211_PMSR_PEER_ATTRS,
+ NL80211_PMSR_PEER_ATTR_MAX = NUM_NL80211_PMSR_PEER_ATTRS - 1,
+};
+
+/**
+ * enum nl80211_peer_measurement_attrs - peer measurement attributes
+ * @__NL80211_PMSR_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_ATTR_MAX_PEERS: u32 attribute used for capability
+ * advertisement only, indicates the maximum number of peers
+ * measurements can be done with in a single request
+ * @NL80211_PMSR_ATTR_REPORT_AP_TSF: flag attribute in capability
+ * indicating that the connected AP's TSF can be reported in
+ * measurement results
+ * @NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR: flag attribute in capability
+ * indicating that MAC address randomization is supported.
+ * @NL80211_PMSR_ATTR_TYPE_CAPA: capabilities reported by the device,
+ * this contains a nesting indexed by measurement type, and
+ * type-specific capabilities inside, which are from the enums
+ * named nl80211_peer_measurement_<type>_capa.
+ * @NL80211_PMSR_ATTR_PEERS: nested attribute, the nesting index is
+ * meaningless, just a list of peers to measure with, with the
+ * sub-attributes taken from
+ * &enum nl80211_peer_measurement_peer_attrs.
+ *
+ * @NUM_NL80211_PMSR_ATTR: internal
+ * @NL80211_PMSR_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_attrs {
+ __NL80211_PMSR_ATTR_INVALID,
+
+ NL80211_PMSR_ATTR_MAX_PEERS,
+ NL80211_PMSR_ATTR_REPORT_AP_TSF,
+ NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR,
+ NL80211_PMSR_ATTR_TYPE_CAPA,
+ NL80211_PMSR_ATTR_PEERS,
+
+ /* keep last */
+ NUM_NL80211_PMSR_ATTR,
+ NL80211_PMSR_ATTR_MAX = NUM_NL80211_PMSR_ATTR - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_capa - FTM capabilities
+ * @__NL80211_PMSR_FTM_CAPA_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_FTM_CAPA_ATTR_ASAP: flag attribute indicating ASAP mode
+ * is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP: flag attribute indicating non-ASAP
+ * mode is supported
+ * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI: flag attribute indicating if LCI
+ * data can be requested during the measurement
+ * @NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC: flag attribute indicating if civic
+ * location data can be requested during the measurement
+ * @NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES: u32 bitmap attribute of bits
+ * from &enum nl80211_preamble.
+ * @NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS: bitmap of values from
+ * &enum nl80211_chan_width indicating the supported channel
+ * bandwidths for FTM. Note that a higher channel bandwidth may be
+ * configured to allow for other measurements types with different
+ * bandwidth requirement in the same measurement.
+ * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT: u32 attribute indicating
+ * the maximum bursts exponent that can be used (if not present anything
+ * is valid)
+ * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating
+ * the maximum FTMs per burst (if not present anything is valid)
+ *
+ * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal
+ * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_ftm_capa {
+ __NL80211_PMSR_FTM_CAPA_ATTR_INVALID,
+
+ NL80211_PMSR_FTM_CAPA_ATTR_ASAP,
+ NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP,
+ NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI,
+ NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC,
+ NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
+ NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
+ NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
+ NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+
+ /* keep last */
+ NUM_NL80211_PMSR_FTM_CAPA_ATTR,
+ NL80211_PMSR_FTM_CAPA_ATTR_MAX = NUM_NL80211_PMSR_FTM_CAPA_ATTR - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_req - FTM request attributes
+ * @__NL80211_PMSR_FTM_REQ_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_FTM_REQ_ATTR_ASAP: ASAP mode requested (flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE: preamble type (see
+ * &enum nl80211_preamble), optional for DMG (u32)
+ * @NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP: number of bursts exponent as in
+ * 802.11-2016 9.4.2.168 "Fine Timing Measurement Parameters element"
+ * (u8, 0-15, optional with default 15 i.e. "no preference")
+ * @NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD: interval between bursts in units
+ * of 100ms (u16, optional with default 0)
+ * @NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION: burst duration, as in 802.11-2016
+ * Table 9-257 "Burst Duration field encoding" (u8, 0-15, optional with
+ * default 15 i.e. "no preference")
+ * @NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST: number of successful FTM frames
+ * requested per burst
+ * (u8, 0-31, optional with default 0 i.e. "no preference")
+ * @NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES: number of FTMR frame retries
+ * (u8, default 3)
+ * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag)
+ * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data
+ * (flag)
+ *
+ * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
+ * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_ftm_req {
+ __NL80211_PMSR_FTM_REQ_ATTR_INVALID,
+
+ NL80211_PMSR_FTM_REQ_ATTR_ASAP,
+ NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE,
+ NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP,
+ NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD,
+ NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION,
+ NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST,
+ NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES,
+ NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI,
+ NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
+
+ /* keep last */
+ NUM_NL80211_PMSR_FTM_REQ_ATTR,
+ NL80211_PMSR_FTM_REQ_ATTR_MAX = NUM_NL80211_PMSR_FTM_REQ_ATTR - 1
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_failure_reasons - FTM failure reasons
+ * @NL80211_PMSR_FTM_FAILURE_UNSPECIFIED: unspecified failure, not used
+ * @NL80211_PMSR_FTM_FAILURE_NO_RESPONSE: no response from the FTM responder
+ * @NL80211_PMSR_FTM_FAILURE_REJECTED: FTM responder rejected measurement
+ * @NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL: we already know the peer is
+ * on a different channel, so can't measure (if we didn't know, we'd
+ * try and get no response)
+ * @NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE: peer can't actually do FTM
+ * @NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP: invalid T1/T4 timestamps
+ * received
+ * @NL80211_PMSR_FTM_FAILURE_PEER_BUSY: peer reports busy, you may retry
+ * later (see %NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME)
+ * @NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS: parameters were changed
+ * by the peer and are no longer supported
+ */
+enum nl80211_peer_measurement_ftm_failure_reasons {
+ NL80211_PMSR_FTM_FAILURE_UNSPECIFIED,
+ NL80211_PMSR_FTM_FAILURE_NO_RESPONSE,
+ NL80211_PMSR_FTM_FAILURE_REJECTED,
+ NL80211_PMSR_FTM_FAILURE_WRONG_CHANNEL,
+ NL80211_PMSR_FTM_FAILURE_PEER_NOT_CAPABLE,
+ NL80211_PMSR_FTM_FAILURE_INVALID_TIMESTAMP,
+ NL80211_PMSR_FTM_FAILURE_PEER_BUSY,
+ NL80211_PMSR_FTM_FAILURE_BAD_CHANGED_PARAMS,
+};
+
+/**
+ * enum nl80211_peer_measurement_ftm_resp - FTM response attributes
+ * @__NL80211_PMSR_FTM_RESP_ATTR_INVALID: invalid
+ *
+ * @NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON: FTM-specific failure reason
+ * (u32, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX: optional, if bursts are reported
+ * as separate results then it will be the burst index 0...(N-1) and
+ * the top level will indicate partial results (u32)
+ * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS: number of FTM Request frames
+ * transmitted (u32, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES: number of FTM Request frames
+ * that were acknowleged (u32, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME: retry time received from the
+ * busy peer (u32, seconds)
+ * @NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP: actual number of bursts exponent
+ * used by the responder (similar to request, u8)
+ * @NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION: actual burst duration used by
+ * the responder (similar to request, u8)
+ * @NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST: actual FTMs per burst used
+ * by the responder (similar to request, u8)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG: average RSSI across all FTM action
+ * frames (optional, s32, 1/2 dBm)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD: RSSI spread across all FTM action
+ * frames (optional, s32, 1/2 dBm)
+ * @NL80211_PMSR_FTM_RESP_ATTR_TX_RATE: bitrate we used for the response to the
+ * FTM action frame (optional, nested, using &enum nl80211_rate_info
+ * attributes)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RX_RATE: bitrate the responder used for the FTM
+ * action frame (optional, nested, using &enum nl80211_rate_info attrs)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG: average RTT (s64, picoseconds, optional
+ * but one of RTT/DIST must be present)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE: RTT variance (u64, ps^2, note that
+ * standard deviation is the square root of variance, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD: RTT spread (u64, picoseconds,
+ * optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG: average distance (s64, mm, optional
+ * but one of RTT/DIST must be present)
+ * @NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE: distance variance (u64, mm^2, note
+ * that standard deviation is the square root of variance, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD: distance spread (u64, mm, optional)
+ * @NL80211_PMSR_FTM_RESP_ATTR_LCI: LCI data from peer (binary, optional);
+ * this is the contents of the Measurement Report Element (802.11-2016
+ * 9.4.2.22.1) starting with the Measurement Token, with Measurement
+ * Type 8.
+ * @NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC: civic location data from peer
+ * (binary, optional);
+ * this is the contents of the Measurement Report Element (802.11-2016
+ * 9.4.2.22.1) starting with the Measurement Token, with Measurement
+ * Type 11.
+ * @NL80211_PMSR_FTM_RESP_ATTR_PAD: ignore, for u64/s64 padding only
+ *
+ * @NUM_NL80211_PMSR_FTM_RESP_ATTR: internal
+ * @NL80211_PMSR_FTM_RESP_ATTR_MAX: highest attribute number
+ */
+enum nl80211_peer_measurement_ftm_resp {
+ __NL80211_PMSR_FTM_RESP_ATTR_INVALID,
+
+ NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON,
+ NL80211_PMSR_FTM_RESP_ATTR_BURST_INDEX,
+ NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS,
+ NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES,
+ NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME,
+ NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP,
+ NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION,
+ NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST,
+ NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG,
+ NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD,
+ NL80211_PMSR_FTM_RESP_ATTR_TX_RATE,
+ NL80211_PMSR_FTM_RESP_ATTR_RX_RATE,
+ NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG,
+ NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE,
+ NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD,
+ NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG,
+ NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE,
+ NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD,
+ NL80211_PMSR_FTM_RESP_ATTR_LCI,
+ NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC,
+ NL80211_PMSR_FTM_RESP_ATTR_PAD,
+
+ /* keep last */
+ NUM_NL80211_PMSR_FTM_RESP_ATTR,
+ NL80211_PMSR_FTM_RESP_ATTR_MAX = NUM_NL80211_PMSR_FTM_RESP_ATTR - 1
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 74cec7d..94ce57d 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -250,8 +250,8 @@
os_memset(data->key_data, 0, EAP_FAST_KEY_LEN);
os_memset(data->emsk, 0, EAP_EMSK_LEN);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
os_free(data);
}
@@ -486,7 +486,7 @@
(config->pending_req_identity || config->pending_req_password ||
config->pending_req_otp || config->pending_req_new_password ||
config->pending_req_sim)) {
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
} else if (*resp == NULL)
return -1;
@@ -801,7 +801,7 @@
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
data->phase2_success = 0;
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
@@ -815,7 +815,7 @@
} else {
wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
"Session-Id");
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
}
@@ -1150,7 +1150,7 @@
wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
"frame");
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return 0;
}
@@ -1328,14 +1328,14 @@
wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
"TLV frame (len=%lu)",
(unsigned long) wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return -1;
}
res = eap_fast_process_decrypted(sm, data, ret, identifier,
in_decrypted, out_data);
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return res;
}
@@ -1613,7 +1613,7 @@
if (sm->waiting_ext_cert_check) {
wpa_printf(MSG_DEBUG,
"EAP-FAST: Waiting external server certificate validation");
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = resp;
return NULL;
}
@@ -1641,7 +1641,7 @@
"EAP-FAST: Could not derive keys");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return NULL;
}
}
@@ -1650,7 +1650,7 @@
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = resp;
resp = NULL;
res = eap_fast_decrypt(sm, data, ret, id, &msg, &resp);
@@ -1658,7 +1658,7 @@
}
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_FAST,
data->fast_version);
}
@@ -1684,9 +1684,9 @@
data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
os_free(data->key_block_p);
data->key_block_p = NULL;
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = NULL;
}
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 34075b1..650bea6 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -169,7 +169,7 @@
static void eap_peap_free_key(struct eap_peap_data *data)
{
if (data->key_data) {
- bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
data->key_data = NULL;
}
}
@@ -186,9 +186,9 @@
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_peap_free_key(data);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
- wpabuf_free(data->pending_resp);
- os_free(data);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
+ bin_clear_free(data, sizeof(*data));
}
@@ -253,7 +253,7 @@
{
u8 *tk;
u8 isk[32], imck[60];
- int resumed;
+ int resumed, res;
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
@@ -292,9 +292,11 @@
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- if (peap_prfplus(data->peap_version, tk, 40,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck)) < 0)
+ res = peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ os_memset(isk, 0, sizeof(isk));
+ if (res < 0)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
imck, sizeof(imck));
@@ -303,6 +305,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
os_memcpy(data->cmk, imck + 40, 20);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+ os_memset(imck, 0, sizeof(imck));
return 0;
}
@@ -382,7 +385,7 @@
wpabuf_put_be16(msg, status); /* Status */
if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
return NULL;
}
@@ -651,11 +654,11 @@
if (*resp == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(buf);
+ wpabuf_clear_free(buf);
return -1;
}
wpabuf_put_buf(*resp, buf);
- wpabuf_free(buf);
+ wpabuf_clear_free(buf);
break;
}
}
@@ -728,7 +731,7 @@
(config->pending_req_identity || config->pending_req_password ||
config->pending_req_otp || config->pending_req_new_password ||
config->pending_req_sim)) {
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
}
@@ -807,7 +810,7 @@
struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
wpabuf_len(in_decrypted));
if (nmsg == NULL) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
@@ -817,7 +820,7 @@
nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
in_decrypted = nmsg;
}
@@ -826,7 +829,7 @@
wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
"EAP frame (len=%lu)",
(unsigned long) wpabuf_len(in_decrypted));
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
len = be_to_host16(hdr->length);
@@ -835,7 +838,7 @@
"Phase 2 EAP frame (len=%lu hdr->length=%lu)",
(unsigned long) wpabuf_len(in_decrypted),
(unsigned long) len);
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
if (len < wpabuf_len(in_decrypted)) {
@@ -852,7 +855,7 @@
case EAP_CODE_REQUEST:
if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
&resp)) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
"processing failed");
return 0;
@@ -872,7 +875,7 @@
"completed successfully");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return 0;
}
wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
@@ -882,7 +885,7 @@
ret->methodState = METHOD_DONE;
data->phase2_success = 1;
if (data->peap_outer_success == 2) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
"to finish authentication");
return 1;
@@ -928,7 +931,7 @@
break;
}
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
if (resp) {
int skip_change2 = 0;
@@ -955,7 +958,7 @@
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
"a Phase 2 frame");
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
}
return 0;
@@ -1056,7 +1059,7 @@
if (sm->waiting_ext_cert_check) {
wpa_printf(MSG_DEBUG,
"EAP-PEAP: Waiting external server certificate validation");
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = resp;
return NULL;
}
@@ -1081,12 +1084,18 @@
"key derivation", label);
data->key_data =
eap_peer_tls_derive_key(sm, &data->ssl, label,
- EAP_TLS_KEY_LEN);
+ EAP_TLS_KEY_LEN +
+ EAP_EMSK_LEN);
if (data->key_data) {
wpa_hexdump_key(MSG_DEBUG,
"EAP-PEAP: Derived key",
data->key_data,
EAP_TLS_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-PEAP: Derived EMSK",
+ data->key_data +
+ EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
} else {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
"derive key");
@@ -1131,7 +1140,7 @@
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = resp;
resp = NULL;
res = eap_peap_decrypt(sm, data, ret, req, &msg,
@@ -1144,7 +1153,7 @@
}
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
data->peap_version);
}
@@ -1168,9 +1177,9 @@
if (data->phase2_priv && data->phase2_method &&
data->phase2_method->deinit_for_reauth)
data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = NULL;
data->crypto_binding_used = 0;
}
@@ -1257,6 +1266,7 @@
os_memcpy(key, csk, EAP_TLS_KEY_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
key, EAP_TLS_KEY_LEN);
+ os_memset(csk, 0, sizeof(csk));
} else
os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
@@ -1264,6 +1274,29 @@
}
+static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *key;
+
+ if (!data->key_data || !data->phase2_success)
+ return NULL;
+
+ if (data->crypto_binding_used) {
+ /* [MS-PEAP] does not define EMSK derivation */
+ return NULL;
+ }
+
+ key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+ if (!key)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
@@ -1296,6 +1329,7 @@
eap->process = eap_peap_process;
eap->isKeyAvailable = eap_peap_isKeyAvailable;
eap->getKey = eap_peap_getKey;
+ eap->get_emsk = eap_peap_get_emsk;
eap->get_status = eap_peap_get_status;
eap->has_reauth_data = eap_peap_has_reauth_data;
eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 0de1315..7dbd364 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -1,6 +1,6 @@
/*
* EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -70,16 +70,22 @@
params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
if (os_strstr(txt, "tls_disable_tlsv1_0=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_0;
- if (os_strstr(txt, "tls_disable_tlsv1_0=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_0=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_0;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_0;
+ }
if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_1;
- if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_1=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_1;
+ }
if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_2;
- if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
+ if (os_strstr(txt, "tls_disable_tlsv1_2=0")) {
params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+ params->flags |= TLS_CONN_ENABLE_TLSv1_2;
+ }
if (os_strstr(txt, "tls_disable_tlsv1_3=1"))
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
if (os_strstr(txt, "tls_disable_tlsv1_3=0"))
@@ -170,7 +176,9 @@
* TLS v1.3 changes, so disable this by default for now. */
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
- if (data->eap_type == EAP_TYPE_TLS) {
+ if (data->eap_type == EAP_TYPE_TLS ||
+ data->eap_type == EAP_UNAUTH_TLS_TYPE ||
+ data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) {
/* While the current EAP-TLS implementation is more or less
* complete for TLS v1.3, there has been no interoperability
* testing with other implementations, so disable for by default
@@ -388,10 +396,26 @@
u8 *out;
if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
- *len = 64;
- return eap_peer_tls_derive_key(sm, data,
- "EXPORTER_EAP_TLS_Session-Id",
- 64);
+ u8 *id, *method_id;
+
+ /* Session-Id = <EAP-Type> || Method-Id
+ * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
+ * "", 64)
+ */
+ *len = 1 + 64;
+ id = os_malloc(*len);
+ if (!id)
+ return NULL;
+ method_id = eap_peer_tls_derive_key(
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", 64);
+ if (!method_id) {
+ os_free(id);
+ return NULL;
+ }
+ id[0] = eap_type;
+ os_memcpy(id + 1, method_id, 64);
+ os_free(method_id);
+ return id;
}
if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys) ||
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index f18788c..5d26701 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -196,8 +196,8 @@
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_ttls_free_key(data);
os_free(data->session_id);
- wpabuf_free(data->pending_phase2_req);
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_resp);
os_free(data);
}
@@ -248,7 +248,7 @@
msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
if (msg == NULL) {
- wpabuf_free(*resp);
+ wpabuf_clear_free(*resp);
*resp = NULL;
return -1;
}
@@ -258,7 +258,7 @@
os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
pos += wpabuf_len(*resp);
AVP_PAD(avp, pos);
- wpabuf_free(*resp);
+ wpabuf_clear_free(*resp);
wpabuf_put(msg, pos - avp);
*resp = msg;
return 0;
@@ -510,7 +510,7 @@
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"implicit challenge");
return -1;
@@ -529,7 +529,7 @@
*pos++ = 0; /* Flags */
if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
os_free(challenge);
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
"random data for peer challenge");
return -1;
@@ -543,7 +543,7 @@
peer_challenge, pos, data->auth_response,
data->master_key)) {
os_free(challenge);
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"response");
return -1;
@@ -604,7 +604,7 @@
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -628,7 +628,7 @@
if (challenge_response(challenge, password, pos)) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAP: Failed derive password hash");
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
os_free(challenge);
return -1;
}
@@ -641,7 +641,7 @@
pos)) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAP: Failed derive password");
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
os_free(challenge);
return -1;
}
@@ -760,7 +760,7 @@
challenge = eap_ttls_implicit_challenge(
sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
- wpabuf_free(msg);
+ wpabuf_clear_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -1073,10 +1073,10 @@
resp, out_data)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
"frame");
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return -1;
}
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return 0;
}
@@ -1297,7 +1297,7 @@
config->pending_req_otp ||
config->pending_req_new_password ||
config->pending_req_sim) {
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_dup(in_decrypted);
}
@@ -1340,7 +1340,7 @@
* processing when EAP request is re-processed after
* user input.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc(0);
}
@@ -1413,7 +1413,7 @@
in_decrypted = data->pending_phase2_req;
data->pending_phase2_req = NULL;
if (wpabuf_len(in_decrypted) == 0) {
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
return eap_ttls_implicit_identity_request(
sm, data, ret, identifier, out_data);
}
@@ -1449,7 +1449,7 @@
&parse, in_decrypted, out_data);
done:
- wpabuf_free(in_decrypted);
+ wpabuf_clear_free(in_decrypted);
os_free(parse.eapdata);
if (retval < 0) {
@@ -1509,7 +1509,7 @@
if (sm->waiting_ext_cert_check) {
wpa_printf(MSG_DEBUG,
"EAP-TTLS: Waiting external server certificate validation");
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = *out_data;
*out_data = NULL;
return 0;
@@ -1543,7 +1543,7 @@
/*
* Application data included in the handshake message.
*/
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = *out_data;
*out_data = NULL;
res = eap_ttls_decrypt(sm, data, ret, identifier, in_data,
@@ -1646,7 +1646,7 @@
/* FIX: what about res == -1? Could just move all error processing into
* the other functions and get rid of this res==1 case here. */
if (res == 1) {
- wpabuf_free(resp);
+ wpabuf_clear_free(resp);
return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
data->ttls_version);
}
@@ -1669,9 +1669,9 @@
if (data->phase2_priv && data->phase2_method &&
data->phase2_method->deinit_for_reauth)
data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
- wpabuf_free(data->pending_phase2_req);
+ wpabuf_clear_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
- wpabuf_free(data->pending_resp);
+ wpabuf_clear_free(data->pending_resp);
data->pending_resp = NULL;
data->decision_succ = DECISION_FAIL;
#ifdef EAP_TNC
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 4fbc661..45e1212 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -153,6 +153,8 @@
int eap_sm_method_pending(struct eap_sm *sm);
const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
const char * eap_get_serial_num(struct eap_sm *sm);
+const char * eap_get_method(struct eap_sm *sm);
+const char * eap_get_imsi(struct eap_sm *sm);
struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
void eap_server_clear_identity(struct eap_sm *sm);
void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index cf8a9f0..1cade10 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -160,6 +160,7 @@
u8 *identity;
size_t identity_len;
char *serial_num;
+ char imsi[20];
/* Whether Phase 2 method should validate identity match */
int require_identity_match;
int lastId; /* Identifier used in the last EAP-Packet */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 38a1b5c..b33f632 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -2003,6 +2003,32 @@
}
+/**
+ * eap_get_method - Get the used EAP method
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to the method name or %NULL if not available
+ */
+const char * eap_get_method(struct eap_sm *sm)
+{
+ if (!sm || !sm->m)
+ return NULL;
+ return sm->m->name;
+}
+
+
+/**
+ * eap_get_imsi - Get IMSI of the user
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * Returns: Pointer to IMSI or %NULL if not available
+ */
+const char * eap_get_imsi(struct eap_sm *sm)
+{
+ if (!sm || sm->imsi[0] == '\0')
+ return NULL;
+ return sm->imsi;
+}
+
+
void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len)
{
#ifdef CONFIG_ERP
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 1750211..1bea706 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -796,6 +796,10 @@
return;
}
+ if (data->permanent[0] == EAP_AKA_PERMANENT_PREFIX ||
+ data->permanent[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)
+ os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
+
#ifdef EAP_SERVER_AKA_PRIME
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 18d31b5..3d334a0 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -324,6 +324,7 @@
{
u8 *tk;
u8 isk[32], imck[60];
+ int res;
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
@@ -358,9 +359,11 @@
* in the end of the label just before ISK; is that just a typo?)
*/
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
- if (peap_prfplus(data->peap_version, tk, 40,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+ res = peap_prfplus(data->peap_version, tk, 40,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ os_memset(isk, 0, sizeof(isk));
+ if (res < 0) {
os_free(tk);
return -1;
}
@@ -373,6 +376,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
os_memcpy(data->cmk, imck + 40, 20);
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+ os_memset(imck, 0, sizeof(imck));
return 0;
}
@@ -756,7 +760,7 @@
} else {
eap_peap_state(data, FAILURE);
}
-
+
} else if (status == EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
"- requested %s", requested);
@@ -1322,14 +1326,17 @@
"key");
}
+ os_memset(csk, 0, sizeof(csk));
+
return eapKeyData;
}
/* TODO: PEAPv1 - different label in some cases */
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
"client EAP encryption",
- EAP_TLS_KEY_LEN);
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
+ os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
*len = EAP_TLS_KEY_LEN;
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
eapKeyData, EAP_TLS_KEY_LEN);
@@ -1341,6 +1348,40 @@
}
+static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *eapKeyData, *emsk;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ if (data->crypto_binding_used) {
+ /* [MS-PEAP] does not define EMSK derivation */
+ return NULL;
+ }
+
+ /* TODO: PEAPv1 - different label in some cases */
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+ "client EAP encryption",
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (eapKeyData) {
+ emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (!emsk)
+ return NULL;
+ *len = EAP_EMSK_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived EMSK",
+ emsk, EAP_EMSK_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive EMSK");
+ emsk = NULL;
+ }
+
+ return emsk;
+}
+
+
static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
@@ -1376,6 +1417,7 @@
eap->process = eap_peap_process;
eap->isDone = eap_peap_isDone;
eap->getKey = eap_peap_getKey;
+ eap->get_emsk = eap_peap_get_emsk;
eap->isSuccess = eap_peap_isSuccess;
eap->getSessionId = eap_peap_get_session_id;
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 10637d4..1287827 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -535,6 +535,9 @@
goto failed;
}
+ if (data->permanent[0] == EAP_SIM_PERMANENT_PREFIX)
+ os_strlcpy(sm->imsi, &data->permanent[1], sizeof(sm->imsi));
+
identity_len = sm->identity_len;
while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') {
wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null "
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 8b9e53c..13d2349 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -22,6 +22,7 @@
enum { START, CONTINUE, SUCCESS, FAILURE } state;
int established;
u8 eap_type;
+ int phase2;
};
@@ -85,6 +86,8 @@
data->eap_type = EAP_TYPE_TLS;
+ data->phase2 = sm->init_phase2;
+
return data;
}
@@ -202,6 +205,20 @@
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
eap_tls_state(data, SUCCESS);
eap_tls_valid_session(sm, data);
+ if (sm->serial_num) {
+ char user[128];
+ int user_len;
+
+ user_len = os_snprintf(user, sizeof(user), "cert-%s",
+ sm->serial_num);
+ if (eap_user_get(sm, (const u8 *) user, user_len,
+ data->phase2) < 0)
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: No user entry found based on the serial number of the client certificate ");
+ else
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Updated user entry based on the serial number of the client certificate ");
+ }
}
return res;
@@ -288,6 +305,8 @@
"EAP-TLS: Resuming previous session");
eap_tls_state(data, SUCCESS);
tls_connection_set_success_data_resumed(data->ssl.conn);
+ /* TODO: Cache serial number with session and update EAP user
+ * information based on the cached serial number */
}
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 0ae7867..4ba7c24 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -146,10 +146,26 @@
u8 *out;
if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
- *len = 64;
- return eap_server_tls_derive_key(sm, data,
- "EXPORTER_EAP_TLS_Session-Id",
- 64);
+ u8 *id, *method_id;
+
+ /* Session-Id = <EAP-Type> || Method-Id
+ * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
+ * "", 64)
+ */
+ *len = 1 + 64;
+ id = os_malloc(*len);
+ if (!id)
+ return NULL;
+ method_id = eap_server_tls_derive_key(
+ sm, data, "EXPORTER_EAP_TLS_Method-Id", 64);
+ if (!method_id) {
+ os_free(id);
+ return NULL;
+ }
+ id[0] = eap_type;
+ os_memcpy(id + 1, method_id, 64);
+ os_free(method_id);
+ return id;
}
if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
diff --git a/src/lib.rules b/src/lib.rules
index 0c79d99..4ec4711 100644
--- a/src/lib.rules
+++ b/src/lib.rules
@@ -6,6 +6,11 @@
CFLAGS = -MMD -O2 -Wall -g
endif
+ifdef TEST_FUZZ
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+CFLAGS += -DTEST_FUZZ
+endif
+
CFLAGS += -I.. -I../utils
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 585b4a0..5115239 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1172,9 +1172,9 @@
u8 seek_count, const char **seek, int freq)
{
int res;
+ struct os_reltime start;
p2p_dbg(p2p, "Starting find (type=%d)", type);
- os_get_reltime(&p2p->find_start);
if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan is already running");
}
@@ -1258,6 +1258,7 @@
if (timeout)
eloop_register_timeout(timeout, 0, p2p_find_timeout,
p2p, NULL);
+ os_get_reltime(&start);
switch (type) {
case P2P_FIND_START_WITH_FULL:
if (freq > 0) {
@@ -1289,6 +1290,9 @@
return -1;
}
+ if (!res)
+ p2p->find_start = start;
+
if (res != 0 && p2p->p2p_scan_running) {
p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
/* wait for the previous p2p_scan to complete */
@@ -1470,7 +1474,8 @@
p2p->op_channel = p2p->cfg->op_channel;
} else if (p2p_channel_random_social(&p2p->cfg->channels,
&p2p->op_reg_class,
- &p2p->op_channel) == 0) {
+ &p2p->op_channel,
+ NULL, NULL) == 0) {
p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference",
p2p->op_reg_class, p2p->op_channel);
} else {
@@ -4769,9 +4774,12 @@
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
- return p2p_channel_random_social(&p2p->channels, op_class, op_channel);
+ return p2p_channel_random_social(&p2p->channels, op_class, op_channel,
+ avoid_list, disallow_list);
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fac5ce0..f2969ee 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -104,6 +104,11 @@
unsigned int vht_center_freq2;
/**
+ * he - Indicates if IEEE 802.11ax HE is enabled
+ */
+ int he;
+
+ /**
* ssid - SSID of the group
*/
u8 ssid[SSID_MAX_LEN];
@@ -2005,6 +2010,8 @@
* @p2p: P2P config
* @op_class: Selected operating class
* @op_channel: Selected social channel
+ * @avoid_list: Channel ranges to try to avoid or %NULL
+ * @disallow_list: Channel ranges to discard or %NULL
* Returns: 0 on success, -1 on failure
*
* This function is used before p2p_init is called. A random social channel
@@ -2012,7 +2019,9 @@
* returned on success.
*/
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
- u8 *op_channel);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
u8 forced);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index a73d99e..64a9977 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -718,7 +718,9 @@
int p2p_channel_select(struct p2p_channels *chans, const int *classes,
u8 *op_class, u8 *op_channel);
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
- u8 *op_channel);
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list);
/* p2p_parse.c */
void p2p_copy_filter_devname(char *dst, size_t dst_len,
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index bbba001..77d662a 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -488,7 +488,7 @@
if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
p2p->retry_invite_req &&
p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
- &p2p->op_channel) == 0) {
+ &p2p->op_channel, NULL, NULL) == 0) {
p2p->retry_invite_req = 0;
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 2e2aa8a..1a62a44 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -413,17 +413,30 @@
int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class,
- u8 *op_channel)
+ u8 *op_channel,
+ struct wpa_freq_range_list *avoid_list,
+ struct wpa_freq_range_list *disallow_list)
{
u8 chan[4];
unsigned int num_channels = 0;
- /* Try to find available social channels from 2.4 GHz */
- if (p2p_channels_includes(chans, 81, 1))
+ /* Try to find available social channels from 2.4 GHz.
+ * If the avoid_list includes any of the 2.4 GHz social channels, that
+ * channel is not allowed by p2p_channels_includes() rules. However, it
+ * is assumed to allow minimal traffic for P2P negotiation, so allow it
+ * here for social channel selection unless explicitly disallowed in the
+ * disallow_list. */
+ if (p2p_channels_includes(chans, 81, 1) ||
+ (freq_range_list_includes(avoid_list, 2412) &&
+ !freq_range_list_includes(disallow_list, 2412)))
chan[num_channels++] = 1;
- if (p2p_channels_includes(chans, 81, 6))
+ if (p2p_channels_includes(chans, 81, 6) ||
+ (freq_range_list_includes(avoid_list, 2437) &&
+ !freq_range_list_includes(disallow_list, 2437)))
chan[num_channels++] = 6;
- if (p2p_channels_includes(chans, 81, 11))
+ if (p2p_channels_includes(chans, 81, 11) ||
+ (freq_range_list_includes(avoid_list, 2462) &&
+ !freq_range_list_includes(disallow_list, 2462)))
chan[num_channels++] = 11;
/* Try to find available social channels from 60 GHz */
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index 360fcd3..8cdce30 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -38,12 +38,10 @@
/* Logon -> CP */
enum connect_type connect;
- u8 *authorization_data;
/* KaY -> CP */
Boolean chgd_server; /* clear by CP */
Boolean elected_self;
- u8 *authorization_data1;
enum confidentiality_offset cipher_offset;
u64 cipher_suite;
Boolean new_sak; /* clear by CP */
@@ -320,8 +318,11 @@
SM_ENTRY(CP, RETIRE);
/* RETIRE state machine not keep with Figure 12-2 in
* IEEE Std 802.1X-2010 */
- os_free(sm->oki);
- sm->oki = NULL;
+ if (sm->oki) {
+ ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
+ os_free(sm->oki);
+ sm->oki = NULL;
+ }
sm->orx = FALSE;
sm->otx = FALSE;
ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
@@ -383,7 +384,8 @@
if (!sm->elected_self)
SM_ENTER(CP, READY);
if (sm->elected_self &&
- (sm->all_receiving || !sm->transmit_when))
+ (sm->all_receiving || !sm->controlled_port_enabled ||
+ !sm->transmit_when))
SM_ENTER(CP, TRANSMIT);
break;
@@ -406,8 +408,8 @@
case CP_READY:
if (sm->new_sak || changed_connect(sm))
- SM_ENTER(CP, RECEIVE);
- if (sm->server_transmitting)
+ SM_ENTER(CP, ABANDON);
+ if (sm->server_transmitting || !sm->controlled_port_enabled)
SM_ENTER(CP, TRANSMIT);
break;
case CP_ABANDON:
@@ -464,7 +466,6 @@
sm->retire_delay = MKA_SAK_RETIRE_TIME;
sm->CP_state = CP_BEGIN;
sm->changed = FALSE;
- sm->authorization_data = NULL;
wpa_printf(MSG_DEBUG, "CP: state machine created");
@@ -476,7 +477,6 @@
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
- SM_ENTER(CP, INIT);
SM_STEP_RUN(CP);
return sm;
@@ -518,7 +518,6 @@
eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
os_free(sm->lki);
os_free(sm->oki);
- os_free(sm->authorization_data);
os_free(sm);
}
@@ -589,19 +588,6 @@
/**
- * ieee802_1x_cp_set_authorizationdata -
- */
-void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len)
-{
- struct ieee802_1x_cp_sm *sm = cp_ctx;
- os_free(sm->authorization_data);
- sm->authorization_data = os_zalloc(len);
- if (sm->authorization_data)
- os_memcpy(sm->authorization_data, pdata, len);
-}
-
-
-/**
* ieee802_1x_cp_set_ciphersuite -
*/
void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs)
diff --git a/src/pae/ieee802_1x_cp.h b/src/pae/ieee802_1x_cp.h
index 695629e..a357b27 100644
--- a/src/pae/ieee802_1x_cp.h
+++ b/src/pae/ieee802_1x_cp.h
@@ -25,7 +25,6 @@
void ieee802_1x_cp_connect_secure(void *cp_ctx);
void ieee802_1x_cp_signal_chgdserver(void *cp_ctx);
void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status);
-void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len);
void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs);
void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset);
void ieee802_1x_cp_signal_newsak(void *cp_ctx);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index cda23fc..b4455c8 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1,5 +1,5 @@
/*
- * IEEE 802.1X-2010 Key Agree Protocol of PAE state machine
+ * IEEE 802.1X-2010 Key Agreement Protocol of PAE state machine
* Copyright (c) 2013, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
@@ -27,6 +27,9 @@
#define DEFAULT_ICV_LEN 16
#define MAX_ICV_LEN 32 /* 32 bytes, 256 bits */
+#define MAX_MISSING_SAK_USE 10 /* Accept up to 10 inbound MKPDUs without
+ * SAK-USE before dropping */
+
#define PENDING_PN_EXHAUSTION 0xC0000000
#define MKA_ALIGN_LENGTH(len) (((len) + 0x3) & ~0x3)
@@ -43,7 +46,6 @@
.name = CS_NAME_GCM_AES_128,
.capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
.sak_len = DEFAULT_SA_KEY_LEN,
- .index = 0,
},
/* GCM-AES-256 */
{
@@ -51,7 +53,6 @@
.name = CS_NAME_GCM_AES_256,
.capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
.sak_len = 32,
- .index = 1 /* index */
},
};
#define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
@@ -61,19 +62,13 @@
{
.parameter = MKA_ALGO_AGILITY_2009,
- /* 128-bit CAK, KEK, ICK, ICV */
- .cak_len = DEFAULT_ICV_LEN,
- .kek_len = DEFAULT_ICV_LEN,
- .ick_len = DEFAULT_ICV_LEN,
.icv_len = DEFAULT_ICV_LEN,
- .cak_trfm = ieee802_1x_cak_128bits_aes_cmac,
- .ckn_trfm = ieee802_1x_ckn_128bits_aes_cmac,
- .kek_trfm = ieee802_1x_kek_128bits_aes_cmac,
- .ick_trfm = ieee802_1x_ick_128bits_aes_cmac,
- .icv_hash = ieee802_1x_icv_128bits_aes_cmac,
-
- .index = 1,
+ .cak_trfm = ieee802_1x_cak_aes_cmac,
+ .ckn_trfm = ieee802_1x_ckn_aes_cmac,
+ .kek_trfm = ieee802_1x_kek_aes_cmac,
+ .ick_trfm = ieee802_1x_ick_aes_cmac,
+ .icv_hash = ieee802_1x_icv_aes_cmac,
},
};
#define MKA_ALG_TABLE_SIZE (ARRAY_SIZE(mka_alg_tbl))
@@ -109,6 +104,34 @@
}
+static const char * mi_txt(const u8 *mi)
+{
+ static char txt[MI_LEN * 2 + 1];
+
+ wpa_snprintf_hex(txt, sizeof(txt), mi, MI_LEN);
+ return txt;
+}
+
+
+static const char * sci_txt(const struct ieee802_1x_mka_sci *sci)
+{
+ static char txt[ETH_ALEN * 3 + 1 + 5 + 1];
+
+ os_snprintf(txt, sizeof(txt), MACSTR "@%u",
+ MAC2STR(sci->addr), be_to_host16(sci->port));
+ return txt;
+}
+
+
+static const char * algo_agility_txt(const u8 *algo_agility)
+{
+ static char txt[4 * 2 + 1];
+
+ wpa_snprintf_hex(txt, sizeof(txt), algo_agility, 4);
+ return txt;
+}
+
+
/**
* ieee802_1x_mka_dump_basic_body -
*/
@@ -120,26 +143,25 @@
if (!body)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-8 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_DEBUG, "*** MKA Basic Parameter set ***");
- wpa_printf(MSG_DEBUG, "\tVersion.......: %d", body->version);
- wpa_printf(MSG_DEBUG, "\tPriority......: %d", body->priority);
- wpa_printf(MSG_DEBUG, "\tKeySvr........: %d", body->key_server);
- wpa_printf(MSG_DEBUG, "\tMACSecDesired.: %d", body->macsec_desired);
- wpa_printf(MSG_DEBUG, "\tMACSecCapable.: %d", body->macsec_capability);
- wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
- wpa_printf(MSG_DEBUG, "\tSCI MAC.......: " MACSTR,
- MAC2STR(body->actor_sci.addr));
- wpa_printf(MSG_DEBUG, "\tSCI Port .....: %d",
- be_to_host16(body->actor_sci.port));
- wpa_hexdump(MSG_DEBUG, "\tMember Id.....:",
- body->actor_mi, sizeof(body->actor_mi));
- wpa_printf(MSG_DEBUG, "\tMessage Number: %d",
+ wpa_printf(MSG_DEBUG, "MKA Basic Parameter Set");
+ wpa_printf(MSG_DEBUG, "\tMKA Version Identifier: %d", body->version);
+ wpa_printf(MSG_DEBUG, "\tKey Server Priority: %d", body->priority);
+ wpa_printf(MSG_DEBUG, "\tKey Server: %d", body->key_server);
+ wpa_printf(MSG_DEBUG, "\tMACsec Desired: %d", body->macsec_desired);
+ wpa_printf(MSG_DEBUG, "\tMACsec Capability: %d",
+ body->macsec_capability);
+ wpa_printf(MSG_DEBUG, "\tParameter set body length: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "\tSCI: %s", sci_txt(&body->actor_sci));
+ wpa_printf(MSG_DEBUG, "\tActor's Member Identifier: %s",
+ mi_txt(body->actor_mi));
+ wpa_printf(MSG_DEBUG, "\tActor's Message Number: %d",
be_to_host32(body->actor_mn));
- wpa_hexdump(MSG_DEBUG, "\tAlgo Agility..:",
- body->algo_agility, sizeof(body->algo_agility));
- wpa_hexdump_ascii(MSG_DEBUG, "\tCAK Name......:", body->ckn,
- body_len + MKA_HDR_LEN - sizeof(*body));
+ wpa_printf(MSG_DEBUG, "\tAlgorithm Agility: %s",
+ algo_agility_txt(body->algo_agility));
+ wpa_hexdump(MSG_DEBUG, "\tCAK Name", body->ckn,
+ body_len + MKA_HDR_LEN - sizeof(*body));
}
@@ -157,20 +179,21 @@
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-9 */
body_len = get_mka_param_body_len(body);
if (body->type == MKA_LIVE_PEER_LIST) {
- wpa_printf(MSG_DEBUG, "*** Live Peer List ***");
- wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "Live Peer List parameter set");
+ wpa_printf(MSG_DEBUG, "\tBody Length: %zu", body_len);
} else if (body->type == MKA_POTENTIAL_PEER_LIST) {
- wpa_printf(MSG_DEBUG, "*** Potential Live Peer List ***");
- wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "Potential Peer List parameter set");
+ wpa_printf(MSG_DEBUG, "\tBody Length: %zu", body_len);
}
for (i = 0; i < body_len; i += MI_LEN + sizeof(mn)) {
mi = body->peer + i;
os_memcpy(&mn, mi + MI_LEN, sizeof(mn));
- wpa_hexdump_ascii(MSG_DEBUG, "\tMember Id.....:", mi, MI_LEN);
- wpa_printf(MSG_DEBUG, "\tMessage Number: %d", be_to_host32(mn));
+ wpa_printf(MSG_DEBUG, "\tMember Id: %s Message Number: %d",
+ mi_txt(mi), be_to_host32(mn));
}
}
@@ -186,18 +209,20 @@
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-11 and 11-12 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_INFO, "*** Distributed SAK ***");
- wpa_printf(MSG_INFO, "\tDistributed AN........: %d", body->dan);
- wpa_printf(MSG_INFO, "\tConfidentiality Offset: %d",
+ wpa_printf(MSG_DEBUG, "Distributed SAK parameter set");
+ wpa_printf(MSG_DEBUG, "\tDistributed AN........: %d", body->dan);
+ wpa_printf(MSG_DEBUG, "\tConfidentiality Offset: %d",
body->confid_offset);
- wpa_printf(MSG_INFO, "\tBody Length...........: %zu", body_len);
+ wpa_printf(MSG_DEBUG, "\tBody Length...........: %zu", body_len);
if (!body_len)
return;
- wpa_printf(MSG_INFO, "\tKey Number............: %d",
+ wpa_printf(MSG_DEBUG, "\tKey Number............: %d",
be_to_host32(body->kn));
- wpa_hexdump(MSG_INFO, "\tAES Key Wrap of SAK...:", body->sak, 24);
+ /* TODO: Other than GCM-AES-128 case: MACsec Cipher Suite */
+ wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", body->sak, 24);
}
@@ -218,33 +243,32 @@
if (body == NULL)
return;
+ /* IEEE Std 802.1X-2010, Figure 11-10 */
body_len = get_mka_param_body_len(body);
- wpa_printf(MSG_DEBUG, "*** MACsec SAK Use ***");
+ wpa_printf(MSG_DEBUG, "MACsec SAK Use parameter set");
wpa_printf(MSG_DEBUG, "\tLatest Key AN....: %d", body->lan);
wpa_printf(MSG_DEBUG, "\tLatest Key Tx....: %s", yes_no(body->ltx));
wpa_printf(MSG_DEBUG, "\tLatest Key Rx....: %s", yes_no(body->lrx));
- wpa_printf(MSG_DEBUG, "\tOld Key AN....: %d", body->oan);
- wpa_printf(MSG_DEBUG, "\tOld Key Tx....: %s", yes_no(body->otx));
- wpa_printf(MSG_DEBUG, "\tOld Key Rx....: %s", yes_no(body->orx));
- wpa_printf(MSG_DEBUG, "\tPlain Key Tx....: %s", yes_no(body->ptx));
- wpa_printf(MSG_DEBUG, "\tPlain Key Rx....: %s", yes_no(body->prx));
+ wpa_printf(MSG_DEBUG, "\tOld Key AN.......: %d", body->oan);
+ wpa_printf(MSG_DEBUG, "\tOld Key Tx.......: %s", yes_no(body->otx));
+ wpa_printf(MSG_DEBUG, "\tOld Key Rx.......: %s", yes_no(body->orx));
+ wpa_printf(MSG_DEBUG, "\tPlain Tx.........: %s", yes_no(body->ptx));
+ wpa_printf(MSG_DEBUG, "\tPlain Rx.........: %s", yes_no(body->prx));
wpa_printf(MSG_DEBUG, "\tDelay Protect....: %s",
yes_no(body->delay_protect));
wpa_printf(MSG_DEBUG, "\tBody Length......: %d", body_len);
if (!body_len)
return;
- wpa_hexdump(MSG_DEBUG, "\tKey Server MI....:",
- body->lsrv_mi, sizeof(body->lsrv_mi));
+ wpa_printf(MSG_DEBUG, "\tKey Server MI....: %s", mi_txt(body->lsrv_mi));
wpa_printf(MSG_DEBUG, "\tKey Number.......: %u",
be_to_host32(body->lkn));
wpa_printf(MSG_DEBUG, "\tLowest PN........: %u",
be_to_host32(body->llpn));
- wpa_hexdump_ascii(MSG_DEBUG, "\tOld Key Server MI....:",
- body->osrv_mi, sizeof(body->osrv_mi));
- wpa_printf(MSG_DEBUG, "\tOld Key Number.......: %u",
+ wpa_printf(MSG_DEBUG, "\tOld Key Server MI: %s", mi_txt(body->osrv_mi));
+ wpa_printf(MSG_DEBUG, "\tOld Key Number...: %u",
be_to_host32(body->okn));
- wpa_printf(MSG_DEBUG, "\tOld Lowest PN........: %u",
+ wpa_printf(MSG_DEBUG, "\tOld Lowest PN....: %u",
be_to_host32(body->olpn));
}
@@ -371,7 +395,7 @@
*/
static struct macsec_ciphersuite *
ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
- const u8 *cs_id)
+ const u8 *cs_id, unsigned int *idx)
{
unsigned int i;
u64 cs;
@@ -381,8 +405,10 @@
cs = be_to_host64(_cs);
for (i = 0; i < CS_TABLE_SIZE; i++) {
- if (cipher_suite_tbl[i].id == cs)
+ if (cipher_suite_tbl[i].id == cs) {
+ *idx = i;
return &cipher_suite_tbl[i];
+ }
}
return NULL;
@@ -464,7 +490,7 @@
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create receive SA(AN: %hhu lowest_pn: %u of SC",
+ "KaY: Create receive SA(an: %hhu lowest_pn: %u) of SC",
an, lowest_pn);
return psa;
@@ -511,8 +537,8 @@
psc->receiving = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create receive SC");
- wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)psci, sizeof(*psci));
+ wpa_printf(MSG_DEBUG, "KaY: Create receive SC: SCI %s",
+ sci_txt(&psc->sci));
return psc;
}
@@ -549,10 +575,8 @@
static void ieee802_1x_kay_dump_peer(struct ieee802_1x_kay_peer *peer)
{
- wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, sizeof(peer->mi));
- wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn);
- wpa_hexdump(MSG_DEBUG, "\tSCI Addr: ", peer->sci.addr, ETH_ALEN);
- wpa_printf(MSG_DEBUG, "\tPort: %d", peer->sci.port);
+ wpa_printf(MSG_DEBUG, "\tMI: %s MN: %d SCI: %s",
+ mi_txt(peer->mi), peer->mn, sci_txt(&peer->sci));
}
@@ -571,6 +595,7 @@
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
peer->sak_used = FALSE;
+ peer->missing_sak_use_count = 0;
return peer;
}
@@ -599,9 +624,13 @@
return NULL;
}
+ if (secy_create_receive_sc(participant->kay, rxsc)) {
+ os_free(rxsc);
+ os_free(peer);
+ return NULL;
+ }
dl_list_add(&participant->live_peers, &peer->list);
dl_list_add(&participant->rxsc_list, &rxsc->list);
- secy_create_receive_sc(participant->kay, rxsc);
wpa_printf(MSG_DEBUG, "KaY: Live peer created");
ieee802_1x_kay_dump_peer(peer);
@@ -625,7 +654,7 @@
dl_list_add(&participant->potential_peers, &peer->list);
- wpa_printf(MSG_DEBUG, "KaY: potential peer created");
+ wpa_printf(MSG_DEBUG, "KaY: Potential peer created");
ieee802_1x_kay_dump_peer(peer);
return peer;
@@ -655,14 +684,19 @@
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- wpa_printf(MSG_DEBUG, "KaY: move potential peer to live peer");
+ wpa_printf(MSG_DEBUG, "KaY: Move potential peer to live peer");
ieee802_1x_kay_dump_peer(peer);
dl_list_del(&peer->list);
+ if (secy_create_receive_sc(participant->kay, rxsc)) {
+ wpa_printf(MSG_ERROR, "KaY: Can't create SC, discard peer");
+ os_free(rxsc);
+ os_free(peer);
+ return NULL;
+ }
dl_list_add_tail(&participant->live_peers, &peer->list);
dl_list_add(&participant->rxsc_list, &rxsc->list);
- secy_create_receive_sc(participant->kay, rxsc);
return peer;
}
@@ -704,12 +738,15 @@
{
struct ieee802_1x_mka_basic_body *body;
struct ieee802_1x_kay *kay = participant->kay;
- unsigned int length = ieee802_1x_mka_basic_body_length(participant);
+ unsigned int length = sizeof(struct ieee802_1x_mka_basic_body);
- body = wpabuf_put(buf, length);
+ length += participant->ckn.len;
+ body = wpabuf_put(buf, MKA_ALIGN_LENGTH(length));
body->version = kay->mka_version;
body->priority = kay->actor_priority;
+ /* The Key Server flag is set if and only if the participant has not
+ * decided that another participant is or will be the Key Server. */
if (participant->is_elected)
body->key_server = participant->is_key_server;
else
@@ -765,11 +802,11 @@
if (body->version > MKA_VERSION_ID) {
wpa_printf(MSG_DEBUG,
- "KaY: peer's version(%d) greater than mka current version(%d)",
+ "KaY: Peer's version(%d) greater than MKA current version(%d)",
body->version, MKA_VERSION_ID);
}
if (kay->is_obliged_key_server && body->key_server) {
- wpa_printf(MSG_DEBUG, "I must be as key server");
+ wpa_printf(MSG_DEBUG, "KaY: I must be key server - ignore MKPDU claiming to be from a key server");
return NULL;
}
@@ -783,7 +820,8 @@
(sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
if (!participant) {
- wpa_printf(MSG_DEBUG, "Peer is not included in my CA");
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer is not included in my CA - ignore MKPDU");
return NULL;
}
@@ -791,6 +829,9 @@
if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
if (!reset_participant_mi(participant))
return NULL;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer using my MI - selected a new random MI: %s",
+ mi_txt(participant->mi));
}
os_memcpy(participant->current_peer_id.mi, body->actor_mi, MI_LEN);
@@ -802,24 +843,48 @@
/* handler peer */
peer = ieee802_1x_kay_get_peer(participant, body->actor_mi);
if (!peer) {
- /* Check duplicated SCI */
- /* TODO: What policy should be applied to detect duplicated SCI
- * is active attacker or a valid peer whose MI is be changed?
+ /* Check duplicated SCI
+ *
+ * A duplicated SCI indicates either an active attacker or
+ * a valid peer whose MI is being changed. The latter scenario
+ * is more likely because to have gotten this far the received
+ * MKPDU must have had a valid ICV, indicating the peer holds
+ * the same CAK as our participant.
+ *
+ * Before creating a new peer object for the new MI we must
+ * clean up the resources (SCs and SAs) associated with the
+ * old peer. An easy way to do this is to ignore MKPDUs with
+ * the new MI's for now and just wait for the old peer to
+ * time out and clean itself up (within MKA_LIFE_TIME).
+ *
+ * This method is preferable to deleting the old peer here
+ * and now and continuing on with processing because if this
+ * MKPDU is from an attacker it's better to ignore the MKPDU
+ * than to process it (and delete a valid peer as well).
*/
peer = ieee802_1x_kay_get_peer_sci(participant,
&body->actor_sci);
if (peer) {
+ time_t new_expire;
+
wpa_printf(MSG_WARNING,
- "KaY: duplicated SCI detected, Maybe active attacker");
- dl_list_del(&peer->list);
- os_free(peer);
+ "KaY: duplicated SCI detected - maybe active attacker or peer selected new MI - ignore MKPDU");
+ /* Reduce timeout to speed up this process but left the
+ * chance for old one to prove aliveness. */
+ new_expire = time(NULL) + MKA_HELLO_TIME * 1.5 / 1000;
+ if (peer->expire > new_expire)
+ peer->expire = new_expire;
+ return NULL;
}
peer = ieee802_1x_kay_create_potential_peer(
participant, body->actor_mi,
be_to_host32(body->actor_mn));
- if (!peer)
+ if (!peer) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: No potential peer entry found - ignore MKPDU");
return NULL;
+ }
peer->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
@@ -827,13 +892,13 @@
peer->key_server_priority = body->priority;
} else if (peer->mn < be_to_host32(body->actor_mn)) {
peer->mn = be_to_host32(body->actor_mn);
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
peer->macsec_desired = body->macsec_desired;
peer->macsec_capability = body->macsec_capability;
peer->is_key_server = (Boolean) body->key_server;
peer->key_server_priority = body->priority;
} else {
- wpa_printf(MSG_WARNING, "KaY: The peer MN have received");
+ wpa_printf(MSG_WARNING,
+ "KaY: The peer MN did not increase - ignore MKPDU");
return NULL;
}
@@ -978,8 +1043,8 @@
for (pos = mka_msg, left_len = msg_len;
left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
- left_len -= body_len + MKA_HDR_LEN,
- pos += body_len + MKA_HDR_LEN) {
+ left_len -= MKA_ALIGN_LENGTH(body_len) + MKA_HDR_LEN,
+ pos += MKA_ALIGN_LENGTH(body_len) + MKA_HDR_LEN) {
hdr = (struct ieee802_1x_mka_hdr *) pos;
body_len = get_mka_param_body_len(hdr);
body_type = get_mka_param_body_type(hdr);
@@ -1014,9 +1079,15 @@
peer_mi = (const struct ieee802_1x_mka_peer_id *)
(pos + MKA_HDR_LEN + i);
if (os_memcmp(peer_mi->mi, participant->mi,
- MI_LEN) == 0 &&
- be_to_host32(peer_mi->mn) == participant->mn)
- return TRUE;
+ MI_LEN) == 0) {
+ u32 mn = be_to_host32(peer_mi->mn);
+
+ wpa_printf(MSG_DEBUG,
+ "KaY: My MI - received MN %u, most recently transmitted MN %u",
+ mn, participant->mn);
+ if (mn == participant->mn)
+ return TRUE;
+ }
}
}
@@ -1072,7 +1143,6 @@
peer = ieee802_1x_kay_get_peer(participant, peer_mi->mi);
if (peer) {
peer->mn = peer_mn;
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
} else if (!ieee802_1x_kay_create_potential_peer(
participant, peer_mi->mi, peer_mn)) {
return -1;
@@ -1154,27 +1224,38 @@
/**
- *
+ * ieee802_1x_mka_get_lpn
*/
static u32
ieee802_1x_mka_get_lpn(struct ieee802_1x_mka_participant *principal,
struct ieee802_1x_mka_ki *ki)
{
- struct receive_sa *rxsa;
- struct receive_sc *rxsc;
+ struct transmit_sa *txsa;
u32 lpn = 0;
- dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
- dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list)
- {
- if (is_ki_equal(&rxsa->pkey->key_identifier, ki)) {
- secy_get_receive_lowest_pn(principal->kay,
- rxsa);
+ dl_list_for_each(txsa, &principal->txsc->sa_list,
+ struct transmit_sa, list) {
+ if (is_ki_equal(&txsa->pkey->key_identifier, ki)) {
+ /* Per IEEE Std 802.1X-2010, Clause 9, "Each SecY uses
+ * MKA to communicate the lowest PN used for
+ * transmission with the SAK within the last two
+ * seconds". Achieve this 2 second delay by setting the
+ * lpn using the transmit next PN (i.e., txsa->next_pn)
+ * that was read last time here (i.e., mka_hello_time
+ * 2 seconds ago).
+ *
+ * The lowest acceptable PN is the same as the last
+ * transmitted PN, which is one less than the next
+ * transmit PN.
+ *
+ * NOTE: This method only works if mka_hello_time is 2s.
+ */
+ lpn = (txsa->next_pn > 0) ? (txsa->next_pn - 1) : 0;
- lpn = lpn > rxsa->lowest_pn ?
- lpn : rxsa->lowest_pn;
- break;
- }
+ /* Now read the current transmit next PN for use next
+ * time through. */
+ secy_get_transmit_next_pn(principal->kay, txsa);
+ break;
}
}
@@ -1214,8 +1295,9 @@
return 0;
}
- /* data protect, lowest accept packet number */
- body->delay_protect = kay->macsec_replay_protect;
+ /* data delay protect */
+ body->delay_protect = kay->mka_hello_time <= MKA_BOUNDED_HELLO_TIME;
+ /* lowest accept packet number */
pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
if (pn > kay->pn_exhaustion) {
wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
@@ -1276,7 +1358,8 @@
struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_mka_sak_use_body *body;
struct ieee802_1x_kay_peer *peer;
- struct transmit_sa *txsa;
+ struct receive_sc *rxsc;
+ struct receive_sa *rxsa;
struct data_key *sa_key = NULL;
size_t body_len;
struct ieee802_1x_mka_ki ki;
@@ -1292,7 +1375,9 @@
peer = ieee802_1x_kay_get_live_peer(participant,
participant->current_peer_id.mi);
if (!peer) {
- wpa_printf(MSG_WARNING, "KaY: the peer is not my live peer");
+ wpa_printf(MSG_WARNING,
+ "KaY: The peer (%s) is not my live peer - ignore MACsec SAK Use parameter set",
+ mi_txt(participant->current_peer_id.mi));
return -1;
}
@@ -1336,7 +1421,7 @@
}
}
if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Latest key is invalid");
+ wpa_printf(MSG_INFO, "KaY: Latest key is invalid");
return -1;
}
if (os_memcmp(participant->lki.mi, body->lsrv_mi,
@@ -1366,7 +1451,7 @@
if (body->delay_protect &&
(!be_to_host32(body->llpn) || !be_to_host32(body->olpn))) {
wpa_printf(MSG_WARNING,
- "KaY: Lowest packet number should greater than 0 when delay_protect is TRUE");
+ "KaY: Lowest packet number should be greater than 0 when delay_protect is TRUE");
return -1;
}
@@ -1385,7 +1470,7 @@
ieee802_1x_cp_sm_step(kay->cp);
}
- /* if i'm key server, and detects peer member pn exhaustion, rekey.*/
+ /* if I'm key server, and detects peer member pn exhaustion, rekey. */
lpn = be_to_host32(body->llpn);
if (lpn > kay->pn_exhaustion) {
if (participant->is_key_server) {
@@ -1394,26 +1479,41 @@
}
}
+ if (sa_key)
+ sa_key->next_pn = lpn;
found = FALSE;
- dl_list_for_each(txsa, &participant->txsc->sa_list,
- struct transmit_sa, list) {
- if (sa_key != NULL && txsa->pkey == sa_key) {
- found = TRUE;
- break;
+ dl_list_for_each(rxsc, &participant->rxsc_list, struct receive_sc,
+ list) {
+ dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa,
+ list) {
+ if (sa_key && rxsa->pkey == sa_key) {
+ found = TRUE;
+ break;
+ }
}
+ if (found)
+ break;
}
if (!found) {
- wpa_printf(MSG_WARNING, "KaY: Can't find txsa");
+ wpa_printf(MSG_WARNING, "KaY: Can't find rxsa");
return -1;
}
- /* FIXME: Secy creates txsa with default npn. If MKA detected Latest Key
- * npn is larger than txsa's npn, set it to txsa.
- */
- secy_get_transmit_next_pn(kay, txsa);
- if (lpn > txsa->next_pn) {
- secy_set_transmit_next_pn(kay, txsa);
- wpa_printf(MSG_INFO, "KaY: update lpn =0x%x", lpn);
+ if (body->delay_protect) {
+ secy_get_receive_lowest_pn(participant->kay, rxsa);
+ if (lpn > rxsa->lowest_pn) {
+ /* Delay protect window (communicated via MKA) is
+ * tighter than SecY's current replay protect window,
+ * so tell SecY the new (and higher) lpn. */
+ rxsa->lowest_pn = lpn;
+ secy_set_receive_lowest_pn(participant->kay, rxsa);
+ wpa_printf(MSG_DEBUG, "KaY: update lpn =0x%x", lpn);
+ }
+ /* FIX: Delay protection for olpn not implemented.
+ * Note that Old Key is only active for MKA_SAK_RETIRE_TIME
+ * (3 seconds) and delay protection does allow PN's within
+ * a 2 seconds window, so olpn would be a lot of work for
+ * just 1 second's worth of protection. */
}
return 0;
@@ -1427,7 +1527,8 @@
ieee802_1x_mka_dist_sak_body_present(
struct ieee802_1x_mka_participant *participant)
{
- return participant->to_dist_sak && participant->new_key;
+ return participant->is_key_server && participant->to_dist_sak &&
+ participant->new_key;
}
@@ -1478,6 +1579,11 @@
}
sak = participant->new_key;
+ if (!sak) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: No SAK available to build Distributed SAK parameter set");
+ return -1;
+ }
body->confid_offset = sak->confidentiality_offset;
body->dan = sak->an;
body->kn = host_to_be32(sak->key_identifier.kn);
@@ -1492,7 +1598,7 @@
os_memcpy(body->sak, &cs, CS_ID_LEN);
sak_pos = CS_ID_LEN;
}
- if (aes_wrap(participant->kek.key, 16,
+ if (aes_wrap(participant->kek.key, participant->kek.len,
cipher_suite_tbl[cs_index].sak_len / 8,
sak->key, body->sak + sak_pos)) {
wpa_printf(MSG_ERROR, "KaY: AES wrap failed");
@@ -1514,6 +1620,7 @@
pkey->receives = TRUE;
os_get_time(&pkey->created_time);
+ pkey->next_pn = 1;
pkey->user = 1;
}
@@ -1553,7 +1660,7 @@
}
if (participant->is_key_server) {
wpa_printf(MSG_ERROR,
- "KaY: I can't accept the distributed SAK as myself is key server ");
+ "KaY: Reject distributed SAK since I'm a key server");
return -1;
}
if (!kay->macsec_desired ||
@@ -1582,7 +1689,7 @@
participant->advised_desired = FALSE;
ieee802_1x_cp_connect_authenticated(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
- wpa_printf(MSG_WARNING, "KaY:The Key server advise no MACsec");
+ wpa_printf(MSG_WARNING, "KaY: The Key server advise no MACsec");
participant->to_use_sak = FALSE;
return 0;
}
@@ -1601,7 +1708,8 @@
if (os_memcmp(sa_key->key_identifier.mi,
participant->current_peer_id.mi, MI_LEN) == 0 &&
sa_key->key_identifier.kn == be_to_host32(body->kn)) {
- wpa_printf(MSG_WARNING, "KaY:The Key has installed");
+ wpa_printf(MSG_DEBUG,
+ "KaY: SAK has already been installed - do not set it again");
return 0;
}
}
@@ -1612,7 +1720,10 @@
kay->macsec_csindex = DEFAULT_CS_INDEX;
cs = &cipher_suite_tbl[kay->macsec_csindex];
} else {
- cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
+ unsigned int idx;
+
+ cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak,
+ &idx);
if (!cs) {
wpa_printf(MSG_ERROR,
"KaY: I can't support the Cipher Suite advised by key server");
@@ -1620,7 +1731,7 @@
}
sak_len = cs->sak_len;
wrap_sak = body->sak + CS_ID_LEN;
- kay->macsec_csindex = cs->index;
+ kay->macsec_csindex = idx;
}
unwrap_sak = os_zalloc(sak_len);
@@ -1628,13 +1739,13 @@
wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
return -1;
}
- if (aes_unwrap(participant->kek.key, 16, sak_len >> 3, wrap_sak,
- unwrap_sak)) {
+ if (aes_unwrap(participant->kek.key, participant->kek.len,
+ sak_len >> 3, wrap_sak, unwrap_sak)) {
wpa_printf(MSG_ERROR, "KaY: AES unwrap failed");
os_free(unwrap_sak);
return -1;
}
- wpa_hexdump_key(MSG_DEBUG, "\tAES Key Unwrap of SAK:",
+ wpa_hexdump_key(MSG_DEBUG, "\tAES Key Unwrap of SAK.:",
unwrap_sak, sak_len);
sa_key = os_zalloc(sizeof(*sa_key));
@@ -1691,7 +1802,12 @@
{
int length;
- length = sizeof(struct ieee802_1x_mka_icv_body);
+ /* Determine if we need space for the ICV Indicator */
+ if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
+ DEFAULT_ICV_LEN)
+ length = sizeof(struct ieee802_1x_mka_icv_body);
+ else
+ length = 0;
length += mka_alg_tbl[participant->kay->mka_algindex].icv_len;
return MKA_ALIGN_LENGTH(length);
@@ -1710,20 +1826,23 @@
u8 cmac[MAX_ICV_LEN];
length = ieee802_1x_mka_get_icv_length(participant);
- if (length != DEFAULT_ICV_LEN) {
+ if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
+ DEFAULT_ICV_LEN) {
+ wpa_printf(MSG_DEBUG, "KaY: ICV Indicator");
body = wpabuf_put(buf, MKA_HDR_LEN);
body->type = MKA_ICV_INDICATOR;
- set_mka_param_body_len(body, length - MKA_HDR_LEN);
+ length -= MKA_HDR_LEN;
+ set_mka_param_body_len(body, length);
}
if (mka_alg_tbl[participant->kay->mka_algindex].icv_hash(
- participant->ick.key, wpabuf_head(buf), buf->used, cmac)) {
- wpa_printf(MSG_ERROR, "KaY, omac1_aes_128 failed");
+ participant->ick.key, participant->ick.len,
+ wpabuf_head(buf), wpabuf_len(buf), cmac)) {
+ wpa_printf(MSG_ERROR, "KaY: failed to calculate ICV");
return -1;
}
+ wpa_hexdump(MSG_DEBUG, "KaY: ICV", cmac, length);
- if (length != DEFAULT_ICV_LEN)
- length -= MKA_HDR_LEN;
os_memcpy(wpabuf_put(buf, length), cmac, length);
return 0;
@@ -1732,12 +1851,12 @@
/**
* ieee802_1x_mka_decode_icv_body -
*/
-static u8 *
+static const u8 *
ieee802_1x_mka_decode_icv_body(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len)
{
- struct ieee802_1x_mka_hdr *hdr;
- struct ieee802_1x_mka_icv_body *body;
+ const struct ieee802_1x_mka_hdr *hdr;
+ const struct ieee802_1x_mka_icv_body *body;
size_t body_len;
size_t left_len;
u8 body_type;
@@ -1745,12 +1864,12 @@
pos = mka_msg;
left_len = msg_len;
- while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
- hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ while (left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN) {
+ hdr = (const struct ieee802_1x_mka_hdr *) pos;
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
body_type = get_mka_param_body_type(hdr);
- if (left_len < (body_len + MKA_HDR_LEN))
+ if (left_len < body_len + MKA_HDR_LEN)
break;
if (body_type != MKA_ICV_INDICATOR) {
@@ -1759,16 +1878,15 @@
continue;
}
- body = (struct ieee802_1x_mka_icv_body *)pos;
+ body = (const struct ieee802_1x_mka_icv_body *) pos;
if (body_len
- < mka_alg_tbl[participant->kay->mka_algindex].icv_len) {
+ < mka_alg_tbl[participant->kay->mka_algindex].icv_len)
return NULL;
- }
return body->icv;
}
- return (u8 *) (mka_msg + msg_len - DEFAULT_ICV_LEN);
+ return mka_msg + msg_len - DEFAULT_ICV_LEN;
}
@@ -1787,7 +1905,7 @@
body_len = get_mka_param_body_len(hdr);
if (body_len < 28) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 28 or more octets",
+ "KaY: MKA Use CAK Packet Body Length (%zu bytes) should be 28 or more octets",
body_len);
return -1;
}
@@ -1811,7 +1929,7 @@
body_len = get_mka_param_body_len(hdr);
if (body_len < 5) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 5 or more octets",
+ "KaY: MKA Use KMD Packet Body Length (%zu bytes) should be 5 or more octets",
body_len);
return -1;
}
@@ -1842,7 +1960,7 @@
static struct mka_param_body_handler mka_body_handler[] = {
- /* basic parameter set */
+ /* Basic parameter set */
{
.body_tx = ieee802_1x_mka_encode_basic_body,
.body_rx = NULL,
@@ -1850,7 +1968,7 @@
.body_present = ieee802_1x_mka_basic_body_present
},
- /* live peer list parameter set */
+ /* Live Peer List parameter set */
{
.body_tx = ieee802_1x_mka_encode_live_peer_body,
.body_rx = ieee802_1x_mka_decode_live_peer_body,
@@ -1858,7 +1976,7 @@
.body_present = ieee802_1x_mka_live_peer_body_present
},
- /* potential peer list parameter set */
+ /* Potential Peer List parameter set */
{
.body_tx = ieee802_1x_mka_encode_potential_peer_body,
.body_rx = ieee802_1x_mka_decode_potential_peer_body,
@@ -1866,7 +1984,7 @@
.body_present = ieee802_1x_mka_potential_peer_body_present
},
- /* sak use parameter set */
+ /* MACsec SAK Use parameter set */
{
.body_tx = ieee802_1x_mka_encode_sak_use_body,
.body_rx = ieee802_1x_mka_decode_sak_use_body,
@@ -1874,7 +1992,7 @@
.body_present = ieee802_1x_mka_sak_use_body_present
},
- /* distribute sak parameter set */
+ /* Distributed SAK parameter set */
{
.body_tx = ieee802_1x_mka_encode_dist_sak_body,
.body_rx = ieee802_1x_mka_decode_dist_sak_body,
@@ -1882,7 +2000,7 @@
.body_present = ieee802_1x_mka_dist_sak_body_present
},
- /* distribute cak parameter set */
+ /* Distribute CAK parameter set */
{
.body_tx = NULL,
.body_rx = ieee802_1x_mka_decode_dist_cak_body,
@@ -1890,7 +2008,7 @@
.body_present = NULL
},
- /* kmd parameter set */
+ /* KMD parameter set */
{
.body_tx = NULL,
.body_rx = ieee802_1x_mka_decode_kmd_body,
@@ -1898,7 +2016,7 @@
.body_present = NULL
},
- /* announce parameter set */
+ /* Announcement parameter set */
{
.body_tx = NULL,
.body_rx = ieee802_1x_mka_decode_announce_body,
@@ -1906,7 +2024,7 @@
.body_present = NULL
},
- /* icv parameter set */
+ /* ICV Indicator parameter set */
{
.body_tx = ieee802_1x_mka_encode_icv_body,
.body_rx = NULL,
@@ -1965,7 +2083,7 @@
*/
if (dl_list_empty(&participant->live_peers)) {
wpa_printf(MSG_ERROR,
- "KaY: Live peers list must not empty when generating fresh SAK");
+ "KaY: Live peers list must not be empty when generating fresh SAK");
return -1;
}
@@ -1979,7 +2097,7 @@
*/
if ((time(NULL) - kay->dist_time) < MKA_LIFE_TIME / 1000) {
wpa_printf(MSG_ERROR,
- "KaY: Life time have not elapsed since prior SAK distributed");
+ "KaY: Life time has not elapsed since prior SAK distributed");
return -1;
}
@@ -2016,14 +2134,17 @@
ctx_offset += sizeof(participant->mi);
os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
- if (key_len == 16) {
- ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, key);
- } else if (key_len == 32) {
- ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, key);
+ if (key_len == 16 || key_len == 32) {
+ if (ieee802_1x_sak_aes_cmac(participant->cak.key,
+ participant->cak.len,
+ context, ctx_len,
+ key, key_len)) {
+ wpa_printf(MSG_ERROR, "KaY: Failed to generate SAK");
+ goto fail;
+ }
} else {
- wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
+ wpa_printf(MSG_ERROR, "KaY: SAK Length(%u) not supported",
+ key_len);
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
@@ -2155,7 +2276,7 @@
participant->is_key_server = TRUE;
participant->principal = TRUE;
participant->new_sak = TRUE;
- wpa_printf(MSG_DEBUG, "KaY: I is elected as key server");
+ wpa_printf(MSG_DEBUG, "KaY: I am elected as key server");
participant->to_dist_sak = FALSE;
participant->is_elected = TRUE;
@@ -2163,6 +2284,9 @@
sizeof(kay->key_server_sci));
kay->key_server_priority = kay->actor_priority;
} else if (key_server) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: Peer %s was elected as the key server",
+ mi_txt(key_server->mi));
ieee802_1x_cp_set_electedself(kay->cp, FALSE);
if (!sci_equal(&kay->key_server_sci, &key_server->sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
@@ -2281,11 +2405,19 @@
os_memcpy(ether_hdr->src, participant->kay->actor_sci.addr,
sizeof(ether_hdr->dest));
ether_hdr->ethertype = host_to_be16(ETH_P_EAPOL);
+ wpa_printf(MSG_DEBUG, "KaY: Ethernet header: DA=" MACSTR " SA=" MACSTR
+ " Ethertype=0x%x",
+ MAC2STR(ether_hdr->dest), MAC2STR(ether_hdr->src),
+ be_to_host16(ether_hdr->ethertype));
eapol_hdr = wpabuf_put(pbuf, sizeof(*eapol_hdr));
eapol_hdr->version = EAPOL_VERSION;
eapol_hdr->type = IEEE802_1X_TYPE_EAPOL_MKA;
- eapol_hdr->length = host_to_be16(pbuf->size - pbuf->used);
+ eapol_hdr->length = host_to_be16(wpabuf_tailroom(pbuf));
+ wpa_printf(MSG_DEBUG,
+ "KaY: Common EAPOL PDU structure: Protocol Version=%u Packet Type=%u Packet Body Length=%u",
+ eapol_hdr->version, eapol_hdr->type,
+ be_to_host16(eapol_hdr->length));
for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
if (mka_body_handler[i].body_present &&
@@ -2298,6 +2430,7 @@
return 0;
}
+
/**
* ieee802_1x_participant_send_mkpdu -
*/
@@ -2310,7 +2443,8 @@
size_t length = 0;
unsigned int i;
- wpa_printf(MSG_DEBUG, "KaY: to enpacket and send the MKPDU");
+ wpa_printf(MSG_DEBUG, "KaY: Encode and send an MKPDU (ifname=%s)",
+ kay->if_name);
length += sizeof(struct ieee802_1x_hdr) + sizeof(struct ieee8023_hdr);
for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
if (mka_body_handler[i].body_present &&
@@ -2325,10 +2459,11 @@
}
if (ieee802_1x_kay_encode_mkpdu(participant, buf)) {
- wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail!");
+ wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail");
return -1;
}
+ wpa_hexdump_buf(MSG_MSGDUMP, "KaY: Outgoing MKPDU", buf);
l2_packet_send(kay->l2_mka, NULL, 0, wpabuf_head(buf), wpabuf_len(buf));
wpabuf_free(buf);
@@ -2365,6 +2500,8 @@
participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
kay = participant->kay;
+ wpa_printf(MSG_DEBUG, "KaY: Participant timer (ifname=%s)",
+ kay->if_name);
if (participant->cak_life) {
if (now > participant->cak_life)
goto delete_mka;
@@ -2452,7 +2589,7 @@
}
}
- if (participant->new_sak) {
+ if (participant->new_sak && participant->is_key_server) {
if (!ieee802_1x_kay_generate_new_sak(participant))
participant->to_dist_sak = TRUE;
@@ -2465,7 +2602,7 @@
participant->retry_count++;
}
- eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
+ eloop_register_timeout(kay->mka_hello_time / 1000, 0,
ieee802_1x_participant_timer,
participant, NULL);
@@ -2514,7 +2651,7 @@
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create transmit SA(an: %hhu, next_PN: %u) of SC",
+ "KaY: Create transmit SA(an: %hhu, next_pn: %u) of SC",
an, next_PN);
return psa;
@@ -2557,8 +2694,8 @@
psc->enciphering_sa = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create transmit SC");
- wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)sci , sizeof(*sci));
+ wpa_printf(MSG_DEBUG, "KaY: Create transmit SC - SCI: %s",
+ sci_txt(&psc->sci));
return psc;
}
@@ -2709,7 +2846,7 @@
}
}
if (!latest_sak) {
- wpa_printf(MSG_ERROR, "lki related sak not found");
+ wpa_printf(MSG_ERROR, "KaY: lki related sak not found");
return -1;
}
@@ -2730,7 +2867,9 @@
ieee802_1x_delete_transmit_sa(kay, txsa);
txsa = ieee802_1x_kay_init_transmit_sa(principal->txsc, latest_sak->an,
- 1, latest_sak);
+ latest_sak->next_pn ?
+ latest_sak->next_pn : 1,
+ latest_sak);
if (!txsa)
return -1;
@@ -2779,12 +2918,12 @@
dl_list_for_each_safe(sa_key, pre_key, &principal->sak_list,
struct data_key, list) {
if (is_ki_equal(&sa_key->key_identifier, ki)) {
+ if (principal->new_key == sa_key)
+ principal->new_key = NULL;
dl_list_del(&sa_key->list);
ieee802_1x_kay_deinit_data_key(sa_key);
break;
}
- if (principal->new_key == sa_key)
- principal->new_key = NULL;
}
return 0;
@@ -2872,7 +3011,8 @@
/**
* ieee802_1x_kay_mkpdu_sanity_check -
- * sanity check specified in clause 11.11.2 of IEEE802.1X-2010
+ * Sanity checks specified in IEEE Std 802.1X-2010, 11.11.2 (Validation of
+ * MKPDUs)
*/
static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
const u8 *buf, size_t len)
@@ -2886,34 +3026,49 @@
size_t body_len;
size_t ckn_len;
u8 icv[MAX_ICV_LEN];
- u8 *msg_icv;
+ const u8 *msg_icv;
+ /* len > eth+eapol header already verified in kay_l2_receive();
+ * likewise, eapol_hdr->length validated there */
eth_hdr = (struct ieee8023_hdr *) buf;
eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
mka_hdr = (struct ieee802_1x_mka_hdr *) (eapol_hdr + 1);
- /* destination address should be not individual address */
+ wpa_printf(MSG_DEBUG, "KaY: Ethernet header: DA=" MACSTR " SA=" MACSTR
+ " Ethertype=0x%x",
+ MAC2STR(eth_hdr->dest), MAC2STR(eth_hdr->src),
+ be_to_host16(eth_hdr->ethertype));
+
+ /* the destination address shall not be an individual address */
if (os_memcmp(eth_hdr->dest, pae_group_addr, ETH_ALEN) != 0) {
- wpa_printf(MSG_MSGDUMP,
+ wpa_printf(MSG_DEBUG,
"KaY: ethernet destination address is not PAE group address");
return -1;
}
- /* MKPDU should not be less than 32 octets */
+ wpa_printf(MSG_DEBUG,
+ "KaY: Common EAPOL PDU structure: Protocol Version=%u Packet Type=%u Packet Body Length=%u",
+ eapol_hdr->version, eapol_hdr->type,
+ be_to_host16(eapol_hdr->length));
+
+ /* MKPDU shall not be less than 32 octets */
mka_msg_len = be_to_host16(eapol_hdr->length);
if (mka_msg_len < 32) {
- wpa_printf(MSG_MSGDUMP, "KaY: MKPDU is less than 32 octets");
+ wpa_printf(MSG_DEBUG, "KaY: MKPDU is less than 32 octets");
return -1;
}
- /* MKPDU should be a multiple of 4 octets */
+ /* MKPDU shall be a multiple of 4 octets */
if ((mka_msg_len % 4) != 0) {
- wpa_printf(MSG_MSGDUMP,
+ wpa_printf(MSG_DEBUG,
"KaY: MKPDU is not multiple of 4 octets");
return -1;
}
+ wpa_hexdump(MSG_MSGDUMP, "KaY: EAPOL-MKA Packet Body (MKPDU)",
+ mka_hdr, mka_msg_len);
+
+ /* Room for body_len already verified in kay_l2_receive() */
body = (struct ieee802_1x_mka_basic_body *) mka_hdr;
- ieee802_1x_mka_dump_basic_body(body);
body_len = get_mka_param_body_len(body);
/* EAPOL-MKA body should comprise basic parameter set and ICV */
if (mka_msg_len < MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN) {
@@ -2932,24 +3087,27 @@
ckn_len = body_len -
(sizeof(struct ieee802_1x_mka_basic_body) - MKA_HDR_LEN);
if (ckn_len < 1 || ckn_len > MAX_CKN_LEN) {
- wpa_printf(MSG_ERROR,
+ wpa_printf(MSG_WARNING,
"KaY: Received EAPOL-MKA CKN Length (%zu bytes) is out of range (<= %u bytes)",
ckn_len, MAX_CKN_LEN);
return -1;
}
+ ieee802_1x_mka_dump_basic_body(body);
+
/* CKN should be owned by I */
participant = ieee802_1x_kay_get_participant(kay, body->ckn, ckn_len);
if (!participant) {
- wpa_printf(MSG_DEBUG, "CKN is not included in my CA");
+ wpa_printf(MSG_DEBUG, "KaY: CKN is not included in my CA");
return -1;
}
/* algorithm agility check */
if (os_memcmp(body->algo_agility, mka_algo_agility,
sizeof(body->algo_agility)) != 0) {
- wpa_printf(MSG_ERROR,
- "KaY: peer's algorithm agility not supported for me");
+ wpa_printf(MSG_INFO,
+ "KaY: Peer's algorithm agility (%s) not supported",
+ algo_agility_txt(body->algo_agility));
return -1;
}
@@ -2959,23 +3117,29 @@
* its size, not the fixed length 16 octets, indicated by the EAPOL
* packet body length.
*/
- if (mka_alg_tbl[kay->mka_algindex].icv_hash(
- participant->ick.key,
+ if (len < mka_alg_tbl[kay->mka_algindex].icv_len ||
+ mka_alg_tbl[kay->mka_algindex].icv_hash(
+ participant->ick.key, participant->ick.len,
buf, len - mka_alg_tbl[kay->mka_algindex].icv_len, icv)) {
- wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
+ wpa_printf(MSG_ERROR, "KaY: Failed to calculate ICV");
return -1;
}
- msg_icv = ieee802_1x_mka_decode_icv_body(participant, (u8 *) mka_hdr,
+ msg_icv = ieee802_1x_mka_decode_icv_body(participant,
+ (const u8 *) mka_hdr,
mka_msg_len);
if (!msg_icv) {
- wpa_printf(MSG_ERROR, "KaY: No ICV");
+ wpa_printf(MSG_WARNING, "KaY: No ICV in MKPDU - ignore it");
return -1;
}
+ wpa_hexdump(MSG_DEBUG, "KaY: Received ICV",
+ msg_icv, mka_alg_tbl[kay->mka_algindex].icv_len);
if (os_memcmp_const(msg_icv, icv,
mka_alg_tbl[kay->mka_algindex].icv_len) != 0) {
- wpa_printf(MSG_ERROR,
+ wpa_printf(MSG_WARNING,
"KaY: Computed ICV is not equal to Received ICV");
+ wpa_hexdump(MSG_DEBUG, "KaY: Calculated ICV",
+ icv, mka_alg_tbl[kay->mka_algindex].icv_len);
return -1;
}
@@ -2991,13 +3155,19 @@
{
struct ieee802_1x_mka_participant *participant;
struct ieee802_1x_mka_hdr *hdr;
+ struct ieee802_1x_kay_peer *peer;
size_t body_len;
size_t left_len;
u8 body_type;
int i;
const u8 *pos;
Boolean handled[256];
+ Boolean bad_sak_use = FALSE; /* Error detected while processing SAK Use
+ * parameter set */
+ Boolean i_in_peerlist, is_in_live_peer, is_in_potential_peer;
+ wpa_printf(MSG_DEBUG, "KaY: Decode received MKPDU (ifname=%s)",
+ kay->if_name);
if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
return -1;
@@ -3011,17 +3181,24 @@
/* to skip basic parameter set */
hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
+ if (left_len < body_len + MKA_HDR_LEN)
+ return -1;
pos += body_len + MKA_HDR_LEN;
left_len -= body_len + MKA_HDR_LEN;
/* check i am in the peer's peer list */
- if (ieee802_1x_mka_i_in_peerlist(participant, pos, left_len) &&
- !ieee802_1x_kay_is_in_live_peer(participant,
- participant->current_peer_id.mi)) {
+ i_in_peerlist = ieee802_1x_mka_i_in_peerlist(participant, pos,
+ left_len);
+ is_in_live_peer = ieee802_1x_kay_is_in_live_peer(
+ participant, participant->current_peer_id.mi);
+ wpa_printf(MSG_DEBUG, "KaY: i_in_peerlist=%s is_in_live_peer=%s",
+ yes_no(i_in_peerlist), yes_no(is_in_live_peer));
+ if (i_in_peerlist && !is_in_live_peer) {
/* accept the peer as live peer */
- if (ieee802_1x_kay_is_in_potential_peer(
- participant, participant->current_peer_id.mi)) {
+ is_in_potential_peer = ieee802_1x_kay_is_in_potential_peer(
+ participant, participant->current_peer_id.mi);
+ if (is_in_potential_peer) {
if (!ieee802_1x_kay_move_live_peer(
participant,
participant->current_peer_id.mi,
@@ -3051,7 +3228,7 @@
pos += body_len + MKA_HDR_LEN,
left_len -= body_len + MKA_HDR_LEN) {
hdr = (struct ieee802_1x_mka_hdr *) pos;
- body_len = get_mka_param_body_len(hdr);
+ body_len = MKA_ALIGN_LENGTH(get_mka_param_body_len(hdr));
body_type = get_mka_param_body_type(hdr);
if (body_type == MKA_ICV_INDICATOR)
@@ -3065,21 +3242,103 @@
return -1;
}
- if (handled[body_type])
+ if (handled[body_type]) {
+ wpa_printf(MSG_DEBUG,
+ "KaY: Ignore duplicated body type %u",
+ body_type);
continue;
+ }
handled[body_type] = TRUE;
if (body_type < ARRAY_SIZE(mka_body_handler) &&
mka_body_handler[body_type].body_rx) {
- mka_body_handler[body_type].body_rx
- (participant, pos, left_len);
+ if (mka_body_handler[body_type].body_rx
+ (participant, pos, left_len) != 0) {
+ /* Handle parameter set failure */
+ if (body_type != MKA_SAK_USE) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: decode of parameter set type (%d) failed",
+ body_type);
+ return -1;
+ }
+
+ /* Ideally DIST-SAK should be processed before
+ * SAK-USE. Unfortunately IEEE Std 802.1X-2010,
+ * 11.11.3 (Encoding MKPDUs) states SAK-USE(3)
+ * must always be encoded before DIST-SAK(4).
+ * Rather than redesigning mka_body_handler so
+ * that it somehow processes DIST-SAK before
+ * SAK-USE, just ignore SAK-USE failures if
+ * DIST-SAK is also present in this MKPDU. */
+ bad_sak_use = TRUE;
+ }
} else {
wpa_printf(MSG_ERROR,
- "The type %d is not supported in this MKA version %d",
+ "KaY: The body type %d is not supported in this MKA version %d",
body_type, MKA_VERSION_ID);
}
}
+ if (bad_sak_use && !handled[MKA_DISTRIBUTED_SAK]) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: decode of parameter set type (%d) failed",
+ MKA_SAK_USE);
+ if (!reset_participant_mi(participant))
+ wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
+ else
+ wpa_printf(MSG_DEBUG,
+ "KaY: Selected a new random MI: %s",
+ mi_txt(participant->mi));
+ return -1;
+ }
+
+ /* Detect missing parameter sets */
+ peer = ieee802_1x_kay_get_live_peer(participant,
+ participant->current_peer_id.mi);
+ if (peer) {
+ /* MKPDU is from live peer */
+ if (!handled[MKA_SAK_USE]) {
+ /* Once a live peer starts sending SAK-USE, it should be
+ * sent every time. */
+ if (peer->sak_used) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: Live Peer stopped sending SAK-USE");
+ return -1;
+ }
+
+ /* Live peer is probably hung if it hasn't sent SAK-USE
+ * after a reasonable number of MKPDUs. Drop the MKPDU,
+ * which will eventually force an timeout. */
+ if (++peer->missing_sak_use_count >
+ MAX_MISSING_SAK_USE) {
+ wpa_printf(MSG_INFO,
+ "KaY: Discarding Rx MKPDU: Live Peer not sending SAK-USE");
+ return -1;
+ }
+ } else {
+ peer->missing_sak_use_count = 0;
+
+ /* Only update live peer watchdog after successful
+ * decode of all parameter sets */
+ peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
+ }
+ } else {
+ /* MKPDU is from new or potential peer */
+ peer = ieee802_1x_kay_get_peer(participant,
+ participant->current_peer_id.mi);
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "KaY: No peer entry found");
+ return -1;
+ }
+
+ /* Do not update potential peer watchdog. Per IEEE Std
+ * 802.1X-2010, 9.4.3, potential peers need to show liveness by
+ * including our MI/MN in their transmitted MKPDU (within
+ * potential or live parameter sets). Whena potential peer does
+ * include our MI/MN in an MKPDU, we respond by moving the peer
+ * from 'potential_peers' to 'live_peers'. */
+ }
+
kay->active = TRUE;
participant->retry_count = 0;
participant->active = TRUE;
@@ -3095,6 +3354,9 @@
struct ieee802_1x_kay *kay = ctx;
struct ieee8023_hdr *eth_hdr;
struct ieee802_1x_hdr *eapol_hdr;
+ size_t calc_len;
+
+ /* IEEE Std 802.1X-2010, 11.4 (Validation of received EAPOL PDUs) */
/* must contain at least ieee8023_hdr + ieee802_1x_hdr */
if (len < sizeof(*eth_hdr) + sizeof(*eapol_hdr)) {
@@ -3105,13 +3367,21 @@
eth_hdr = (struct ieee8023_hdr *) buf;
eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
- if (len != sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
- be_to_host16(eapol_hdr->length)) {
- wpa_printf(MSG_MSGDUMP, "KAY: EAPOL MPDU is invalid: (%lu-%lu)",
+ calc_len = sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
+ be_to_host16(eapol_hdr->length);
+ if (len < calc_len) {
+ wpa_printf(MSG_MSGDUMP, "KaY: EAPOL MPDU is invalid: (received len %lu, calculated len %lu, EAPOL length %u)",
(unsigned long) len,
- (unsigned long) be_to_host16(eapol_hdr->length));
+ (unsigned long) calc_len,
+ be_to_host16(eapol_hdr->length));
return;
}
+ if (len > calc_len) {
+ wpa_hexdump(MSG_DEBUG,
+ "KaY: Ignore extra octets following the Packey Body field",
+ &buf[calc_len], len - calc_len);
+ len = calc_len;
+ }
if (eapol_hdr->version < EAPOL_VERSION) {
wpa_printf(MSG_MSGDUMP, "KaY: version %d does not support MKA",
@@ -3120,11 +3390,12 @@
}
if (be_to_host16(eth_hdr->ethertype) != ETH_P_PAE ||
eapol_hdr->type != IEEE802_1X_TYPE_EAPOL_MKA)
- return;
+ return; /* ignore other EAPOL types silently here */
- wpa_hexdump(MSG_DEBUG, "RX EAPOL-MKA: ", buf, len);
+ wpa_hexdump(MSG_DEBUG, "KaY: RX EAPOL-MKA", buf, len);
if (dl_list_empty(&kay->participant_list)) {
- wpa_printf(MSG_ERROR, "KaY: no MKA participant instance");
+ wpa_printf(MSG_ERROR,
+ "KaY: No MKA participant instance - ignore EAPOL-MKA");
return;
}
@@ -3137,10 +3408,14 @@
*/
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
+ Boolean macsec_replay_protect, u32 macsec_replay_window,
u16 port, u8 priority, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
+ wpa_printf(MSG_DEBUG, "KaY: Initialize - ifname=%s addr=" MACSTR
+ " port=%u priority=%u",
+ ifname, MAC2STR(addr), port, priority);
kay = os_zalloc(sizeof(*kay));
if (!kay) {
wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
@@ -3161,6 +3436,8 @@
os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
kay->actor_sci.port = host_to_be16(port ? port : 0x0001);
+ wpa_printf(MSG_DEBUG, "KaY: Generated SCI: %s",
+ sci_txt(&kay->actor_sci));
kay->actor_priority = priority;
/* While actor acts as a key server, shall distribute sakey */
@@ -3187,21 +3464,27 @@
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
kay->macsec_desired = FALSE;
kay->macsec_protect = FALSE;
+ kay->macsec_encrypt = FALSE;
kay->macsec_validate = Disabled;
kay->macsec_replay_protect = FALSE;
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
+ kay->mka_hello_time = MKA_HELLO_TIME;
} else {
kay->macsec_desired = TRUE;
kay->macsec_protect = TRUE;
- kay->macsec_encrypt = policy == SHOULD_ENCRYPT;
- kay->macsec_validate = Strict;
- kay->macsec_replay_protect = FALSE;
- kay->macsec_replay_window = 0;
- if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF)
+ if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF &&
+ policy == SHOULD_ENCRYPT) {
+ kay->macsec_encrypt = TRUE;
kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
- else
+ } else { /* SHOULD_SECURE */
+ kay->macsec_encrypt = FALSE;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
+ }
+ kay->macsec_validate = Strict;
+ kay->macsec_replay_protect = macsec_replay_protect;
+ kay->macsec_replay_window = macsec_replay_window;
+ kay->mka_hello_time = MKA_HELLO_TIME;
}
wpa_printf(MSG_DEBUG, "KaY: state machine created");
@@ -3273,6 +3556,19 @@
}
+static const char * mode_txt(enum mka_created_mode mode)
+{
+ switch (mode) {
+ case PSK:
+ return "PSK";
+ case EAP_EXCHANGE:
+ return "EAP";
+ }
+
+ return "?";
+}
+
+
/**
* ieee802_1x_kay_create_mka -
*/
@@ -3285,17 +3581,22 @@
struct ieee802_1x_mka_participant *participant;
unsigned int usecs;
+ wpa_printf(MSG_DEBUG,
+ "KaY: Create MKA (ifname=%s mode=%s authenticator=%s)",
+ kay->if_name, mode_txt(mode), yes_no(is_authenticator));
+
if (!kay || !ckn || !cak) {
wpa_printf(MSG_ERROR, "KaY: ckn or cak is null");
return NULL;
}
- if (cak->len != mka_alg_tbl[kay->mka_algindex].cak_len) {
- wpa_printf(MSG_ERROR, "KaY: CAK length not follow key schema");
+ if (cak->len != 16 && cak->len != 32) {
+ wpa_printf(MSG_ERROR, "KaY: Unexpected CAK length %u",
+ (unsigned int) cak->len);
return NULL;
}
if (ckn->len > MAX_CKN_LEN) {
- wpa_printf(MSG_ERROR, "KaY: CKN is out of range(<=32 bytes)");
+ wpa_printf(MSG_ERROR, "KaY: CKN is out of range (>32 bytes)");
return NULL;
}
if (!kay->enable) {
@@ -3311,8 +3612,12 @@
participant->ckn.len = ckn->len;
os_memcpy(participant->ckn.name, ckn->name, ckn->len);
+ wpa_hexdump(MSG_DEBUG, "KaY: CKN", participant->ckn.name,
+ participant->ckn.len);
participant->cak.len = cak->len;
os_memcpy(participant->cak.key, cak->key, cak->len);
+ wpa_hexdump_key(MSG_DEBUG, "KaY: CAK", participant->cak.key,
+ participant->cak.len);
if (life)
participant->cak_life = life + time(NULL);
@@ -3362,6 +3667,8 @@
if (!reset_participant_mi(participant))
goto fail;
+ wpa_printf(MSG_DEBUG, "KaY: Selected random MI: %s",
+ mi_txt(participant->mi));
participant->lrx = FALSE;
participant->ltx = FALSE;
@@ -3377,37 +3684,40 @@
secy_cp_control_protect_frames(kay, kay->macsec_protect);
secy_cp_control_replay(kay, kay->macsec_replay_protect,
kay->macsec_replay_window);
- secy_create_transmit_sc(kay, participant->txsc);
+ if (secy_create_transmit_sc(kay, participant->txsc))
+ goto fail;
/* to derive KEK from CAK and CKN */
- participant->kek.len = mka_alg_tbl[kay->mka_algindex].kek_len;
+ participant->kek.len = participant->cak.len;
if (mka_alg_tbl[kay->mka_algindex].kek_trfm(participant->cak.key,
+ participant->cak.len,
participant->ckn.name,
participant->ckn.len,
- participant->kek.key)) {
- wpa_printf(MSG_ERROR, "KaY: Derived KEK failed");
+ participant->kek.key,
+ participant->kek.len)) {
+ wpa_printf(MSG_ERROR, "KaY: KEK derivation failed");
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "KaY: Derived KEK",
participant->kek.key, participant->kek.len);
/* to derive ICK from CAK and CKN */
- participant->ick.len = mka_alg_tbl[kay->mka_algindex].ick_len;
+ participant->ick.len = participant->cak.len;
if (mka_alg_tbl[kay->mka_algindex].ick_trfm(participant->cak.key,
+ participant->cak.len,
participant->ckn.name,
participant->ckn.len,
- participant->ick.key)) {
- wpa_printf(MSG_ERROR, "KaY: Derived ICK failed");
+ participant->ick.key,
+ participant->ick.len)) {
+ wpa_printf(MSG_ERROR, "KaY: ICK derivation failed");
goto fail;
}
wpa_hexdump_key(MSG_DEBUG, "KaY: Derived ICK",
participant->ick.key, participant->ick.len);
dl_list_add(&kay->participant_list, &participant->list);
- wpa_hexdump(MSG_DEBUG, "KaY: Participant created:",
- ckn->name, ckn->len);
- usecs = os_random() % (MKA_HELLO_TIME * 1000);
+ usecs = os_random() % (kay->mka_hello_time * 1000);
eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
participant, NULL);
@@ -3425,6 +3735,7 @@
return participant;
fail:
+ os_free(participant->txsc);
os_free(participant);
return NULL;
}
@@ -3580,6 +3891,7 @@
#ifdef CONFIG_CTRL_IFACE
+
/**
* ieee802_1x_kay_get_status - Get IEEE 802.1X KaY status details
* @sm: Pointer to KaY allocated with ieee802_1x_kay_init()
@@ -3588,19 +3900,24 @@
* @verbose: Whether to include verbose status information
* Returns: Number of bytes written to buf.
*
- * Query KAY status information. This function fills in a text area with current
+ * Query KaY status information. This function fills in a text area with current
* status information. If the buffer (buf) is not large enough, status
* information will be truncated to fit the buffer.
*/
int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
size_t buflen)
{
- int len;
+ char *pos, *end;
+ int res, count;
+ struct ieee802_1x_mka_participant *p;
if (!kay)
return 0;
- len = os_snprintf(buf, buflen,
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos,
"PAE KaY status=%s\n"
"Authenticated=%s\n"
"Secured=%s\n"
@@ -3609,7 +3926,8 @@
"Key Server Priority=%u\n"
"Is Key Server=%s\n"
"Number of Keys Distributed=%u\n"
- "Number of Keys Received=%u\n",
+ "Number of Keys Received=%u\n"
+ "MKA Hello Time=%u\n",
kay->active ? "Active" : "Not-Active",
kay->authenticated ? "Yes" : "No",
kay->secured ? "Yes" : "No",
@@ -3618,10 +3936,162 @@
kay->key_server_priority,
kay->is_key_server ? "Yes" : "No",
kay->dist_kn - 1,
- kay->rcvd_keys);
- if (os_snprintf_error(buflen, len))
+ kay->rcvd_keys,
+ kay->mka_hello_time);
+ if (os_snprintf_error(buflen, res))
+ return 0;
+ pos += res;
+
+ res = os_snprintf(pos, end - pos,
+ "actor_sci=%s\n", sci_txt(&kay->actor_sci));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos += res;
+
+ res = os_snprintf(pos, end - pos,
+ "key_server_sci=%s\n", sci_txt(&kay->key_server_sci));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos += res;
+
+ count = 0;
+ dl_list_for_each(p, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ char *pos2 = pos;
+
+ res = os_snprintf(pos2, end - pos2, "participant_idx=%d\nckn=",
+ count);
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ count++;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, p->ckn.name,
+ p->ckn.len);
+
+ res = os_snprintf(pos2, end - pos2,
+ "\nmi=%s\n"
+ "mn=%u\n"
+ "active=%s\n"
+ "participant=%s\n"
+ "retain=%s\n"
+ "live_peers=%u\n"
+ "potential_peers=%u\n"
+ "is_key_server=%s\n"
+ "is_elected=%s\n",
+ mi_txt(p->mi), p->mn,
+ yes_no(p->active),
+ yes_no(p->participant),
+ yes_no(p->retain),
+ dl_list_len(&p->live_peers),
+ dl_list_len(&p->potential_peers),
+ yes_no(p->is_key_server),
+ yes_no(p->is_elected));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ pos = pos2;
+ }
+
+ return pos - buf;
+}
+
+
+static const char * true_false(Boolean val)
+{
+ return val ? "true" : "false";
+}
+
+
+static const char * activate_control_txt(enum activate_ctrl activate)
+{
+ switch (activate) {
+ case DEFAULT:
+ return "default";
+ case DISABLED:
+ return "disabled";
+ case ON_OPER_UP:
+ return "onOperUp";
+ case ALWAYS:
+ return "always";
+ }
+
+ return "?";
+}
+
+
+static char * mka_mib_peer(struct dl_list *peers, Boolean live, char *buf,
+ char *end)
+{
+ char *pos = buf;
+ struct ieee802_1x_kay_peer *p;
+ int res;
+
+ dl_list_for_each(p, peers, struct ieee802_1x_kay_peer, list) {
+ res = os_snprintf(pos, end - pos,
+ "ieee8021XKayMkaPeerListMI=%s\n"
+ "ieee8021XKayMkaPeerListMN=%u\n"
+ "ieee8021XKayMkaPeerListType=%u\n"
+ "ieee8021XKayMkaPeerListSCI=%s\n",
+ mi_txt(p->mi),
+ p->mn,
+ live ? 1 : 2,
+ sci_txt(&p->sci));
+ if (os_snprintf_error(end - pos, res))
+ return pos;
+ pos += res;
+ }
+
+ return pos;
+}
+
+
+int ieee802_1x_kay_get_mib(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen)
+{
+ char *pos, *end;
+ int res;
+ struct ieee802_1x_mka_participant *p;
+
+ if (!kay)
return 0;
- return len;
+ pos = buf;
+ end = buf + buflen;
+
+ dl_list_for_each(p, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ char *pos2 = pos;
+
+ res = os_snprintf(pos2, end - pos2, "ieee8021XKayMkaPartCKN=");
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, p->ckn.name,
+ p->ckn.len);
+
+ res = os_snprintf(pos2, end - pos2,
+ "\nieee8021XKayMkaPartCached=%s\n"
+ "ieee8021XKayMkaPartActive=%s\n"
+ "ieee8021XKayMkaPartRetain=%s\n"
+ "ieee8021XKayMkaPartActivateControl=%s\n"
+ "ieee8021XKayMkaPartPrincipal=%s\n",
+ true_false(p->cached),
+ true_false(p->active),
+ true_false(p->retain),
+ activate_control_txt(p->activate),
+ true_false(p->principal));
+ if (os_snprintf_error(buflen, res))
+ return end - pos;
+ pos2 += res;
+ pos = pos2;
+
+ pos = mka_mib_peer(&p->live_peers, TRUE, pos, end);
+ pos = mka_mib_peer(&p->potential_peers, FALSE, pos, end);
+ }
+
+ return pos - buf;
}
+
#endif /* CONFIG_CTRL_IFACE */
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index b265059..3367d3a 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -21,6 +21,7 @@
/* MKA timer, unit: millisecond */
#define MKA_HELLO_TIME 2000
+#define MKA_BOUNDED_HELLO_TIME 500
#define MKA_LIFE_TIME 6000
#define MKA_SAK_RETIRE_TIME 3000
@@ -38,7 +39,7 @@
struct ieee802_1x_mka_sci {
u8 addr[ETH_ALEN];
be16 port;
-};
+} STRUCT_PACKED;
struct mka_key {
u8 key[MAX_KEY_LEN];
@@ -149,6 +150,7 @@
int (*get_receive_lowest_pn)(void *ctx, struct receive_sa *sa);
int (*get_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
int (*set_transmit_next_pn)(void *ctx, struct transmit_sa *sa);
+ int (*set_receive_lowest_pn)(void *ctx, struct receive_sa *sa);
int (*create_receive_sc)(void *ctx, struct receive_sc *sc,
enum validate_frames vf,
enum confidentiality_offset co);
@@ -187,6 +189,7 @@
u32 macsec_replay_window;
enum validate_frames macsec_validate;
enum confidentiality_offset macsec_confidentiality;
+ u32 mka_hello_time;
u32 ltx_kn;
u8 ltx_an;
@@ -236,6 +239,7 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
+ Boolean macsec_replay_protect, u32 macsec_replay_window,
u16 port, u8 priority, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
@@ -271,5 +275,7 @@
int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay);
int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
size_t buflen);
+int ieee802_1x_kay_get_mib(struct ieee802_1x_kay *kay, char *buf,
+ size_t buflen);
#endif /* IEEE802_1X_KAY_H */
diff --git a/src/pae/ieee802_1x_kay_i.h b/src/pae/ieee802_1x_kay_i.h
index bc522d8..1d1589c 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -15,7 +15,7 @@
#define MKA_VERSION_ID 1
-/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 */
+/* IEEE Std 802.1X-2010, 11.11.1, Table 11-7 (MKPDU parameter sets) */
enum mka_packet_type {
MKA_BASIC_PARAMETER_SET = MKA_VERSION_ID,
MKA_LIVE_PEER_LIST = 1,
@@ -51,6 +51,7 @@
Boolean macsec_desired;
enum macsec_cap macsec_capability;
Boolean sak_used;
+ int missing_sak_use_count;
struct dl_list list;
};
@@ -59,25 +60,24 @@
char name[32];
enum macsec_cap capable;
int sak_len; /* unit: byte */
-
- u32 index;
};
struct mka_alg {
u8 parameter[4];
- size_t cak_len;
- size_t kek_len;
- size_t ick_len;
size_t icv_len;
- int (*cak_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2, u8 *cak);
- int (*ckn_trfm)(const u8 *msk, const u8 *mac1, const u8 *mac2,
- const u8 *sid, size_t sid_len, u8 *ckn);
- int (*kek_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *kek);
- int (*ick_trfm)(const u8 *cak, const u8 *ckn, size_t ckn_len, u8 *ick);
- int (*icv_hash)(const u8 *ick, const u8 *msg, size_t msg_len, u8 *icv);
-
- int index; /* index for configuring */
+ int (*cak_trfm)(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes);
+ int (*ckn_trfm)(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid, size_t sid_len, u8 *ckn);
+ int (*kek_trfm)(const u8 *cak, size_t cak_bytes,
+ const u8 *ckn, size_t ckn_len,
+ u8 *kek, size_t kek_bytes);
+ int (*ick_trfm)(const u8 *cak, size_t cak_bytes,
+ const u8 *ckn, size_t ckn_len,
+ u8 *ick, size_t ick_bytes);
+ int (*icv_hash)(const u8 *ick, size_t ick_bytes,
+ const u8 *msg, size_t msg_len, u8 *icv);
};
#define DEFAULT_MKA_ALG_INDEX 0
@@ -95,7 +95,7 @@
Boolean retain;
enum mka_created_mode mode;
- enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
+ enum activate_ctrl { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
/* used for active participant */
Boolean principal;
@@ -131,8 +131,10 @@
u8 mi[MI_LEN];
u32 mn;
+ /* Current peer MI and SCI during MKPDU processing */
struct ieee802_1x_mka_peer_id current_peer_id;
struct ieee802_1x_mka_sci current_peer_sci;
+
time_t cak_life;
time_t mka_life;
Boolean to_dist_sak;
@@ -165,7 +167,7 @@
#endif
/* octet 4 */
u8 length1;
-};
+} STRUCT_PACKED;
#define MKA_HDR_LEN sizeof(struct ieee802_1x_mka_hdr)
@@ -210,9 +212,9 @@
be32 actor_mn;
u8 algo_agility[4];
- /* followed by CAK Name*/
+ /* followed by CAK Name */
u8 ckn[0];
-};
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_peer_body - Live Peer List and Potential Peer List
@@ -238,9 +240,9 @@
/* octet 4 */
u8 length1;
- u8 peer[0];
/* followed by Peers */
-};
+ u8 peer[0];
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_sak_use_body - MACsec SAK Use parameter set (Figure
@@ -315,7 +317,7 @@
be32 okn;
/* octet 41 - 44 */
be32 olpn;
-};
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_dist_sak_body - Distributed SAK parameter set
@@ -362,7 +364,7 @@
* for other cipher suite: octet 9-16: cipher suite id, octet 17-: SAK
*/
u8 sak[0];
-};
+} STRUCT_PACKED;
/**
* struct ieee802_1x_mka_dist_cak_body - Distributed CAK parameter set (Figure
@@ -398,7 +400,7 @@
/* followed by CAK Name, 29- */
u8 ckn[0];
-};
+} STRUCT_PACKED;
struct ieee802_1x_mka_icv_body {
/* octet 1 */
@@ -418,6 +420,6 @@
/* octet 5 - */
u8 icv[0];
-};
+} STRUCT_PACKED;
#endif /* IEEE802_1X_KAY_I_H */
diff --git a/src/pae/ieee802_1x_key.c b/src/pae/ieee802_1x_key.c
index 9a8d923..d63ca7f 100644
--- a/src/pae/ieee802_1x_key.c
+++ b/src/pae/ieee802_1x_key.c
@@ -31,8 +31,9 @@
/* IEEE Std 802.1X-2010, 6.2.1 KDF */
-static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context,
- int ctx_bits, int ret_bits, u8 *ret)
+static int aes_kdf(const u8 *kdk, size_t kdk_bits,
+ const char *label, const u8 *context,
+ int ctx_bits, int ret_bits, u8 *ret)
{
const int h = 128;
const int r = 8;
@@ -40,6 +41,9 @@
int lab_len, ctx_len, ret_len, buf_len;
u8 *buf;
+ if (kdk_bits != 128 && kdk_bits != 256)
+ return -1;
+
lab_len = os_strlen(label);
ctx_len = (ctx_bits + 7) / 8;
ret_len = ((ret_bits & 0xffff) + 7) / 8;
@@ -60,8 +64,14 @@
WPA_PUT_BE16(&buf[buf_len - 2], ret_bits);
for (i = 0; i < n; i++) {
+ int res;
+
buf[0] = (u8) (i + 1);
- if (omac1_aes_128(kdk, buf, buf_len, ret)) {
+ if (kdk_bits == 128)
+ res = omac1_aes_128(kdk, buf, buf_len, ret);
+ else
+ res = omac1_aes_256(kdk, buf, buf_len, ret);
+ if (res) {
os_free(buf);
return -1;
}
@@ -72,33 +82,32 @@
}
-/********** AES-CMAC-128 **********/
/**
- * ieee802_1x_cak_128bits_aes_cmac
+ * ieee802_1x_cak_aes_cmac
*
* IEEE Std 802.1X-2010, 6.2.2
* CAK = KDF(Key, Label, mac1 | mac2, CAKlength)
*/
-int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, u8 *cak)
+int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes)
{
u8 context[2 * ETH_ALEN];
joint_two_mac(mac1, mac2, context);
- return aes_kdf_128(msk, "IEEE8021 EAP CAK",
- context, sizeof(context) * 8, 128, cak);
+ return aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CAK",
+ context, sizeof(context) * 8, 8 * cak_bytes, cak);
}
/**
- * ieee802_1x_ckn_128bits_aes_cmac
+ * ieee802_1x_ckn_aes_cmac
*
* IEEE Std 802.1X-2010, 6.2.2
* CKN = KDF(Key, Label, ID | mac1 | mac2, CKNlength)
*/
-int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, const u8 *sid,
- size_t sid_bytes, u8 *ckn)
+int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid,
+ size_t sid_bytes, u8 *ckn)
{
int res;
u8 *context;
@@ -112,21 +121,21 @@
os_memcpy(context, sid, sid_bytes);
joint_two_mac(mac1, mac2, context + sid_bytes);
- res = aes_kdf_128(msk, "IEEE8021 EAP CKN", context, ctx_len * 8,
- 128, ckn);
+ res = aes_kdf(msk, 8 * msk_bytes, "IEEE8021 EAP CKN",
+ context, ctx_len * 8, 128, ckn);
os_free(context);
return res;
}
/**
- * ieee802_1x_kek_128bits_aes_cmac
+ * ieee802_1x_kek_aes_cmac
*
* IEEE Std 802.1X-2010, 9.3.3
* KEK = KDF(Key, Label, Keyid, KEKLength)
*/
-int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *kek)
+int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *kek, size_t kek_bytes)
{
u8 context[16];
@@ -134,19 +143,20 @@
os_memset(context, 0, sizeof(context));
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
- return aes_kdf_128(cak, "IEEE8021 KEK", context, sizeof(context) * 8,
- 128, kek);
+ return aes_kdf(cak, 8 * cak_bytes, "IEEE8021 KEK",
+ context, sizeof(context) * 8,
+ 8 * kek_bytes, kek);
}
/**
- * ieee802_1x_ick_128bits_aes_cmac
+ * ieee802_1x_ick_aes_cmac
*
* IEEE Std 802.1X-2010, 9.3.3
* ICK = KDF(Key, Label, Keyid, ICKLength)
*/
-int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *ick)
+int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *ick, size_t ick_bytes)
{
u8 context[16];
@@ -154,22 +164,32 @@
os_memset(context, 0, sizeof(context));
os_memcpy(context, ckn, (ckn_bytes < 16) ? ckn_bytes : 16);
- return aes_kdf_128(cak, "IEEE8021 ICK", context, sizeof(context) * 8,
- 128, ick);
+ return aes_kdf(cak, 8 *cak_bytes, "IEEE8021 ICK",
+ context, sizeof(context) * 8,
+ 8 * ick_bytes, ick);
}
/**
- * ieee802_1x_icv_128bits_aes_cmac
+ * ieee802_1x_icv_aes_cmac
*
* IEEE Std 802.1X-2010, 9.4.1
* ICV = AES-CMAC(ICK, M, 128)
*/
-int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
- size_t msg_bytes, u8 *icv)
+int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
+ size_t msg_bytes, u8 *icv)
{
- if (omac1_aes_128(ick, msg, msg_bytes, icv)) {
- wpa_printf(MSG_ERROR, "MKA: omac1_aes_128 failed");
+ int res;
+
+ if (ick_bytes == 16)
+ res = omac1_aes_128(ick, msg, msg_bytes, icv);
+ else if (ick_bytes == 32)
+ res = omac1_aes_256(ick, msg, msg_bytes, icv);
+ else
+ return -1;
+ if (res) {
+ wpa_printf(MSG_ERROR,
+ "MKA: AES-CMAC failed for ICV calculation");
return -1;
}
return 0;
@@ -177,13 +197,14 @@
/**
- * ieee802_1x_sak_128bits_aes_cmac
+ * ieee802_1x_sak_aes_cmac
*
* IEEE Std 802.1X-2010, 9.8.1
* SAK = KDF(Key, Label, KS-nonce | MI-value list | KN, SAKLength)
*/
-int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
- size_t ctx_bytes, u8 *sak)
+int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+ size_t ctx_bytes, u8 *sak, size_t sak_bytes)
{
- return aes_kdf_128(cak, "IEEE8021 SAK", ctx, ctx_bytes * 8, 128, sak);
+ return aes_kdf(cak, cak_bytes * 8, "IEEE8021 SAK", ctx, ctx_bytes * 8,
+ sak_bytes * 8, sak);
}
diff --git a/src/pae/ieee802_1x_key.h b/src/pae/ieee802_1x_key.h
index ea318ea..1f9058d 100644
--- a/src/pae/ieee802_1x_key.h
+++ b/src/pae/ieee802_1x_key.h
@@ -9,18 +9,18 @@
#ifndef IEEE802_1X_KEY_H
#define IEEE802_1X_KEY_H
-int ieee802_1x_cak_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, u8 *cak);
-int ieee802_1x_ckn_128bits_aes_cmac(const u8 *msk, const u8 *mac1,
- const u8 *mac2, const u8 *sid,
- size_t sid_bytes, u8 *ckn);
-int ieee802_1x_kek_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *kek);
-int ieee802_1x_ick_128bits_aes_cmac(const u8 *cak, const u8 *ckn,
- size_t ckn_bytes, u8 *ick);
-int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg,
- size_t msg_bytes, u8 *icv);
-int ieee802_1x_sak_128bits_aes_cmac(const u8 *cak, const u8 *ctx,
- size_t ctx_bytes, u8 *sak);
+int ieee802_1x_cak_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, u8 *cak, size_t cak_bytes);
+int ieee802_1x_ckn_aes_cmac(const u8 *msk, size_t msk_bytes, const u8 *mac1,
+ const u8 *mac2, const u8 *sid,
+ size_t sid_bytes, u8 *ckn);
+int ieee802_1x_kek_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *kek, size_t kek_bytes);
+int ieee802_1x_ick_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ckn,
+ size_t ckn_bytes, u8 *ick, size_t ick_bytes);
+int ieee802_1x_icv_aes_cmac(const u8 *ick, size_t ick_bytes, const u8 *msg,
+ size_t msg_bytes, u8 *icv);
+int ieee802_1x_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx,
+ size_t ctx_bytes, u8 *sak, size_t sak_bytes);
#endif /* IEEE802_1X_KEY_H */
diff --git a/src/pae/ieee802_1x_secy_ops.c b/src/pae/ieee802_1x_secy_ops.c
index ab5339b..84ee42b 100644
--- a/src/pae/ieee802_1x_secy_ops.c
+++ b/src/pae/ieee802_1x_secy_ops.c
@@ -187,7 +187,7 @@
ops = kay->ctx;
if (!ops || !ops->get_transmit_next_pn) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_receive_lowest_pn operation not supported");
+ "KaY: secy get_transmit_next_pn operation not supported");
return -1;
}
@@ -208,7 +208,7 @@
ops = kay->ctx;
if (!ops || !ops->set_transmit_next_pn) {
wpa_printf(MSG_ERROR,
- "KaY: secy get_receive_lowest_pn operation not supported");
+ "KaY: secy set_transmit_next_pn operation not supported");
return -1;
}
@@ -216,6 +216,27 @@
}
+int secy_set_receive_lowest_pn(struct ieee802_1x_kay *kay,
+ struct receive_sa *rxsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !rxsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->set_receive_lowest_pn) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy set_receive_lowest_pn operation not supported");
+ return -1;
+ }
+
+ return ops->set_receive_lowest_pn(ops->ctx, rxsa);
+}
+
+
int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc)
{
struct ieee802_1x_kay_ctx *ops;
diff --git a/src/pae/ieee802_1x_secy_ops.h b/src/pae/ieee802_1x_secy_ops.h
index 9fb29c3..2d112ba 100644
--- a/src/pae/ieee802_1x_secy_ops.h
+++ b/src/pae/ieee802_1x_secy_ops.h
@@ -36,6 +36,8 @@
struct transmit_sa *txsa);
int secy_set_transmit_next_pn(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
+int secy_set_receive_lowest_pn(struct ieee802_1x_kay *kay,
+ struct receive_sa *txsa);
int secy_create_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
int secy_delete_receive_sc(struct ieee802_1x_kay *kay, struct receive_sc *rxsc);
int secy_create_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index a87ee74..a3db404 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -26,12 +26,12 @@
#define RADIUS_CLIENT_MAX_WAIT 120
/**
- * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
+ * RADIUS_CLIENT_MAX_FAILOVER - RADIUS client maximum retries
*
- * Maximum number of retransmit attempts before the entry is removed from
+ * Maximum number of server failovers before the entry is removed from
* retransmit list.
*/
-#define RADIUS_CLIENT_MAX_RETRIES 10
+#define RADIUS_CLIENT_MAX_FAILOVER 3
/**
* RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
@@ -110,11 +110,16 @@
os_time_t next_try;
/**
- * attempts - Number of transmission attempts
+ * attempts - Number of transmission attempts for one server
*/
int attempts;
/**
+ * accu_attempts - Number of accumulated attempts
+ */
+ int accu_attempts;
+
+ /**
* next_wait - Next retransmission wait time in seconds
*/
int next_wait;
@@ -367,9 +372,11 @@
size_t prev_num_msgs;
u8 *acct_delay_time;
size_t acct_delay_time_len;
+ int num_servers;
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM) {
+ num_servers = conf->num_acct_servers;
if (radius->acct_sock < 0)
radius_client_init_acct(radius);
if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
@@ -386,6 +393,7 @@
conf->acct_server->retransmissions++;
}
} else {
+ num_servers = conf->num_auth_servers;
if (radius->auth_sock < 0)
radius_client_init_auth(radius);
if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
@@ -449,7 +457,15 @@
}
/* retransmit; remove entry if too many attempts */
+ if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
+ RADIUS_CLIENT_NUM_FAILOVER * num_servers) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
+ return 1;
+ }
+
entry->attempts++;
+ entry->accu_attempts++;
hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
radius_msg_get_hdr(entry->msg)->identifier);
@@ -466,10 +482,6 @@
entry->next_wait *= 2;
if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
- if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
- wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
- return 1;
- }
return 0;
}
@@ -490,6 +502,30 @@
return;
os_get_reltime(&now);
+
+ while (entry) {
+ if (now.sec >= entry->next_try) {
+ s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
+ radius->acct_sock;
+ if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
+ (s < 0 && entry->attempts > 0)) {
+ if (entry->msg_type == RADIUS_ACCT ||
+ entry->msg_type == RADIUS_ACCT_INTERIM)
+ acct_failover++;
+ else
+ auth_failover++;
+ }
+ }
+ entry = entry->next;
+ }
+
+ if (auth_failover)
+ radius_client_auth_failover(radius);
+
+ if (acct_failover)
+ radius_client_acct_failover(radius);
+
+ entry = radius->msgs;
first = 0;
prev = NULL;
@@ -517,17 +553,6 @@
continue;
}
- s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
- radius->acct_sock;
- if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
- (s < 0 && entry->attempts > 0)) {
- if (entry->msg_type == RADIUS_ACCT ||
- entry->msg_type == RADIUS_ACCT_INTERIM)
- acct_failover++;
- else
- auth_failover++;
- }
-
if (first == 0 || entry->next_try < first)
first = entry->next_try;
@@ -538,6 +563,7 @@
if (radius->msgs) {
if (first < now.sec)
first = now.sec;
+ eloop_cancel_timeout(radius_client_timer, radius, NULL);
eloop_register_timeout(first - now.sec, 0,
radius_client_timer, radius, NULL);
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
@@ -545,12 +571,6 @@
"retransmit in %ld seconds",
(long int) (first - now.sec));
}
-
- if (auth_failover)
- radius_client_auth_failover(radius);
-
- if (acct_failover)
- radius_client_acct_failover(radius);
}
@@ -674,7 +694,10 @@
entry->first_try = entry->last_attempt.sec;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
entry->attempts = 1;
+ entry->accu_attempts = 1;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+ if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
+ entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
entry->next = radius->msgs;
radius->msgs = entry;
radius_client_update_timeout(radius);
@@ -713,9 +736,9 @@
*
* The message is added on the retransmission queue and will be retransmitted
* automatically until a response is received or maximum number of retries
- * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
- * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
- * automatically on transmission failure.
+ * (RADIUS_CLIENT_MAX_FAILOVER * RADIUS_CLIENT_NUM_FAILOVER) is reached. No
+ * such retries are used with RADIUS_ACCT_INTERIM, i.e., such a pending message
+ * is removed from the queue automatically on transmission failure.
*
* The related device MAC address can be used to identify pending messages that
* can be removed with radius_client_flush_auth().
@@ -1087,14 +1110,13 @@
}
}
- /* Reset retry counters for the new server */
- for (entry = radius->msgs; oserv && oserv != nserv && entry;
- entry = entry->next) {
+ /* Reset retry counters */
+ for (entry = radius->msgs; oserv && entry; entry = entry->next) {
if ((auth && entry->msg_type != RADIUS_AUTH) ||
(!auth && entry->msg_type != RADIUS_ACCT))
continue;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
- entry->attempts = 0;
+ entry->attempts = 1;
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index e3afc0d..aa78cba 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -357,6 +357,7 @@
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
char *t_c_server_url;
@@ -380,6 +381,44 @@
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);
@@ -866,6 +905,117 @@
}
+#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,
@@ -979,6 +1129,48 @@
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) {
@@ -2173,6 +2365,9 @@
os_strdup(conf->subscr_remediation_url);
}
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 (conf->t_c_server_url)
data->t_c_server_url = os_strdup(conf->t_c_server_url);
@@ -2293,6 +2488,7 @@
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
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 167bbf5..53728f9 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -233,6 +233,7 @@
char *subscr_remediation_url;
u8 subscr_remediation_method;
+ char *hs20_sim_provisioning_url;
char *t_c_server_url;
};
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 14b346a..345b0c8 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -2159,11 +2159,11 @@
eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout,
sm, peer);
#ifdef CONFIG_TDLS_TESTING
- if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
- wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK "
- "expiration");
- eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
- }
+ if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Testing - disable TPK expiration");
+ eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
+ }
#endif /* CONFIG_TDLS_TESTING */
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 72a2d66..52aa766 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -20,8 +20,10 @@
#include "crypto/sha512.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "drivers/driver.h"
#include "wpa.h"
#include "eloop.h"
#include "preauth.h"
@@ -618,6 +620,33 @@
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in EAPOL-Key 2/4");
+ goto failed;
+ }
+
+ kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
+ if (!kde_buf) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
+ goto failed;
+ }
+
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
+ pos = kde + kde_len;
+ if (ocv_insert_oci_kde(&ci, &pos) < 0)
+ goto failed;
+ kde_len = pos - kde;
+ }
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_P2P
if (sm->p2p) {
kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
@@ -686,7 +715,9 @@
* likelihood of the first preauth EAPOL-Start frame getting to
* the target AP.
*/
- eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
+ if (!dl_list_empty(&sm->pmksa_candidates))
+ eloop_register_timeout(1, 0, wpa_sm_start_preauth,
+ sm, NULL);
}
if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
@@ -1418,6 +1449,26 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in EAPOL-Key 3/4");
+ return;
+ }
+
+ if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
&sm->ptk) < 0) {
goto failed;
@@ -1511,6 +1562,26 @@
}
maxkeylen = gd->gtk_len = ie.gtk_len - 2;
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in EAPOL-Key group msg 1/2");
+ return -1;
+ }
+
+ if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
+ ocv_errorstr);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
gd->gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
@@ -1631,11 +1702,17 @@
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
u8 *rbuf, *key_mic;
+ size_t kde_len = 0;
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm))
+ kde_len = OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- hdrlen, &rlen, (void *) &reply);
+ hdrlen + kde_len, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
@@ -1657,7 +1734,27 @@
WPA_REPLAY_COUNTER_LEN);
key_mic = (u8 *) (reply + 1);
- WPA_PUT_BE16(key_mic + mic_len, 0);
+ WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in EAPOL-Key 2/2");
+ os_free(rbuf);
+ return -1;
+ }
+
+ pos = key_mic + mic_len + 2; /* Key Data */
+ if (ocv_insert_oci_kde(&ci, &pos) < 0) {
+ os_free(rbuf);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL,
@@ -1755,7 +1852,15 @@
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
} else {
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
ok = 1;
sm->tptk_set = 0;
sm->ptk_set = 1;
@@ -1781,8 +1886,16 @@
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz2;
+#endif /* TEST_FUZZ */
return -1;
}
+#ifdef TEST_FUZZ
+ continue_fuzz2:
+#endif /* TEST_FUZZ */
ok = 1;
}
@@ -1857,14 +1970,25 @@
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
+#ifdef TEST_FUZZ
+ os_memset(buf, 0x11, *key_data_len);
+#endif /* TEST_FUZZ */
if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
key_data, buf)) {
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore AES unwrap failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
bin_clear_free(buf, *key_data_len);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
os_memcpy(key_data, buf, *key_data_len);
bin_clear_free(buf, *key_data_len);
WPA_PUT_BE16(((u8 *) (key + 1)) + mic_len, *key_data_len);
@@ -2864,6 +2988,9 @@
case WPA_PARAM_MFP:
sm->mfp = value;
break;
+ case WPA_PARAM_OCV:
+ sm->ocv = value;
+ break;
default:
break;
}
@@ -2938,6 +3065,19 @@
}
+int wpa_sm_ocv_enabled(struct wpa_sm *sm)
+{
+ struct wpa_ie_data rsn;
+
+ if (!sm->ocv || !sm->ap_rsn_ie)
+ return 0;
+
+ return wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+ &rsn) >= 0 &&
+ (rsn.capabilities & WPA_CAPABILITY_OCVC);
+}
+
+
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -3817,6 +3957,8 @@
if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
capab |= WPA_CAPABILITY_MFPC;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@@ -3951,6 +4093,26 @@
/* TODO: FILS IP Address Assignment */
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "FILS: Failed to get channel info for OCI element");
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
+
wpa_hexdump_buf(MSG_DEBUG, "FILS: Association Request plaintext", buf);
*kek = sm->ptk.kek;
@@ -4114,6 +4276,25 @@
goto fail;
}
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in FILS (Re)Association Response frame");
+ goto fail;
+ }
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_OCV */
+
/* Key Delivery */
if (!elems.key_delivery) {
wpa_printf(MSG_DEBUG, "FILS: No Key Delivery element");
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 21f4b17..9eee383 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -18,6 +18,7 @@
struct eapol_sm;
struct wpa_config_blob;
struct hostapd_freq_params;
+struct wpa_channel_info;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -82,6 +83,7 @@
int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
const u8 *pkt, size_t pkt_len);
+ int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
};
@@ -95,7 +97,8 @@
WPA_PARAM_KEY_MGMT,
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
- WPA_PARAM_MFP
+ WPA_PARAM_MFP,
+ WPA_PARAM_OCV
};
struct rsn_supp_config {
@@ -141,6 +144,7 @@
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int wpa_sm_pmf_enabled(struct wpa_sm *sm);
+int wpa_sm_ocv_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -279,6 +283,11 @@
return 0;
}
+static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
+{
+ return 0;
+}
+
static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
int pairwise)
{
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index b8d60e3..7dcb104 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -14,6 +14,8 @@
#include "crypto/random.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
@@ -242,6 +244,8 @@
sm->mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256)
capab |= WPA_CAPABILITY_MFPC;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -323,6 +327,26 @@
*pos++ = sm->r0kh_id_len;
os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
pos += sm->r0kh_id_len;
+#ifdef CONFIG_OCV
+ if (kck && wpa_sm_ocv_enabled(sm)) {
+ /* OCI sub-element in the third FT message */
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in FTE");
+ os_free(buf);
+ return NULL;
+ }
+
+ *pos++ = FTIE_SUBELEM_OCI;
+ *pos++ = OCV_OCI_LEN;
+ if (ocv_insert_oci(&ci, &pos) < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
*ftie_len = pos - ftie_len - 1;
if (ric_ies) {
@@ -961,6 +985,25 @@
return -1;
}
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(sm)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_sm_channel_info(sm, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in (Re)Assoc Response");
+ return -1;
+ }
+
+ if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
sm->ft_reassoc_completed = 1;
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index b94b17a..e1a213b 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -86,6 +86,7 @@
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
+ int ocv; /* Operating Channel Validation */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
@@ -395,6 +396,14 @@
sm->ctx->fils_hlp_rx(sm->ctx->ctx, dst, src, pkt, pkt_len);
}
+static inline int wpa_sm_channel_info(struct wpa_sm *sm,
+ struct wpa_channel_info *ci)
+{
+ if (!sm->ctx->channel_info)
+ return -1;
+ return sm->ctx->channel_info(sm->ctx->ctx, ci);
+}
+
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index a3410d1..ae9f4ca 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -223,6 +223,8 @@
if (sm->mfp == 2)
capab |= WPA_CAPABILITY_MFPR;
#endif /* CONFIG_IEEE80211W */
+ if (sm->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
WPA_PUT_LE16(pos, capab);
pos += 2;
@@ -463,6 +465,17 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+#endif /* CONFIG_OCV */
+
return 0;
}
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 0e72af5..9d53973 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -53,6 +53,10 @@
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_OCV
+ const u8 *oci;
+ size_t oci_len;
+#endif /* CONFIG_OCV */
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index cec1092..822f87c 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -31,6 +31,10 @@
pos = buf;
end = buf + len;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
+ return -1;
+ }
hdr->identifier = *pos++;
hdr->class = hdr->identifier >> 6;
hdr->constructed = !!(hdr->identifier & (1 << 5));
@@ -51,6 +55,10 @@
} else
hdr->tag = hdr->identifier & 0x1f;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
+ return -1;
+ }
tmp = *pos++;
if (tmp & 0x80) {
if (tmp == 0xff) {
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index e66f1a9..80874e5 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -290,7 +290,7 @@
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cred->cert_probe || conn->cert_in_cb) {
+ if ((conn->cred && conn->cred->cert_probe) || conn->cert_in_cb) {
cert_buf = wpabuf_alloc_copy(cert->cert_start,
cert->cert_len);
ev.peer_cert.cert = cert_buf;
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 04d895e..4a1147b 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -72,6 +72,9 @@
*out_len = 0;
os_get_time(&now);
+#ifdef TEST_FUZZ
+ now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
WPA_PUT_BE32(conn->client_random, now.sec);
if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 5406969..4759509 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -164,7 +164,8 @@
/* need more data */
wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
"yet supported");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
goto failed;
}
ct = pos[0];
@@ -204,6 +205,7 @@
msg = tlsv1_server_send_alert(conn, conn->alert_level,
conn->alert_description,
out_len);
+ conn->write_alerts++;
}
return msg;
@@ -296,6 +298,7 @@
}
tlsv1_server_log(conn, "Received alert %d:%d",
out_pos[0], out_pos[1]);
+ conn->read_alerts++;
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
/* Continue processing */
pos += used;
@@ -708,6 +711,24 @@
}
+int tlsv1_server_get_failed(struct tlsv1_server *conn)
+{
+ return conn->state == FAILED;
+}
+
+
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn)
+{
+ return conn->read_alerts;
+}
+
+
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn)
+{
+ return conn->write_alerts;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
{
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index 10e7699..c3fd37e 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -48,6 +48,10 @@
void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
void (*cb)(void *ctx, const char *msg), void *ctx);
+int tlsv1_server_get_failed(struct tlsv1_server *conn);
+int tlsv1_server_get_read_alerts(struct tlsv1_server *conn);
+int tlsv1_server_get_write_alerts(struct tlsv1_server *conn);
+
void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
#endif /* TLSV1_SERVER_H */
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 29c6678..2622585 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -30,6 +30,8 @@
u8 alert_level;
u8 alert_description;
+ int read_alerts, write_alerts;
+
struct crypto_public_key *client_rsa_key;
struct tls_verify_hash verify;
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 4aa8a01..e957678 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -139,8 +139,11 @@
pos = in_data;
left = *in_len;
- if (left < 4)
+ if (left < 4) {
+ tlsv1_server_log(conn,
+ "Truncated handshake message (expected ClientHello)");
goto decode_error;
+ }
/* HandshakeType msg_type */
if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
@@ -157,8 +160,12 @@
pos += 3;
left -= 4;
- if (len > left)
+ if (len > left) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello (len=%d left=%d)",
+ (int) len, (int) left);
goto decode_error;
+ }
/* body - ClientHello */
@@ -166,8 +173,10 @@
end = pos + len;
/* ProtocolVersion client_version */
- if (end - pos < 2)
+ if (end - pos < 2) {
+ tlsv1_server_log(conn, "Truncated ClientHello/client_version");
goto decode_error;
+ }
conn->client_version = WPA_GET_BE16(pos);
tlsv1_server_log(conn, "Client version %d.%d",
conn->client_version >> 8,
@@ -196,8 +205,10 @@
tls_version_str(conn->rl.tls_version));
/* Random random */
- if (end - pos < TLS_RANDOM_LEN)
+ if (end - pos < TLS_RANDOM_LEN) {
+ tlsv1_server_log(conn, "Truncated ClientHello/client_random");
goto decode_error;
+ }
os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
pos += TLS_RANDOM_LEN;
@@ -205,25 +216,36 @@
conn->client_random, TLS_RANDOM_LEN);
/* SessionID session_id */
- if (end - pos < 1)
+ if (end - pos < 1) {
+ tlsv1_server_log(conn, "Truncated ClientHello/session_id len");
goto decode_error;
- if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+ }
+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) {
+ tlsv1_server_log(conn, "Truncated ClientHello/session_id");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
pos += 1 + *pos;
/* TODO: add support for session resumption */
/* CipherSuite cipher_suites<2..2^16-1> */
- if (end - pos < 2)
+ if (end - pos < 2) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/cipher_suites len");
goto decode_error;
+ }
num_suites = WPA_GET_BE16(pos);
pos += 2;
- if (end - pos < num_suites)
+ if (end - pos < num_suites) {
+ tlsv1_server_log(conn, "Truncated ClientHello/cipher_suites");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
pos, num_suites);
- if (num_suites & 1)
+ if (num_suites & 1) {
+ tlsv1_server_log(conn, "Odd len ClientHello/cipher_suites");
goto decode_error;
+ }
num_suites /= 2;
cipher_suite = 0;
@@ -259,11 +281,17 @@
conn->cipher_suite = cipher_suite;
/* CompressionMethod compression_methods<1..2^8-1> */
- if (end - pos < 1)
+ if (end - pos < 1) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/compression_methods len");
goto decode_error;
+ }
num_suites = *pos++;
- if (end - pos < num_suites)
+ if (end - pos < num_suites) {
+ tlsv1_server_log(conn,
+ "Truncated ClientHello/compression_methods");
goto decode_error;
+ }
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
pos, num_suites);
compr_null_found = 0;
@@ -1217,6 +1245,7 @@
if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
tlsv1_server_log(conn, "Mismatch in verify_data");
+ conn->state = FAILED;
return -1;
}
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index bdc6c11..8d36cf1 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -26,7 +26,7 @@
size_t len = 0;
struct x509_certificate *cert;
- cert = conn->cred->cert;
+ cert = conn->cred ? conn->cred->cert : NULL;
while (cert) {
len += 3 + cert->cert_len;
if (x509_certificate_self_signed(cert))
@@ -53,6 +53,9 @@
pos += TLS_RECORD_HEADER_LEN;
os_get_time(&now);
+#ifdef TEST_FUZZ
+ now.sec = 0xfffefdfc;
+#endif /* TEST_FUZZ */
WPA_PUT_BE32(conn->server_random, now.sec);
if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index f80c9a3..fa4d442 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -532,6 +532,8 @@
}
done:
+ if (pos < end)
+ *pos = '\0';
end[-1] = '\0';
}
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 52efc53..1ee2bee 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -19,6 +19,7 @@
common.o \
crc32.o \
ip_addr.o \
+ json.o \
radiotap.o \
trace.o \
uuid.o \
diff --git a/src/utils/browser.c b/src/utils/browser.c
index 9cf6152..ad0b382 100644
--- a/src/utils/browser.c
+++ b/src/utils/browser.c
@@ -166,8 +166,7 @@
g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_wmclass(GTK_WINDOW(ctx.win), "Hotspot 2.0 client",
- "Hotspot 2.0 client");
+ gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600);
scroll = gtk_scrolled_window_new(NULL, NULL);
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index 436bc8c..bb375be 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -224,22 +224,25 @@
#ifdef CONFIG_ELOOP_KQUEUE
-static int eloop_sock_queue(int sock, eloop_event_type type)
-{
- int filter;
- struct kevent ke;
+static short event_type_kevent_filter(eloop_event_type type)
+{
switch (type) {
case EVENT_TYPE_READ:
- filter = EVFILT_READ;
- break;
+ return EVFILT_READ;
case EVENT_TYPE_WRITE:
- filter = EVFILT_WRITE;
- break;
+ return EVFILT_WRITE;
default:
- filter = 0;
+ return 0;
}
- EV_SET(&ke, sock, filter, EV_ADD, 0, 0, 0);
+}
+
+
+static int eloop_sock_queue(int sock, eloop_event_type type)
+{
+ struct kevent ke;
+
+ EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0);
if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) {
wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s",
__func__, sock, strerror(errno));
@@ -247,6 +250,7 @@
}
return 0;
}
+
#endif /* CONFIG_ELOOP_KQUEUE */
@@ -301,7 +305,7 @@
#endif /* CONFIG_ELOOP_POLL */
#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
if (new_max_sock >= eloop.max_fd) {
- next = eloop.max_fd == 0 ? 16 : eloop.max_fd * 2;
+ next = new_max_sock + 16;
temp_table = os_realloc_array(eloop.fd_table, next,
sizeof(struct eloop_sock));
if (temp_table == NULL)
@@ -411,7 +415,8 @@
os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock));
#endif /* CONFIG_ELOOP_EPOLL */
#ifdef CONFIG_ELOOP_KQUEUE
- EV_SET(&ke, sock, 0, EV_DELETE, 0, 0, 0);
+ EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0,
+ 0, 0);
if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) {
wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s",
__func__, sock, strerror(errno));
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index 58519ea..e62fbf9 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -31,6 +31,14 @@
#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;
@@ -446,6 +454,7 @@
#define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \
sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i))
#else /* OPENSSL_IS_BORINGSSL */
+#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))
@@ -456,6 +465,13 @@
#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
#endif /* OPENSSL_IS_BORINGSSL */
@@ -486,7 +502,8 @@
return;
n->hash_len = ASN1_STRING_length(hash->hashValue);
- n->hash = os_memdup(ASN1_STRING_data(hash->hashValue), n->hash_len);
+ n->hash = os_memdup(ASN1_STRING_get0_data(hash->hashValue),
+ n->hash_len);
if (n->hash == NULL) {
os_free(n->alg_oid);
return;
@@ -499,7 +516,7 @@
os_free(n->hash);
return;
}
- os_memcpy(n->uri, ASN1_STRING_data(uri), len);
+ os_memcpy(n->uri, ASN1_STRING_get0_data(uri), len);
n->uri[len] = '\0';
hcert->num_logo++;
@@ -814,9 +831,9 @@
}
wpa_hexdump(MSG_DEBUG, "logotypeExtn",
- ASN1_STRING_data(os), ASN1_STRING_length(os));
+ ASN1_STRING_get0_data(os), ASN1_STRING_length(os));
- data = ASN1_STRING_data(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");
@@ -1136,7 +1153,7 @@
return 0;
}
- store = SSL_CTX_get_cert_store(s->ctx);
+ store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s));
if (ctx->peer_issuer) {
wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer");
debug_dump_cert("OpenSSL: Issuer certificate",
@@ -1272,12 +1289,13 @@
}
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
static SSL_METHOD patch_ssl_method;
static const SSL_METHOD *real_ssl_method;
static int curl_patch_ssl_new(SSL *s)
{
- SSL_CTX *ssl = s->ctx;
+ SSL_CTX *ssl = SSL_get_SSL_CTX(s);
int ret;
ssl->method = real_ssl_method;
@@ -1288,6 +1306,7 @@
return ret;
}
+#endif /* OpenSSL < 1.1.0 */
#endif /* HAVE_OCSP */
@@ -1306,6 +1325,7 @@
SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb);
SSL_CTX_set_tlsext_status_arg(ssl, ctx);
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
/*
* Use a temporary SSL_METHOD to get a callback on SSL_new()
* from libcurl since there is no proper callback registration
@@ -1315,6 +1335,7 @@
patch_ssl_method.ssl_new = curl_patch_ssl_new;
real_ssl_method = ssl->method;
ssl->method = &patch_ssl_method;
+#endif /* OpenSSL < 1.1.0 */
}
#endif /* HAVE_OCSP */
@@ -1351,7 +1372,7 @@
#ifdef EAP_TLS_OPENSSL
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl);
curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx);
-#ifdef OPENSSL_IS_BORINGSSL
+#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L)
/* For now, using the CURLOPT_SSL_VERIFYSTATUS option only
* with BoringSSL since the OpenSSL specific callback hack to
* enable OCSP is not available with BoringSSL. The OCSP
diff --git a/src/utils/json.c b/src/utils/json.c
index b9130d3..b644339 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -103,6 +103,11 @@
return str;
case '\\':
pos++;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG,
+ "JSON: Truncated \\ escape");
+ goto fail;
+ }
switch (*pos) {
case '"':
case '\\':
@@ -165,6 +170,8 @@
break;
}
}
+ if (pos == end)
+ pos--;
if (pos < *json_pos)
return -1;
len = pos - *json_pos + 1;
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 381846a..b79a70d 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -252,6 +252,13 @@
int os_get_random(unsigned char *buf, size_t len)
{
+#ifdef TEST_FUZZ
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = i & 0xff;
+ return 0;
+#else /* TEST_FUZZ */
FILE *f;
size_t rc;
@@ -268,6 +275,7 @@
fclose(f);
return rc != len ? -1 : 0;
+#endif /* TEST_FUZZ */
}
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index a56462b..c437000 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -422,6 +422,12 @@
#ifdef CONFIG_ANDROID_LOG
_wpa_hexdump(level, title, buf, len, show);
#else /* CONFIG_ANDROID_LOG */
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog) {
+ _wpa_hexdump(level, title, buf, len, show);
+ return;
+ }
+#endif /* CONFIG_DEBUG_SYSLOG */
wpa_debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 770f5e9..7dfa95b 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -60,7 +60,8 @@
}
wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
- wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
+ if (wps->dh_privkey && pubkey)
+ wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
#endif /* CONFIG_WPS_NFC */
} else {
wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
diff --git a/src/wps/wps_validate.c b/src/wps/wps_validate.c
index 267b565..5c12bce 100644
--- a/src/wps/wps_validate.c
+++ b/src/wps/wps_validate.c
@@ -1057,7 +1057,7 @@
}
-static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,
+static int wps_validate_credential(const u8 *cred[], u16 len[], size_t num,
int mandatory)
{
size_t i;
diff --git a/tests/test-eapol.c b/tests/test-eapol.c
new file mode 100644
index 0000000..0a0844b
--- /dev/null
+++ b/tests/test-eapol.c
@@ -0,0 +1,606 @@
+/*
+ * Testing tool for EAPOL-Key Supplicant/Authenticator routines
+ * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "rsn_supp/wpa.h"
+#include "ap/wpa_auth.h"
+
+
+struct wpa {
+ enum { AUTH, SUPP } test_peer;
+ enum { READ, WRITE } test_oper;
+ FILE *f;
+ int wpa1;
+
+ u8 auth_addr[ETH_ALEN];
+ u8 supp_addr[ETH_ALEN];
+ u8 psk[PMK_LEN];
+
+ /* from authenticator */
+ u8 *auth_eapol;
+ size_t auth_eapol_len;
+
+ /* from supplicant */
+ u8 *supp_eapol;
+ size_t supp_eapol_len;
+
+ struct wpa_sm *supp;
+ struct wpa_authenticator *auth_group;
+ struct wpa_state_machine *auth;
+
+ u8 supp_ie[80];
+ size_t supp_ie_len;
+
+ int key_request_done;
+ int key_request_done1;
+ int auth_sent;
+};
+
+
+const struct wpa_driver_ops *const wpa_drivers[] = { NULL };
+
+
+static int auth_read_msg(struct wpa *wpa);
+static void supp_eapol_key_request(void *eloop_data, void *user_ctx);
+
+
+static void usage(void) {
+ wpa_printf(MSG_INFO,
+ "usage: test-eapol <auth/supp> <read/write> <file>");
+ exit(-1);
+}
+
+
+static void write_msg(FILE *f, const u8 *msg, size_t msg_len)
+{
+ u8 len[2];
+
+ wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
+ (unsigned int) msg_len);
+ WPA_PUT_BE16(len, msg_len);
+ fwrite(len, 2, 1, f);
+ fwrite(msg, msg_len, 1, f);
+}
+
+
+static u8 * read_msg(FILE *f, size_t *ret_len)
+{
+ u8 len[2];
+ u16 msg_len;
+ u8 *msg;
+
+ if (fread(len, 2, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
+ eloop_terminate();
+ return NULL;
+ }
+ msg_len = WPA_GET_BE16(len);
+
+ msg = os_malloc(msg_len);
+ if (!msg)
+ return NULL;
+ if (msg_len > 0 && fread(msg, msg_len, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
+ msg_len);
+ os_free(msg);
+ eloop_terminate();
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "TEST: Read message from file", msg, msg_len);
+
+ *ret_len = msg_len;
+ return msg;
+}
+
+
+static int supp_get_bssid(void *ctx, u8 *bssid)
+{
+ struct wpa *wpa = ctx;
+ wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+ os_memcpy(bssid, wpa->auth_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static void supp_set_state(void *ctx, enum wpa_states state)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(state=%d)", __func__, state);
+}
+
+
+static void auth_eapol_rx(void *eloop_data, void *user_ctx)
+{
+ struct wpa *wpa = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "AUTH: RX EAPOL frame");
+ wpa->auth_sent = 0;
+ wpa_receive(wpa->auth_group, wpa->auth, wpa->supp_eapol,
+ wpa->supp_eapol_len);
+ if (!wpa->auth_sent && wpa->test_peer == SUPP &&
+ wpa->test_oper == READ) {
+ /* Speed up process by not going through retransmit timeout */
+ wpa_printf(MSG_DEBUG,
+ "AUTH: No response was sent - process next message");
+ auth_read_msg(wpa);
+ }
+ if (wpa->wpa1 && wpa->key_request_done && !wpa->key_request_done1) {
+ wpa->key_request_done1 = 1;
+ eloop_register_timeout(0, 0, supp_eapol_key_request,
+ wpa, NULL);
+ }
+
+}
+
+
+static void supp_eapol_rx(void *eloop_data, void *user_ctx)
+{
+ struct wpa *wpa = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "SUPP: RX EAPOL frame");
+ wpa_sm_rx_eapol(wpa->supp, wpa->auth_addr, wpa->auth_eapol,
+ wpa->auth_eapol_len);
+}
+
+
+static int supp_read_msg(struct wpa *wpa)
+{
+ os_free(wpa->auth_eapol);
+ wpa->auth_eapol = read_msg(wpa->f, &wpa->auth_eapol_len);
+ if (!wpa->auth_eapol)
+ return -1;
+ eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
+ return 0;
+}
+
+
+static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
+ size_t len)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x "
+ "len=%lu)",
+ __func__, MAC2STR(dest), proto, (unsigned long) len);
+
+ if (wpa->test_peer == SUPP && wpa->test_oper == WRITE)
+ write_msg(wpa->f, buf, len);
+
+ if (wpa->test_peer == AUTH && wpa->test_oper == READ)
+ return supp_read_msg(wpa);
+
+ os_free(wpa->supp_eapol);
+ wpa->supp_eapol = os_malloc(len);
+ if (!wpa->supp_eapol)
+ return -1;
+ os_memcpy(wpa->supp_eapol, buf, len);
+ wpa->supp_eapol_len = len;
+ eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
+
+ return 0;
+}
+
+
+static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data,
+ u16 data_len, size_t *msg_len, void **data_pos)
+{
+ struct ieee802_1x_hdr *hdr;
+
+ wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)",
+ __func__, type, data_len);
+
+ *msg_len = sizeof(*hdr) + data_len;
+ hdr = os_malloc(*msg_len);
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->version = 2;
+ hdr->type = type;
+ hdr->length = host_to_be16(data_len);
+
+ if (data)
+ os_memcpy(hdr + 1, data, data_len);
+ else
+ os_memset(hdr + 1, 0, data_len);
+
+ if (data_pos)
+ *data_pos = hdr + 1;
+
+ return (u8 *) hdr;
+}
+
+
+static int supp_get_beacon_ie(void *ctx)
+{
+ struct wpa *wpa = ctx;
+ const u8 *ie;
+ size_t ielen;
+
+ wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+
+ ie = wpa_auth_get_wpa_ie(wpa->auth_group, &ielen);
+ if (ie == NULL || ielen < 1)
+ return -1;
+ if (ie[0] == WLAN_EID_RSN)
+ return wpa_sm_set_ap_rsn_ie(wpa->supp, ie, 2 + ie[1]);
+ return wpa_sm_set_ap_wpa_ie(wpa->supp, ie, 2 + ie[1]);
+}
+
+
+static int supp_set_key(void *ctx, enum wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d "
+ "set_tx=%d)",
+ __func__, alg, MAC2STR(addr), key_idx, set_tx);
+ wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len);
+ wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
+ return 0;
+}
+
+
+static int supp_mlme_setprotection(void *ctx, const u8 *addr,
+ int protection_type, int key_type)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d "
+ "key_type=%d)",
+ __func__, MAC2STR(addr), protection_type, key_type);
+ return 0;
+}
+
+
+static void supp_cancel_auth_timeout(void *ctx)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
+}
+
+
+static void * supp_get_network_ctx(void *ctx)
+{
+ return (void *) 1;
+}
+
+
+static void supp_deauthenticate(void *ctx, int reason_code)
+{
+ wpa_printf(MSG_DEBUG, "SUPP: %s(%d)", __func__, reason_code);
+}
+
+
+static enum wpa_states supp_get_state(void *ctx)
+{
+ return WPA_COMPLETED;
+}
+
+
+static int supp_init(struct wpa *wpa)
+{
+ struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
+
+ if (!ctx)
+ return -1;
+
+ ctx->ctx = wpa;
+ ctx->msg_ctx = wpa;
+ ctx->set_state = supp_set_state;
+ ctx->get_bssid = supp_get_bssid;
+ ctx->ether_send = supp_ether_send;
+ ctx->get_beacon_ie = supp_get_beacon_ie;
+ ctx->alloc_eapol = supp_alloc_eapol;
+ ctx->set_key = supp_set_key;
+ ctx->mlme_setprotection = supp_mlme_setprotection;
+ ctx->cancel_auth_timeout = supp_cancel_auth_timeout;
+ ctx->get_network_ctx = supp_get_network_ctx;
+ ctx->deauthenticate = supp_deauthenticate;
+ ctx->get_state = supp_get_state;
+ wpa->supp = wpa_sm_init(ctx);
+ if (!wpa->supp) {
+ wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+ return -1;
+ }
+
+ wpa_sm_set_own_addr(wpa->supp, wpa->supp_addr);
+ if (wpa->wpa1) {
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 0);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_WPA);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
+ WPA_CIPHER_TKIP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_TKIP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
+ WPA_KEY_MGMT_PSK);
+ } else {
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_RSN_ENABLED, 1);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_PAIRWISE,
+ WPA_CIPHER_CCMP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_KEY_MGMT,
+ WPA_KEY_MGMT_PSK);
+ wpa_sm_set_param(wpa->supp, WPA_PARAM_MFP,
+ MGMT_FRAME_PROTECTION_OPTIONAL);
+ }
+ wpa_sm_set_pmk(wpa->supp, wpa->psk, PMK_LEN, NULL, NULL);
+
+ wpa->supp_ie_len = sizeof(wpa->supp_ie);
+ if (wpa_sm_set_assoc_wpa_ie_default(wpa->supp, wpa->supp_ie,
+ &wpa->supp_ie_len) < 0) {
+ wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()"
+ " failed");
+ return -1;
+ }
+
+ wpa_sm_notify_assoc(wpa->supp, wpa->auth_addr);
+
+ return 0;
+}
+
+
+static void auth_logger(void *ctx, const u8 *addr, logger_level level,
+ const char *txt)
+{
+ if (addr)
+ wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
+ MAC2STR(addr), txt);
+ else
+ wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
+}
+
+
+static int auth_read_msg(struct wpa *wpa)
+{
+ os_free(wpa->supp_eapol);
+ wpa->supp_eapol = read_msg(wpa->f, &wpa->supp_eapol_len);
+ if (!wpa->supp_eapol)
+ return -1;
+ eloop_register_timeout(0, 0, auth_eapol_rx, wpa, NULL);
+ return 0;
+}
+
+
+static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu "
+ "encrypt=%d)",
+ __func__, MAC2STR(addr), (unsigned long) data_len, encrypt);
+ wpa->auth_sent = 1;
+
+ if (wpa->test_peer == AUTH && wpa->test_oper == WRITE)
+ write_msg(wpa->f, data, data_len);
+
+ if (wpa->test_peer == SUPP && wpa->test_oper == READ)
+ return auth_read_msg(wpa);
+
+ os_free(wpa->auth_eapol);
+ wpa->auth_eapol = os_malloc(data_len);
+ if (!wpa->auth_eapol)
+ return -1;
+ os_memcpy(wpa->auth_eapol, data, data_len);
+ wpa->auth_eapol_len = data_len;
+ eloop_register_timeout(0, 0, supp_eapol_rx, wpa, NULL);
+
+ return 0;
+}
+
+
+static const u8 * auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *p2p_dev_addr, const u8 *prev_psk,
+ size_t *psk_len)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+ __func__, MAC2STR(addr), prev_psk);
+ if (psk_len)
+ *psk_len = PMK_LEN;
+ if (prev_psk)
+ return NULL;
+ return wpa->psk;
+}
+
+
+static void supp_eapol_key_request(void *eloop_data, void *user_ctx)
+{
+ struct wpa *wpa = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "SUPP: EAPOL-Key Request trigger");
+ if (wpa->test_peer == SUPP && wpa->test_oper == READ) {
+ if (!eloop_is_timeout_registered(auth_eapol_rx, wpa, NULL))
+ auth_read_msg(wpa);
+ } else {
+ wpa_sm_key_request(wpa->supp, 0, 1);
+ }
+}
+
+
+static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+ const u8 *addr, int idx, u8 *key,
+ size_t key_len)
+{
+ struct wpa *wpa = ctx;
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s (vlan_id=%d alg=%d idx=%d key_len=%d)",
+ __func__, vlan_id, alg, idx, (int) key_len);
+ if (addr)
+ wpa_printf(MSG_DEBUG, "AUTH: addr=" MACSTR, MAC2STR(addr));
+
+ if (alg != WPA_ALG_NONE && idx == 0 && key_len > 0 &&
+ !wpa->key_request_done) {
+ wpa_printf(MSG_DEBUG, "Test EAPOL-Key Request");
+ wpa->key_request_done = 1;
+ if (!wpa->wpa1)
+ eloop_register_timeout(0, 0, supp_eapol_key_request,
+ wpa, NULL);
+ }
+
+ return 0;
+}
+
+
+static int auth_init_group(struct wpa *wpa)
+{
+ struct wpa_auth_config conf;
+ struct wpa_auth_callbacks cb;
+
+ wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
+
+ os_memset(&conf, 0, sizeof(conf));
+ if (wpa->wpa1) {
+ conf.wpa = 1;
+ conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ conf.wpa_pairwise = WPA_CIPHER_TKIP;
+ conf.wpa_group = WPA_CIPHER_TKIP;
+ } else {
+ conf.wpa = 2;
+ conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ conf.wpa_pairwise = WPA_CIPHER_CCMP;
+ conf.rsn_pairwise = WPA_CIPHER_CCMP;
+ conf.wpa_group = WPA_CIPHER_CCMP;
+ conf.ieee80211w = 2;
+ conf.group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC;
+ }
+ conf.eapol_version = 2;
+ conf.wpa_group_update_count = 4;
+ conf.wpa_pairwise_update_count = 4;
+
+ os_memset(&cb, 0, sizeof(cb));
+ cb.logger = auth_logger;
+ cb.send_eapol = auth_send_eapol;
+ cb.get_psk = auth_get_psk;
+ cb.set_key = auth_set_key,
+
+ wpa->auth_group = wpa_init(wpa->auth_addr, &conf, &cb, wpa);
+ if (!wpa->auth_group) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int auth_init(struct wpa *wpa)
+{
+ if (wpa->test_peer == AUTH && wpa->test_oper == READ)
+ return supp_read_msg(wpa);
+
+ wpa->auth = wpa_auth_sta_init(wpa->auth_group, wpa->supp_addr, NULL);
+ if (!wpa->auth) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed");
+ return -1;
+ }
+
+ if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, wpa->supp_ie,
+ wpa->supp_ie_len, NULL, 0, NULL, 0) !=
+ WPA_IE_OK) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
+ return -1;
+ }
+
+ wpa_auth_sm_event(wpa->auth, WPA_ASSOC);
+
+ wpa_auth_sta_associated(wpa->auth_group, wpa->auth);
+
+ return 0;
+}
+
+
+static void deinit(struct wpa *wpa)
+{
+ wpa_auth_sta_deinit(wpa->auth);
+ wpa_sm_deinit(wpa->supp);
+ wpa_deinit(wpa->auth_group);
+ os_free(wpa->auth_eapol);
+ wpa->auth_eapol = NULL;
+ os_free(wpa->supp_eapol);
+ wpa->supp_eapol = NULL;
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char *file;
+ int ret;
+ struct wpa wpa;
+
+ if (os_program_init())
+ return -1;
+
+ wpa_debug_level = 0;
+ wpa_debug_show_keys = 1;
+ os_memset(&wpa, 0, sizeof(wpa));
+
+ if (argc < 4)
+ usage();
+
+ if (os_strcmp(argv[1], "auth") == 0) {
+ wpa.test_peer = AUTH;
+ } else if (os_strcmp(argv[1], "auth1") == 0) {
+ wpa.test_peer = AUTH;
+ wpa.wpa1 = 1;
+ } else if (os_strcmp(argv[1], "supp") == 0) {
+ wpa.test_peer = SUPP;
+ } else if (os_strcmp(argv[1], "supp1") == 0) {
+ wpa.test_peer = SUPP;
+ wpa.wpa1 = 1;
+ } else {
+ usage();
+ }
+
+ if (os_strcmp(argv[2], "read") == 0)
+ wpa.test_oper = READ;
+ else if (os_strcmp(argv[2], "write") == 0)
+ wpa.test_oper = WRITE;
+ else
+ usage();
+
+ file = argv[3];
+
+ wpa.f = fopen(file, wpa.test_oper == READ ? "r" : "w");
+ if (!wpa.f)
+ return -1;
+
+ os_memset(wpa.auth_addr, 0x12, ETH_ALEN);
+ os_memset(wpa.supp_addr, 0x32, ETH_ALEN);
+ os_memset(wpa.psk, 0x44, PMK_LEN);
+
+ if (eloop_init()) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ goto fail;
+ }
+
+ if (auth_init_group(&wpa) < 0)
+ goto fail;
+
+ if (supp_init(&wpa) < 0)
+ goto fail;
+
+ if (auth_init(&wpa) < 0)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "Starting eloop");
+ eloop_run();
+ wpa_printf(MSG_DEBUG, "eloop done");
+
+ ret = 0;
+fail:
+ deinit(&wpa);
+ fclose(wpa.f);
+
+ eloop_destroy();
+
+ os_program_deinit();
+
+ return ret;
+}
diff --git a/tests/test-json.c b/tests/test-json.c
new file mode 100644
index 0000000..c7cb460
--- /dev/null
+++ b/tests/test-json.c
@@ -0,0 +1,44 @@
+/*
+ * JSON parser - test program
+ * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/os.h"
+#include "utils/json.h"
+
+
+int main(int argc, char *argv[])
+{
+ char *buf;
+ size_t len;
+ struct json_token *root;
+
+ if (argc < 2)
+ return -1;
+
+ buf = os_readfile(argv[1], &len);
+ if (!buf)
+ return -1;
+
+ root = json_parse(buf, len);
+ os_free(buf);
+ if (root) {
+ size_t buflen = 10000;
+
+ buf = os_zalloc(buflen);
+ if (buf) {
+ json_print_tree(root, buf, buflen);
+ printf("%s\n", buf);
+ os_free(buf);
+ }
+ json_free(root);
+ } else {
+ printf("JSON parsing failed\n");
+ }
+
+ return 0;
+}
diff --git a/tests/test-tls.c b/tests/test-tls.c
new file mode 100644
index 0000000..9941fb5
--- /dev/null
+++ b/tests/test-tls.c
@@ -0,0 +1,243 @@
+/*
+ * Testing tool for TLSv1 client/server routines
+ * Copyright (c) 2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+
+
+static void usage(void) {
+ wpa_printf(MSG_INFO,
+ "usage: test-tls <server/client> <read/write> <file>");
+ exit(-1);
+}
+
+
+static void write_msg(FILE *f, struct wpabuf *msg)
+{
+ u8 len[2];
+
+ wpa_printf(MSG_DEBUG, "TEST: Write message to file (msg_len=%u)",
+ (unsigned int) wpabuf_len(msg));
+ WPA_PUT_BE16(len, wpabuf_len(msg));
+ fwrite(len, 2, 1, f);
+ fwrite(wpabuf_head(msg), wpabuf_len(msg), 1, f);
+}
+
+
+static struct wpabuf * read_msg(FILE *f)
+{
+ u8 len[2];
+ u16 msg_len;
+ struct wpabuf *msg;
+
+ if (fread(len, 2, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Could not read msg len");
+ return NULL;
+ }
+ msg_len = WPA_GET_BE16(len);
+
+ msg = wpabuf_alloc(msg_len);
+ if (!msg)
+ return NULL;
+ if (msg_len > 0 &&
+ fread(wpabuf_put(msg, msg_len), msg_len, 1, f) != 1) {
+ wpa_printf(MSG_ERROR, "TEST-ERROR: Truncated msg (msg_len=%u)",
+ msg_len);
+ wpabuf_free(msg);
+ return NULL;
+ }
+ wpa_hexdump_buf(MSG_DEBUG, "TEST: Read message from file", msg);
+
+ return msg;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct tls_config conf;
+ void *tls_server, *tls_client;
+ struct tls_connection_params params;
+ struct tls_connection *conn_server = NULL, *conn_client = NULL;
+ int ret = -1;
+ struct wpabuf *in = NULL, *out = NULL, *appl;
+ enum { SERVER, CLIENT } test_peer;
+ enum { READ, WRITE } test_oper;
+ const char *file;
+ FILE *f;
+
+ wpa_debug_level = 0;
+ wpa_debug_show_keys = 1;
+
+ if (argc < 4)
+ usage();
+
+ if (os_strcmp(argv[1], "server") == 0)
+ test_peer = SERVER;
+ else if (os_strcmp(argv[1], "client") == 0)
+ test_peer = CLIENT;
+ else
+ usage();
+
+ if (os_strcmp(argv[2], "read") == 0)
+ test_oper = READ;
+ else if (os_strcmp(argv[2], "write") == 0)
+ test_oper = WRITE;
+ else
+ usage();
+
+ file = argv[3];
+
+ f = fopen(file, test_oper == READ ? "r" : "w");
+ if (!f)
+ return -1;
+
+ os_memset(&conf, 0, sizeof(conf));
+ tls_server = tls_init(&conf);
+ tls_client = tls_init(&conf);
+ if (!tls_server || !tls_client)
+ goto fail;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.ca_cert = "hwsim/auth_serv/ca.pem";
+ params.client_cert = "hwsim/auth_serv/server.pem";
+ params.private_key = "hwsim/auth_serv/server.key";
+ params.dh_file = "hwsim/auth_serv/dh.conf";
+
+ if (tls_global_set_params(tls_server, ¶ms)) {
+ wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
+ goto fail;
+ }
+
+ conn_server = tls_connection_init(tls_server);
+ conn_client = tls_connection_init(tls_client);
+ if (!conn_server || !conn_client)
+ goto fail;
+
+ in = NULL;
+ for (;;) {
+ appl = NULL;
+ if (test_peer == CLIENT && test_oper == READ)
+ out = read_msg(f);
+ else
+ out = tls_connection_handshake(tls_client, conn_client,
+ in, &appl);
+ wpabuf_free(in);
+ in = NULL;
+ if (!out)
+ goto fail;
+ if (test_peer == CLIENT && test_oper == WRITE &&
+ wpabuf_len(out) > 0)
+ write_msg(f, out);
+ if (!(test_peer == CLIENT && test_oper == READ) &&
+ tls_connection_get_failed(tls_client, conn_client)) {
+ wpa_printf(MSG_ERROR, "TLS handshake failed");
+ goto fail;
+ }
+ if (((test_peer == CLIENT && test_oper == READ) ||
+ tls_connection_established(tls_client, conn_client)) &&
+ ((test_peer == SERVER && test_oper == READ) ||
+ tls_connection_established(tls_server, conn_server)))
+ break;
+
+ appl = NULL;
+ if (test_peer == SERVER && test_oper == READ)
+ in = read_msg(f);
+ else
+ in = tls_connection_server_handshake(tls_server,
+ conn_server,
+ out, &appl);
+ wpabuf_free(out);
+ out = NULL;
+ if (!in)
+ goto fail;
+ if (test_peer == SERVER && test_oper == WRITE)
+ write_msg(f, in);
+ if (!(test_peer == SERVER && test_oper == READ) &&
+ tls_connection_get_failed(tls_server, conn_server)) {
+ wpa_printf(MSG_ERROR, "TLS handshake failed");
+ goto fail;
+ }
+ if (((test_peer == CLIENT && test_oper == READ) ||
+ tls_connection_established(tls_client, conn_client)) &&
+ ((test_peer == SERVER && test_oper == READ) ||
+ tls_connection_established(tls_server, conn_server)))
+ break;
+ }
+
+ wpabuf_free(in);
+ in = wpabuf_alloc(100);
+ if (!in)
+ goto fail;
+ wpabuf_put_str(in, "PING");
+ wpabuf_free(out);
+ if (test_peer == CLIENT && test_oper == READ)
+ out = read_msg(f);
+ else
+ out = tls_connection_encrypt(tls_client, conn_client, in);
+ wpabuf_free(in);
+ in = NULL;
+ if (!out)
+ goto fail;
+ if (test_peer == CLIENT && test_oper == WRITE)
+ write_msg(f, out);
+
+ if (!(test_peer == SERVER && test_oper == READ)) {
+ in = tls_connection_decrypt(tls_server, conn_server, out);
+ wpabuf_free(out);
+ out = NULL;
+ if (!in)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "Server decrypted ApplData", in);
+ }
+
+ wpabuf_free(in);
+ in = wpabuf_alloc(100);
+ if (!in)
+ goto fail;
+ wpabuf_put_str(in, "PONG");
+ wpabuf_free(out);
+ if (test_peer == SERVER && test_oper == READ)
+ out = read_msg(f);
+ else
+ out = tls_connection_encrypt(tls_server, conn_server, in);
+ wpabuf_free(in);
+ in = NULL;
+ if (!out)
+ goto fail;
+ if (test_peer == SERVER && test_oper == WRITE)
+ write_msg(f, out);
+
+ if (!(test_peer == CLIENT && test_oper == READ)) {
+ in = tls_connection_decrypt(tls_client, conn_client, out);
+ wpabuf_free(out);
+ out = NULL;
+ if (!in)
+ goto fail;
+ wpa_hexdump_buf(MSG_DEBUG, "Client decrypted ApplData", in);
+ }
+
+ ret = 0;
+fail:
+ if (tls_server) {
+ if (conn_server)
+ tls_connection_deinit(tls_server, conn_server);
+ tls_deinit(tls_server);
+ }
+ if (tls_client) {
+ if (conn_client)
+ tls_connection_deinit(tls_server, conn_client);
+ tls_deinit(tls_client);
+ }
+ wpabuf_free(in);
+ wpabuf_free(out);
+ fclose(f);
+
+ return ret;
+}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 39f8b50..1834fc5 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -238,6 +238,12 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+L_CFLAGS += -DCONFIG_OCV
+OBJS += src/common/ocv.c
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index f28055f..bf4daaa 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,75 @@
ChangeLog for wpa_supplicant
+2018-12-02 - v2.7
+ * fixed WPA packet number reuse with replayed messages and key
+ reinstallation
+ [https://w1.fi/security/2017-1/] (CVE-2017-13077, CVE-2017-13078,
+ CVE-2017-13079, CVE-2017-13080, CVE-2017-13081, CVE-2017-13082,
+ CVE-2017-13086, CVE-2017-13087, CVE-2017-13088)
+ * fixed unauthenticated EAPOL-Key decryption in wpa_supplicant
+ [https://w1.fi/security/2018-1/] (CVE-2018-14526)
+ * added support for FILS (IEEE 802.11ai) shared key authentication
+ * added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
+ and transition mode defined by WFA)
+ * added support for DPP (Wi-Fi Device Provisioning Protocol)
+ * added support for RSA 3k key case with Suite B 192-bit level
+ * fixed Suite B PMKSA caching not to update PMKID during each 4-way
+ handshake
+ * fixed EAP-pwd pre-processing with PasswordHashHash
+ * added EAP-pwd client support for salted passwords
+ * fixed a regression in TDLS prohibited bit validation
+ * started to use estimated throughput to avoid undesired signal
+ strength based roaming decision
+ * MACsec/MKA:
+ - new macsec_linux driver interface support for the Linux
+ kernel macsec module
+ - number of fixes and extensions
+ * added support for external persistent storage of PMKSA cache
+ (PMKSA_GET/PMKSA_ADD control interface commands; and
+ MESH_PMKSA_GET/MESH_PMKSA_SET for the mesh case)
+ * fixed mesh channel configuration pri/sec switch case
+ * added support for beacon report
+ * large number of other fixes, cleanup, and extensions
+ * added support for randomizing local address for GAS queries
+ (gas_rand_mac_addr parameter)
+ * fixed EAP-SIM/AKA/AKA' ext auth cases within TLS tunnel
+ * added option for using random WPS UUID (auto_uuid=1)
+ * added SHA256-hash support for OCSP certificate matching
+ * fixed EAP-AKA' to add AT_KDF into Synchronization-Failure
+ * fixed a regression in RSN pre-authentication candidate selection
+ * added option to configure allowed group management cipher suites
+ (group_mgmt network profile parameter)
+ * removed all PeerKey functionality
+ * fixed nl80211 AP and mesh mode configuration regression with
+ Linux 4.15 and newer
+ * added ap_isolate configuration option for AP mode
+ * added support for nl80211 to offload 4-way handshake into the driver
+ * added support for using wolfSSL cryptographic library
+ * SAE
+ - added support for configuring SAE password separately of the
+ WPA2 PSK/passphrase
+ - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
+ for SAE;
+ note: this is not backwards compatible, i.e., both the AP and
+ station side implementations will need to be update at the same
+ time to maintain interoperability
+ - added support for Password Identifier
+ - fixed FT-SAE PMKID matching
+ * Hotspot 2.0
+ - added support for fetching of Operator Icon Metadata ANQP-element
+ - added support for Roaming Consortium Selection element
+ - added support for Terms and Conditions
+ - added support for OSEN connection in a shared RSN BSS
+ - added support for fetching Venue URL information
+ * added support for using OpenSSL 1.1.1
+ * FT
+ - disabled PMKSA caching with FT since it is not fully functional
+ - added support for SHA384 based AKM
+ - added support for BIP ciphers BIP-CMAC-256, BIP-GMAC-128,
+ BIP-GMAC-256 in addition to previously supported BIP-CMAC-128
+ - fixed additional IE inclusion in Reassociation Request frame when
+ using FT protocol
+
2016-10-02 - v2.6
* fixed WNM Sleep Mode processing when PMF is not enabled
[http://w1.fi/security/2015-6/] (CVE-2015-5310)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index c2e93e2..e55e062 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -240,6 +240,12 @@
NEED_SHA384=y
endif
+ifdef CONFIG_OCV
+CFLAGS += -DCONFIG_OCV
+OBJS += ../src/common/ocv.o
+CONFIG_IEEE80211W=y
+endif
+
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -1526,6 +1532,9 @@
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
+ifdef CONFIG_GETRANDOM
+CFLAGS += -DCONFIG_GETRANDOM
+endif
OBJS += ../src/crypto/random.o
endif
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 730714b..bbc86b1 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
-WPA Supplicant
+wpa_supplicant
==============
-Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
new file mode 100644
index 0000000..6496733
--- /dev/null
+++ b/wpa_supplicant/README-DPP
@@ -0,0 +1,195 @@
+Device Provisioning Protocol (DPP)
+==================================
+
+This document describes how the Device Provisioning Protocol (DPP)
+implementation in wpa_supplicant and hostapd can be configured and how
+the STA device and AP can be configured to connect each other using DPP
+Connector mechanism.
+
+Introduction to DPP
+-------------------
+
+Device provisioning Protocol allows enrolling of interface-less devices
+in a secure Wi-Fi network using many methods like QR code based
+authentication( detailed below ), PKEX based authentication etc. In DPP
+a Configurator is used to provide network credentials to the devices.
+The three phases of DPP connection are authentication, configuration and
+network introduction.
+
+Build config setup
+------------------
+
+The following changes must go in the config file used to compile hostapd
+and wpa_supplicant.
+
+wpa_supplicant build config
+---------------------------
+
+Enable DPP and protected management frame in wpa_supplicant build config
+file
+
+CONFIG_IEEE80211W=y
+CONFIG_DPP=y
+
+hostapd build config
+--------------------
+
+Enable DPP and protected management frame in hostapd build config file
+
+CONFIG_IEEE80211W=y
+CONFIG_DPP=y
+
+Configurator build config
+-------------------------
+
+Any STA or AP device can act as a Configurator. Enable DPP and protected
+managment frames in build config. For an AP to act as Configurator,
+Interworking needs to be enabled. For wpa_supplicant it is not required.
+
+CONFIG_INTERWORKING=y
+
+
+Sample supplicant config file before provisioning
+-------------------------------------------------
+
+ctrl_interface=DIR=/var/run/wpa_supplicant
+ctrl_interface_group=0
+update_config=1
+pmf=2
+dpp_config_processing=2
+
+Sample hostapd config file before provisioning
+----------------------------------------------
+
+interface=wlan0
+driver=nl80211
+ctrl_interface=/var/run/hostapd
+ssid=test
+channel=1
+wpa=2
+wpa_key_mgmt=DPP
+ieee80211w=1
+wpa_pairwise=CCMP
+rsn_pairwise=CCMP
+
+
+Pre-requisites
+--------------
+
+It is assumed that an AP and client station are up by running hostapd
+and wpa_supplicant using respective config files.
+
+
+Creating Configurator
+---------------------
+
+Add a Configurator over the control interface (wpa_cli/hostapd_cli)
+
+> dpp_configurator_add
+(returns id)
+
+To get key of Configurator
+> dpp_configurator_get_key <id>
+
+
+How to configure an enrollee using Configurator
+-----------------------------------------------
+
+On enrollee side:
+
+Generate QR code for the device. Store the qr code id returned by the
+command.
+
+> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-channel> key=<key of the device>
+(returns bootstrapping info id)
+
+Get QR Code of device using the bootstrap info id.
+> dpp_bootstrap_get_uri <bootstrap-id>
+
+Make device listen to DPP request (The central frequency of channel 1 is
+2412) in case if enrollee is a client device.
+
+> dpp_listen <frequency>
+
+On Configurator side:
+
+Enter the QR Code in the Configurator.
+> dpp_qr_code "<QR-Code-read-from-enrollee>"
+
+On successfully adding QR Code, a bootstrapping info id is returned.
+
+Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
+AP. conf is sta-dpp if enrollee is a client)
+> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+
+The DPP values will be printed in the console. Save this values into the
+config file. If the enrollee is an AP, we need to manually write these
+values to the hostapd config file. If the enrollee is a client device,
+these details can be automatically saved to config file using the
+following command.
+
+> save_config
+
+To set values in runtime for AP enrollees
+
+> set dpp_connector <Connector-value-printed-on-console>
+> set dpp_csign <csign-value-on-console>
+> set dpp_netaccesskey <netaccess-value-on-console>
+
+To set values in runtime for client enrollees, set dpp_config_processing
+to 2 in wpa_supplicant conf file.
+
+Once the values are set in run-time (if not set in run-time, but saved
+in config files, they are taken up in next restart), the client device
+will automatically connect to the already provisioned AP and connection
+will be established.
+
+
+Self-configuring a device
+-------------------------
+
+It is possible for a device to configure itself if it is the
+Configurator for the network.
+
+Create a Configurator in the device and use the dpp_configurator_sign
+command to get DPP credentials.
+
+> dpp_configurator_add
+(returns configurator id)
+> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+
+
+Sample AP configuration files after provisioning
+------------------------------------------------
+
+interface=wlan0
+driver=nl80211
+ctrl_interface=/var/run/hostapd
+ssid=test
+channel=1
+wpa=2
+wpa_key_mgmt=DPP
+ieee80211w=1
+wpa_pairwise=CCMP
+rsn_pairwise=CCMP
+dpp_connector=<Connector value provided by Configurator>
+dpp_csign=<C-Sign-Key value provided by Configurator>
+dpp_netaccesskey=<Net access key provided by Configurator>
+
+
+Sample station configuration file after provisioning
+----------------------------------------------------
+
+ctrl_interface=DIR=/var/run/wpa_supplicant
+ctrl_interface_group=0
+update_config=1
+pmf=2
+dpp_config_processing=2
+network={
+ ssid="test"
+ key_mgmt=DPP
+ ieee80211w=2
+ dpp_connector="<Connector value provided by Configurator>"
+ dpp_netaccesskey=<Net access key provided by Configurator>
+ dpp_csign=<C-sign-key value provided by Configurator>
+}
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 23ac7fa..55a60a2 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -150,7 +150,7 @@
p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps]
[persistent|persistent=<network id>] [join|auth]
- [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [he] [provdisc] [auto]
[ssid=<hexdump>]
Start P2P group formation with a discovered P2P peer. This includes
@@ -262,7 +262,7 @@
session_mac - Mandatory MAC address that owns/initiated the session
p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
- [ht40] [vht]
+ [ht40] [vht] [he]
Set up a P2P group owner manually (i.e., without group owner
negotiation with a specific peer). This is also known as autonomous
@@ -558,7 +558,7 @@
Invitation
p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
- [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht] [he]
[pref=<MHz>]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index d4146db..feff916 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -277,6 +277,9 @@
# Driver support is also needed for IEEE 802.11w.
CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
@@ -514,8 +517,6 @@
#CONFIG_MBO=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-# Note: This is an experimental and not yet complete implementation. This
-# should not be enabled for production use.
#CONFIG_FILS=y
# Support RSN on IBSS networks
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index ea846a0..453c99d 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -334,6 +334,9 @@
list[8] = -1;
}
conf->supported_rates = list;
+#ifdef CONFIG_IEEE80211AX
+ conf->ieee80211ax = ssid->he;
+#endif /* CONFIG_IEEE80211AX */
}
bss->isolate = !wpa_s->conf->p2p_intra_bss;
@@ -494,6 +497,10 @@
bss->ieee80211w = ssid->ieee80211w;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ bss->ocv = ssid->ocv;
+#endif /* CONFIG_OCV */
+
#ifdef CONFIG_WPS
/*
* Enable WPS by default for open and WPA/WPA2-Personal network, but
@@ -1379,13 +1386,16 @@
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
int offset, int width, int cf1, int cf2)
{
- if (!wpa_s->ap_iface)
- return;
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface)
+ return;
wpa_s->assoc_freq = freq;
if (wpa_s->current_ssid)
wpa_s->current_ssid->frequency = freq;
- hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht,
+ hostapd_event_ch_switch(iface->bss[0], freq, ht,
offset, width, cf1, cf2);
}
@@ -1582,10 +1592,14 @@
void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
- hostapd_dfs_radar_detected(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_radar_detected(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width,
radar->cf1, radar->cf2);
@@ -1595,10 +1609,14 @@
void wpas_ap_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC started on %d MHz", radar->freq);
- hostapd_dfs_start_cac(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_start_cac(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
@@ -1607,10 +1625,14 @@
void wpas_ap_event_dfs_cac_finished(struct wpa_supplicant *wpa_s,
struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(wpa_s->ap_iface, 1, radar->freq,
+ hostapd_dfs_complete_cac(iface, 1, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
@@ -1619,10 +1641,14 @@
void wpas_ap_event_dfs_cac_aborted(struct wpa_supplicant *wpa_s,
struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
- hostapd_dfs_complete_cac(wpa_s->ap_iface, 0, radar->freq,
+ hostapd_dfs_complete_cac(iface, 0, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
@@ -1631,10 +1657,14 @@
void wpas_ap_event_dfs_cac_nop_finished(struct wpa_supplicant *wpa_s,
struct dfs_event *radar)
{
- if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0])
+ struct hostapd_iface *iface = wpa_s->ap_iface;
+
+ if (!iface)
+ iface = wpa_s->ifmsh;
+ if (!iface || !iface->bss[0])
return;
wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
- hostapd_dfs_nop_finished(wpa_s->ap_iface, radar->freq,
+ hostapd_dfs_nop_finished(iface, radar->freq,
radar->ht_enabled, radar->chan_offset,
radar->chan_width, radar->cf1, radar->cf2);
}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 3a41db9..9b19f37 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -1337,3 +1337,10 @@
return NULL;
}
#endif /* CONFIG_FILS */
+
+
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
+{
+ return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
+ capab);
+}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 5251b2c..3ce8cd3 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -148,6 +148,7 @@
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
const u8 * wpa_bss_get_fils_cache_id(struct wpa_bss *bss);
+int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab);
static inline int bss_is_dmg(const struct wpa_bss *bss)
{
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 5cdc059..2902413 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1043,6 +1043,30 @@
#endif /* CONFIG_IEEE80211R */
#endif /* CONFIG_FILS */
+#ifdef CONFIG_DPP
+ if (ssid->key_mgmt & WPA_KEY_MGMT_DPP) {
+ ret = os_snprintf(pos, end - pos, "%sDPP",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_DPP */
+
+#ifdef CONFIG_OWE
+ if (ssid->key_mgmt & WPA_KEY_MGMT_OWE) {
+ ret = os_snprintf(pos, end - pos, "%sOWE",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_OWE */
+
if (pos == buf) {
os_free(buf);
buf = NULL;
@@ -1978,16 +2002,21 @@
struct wpa_ssid *ssid, int line,
const char *value)
{
- if (hexstr2bin(value, ssid->mka_cak, MACSEC_CAK_LEN) ||
- value[MACSEC_CAK_LEN * 2] != '\0') {
+ size_t len;
+
+ len = os_strlen(value);
+ if (len > 2 * MACSEC_CAK_MAX_LEN ||
+ (len != 2 * 16 && len != 2 * 32) ||
+ hexstr2bin(value, ssid->mka_cak, len / 2)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
line, value);
return -1;
}
-
+ ssid->mka_cak_len = len / 2;
ssid->mka_psk_set |= MKA_PSK_SET_CAK;
- wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, MACSEC_CAK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak,
+ ssid->mka_cak_len);
return 0;
}
@@ -1996,8 +2025,18 @@
struct wpa_ssid *ssid, int line,
const char *value)
{
- if (hexstr2bin(value, ssid->mka_ckn, MACSEC_CKN_LEN) ||
- value[MACSEC_CKN_LEN * 2] != '\0') {
+ size_t len;
+
+ len = os_strlen(value);
+ if (len > 2 * MACSEC_CKN_MAX_LEN || /* too long */
+ len < 2 || /* too short */
+ len % 2 != 0 /* not an integral number of bytes */) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+ line, value);
+ return -1;
+ }
+ ssid->mka_ckn_len = len / 2;
+ if (hexstr2bin(value, ssid->mka_ckn, ssid->mka_ckn_len)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
line, value);
return -1;
@@ -2005,7 +2044,8 @@
ssid->mka_psk_set |= MKA_PSK_SET_CKN;
- wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, MACSEC_CKN_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn,
+ ssid->mka_ckn_len);
return 0;
}
@@ -2018,7 +2058,7 @@
if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
return NULL;
- return wpa_config_write_string_hex(ssid->mka_cak, MACSEC_CAK_LEN);
+ return wpa_config_write_string_hex(ssid->mka_cak, ssid->mka_cak_len);
}
@@ -2027,7 +2067,7 @@
{
if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
return NULL;
- return wpa_config_write_string_hex(ssid->mka_ckn, MACSEC_CKN_LEN);
+ return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len);
}
#endif /* NO_CONFIG_WRITE */
@@ -2035,6 +2075,43 @@
#endif /* CONFIG_MACSEC */
+#ifdef CONFIG_OCV
+
+static int wpa_config_parse_ocv(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ char *end;
+
+ ssid->ocv = strtol(value, &end, 0);
+ if (*end || ssid->ocv < 0 || ssid->ocv > 1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid ocv value '%s'.",
+ line, value);
+ return -1;
+ }
+ if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_ocv(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value = os_malloc(20);
+
+ if (!value)
+ return NULL;
+ os_snprintf(value, 20, "%d", ssid->ocv);
+ value[20 - 1] = '\0';
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_OCV */
+
+
static int wpa_config_parse_peerkey(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -2238,6 +2315,9 @@
#ifdef CONFIG_IEEE80211W
{ INT_RANGE(ieee80211w, 0, 2) },
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ { FUNC(ocv) },
+#endif /* CONFIG_OCV */
{ FUNC(peerkey) /* obsolete - removed */ },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
@@ -2267,6 +2347,8 @@
{ INT_RANGE(disable_sgi, 0, 1) },
{ INT_RANGE(disable_ldpc, 0, 1) },
{ INT_RANGE(ht40_intolerant, 0, 1) },
+ { INT_RANGE(tx_stbc, -1, 1) },
+ { INT_RANGE(rx_stbc, -1, 3) },
{ INT_RANGE(disable_max_amsdu, -1, 1) },
{ INT_RANGE(ampdu_factor, -1, 3) },
{ INT_RANGE(ampdu_density, -1, 7) },
@@ -2299,6 +2381,8 @@
#ifdef CONFIG_MACSEC
{ INT_RANGE(macsec_policy, 0, 1) },
{ INT_RANGE(macsec_integ_only, 0, 1) },
+ { INT_RANGE(macsec_replay_protect, 0, 1) },
+ { INT(macsec_replay_window) },
{ INT_RANGE(macsec_port, 1, 65534) },
{ INT_RANGE(mka_priority, 0, 255) },
{ FUNC_KEY(mka_cak) },
@@ -2320,6 +2404,7 @@
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
{ INT_RANGE(owe_only, 0, 1) },
+ { INT_RANGE(multi_ap_backhaul_sta, 0, 1) },
};
#undef OFFSET
@@ -2786,6 +2871,8 @@
ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
ssid->disable_sgi = DEFAULT_DISABLE_SGI;
ssid->disable_ldpc = DEFAULT_DISABLE_LDPC;
+ ssid->tx_stbc = DEFAULT_TX_STBC;
+ ssid->rx_stbc = DEFAULT_RX_STBC;
ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
@@ -2816,6 +2903,7 @@
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
ssid->mac_addr = -1;
+ ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
}
@@ -4686,6 +4774,7 @@
{ INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
{ INT(p2p_go_ht40), 0 },
{ INT(p2p_go_vht), 0 },
+ { INT(p2p_go_he), 0 },
{ INT(p2p_disabled), 0 },
{ INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
{ INT(p2p_no_group_iface), 0 },
@@ -4772,9 +4861,7 @@
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
{ INT_RANGE(dpp_config_processing, 0, 2), 0 },
- { INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
{ INT_RANGE(coloc_intf_reporting, 0, 1), 0 },
- { INT_RANGE(bss_no_flush_when_down, 0, 1), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 6eb0074..4b84200 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1079,6 +1079,16 @@
int p2p_go_vht;
/**
+ * p2p_go_he - Default mode for 11ax HE enable when operating as GO
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_he;
+
+ /**
* p2p_go_ctwindow - CTWindow to use when operating as GO
*
* By default: 0 (no CTWindow). Values 0-127 can be used to indicate
@@ -1483,7 +1493,8 @@
* p2p_device_random_mac_addr - P2P Device MAC address policy default
*
* 0 = use permanent MAC address
- * 1 = use random MAC address on creating the interface if there is no persistent groups.
+ * 1 = use random MAC address on creating the interface if there is no
+ * persistent groups.
*
* By default, permanent MAC address is used.
*/
@@ -1492,9 +1503,8 @@
/**
* p2p_device_persistent_mac_addr - Record last used MAC address
*
- * If there are saved persistent groups, P2P cannot generate another random MAC address,
- * and need to restore to last used MAC address.
- * format: aa:bb:cc:dd:ee:ff
+ * If there are saved persistent groups, P2P cannot generate another
+ * random MAC address, and need to restore to last used MAC address.
*/
u8 p2p_device_persistent_mac_addr[ETH_ALEN];
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index becc809..f1d865c 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -160,6 +160,15 @@
errors++;
}
+#ifdef CONFIG_OCV
+ if (ssid->ocv && ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: PMF needs to be enabled whenever using OCV",
+ line);
+ errors++;
+ }
+#endif /* CONFIG_OCV */
+
return errors;
}
@@ -484,7 +493,7 @@
if (value == NULL)
return;
fprintf(f, "\t%s=%s\n", field, value);
- os_free(value);
+ str_clear_free(value);
}
@@ -829,7 +838,7 @@
INT(vht);
INT_DEF(ht, 1);
INT(ht40);
- INT(max_oper_chwidth);
+ INT_DEF(max_oper_chwidth, DEFAULT_MAX_OPER_CHWIDTH);
INT(vht_center_freq1);
INT(vht_center_freq2);
INT(pbss);
@@ -853,6 +862,8 @@
write_mka_cak(f, ssid);
write_mka_ckn(f, ssid);
INT(macsec_integ_only);
+ INT(macsec_replay_protect);
+ INT(macsec_replay_window);
INT(macsec_port);
INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
#endif /* CONFIG_MACSEC */
@@ -880,12 +891,15 @@
#endif /* CONFIG_DPP */
INT(owe_group);
INT(owe_only);
+ INT(multi_ap_backhaul_sta);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
INT_DEF(disable_sgi, DEFAULT_DISABLE_SGI);
INT_DEF(disable_ldpc, DEFAULT_DISABLE_LDPC);
INT(ht40_intolerant);
+ INT_DEF(tx_stbc, DEFAULT_TX_STBC);
+ INT_DEF(rx_stbc, DEFAULT_RX_STBC);
INT_DEF(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU);
INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR);
INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY);
@@ -1248,6 +1262,8 @@
fprintf(f, "p2p_go_ht40=%d\n", config->p2p_go_ht40);
if (config->p2p_go_vht)
fprintf(f, "p2p_go_vht=%d\n", config->p2p_go_vht);
+ if (config->p2p_go_he)
+ fprintf(f, "p2p_go_he=%d\n", config->p2p_go_he);
if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW)
fprintf(f, "p2p_go_ctwindow=%d\n", config->p2p_go_ctwindow);
if (config->p2p_disabled)
@@ -1523,9 +1539,6 @@
if (config->p2p_interface_random_mac_addr)
fprintf(f, "p2p_interface_random_mac_addr=%d\n",
config->p2p_interface_random_mac_addr);
- if (config->bss_no_flush_when_down)
- fprintf(f, "bss_no_flush_when_down=%d\n",
- config->bss_no_flush_when_down);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index d2a52d7..1b2b1f1 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -33,10 +33,13 @@
#define DEFAULT_DISABLE_HT40 0
#define DEFAULT_DISABLE_SGI 0
#define DEFAULT_DISABLE_LDPC 0
+#define DEFAULT_TX_STBC -1 /* no change */
+#define DEFAULT_RX_STBC -1 /* no change */
#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
#define DEFAULT_AMPDU_FACTOR -1 /* no change */
#define DEFAULT_AMPDU_DENSITY -1 /* no change */
#define DEFAULT_USER_SELECTED_SIM 1
+#define DEFAULT_MAX_OPER_CHWIDTH -1
struct psk_list_entry {
struct dl_list list;
@@ -457,6 +460,17 @@
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ /**
+ * ocv - Enable/disable operating channel validation
+ *
+ * If this parameter is set to 1, stations will exchange OCI element
+ * to cryptographically verify the operating channel. Setting this
+ * parameter to 0 disables this option. Default value: 0.
+ */
+ int ocv;
+#endif /* CONFIG_OCV */
+
/**
* frequency - Channel frequency in megahertz (MHz) for IBSS
*
@@ -505,6 +519,8 @@
int vht;
+ int he;
+
int max_oper_chwidth;
unsigned int vht_center_freq1;
@@ -682,6 +698,22 @@
* By default (empty string): Use whatever the OS has configured.
*/
char *ht_mcs;
+
+ /**
+ * tx_stbc - Indicate STBC support for TX streams
+ *
+ * Value: -1..1, by default (-1): use whatever the OS or card has
+ * configured. See IEEE Std 802.11-2016, 9.4.2.56.2.
+ */
+ int tx_stbc;
+
+ /**
+ * rx_stbc - Indicate STBC support for RX streams
+ *
+ * Value: -1..3, by default (-1): use whatever the OS or card has
+ * configured. See IEEE Std 802.11-2016, 9.4.2.56.2.
+ */
+ int rx_stbc;
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
@@ -774,6 +806,33 @@
int macsec_integ_only;
/**
+ * macsec_replay_protect - Enable MACsec replay protection
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Replay protection disabled (default)
+ * 1: Replay protection enabled
+ */
+ int macsec_replay_protect;
+
+ /**
+ * macsec_replay_window - MACsec replay protection window
+ *
+ * A window in which replay is tolerated, to allow receipt of frames
+ * that have been misordered by the network.
+ *
+ * This setting applies only when MACsec replay protection active, i.e.,
+ * - macsec_replay_protect is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: No replay window, strict check (default)
+ * 1..2^32-1: number of packets that could be misordered
+ */
+ u32 macsec_replay_window;
+
+ /**
* macsec_port - MACsec port (in SCI)
*
* Port component of the SCI.
@@ -792,14 +851,16 @@
/**
* mka_ckn - MKA pre-shared CKN
*/
-#define MACSEC_CKN_LEN 32
- u8 mka_ckn[MACSEC_CKN_LEN];
+#define MACSEC_CKN_MAX_LEN 32
+ size_t mka_ckn_len;
+ u8 mka_ckn[MACSEC_CKN_MAX_LEN];
/**
* mka_cak - MKA pre-shared CAK
*/
-#define MACSEC_CAK_LEN 16
- u8 mka_cak[MACSEC_CAK_LEN];
+#define MACSEC_CAK_MAX_LEN 32
+ size_t mka_cak_len;
+ u8 mka_cak[MACSEC_CAK_MAX_LEN];
#define MKA_PSK_SET_CKN BIT(0)
#define MKA_PSK_SET_CAK BIT(1)
@@ -937,6 +998,13 @@
* the selection attempts for OWE BSS exceed the configured threshold.
*/
int owe_transition_bss_select_count;
+
+ /**
+ * multi_ap_backhaul_sta - Multi-AP backhaul STA
+ * 0 = normal (non-Multi-AP) station
+ * 1 = Multi-AP backhaul station
+ */
+ int multi_ap_backhaul_sta;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 77a3133..a0db9e4 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -56,6 +56,7 @@
#include "drivers/driver.h"
#include "mesh.h"
#include "dpp_supplicant.h"
+#include "sme.h"
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
@@ -2912,6 +2913,12 @@
pos += ret;
}
#endif /* CONFIG_FST */
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+ ret = os_snprintf(pos, end - pos, "[UTF-8]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -3987,6 +3994,22 @@
}
#endif /* CONFIG_IEEE80211R */
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) {
+ ret = os_snprintf(pos, end - pos, " FT-PSK");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, " SAE");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
return pos - buf;
}
@@ -4387,6 +4410,13 @@
}
#endif /* CONFIG_FILS */
+ if (os_strcmp(field, "multibss") == 0 && wpa_s->multi_bss_support) {
+ res = os_snprintf(buf, buflen, "MULTIBSS-STA");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4717,6 +4747,20 @@
pos += ret;
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_FST
+ if (wpa_bss_get_ie(bss, WLAN_EID_MULTI_BAND)) {
+ ret = os_snprintf(pos, end - pos, "[FST]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_FST */
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_UTF_8_SSID)) {
+ ret = os_snprintf(pos, end - pos, "[UTF-8]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\n");
if (os_snprintf_error(end - pos, ret))
@@ -5502,6 +5546,7 @@
int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
u8 _group_ssid[SSID_MAX_LEN], *group_ssid = NULL;
size_t group_ssid_len = 0;
+ int he;
if (!wpa_s->global->p2p_init_wpa_s)
return -1;
@@ -5514,7 +5559,7 @@
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] [vht] [auto] [ssid=<hexdump>] */
+ * [ht40] [vht] [he] [auto] [ssid=<hexdump>] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -5545,6 +5590,7 @@
vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
+ he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -5615,7 +5661,7 @@
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, freq2, persistent_id,
- pd, ht40, vht, max_oper_chwidth,
+ pd, ht40, vht, max_oper_chwidth, he,
group_ssid, group_ssid_len);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
@@ -6171,7 +6217,7 @@
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
- int ht40, vht, max_oper_chwidth, chwidth = 0, freq2 = 0;
+ int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -6208,6 +6254,7 @@
vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
vht;
+ he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
pos = os_strstr(cmd, "freq2=");
if (pos)
@@ -6222,7 +6269,7 @@
return -1;
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
- max_oper_chwidth, pref_freq);
+ max_oper_chwidth, pref_freq, he);
}
@@ -6270,7 +6317,8 @@
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
int id, int freq, int vht_center_freq2,
- int ht40, int vht, int vht_chwidth)
+ int ht40, int vht, int vht_chwidth,
+ int he)
{
struct wpa_ssid *ssid;
@@ -6284,7 +6332,7 @@
return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq,
vht_center_freq2, 0, ht40, vht,
- vht_chwidth, NULL, 0, 0);
+ vht_chwidth, he, NULL, 0, 0);
}
@@ -6293,6 +6341,7 @@
int freq = 0, persistent = 0, group_id = -1;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ int he = wpa_s->conf->p2p_go_he;
int max_oper_chwidth, chwidth = 0, freq2 = 0;
char *token, *context = NULL;
#ifdef CONFIG_ACS
@@ -6315,6 +6364,8 @@
} else if (os_strcmp(token, "vht") == 0) {
vht = 1;
ht40 = 1;
+ } else if (os_strcmp(token, "he") == 0) {
+ he = 1;
} else if (os_strcmp(token, "persistent") == 0) {
persistent = 1;
} else {
@@ -6350,10 +6401,10 @@
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
freq, freq2, ht40, vht,
- max_oper_chwidth);
+ max_oper_chwidth, he);
return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
- max_oper_chwidth);
+ max_oper_chwidth, he);
}
@@ -7941,6 +7992,10 @@
wpabuf_free(wpa_s->ric_ies);
wpa_s->ric_ies = NULL;
+
+ wpa_supplicant_update_channel_list(wpa_s, NULL);
+
+ free_bss_tmp_disallowed(wpa_s);
}
@@ -8763,26 +8818,39 @@
struct iphdr ip;
const u8 *pos;
unsigned int i;
+ char extra[30];
- if (len != HWSIM_PACKETLEN)
+ if (len < sizeof(*eth) + sizeof(ip) || len > HWSIM_PACKETLEN) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore unexpected length %d",
+ (int) len);
return;
+ }
eth = (const struct ether_header *) buf;
os_memcpy(&ip, eth + 1, sizeof(ip));
pos = &buf[sizeof(*eth) + sizeof(ip)];
if (ip.ihl != 5 || ip.version != 4 ||
- ntohs(ip.tot_len) != HWSIM_IP_LEN)
+ ntohs(ip.tot_len) > HWSIM_IP_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore unexpect IP header");
return;
-
- for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
- if (*pos != (u8) i)
- return;
- pos++;
}
- wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
- MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+ for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) {
+ if (*pos != (u8) i) {
+ wpa_printf(MSG_DEBUG,
+ "test data: RX - ignore mismatching payload");
+ return;
+ }
+ pos++;
+ }
+ extra[0] = '\0';
+ if (ntohs(ip.tot_len) != HWSIM_IP_LEN)
+ os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len));
+ wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s",
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra);
}
@@ -8826,7 +8894,7 @@
static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
{
u8 dst[ETH_ALEN], src[ETH_ALEN];
- char *pos;
+ char *pos, *pos2;
int used;
long int val;
u8 tos;
@@ -8835,11 +8903,12 @@
struct iphdr *ip;
u8 *dpos;
unsigned int i;
+ size_t send_len = HWSIM_IP_LEN;
if (wpa_s->l2_test == NULL)
return -1;
- /* format: <dst> <src> <tos> */
+ /* format: <dst> <src> <tos> [len=<length>] */
pos = cmd;
used = hwaddr_aton2(pos, dst);
@@ -8853,11 +8922,19 @@
return -1;
pos += used;
- val = strtol(pos, NULL, 0);
+ val = strtol(pos, &pos2, 0);
if (val < 0 || val > 0xff)
return -1;
tos = val;
+ pos = os_strstr(pos2, " len=");
+ if (pos) {
+ i = atoi(pos + 5);
+ if (i < sizeof(*ip) || i > HWSIM_IP_LEN)
+ return -1;
+ send_len = i;
+ }
+
eth = (struct ether_header *) &buf[2];
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
@@ -8868,17 +8945,17 @@
ip->version = 4;
ip->ttl = 64;
ip->tos = tos;
- ip->tot_len = htons(HWSIM_IP_LEN);
+ ip->tot_len = htons(send_len);
ip->protocol = 1;
ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1);
ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2);
ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
dpos = (u8 *) (ip + 1);
- for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
+ for (i = 0; i < send_len - sizeof(*ip); i++)
*dpos++ = i;
if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, &buf[2],
- HWSIM_PACKETLEN) < 0)
+ sizeof(struct ether_header) + send_len) < 0)
return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
@@ -9458,13 +9535,6 @@
return -1;
}
- if ((wpa_s->mac_addr_rand_supported & type) != type) {
- wpa_printf(MSG_INFO,
- "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
- type, wpa_s->mac_addr_rand_supported);
- return -1;
- }
-
if (enable > 1) {
wpa_printf(MSG_INFO,
"CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
@@ -9498,21 +9568,25 @@
}
if (type & MAC_ADDR_RAND_SCAN) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+ addr, mask))
+ return -1;
}
if (type & MAC_ADDR_RAND_SCHED_SCAN) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+ addr, mask))
+ return -1;
if (wpa_s->sched_scanning && !wpa_s->pno)
wpas_scan_restart_sched_scan(wpa_s);
}
if (type & MAC_ADDR_RAND_PNO) {
- wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
- addr, mask);
+ if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+ addr, mask))
+ return -1;
+
if (wpa_s->pno) {
wpas_stop_pno(wpa_s);
wpas_start_pno(wpa_s);
@@ -9858,6 +9932,11 @@
reply_len += eapol_sm_get_mib(wpa_s->eapol,
reply + reply_len,
reply_size - reply_len);
+#ifdef CONFIG_MACSEC
+ reply_len += ieee802_1x_kay_get_mib(
+ wpa_s->kay, reply + reply_len,
+ reply_size - reply_len);
+#endif /* CONFIG_MACSEC */
}
} else if (os_strncmp(buf, "STATUS", 6) == 0) {
reply_len = wpa_supplicant_ctrl_iface_status(
@@ -10506,6 +10585,12 @@
} else if (os_strcmp(buf, "RESEND_ASSOC") == 0) {
if (wpas_ctrl_resend_assoc(wpa_s) < 0)
reply_len = -1;
+#ifdef CONFIG_IEEE80211W
+ } else if (os_strcmp(buf, "UNPROT_DEAUTH") == 0) {
+ sme_event_unprot_disconnect(
+ wpa_s, wpa_s->bssid, NULL,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+#endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -10598,7 +10683,7 @@
if (wpas_dpp_configurator_remove(wpa_s, buf + 24) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_SIGN ", 22) == 0) {
- if (wpas_dpp_configurator_sign(wpa_s, buf + 22) < 0)
+ if (wpas_dpp_configurator_sign(wpa_s, buf + 21) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_GET_KEY ", 25) == 0) {
reply_len = wpas_dpp_configurator_get_key(wpa_s, atoi(buf + 25),
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index b88c80a..71fe7ed 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -570,8 +570,8 @@
}
}
- if (gid_set && chown(dir, -1, gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ if (gid_set && lchown(dir, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
dir, (int) gid, strerror(errno));
goto fail;
}
@@ -638,8 +638,8 @@
}
}
- if (gid_set && chown(fname, -1, gid) < 0) {
- wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+ if (gid_set && lchown(fname, -1, gid) < 0) {
+ wpa_printf(MSG_ERROR, "lchown[ctrl_interface=%s,gid=%d]: %s",
fname, (int) gid, strerror(errno));
goto fail;
}
@@ -1235,9 +1235,9 @@
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
(int) gid);
}
- if (chown(ctrl, -1, gid) < 0) {
+ if (lchown(ctrl, -1, gid) < 0) {
wpa_printf(MSG_ERROR,
- "chown[global_ctrl_interface=%s,gid=%d]: %s",
+ "lchown[global_ctrl_interface=%s,gid=%d]: %s",
ctrl, (int) gid, strerror(errno));
goto fail;
}
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index e0f16bb..fc2fc2e 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -13,6 +13,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+#include "ap/sta_info.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../bss.h"
@@ -128,7 +129,8 @@
* Notify listeners about event related with interface
*/
static void wpas_dbus_signal_interface(struct wpa_supplicant *wpa_s,
- const char *sig_name, int properties)
+ const char *sig_name,
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -230,7 +232,7 @@
*/
static void wpas_dbus_signal_bss(struct wpa_supplicant *wpa_s,
const char *bss_obj_path,
- const char *sig_name, int properties)
+ const char *sig_name, dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -364,7 +366,7 @@
*/
static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
- int properties)
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -1077,6 +1079,79 @@
}
+/**
+ * wpas_dbus_signal_station - Send an event signal related to a station object
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: Station object path
+ * @sig_name: signal name - StationAdded or StationRemoved
+ * @properties: Whether to add second argument with object properties
+ *
+ * Notify listeners about event related with station.
+ */
+static void wpas_dbus_signal_station(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path,
+ const char *sig_name,
+ dbus_bool_t properties)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ wpa_printf(MSG_DEBUG, "dbus: STA signal %s", sig_name);
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, sig_name);
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &station_obj_path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(iface, station_obj_path,
+ WPAS_DBUS_NEW_IFACE_STA,
+ &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_station_added - Send a Station added signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: new Station object path
+ *
+ * Notify listeners about adding new Station
+ */
+static void wpas_dbus_signal_station_added(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path)
+{
+ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationAdded", TRUE);
+}
+
+
+/**
+ * wpas_dbus_signal_station_removed - Send a Station removed signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @station_obj_path: Station object path
+ *
+ * Notify listeners about removing Station
+ */
+static void wpas_dbus_signal_station_removed(struct wpa_supplicant *wpa_s,
+ const char *station_obj_path)
+{
+ wpas_dbus_signal_station(wpa_s, station_obj_path, "StationRemoved",
+ FALSE);
+}
+
+
#ifdef CONFIG_P2P
/**
@@ -1882,7 +1957,7 @@
*/
static void wpas_dbus_signal_persistent_group(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
- int properties)
+ dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -2131,11 +2206,6 @@
case WPAS_DBUS_PROP_AP_SCAN:
prop = "ApScan";
break;
-#ifdef CONFIG_IEEE80211W
- case WPAS_DBUS_PROP_PMF:
- prop = "Pmf";
- break;
-#endif /* CONFIG_IEEE80211W */
case WPAS_DBUS_PROP_SCANNING:
prop = "Scanning";
break;
@@ -2151,6 +2221,9 @@
case WPAS_DBUS_PROP_BSSS:
prop = "BSSs";
break;
+ case WPAS_DBUS_PROP_STATIONS:
+ prop = "Stations";
+ break;
case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
prop = "CurrentAuthMode";
break;
@@ -2158,10 +2231,26 @@
prop = "DisconnectReason";
flush = TRUE;
break;
+ case WPAS_DBUS_PROP_AUTH_STATUS_CODE:
+ prop = "AuthStatusCode";
+ flush = TRUE;
+ break;
case WPAS_DBUS_PROP_ASSOC_STATUS_CODE:
prop = "AssocStatusCode";
flush = TRUE;
break;
+ case WPAS_DBUS_PROP_ROAM_TIME:
+ prop = "RoamTime";
+ break;
+ case WPAS_DBUS_PROP_ROAM_COMPLETE:
+ prop = "RoamComplete";
+ break;
+ case WPAS_DBUS_PROP_SESSION_LENGTH:
+ prop = "SessionLength";
+ break;
+ case WPAS_DBUS_PROP_BSS_TM_STATUS:
+ prop = "BSSTMStatus";
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -2244,6 +2333,41 @@
/**
+ * 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
*
@@ -2731,6 +2855,30 @@
NULL,
NULL
},
+ {
+ "RoamTime", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_roam_time,
+ NULL,
+ NULL
+ },
+ {
+ "RoamComplete", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+ wpas_dbus_getter_roam_complete,
+ NULL,
+ NULL
+ },
+ {
+ "SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_session_length,
+ NULL,
+ NULL
+ },
+ {
+ "BSSTMStatus", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
+ wpas_dbus_getter_bss_tm_status,
+ NULL,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -2857,6 +3005,157 @@
}
+static const struct wpa_dbus_property_desc wpas_dbus_sta_properties[] = {
+ { "Address", WPAS_DBUS_NEW_IFACE_STA, "ay",
+ wpas_dbus_getter_sta_address,
+ NULL, NULL
+ },
+ { "AID", WPAS_DBUS_NEW_IFACE_STA, "q",
+ wpas_dbus_getter_sta_aid,
+ NULL, NULL
+ },
+ { "Capabilities", WPAS_DBUS_NEW_IFACE_STA, "q",
+ wpas_dbus_getter_sta_caps,
+ NULL, NULL
+ },
+ { "RxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_rx_packets,
+ NULL, NULL
+ },
+ { "TxPackets", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_tx_packets,
+ NULL, NULL
+ },
+ { "RxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_rx_bytes,
+ NULL, NULL
+ },
+ { "TxBytes", WPAS_DBUS_NEW_IFACE_STA, "t",
+ wpas_dbus_getter_sta_tx_bytes,
+ NULL, NULL
+ },
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static const struct wpa_dbus_signal_desc wpas_dbus_sta_signals[] = {
+ /* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
+ { "PropertiesChanged", WPAS_DBUS_NEW_IFACE_STA,
+ {
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { NULL, NULL, { END_ARGS } }
+};
+
+
+/**
+ * wpas_dbus_unregister_sta - Unregister a connected station from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @sta: station MAC address
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters STA representing object from dbus.
+ */
+int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+
+ /* Do nothing if the control interface is not turned on */
+ if (!wpa_s || !wpa_s->global)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (!ctrl_iface)
+ return 0;
+
+ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta));
+
+ wpa_printf(MSG_DEBUG, "dbus: Unregister STA object '%s'",
+ station_obj_path);
+ if (wpa_dbus_unregister_object_per_iface(ctrl_iface,
+ station_obj_path)) {
+ wpa_printf(MSG_ERROR, "dbus: Cannot unregister STA object %s",
+ station_obj_path);
+ return -1;
+ }
+
+ wpas_dbus_signal_station_removed(wpa_s, station_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
+
+ return 0;
+}
+
+
+/**
+ * wpas_dbus_register_sta - Register a connected station with dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * @sta: station MAC address
+ * Returns: 0 on success, -1 on failure
+ *
+ * Registers STA representing object with dbus.
+ */
+int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta)
+{
+ struct wpas_dbus_priv *ctrl_iface;
+ struct wpa_dbus_object_desc *obj_desc;
+ char station_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ struct sta_handler_args *arg;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!wpa_s || !wpa_s->global)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus;
+ if (!ctrl_iface)
+ return 0;
+
+ os_snprintf(station_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta));
+
+ obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
+ if (!obj_desc) {
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
+ goto err;
+ }
+
+ arg = os_zalloc(sizeof(struct sta_handler_args));
+ if (!arg) {
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for handler");
+ goto err;
+ }
+ arg->wpa_s = wpa_s;
+ arg->sta = sta;
+
+ wpas_dbus_register(obj_desc, arg, wpa_dbus_free, NULL,
+ wpas_dbus_sta_properties, wpas_dbus_sta_signals);
+
+ wpa_printf(MSG_DEBUG, "dbus: Register STA object '%s'",
+ station_obj_path);
+ if (wpa_dbus_register_object_per_iface(ctrl_iface, station_obj_path,
+ wpa_s->ifname, obj_desc)) {
+ wpa_printf(MSG_ERROR,
+ "Cannot register STA dbus object %s",
+ station_obj_path);
+ goto err;
+ }
+
+ wpas_dbus_signal_station_added(wpa_s, station_obj_path);
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATIONS);
+
+ return 0;
+
+err:
+ free_dbus_object_desc(obj_desc);
+ return -1;
+}
+
+
static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_scan,
@@ -3307,13 +3606,6 @@
wpas_dbus_setter_ap_scan,
NULL
},
-#ifdef CONFIG_IEEE80211W
- { "Pmf", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
- wpas_dbus_getter_pmf,
- wpas_dbus_setter_pmf,
- NULL
- },
-#endif /* CONFIG_IEEE80211W */
{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_bss_expire_age,
wpas_dbus_setter_bss_expire_age,
@@ -3484,6 +3776,11 @@
NULL,
NULL
},
+ { "AuthStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
+ wpas_dbus_getter_auth_status_code,
+ NULL,
+ NULL
+ },
{ "AssocStatusCode", WPAS_DBUS_NEW_IFACE_INTERFACE, "i",
wpas_dbus_getter_assoc_status_code,
NULL,
@@ -3501,6 +3798,11 @@
NULL
},
#endif /* CONFIG_MESH */
+ { "Stations", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
+ wpas_dbus_getter_stas,
+ NULL,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -3770,6 +4072,19 @@
END_ARGS
}
},
+ { "StationAdded", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "StationRemoved", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
{
{ "path", "o", ARG_OUT },
@@ -4050,6 +4365,11 @@
NULL,
NULL
},
+ { "VSIE", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
+ wpas_dbus_getter_p2p_peer_vsie,
+ NULL,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4078,7 +4398,7 @@
*/
static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
const u8 *dev_addr, const char *interface,
- const char *sig_name, int properties)
+ const char *sig_name, dbus_bool_t properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index e68acb7..42db389 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -22,15 +22,20 @@
enum wpas_dbus_prop {
WPAS_DBUS_PROP_AP_SCAN,
- WPAS_DBUS_PROP_PMF,
WPAS_DBUS_PROP_SCANNING,
WPAS_DBUS_PROP_STATE,
WPAS_DBUS_PROP_CURRENT_BSS,
WPAS_DBUS_PROP_CURRENT_NETWORK,
WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
WPAS_DBUS_PROP_BSSS,
+ WPAS_DBUS_PROP_STATIONS,
WPAS_DBUS_PROP_DISCONNECT_REASON,
+ WPAS_DBUS_PROP_AUTH_STATUS_CODE,
WPAS_DBUS_PROP_ASSOC_STATUS_CODE,
+ WPAS_DBUS_PROP_ROAM_TIME,
+ WPAS_DBUS_PROP_ROAM_COMPLETE,
+ WPAS_DBUS_PROP_SESSION_LENGTH,
+ WPAS_DBUS_PROP_BSS_TM_STATUS,
};
enum wpas_dbus_bss_prop {
@@ -46,6 +51,10 @@
WPAS_DBUS_BSS_PROP_AGE,
};
+enum wpas_dbus_sta_prop {
+ WPAS_DBUS_STA_PROP_ADDRESS,
+};
+
#define WPAS_DBUS_OBJECT_PATH_MAX 150
#define WPAS_DBUS_NEW_SERVICE "fi.w1.wpa_supplicant1"
@@ -62,6 +71,9 @@
#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
#define WPAS_DBUS_NEW_IFACE_BSS WPAS_DBUS_NEW_INTERFACE ".BSS"
+#define WPAS_DBUS_NEW_STAS_PART "Stations"
+#define WPAS_DBUS_NEW_IFACE_STA WPAS_DBUS_NEW_INTERFACE ".Station"
+
#define WPAS_DBUS_NEW_IFACE_P2PDEVICE \
WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
@@ -164,6 +176,8 @@
u8 bssid[ETH_ALEN], unsigned int id);
int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN], unsigned int id);
+int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s, const u8 *sta);
+int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s, const u8 *sta);
void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
const char *name);
void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
@@ -346,6 +360,18 @@
return 0;
}
+static inline int wpas_dbus_unregister_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ return 0;
+}
+
+static inline int wpas_dbus_register_sta(struct wpa_supplicant *wpa_s,
+ const u8 *sta)
+{
+ return 0;
+}
+
static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
const char *name)
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index a3c98fa..6c36d91 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -15,6 +15,9 @@
#include "eap_peer/eap_methods.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ap_drv_ops.h"
#include "../config.h"
#include "../wpa_supplicant_i.h"
#include "../driver_i.h"
@@ -22,6 +25,7 @@
#include "../bss.h"
#include "../scan.h"
#include "../autoscan.h"
+#include "../ap.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
@@ -980,8 +984,8 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[8] = { NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL };
+ const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL };
size_t num_items = 0;
#ifdef CONFIG_FILS
struct wpa_global *global = user_data;
@@ -1020,6 +1024,12 @@
if (fils_sk_pfs_supported)
capabilities[num_items++] = "fils_sk_pfs";
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ capabilities[num_items++] = "ft";
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SHA384
+ capabilities[num_items++] = "sha384";
+#endif /* CONFIG_SHA384 */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -3012,61 +3022,6 @@
}
-#ifdef CONFIG_IEEE80211W
-
-/**
- * wpas_dbus_getter_pmf - Control PMF default
- * @iter: Pointer to incoming dbus message iter
- * @error: Location to store error on failure
- * @user_data: Function specific data
- * Returns: TRUE on success, FALSE on failure
- *
- * Getter function for "Pmf" property.
- */
-dbus_bool_t wpas_dbus_getter_pmf(
- const struct wpa_dbus_property_desc *property_desc,
- DBusMessageIter *iter, DBusError *error, void *user_data)
-{
- struct wpa_supplicant *wpa_s = user_data;
- dbus_uint32_t pmf = wpa_s->conf->pmf;
-
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
- &pmf, error);
-}
-
-
-/**
- * wpas_dbus_setter_pmf - Control PMF default
- * @iter: Pointer to incoming dbus message iter
- * @error: Location to store error on failure
- * @user_data: Function specific data
- * Returns: TRUE on success, FALSE on failure
- *
- * Setter function for "Pmf" property.
- */
-dbus_bool_t wpas_dbus_setter_pmf(
- const struct wpa_dbus_property_desc *property_desc,
- DBusMessageIter *iter, DBusError *error, void *user_data)
-{
- struct wpa_supplicant *wpa_s = user_data;
- dbus_uint32_t pmf;
-
- if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
- &pmf))
- return FALSE;
-
- if (pmf > 2) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "Pmf must be 0, 1, or 2");
- return FALSE;
- }
- wpa_s->conf->pmf = pmf;
- return TRUE;
-}
-
-#endif /* CONFIG_IEEE80211W */
-
-
/**
* wpas_dbus_getter_fast_reauth - Control fast
* reauthentication (TLS session resumption)
@@ -3138,6 +3093,27 @@
/**
+ * wpas_dbus_getter_auth_status_code - Get most recent auth status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AuthStatusCode" property.
+ */
+dbus_bool_t wpas_dbus_getter_auth_status_code(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_int32_t reason = wpa_s->auth_status_code;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
+ &reason, error);
+}
+
+
+/**
* wpas_dbus_getter_assoc_status_code - Get most recent failed assoc status code
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3159,6 +3135,97 @@
/**
+ * wpas_dbus_getter_roam_time - Get most recent roam time
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RoamTime" property.
+ */
+dbus_bool_t wpas_dbus_getter_roam_time(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t roam_time = wpa_s->roam_time.sec * 1000 +
+ wpa_s->roam_time.usec / 1000;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &roam_time, error);
+}
+
+
+/**
+ * wpas_dbus_getter_roam_complete - Get most recent roam success or failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RoamComplete" property.
+ */
+dbus_bool_t wpas_dbus_getter_roam_complete(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_bool_t roam_complete = os_reltime_initialized(&wpa_s->roam_time);
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+ &roam_complete, error);
+}
+
+
+/**
+ * wpas_dbus_getter_session_length - Get most recent BSS session length
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "SessionLength" property.
+ */
+dbus_bool_t wpas_dbus_getter_session_length(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t session_length = wpa_s->session_length.sec * 1000 +
+ wpa_s->session_length.usec / 1000;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &session_length, error);
+}
+
+
+/**
+ * wpas_dbus_getter_bss_tm_status - Get most BSS Transition Management request
+ * status code
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "BSSTMStatus" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_tm_status(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_WNM
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_uint32_t bss_tm_status = wpa_s->bss_tm_status;
+#else /* CONFIG_WNM */
+ dbus_uint32_t bss_tm_status = 0;
+#endif /* CONFIG_WNM */
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+ &bss_tm_status, error);
+}
+
+
+/**
* wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -3854,6 +3921,320 @@
}
+/**
+ * wpas_dbus_getter_stas - Get connected stations for an interface
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: a list of stations
+ *
+ * Getter for "Stations" property.
+ */
+dbus_bool_t wpas_dbus_getter_stas(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ struct sta_info *sta = NULL;
+ char **paths = NULL;
+ unsigned int i = 0, num = 0;
+ dbus_bool_t success = FALSE;
+
+ if (!wpa_s->dbus_new_path) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: no D-Bus interface", __func__);
+ return FALSE;
+ }
+
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ struct hostapd_data *hapd;
+
+ hapd = wpa_s->ap_iface->bss[0];
+ sta = hapd->sta_list;
+ num = hapd->num_sta;
+ }
+#endif /* CONFIG_AP */
+
+ paths = os_calloc(num, sizeof(char *));
+ if (!paths) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ /* Loop through scan results and append each result's object path */
+ for (; sta; sta = sta->next) {
+ paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (!paths[i]) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ goto out;
+ }
+ /* Construct the object path for this BSS. */
+ os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_STAS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(sta->addr));
+ }
+
+ success = wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_OBJECT_PATH,
+ paths, num,
+ error);
+
+out:
+ while (i)
+ os_free(paths[--i]);
+ os_free(paths);
+ return success;
+}
+
+
+/**
+ * wpas_dbus_getter_sta_address - Return the address of a connected station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Address" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_address(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ sta->addr, ETH_ALEN,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_sta_aid - Return the AID of a connected station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "AID" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_aid(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+ &sta->aid,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_sta_caps - Return the capabilities of a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_caps(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(args->wpa_s->ap_iface->bss[0], args->sta);
+ if (!sta)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+ &sta->capability,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_rx_packets - Return the received packets for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RxPackets" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_rx_packets(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.rx_packets,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_tx_packets - Return the transmitted packets for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "TxPackets" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_tx_packets(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.tx_packets,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_tx_bytes - Return the transmitted bytes for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "TxBytes" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_tx_bytes(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.tx_bytes,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
+/**
+ * wpas_dbus_getter_rx_bytes - Return the received bytes for a station
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "RxBytes" property.
+ */
+dbus_bool_t wpas_dbus_getter_sta_rx_bytes(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+#ifdef CONFIG_AP
+ struct sta_handler_args *args = user_data;
+ struct sta_info *sta;
+ struct hostap_sta_driver_data data;
+ struct hostapd_data *hapd;
+
+ if (!args->wpa_s->ap_iface)
+ return FALSE;
+
+ hapd = args->wpa_s->ap_iface->bss[0];
+ sta = ap_get_sta(hapd, args->sta);
+ if (!sta)
+ return FALSE;
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
+ return FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT64,
+ &data.rx_bytes,
+ error);
+#else /* CONFIG_AP */
+ return FALSE;
+#endif /* CONFIG_AP */
+}
+
+
static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
DBusError *error, const char *func_name)
{
@@ -4116,7 +4497,7 @@
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[13]; /* max 13 key managements may be supported */
+ const char *key_mgmt[15]; /* max 15 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4126,7 +4507,12 @@
if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
goto nomem;
- /* KeyMgmt */
+ /*
+ * KeyMgmt
+ *
+ * When adding a new entry here, please take care to extend key_mgmt[]
+ * and keep documentation in doc/dbus.doxygen up to date.
+ */
n = 0;
if (ie_data->key_mgmt & WPA_KEY_MGMT_PSK)
key_mgmt[n++] = "wpa-psk";
@@ -4158,6 +4544,12 @@
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
key_mgmt[n++] = "wpa-ft-fils-sha384";
#endif /* CONFIG_FILS */
+#ifdef CONFIG_SAE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_SAE)
+ key_mgmt[n++] = "sae";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
+ key_mgmt[n++] = "ft-sae";
+#endif /* CONFIG_SAE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 26652ad..d922ce1 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -22,6 +22,11 @@
unsigned int id;
};
+struct sta_handler_args {
+ struct wpa_supplicant *wpa_s;
+ const u8 *sta;
+};
+
dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
const int type,
const void *val,
@@ -141,13 +146,16 @@
DECLARE_ACCESSOR(wpas_dbus_getter_scanning);
DECLARE_ACCESSOR(wpas_dbus_getter_ap_scan);
DECLARE_ACCESSOR(wpas_dbus_setter_ap_scan);
-DECLARE_ACCESSOR(wpas_dbus_getter_pmf);
-DECLARE_ACCESSOR(wpas_dbus_setter_pmf);
DECLARE_ACCESSOR(wpas_dbus_getter_fast_reauth);
DECLARE_ACCESSOR(wpas_dbus_setter_fast_reauth);
DECLARE_ACCESSOR(wpas_dbus_getter_disconnect_reason);
DECLARE_ACCESSOR(wpas_dbus_getter_disassociate_reason);
+DECLARE_ACCESSOR(wpas_dbus_getter_auth_status_code);
DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code);
+DECLARE_ACCESSOR(wpas_dbus_getter_roam_time);
+DECLARE_ACCESSOR(wpas_dbus_getter_roam_complete);
+DECLARE_ACCESSOR(wpas_dbus_getter_session_length);
+DECLARE_ACCESSOR(wpas_dbus_getter_bss_tm_status);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age);
DECLARE_ACCESSOR(wpas_dbus_setter_bss_expire_age);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_count);
@@ -168,6 +176,14 @@
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
+DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_packets);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_packets);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_tx_bytes);
+DECLARE_ACCESSOR(wpas_dbus_getter_sta_rx_bytes);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_bssid);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_ssid);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_privacy);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 9305b9a..8cdd885 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -384,14 +384,14 @@
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0,
- 0, 0, NULL, 0, 0)) {
+ 0, 0, 0, NULL, 0, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0,
- 0))
+ 0, 0))
goto inv_args;
out:
@@ -505,6 +505,7 @@
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ wpas_p2p_stop_find(wpa_s);
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->force_long_sd = 0;
p2p_flush(wpa_s->global->p2p);
@@ -532,6 +533,7 @@
int new_pin;
char *err_msg = NULL;
char *iface = NULL;
+ int ret;
if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
return reply;
@@ -603,13 +605,19 @@
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, 0, -1, 0, 0, 0, 0, NULL, 0);
+ go_intent, freq, 0, -1, 0, 0, 0, 0, 0,
+ NULL, 0);
if (new_pin >= 0) {
char npin[9];
char *generated_pin;
- os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+ ret = os_snprintf(npin, sizeof(npin), "%08d", new_pin);
+ if (os_snprintf_error(sizeof(npin), ret)) {
+ reply = wpas_dbus_error_unknown_error(message,
+ "invalid PIN");
+ goto out;
+ }
generated_pin = npin;
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING,
@@ -755,7 +763,7 @@
goto err;
if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
- 0) < 0) {
+ 0, 0) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -1910,6 +1918,30 @@
return success;
}
+dbus_bool_t wpas_dbus_getter_p2p_peer_vsie(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct peer_handler_args *peer_args = user_data;
+ const struct p2p_peer_info *info;
+
+ info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
+ peer_args->p2p_device_addr, 0);
+ if (!info) {
+ dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
+ return FALSE;
+ }
+
+ if (!info->vendor_elems)
+ return wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_BYTE,
+ NULL, 0, error);
+
+ return wpas_dbus_simple_array_property_getter(
+ iter, DBUS_TYPE_BYTE, (char *) info->vendor_elems->buf,
+ info->vendor_elems->used, error);
+}
+
/**
* wpas_dbus_getter_persistent_groups - Get array of persistent group objects
@@ -2661,7 +2693,7 @@
if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
goto error;
- if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
@@ -2673,26 +2705,27 @@
bonjour = 1;
else
goto error_clear;
- wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "version") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
+ version = entry.uint32_value;
+ } else if (os_strcmp(entry.key, "service") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(service);
+ service = os_strdup(entry.str_value);
+ } else if (os_strcmp(entry.key, "query") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
+ goto error_clear;
+ wpabuf_free(query);
+ query = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ } else {
+ goto error_clear;
}
+
+ wpa_dbus_dict_entry_clear(&entry);
}
if (upnp == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
- if (os_strcmp(entry.key, "version") == 0 &&
- entry.type == DBUS_TYPE_INT32)
- version = entry.uint32_value;
- else if (os_strcmp(entry.key, "service") == 0 &&
- entry.type == DBUS_TYPE_STRING) {
- os_free(service);
- service = os_strdup(entry.str_value);
- } else
- goto error_clear;
-
- wpa_dbus_dict_entry_clear(&entry);
- }
-
if (version <= 0 || service == NULL)
goto error;
@@ -2700,24 +2733,6 @@
if (ret != 0)
goto error;
} else if (bonjour == 1) {
- while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- if (os_strcmp(entry.key, "query") == 0) {
- if (entry.type != DBUS_TYPE_ARRAY ||
- entry.array_type != DBUS_TYPE_BYTE)
- goto error_clear;
- wpabuf_free(query);
- query = wpabuf_alloc_copy(
- entry.bytearray_value,
- entry.array_len);
- } else
- goto error_clear;
-
- wpa_dbus_dict_entry_clear(&entry);
- }
-
if (query == NULL)
goto error;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index c4c0261..b3c45c1 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -114,6 +114,7 @@
DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_ies);
DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_device_address);
DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_groups);
+DECLARE_ACCESSOR(wpas_dbus_getter_p2p_peer_vsie);
/*
* P2P Group properties
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index f762b3f..19c1a61 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -286,8 +286,12 @@
ret = wpas_wps_start_pin(wpa_s, params.bssid,
params.pin, 0,
DEV_PW_DEFAULT);
- if (ret > 0)
- os_snprintf(npin, sizeof(npin), "%08d", ret);
+ if (ret > 0) {
+ ret = os_snprintf(npin, sizeof(npin), "%08d", ret);
+ if (os_snprintf_error(sizeof(npin), ret))
+ return wpas_dbus_error_unknown_error(
+ message, "invalid PIN");
+ }
} else {
ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
}
diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
index 5309a53..987e12d 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
@@ -71,7 +71,7 @@
char *arg_bssid;
char *pin = NULL;
u8 bssid[ETH_ALEN], *_bssid = NULL;
- int ret = 0;
+ int ret;
char npin[9];
if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
@@ -105,7 +105,11 @@
return NULL;
if (ret > 0) {
- os_snprintf(npin, sizeof(npin), "%08d", ret);
+ ret = os_snprintf(npin, sizeof(npin), "%08d", ret);
+ if (os_snprintf_error(sizeof(npin), ret))
+ return wpas_dbus_new_invalid_opts_error(message,
+ "invalid PIN");
+
pin = npin;
}
dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 08f5857..b51675b 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -44,7 +44,7 @@
#CONFIG_LIBNL20=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
-#CONFIG_LIBNL32=y
+CONFIG_LIBNL32=y
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
@@ -301,6 +301,9 @@
# Driver support is also needed for IEEE 802.11w.
#CONFIG_IEEE80211W=y
+# Support Operating Channel Validation
+#CONFIG_OCV=y
+
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
@@ -458,6 +461,11 @@
# that meet the requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# Should we attempt to use the getrandom(2) call that provides more reliable
+# yet secure randomness source than /dev/random on Linux 3.17 and newer.
+# Requires glibc 2.25 to build, falls back to /dev/random if unavailable.
+#CONFIG_GETRANDOM=y
+
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
#CONFIG_IEEE80211N=y
@@ -561,8 +569,6 @@
#CONFIG_MBO=y
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
-# Note: This is an experimental and not yet complete implementation. This
-# should not be enabled for production use.
#CONFIG_FILS=y
# FILS shared key authentication with PFS
#CONFIG_FILS_SK_PFS=y
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index 25cfd06..e7705ab 100644
--- a/wpa_supplicant/doc/docbook/eapol_test.sgml
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -194,7 +194,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index fa94ae4..f6a0ca8 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,7 +90,7 @@
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index be3045a..dc7fee4 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -345,7 +345,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index cee9ed6..31214e3 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -91,7 +91,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index 6667a07..ed9baf1 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -62,7 +62,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index 3796b93..dd44565 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,7 +137,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 80b3878..ebf102e 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -246,9 +246,18 @@
<variablelist>
<varlistentry>
+ <term>nl80211</term>
+ <listitem>
+ <para>Uses the modern Linux nl80211/cfg80211 netlink-based
+ interface (most new drivers).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>wext</term>
<listitem>
- <para>Linux wireless extensions (generic).</para>
+ <para>Uses the legacy Linux wireless extensions ioctl-based
+ interface (older hardware/drivers).</para>
</listitem>
</varlistentry>
@@ -538,10 +547,14 @@
<itemizedlist>
<listitem>
- <para>Linux kernel 2.4.x or 2.6.x with Linux Wireless
- Extensions v15 or newer</para>
+ <para>Linux kernel 2.6.30 or higher with
+ nl80211/cfg80211 support</para>
</listitem>
+ <listitem>
+ <para>Linux kernel 2.4.x or higher with Linux Wireless
+ Extensions v15 or newer</para>
+ </listitem>
<listitem>
<para>FreeBSD 6-CURRENT</para>
@@ -558,6 +571,13 @@
<title>Supported Drivers</title>
<variablelist>
<varlistentry>
+ <term>Linux nl80211/cfg80211</term>
+ <listitem>
+ <para>This is the preferred driver for Linux.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>Linux wireless extensions</term>
<listitem>
<para>In theory, any driver that supports Linux wireless
@@ -729,7 +749,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2017,
+ <para>wpa_supplicant is copyright (c) 2003-2019,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 22ba902..8877f7a 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -529,9 +529,9 @@
}
-static void wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth,
- const char *cmd)
+static int wpas_dpp_set_configurator(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth,
+ const char *cmd)
{
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
@@ -545,7 +545,7 @@
char *group_id = NULL;
if (!cmd)
- return;
+ return 0;
wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
pos = os_strstr(cmd, " ssid=");
@@ -609,10 +609,12 @@
conf_sta->akm = DPP_AKM_PSK;
if (psk_set) {
os_memcpy(conf_sta->psk, psk, PMK_LEN);
- } else {
+ } else if (pass_len > 0) {
conf_sta->passphrase = os_strdup(pass);
if (!conf_sta->passphrase)
goto fail;
+ } else {
+ goto fail;
}
} else if (os_strstr(cmd, " conf=sta-dpp")) {
conf_sta->akm = DPP_AKM_DPP;
@@ -686,13 +688,14 @@
auth->conf_ap = conf_ap;
auth->conf = conf;
os_free(group_id);
- return;
+ return 0;
fail:
- wpa_printf(MSG_DEBUG, "DPP: Failed to set configurator parameters");
+ wpa_msg(wpa_s, MSG_INFO, "DPP: Failed to set configurator parameters");
dpp_configuration_free(conf_sta);
dpp_configuration_free(conf_ap);
os_free(group_id);
+ return -1;
}
@@ -872,7 +875,11 @@
if (!wpa_s->dpp_auth)
goto fail;
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, cmd);
+ if (wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth, cmd) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ goto fail;
+ }
wpa_s->dpp_auth->neg_freq = neg_freq;
@@ -938,6 +945,7 @@
wpa_printf(MSG_DEBUG,
"DPP: Failed to request the driver to remain on channel (%u MHz) for listen",
lwork->freq);
+ wpa_s->dpp_listen_freq = 0;
wpas_dpp_listen_work_done(wpa_s);
wpa_s->dpp_pending_listen_freq = 0;
return;
@@ -1018,29 +1026,6 @@
}
-void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
- unsigned int freq)
-{
- if (!wpa_s->dpp_listen_freq && !wpa_s->dpp_pending_listen_freq)
- return;
-
- wpa_printf(MSG_DEBUG,
- "DPP: remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u)",
- wpa_s->off_channel_freq, wpa_s->dpp_pending_listen_freq,
- wpa_s->roc_waiting_drv_freq, freq);
- if (wpa_s->off_channel_freq &&
- wpa_s->off_channel_freq == wpa_s->dpp_pending_listen_freq) {
- wpa_printf(MSG_DEBUG, "DPP: Listen on %u MHz started", freq);
- wpa_s->dpp_pending_listen_freq = 0;
- } else {
- wpa_printf(MSG_DEBUG,
- "DPP: Ignore remain-on-channel callback (off_channel_freq=%u dpp_pending_listen_freq=%d freq=%u)",
- wpa_s->off_channel_freq,
- wpa_s->dpp_pending_listen_freq, freq);
- }
-}
-
-
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
@@ -1145,8 +1130,12 @@
return;
}
wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth);
- wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth,
- wpa_s->dpp_configurator_params);
+ if (wpas_dpp_set_configurator(wpa_s, wpa_s->dpp_auth,
+ wpa_s->dpp_configurator_params) < 0) {
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
+ return;
+ }
os_memcpy(wpa_s->dpp_auth->peer_mac_addr, src, ETH_ALEN);
if (wpa_s->dpp_listen_freq &&
@@ -1353,7 +1342,8 @@
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
return;
}
- if (!resp || status_code != WLAN_STATUS_SUCCESS) {
+ if (result != GAS_QUERY_SUCCESS ||
+ !resp || status_code != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "DPP: GAS query did not succeed");
goto fail;
}
@@ -2303,9 +2293,9 @@
return -1;
curve = get_param(cmd, " curve=");
- wpas_dpp_set_configurator(wpa_s, auth, cmd);
-
- if (dpp_configurator_own_config(auth, curve, 0) == 0) {
+ wpas_dpp_set_testing_options(wpa_s, auth);
+ if (wpas_dpp_set_configurator(wpa_s, auth, cmd) == 0 &&
+ dpp_configurator_own_config(auth, curve, 0) == 0) {
wpas_dpp_handle_config_obj(wpa_s, auth);
ret = 0;
}
diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h
index 9b539df..5a4f06e 100644
--- a/wpa_supplicant/dpp_supplicant.h
+++ b/wpa_supplicant/dpp_supplicant.h
@@ -19,8 +19,6 @@
int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd);
int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd);
void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s);
-void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
- unsigned int freq);
void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq);
void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 078de23..4a9f472 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -492,6 +492,14 @@
return -1;
}
+static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
+ struct wpa_channel_info *ci)
+{
+ if (wpa_s->driver->channel_info)
+ return wpa_s->driver->channel_info(wpa_s->drv_priv, ci);
+ return -1;
+}
+
static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s,
struct hostap_sta_driver_data *sta)
{
@@ -796,6 +804,14 @@
return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, sa);
}
+static inline int wpa_drv_set_receive_lowest_pn(struct wpa_supplicant *wpa_s,
+ struct receive_sa *sa)
+{
+ if (!wpa_s->driver->set_receive_lowest_pn)
+ return -1;
+ return wpa_s->driver->set_receive_lowest_pn(wpa_s->drv_priv, sa);
+}
+
static inline int
wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, struct receive_sc *sc,
unsigned int conf_offset, int validation)
@@ -1046,4 +1062,12 @@
params);
}
+static inline int wpa_drv_set_4addr_mode(struct wpa_supplicant *wpa_s, int val)
+{
+ if (!wpa_s->driver->set_4addr_mode)
+ return -1;
+ return wpa_s->driver->set_4addr_mode(wpa_s->drv_priv,
+ wpa_s->bridge_ifname, val);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 6548bd1..3fd4ce6 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -711,7 +711,8 @@
eap = (struct eap_hdr *) (hdr + 1);
eap->code = EAP_CODE_REQUEST;
- eap->identifier = 0;
+ if (os_get_random((u8 *) &eap->identifier, sizeof(eap->identifier)) < 0)
+ eap->identifier = os_random() & 0xff;
eap->length = htons(5);
pos = (u8 *) (eap + 1);
*pos = EAP_TYPE_IDENTITY;
diff --git a/wpa_supplicant/eapol_test.py b/wpa_supplicant/eapol_test.py
index 80e7dfc..734428d 100644
--- a/wpa_supplicant/eapol_test.py
+++ b/wpa_supplicant/eapol_test.py
@@ -136,7 +136,7 @@
results = res[i].get(False)
except:
results = "N/A"
- print "%d: %s" % (i, results)
+ print("%d: %s" % (i, results))
if __name__ == "__main__":
main()
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index ef28ffe..8ede2bb 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -293,6 +293,13 @@
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
return;
+ if (os_reltime_initialized(&wpa_s->session_start)) {
+ os_reltime_age(&wpa_s->session_start, &wpa_s->session_length);
+ wpa_s->session_start.sec = 0;
+ wpa_s->session_start.usec = 0;
+ wpas_notify_session_length(wpa_s);
+ }
+
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
@@ -324,6 +331,9 @@
os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->ieee80211ac = 0;
+
+ if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+ wpa_s->enabled_4addr_mode = 0;
}
@@ -1335,10 +1345,10 @@
continue;
}
- if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
+ if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO retry delay has not passed yet");
+ " skip - AP temporarily disallowed");
continue;
}
#ifdef CONFIG_TESTING_OPTIONS
@@ -2267,6 +2277,50 @@
#endif /* CONFIG_INTERWORKING */
+static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+ const u8 *map_sub_elem, *pos;
+ size_t len;
+
+ if (!wpa_s->current_ssid ||
+ !wpa_s->current_ssid->multi_ap_backhaul_sta ||
+ !ies ||
+ ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+ return;
+
+ if (!elems.multi_ap || elems.multi_ap_len < 7) {
+ wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol");
+ goto fail;
+ }
+
+ pos = elems.multi_ap + 4;
+ len = elems.multi_ap_len - 4;
+
+ map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE);
+ if (!map_sub_elem || map_sub_elem[1] < 1) {
+ wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type");
+ goto fail;
+ }
+
+ if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) {
+ wpa_printf(MSG_INFO, "AP doesn't support backhaul BSS");
+ goto fail;
+ }
+
+ if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set 4addr mode");
+ goto fail;
+ }
+ wpa_s->enabled_4addr_mode = 1;
+ return;
+
+fail:
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+}
+
+
#ifdef CONFIG_FST
static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
const u8 *ie, size_t ie_len)
@@ -2343,6 +2397,9 @@
get_ie(data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
wpa_s->ieee80211ac = 1;
+
+ multi_ap_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
}
if (data->assoc_info.beacon_ies)
wpa_hexdump(MSG_DEBUG, "beacon_ies",
@@ -2648,6 +2705,16 @@
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (os_reltime_initialized(&wpa_s->session_start)) {
+ os_reltime_age(&wpa_s->session_start,
+ &wpa_s->session_length);
+ wpa_s->session_start.sec = 0;
+ wpa_s->session_start.usec = 0;
+ wpas_notify_session_length(wpa_s);
+ } else {
+ wpas_notify_auth_changed(wpa_s);
+ os_get_reltime(&wpa_s->session_start);
+ }
wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
new_bss = 1;
@@ -2738,7 +2805,7 @@
}
wpa_supplicant_cancel_scan(wpa_s);
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
/*
* We are done; the driver will take care of RSN 4-way
@@ -2748,7 +2815,7 @@
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+ } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
* The driver will take care of RSN 4-way handshake, so we need
@@ -3010,7 +3077,7 @@
!disallowed_ssid(wpa_s, fast_reconnect->ssid,
fast_reconnect->ssid_len) &&
!wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
- !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
+ !wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) {
#ifndef CONFIG_NO_SCAN_PROCESSING
wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
if (wpa_supplicant_connect(wpa_s, fast_reconnect,
@@ -3583,8 +3650,8 @@
}
-static void wpa_supplicant_update_channel_list(
- struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
+void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
+ struct channel_list_changed *info)
{
struct wpa_supplicant *ifs;
u8 dfs_domain;
@@ -3598,10 +3665,13 @@
for (ifs = wpa_s; ifs->parent && ifs != ifs->parent; ifs = ifs->parent)
;
- wpa_msg(ifs, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
- reg_init_str(info->initiator), reg_type_str(info->type),
- info->alpha2[0] ? " alpha2=" : "",
- info->alpha2[0] ? info->alpha2 : "");
+ if (info) {
+ wpa_msg(ifs, MSG_INFO,
+ WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+ reg_init_str(info->initiator), reg_type_str(info->type),
+ info->alpha2[0] ? " alpha2=" : "",
+ info->alpha2[0] ? info->alpha2 : "");
+ }
if (wpa_s->drv_priv == NULL)
return; /* Ignore event during drv initialization */
@@ -3840,7 +3910,7 @@
struct dfs_event *radar)
{
#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
- if (wpa_s->ap_iface) {
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
wpas_ap_event_dfs_cac_started(wpa_s, radar);
} else
#endif /* NEED_AP_MLME && CONFIG_AP */
@@ -3861,7 +3931,7 @@
struct dfs_event *radar)
{
#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
- if (wpa_s->ap_iface) {
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
wpas_ap_event_dfs_cac_finished(wpa_s, radar);
} else
#endif /* NEED_AP_MLME && CONFIG_AP */
@@ -3877,7 +3947,7 @@
struct dfs_event *radar)
{
#if defined(NEED_AP_MLME) && defined(CONFIG_AP)
- if (wpa_s->ap_iface) {
+ if (wpa_s->ap_iface || wpa_s->ifmsh) {
wpas_ap_event_dfs_cac_aborted(wpa_s, radar);
} else
#endif /* NEED_AP_MLME && CONFIG_AP */
@@ -3985,6 +4055,32 @@
}
#endif /* CONFIG_OWE */
+#ifdef CONFIG_MBO
+ if (data->assoc_reject.status_code ==
+ WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
+ wpa_s->current_bss && data->assoc_reject.bssid &&
+ data->assoc_reject.resp_ies) {
+ const u8 *rssi_rej;
+
+ rssi_rej = mbo_get_attr_from_ies(
+ data->assoc_reject.resp_ies,
+ data->assoc_reject.resp_ies_len,
+ OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
+ if (rssi_rej && rssi_rej[1] == 2) {
+ wpa_printf(MSG_DEBUG,
+ "OCE: RSSI-based association rejection from "
+ MACSTR " (Delta RSSI: %u, Retry Delay: %u)",
+ MAC2STR(data->assoc_reject.bssid),
+ rssi_rej[2], rssi_rej[3]);
+ wpa_bss_tmp_disallow(wpa_s,
+ data->assoc_reject.bssid,
+ rssi_rej[3],
+ rssi_rej[2] +
+ wpa_s->current_bss->level);
+ }
+ }
+#endif /* CONFIG_MBO */
+
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
sme_event_assoc_reject(wpa_s, data);
return;
@@ -4032,6 +4128,9 @@
{
struct wpa_supplicant *wpa_s = ctx;
int resched;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ int level = MSG_DEBUG;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
event != EVENT_INTERFACE_ENABLED &&
@@ -4045,9 +4144,6 @@
}
#ifndef CONFIG_NO_STDOUT_DEBUG
-{
- int level = MSG_DEBUG;
-
if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
@@ -4060,7 +4156,6 @@
wpa_dbg(wpa_s, level, "Event %s (%d) received",
event_to_string(event), event);
-}
#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (event) {
@@ -4072,6 +4167,8 @@
"FST: MB IEs updated from auth IE");
#endif /* CONFIG_FST */
sme_event_auth(wpa_s, data);
+ wpa_s->auth_status_code = data->auth.status_code;
+ wpas_notify_auth_status_code(wpa_s);
break;
case EVENT_ASSOC:
#ifdef CONFIG_TESTING_OPTIONS
@@ -4087,6 +4184,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
wpa_supplicant_event_assoc(wpa_s, data);
+ wpa_s->assoc_status_code = WLAN_STATUS_SUCCESS;
if (data &&
(data->assoc_info.authorized ||
(!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
@@ -4329,6 +4427,7 @@
#ifdef CONFIG_AP
if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO ||
+ wpa_s->current_ssid->mode == WPAS_MODE_MESH ||
wpa_s->current_ssid->mode ==
WPAS_MODE_P2P_GROUP_FORMATION) {
wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
@@ -4340,6 +4439,9 @@
}
#endif /* CONFIG_AP */
+#ifdef CONFIG_IEEE80211W
+ sme_event_ch_switch(wpa_s);
+#endif /* CONFIG_IEEE80211W */
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_CS);
wnm_clear_coloc_intf_reporting(wpa_s);
break;
diff --git a/wpa_supplicant/examples/dbus-listen-preq.py b/wpa_supplicant/examples/dbus-listen-preq.py
index 5ac9859..337519f 100755
--- a/wpa_supplicant/examples/dbus-listen-preq.py
+++ b/wpa_supplicant/examples/dbus-listen-preq.py
@@ -1,5 +1,6 @@
#!/usr/bin/python
+from __future__ import print_function
import dbus
import sys
import time
@@ -12,21 +13,24 @@
WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface"
def usage():
- print "Usage: %s <ifname>" % sys.argv[0]
- print "Press Ctrl-C to stop"
+ print("Usage: %s <ifname>" % sys.argv[0])
+ print("Press Ctrl-C to stop")
def ProbeRequest(args):
if 'addr' in args:
- print '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ print('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']),
+ end=' ')
if 'dst' in args:
- print '-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ print('-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']),
+ end=' ')
if 'bssid' in args:
- print '(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ print('(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']),
+ end=' ')
if 'signal' in args:
- print 'signal:%d' % args['signal'],
+ print('signal:%d' % args['signal'], end=' ')
if 'ies' in args:
- print 'have IEs (%d bytes)' % len(args['ies']),
- print ''
+ print('have IEs (%d bytes)' % len(args['ies']), end=' ')
+ print('')
if __name__ == "__main__":
global bus
diff --git a/wpa_supplicant/examples/dpp-qrcode.py b/wpa_supplicant/examples/dpp-qrcode.py
index e2a00c9..b468d15 100644
--- a/wpa_supplicant/examples/dpp-qrcode.py
+++ b/wpa_supplicant/examples/dpp-qrcode.py
@@ -24,19 +24,19 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -55,27 +55,27 @@
continue
if not uri.startswith('DPP:'):
continue
- print "Found DPP bootstrap info URI:"
- print uri
+ print("Found DPP bootstrap info URI:")
+ print(uri)
wpas = wpas_connect()
if not wpas:
- print "Could not connect to wpa_supplicant"
- print
+ print("Could not connect to wpa_supplicant")
+ print('')
continue
res = wpas.request("DPP_QR_CODE " + uri);
try:
id = int(res)
except ValueError:
- print "QR Code URI rejected"
+ print("QR Code URI rejected")
continue
- print "QR Code URI accepted - ID=%d" % id
- print wpas.request("DPP_BOOTSTRAP_INFO %d" % id)
+ print("QR Code URI accepted - ID=%d" % id)
+ print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
del wpas
def dpp_display(curve):
wpas = wpas_connect()
if not wpas:
- print "Could not connect to wpa_supplicant"
+ print("Could not connect to wpa_supplicant")
return
res = wpas.request("STATUS")
addr = None
@@ -93,18 +93,18 @@
try:
id = int(res)
except ValueError:
- print "Failed to generate bootstrap info URI"
+ print("Failed to generate bootstrap info URI")
return
- print "Bootstrap information - ID=%d" % id
- print wpas.request("DPP_BOOTSTRAP_INFO %d" % id)
+ print("Bootstrap information - ID=%d" % id)
+ print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id))
uri = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % id)
- print uri
- print "ID=%d" % id
+ print(uri)
+ print("ID=%d" % id)
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M,
border=3)
qr.add_data(uri, optimize=5)
qr.print_ascii(tty=True)
- print "ID=%d" % id
+ print("ID=%d" % id)
del wpas
def main():
diff --git a/wpa_supplicant/examples/p2p-nfc.py b/wpa_supplicant/examples/p2p-nfc.py
index 91eba28..889ac8b 100644
--- a/wpa_supplicant/examples/p2p-nfc.py
+++ b/wpa_supplicant/examples/p2p-nfc.py
@@ -37,7 +37,7 @@
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -53,12 +53,12 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
@@ -66,10 +66,10 @@
if ifname not in ctrl:
continue
try:
- print "Trying to use control interface " + ctrl
+ print("Trying to use control interface " + ctrl)
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -160,30 +160,30 @@
if (data == None):
summary("Could not get handover request carrier record from wpa_supplicant")
return
- print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ print("Handover request carrier record from wpa_supplicant: " + data.encode("hex"))
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
global include_wps_req
if include_wps_req:
- print "Handover request (pre-WPS):"
+ print("Handover request (pre-WPS):")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_req_wps()
if data:
- print "Add WPS request in addition to P2P"
+ print("Add WPS request in addition to P2P")
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
- print "Handover request:"
+ print("Handover request:")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
client = nfc.handover.HandoverClient(llc)
try:
@@ -194,7 +194,7 @@
summary("Handover connection refused")
client.close()
return
- except Exception, e:
+ except Exception as e:
summary("Other exception: " + str(e))
client.close()
return
@@ -217,41 +217,41 @@
client.close()
return
- print "Received message"
+ print("Received message")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
message = nfc.ndef.HandoverSelectMessage(message)
summary("Handover select received")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
for carrier in message.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.p2p":
- print "P2P carrier type match - send to wpa_supplicant"
+ print("P2P carrier type match - send to wpa_supplicant")
if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
success_report("P2P handover reported successfully (initiator)")
else:
summary("P2P handover report rejected")
break
- print "Remove peer"
+ print("Remove peer")
client.close()
- print "Done with handover"
+ print("Done with handover")
global only_one
if only_one:
- print "only_one -> stop loop"
+ print("only_one -> stop loop")
global continue_loop
continue_loop = False
global no_wait
if no_wait:
- print "Trying to exit.."
+ print("Trying to exit..")
global terminate_now
terminate_now = True
@@ -283,33 +283,33 @@
def process_request(self, request):
self.ho_server_processing = True
clear_raw_mode()
- print "HandoverServer - request received"
+ print("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
found = False
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.p2p":
- print "P2P carrier type match - add P2P carrier record"
+ print("P2P carrier type match - add P2P carrier record")
found = True
self.received_carrier = carrier.record
- print "Carrier record:"
+ print("Carrier record:")
try:
- print carrier.record.pretty()
- except Exception, e:
- print e
+ print(carrier.record.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_sel()
if data is None:
- print "Could not get handover select carrier record from wpa_supplicant"
+ print("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"):
success_report("P2P handover reported successfully (responder)")
@@ -324,22 +324,22 @@
for carrier in request.carriers:
if found:
break
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
- print "WSC carrier type match - add WSC carrier record"
+ print("WSC carrier type match - add WSC carrier record")
found = True
self.received_carrier = carrier.record
- print "Carrier record:"
+ print("Carrier record:")
try:
- print carrier.record.pretty()
- except Exception, e:
- print e
+ print(carrier.record.pretty())
+ except Exception as e:
+ print(e)
data = wpas_get_handover_sel_wps()
if data is None:
- print "Could not get handover select carrier record from wpa_supplicant"
+ print("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"):
success_report("WSC handover reported successfully")
@@ -352,12 +352,12 @@
found = True
break
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -396,7 +396,7 @@
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to wpa_supplicant")
success = wpas_tag_read(tag.ndef.message)
@@ -419,7 +419,7 @@
global p2p_sel_data
tag.ndef.message = str(p2p_sel_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -428,7 +428,7 @@
return p2p_sel_wait_remove
def wps_write_p2p_handover_sel(clf, wait_remove=True):
- print "Write P2P handover select"
+ print("Write P2P handover select")
data = wpas_get_handover_sel(tag=True)
if (data == None):
summary("Could not get P2P handover select from wpa_supplicant")
@@ -440,14 +440,14 @@
p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2")
message = nfc.ndef.Message(data);
p2p_sel_data.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print p2p_sel_data.pretty()
- except Exception, e:
- print e
- print str(p2p_sel_data).encode("hex")
+ print(p2p_sel_data.pretty())
+ except Exception as e:
+ print(e)
+ print(str(p2p_sel_data).encode("hex"))
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write})
@@ -456,11 +456,11 @@
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = p2p_tag_read(tag)
if only_one and success:
global continue_loop
@@ -475,15 +475,15 @@
def llcp_worker(llc):
global init_on_touch
if init_on_touch:
- print "Starting handover client"
+ print("Starting handover client")
p2p_handover_client(llc)
return
global no_input
if no_input:
- print "Wait for handover to complete"
+ print("Wait for handover to complete")
else:
- print "Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)"
+ print("Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)")
global srv
global wait_connection
while not wait_connection and srv.sent_carrier is None:
@@ -506,21 +506,21 @@
else:
continue
clear_raw_mode()
- print "Starting handover client"
+ print("Starting handover client")
p2p_handover_client(llc)
return
clear_raw_mode()
- print "Exiting llcp_worker thread"
+ print("Exiting llcp_worker thread")
def llcp_startup(clf, llc):
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global init_on_touch
@@ -587,7 +587,7 @@
if args.ifname:
global ifname
ifname = args.ifname
- print "Selected ifname " + ifname
+ print("Selected ifname " + ifname)
if args.no_wps_req:
global include_wps_req
@@ -610,7 +610,7 @@
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-p2p-sel":
@@ -619,7 +619,7 @@
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if args.tag_read_only:
@@ -636,8 +636,8 @@
'on-connect': llcp_connected},
terminate=terminate_loop):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
index 59b0a9d..6e3d94e 100644
--- a/wpa_supplicant/examples/p2p/p2p_connect.py
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -13,40 +13,40 @@
def usage():
- print "Usage:"
- print " %s -i <interface_name> -m <wps_method> \ " \
- % sys.argv[0]
- print " -a <addr> [-p <pin>] [-g <go_intent>] \ "
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -m = wps method"
- print " -a = peer address"
- print " -p = pin number (8 digits)"
- print " -g = group owner intent"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> -m <wps_method> \ " \
+ % sys.argv[0])
+ print(" -a <addr> [-p <pin>] [-g <go_intent>] \ ")
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -m = wps method")
+ print(" -a = peer address")
+ print(" -p = pin number (8 digits)")
+ print(" -g = group owner intent")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0])
# Required Signals
def GONegotiationSuccess(status):
- print "Go Negotiation Success"
+ print("Go Negotiation Success")
def GONegotiationFailure(status):
- print 'Go Negotiation Failed. Status:'
- print format(status)
+ print('Go Negotiation Failed. Status:')
+ print(format(status))
os._exit(0)
def GroupStarted(properties):
if properties.has_key("group_object"):
- print 'Group Formation Complete %s' \
- % properties["group_object"]
+ print('Group Formation Complete %s' \
+ % properties["group_object"])
os._exit(0)
def WpsFailure(status, etc):
- print "WPS Authentication Failure".format(status)
- print etc
+ print("WPS Authentication Failure".format(status))
+ print(etc)
os._exit(0)
class P2P_Connect():
@@ -118,7 +118,7 @@
{'Ifname': ifname, 'Driver': 'test'})
time.sleep(1)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith(
self.wpas_dbus_interface + \
".InterfaceExists:"):
@@ -157,12 +157,12 @@
if (self.pin != None):
self.p2p_connect_arguements.update({'pin':self.pin})
else:
- print "Error:\n Pin required for wps_method=display"
+ print("Error:\n Pin required for wps_method=display")
usage()
quit()
if (self.go_intent != None and int(self.go_intent) != 15):
- print "go_intent overwritten to 15"
+ print("go_intent overwritten to 15")
self.go_intent = '15'
@@ -171,14 +171,14 @@
if (self.pin != None):
self.p2p_connect_arguements.update({'pin':self.pin})
else:
- print "Error:\n Pin required for wps_method=keypad"
+ print("Error:\n Pin required for wps_method=keypad")
usage()
quit()
if (self.go_intent != None and int(self.go_intent) == 15):
error = "Error :\n Group Owner intent cannot be" + \
" 15 for wps_method=keypad"
- print error
+ print(error)
usage()
quit()
@@ -186,15 +186,15 @@
# for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad
elif (self.wps_method == 'pin'):
if (self.pin != None):
- print "pin ignored"
+ print("pin ignored")
# No pin is required for pbc so it is ignored
elif (self.wps_method == 'pbc'):
if (self.pin != None):
- print "pin ignored"
+ print("pin ignored")
else:
- print "Error:\n wps_method not supported or does not exist"
+ print("Error:\n wps_method not supported or does not exist")
usage()
quit()
@@ -209,12 +209,12 @@
result_pin = self.p2p_interface.Connect(
self.p2p_connect_arguements)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
raise exc
if (self.wps_method == 'pin' and \
not self.p2p_connect_arguements.has_key('pin') ):
- print "Connect return with pin value of %d " % int(result_pin)
+ print("Connect return with pin value of %d " % int(result_pin))
gobject.MainLoop().run()
if __name__ == "__main__":
@@ -268,19 +268,19 @@
# Required Arguements check
if (interface_name == None or wps_method == None or addr == None):
- print "Error:\n Required arguements not specified"
+ print("Error:\n Required arguements not specified")
usage()
quit()
# Group Owner Intent Check
if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ):
- print "Error:\n Group Owner Intent must be between 0 and 15 inclusive"
+ print("Error:\n Group Owner Intent must be between 0 and 15 inclusive")
usage()
quit()
# Pin Check
if (pin != None and len(pin) != 8):
- print "Error:\n Pin is not 8 digits"
+ print("Error:\n Pin is not 8 digits")
usage()
quit()
@@ -289,7 +289,7 @@
addr,pin,wps_method,go_intent)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant/examples/p2p/p2p_disconnect.py
index c3e39b3..85b5a8b 100644
--- a/wpa_supplicant/examples/p2p/p2p_disconnect.py
+++ b/wpa_supplicant/examples/p2p/p2p_disconnect.py
@@ -12,19 +12,19 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i p2p-wlan0-0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i p2p-wlan0-0" % sys.argv[0])
# Required Signals
def GroupFinished(status, etc):
- print "Disconnected"
+ print("Disconnected")
os._exit(0)
class P2P_Disconnect (threading.Thread):
@@ -81,10 +81,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -142,7 +142,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -152,7 +152,7 @@
wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -165,5 +165,5 @@
except:
pass
- print "Disconnect timed out"
+ print("Disconnect timed out")
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant/examples/p2p/p2p_find.py
index 973d46a..e2df528 100644
--- a/wpa_supplicant/examples/p2p/p2p_find.py
+++ b/wpa_supplicant/examples/p2p/p2p_find.py
@@ -13,23 +13,23 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-t <timeout>] \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -t = timeout = 0s (infinite)"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -t 10" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -t = timeout = 0s (infinite)")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -t 10" % sys.argv[0])
# Required Signals
def deviceFound(devicepath):
- print "Device found: %s" % (devicepath)
+ print("Device found: %s" % (devicepath))
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
class P2P_Find (threading.Thread):
# Needed Variables
@@ -85,10 +85,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -150,7 +150,7 @@
if ( int(value) >= 0):
timeout = value
else:
- print "Error:\n Timeout cannot be negative"
+ print("Error:\n Timeout cannot be negative")
usage()
quit()
# Dbus interface
@@ -161,7 +161,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -170,7 +170,7 @@
p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant/examples/p2p/p2p_flush.py
index ff8509d..42fc7a3 100644
--- a/wpa_supplicant/examples/p2p/p2p_flush.py
+++ b/wpa_supplicant/examples/p2p/p2p_flush.py
@@ -13,19 +13,19 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals\
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
class P2P_Flush (threading.Thread):
# Needed Variables
@@ -81,10 +81,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -142,7 +142,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -151,7 +151,7 @@
p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -164,5 +164,5 @@
except:
pass
- print "p2p_flush complete"
+ print("p2p_flush complete")
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant/examples/p2p/p2p_group_add.py
index 5c8fdaf..6d40821 100644
--- a/wpa_supplicant/examples/p2p/p2p_group_add.py
+++ b/wpa_supplicant/examples/p2p/p2p_group_add.py
@@ -11,30 +11,30 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-p <persistent>] \ " \
- % sys.argv[0]
- print " [-f <frequency>] [-o <group_object_path>] \ "
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -p = persistant group = 0 (0=false, 1=true)"
- print " -f = frequency"
- print " -o = persistent group object path"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-p <persistent>] \ " \
+ % sys.argv[0])
+ print(" [-f <frequency>] [-o <group_object_path>] \ ")
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -p = persistant group = 0 (0=false, 1=true)")
+ print(" -f = frequency")
+ print(" -o = persistent group object path")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals
def GroupStarted(properties):
if properties.has_key("group_object"):
- print 'Group Formation Complete %s' \
- % properties["group_object"]
+ print('Group Formation Complete %s' \
+ % properties["group_object"])
os._exit(0)
def WpsFailure(status, etc):
- print "WPS Authentication Failure".format(status)
- print etc
+ print("WPS Authentication Failure".format(status))
+ print(etc)
os._exit(0)
class P2P_Group_Add (threading.Thread):
@@ -99,10 +99,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -127,7 +127,7 @@
if (int(self.frequency) > 0):
self.P2PDictionary.update({'frequency':int(self.frequency)})
else:
- print "Error:\n Frequency must be greater than 0"
+ print("Error:\n Frequency must be greater than 0")
usage()
os._exit(0)
@@ -141,7 +141,7 @@
self.p2p_interface.GroupAdd(self.P2PDictionary)
except:
- print "Error:\n Could not preform group add"
+ print("Error:\n Could not preform group add")
usage()
os._exit(0)
@@ -188,7 +188,7 @@
elif (value == '1'):
persistent = True
else:
- print "Error:\n Persistent can only be 1 or 0"
+ print("Error:\n Persistent can only be 1 or 0")
usage()
os._exit(0)
# Frequency
@@ -205,7 +205,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -213,10 +213,10 @@
p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
persistent,frequency,persistent_group_object)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
p2p_group_add_test.constructArguements()
p2p_group_add_test.start()
time.sleep(5)
- print "Error:\n Group formation timed out"
+ print("Error:\n Group formation timed out")
os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant/examples/p2p/p2p_invite.py
index 6deb397..341dcd0 100644
--- a/wpa_supplicant/examples/p2p/p2p_invite.py
+++ b/wpa_supplicant/examples/p2p/p2p_invite.py
@@ -11,29 +11,29 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> -a <addr> \ " \
- % sys.argv[0]
- print " [-o <persistent_group_object>] [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -a = address of peer"
- print " -o = persistent group object path"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> -a <addr> \ " \
+ % sys.argv[0])
+ print(" [-o <persistent_group_object>] [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -a = address of peer")
+ print(" -o = persistent group object path")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0])
# Required Signals
def InvitationResult(invite_result):
- print "Inviation Result signal :"
+ print("Inviation Result signal :")
status = invite_result['status']
- print "status = ", status
+ print("status = ", status)
if invite_result.has_key('BSSID'):
bssid = invite_result['BSSID']
- print "BSSID = ", hex(bssid[0]) , ":" , \
+ print("BSSID = ", hex(bssid[0]) , ":" , \
hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \
hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \
- hex(bssid[5])
+ hex(bssid[5]))
os._exit(0)
class P2P_Invite (threading.Thread):
@@ -96,10 +96,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -127,7 +127,7 @@
self.p2p_interface.Invite(self.P2PDictionary)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
os._exit(0)
@@ -176,12 +176,12 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
if (addr == None):
- print "Error:\n peer address is required"
+ print("Error:\n peer address is required")
usage()
quit()
@@ -190,12 +190,12 @@
P2P_Invite(interface_name,wpas_dbus_interface,
addr,persistent_group_object)
except:
- print "Error:\n Invalid Arguements"
+ print("Error:\n Invalid Arguements")
usage()
os._exit(1)
p2p_invite_test.constructArguements()
p2p_invite_test.start()
time.sleep(10)
- print "Error:\n p2p_invite timed out"
+ print("Error:\n p2p_invite timed out")
os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant/examples/p2p/p2p_listen.py
index bb3c1e4..b0837d9 100644
--- a/wpa_supplicant/examples/p2p/p2p_listen.py
+++ b/wpa_supplicant/examples/p2p/p2p_listen.py
@@ -13,20 +13,20 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> [-t <timeout>] \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -t = timeout = 0s (infinite)"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0 -t 5" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -t = timeout = 0s (infinite)")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0 -t 5" % sys.argv[0])
# Required Signals
def p2pStateChange(status):
- print status
+ print(status)
class P2P_Listen(threading.Thread):
# Needed Variables
@@ -82,10 +82,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -140,7 +140,7 @@
if ( int(value) >= 0):
timeout = value
else:
- print "Error:\n Timeout cannot be negative"
+ print("Error:\n Timeout cannot be negative")
usage()
quit()
# Dbus interface
@@ -151,7 +151,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -160,7 +160,7 @@
p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant/examples/p2p/p2p_stop_find.py
index f6c03b0..bdb4c0e 100644
--- a/wpa_supplicant/examples/p2p/p2p_stop_find.py
+++ b/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -11,22 +11,22 @@
from dbus.mainloop.glib import DBusGMainLoop
def usage():
- print "Usage:"
- print " %s -i <interface_name> \ " \
- % sys.argv[0]
- print " [-w <wpas_dbus_interface>]"
- print "Options:"
- print " -i = interface name"
- print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
- print "Example:"
- print " %s -i wlan0" % sys.argv[0]
+ print("Usage:")
+ print(" %s -i <interface_name> \ " \
+ % sys.argv[0])
+ print(" [-w <wpas_dbus_interface>]")
+ print("Options:")
+ print(" -i = interface name")
+ print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1")
+ print("Example:")
+ print(" %s -i wlan0" % sys.argv[0])
# Required Signals
def deviceLost(devicepath):
- print "Device lost: %s" % (devicepath)
+ print("Device lost: %s" % (devicepath))
def p2pStateChange(status):
- print status
+ print(status)
os._exit(0)
class P2P_Stop_Find (threading.Thread):
@@ -83,10 +83,10 @@
try:
self.path = self.wpas.GetInterface(
self.interface_name)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
error = 'Error:\n Interface ' + self.interface_name \
+ ' was not found'
- print error
+ print(error)
usage()
os._exit(0)
@@ -147,7 +147,7 @@
# Interface name is required and was not given
if (interface_name == None):
- print "Error:\n interface_name is required"
+ print("Error:\n interface_name is required")
usage()
quit()
@@ -157,7 +157,7 @@
wpas_dbus_interface,timeout)
except:
- print "Error:\n Invalid wpas_dbus_interface"
+ print("Error:\n Invalid wpas_dbus_interface")
usage()
quit()
@@ -170,5 +170,5 @@
except:
pass
- print "p2p find stopped"
+ print("p2p find stopped")
quit()
diff --git a/wpa_supplicant/examples/wpas-dbus-new-getall.py b/wpa_supplicant/examples/wpas-dbus-new-getall.py
index 03da187..732f54d 100755
--- a/wpa_supplicant/examples/wpas-dbus-new-getall.py
+++ b/wpa_supplicant/examples/wpas-dbus-new-getall.py
@@ -11,8 +11,8 @@
"/fi/w1/wpa_supplicant1")
props = wpas_obj.GetAll("fi.w1.wpa_supplicant1",
dbus_interface=dbus.PROPERTIES_IFACE)
- print "GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):"
- print props
+ print("GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):")
+ print(props)
if len(sys.argv) != 2:
os._exit(1)
@@ -24,15 +24,15 @@
if_obj = bus.get_object("fi.w1.wpa_supplicant1", path)
props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path)
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path))
+ print(props)
props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface.WPS",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path)
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path))
+ print(props)
res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'BSSs',
dbus_interface=dbus.PROPERTIES_IFACE)
@@ -40,9 +40,9 @@
bss_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0])
props = bss_obj.GetAll("fi.w1.wpa_supplicant1.BSS",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0])
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0]))
+ print(props)
res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'Networks',
dbus_interface=dbus.PROPERTIES_IFACE)
@@ -50,10 +50,9 @@
net_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0])
props = net_obj.GetAll("fi.w1.wpa_supplicant1.Network",
dbus_interface=dbus.PROPERTIES_IFACE)
- print
- print "GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0])
- print props
+ print('')
+ print("GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0]))
+ print(props)
if __name__ == "__main__":
main()
-
diff --git a/wpa_supplicant/examples/wpas-dbus-new-signals.py b/wpa_supplicant/examples/wpas-dbus-new-signals.py
index d90ef18..366a655 100755
--- a/wpa_supplicant/examples/wpas-dbus-new-signals.py
+++ b/wpa_supplicant/examples/wpas-dbus-new-signals.py
@@ -32,17 +32,17 @@
if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
dbus_interface=dbus.PROPERTIES_IFACE)
- print ifname
+ print(ifname)
def interfaceAdded(interface, properties):
- print "InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])
+ print("InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname']))
def interfaceRemoved(interface):
- print "InterfaceRemoved(%s)" % (interface)
+ print("InterfaceRemoved(%s)" % (interface))
def propertiesChanged(properties):
for i in properties:
- print "PropertiesChanged: %s=%s" % (i, properties[i])
+ print("PropertiesChanged: %s=%s" % (i, properties[i]))
def showBss(bss):
net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
@@ -80,48 +80,48 @@
else:
maxrate = 0
- print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
+ print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq))
def scanDone(success):
gobject.MainLoop().quit()
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
def scanDone2(success, path=None):
- print "Scan done: success=%s [path=%s]" % (success, path)
+ print("Scan done: success=%s [path=%s]" % (success, path))
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
showBss(bss)
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def blobAdded(blob):
- print "BlobAdded(%s)" % (blob)
+ print("BlobAdded(%s)" % (blob))
def blobRemoved(blob):
- print "BlobRemoved(%s)" % (blob)
+ print("BlobRemoved(%s)" % (blob))
def networkAdded(network, properties):
- print "NetworkAdded(%s)" % (network)
+ print("NetworkAdded(%s)" % (network))
def networkRemoved(network):
- print "NetworkRemoved(%s)" % (network)
+ print("NetworkRemoved(%s)" % (network))
def networkSelected(network):
- print "NetworkSelected(%s)" % (network)
+ print("NetworkSelected(%s)" % (network))
def propertiesChangedInterface(properties):
for i in properties:
- print "PropertiesChanged(interface): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(interface): %s=%s" % (i, properties[i]))
def propertiesChangedBss(properties):
for i in properties:
- print "PropertiesChanged(BSS): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(BSS): %s=%s" % (i, properties[i]))
def propertiesChangedNetwork(properties):
for i in properties:
- print "PropertiesChanged(Network): %s=%s" % (i, properties[i])
+ print("PropertiesChanged(Network): %s=%s" % (i, properties[i]))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
diff --git a/wpa_supplicant/examples/wpas-dbus-new-wps.py b/wpa_supplicant/examples/wpas-dbus-new-wps.py
index b886385..7d87b1e 100755
--- a/wpa_supplicant/examples/wpas-dbus-new-wps.py
+++ b/wpa_supplicant/examples/wpas-dbus-new-wps.py
@@ -15,23 +15,23 @@
def propertiesChanged(properties):
if properties.has_key("State"):
- print "PropertiesChanged: State: %s" % (properties["State"])
+ print("PropertiesChanged: State: %s" % (properties["State"]))
def scanDone(success):
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def wpsEvent(name, args):
- print "WPS event: %s" % (name)
- print args
+ print("WPS event: %s" % (name))
+ print(args)
def credentials(cred):
- print "WPS credentials: %s" % (cred)
+ print("WPS credentials: %s" % (cred))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -40,7 +40,7 @@
wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH)
if len(sys.argv) != 2:
- print "Missing ifname argument"
+ print("Missing ifname argument")
os._exit(1)
wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE)
diff --git a/wpa_supplicant/examples/wpas-dbus-new.py b/wpa_supplicant/examples/wpas-dbus-new.py
index 25072ce..6bf74ae 100755
--- a/wpa_supplicant/examples/wpas-dbus-new.py
+++ b/wpa_supplicant/examples/wpas-dbus-new.py
@@ -31,11 +31,11 @@
if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname',
dbus_interface=dbus.PROPERTIES_IFACE)
- print ifname
+ print(ifname)
def propertiesChanged(properties):
if properties.has_key("State"):
- print "PropertiesChanged: State: %s" % (properties["State"])
+ print("PropertiesChanged: State: %s" % (properties["State"]))
def showBss(bss):
net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss)
@@ -73,25 +73,25 @@
else:
maxrate = 0
- print " %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)
+ print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq))
def scanDone(success):
- print "Scan done: success=%s" % success
+ print("Scan done: success=%s" % success)
res = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'BSSs',
dbus_interface=dbus.PROPERTIES_IFACE)
- print "Scanned wireless networks:"
+ print("Scanned wireless networks:")
for opath in res:
- print opath
+ print(opath)
showBss(opath)
def bssAdded(bss, properties):
- print "BSS added: %s" % (bss)
+ print("BSS added: %s" % (bss))
showBss(bss)
def bssRemoved(bss):
- print "BSS removed: %s" % (bss)
+ print("BSS removed: %s" % (bss))
def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -123,14 +123,14 @@
path = None
try:
path = wpas.GetInterface(ifname)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceUnknown:"):
raise exc
try:
path = wpas.CreateInterface({'Ifname': ifname, 'Driver': 'test'})
time.sleep(1)
- except dbus.DBusException, exc:
+ except dbus.DBusException as exc:
if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceExists:"):
raise exc
diff --git a/wpa_supplicant/examples/wpas-test.py b/wpa_supplicant/examples/wpas-test.py
index fd7f73d..bdd16a8 100755
--- a/wpa_supplicant/examples/wpas-test.py
+++ b/wpa_supplicant/examples/wpas-test.py
@@ -24,7 +24,7 @@
def main():
if len(sys.argv) != 2:
- print "Usage: wpas-test.py <interface>"
+ print("Usage: wpas-test.py <interface>")
os._exit(1)
ifname = sys.argv[1]
@@ -37,12 +37,12 @@
path = None
try:
path = wpas.getInterface(ifname)
- except dbus.dbus_bindings.DBusException, exc:
+ except dbus.dbus_bindings.DBusException as exc:
if str(exc) != "wpa_supplicant knows nothing about this interface.":
raise exc
try:
path = wpas.addInterface(ifname, {'driver': dbus.Variant('wext')})
- except dbus.dbus_bindings.DBusException, exc:
+ except dbus.dbus_bindings.DBusException as exc:
if str(exc) != "wpa_supplicant already controls this interface.":
raise exc
@@ -53,7 +53,7 @@
time.sleep(5)
res = iface.scanResults()
- print "Scanned wireless networks:"
+ print("Scanned wireless networks:")
for opath in res:
net_obj = bus.get_object(WPAS_DBUS_SERVICE, opath)
net = dbus.Interface(net_obj, WPAS_DBUS_BSSID_INTERFACE)
@@ -80,7 +80,7 @@
noise = props["noise"]
maxrate = props["maxrate"] / 1000000
- print " %s :: ssid='%s' wpa=%s wpa2=%s quality=%d%% rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, qual, maxrate, freq)
+ print(" %s :: ssid='%s' wpa=%s wpa2=%s quality=%d%% rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, qual, maxrate, freq))
wpas.removeInterface(dbus.ObjectPath(path))
# Should fail here with unknown interface error
diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli
index cc2cff2..15d913e 100755
--- a/wpa_supplicant/examples/wps-ap-cli
+++ b/wpa_supplicant/examples/wps-ap-cli
@@ -14,12 +14,12 @@
enter_pin()
{
echo "Enter a PIN from a station to be enrolled to the network."
- echo -n "Enrollee PIN: "
+ printf "Enrollee PIN: "
read pin
cpin=`$CLI wps_check_pin "$pin" | tail -1`
if [ "$cpin" = "FAIL-CHECKSUM" ]; then
echo "Checksum digit is not valid"
- echo -n "Do you want to use this PIN (y/n)? "
+ printf "Do you want to use this PIN (y/n)? "
read resp
case "$resp" in
y*)
@@ -52,7 +52,7 @@
echo "3: Show current configuration"
echo "0: Exit wps-ap-cli"
- echo -n "Command: "
+ printf "Command: "
read cmd
case "$cmd" in
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
index 7459eb9..bb458fb 100755
--- a/wpa_supplicant/examples/wps-nfc.py
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -30,7 +30,7 @@
success_file = None
def summary(txt):
- print txt
+ print(txt)
if summary_file:
with open(summary_file, 'a') as f:
f.write(txt + "\n")
@@ -46,19 +46,19 @@
if os.path.isdir(wpas_ctrl):
try:
ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
- except OSError, error:
- print "Could not find wpa_supplicant: ", error
+ except OSError as error:
+ print("Could not find wpa_supplicant: ", error)
return None
if len(ifaces) < 1:
- print "No wpa_supplicant control interface found"
+ print("No wpa_supplicant control interface found")
return None
for ctrl in ifaces:
try:
wpas = wpaspy.Ctrl(ctrl)
return wpas
- except Exception, e:
+ except Exception as e:
pass
return None
@@ -163,22 +163,22 @@
self.ho_server_processing = True
summary("HandoverServer - request received")
try:
- print "Parsed handover request: " + request.pretty()
- except Exception, e:
- print e
+ print("Parsed handover request: " + request.pretty())
+ except Exception as e:
+ print(e)
sel = nfc.ndef.HandoverSelectMessage(version="1.2")
for carrier in request.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
summary("WPS carrier type match - add WPS carrier record")
data = wpas_get_handover_sel(self.uuid)
if data is None:
summary("Could not get handover select carrier record from wpa_supplicant")
continue
- print "Handover select carrier record from wpa_supplicant:"
- print data.encode("hex")
+ print("Handover select carrier record from wpa_supplicant:")
+ print(data.encode("hex"))
self.sent_carrier = data
if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"):
success_report("Handover reported successfully (responder)")
@@ -188,12 +188,12 @@
message = nfc.ndef.Message(data);
sel.add_carrier(message[0], "active", message[1:])
- print "Handover select:"
+ print("Handover select:")
try:
- print sel.pretty()
- except Exception, e:
- print e
- print str(sel).encode("hex")
+ print(sel.pretty())
+ except Exception as e:
+ print(e)
+ print(str(sel).encode("hex"))
summary("Sending handover select")
self.success = True
@@ -207,19 +207,19 @@
if (data == None):
summary("Could not get handover request carrier record from wpa_supplicant")
return
- print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ print("Handover request carrier record from wpa_supplicant: " + data.encode("hex"))
message = nfc.ndef.HandoverRequestMessage(version="1.2")
message.nonce = random.randint(0, 0xffff)
datamsg = nfc.ndef.Message(data)
message.add_carrier(datamsg[0], "active", datamsg[1:])
- print "Handover request:"
+ print("Handover request:")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
client = nfc.handover.HandoverClient(llc)
try:
@@ -230,7 +230,7 @@
summary("Handover connection refused")
client.close()
return
- except Exception, e:
+ except Exception as e:
summary("Other exception: " + str(e))
client.close()
return
@@ -253,23 +253,23 @@
client.close()
return
- print "Received message"
+ print("Received message")
try:
- print message.pretty()
- except Exception, e:
- print e
- print str(message).encode("hex")
+ print(message.pretty())
+ except Exception as e:
+ print(e)
+ print(str(message).encode("hex"))
message = nfc.ndef.HandoverSelectMessage(message)
summary("Handover select received")
try:
- print message.pretty()
- except Exception, e:
- print e
+ print(message.pretty())
+ except Exception as e:
+ print(e)
for carrier in message.carriers:
- print "Remote carrier type: " + carrier.type
+ print("Remote carrier type: " + carrier.type)
if carrier.type == "application/vnd.wfa.wsc":
- print "WPS carrier type match - send to wpa_supplicant"
+ print("WPS carrier type match - send to wpa_supplicant")
if "OK" in wpas_report_handover(data, carrier.record, "INIT"):
success_report("Handover reported successfully (initiator)")
else:
@@ -278,9 +278,9 @@
#wifi = nfc.ndef.WifiConfigRecord(carrier.record)
#print wifi.pretty()
- print "Remove peer"
+ print("Remove peer")
client.close()
- print "Done with handover"
+ print("Done with handover")
global only_one
if only_one:
global continue_loop
@@ -288,7 +288,7 @@
global no_wait
if no_wait:
- print "Trying to exit.."
+ print("Trying to exit..")
global terminate_now
terminate_now = True
@@ -296,7 +296,7 @@
success = False
if len(tag.ndef.message):
for record in tag.ndef.message:
- print "record type " + record.type
+ print("record type " + record.type)
if record.type == "application/vnd.wfa.wsc":
summary("WPS tag - send to wpa_supplicant")
success = wpas_tag_read(tag.ndef.message)
@@ -308,7 +308,7 @@
success_report("Tag read succeeded")
if wait_remove:
- print "Remove tag"
+ print("Remove tag")
while tag.is_present:
time.sleep(0.1)
@@ -320,7 +320,7 @@
global write_data
tag.ndef.message = str(write_data)
success_report("Tag write succeeded")
- print "Done - remove tag"
+ print("Done - remove tag")
global only_one
if only_one:
global continue_loop
@@ -330,41 +330,41 @@
time.sleep(0.1)
def wps_write_config_tag(clf, id=None, wait_remove=True):
- print "Write WPS config token"
+ print("Write WPS config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_config_token(id)
if write_data == None:
- print "Could not get WPS config token from wpa_supplicant"
+ print("Could not get WPS config token from wpa_supplicant")
sys.exit(1)
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_er_config_tag(clf, uuid, wait_remove=True):
- print "Write WPS ER config token"
+ print("Write WPS ER config token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_er_config_token(uuid)
if write_data == None:
- print "Could not get WPS config token from wpa_supplicant"
+ print("Could not get WPS config token from wpa_supplicant")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
def wps_write_password_tag(clf, wait_remove=True):
- print "Write WPS password token"
+ print("Write WPS password token")
global write_data, write_wait_remove
write_wait_remove = wait_remove
write_data = wpas_get_password_token()
if write_data == None:
- print "Could not get WPS password token from wpa_supplicant"
+ print("Could not get WPS password token from wpa_supplicant")
return
- print "Touch an NFC tag"
+ print("Touch an NFC tag")
clf.connect(rdwr={'on-connect': rdwr_connected_write})
@@ -373,11 +373,11 @@
summary("Tag connected: " + str(tag))
if tag.ndef:
- print "NDEF tag: " + tag.type
+ print("NDEF tag: " + tag.type)
try:
- print tag.ndef.message.pretty()
- except Exception, e:
- print e
+ print(tag.ndef.message.pretty())
+ except Exception as e:
+ print(e)
success = wps_tag_read(tag, not only_one)
if only_one and success:
global continue_loop
@@ -393,7 +393,7 @@
global arg_uuid
if arg_uuid is None:
wps_handover_init(llc)
- print "Exiting llcp_worker thread"
+ print("Exiting llcp_worker thread")
return
global srv
@@ -405,19 +405,19 @@
def llcp_startup(clf, llc):
global arg_uuid
if arg_uuid:
- print "Start LLCP server"
+ print("Start LLCP server")
global srv
srv = HandoverServer(llc)
if arg_uuid is "ap":
- print "Trying to handle WPS handover"
+ print("Trying to handle WPS handover")
srv.uuid = None
else:
- print "Trying to handle WPS handover with AP " + arg_uuid
+ print("Trying to handle WPS handover with AP " + arg_uuid)
srv.uuid = arg_uuid
return llc
def llcp_connected(llc):
- print "P2P LLCP connected"
+ print("P2P LLCP connected")
global wait_connection
wait_connection = False
global arg_uuid
@@ -426,7 +426,7 @@
srv.start()
else:
threading.Thread(target=llcp_worker, args=(llc,)).start()
- print "llcp_connected returning"
+ print("llcp_connected returning")
return True
@@ -482,7 +482,7 @@
try:
if not clf.open("usb"):
- print "Could not open connection with an NFC device"
+ print("Could not open connection with an NFC device")
raise SystemExit
if args.command == "write-config":
@@ -499,7 +499,7 @@
global continue_loop
while continue_loop:
- print "Waiting for a tag or peer to be touched"
+ print("Waiting for a tag or peer to be touched")
wait_connection = True
try:
if not clf.connect(rdwr={'on-connect': rdwr_connected},
@@ -507,8 +507,8 @@
'on-connect': llcp_connected},
terminate=terminate_loop):
break
- except Exception, e:
- print "clf.connect failed"
+ except Exception as e:
+ print("clf.connect failed")
global srv
if only_one and srv and srv.success:
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index f4f60c5..8e977a3 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -272,7 +272,7 @@
}
-static int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
{
if (wpa_s->current_ssid == NULL ||
wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index 982c0f7..d2b4554 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -19,6 +19,7 @@
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
const u8 *bssid, u8 categ, const u8 *data, size_t len,
int freq);
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
/**
* enum gas_query_result - GAS query result
diff --git a/wpa_supplicant/hidl/1.2/p2p_iface.cpp b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
index 4c16743..56f8344 100644
--- a/wpa_supplicant/hidl/1.2/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
@@ -330,7 +330,7 @@
if (wpas_p2p_group_add_persistent(
wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, NULL, 0, 1)) {
+ VHT_CHANWIDTH_USE_HT, 0, NULL, 0, 1)) {
ret = -1;
}
@@ -1048,7 +1048,7 @@
int new_pin = wpas_p2p_connect(
wpa_s, peer_address.data(), pin, wps_method, persistent, false,
join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
- vht, VHT_CHANWIDTH_USE_HT, nullptr, 0);
+ vht, VHT_CHANWIDTH_USE_HT, 0, nullptr, 0);
if (new_pin < 0) {
return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
}
@@ -1111,7 +1111,7 @@
if (ssid == NULL) {
if (wpas_p2p_group_add(
wpa_s, persistent, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT)) {
+ VHT_CHANWIDTH_USE_HT, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
} else {
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1119,7 +1119,7 @@
} else if (ssid->disabled == 2) {
if (wpas_p2p_group_add_persistent(
wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, NULL, 0, 0)) {
+ VHT_CHANWIDTH_USE_HT, 0, NULL, 0, 0)) {
return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
""};
} else {
@@ -1183,7 +1183,7 @@
}
if (wpas_p2p_invite(
wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT, 0)) {
+ VHT_CHANWIDTH_USE_HT, 0, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
@@ -1639,7 +1639,7 @@
if (wpas_p2p_group_add(
wpa_s, persistent, freq, 0, ht40, vht,
- VHT_CHANWIDTH_USE_HT)) {
+ VHT_CHANWIDTH_USE_HT, 0)) {
return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
}
return {SupplicantStatusCode::SUCCESS, ""};
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 814d18e..e81fef1 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -96,8 +96,7 @@
return;
}
- /* Check if Proxy ARP is enabled (2nd byte in the IE) */
- if (ext_capa[3] & BIT(4))
+ if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_PROXY_ARP))
filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
WPA_DATA_FRAME_FILTER_FLAG_NA;
@@ -105,15 +104,22 @@
}
-void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id, int ap_release)
{
+ int release;
u8 conf;
+ release = (HS20_VERSION >> 4) + 1;
+ if (ap_release > 0 && release > ap_release)
+ release = ap_release;
+ if (release < 2)
+ pps_mo_id = -1;
+
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5);
wpabuf_put_be24(buf, OUI_WFA);
wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
- conf = HS20_VERSION;
+ conf = (release - 1) << 4;
if (pps_mo_id >= 0)
conf |= HS20_PPS_MO_ID_PRESENT;
wpabuf_put_u8(buf, conf);
@@ -138,6 +144,21 @@
}
+int get_hs20_version(struct wpa_bss *bss)
+{
+ const u8 *ie;
+
+ if (!bss)
+ return 0;
+
+ ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+ if (!ie || ie[1] < 5)
+ return 0;
+
+ return ((ie[6] >> 4) & 0x0f) + 1;
+}
+
+
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss)
{
@@ -411,7 +432,7 @@
return;
}
- if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+ if (lchown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
fname);
}
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 66fc540..e43414b 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -9,7 +9,8 @@
#define HS20_SUPPLICANT_H
void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s);
-void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id);
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id,
+ int ap_release);
void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
const struct wpa_ssid *ssid);
@@ -20,6 +21,7 @@
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);
+int get_hs20_version(struct wpa_bss *bss);
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);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index ebb3a50..c66a09b 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -958,6 +958,7 @@
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
+ wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
@@ -2625,7 +2626,6 @@
{
struct wpa_bss *bss;
int found = 0;
- const u8 *ie;
wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
"fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
@@ -2648,8 +2648,7 @@
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
if (!(bss->caps & IEEE80211_CAP_ESS))
continue;
- ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
- if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
+ if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_INTERWORKING))
continue; /* AP does not support Interworking */
if (disallowed_bssid(wpa_s, bss->bssid) ||
disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
@@ -2982,7 +2981,7 @@
MAC2STR(sa));
anqp_add_extra(wpa_s, anqp, info_id, pos, slen);
- if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
+ if (!pmf_in_use(wpa_s, sa)) {
wpa_printf(MSG_DEBUG,
"ANQP: Ignore Venue URL since PMF was not enabled");
break;
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 5adf61e..bd5020a 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -51,6 +51,19 @@
}
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+ enum mbo_attr_id attr)
+{
+ const u8 *mbo_ie;
+
+ mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE);
+ if (!mbo_ie)
+ return NULL;
+
+ return mbo_attr_from_mbo_ie(mbo_ie, attr);
+}
+
+
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
{
const u8 *mbo, *end;
@@ -501,7 +514,7 @@
if (disallowed_sec && wpa_s->current_bss)
wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
- disallowed_sec);
+ disallowed_sec, 0);
return;
fail:
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 38b9fb3..e9457f0 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -34,6 +34,8 @@
wpa_s->current_ssid = NULL;
os_free(wpa_s->mesh_rsn);
wpa_s->mesh_rsn = NULL;
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = NULL;
/* TODO: leave mesh (stop beacon). This will happen on link down
* anyway, so it's not urgent */
}
@@ -93,6 +95,9 @@
conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ conf->ocv = ssid->ocv;
+#endif /* CONFIG_OCV */
cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
@@ -147,6 +152,95 @@
}
+static int wpas_mesh_init_rsn(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_data *bss = ifmsh->bss[0];
+ static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
+ const char *password;
+ size_t len;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+ if (!password) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Passphrase for SAE not configured");
+ return -1;
+ }
+
+ bss->conf->wpa = ssid->proto;
+ bss->conf->wpa_key_mgmt = ssid->key_mgmt;
+
+ if (wpa_s->conf->sae_groups && wpa_s->conf->sae_groups[0] > 0) {
+ wpas_mesh_copy_groups(bss, wpa_s);
+ } else {
+ bss->conf->sae_groups = os_memdup(default_groups,
+ sizeof(default_groups));
+ if (!bss->conf->sae_groups)
+ return -1;
+ }
+
+ len = os_strlen(password);
+ bss->conf->ssid.wpa_passphrase = dup_binstr(password, len);
+
+ wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, ifmsh->mconf);
+ return !wpa_s->mesh_rsn ? -1 : 0;
+}
+
+
+static int wpas_mesh_complete(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct wpa_driver_mesh_join_params *params = wpa_s->mesh_params;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int ret;
+
+ if (!params || !ssid) {
+ wpa_printf(MSG_ERROR, "mesh: %s called without active mesh",
+ __func__);
+ return -1;
+ }
+
+ if (ifmsh->mconf->security != MESH_CONF_SEC_NONE &&
+ wpas_mesh_init_rsn(wpa_s)) {
+ wpa_printf(MSG_ERROR,
+ "mesh: RSN initialization failed - deinit mesh");
+ wpa_supplicant_mesh_deinit(wpa_s);
+ return -1;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
+ wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
+ wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
+ }
+
+ if (ifmsh) {
+ params->ies = ifmsh->mconf->rsn_ie;
+ params->ie_len = ifmsh->mconf->rsn_ie_len;
+ params->basic_rates = ifmsh->basic_rates;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+ params->conf.ht_opmode = ifmsh->bss[0]->iface->ht_op_mode;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ret = wpa_drv_join_mesh(wpa_s, params);
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
+
+ /* hostapd sets the interface down until we associate */
+ wpa_drv_set_operstate(wpa_s, 1);
+
+ if (!ret)
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+ return ret;
+}
+
+
static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -156,9 +250,6 @@
struct hostapd_config *conf;
struct mesh_conf *mconf;
int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
- static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
- const char *password;
- size_t len;
int rate_len;
int frequency;
@@ -208,6 +299,16 @@
bss->conf->start_disabled = 1;
bss->conf->mesh = MESH_ENABLED;
bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+
+ if (ieee80211_is_dfs(ssid->frequency, wpa_s->hw.modes,
+ wpa_s->hw.num_modes) && wpa_s->conf->country[0]) {
+ conf->ieee80211h = 1;
+ conf->ieee80211d = 1;
+ conf->country[0] = wpa_s->conf->country[0];
+ conf->country[1] = wpa_s->conf->country[1];
+ conf->country[2] = ' ';
+ }
+
bss->iconf = conf;
ifmsh->conf = conf;
@@ -231,7 +332,8 @@
if (ssid->ht40)
conf->secondary_channel = ssid->ht40;
if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A && ssid->vht) {
- conf->vht_oper_chwidth = ssid->max_oper_chwidth;
+ if (ssid->max_oper_chwidth != DEFAULT_MAX_OPER_CHWIDTH)
+ conf->vht_oper_chwidth = ssid->max_oper_chwidth;
switch (conf->vht_oper_chwidth) {
case VHT_CHANWIDTH_80MHZ:
case VHT_CHANWIDTH_80P80MHZ:
@@ -281,48 +383,15 @@
conf->basic_rates[rate_len] = -1;
}
- if (hostapd_setup_interface(ifmsh)) {
- wpa_printf(MSG_ERROR,
- "Failed to initialize hostapd interface for mesh");
- return -1;
- }
-
if (wpa_drv_init_mesh(wpa_s)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
return -1;
}
- if (mconf->security != MESH_CONF_SEC_NONE) {
- password = ssid->sae_password;
- if (!password)
- password = ssid->passphrase;
- if (!password) {
- wpa_printf(MSG_ERROR,
- "mesh: Passphrase for SAE not configured");
- goto out_free;
- }
-
- bss->conf->wpa = ssid->proto;
- bss->conf->wpa_key_mgmt = ssid->key_mgmt;
-
- if (wpa_s->conf->sae_groups &&
- wpa_s->conf->sae_groups[0] > 0) {
- wpas_mesh_copy_groups(bss, wpa_s);
- } else {
- bss->conf->sae_groups =
- os_memdup(default_groups,
- sizeof(default_groups));
- if (!bss->conf->sae_groups)
- goto out_free;
- }
-
- len = os_strlen(password);
- bss->conf->ssid.wpa_passphrase =
- dup_binstr(password, len);
-
- wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
- if (!wpa_s->mesh_rsn)
- goto out_free;
+ if (hostapd_setup_interface(ifmsh)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize hostapd interface for mesh");
+ return -1;
}
wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
@@ -367,11 +436,13 @@
int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- struct wpa_driver_mesh_join_params params;
+ struct wpa_driver_mesh_join_params *params = os_zalloc(sizeof(*params));
int ret = 0;
- if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
+ if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency ||
+ !params) {
ret = -ENOENT;
+ os_free(params);
goto out;
}
@@ -381,22 +452,23 @@
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
- os_memset(¶ms, 0, sizeof(params));
- params.meshid = ssid->ssid;
- params.meshid_len = ssid->ssid_len;
- ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq);
- wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
- wpa_s->mesh_vht_enabled = !!params.freq.vht_enabled;
- if (params.freq.ht_enabled && params.freq.sec_channel_offset)
- ssid->ht40 = params.freq.sec_channel_offset;
+ params->meshid = ssid->ssid;
+ params->meshid_len = ssid->ssid_len;
+ ibss_mesh_setup_freq(wpa_s, ssid, ¶ms->freq);
+ wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled;
+ wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled;
+ if (params->freq.ht_enabled && params->freq.sec_channel_offset)
+ ssid->ht40 = params->freq.sec_channel_offset;
+
if (wpa_s->mesh_vht_enabled) {
ssid->vht = 1;
- switch (params.freq.bandwidth) {
+ ssid->vht_center_freq1 = params->freq.center_freq1;
+ switch (params->freq.bandwidth) {
case 80:
- if (params.freq.center_freq2) {
+ if (params->freq.center_freq2) {
ssid->max_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
ssid->vht_center_freq2 =
- params.freq.center_freq2;
+ params->freq.center_freq2;
} else {
ssid->max_oper_chwidth = VHT_CHANWIDTH_80MHZ;
}
@@ -410,67 +482,44 @@
}
}
if (ssid->beacon_int > 0)
- params.beacon_int = ssid->beacon_int;
+ params->beacon_int = ssid->beacon_int;
else if (wpa_s->conf->beacon_int > 0)
- params.beacon_int = wpa_s->conf->beacon_int;
+ params->beacon_int = wpa_s->conf->beacon_int;
if (ssid->dtim_period > 0)
- params.dtim_period = ssid->dtim_period;
+ params->dtim_period = ssid->dtim_period;
else if (wpa_s->conf->dtim_period > 0)
- params.dtim_period = wpa_s->conf->dtim_period;
- params.conf.max_peer_links = wpa_s->conf->max_peer_links;
+ params->dtim_period = wpa_s->conf->dtim_period;
+ params->conf.max_peer_links = wpa_s->conf->max_peer_links;
if (ssid->mesh_rssi_threshold < DEFAULT_MESH_RSSI_THRESHOLD) {
- params.conf.rssi_threshold = ssid->mesh_rssi_threshold;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD;
+ params->conf.rssi_threshold = ssid->mesh_rssi_threshold;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_RSSI_THRESHOLD;
}
if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
- params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
- params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
+ params->flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
+ params->flags |= WPA_DRIVER_MESH_FLAG_AMPE;
wpa_s->conf->user_mpm = 1;
}
if (wpa_s->conf->user_mpm) {
- params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
- params.conf.auto_plinks = 0;
+ params->flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
+ params->conf.auto_plinks = 0;
} else {
- params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
- params.conf.auto_plinks = 1;
+ params->flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+ params->conf.auto_plinks = 1;
}
- params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
+ params->conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
- if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms.freq)) {
+ os_free(wpa_s->mesh_params);
+ wpa_s->mesh_params = params;
+ if (wpa_supplicant_mesh_init(wpa_s, ssid, ¶ms->freq)) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
wpa_drv_leave_mesh(wpa_s);
ret = -1;
goto out;
}
- if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
- wpa_s->pairwise_cipher = wpa_s->mesh_rsn->pairwise_cipher;
- wpa_s->group_cipher = wpa_s->mesh_rsn->group_cipher;
- wpa_s->mgmt_group_cipher = wpa_s->mesh_rsn->mgmt_group_cipher;
- }
-
- if (wpa_s->ifmsh) {
- params.ies = wpa_s->ifmsh->mconf->rsn_ie;
- params.ie_len = wpa_s->ifmsh->mconf->rsn_ie_len;
- params.basic_rates = wpa_s->ifmsh->basic_rates;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
- params.conf.ht_opmode = wpa_s->ifmsh->bss[0]->iface->ht_op_mode;
- }
-
- wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- ret = wpa_drv_join_mesh(wpa_s, ¶ms);
- if (ret)
- wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d", ret);
-
- /* hostapd sets the interface down until we associate */
- wpa_drv_set_operstate(wpa_s, 1);
-
- if (!ret)
- wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
-
+ ret = wpas_mesh_complete(wpa_s);
out:
return ret;
}
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index d166cfe..4485939 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h"
+#include "common/ocv.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ieee802_11.h"
@@ -222,13 +223,14 @@
if (!sta)
return;
- buf_len = 2 + /* capability info */
+ buf_len = 2 + /* Category and Action */
+ 2 + /* capability info */
2 + /* AID */
2 + 8 + /* supported rates */
2 + (32 - 8) +
2 + 32 + /* mesh ID */
2 + 7 + /* mesh config */
- 2 + 23 + /* peering management */
+ 2 + 24 + /* peering management */
2 + 96 + /* AMPE */
2 + 16; /* MIC */
#ifdef CONFIG_IEEE80211N
@@ -245,6 +247,11 @@
#endif /* CONFIG_IEEE80211AC */
if (type != PLINK_CLOSE)
buf_len += conf->rsn_ie_len; /* RSN IE */
+#ifdef CONFIG_OCV
+ /* OCI is included even when the other STA doesn't support OCV */
+ if (type != PLINK_CLOSE && conf->ocv)
+ buf_len += OCV_OCI_EXTENDED_LEN;
+#endif /* CONFIG_OCV */
buf = wpabuf_alloc(buf_len);
if (!buf)
@@ -356,6 +363,22 @@
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_OCV
+ if (type != PLINK_CLOSE && conf->ocv) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Mesh MPM: Failed to get channel info for OCI element");
+ goto fail;
+ }
+
+ pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_OCV */
+
if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
wpa_msg(wpa_s, MSG_INFO,
"Mesh MPM: failed to add AMPE and MIC IE");
@@ -698,6 +721,7 @@
#ifdef CONFIG_IEEE80211AC
copy_sta_vht_capab(data, sta, elems->vht_capabilities);
+ copy_sta_vht_oper(data, sta, elems->vht_operation);
set_sta_vht_opmode(data, sta, elems->vht_opmode_notif);
#endif /* CONFIG_IEEE80211AC */
@@ -1195,6 +1219,56 @@
}
return;
}
+
+#ifdef CONFIG_OCV
+ if (action_field == PLINK_OPEN && elems.rsn_ie) {
+ struct wpa_state_machine *sm = sta->wpa_sm;
+ struct wpa_ie_data data;
+
+ res = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2,
+ elems.rsn_ie_len + 2,
+ &data);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to parse RSN IE (res=%d)",
+ res);
+ wpa_hexdump(MSG_DEBUG, "RSN IE", elems.rsn_ie,
+ elems.rsn_ie_len);
+ return;
+ }
+
+ wpa_auth_set_ocv(sm, mconf->ocv &&
+ (data.capabilities &
+ WPA_CAPABILITY_OCVC));
+ }
+
+ if (action_field != PLINK_CLOSE &&
+ wpa_auth_uses_ocv(sta->wpa_sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "MPM: Failed to get channel info to validate received OCI in MPM Confirm");
+ return;
+ }
+
+ if (get_tx_parameters(
+ sta, channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) !=
+ 0) {
+ wpa_printf(MSG_WARNING, "MPM: %s",
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
}
if (sta->plink_state == PLINK_BLOCKED) {
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e74cb16..04ac747 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -140,7 +140,7 @@
static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
- enum mfp_options ieee80211w)
+ enum mfp_options ieee80211w, int ocv)
{
struct wpa_auth_config conf;
static const struct wpa_auth_callbacks cb = {
@@ -168,6 +168,9 @@
if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ conf.ocv = ocv;
+#endif /* CONFIG_OCV */
rsn->auth = wpa_init(addr, &conf, &cb, rsn);
if (rsn->auth == NULL) {
@@ -240,7 +243,7 @@
mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
- conf->ieee80211w) < 0) {
+ conf->ieee80211w, conf->ocv) < 0) {
mesh_rsn_deinit(mesh_rsn);
os_free(mesh_rsn);
return NULL;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 30bdb6d..a7fdab9 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -149,6 +149,15 @@
}
+void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AUTH_STATUS_CODE);
+}
+
+
void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -166,6 +175,42 @@
wpas_hidl_notify_auth_timeout(wpa_s);
}
+void wpas_notify_roam_time(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_TIME);
+}
+
+
+void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ROAM_COMPLETE);
+}
+
+
+void wpas_notify_session_length(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SESSION_LENGTH);
+}
+
+
+void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_BSS_TM_STATUS);
+}
+
+
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -788,6 +833,9 @@
wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
#endif /* CONFIG_P2P */
+ /* Register the station */
+ wpas_dbus_register_sta(wpa_s, sta);
+
/* Notify listeners a new station has been authorized */
wpas_dbus_signal_sta_authorized(wpa_s, sta);
@@ -811,7 +859,8 @@
/* Notify listeners a station has been deauthorized */
wpas_dbus_signal_sta_deauthorized(wpa_s, sta);
- wpas_hidl_notify_ap_sta_deauthorized(wpa_s, sta, p2p_dev_addr);
+ /* Unregister the station */
+ wpas_dbus_unregister_sta(wpa_s, sta);
}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 703ef8f..2f194ce 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -24,8 +24,13 @@
enum wpa_states new_state,
enum wpa_states old_state);
void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_notify_auth_status_code(struct wpa_supplicant *wpa_s);
void wpas_notify_assoc_status_code(struct wpa_supplicant *wpa_s);
void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s);
+void wpas_notify_roam_time(struct wpa_supplicant *wpa_s);
+void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s);
+void wpas_notify_session_length(struct wpa_supplicant *wpa_s);
+void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index d23b009..947917b 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -208,17 +208,78 @@
static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
const struct oper_class_map *op_class)
{
int chan;
size_t i;
struct hostapd_hw_modes *mode;
int found;
+ int z;
+ int freq2 = 0;
+ int freq5 = 0;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
if (!mode)
return 0;
+ /* If we are configured to disable certain things, take that into
+ * account here. */
+ if (ssid->freq_list && ssid->freq_list[0]) {
+ for (z = 0; ; z++) {
+ int f = ssid->freq_list[z];
+
+ if (f == 0)
+ break; /* end of list */
+ if (f > 4000 && f < 6000)
+ freq5 = 1;
+ else if (f > 2400 && f < 2500)
+ freq2 = 1;
+ }
+ } else {
+ /* No frequencies specified, can use anything hardware supports.
+ */
+ freq2 = freq5 = 1;
+ }
+
+ if (op_class->op_class >= 115 && op_class->op_class <= 130 && !freq5)
+ return 0;
+ if (op_class->op_class >= 81 && op_class->op_class <= 84 && !freq2)
+ return 0;
+
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ switch (op_class->op_class) {
+ case 83:
+ case 84:
+ case 104:
+ case 105:
+ case 116:
+ case 117:
+ case 119:
+ case 120:
+ case 122:
+ case 123:
+ case 126:
+ case 127:
+ case 128:
+ case 129:
+ case 130:
+ /* Disable >= 40 MHz channels if HT is disabled */
+ return 0;
+ }
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
+#ifdef CONFIG_VHT_OVERRIDES
+ if (ssid->disable_vht) {
+ if (op_class->op_class >= 128 && op_class->op_class <= 130) {
+ /* Disable >= 80 MHz channels if VHT is disabled */
+ return 0;
+ }
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
if (op_class->op_class == 128) {
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
@@ -273,8 +334,9 @@
}
-size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
- size_t len)
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ int freq, u8 *pos, size_t len)
{
struct wpabuf *buf;
u8 op, current, chan;
@@ -304,7 +366,7 @@
wpabuf_put_u8(buf, current);
for (op = 0; global_op_class[op].op_class; op++) {
- if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
+ if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op]))
wpabuf_put_u8(buf, global_op_class[op].op_class);
}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 3626ea3..78011c6 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1912,6 +1912,7 @@
ssid->vht = params->vht;
ssid->max_oper_chwidth = params->max_oper_chwidth;
ssid->vht_center_freq2 = params->vht_center_freq2;
+ ssid->he = params->he;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -2076,16 +2077,12 @@
}
if (wpa_s->conf->p2p_interface_random_mac_addr) {
- if (random_mac_addr(wpa_s->pending_interface_addr) < 0) {
- wpa_printf(MSG_ERROR, "P2P: Failed to generate random MAC address "
- "for the group interface");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "P2P: Generate random MAC address " MACSTR " for the group",
- MAC2STR(wpa_s->pending_interface_addr));
+ random_mac_addr(wpa_s->pending_interface_addr);
+ wpa_printf(MSG_DEBUG, "P2P: Generate random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
}
-
if (force_ifname[0]) {
wpa_printf(MSG_DEBUG, "P2P: Driver forced interface name %s",
force_ifname);
@@ -2165,22 +2162,26 @@
wpas_p2p_clone_config(group_wpa_s, wpa_s);
if (wpa_s->conf->p2p_interface_random_mac_addr) {
- if (wpa_drv_set_mac_addr(group_wpa_s, wpa_s->pending_interface_addr) < 0) {
+ if (wpa_drv_set_mac_addr(group_wpa_s,
+ wpa_s->pending_interface_addr) < 0) {
wpa_msg(group_wpa_s, MSG_INFO,
"Failed to set random MAC address");
- wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s, 0);
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
return NULL;
}
if (wpa_supplicant_update_mac_addr(group_wpa_s) < 0) {
wpa_msg(group_wpa_s, MSG_INFO,
"Could not update MAC address information");
- wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s, 0);
+ wpa_supplicant_remove_iface(wpa_s->global, group_wpa_s,
+ 0);
return NULL;
}
- wpa_printf(MSG_DEBUG, "P2P: Using random MAC address " MACSTR " for the group",
- MAC2STR(wpa_s->pending_interface_addr));
+ wpa_printf(MSG_DEBUG, "P2P: Using random MAC address " MACSTR
+ " for the group",
+ MAC2STR(wpa_s->pending_interface_addr));
}
return group_wpa_s;
@@ -3088,7 +3089,7 @@
MAC2STR(sa), s->id);
}
wpas_p2p_group_add_persistent(
- wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL,
+ wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
@@ -3314,6 +3315,7 @@
wpa_s->p2p_go_vht_center_freq2,
wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
@@ -3958,6 +3960,10 @@
/* Remove stale persistent group */
if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ s->id);
+ wpas_notify_persistent_group_removed(wpa_s, s);
wpa_config_remove_network(wpa_s->conf, s->id);
save_config = 1;
continue;
@@ -4081,6 +4087,11 @@
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
}
@@ -4121,6 +4132,10 @@
/* Remove stale persistent group */
if (stale->mode != WPAS_MODE_P2P_GO ||
stale->num_p2p_clients <= 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove stale persistent group id=%d",
+ stale->id);
+ wpas_notify_persistent_group_removed(wpa_s, stale);
wpa_config_remove_network(wpa_s->conf, stale->id);
} else {
size_t i;
@@ -4153,6 +4168,11 @@
if (persistent_go && s != persistent_go &&
!persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s,
+ persistent_go);
wpa_config_remove_network(wpa_s->conf,
persistent_go->id);
/* Save config */
@@ -4205,13 +4225,14 @@
if (response_done && persistent_go) {
wpas_p2p_group_add_persistent(
wpa_s, persistent_go,
- 0, 0, freq, 0, 0, 0, 0, NULL,
+ 0, 0, freq, 0, 0, 0, 0, 0, NULL,
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0, 0);
} else if (response_done) {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq,
+ 0, 0, 0, 0, 0);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4260,6 +4281,10 @@
if (persistent_go && !persistent_go->num_p2p_clients) {
/* remove empty persistent GO */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Remove empty persistent group id=%d",
+ persistent_go->id);
+ wpas_notify_persistent_group_removed(wpa_s, persistent_go);
wpa_config_remove_network(wpa_s->conf, persistent_go->id);
}
@@ -4323,11 +4348,11 @@
if (persistent_go) {
wpas_p2p_group_add_persistent(
- wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, NULL,
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, 0, 0, 0, NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0);
} else {
- wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0);
+ wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0);
}
return 1;
@@ -4391,7 +4416,6 @@
return 0;
}
-
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
@@ -4482,7 +4506,10 @@
* channel.
*/
if (p2p_config_get_random_social(&p2p, &p2p.reg_class,
- &p2p.channel) != 0) {
+ &p2p.channel,
+ &global->p2p_go_avoid_freq,
+ &global->p2p_disallow_freq) !=
+ 0) {
wpa_printf(MSG_INFO,
"P2P: No social channels supported by the driver - do not enable P2P");
return 0;
@@ -4507,10 +4534,14 @@
* other preference is indicated.
*/
if (p2p_config_get_random_social(&p2p, &p2p.op_reg_class,
- &p2p.op_channel) != 0) {
- wpa_printf(MSG_ERROR,
+ &p2p.op_channel, NULL,
+ NULL) != 0) {
+ wpa_printf(MSG_INFO,
"P2P: Failed to select random social channel as operation channel");
- return -1;
+ p2p.op_reg_class = 0;
+ p2p.op_channel = 0;
+ /* This will be overridden during group setup in
+ * p2p_prepare_channel(), so allow setup to continue. */
}
p2p.cfg_op_channel = 0;
wpa_printf(MSG_DEBUG, "P2P: Random operating channel: "
@@ -4903,6 +4934,7 @@
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
NULL, 0);
return;
}
@@ -5200,17 +5232,18 @@
os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
sizeof(group->p2p_pin));
group->p2p_wps_method = wpa_s->p2p_wps_method;
- } else {
- /*
- * Need to mark the current interface for p2p_group_formation
- * when a separate group interface is not used. This is needed
- * to allow p2p_cancel stop a pending p2p_connect-join.
- * wpas_p2p_init_group_interface() addresses this for the case
- * where a separate group interface is used.
- */
- wpa_s->global->p2p_group_formation = wpa_s;
}
+ /*
+ * Need to mark the current interface for p2p_group_formation
+ * when a separate group interface is not used. This is needed
+ * to allow p2p_cancel stop a pending p2p_connect-join.
+ * wpas_p2p_init_group_interface() addresses this for the case
+ * where a separate group interface is used.
+ */
+ if (group == wpa_s->parent)
+ wpa_s->global->p2p_group_formation = group;
+
group->p2p_in_provisioning = 1;
group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
@@ -5450,7 +5483,7 @@
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, const u8 *group_ssid,
+ unsigned int vht_chwidth, int he, const u8 *group_ssid,
size_t group_ssid_len)
{
int force_freq = 0, pref_freq = 0;
@@ -5495,6 +5528,7 @@
wpa_s->p2p_go_vht = !!vht;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
+ wpa_s->p2p_go_he = !!he;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -5918,7 +5952,7 @@
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
int freq, int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels)
{
struct wpa_used_freq_data *freqs;
@@ -5931,6 +5965,7 @@
params->role_go = 1;
params->ht40 = ht40;
params->vht = vht;
+ params->he = he;
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
@@ -6287,7 +6322,7 @@
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth)
+ int max_oper_chwidth, int he)
{
struct p2p_go_neg_results params;
@@ -6308,7 +6343,7 @@
}
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, NULL))
+ ht40, vht, max_oper_chwidth, he, NULL))
return -1;
p2p_go_params(wpa_s->global->p2p, ¶ms);
@@ -6387,7 +6422,7 @@
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels,
int connection_timeout, int force_scan)
{
@@ -6463,7 +6498,7 @@
}
if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2,
- ht40, vht, max_oper_chwidth, channels))
+ ht40, vht, max_oper_chwidth, he, channels))
return -1;
params.role_go = 1;
@@ -7015,7 +7050,7 @@
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht, int max_chwidth,
- int pref_freq)
+ int pref_freq, int he)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -7033,6 +7068,7 @@
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
wpa_s->p2p_go_vht = !!vht;
+ wpa_s->p2p_go_he = !!he;
wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
if (ssid->mode == WPAS_MODE_P2P_GO) {
@@ -8055,7 +8091,8 @@
wpa_s->p2p_pd_before_go_neg,
wpa_s->p2p_go_ht40,
wpa_s->p2p_go_vht,
- wpa_s->p2p_go_max_oper_chwidth, NULL, 0);
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he, NULL, 0);
return ret;
}
@@ -8591,6 +8628,7 @@
WPS_NFC, 0, 0, 1, 0, wpa_s->conf->p2p_go_intent,
params->go_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
params->go_ssid_len ? params->go_ssid : NULL,
params->go_ssid_len);
}
@@ -8670,7 +8708,7 @@
WPS_NFC, 0, 0, 0, 0, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- NULL, 0);
+ wpa_s->p2p_go_he, NULL, 0);
}
@@ -8686,7 +8724,7 @@
WPS_NFC, 0, 0, 0, 1, wpa_s->conf->p2p_go_intent,
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
- NULL, 0);
+ wpa_s->p2p_go_he, NULL, 0);
if (res)
return res;
@@ -9071,7 +9109,7 @@
* TODO: This function may not always work correctly. For example,
* when we have a running GO and a BSS on a DFS channel.
*/
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"P2P CSA: Failed to select new frequency for GO");
return -1;
@@ -9183,7 +9221,7 @@
wpa_supplicant_ap_deinit(wpa_s);
/* Reselect the GO frequency */
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, NULL)) {
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, 0, 0, 0, 0, 0, 0, NULL)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Failed to reselect freq");
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_GO_LEAVE_CHANNEL);
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 0a08a88..24ec2ca 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -37,18 +37,18 @@
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, unsigned int vht_center_freq2,
int persistent_id, int pd, int ht40, int vht,
- unsigned int vht_chwidth, const u8 *group_ssid,
+ unsigned int vht_chwidth, int he, const u8 *group_ssid,
size_t group_ssid_len);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth);
+ int max_oper_chwidth, int he);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
int vht_center_freq2, int ht40,
- int vht, int max_oper_chwidth,
+ int vht, int max_oper_chwidth, int he,
const struct p2p_channels *channels,
int connection_timeout, int force_scan);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
@@ -117,7 +117,7 @@
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int pref_freq);
+ int max_oper_chwidth, int pref_freq, int he);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index f4fbfa7..ab5e6db 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -392,17 +392,66 @@
}
+static int wpas_rrm_beacon_rep_update_last_frame(u8 *pos, size_t len)
+{
+ struct rrm_measurement_report_element *msr_rep;
+ u8 *end = pos + len;
+ u8 *msr_rep_end;
+
+ while (end - pos >= (int) sizeof(*msr_rep)) {
+ msr_rep = (struct rrm_measurement_report_element *) pos;
+ msr_rep_end = pos + msr_rep->len + 2;
+
+ if (msr_rep->eid != WLAN_EID_MEASURE_REPORT ||
+ msr_rep_end > end) {
+ /* Should not happen. This indicates a bug. */
+ wpa_printf(MSG_ERROR,
+ "RRM: non-measurement report element in measurement report frame");
+ return -1;
+ }
+
+ if (msr_rep->type == MEASURE_TYPE_BEACON) {
+ struct rrm_measurement_beacon_report *rep;
+ u8 *subelem;
+
+ rep = (struct rrm_measurement_beacon_report *)
+ msr_rep->variable;
+ subelem = rep->variable;
+ while (subelem + 2 < msr_rep_end &&
+ subelem[0] !=
+ WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION)
+ subelem += 2 + subelem[1];
+
+ if (subelem + 2 < msr_rep_end &&
+ subelem[0] ==
+ WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION &&
+ subelem[1] == 1 &&
+ subelem +
+ BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN <= end)
+ subelem[2] = 1;
+ }
+
+ pos += pos[1] + 2;
+ }
+
+ return 0;
+}
+
+
static void wpas_rrm_send_msr_report(struct wpa_supplicant *wpa_s,
struct wpabuf *buf)
{
int len = wpabuf_len(buf);
- const u8 *pos = wpabuf_head_u8(buf), *next = pos;
+ u8 *pos = wpabuf_mhead_u8(buf), *next = pos;
#define MPDU_REPORT_LEN (int) (IEEE80211_MAX_MMPDU_SIZE - IEEE80211_HDRLEN - 3)
while (len) {
int send_len = (len > MPDU_REPORT_LEN) ? next - pos : len;
+ if (send_len == len)
+ wpas_rrm_beacon_rep_update_last_frame(pos, len);
+
if (send_len == len ||
(send_len + next[1] + 2) > MPDU_REPORT_LEN) {
wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
@@ -707,15 +756,17 @@
static int wpas_beacon_rep_add_frame_body(struct bitfield *eids,
enum beacon_report_detail detail,
struct wpa_bss *bss, u8 *buf,
- size_t buf_len)
+ size_t buf_len, u8 **ies_buf,
+ size_t *ie_len, int add_fixed)
{
- u8 *ies = (u8 *) (bss + 1);
- size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ u8 *ies = *ies_buf;
+ size_t ies_len = *ie_len;
u8 *pos = buf;
int rem_len;
rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
- sizeof(struct rrm_measurement_report_element) - 2;
+ sizeof(struct rrm_measurement_report_element) - 2 -
+ REPORTED_FRAME_BODY_SUBELEM_LEN;
if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
wpa_printf(MSG_DEBUG,
@@ -731,18 +782,21 @@
* Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
* beacon interval(2) + capabilities(2) = 14 bytes
*/
- if (buf_len < 14)
- return 0;
+ if (add_fixed && buf_len < 14)
+ return -1;
*pos++ = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY;
/* The length will be filled later */
pos++;
- WPA_PUT_LE64(pos, bss->tsf);
- pos += sizeof(bss->tsf);
- WPA_PUT_LE16(pos, bss->beacon_int);
- pos += 2;
- WPA_PUT_LE16(pos, bss->caps);
- pos += 2;
+
+ if (add_fixed) {
+ WPA_PUT_LE64(pos, bss->tsf);
+ pos += sizeof(bss->tsf);
+ WPA_PUT_LE16(pos, bss->beacon_int);
+ pos += 2;
+ WPA_PUT_LE16(pos, bss->caps);
+ pos += 2;
+ }
rem_len -= pos - buf;
@@ -757,15 +811,7 @@
while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) {
if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
(eids && bitfield_is_set(eids, ies[0]))) {
- u8 eid = ies[0], elen = ies[1];
-
- if ((eid == WLAN_EID_TIM || eid == WLAN_EID_RSN) &&
- elen > 4)
- elen = 4;
- /*
- * TODO: Truncate IBSS DFS element as described in
- * IEEE Std 802.11-2016, 9.4.2.22.7.
- */
+ u8 elen = ies[1];
if (2 + elen > buf + buf_len - pos ||
2 + elen > rem_len)
@@ -782,22 +828,91 @@
ies += 2 + ies[1];
}
+ *ie_len = ies_len;
+ *ies_buf = ies;
+
/* Now the length is known */
buf[1] = pos - buf - 2;
return pos - buf;
}
+static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data,
+ struct wpa_bss *bss,
+ struct wpabuf **wpa_buf,
+ struct rrm_measurement_beacon_report *rep,
+ u8 **ie, size_t *ie_len, u8 idx)
+{
+ int ret;
+ u8 *buf, *pos;
+ u32 subelems_len = REPORTED_FRAME_BODY_SUBELEM_LEN +
+ (data->last_indication ?
+ BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN : 0);
+
+ /* Maximum element length: Beacon Report element + Reported Frame Body
+ * subelement + all IEs of the reported Beacon frame + Reported Frame
+ * Body Fragment ID subelement */
+ buf = os_malloc(sizeof(*rep) + 14 + *ie_len + subelems_len);
+ if (!buf)
+ return -1;
+
+ os_memcpy(buf, rep, sizeof(*rep));
+
+ ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
+ bss, buf + sizeof(*rep),
+ 14 + *ie_len, ie, ie_len,
+ idx == 0);
+ if (ret < 0)
+ goto out;
+
+ pos = buf + ret + sizeof(*rep);
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID;
+ pos[1] = 2;
+
+ /*
+ * Only one Beacon Report Measurement is supported at a time, so
+ * the Beacon Report ID can always be set to 1.
+ */
+ pos[2] = 1;
+
+ /* Fragment ID Number (bits 0..6) and More Frame Body Fragments (bit 7)
+ */
+ pos[3] = idx;
+ if (data->report_detail != BEACON_REPORT_DETAIL_NONE && *ie_len)
+ pos[3] |= REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+ else
+ pos[3] &= ~REPORTED_FRAME_BODY_MORE_FRAGMENTS;
+
+ pos += REPORTED_FRAME_BODY_SUBELEM_LEN;
+
+ if (data->last_indication) {
+ pos[0] = WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION;
+ pos[1] = 1;
+
+ /* This field will be updated later if this is the last frame */
+ pos[2] = 0;
+ }
+
+ ret = wpas_rrm_report_elem(wpa_buf, data->token,
+ MEASUREMENT_REPORT_MODE_ACCEPT,
+ MEASURE_TYPE_BEACON, buf,
+ ret + sizeof(*rep) + subelems_len);
+out:
+ os_free(buf);
+ return ret;
+}
+
+
static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s,
struct wpabuf **wpa_buf, struct wpa_bss *bss,
u64 start, u64 parent_tsf)
{
struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
- u8 *ie = (u8 *) (bss + 1);
- size_t ie_len = bss->ie_len + bss->beacon_ie_len;
- int ret;
- u8 *buf;
- struct rrm_measurement_beacon_report *rep;
+ u8 *ies = (u8 *) (bss + 1);
+ u8 *pos = ies;
+ size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ struct rrm_measurement_beacon_report rep;
+ u8 idx = 0;
if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
@@ -808,39 +923,29 @@
os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 0))
return 0;
- /* Maximum element length: beacon report element + reported frame body
- * subelement + all IEs of the reported beacon */
- buf = os_malloc(sizeof(*rep) + 14 + ie_len);
- if (!buf)
- return -1;
+ if (wpas_get_op_chan_phy(bss->freq, ies, ies_len, &rep.op_class,
+ &rep.channel, &rep.report_info) < 0)
+ return 0;
- rep = (struct rrm_measurement_beacon_report *) buf;
- if (wpas_get_op_chan_phy(bss->freq, ie, ie_len, &rep->op_class,
- &rep->channel, &rep->report_info) < 0) {
- ret = 0;
- goto out;
- }
+ rep.start_time = host_to_le64(start);
+ rep.duration = host_to_le16(data->scan_params.duration);
+ rep.rcpi = rssi_to_rcpi(bss->level);
+ rep.rsni = 255; /* 255 indicates that RSNI is not available */
+ os_memcpy(rep.bssid, bss->bssid, ETH_ALEN);
+ rep.antenna_id = 0; /* unknown */
+ rep.parent_tsf = host_to_le32(parent_tsf);
- rep->start_time = host_to_le64(start);
- rep->duration = host_to_le16(data->scan_params.duration);
- rep->rcpi = rssi_to_rcpi(bss->level);
- rep->rsni = 255; /* 255 indicates that RSNI is not available */
- os_memcpy(rep->bssid, bss->bssid, ETH_ALEN);
- rep->antenna_id = 0; /* unknown */
- rep->parent_tsf = host_to_le32(parent_tsf);
+ do {
+ int ret;
- ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
- bss, rep->variable, 14 + ie_len);
- if (ret < 0)
- goto out;
+ ret = wpas_add_beacon_rep_elem(data, bss, wpa_buf, &rep,
+ &pos, &ies_len, idx++);
+ if (ret)
+ return ret;
+ } while (data->report_detail != BEACON_REPORT_DETAIL_NONE &&
+ ies_len >= 2);
- ret = wpas_rrm_report_elem(wpa_buf, wpa_s->beacon_rep_data.token,
- MEASUREMENT_REPORT_MODE_ACCEPT,
- MEASURE_TYPE_BEACON, buf,
- ret + sizeof(*rep));
-out:
- os_free(buf);
- return ret;
+ return 0;
}
@@ -1006,6 +1111,16 @@
case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
/* Skip - it will be processed when freqs are added */
break;
+ case WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION:
+ if (slen != 1) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: Invalid last indication request subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ data->last_indication = subelem[0];
+ break;
default:
wpa_printf(MSG_DEBUG,
"Beacon request: Unknown subelement id %u", sid);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index ee39e0c..727c49a 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -581,8 +581,8 @@
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
- wpas_hs20_add_indication(extra_ie, -1);
+ if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0)
+ wpas_hs20_add_indication(extra_ie, -1, 0);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
@@ -2806,6 +2806,13 @@
{
u8 *tmp = NULL;
+ if ((wpa_s->mac_addr_rand_supported & type) != type ) {
+ wpa_printf(MSG_INFO,
+ "scan: MAC randomization type %u != supported=%u",
+ type, wpa_s->mac_addr_rand_supported);
+ return -1;
+ }
+
wpas_mac_addr_rand_scan_clear(wpa_s, type);
if (addr) {
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index d23dc06..ba22a93 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/ocv.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
#include "common/sae.h"
@@ -72,7 +73,7 @@
if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
wpa_s->sme.sae.group);
- return 0;
+ return 0;
}
wpa_s->sme.sae_group_index++;
}
@@ -354,6 +355,20 @@
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)) {
+ 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)) {
/*
@@ -445,7 +460,7 @@
wpa_s->sme.assoc_req_ie_len += 5;
}
- if (wpa_s->sme.ft_used &&
+ if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used &&
os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
wpa_sm_has_ptk(wpa_s->wpa)) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
@@ -505,7 +520,7 @@
sme_auth_handle_rrm(wpa_s, bss);
wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
- wpa_s, bss->freq,
+ wpa_s, ssid, bss->freq,
wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len);
@@ -536,7 +551,8 @@
int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
size_t len;
- wpas_hs20_add_indication(hs20, pps_mo_id);
+ 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;
@@ -881,10 +897,10 @@
os_memcpy(resp->da, da, ETH_ALEN);
os_memcpy(resp->sa, sa, ETH_ALEN);
os_memcpy(resp->bssid, da, ETH_ALEN);
- resp->u.auth.auth_alg = WLAN_AUTH_SAE;
- resp->seq_ctrl = seq_num << 4;
- resp->u.auth.auth_transaction = auth_transaction;
- resp->u.auth.status_code = WLAN_STATUS_SUCCESS;
+ resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
+ resp->seq_ctrl = host_to_le16(seq_num << 4);
+ resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
+ resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
if (params)
wpabuf_put_buf(buf, params);
@@ -944,7 +960,8 @@
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (!wpas_network_disabled(wpa_s, ssid) &&
ssid_str_len == ssid->ssid_len &&
- os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
+ os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 &&
+ (ssid->key_mgmt & WPA_KEY_MGMT_SAE))
break;
}
if (ssid)
@@ -1163,13 +1180,14 @@
return;
}
- if (header->u.auth.auth_alg == WLAN_AUTH_SAE) {
+ if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) {
int res;
- res = sme_sae_auth(wpa_s, header->u.auth.auth_transaction,
- header->u.auth.status_code,
- header->u.auth.variable,
- len - auth_length, 1, header->sa);
+ res = sme_sae_auth(
+ wpa_s, le_to_host16(header->u.auth.auth_transaction),
+ le_to_host16(header->u.auth.status_code),
+ header->u.auth.variable,
+ len - auth_length, 1, header->sa);
if (res < 0) {
/* Notify failure to the driver */
sme_send_external_auth_status(
@@ -1370,7 +1388,6 @@
}
-#ifdef CONFIG_FILS
#ifdef CONFIG_IEEE80211R
static void remove_ie(u8 *buf, size_t *len, u8 eid)
{
@@ -1385,7 +1402,6 @@
}
}
#endif /* CONFIG_IEEE80211R */
-#endif /* CONFIG_FILS */
void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
@@ -1504,14 +1520,18 @@
if (wpa_s->current_ssid && wpa_s->current_ssid->owe_group) {
group = wpa_s->current_ssid->owe_group;
- } else {
+ } else if (wpa_s->assoc_status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
if (wpa_s->last_owe_group == 19)
group = 20;
else if (wpa_s->last_owe_group == 20)
group = 21;
else
group = OWE_DH_GROUP;
+ } else {
+ group = OWE_DH_GROUP;
}
+
wpa_s->last_owe_group = group;
wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
@@ -1534,6 +1554,22 @@
}
#endif /* CONFIG_OWE */
+ if (wpa_s->current_ssid && wpa_s->current_ssid->multi_ap_backhaul_sta) {
+ size_t multi_ap_ie_len;
+
+ multi_ap_ie_len = add_multi_ap_ie(
+ wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len,
+ MULTI_AP_BACKHAUL_STA);
+ if (multi_ap_ie_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "Multi-AP: Failed to build Multi-AP IE");
+ return;
+ }
+ wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
+ }
+
params.bssid = bssid;
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
@@ -1543,6 +1579,8 @@
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_hexdump(MSG_DEBUG, "SME: Association Request IEs",
+ params.wpa_ie, params.wpa_ie_len);
params.pairwise_suite = wpa_s->pairwise_cipher;
params.group_suite = wpa_s->group_cipher;
params.mgmt_group_suite = wpa_s->mgmt_group_cipher;
@@ -1563,9 +1601,85 @@
wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_IEEE80211R
- if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
+ if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
+ get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
+ WLAN_EID_RIC_DATA)) {
+ /* There seems to be a pretty inconvenient bug in the Linux
+ * kernel IE splitting functionality when RIC is used. For now,
+ * skip correct behavior in IE construction here (i.e., drop the
+ * additional non-FT-specific IEs) to avoid kernel issues. This
+ * is fine since RIC is used only for testing purposes in the
+ * current implementation. */
+ wpa_printf(MSG_INFO,
+ "SME: Linux kernel workaround - do not try to include additional IEs with RIC");
params.wpa_ie = wpa_s->sme.ft_ies;
params.wpa_ie_len = wpa_s->sme.ft_ies_len;
+ } else if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
+ const u8 *rm_en, *pos, *end;
+ size_t rm_en_len = 0;
+ u8 *rm_en_dup = NULL, *wpos;
+
+ /* Remove RSNE, MDE, FTE to allow them to be overridden with
+ * FT specific values */
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RSN);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_MOBILITY_DOMAIN);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_FAST_BSS_TRANSITION);
+ rm_en = get_ie(wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (rm_en) {
+ /* Need to remove RM Enabled Capabilities element as
+ * well temporarily, so that it can be placed between
+ * RSNE and MDE. */
+ rm_en_len = 2 + rm_en[1];
+ rm_en_dup = os_memdup(rm_en, rm_en_len);
+ remove_ie(wpa_s->sme.assoc_req_ie,
+ &wpa_s->sme.assoc_req_ie_len,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Association Request IEs after FT IE removal",
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ if (wpa_s->sme.assoc_req_ie_len + wpa_s->sme.ft_ies_len +
+ rm_en_len > sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "SME: Not enough buffer room for FT IEs in Association Request frame");
+ os_free(rm_en_dup);
+ return;
+ }
+
+ os_memmove(wpa_s->sme.assoc_req_ie + wpa_s->sme.ft_ies_len +
+ rm_en_len,
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len);
+ pos = wpa_s->sme.ft_ies;
+ end = pos + wpa_s->sme.ft_ies_len;
+ wpos = wpa_s->sme.assoc_req_ie;
+ if (*pos == WLAN_EID_RSN) {
+ os_memcpy(wpos, pos, 2 + pos[1]);
+ wpos += 2 + pos[1];
+ pos += 2 + pos[1];
+ }
+ if (rm_en_dup) {
+ os_memcpy(wpos, rm_en_dup, rm_en_len);
+ wpos += rm_en_len;
+ os_free(rm_en_dup);
+ }
+ os_memcpy(wpos, pos, end - pos);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->sme.ft_ies_len +
+ rm_en_len;
+ params.wpa_ie = wpa_s->sme.assoc_req_ie;
+ params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
+ wpa_hexdump(MSG_DEBUG,
+ "SME: Association Request IEs after FT override",
+ params.wpa_ie, params.wpa_ie_len);
}
#endif /* CONFIG_IEEE80211R */
params.mode = mode;
@@ -2122,6 +2236,7 @@
static const unsigned int sa_query_max_timeout = 1000;
static const unsigned int sa_query_retry_timeout = 201;
+static const unsigned int sa_query_ch_switch_max_delay = 5000; /* in usec */
static int sme_check_sa_query_timeout(struct wpa_supplicant *wpa_s)
{
@@ -2145,7 +2260,9 @@
static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
const u8 *trans_id)
{
- u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN];
+ u8 req[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
+ u8 req_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Request to "
MACSTR, MAC2STR(wpa_s->bssid));
wpa_hexdump(MSG_DEBUG, "SME: SA Query Transaction ID",
@@ -2153,9 +2270,27 @@
req[0] = WLAN_ACTION_SA_QUERY;
req[1] = WLAN_SA_QUERY_REQUEST;
os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Request frame");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, req + req_len) < 0)
+ return;
+
+ req_len += OCV_OCI_EXTENDED_LEN;
+ }
+#endif /* CONFIG_OCV */
+
if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
- req, sizeof(req), 0) < 0)
+ req, req_len, 0) < 0)
wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
"Request");
}
@@ -2250,15 +2385,74 @@
}
-void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
- const u8 *data, size_t len)
+void sme_event_ch_switch(struct wpa_supplicant *wpa_s)
+{
+ unsigned int usec;
+ u32 _rand;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ !wpa_sm_ocv_enabled(wpa_s->wpa))
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Channel switch completed - trigger new SA Query to verify new operating channel");
+ sme_stop_sa_query(wpa_s);
+
+ if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+ _rand = os_random();
+ usec = _rand % (sa_query_ch_switch_max_delay + 1);
+ eloop_register_timeout(0, usec, sme_sa_query_timer, wpa_s, NULL);
+}
+
+
+static void sme_process_sa_query_request(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ size_t len)
+{
+ u8 resp[2 + WLAN_SA_QUERY_TR_ID_LEN + OCV_OCI_EXTENDED_LEN];
+ u8 resp_len = 2 + WLAN_SA_QUERY_TR_ID_LEN;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Sending SA Query Response to "
+ MACSTR, MAC2STR(wpa_s->bssid));
+
+ resp[0] = WLAN_ACTION_SA_QUERY;
+ resp[1] = WLAN_SA_QUERY_RESPONSE;
+ os_memcpy(resp + 2, data + 1, WLAN_SA_QUERY_TR_ID_LEN);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in SA Query Response frame");
+ return;
+ }
+
+ if (ocv_insert_extended_oci(&ci, resp + resp_len) < 0)
+ return;
+
+ resp_len += OCV_OCI_EXTENDED_LEN;
+ }
+#endif /* CONFIG_OCV */
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ resp, resp_len, 0) < 0)
+ wpa_msg(wpa_s, MSG_INFO,
+ "SME: Failed to send SA Query Response");
+}
+
+
+static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, const u8 *data,
+ size_t len)
{
int i;
- if (wpa_s->sme.sa_query_trans_id == NULL ||
- len < 1 + WLAN_SA_QUERY_TR_ID_LEN ||
- data[0] != WLAN_SA_QUERY_RESPONSE)
+ if (!wpa_s->sme.sa_query_trans_id)
return;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query response from "
MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
@@ -2283,4 +2477,48 @@
sme_stop_sa_query(wpa_s);
}
+
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+ const u8 *data, size_t len)
+{
+ if (len < 1 + WLAN_SA_QUERY_TR_ID_LEN)
+ return;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Received SA Query frame from "
+ MACSTR " (trans_id %02x%02x)", MAC2STR(sa), data[1], data[2]);
+
+#ifdef CONFIG_OCV
+ if (wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct ieee802_11_elems elems;
+ struct wpa_channel_info ci;
+
+ if (ieee802_11_parse_elems(data + 1 + WLAN_SA_QUERY_TR_ID_LEN,
+ len - 1 - WLAN_SA_QUERY_TR_ID_LEN,
+ &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "SA Query: Failed to parse elements");
+ return;
+ }
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info to validate received OCI in SA Query Action frame");
+ return;
+ }
+
+ if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_printf(MSG_WARNING, "%s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ if (data[0] == WLAN_SA_QUERY_REQUEST)
+ sme_process_sa_query_request(wpa_s, sa, data, len);
+ else if (data[0] == WLAN_SA_QUERY_RESPONSE)
+ sme_process_sa_query_response(wpa_s, sa, data, len);
+}
+
#endif /* CONFIG_IEEE80211W */
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index f3c8220..1a7f9e8 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -28,6 +28,7 @@
struct disassoc_info *info);
void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *da, u16 reason_code);
+void sme_event_ch_switch(struct wpa_supplicant *wpa_s);
void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
const u8 *data, size_t len);
void sme_state_changed(struct wpa_supplicant *wpa_s);
@@ -89,6 +90,10 @@
{
}
+static inline void sme_event_ch_switch(struct wpa_supplicant *wpa_s)
+{
+}
+
static inline void sme_state_changed(struct wpa_supplicant *wpa_s)
{
}
diff --git a/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant/utils/log2pcap.py
index 65e2fa1..141aecb 100755
--- a/wpa_supplicant/utils/log2pcap.py
+++ b/wpa_supplicant/utils/log2pcap.py
@@ -28,7 +28,7 @@
input = sys.argv[1]
pcap = sys.argv[2]
except IndexError:
- print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+ print("Usage: %s <log file> <pcap file>" % sys.argv[0])
sys.exit(2)
input_file = open(input, 'r')
diff --git a/wpa_supplicant/wmm_ac.c b/wpa_supplicant/wmm_ac.c
index a88cc46..38800cc 100644
--- a/wpa_supplicant/wmm_ac.c
+++ b/wpa_supplicant/wmm_ac.c
@@ -471,13 +471,8 @@
return -1;
}
- if (!ies) {
- wpa_printf(MSG_ERROR, "WMM AC: Missing IEs");
- return -1;
- }
-
- if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
- wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration");
+ if (!ies || !(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
+ /* WMM AC not in use for this connection */
return -1;
}
@@ -522,7 +517,7 @@
for (i = 0; i < WMM_AC_NUM; i++)
wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL);
- /* delete pending add_ts requset */
+ /* delete pending add_ts request */
wmm_ac_del_req(wpa_s, 1);
os_free(wpa_s->wmm_ac_assoc_info);
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 912f4c4..39cd163 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -12,6 +12,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/ocv.h"
#include "rsn_supp/wpa.h"
#include "config.h"
#include "wpa_supplicant_i.h"
@@ -20,6 +21,7 @@
#include "ctrl_iface.h"
#include "bss.h"
#include "wnm_sta.h"
+#include "notify.h"
#include "hs20_supplicant.h"
#define MAX_TFS_IE_LEN 1024
@@ -58,8 +60,8 @@
int res;
size_t len;
struct wnm_sleep_element *wnmsleep_ie;
- u8 *wnmtfs_ie;
- u8 wnmsleep_ie_len;
+ u8 *wnmtfs_ie, *oci_ie;
+ u8 wnmsleep_ie_len, oci_ie_len;
u16 wnmtfs_ie_len; /* possibly multiple IE(s) */
enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
WNM_SLEEP_TFS_REQ_IE_NONE;
@@ -106,7 +108,41 @@
wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
(u8 *) wnmtfs_ie, wnmtfs_ie_len);
- mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+ oci_ie = NULL;
+ oci_ie_len = 0;
+#ifdef CONFIG_OCV
+ if (action == WNM_SLEEP_MODE_EXIT && wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Failed to get channel info for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ oci_ie_len = OCV_OCI_EXTENDED_LEN;
+ oci_ie = os_zalloc(oci_ie_len);
+ if (!oci_ie) {
+ wpa_printf(MSG_WARNING,
+ "Failed to allocate buffer for for OCI element in WNM-Sleep Mode frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ return -1;
+ }
+
+ if (ocv_insert_extended_oci(&ci, oci_ie) < 0) {
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ os_free(oci_ie);
+ return -1;
+ }
+ }
+#endif /* CONFIG_OCV */
+
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len +
+ oci_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Request action frame");
@@ -131,8 +167,16 @@
wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
}
+#ifdef CONFIG_OCV
+ /* copy OCV OCI here */
+ if (oci_ie_len > 0) {
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+ wnmsleep_ie_len + wnmtfs_ie_len, oci_ie, oci_ie_len);
+ }
+#endif /* CONFIG_OCV */
+
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
- wnmtfs_ie_len;
+ wnmtfs_ie_len + oci_ie_len;
res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
@@ -145,6 +189,7 @@
os_free(wnmsleep_ie);
os_free(wnmtfs_ie);
+ os_free(oci_ie);
os_free(mgmt);
return res;
@@ -256,6 +301,10 @@
/* multiple TFS Resp IE (assuming consecutive) */
const u8 *tfsresp_ie_start = NULL;
const u8 *tfsresp_ie_end = NULL;
+#ifdef CONFIG_OCV
+ const u8 *oci_ie = NULL;
+ u8 oci_ie_len = 0;
+#endif /* CONFIG_OCV */
size_t left;
if (!wpa_s->wnmsleep_used) {
@@ -289,6 +338,12 @@
if (!tfsresp_ie_start)
tfsresp_ie_start = pos;
tfsresp_ie_end = pos;
+#ifdef CONFIG_OCV
+ } else if (*pos == WLAN_EID_EXTENSION && ie_len >= 1 &&
+ pos[2] == WLAN_EID_EXT_OCV_OCI) {
+ oci_ie = pos + 3;
+ oci_ie_len = ie_len - 1;
+#endif /* CONFIG_OCV */
} else
wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
pos += ie_len + 2;
@@ -299,6 +354,26 @@
return;
}
+#ifdef CONFIG_OCV
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT &&
+ wpa_sm_ocv_enabled(wpa_s->wpa)) {
+ struct wpa_channel_info ci;
+
+ if (wpa_drv_channel_info(wpa_s, &ci) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Failed to get channel info to validate received OCI in WNM-Sleep Mode frame");
+ return;
+ }
+
+ if (ocv_verify_tx_params(oci_ie, oci_ie_len, &ci,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING, "WNM: %s", ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
wpa_s->wnmsleep_used = 0;
if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
@@ -700,7 +775,7 @@
continue;
}
- if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
+ if (wpa_is_bss_tmp_disallowed(wpa_s, target)) {
wpa_printf(MSG_DEBUG,
"MBO: Candidate BSS " MACSTR
" retry delay is not over yet",
@@ -945,6 +1020,9 @@
return;
}
+ wpa_s->bss_tm_status = status;
+ wpas_notify_bss_tm_status(wpa_s);
+
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP);
wpabuf_put_u8(buf, dialog_token);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 05e3ebf..9881021 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,7 +29,7 @@
static const char *const wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> and contributors";
#define VENDOR_ELEM_FRAME_ID \
" 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
@@ -49,6 +49,7 @@
static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
static const char *client_socket_dir = NULL;
static char *ctrl_ifname = NULL;
+static const char *global = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
static int ping_interval = 5;
@@ -74,6 +75,7 @@
static void update_creds(struct wpa_ctrl *ctrl);
static void update_networks(struct wpa_ctrl *ctrl);
static void update_stations(struct wpa_ctrl *ctrl);
+static void update_ifnames(struct wpa_ctrl *ctrl);
static void usage(void)
@@ -1203,6 +1205,39 @@
}
+static int wpa_cli_cmd_psk_passphrase(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i, ret;
+
+ if (argc < 2) {
+ printf("Invalid PSK_PASSPHRASE command: needs two arguments (network id and PSK/passphrase)\n");
+ return -1;
+ }
+
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PSK_PASSPHRASE-%s:%s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(end - pos, ret)) {
+ printf("Too long PSK_PASSPHRASE command.\n");
+ return -1;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (os_snprintf_error(end - pos, ret)) {
+ printf("Too long PSK_PASSPHRASE command.\n");
+ return -1;
+ }
+ pos += ret;
+ }
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1412,7 +1447,7 @@
#ifdef CONFIG_HT_OVERRIDES
"disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc",
"ht40_intolerant", "disable_max_amsdu", "ampdu_factor",
- "ampdu_density", "ht_mcs",
+ "ampdu_density", "ht_mcs", "rx_stbc", "tx_stbc",
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
"disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1",
@@ -1426,6 +1461,8 @@
#ifdef CONFIG_MACSEC
"macsec_policy",
"macsec_integ_only",
+ "macsec_replay_protect",
+ "macsec_replay_window",
"macsec_port",
"mka_priority",
#endif /* CONFIG_MACSEC */
@@ -2955,6 +2992,13 @@
}
+static int wpa_cli_cmd_dpp_configurator_sign(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DPP_CONFIGURATOR_SIGN", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -3084,6 +3128,9 @@
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
+ { "psk_passphrase", wpa_cli_cmd_psk_passphrase,
+ wpa_cli_complete_network_id, cli_cmd_flag_sensitive,
+ "<network id> <PSK/passphrase> = configure PSK/passphrase for an SSID" },
{ "passphrase", wpa_cli_cmd_passphrase, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
@@ -3614,6 +3661,9 @@
{ "dpp_configurator_get_key", wpa_cli_cmd_dpp_configurator_get_key,
NULL, cli_cmd_flag_none,
"<id> = Get DPP configurator's private key" },
+ { "dpp_configurator_sign", wpa_cli_cmd_dpp_configurator_sign, NULL,
+ cli_cmd_flag_none,
+ "conf=<role> configurator=<id> = generate self DPP configuration" },
{ "dpp_pkex_add", wpa_cli_cmd_dpp_pkex_add, NULL,
cli_cmd_flag_sensitive,
"add PKEX code" },
@@ -3972,10 +4022,46 @@
#endif /* CONFIG_ANSI_C_EXTRA */
+static int wpa_cli_open_global_ctrl(void)
+{
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ ctrl_conn = wpa_ctrl_open(NULL);
+#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ ctrl_conn = wpa_ctrl_open(global);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ if (!ctrl_conn) {
+ fprintf(stderr,
+ "Failed to connect to wpa_supplicant global interface: %s error: %s\n",
+ global, strerror(errno));
+ return -1;
+ }
+
+ if (interactive) {
+ update_ifnames(ctrl_conn);
+ mon_conn = wpa_ctrl_open(global);
+ if (mon_conn) {
+ if (wpa_ctrl_attach(mon_conn) == 0) {
+ wpa_cli_attached = 1;
+ eloop_register_read_sock(
+ wpa_ctrl_get_fd(mon_conn),
+ wpa_cli_mon_receive,
+ NULL, NULL);
+ } else {
+ printf("Failed to open monitor connection through global control interface\n");
+ }
+ }
+ update_stations(ctrl_conn);
+ }
+
+ return 0;
+}
+
+
static void wpa_cli_reconnect(void)
{
wpa_cli_close_connection();
- if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
+ if ((global && wpa_cli_open_global_ctrl() < 0) ||
+ (!global && wpa_cli_open_connection(ctrl_ifname, 1) < 0))
return;
if (interactive) {
@@ -4534,7 +4620,6 @@
int c;
int daemonize = 0;
int ret = 0;
- const char *global = NULL;
if (os_program_init())
return -1;
@@ -4589,38 +4674,8 @@
if (eloop_init())
return -1;
- if (global) {
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
- ctrl_conn = wpa_ctrl_open(NULL);
-#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
- ctrl_conn = wpa_ctrl_open(global);
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
- if (ctrl_conn == NULL) {
- fprintf(stderr, "Failed to connect to wpa_supplicant "
- "global interface: %s error: %s\n",
- global, strerror(errno));
- return -1;
- }
-
- if (interactive) {
- update_ifnames(ctrl_conn);
- mon_conn = wpa_ctrl_open(global);
- if (mon_conn) {
- if (wpa_ctrl_attach(mon_conn) == 0) {
- wpa_cli_attached = 1;
- eloop_register_read_sock(
- wpa_ctrl_get_fd(mon_conn),
- wpa_cli_mon_receive,
- NULL, NULL);
- } else {
- printf("Failed to open monitor "
- "connection through global "
- "control interface\n");
- }
- }
- update_stations(ctrl_conn);
- }
- }
+ if (global && wpa_cli_open_global_ctrl() < 0)
+ return -1;
eloop_register_signal_terminate(wpa_cli_terminate, NULL);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 4432ec3..857fb35 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -68,7 +68,7 @@
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors";
const char *const wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -445,7 +445,7 @@
}
-static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
{
struct wpa_bss_tmp_disallowed *bss, *prev;
@@ -847,6 +847,23 @@
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
+ if (state == WPA_COMPLETED &&
+ os_reltime_initialized(&wpa_s->roam_start)) {
+ os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time);
+ wpa_s->roam_start.sec = 0;
+ wpa_s->roam_start.usec = 0;
+ wpas_notify_auth_changed(wpa_s);
+ wpas_notify_roam_time(wpa_s);
+ wpas_notify_roam_complete(wpa_s);
+ } else if (state == WPA_DISCONNECTED &&
+ os_reltime_initialized(&wpa_s->roam_start)) {
+ wpa_s->roam_start.sec = 0;
+ wpa_s->roam_start.usec = 0;
+ wpa_s->roam_time.sec = 0;
+ wpa_s->roam_time.usec = 0;
+ wpas_notify_roam_complete(wpa_s);
+ }
+
if (state == WPA_INTERFACE_DISABLED) {
/* Assure normal scan when interface is restored */
wpa_s->normal_scans = 0;
@@ -1217,13 +1234,12 @@
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)) {
+ } 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");
- /* TODO: parse OSEN element */
- os_memset(&ie, 0, sizeof(ie));
- ie.group_cipher = WPA_CIPHER_CCMP;
- ie.pairwise_cipher = WPA_CIPHER_CCMP;
- ie.key_mgmt = WPA_KEY_MGMT_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 &&
@@ -1513,6 +1529,9 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
wpas_get_ssid_pmf(wpa_s, ssid));
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
+#endif /* CONFIG_OCV */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
@@ -1903,6 +1922,8 @@
if (wpa_s->current_bss && wpa_s->current_bss == bss) {
wmm_ac_save_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 1;
+ } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
+ os_get_reltime(&wpa_s->roam_start);
}
}
@@ -2171,9 +2192,14 @@
if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
+ freq->channel = pri_chan->chan;
+
#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht40)
- return;
+ if (ssid->disable_ht40) {
+ if (ssid->disable_vht)
+ return;
+ goto skip_ht40;
+ }
#endif /* CONFIG_HT_OVERRIDES */
/* Check/setup HT40+/HT40- */
@@ -2198,8 +2224,6 @@
if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
- freq->channel = pri_chan->chan;
-
if (ht40 == -1) {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
return;
@@ -2243,6 +2267,9 @@
wpa_scan_results_free(scan_res);
}
+#ifdef CONFIG_HT_OVERRIDES
+skip_ht40:
+#endif /* CONFIG_HT_OVERRIDES */
wpa_printf(MSG_DEBUG,
"IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
freq->channel, freq->sec_channel_offset);
@@ -2332,6 +2359,13 @@
vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
seg0 = 114;
}
+ } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_USE_HT) {
+ chwidth = VHT_CHANWIDTH_USE_HT;
+ seg0 = vht80[j] + 2;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht40)
+ seg0 = 0;
+#endif /* CONFIG_HT_OVERRIDES */
}
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
@@ -2499,6 +2533,19 @@
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)) {
+ 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)) {
/*
@@ -2622,7 +2669,7 @@
#endif /* CONFIG_P2P */
if (bss) {
- wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
wpa_ie + wpa_ie_len,
max_wpa_ie_len -
wpa_ie_len);
@@ -2667,7 +2714,8 @@
int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
size_t len;
- wpas_hs20_add_indication(hs20, pps_mo_id);
+ wpas_hs20_add_indication(hs20, pps_mo_id,
+ get_hs20_version(bss));
wpas_hs20_add_roam_cons_sel(hs20, ssid);
len = max_wpa_ie_len - wpa_ie_len;
if (wpabuf_len(hs20) <= len) {
@@ -2743,14 +2791,18 @@
if (ssid->owe_group) {
group = ssid->owe_group;
- } else {
+ } else if (wpa_s->assoc_status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
if (wpa_s->last_owe_group == 19)
group = 20;
else if (wpa_s->last_owe_group == 20)
group = 21;
else
group = OWE_DH_GROUP;
+ } else {
+ group = OWE_DH_GROUP;
}
+
wpa_s->last_owe_group = group;
wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
@@ -2797,6 +2849,21 @@
}
#endif /* CONFIG_IEEE80211R */
+ if (ssid->multi_ap_backhaul_sta) {
+ size_t multi_ap_ie_len;
+
+ multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
+ max_wpa_ie_len - wpa_ie_len,
+ MULTI_AP_BACKHAUL_STA);
+ if (multi_ap_ie_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "Multi-AP: Failed to build Multi-AP IE");
+ os_free(wpa_ie);
+ return NULL;
+ }
+ wpa_ie_len += multi_ap_ie_len;
+ }
+
params->wpa_ie = wpa_ie;
params->wpa_ie_len = wpa_ie_len;
params->auth_alg = algs;
@@ -3040,7 +3107,7 @@
}
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
- if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
(params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
params.passphrase = ssid->passphrase;
@@ -3048,6 +3115,13 @@
params.psk = ssid->psk;
}
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
+ (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
+ params.req_key_mgmt_offload = 1;
+
if (wpa_s->conf->key_mgmt_offload) {
if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
@@ -3275,6 +3349,9 @@
zero_addr = 1;
}
+ if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
+ wpa_s->enabled_4addr_mode = 0;
+
#ifdef CONFIG_TDLS
wpa_tdls_teardown_peers(wpa_s->wpa);
#endif /* CONFIG_TDLS */
@@ -4044,7 +4121,7 @@
}
if (wpa_s->eapol_received == 0 &&
- (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
+ (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->wpa_state != WPA_COMPLETED) &&
(wpa_s->current_ssid == NULL ||
@@ -4110,7 +4187,7 @@
eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
return;
wpa_drv_poll(wpa_s);
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
@@ -4352,11 +4429,11 @@
{
le16 msk;
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
-
if (disabled == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
htcaps_mask->ht_capabilities_info |= msk;
if (disabled)
@@ -4373,11 +4450,11 @@
struct ieee80211_ht_capabilities *htcaps_mask,
int factor)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
-
if (factor == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
if (factor < 0 || factor > 3) {
wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
"Must be 0-3 or -1", factor);
@@ -4397,11 +4474,11 @@
struct ieee80211_ht_capabilities *htcaps_mask,
int density)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
-
if (density == -1)
return 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
if (density < 0 || density > 7) {
wpa_msg(wpa_s, MSG_ERROR,
"ampdu_density: %d out of range. Must be 0-7 or -1.",
@@ -4422,7 +4499,8 @@
struct ieee80211_ht_capabilities *htcaps_mask,
int disabled)
{
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
set_disable_ht40(htcaps, disabled);
set_disable_ht40(htcaps_mask, 0);
@@ -4440,7 +4518,8 @@
le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
HT_CAP_INFO_SHORT_GI40MHZ);
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
if (disabled)
htcaps->ht_capabilities_info &= ~msk;
@@ -4461,7 +4540,8 @@
/* Masking these out disables LDPC */
le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
- wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
+ if (disabled)
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
if (disabled)
htcaps->ht_capabilities_info &= ~msk;
@@ -4474,6 +4554,58 @@
}
+static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int tx_stbc)
+{
+ le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
+
+ if (tx_stbc == -1)
+ return 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
+
+ if (tx_stbc < 0 || tx_stbc > 1) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
+ return -EINVAL;
+ }
+
+ htcaps_mask->ht_capabilities_info |= msk;
+ htcaps->ht_capabilities_info &= ~msk;
+ htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk;
+
+ return 0;
+}
+
+
+static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int rx_stbc)
+{
+ le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
+
+ if (rx_stbc == -1)
+ return 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
+
+ if (rx_stbc < 0 || rx_stbc > 3) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
+ return -EINVAL;
+ }
+
+ htcaps_mask->ht_capabilities_info |= msk;
+ htcaps->ht_capabilities_info &= ~msk;
+ htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk;
+
+ return 0;
+}
+
+
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params)
@@ -4498,6 +4630,8 @@
wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
+ wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc);
+ wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc);
if (ssid->ht40_intolerant) {
le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
@@ -4532,6 +4666,16 @@
vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
#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);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "disable-sgi override specified, vht-caps: 0x%x",
+ vhtcaps->vht_capabilities_info);
+ }
+
/* if max ampdu is <= 3, we have to make the HT cap the same */
if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
int max_ampdu;
@@ -5545,6 +5689,12 @@
capa.mac_addr_rand_sched_scan_supported)
wpa_s->mac_addr_rand_supported |=
(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
+
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+ if (wpa_s->extended_capa &&
+ wpa_s->extended_capa_len >= 3 &&
+ wpa_s->extended_capa[2] & 0x40)
+ wpa_s->multi_bss_support = 1;
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -7204,16 +7354,14 @@
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
- unsigned int sec)
+ unsigned int sec, int rssi_threshold)
{
struct wpa_bss_tmp_disallowed *bss;
bss = wpas_get_disallowed_bss(wpa_s, bssid);
if (bss) {
eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
- eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
- wpa_s, bss);
- return;
+ goto finish;
}
bss = os_malloc(sizeof(*bss));
@@ -7226,23 +7374,31 @@
os_memcpy(bss->bssid, bssid, ETH_ALEN);
dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
wpa_set_driver_tmp_disallow_list(wpa_s);
+
+finish:
+ bss->rssi_threshold = rssi_threshold;
eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
wpa_s, bss);
}
-int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
{
- struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
+ struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
struct wpa_bss_tmp_disallowed, list) {
- if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
- bss = tmp;
+ if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
+ disallowed = tmp;
break;
}
}
- if (!bss)
+ if (!disallowed)
+ return 0;
+
+ if (disallowed->rssi_threshold != 0 &&
+ bss->level > disallowed->rssi_threshold)
return 0;
return 1;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 4f59160..1bd43b2 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -907,6 +907,13 @@
# PMF required: ieee80211w=2 and key_mgmt=WPA-EAP-SHA256
# (and similarly for WPA-PSK and WPA-WPSK-SHA256 if WPA2-Personal is used)
#
+# ocv: whether operating channel validation is enabled
+# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this automatically also enables ieee80211w, if not yet enabled.
+# 0 = disabled (default)
+# 1 = enabled
+#ocv=1
+#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
# OPEN = Open System authentication (required for WPA/WPA2)
# SHARED = Shared Key authentication (requires static WEP keys)
@@ -987,6 +994,22 @@
# 0: Encrypt traffic (default)
# 1: Integrity only
#
+# macsec_replay_protect: IEEE 802.1X/MACsec replay protection
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Replay protection disabled (default)
+# 1: Replay protection enabled
+#
+# macsec_replay_window: IEEE 802.1X/MACsec replay protection window
+# This determines a window in which replay is tolerated, to allow receipt
+# of frames that have been misordered by the network.
+# This setting applies only when MACsec replay protection active, i.e.,
+# - macsec_replay_protect is enabled
+# - the key server has decided to enable MACsec
+# 0: No replay window, strict check (default)
+# 1..2^32-1: number of packets that could be misordered
+#
# macsec_port: IEEE 802.1X/MACsec port
# Port component of the SCI
# Range: 1-65534 (default: 1)
@@ -995,9 +1018,10 @@
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
# In this mode, instances of wpa_supplicant can act as MACsec peers. The peer
# with lower priority will become the key server and start distributing SAKs.
-# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-bytes (128 bit)
-# hex-string (32 hex-digits)
-# mka_ckn (CKN = CAK Name) takes a 32-bytes (256 bit) hex-string (64 hex-digits)
+# mka_cak (CAK = Secure Connectivity Association Key) takes a 16-byte (128-bit)
+# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits)
+# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string
+# (2..64 hex-digits)
# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being
# default priority
#
@@ -1216,12 +1240,19 @@
# For EAP-FAST, this must be set to 0 (or left unconfigured for the
# default value to be used automatically).
# tls_disable_tlsv1_0=1 - disable use of TLSv1.0
+# tls_disable_tlsv1_0=0 - explicitly enable use of TLSv1.0 (this allows
+# systemwide TLS policies to be overridden)
# tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_1=0 - explicitly enable use of TLSv1.1 (this allows
+# systemwide TLS policies to be overridden)
# tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_2=0 - explicitly enable use of TLSv1.2 (this allows
+# systemwide TLS policies to be overridden)
# tls_disable_tlsv1_3=1 - disable use of TLSv1.3 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_disable_tlsv1_3=0 - enable TLSv1.3 (experimental - disabled by default)
# tls_ext_cert_check=0 - No external server certificate validation (default)
# tls_ext_cert_check=1 - External server certificate validation enabled; this
# requires an external program doing validation of server certificate
@@ -1381,6 +1412,20 @@
# Treated as hint by the kernel.
# -1 = Do not make any changes.
# 0-3 = Set AMPDU density (aka factor) to specified value.
+#
+# tx_stbc: Allow overriding STBC support for TX streams
+# Value: 0-1, see IEEE Std 802.11-2016, 9.4.2.56.2.
+# -1 = Do not make any changes (default)
+# 0 = Set if not supported
+# 1 = Set if supported
+#
+# rx_stbc: Allow overriding STBC support for RX streams
+# Value: 0-3, see IEEE Std 802.11-2016, 9.4.2.56.2.
+# -1 = Do not make any changes (default)
+# 0 = Set if not supported
+# 1 = Set for support of one spatial stream
+# 2 = Set for support of one and two spatial streams
+# 3 = Set for support of one, two and three spatial streams
# disable_vht: Whether VHT should be disabled.
# 0 = VHT enabled (if AP supports it)
@@ -1396,6 +1441,13 @@
# 2: MCS 0-9
# 3: not supported
+# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality
+# 0 = normal STA (default)
+# 1 = backhaul STA
+# A backhaul STA sends the Multi-AP IE, fails to associate if the AP does not
+# support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be
+# added to a bridge to allow forwarding frames over this backhaul link.
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index abacaa9..9cb4ad3 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -451,10 +451,12 @@
struct wpa_bss_tmp_disallowed {
struct dl_list list;
u8 bssid[ETH_ALEN];
+ int rssi_threshold;
};
struct beacon_rep_data {
u8 token;
+ u8 last_indication;
struct wpa_driver_scan_params scan_params;
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
@@ -492,6 +494,10 @@
struct wpa_supplicant *next;
struct l2_packet_data *l2;
struct l2_packet_data *l2_br;
+ struct os_reltime roam_start;
+ struct os_reltime roam_time;
+ struct os_reltime session_start;
+ struct os_reltime session_length;
unsigned char own_addr[ETH_ALEN];
unsigned char perm_addr[ETH_ALEN];
char ifname[100];
@@ -814,6 +820,7 @@
unsigned int mesh_if_created:1;
unsigned int mesh_ht_enabled:1;
unsigned int mesh_vht_enabled:1;
+ struct wpa_driver_mesh_join_params *mesh_params;
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
/* struct external_pmksa_cache::list */
struct dl_list mesh_external_pmksa_cache;
@@ -911,6 +918,7 @@
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
unsigned int p2p_go_vht:1;
+ unsigned int p2p_go_he:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
unsigned int group_formation_reported:1;
@@ -1018,6 +1026,10 @@
/* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason;
+ /* WLAN_STATUS_* status codes from last received Authentication frame
+ * from the AP. */
+ u16 auth_status_code;
+
/* WLAN_STATUS_* status codes from (Re)Association Response frame. */
u16 assoc_status_code;
/* Indicates if the previous association request timed out. */
@@ -1061,6 +1073,7 @@
struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until;
u8 wnm_cand_from_bss[ETH_ALEN];
+ enum bss_trans_mgmt_status_code bss_tm_status;
struct wpabuf *coloc_intf_elems;
u8 coloc_intf_dialog_token;
u8 coloc_intf_auto_report;
@@ -1236,6 +1249,8 @@
unsigned int disable_fils:1;
#endif /* CONFIG_FILS */
unsigned int ieee80211ac:1;
+ unsigned int enabled_4addr_mode:1;
+ unsigned int multi_bss_support:1;
};
@@ -1371,6 +1386,8 @@
int add_oce_capa);
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
+ enum mbo_attr_id attr);
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
const char *non_pref_chan);
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
@@ -1393,8 +1410,9 @@
enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
u8 bw);
-size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
- size_t len);
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ int freq, u8 *pos, size_t len);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -1441,6 +1459,8 @@
struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid);
int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s,
+ struct channel_list_changed *info);
/* eap_register.c */
int eap_register_methods(void);
@@ -1493,8 +1513,10 @@
u16 num_modes, enum hostapd_hw_mode mode);
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
- unsigned int sec);
-int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+ unsigned int sec, int rssi_threshold);
+int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss);
+void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s);
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 4634ed7..449e04a 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -296,7 +296,7 @@
}
if (result != EAPOL_SUPP_RESULT_SUCCESS ||
- !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X))
return;
if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
@@ -1183,6 +1183,15 @@
os_free(hex);
}
+
+static int wpa_supplicant_channel_info(void *_wpa_s,
+ struct wpa_channel_info *ci)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+
+ return wpa_drv_channel_info(wpa_s, ci);
+}
+
#endif /* CONFIG_NO_WPA */
@@ -1233,6 +1242,7 @@
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx;
+ ctx->channel_info = wpa_supplicant_channel_info;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index d3d06b8..41477d5 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -92,6 +92,12 @@
}
+static int wpas_set_receive_lowest_pn(void *wpa_s, struct receive_sa *sa)
+{
+ return wpa_drv_set_receive_lowest_pn(wpa_s, sa);
+}
+
+
static unsigned int conf_offset_val(enum confidentiality_offset co)
{
switch (co) {
@@ -219,6 +225,7 @@
kay_ctx->get_receive_lowest_pn = wpas_get_receive_lowest_pn;
kay_ctx->get_transmit_next_pn = wpas_get_transmit_next_pn;
kay_ctx->set_transmit_next_pn = wpas_set_transmit_next_pn;
+ kay_ctx->set_receive_lowest_pn = wpas_set_receive_lowest_pn;
kay_ctx->create_receive_sc = wpas_create_receive_sc;
kay_ctx->delete_receive_sc = wpas_delete_receive_sc;
kay_ctx->create_receive_sa = wpas_create_receive_sa;
@@ -232,7 +239,8 @@
kay_ctx->enable_transmit_sa = wpas_enable_transmit_sa;
kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa;
- res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_port,
+ res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect,
+ ssid->macsec_replay_window, ssid->macsec_port,
ssid->mka_priority, wpa_s->ifname,
wpa_s->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
@@ -349,8 +357,8 @@
/* Derive CAK from MSK */
cak->len = DEFAULT_KEY_LEN;
- if (ieee802_1x_cak_128bits_aes_cmac(msk->key, wpa_s->own_addr,
- peer_addr, cak->key)) {
+ if (ieee802_1x_cak_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
+ peer_addr, cak->key, cak->len)) {
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Deriving CAK failed");
goto fail;
@@ -359,9 +367,8 @@
/* Derive CKN from MSK */
ckn->len = DEFAULT_CKN_LEN;
- if (ieee802_1x_ckn_128bits_aes_cmac(msk->key, wpa_s->own_addr,
- peer_addr, sid, sid_len,
- ckn->name)) {
+ if (ieee802_1x_ckn_aes_cmac(msk->key, msk->len, wpa_s->own_addr,
+ peer_addr, sid, sid_len, ckn->name)) {
wpa_printf(MSG_ERROR,
"IEEE 802.1X: Deriving CKN failed");
goto fail;
@@ -411,10 +418,10 @@
if (wpa_s->kay->policy == DO_NOT_SECURE)
goto dealloc;
- cak->len = MACSEC_CAK_LEN;
+ cak->len = ssid->mka_cak_len;
os_memcpy(cak->key, ssid->mka_cak, cak->len);
- ckn->len = MACSEC_CKN_LEN;
+ ckn->len = ssid->mka_ckn_len;
os_memcpy(ckn->name, ssid->mka_ckn, ckn->len);
res = ieee802_1x_kay_create_mka(wpa_s->kay, ckn, cak, 0, PSK, FALSE);