[automerger] Use BoringSSL to get random bytes am: 06eaa1c9cf
Change-Id: I726b1c08ccb1d06e972ba2e47c9a6256eeb0b386
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index 76600bc..1dc7547 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -140,7 +140,7 @@
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, 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 7efce0d..945bdc0 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/README b/README
index 9685f58..43b684c 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, 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 67ca129..d9c4b97 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -27,6 +27,9 @@
# Disable unused parameter warnings
L_CFLAGS += -Wno-unused-parameter
+# Disable macro redefined warnings
+L_CFLAGS += -Wno-macro-redefined
+
# Set Android extended P2P functionality
L_CFLAGS += -DANDROID_P2P
@@ -38,6 +41,9 @@
L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/hostapd\"
+# Use Android specific directory for hostapd_cli command completion history
+L_CFLAGS += -DCONFIG_HOSTAPD_CLI_HISTORY_DIR=\"/data/misc/wifi\"
+
# To force sizeof(enum) = 4
ifeq ($(TARGET_ARCH),arm)
L_CFLAGS += -mabi=aapcs-linux
@@ -96,6 +102,8 @@
OBJS += src/ap/ieee802_11_shared.c
OBJS += src/ap/beacon.c
OBJS += src/ap/bss_load.c
+OBJS += src/ap/neighbor_db.c
+OBJS += src/ap/rrm.c
OBJS_d =
OBJS_p =
LIBS =
@@ -147,7 +155,6 @@
OBJS += src/eapol_auth/eapol_auth_sm.c
-
ifndef CONFIG_NO_DUMP_STATE
# define HOSTAPD_DUMP_STATE to include support for dumping internal state
# through control interface commands (undefine it, if you want to save in
@@ -242,7 +249,7 @@
endif
ifdef CONFIG_IEEE80211R
-L_CFLAGS += -DCONFIG_IEEE80211R
+L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += src/ap/wpa_auth_ft.c
NEED_SHA256=y
NEED_AES_OMAC1=y
@@ -256,6 +263,13 @@
NEED_DH_GROUPS=y
endif
+ifdef CONFIG_FILS
+L_CFLAGS += -DCONFIG_FILS
+OBJS += src/ap/fils_hlp.c
+NEED_SHA384=y
+NEED_AES_SIV=y
+endif
+
ifdef CONFIG_WNM
L_CFLAGS += -DCONFIG_WNM
OBJS += src/ap/wnm_ap.c
@@ -269,6 +283,10 @@
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211AX
+L_CFLAGS += -DCONFIG_IEEE80211AX
+endif
+
ifdef CONFIG_MBO
L_CFLAGS += -DCONFIG_MBO
OBJS += src/ap/mbo_ap.c
@@ -735,6 +753,9 @@
AESOBJS += src/crypto/aes-cbc.c
endif
endif
+ifdef NEED_AES_SIV
+AESOBJS += src/crypto/aes-siv.c
+endif
ifdef NEED_AES_DEC
ifdef CONFIG_INTERNAL_AES
AESOBJS += src/crypto/aes-internal-dec.c
@@ -821,6 +842,9 @@
endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/sha384.c
+endif
OBJS += src/crypto/sha384-prf.c
endif
@@ -895,6 +919,10 @@
OBJS += src/ap/ieee802_11_vht.c
endif
+ifdef CONFIG_IEEE80211AX
+OBJS += src/ap/ieee802_11_he.c
+endif
+
ifdef CONFIG_P2P_MANAGER
L_CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += src/ap/p2p_hostapd.c
@@ -933,6 +961,10 @@
L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
endif
+ifdef CONFIG_DEBUG_SYSLOG
+L_CFLAGS += -DCONFIG_DEBUG_SYSLOG
+endif
+
ifdef CONFIG_DEBUG_LINUX_TRACING
L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
endif
@@ -945,7 +977,10 @@
L_CFLAGS += -DCONFIG_ANDROID_LOG
endif
-OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+OBJS_c = hostapd_cli.c
+OBJS_c += src/common/wpa_ctrl.c
+OBJS_c += src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/common/cli.c
OBJS_c += src/utils/eloop.c
OBJS_c += src/utils/common.c
ifdef CONFIG_WPA_TRACE
@@ -963,6 +998,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := hostapd_cli
LOCAL_MODULE_TAGS := debug
+LOCAL_PROPRIETARY_MODULE := true
LOCAL_SHARED_LIBRARIES := libc libcutils liblog
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS_c)
@@ -973,6 +1009,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := hostapd
LOCAL_MODULE_TAGS := optional
+LOCAL_PROPRIETARY_MODULE := true
ifdef CONFIG_DRIVER_CUSTOM
LOCAL_STATIC_LIBRARIES := libCustomWifi
endif
@@ -990,6 +1027,7 @@
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS)
LOCAL_C_INCLUDES := $(INCLUDES)
+LOCAL_INIT_RC := hostapd.android.rc
include $(BUILD_EXECUTABLE)
endif # ifeq ($(WPA_BUILD_HOSTAPD),true)
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index af54e1e..d2b669b 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,78 @@
ChangeLog for hostapd
+2016-10-02 - v2.6
+ * fixed EAP-pwd last fragment validation
+ [http://w1.fi/security/2015-7/] (CVE-2015-5314)
+ * fixed WPS configuration update vulnerability with malformed passphrase
+ [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+ * extended channel switch support for VHT bandwidth changes
+ * added support for configuring new ANQP-elements with
+ anqp_elem=<InfoID>:<hexdump of payload>
+ * fixed Suite B 192-bit AKM to use proper PMK length
+ (note: this makes old releases incompatible with the fixed behavior)
+ * added no_probe_resp_if_max_sta=1 parameter to disable Probe Response
+ frame sending for not-associated STAs if max_num_sta limit has been
+ reached
+ * added option (-S as command line argument) to request all interfaces
+ to be started at the same time
+ * modified rts_threshold and fragm_threshold configuration parameters
+ to allow -1 to be used to disable RTS/fragmentation
+ * EAP-pwd: added support for Brainpool Elliptic Curves
+ (with OpenSSL 1.0.2 and newer)
+ * fixed EAPOL reauthentication after FT protocol run
+ * fixed FTIE generation for 4-way handshake after FT protocol run
+ * fixed and improved various FST operations
+ * TLS server
+ - support SHA384 and SHA512 hashes
+ - support TLS v1.2 signature algorithm with SHA384 and SHA512
+ - support PKCS #5 v2.0 PBES2
+ - support PKCS #5 with PKCS #12 style key decryption
+ - minimal support for PKCS #12
+ - support OCSP stapling (including ocsp_multi)
+ * added support for OpenSSL 1.1 API changes
+ - drop support for OpenSSL 0.9.8
+ - drop support for OpenSSL 1.0.0
+ * EAP-PEAP: support fast-connect crypto binding
+ * RADIUS
+ - fix Called-Station-Id to not escape SSID
+ - add Event-Timestamp to all Accounting-Request packets
+ - add Acct-Session-Id to Accounting-On/Off
+ - add Acct-Multi-Session-Id ton Access-Request packets
+ - add Service-Type (= Frames)
+ - allow server to provide PSK instead of passphrase for WPA-PSK
+ Tunnel_password case
+ - update full message for interim accounting updates
+ - add Acct-Delay-Time into Accounting messages
+ - add require_message_authenticator configuration option to require
+ CoA/Disconnect-Request packets to be authenticated
+ * started to postpone WNM-Notification frame sending by 100 ms so that
+ the STA has some more time to configure the key before this frame is
+ received after the 4-way handshake
+ * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+ * extended VLAN support (per-STA vif, etc.)
+ * fixed PMKID derivation with SAE
+ * nl80211
+ - added support for full station state operations
+ - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+ unencrypted EAPOL frames
+ * added initial MBO support; number of extensions to WNM BSS Transition
+ Management
+ * added initial functionality for location related operations
+ * added assocresp_elements parameter to allow vendor specific elements
+ to be added into (Re)Association Response frames
+ * improved Public Action frame addressing
+ - use Address 3 = wildcard BSSID in GAS response if a query from an
+ unassociated STA used that address
+ - fix TX status processing for Address 3 = wildcard BSSID
+ - add gas_address3 configuration parameter to control Address 3
+ behavior
+ * added command line parameter -i to override interface parameter in
+ hostapd.conf
+ * added command completion support to hostapd_cli
+ * added passive client taxonomy determination (CONFIG_TAXONOMY=y
+ compile option and "SIGNATURE <addr>" control interface command)
+ * number of small fixes
+
2015-09-27 - v2.5
* fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
[http://w1.fi/security/2015-2/] (CVE-2015-4141)
diff --git a/hostapd/CleanSpec.mk b/hostapd/CleanSpec.mk
new file mode 100644
index 0000000..653aebb
--- /dev/null
+++ b/hostapd/CleanSpec.mk
@@ -0,0 +1,52 @@
+# -*- mode: makefile -*-
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(OUT_DIR)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+#
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/obj/SHARED_LIBRARIES/libdvm*)
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/hostapd)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/hostapd_cli)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index fa4af82..3160d0d 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -84,8 +84,13 @@
OBJS += ../src/ap/ieee802_11_shared.o
OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/bss_load.o
+OBJS += ../src/ap/neighbor_db.o
+OBJS += ../src/ap/rrm.o
-OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+OBJS_c = hostapd_cli.o
+OBJS_c += ../src/common/wpa_ctrl.o
+OBJS_c += ../src/utils/os_$(CONFIG_OS).o
+OBJS_c += ../src/common/cli.o
NEED_RC4=y
NEED_AES=y
@@ -95,6 +100,11 @@
OBJS += ../src/drivers/drivers.o
CFLAGS += -DHOSTAPD
+ifdef CONFIG_TAXONOMY
+CFLAGS += -DCONFIG_TAXONOMY
+OBJS += ../src/ap/taxonomy.o
+endif
+
ifdef CONFIG_MODULE_TESTS
CFLAGS += -DCONFIG_MODULE_TESTS
OBJS += hapd_module_tests.o
@@ -280,7 +290,7 @@
endif
ifdef CONFIG_IEEE80211R
-CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP
OBJS += ../src/ap/wpa_auth_ft.o
NEED_SHA256=y
NEED_AES_OMAC1=y
@@ -295,6 +305,13 @@
NEED_AP_MLME=y
endif
+ifdef CONFIG_FILS
+CFLAGS += -DCONFIG_FILS
+OBJS += ../src/ap/fils_hlp.o
+NEED_SHA384=y
+NEED_AES_SIV=y
+endif
+
ifdef CONFIG_WNM
CFLAGS += -DCONFIG_WNM
OBJS += ../src/ap/wnm_ap.o
@@ -308,6 +325,11 @@
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211AX
+CFLAGS += -DCONFIG_IEEE80211AX
+OBJS += ../src/ap/ieee802_11_he.o
+endif
+
ifdef CONFIG_MBO
CFLAGS += -DCONFIG_MBO
OBJS += ../src/ap/mbo_ap.o
@@ -767,6 +789,9 @@
AESOBJS += ../src/crypto/aes-cbc.o
endif
endif
+ifdef NEED_AES_SIV
+AESOBJS += ../src/crypto/aes-siv.o
+endif
ifdef NEED_AES_DEC
ifdef CONFIG_INTERNAL_AES
AESOBJS += ../src/crypto/aes-internal-dec.o
@@ -855,6 +880,9 @@
endif
ifdef NEED_SHA384
CFLAGS += -DCONFIG_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/sha384.o
+endif
OBJS += ../src/crypto/sha384-prf.o
endif
@@ -973,6 +1001,10 @@
CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
endif
+ifdef CONFIG_DEBUG_SYSLOG
+CFLAGS += -DCONFIG_DEBUG_SYSLOG
+endif
+
ifdef CONFIG_DEBUG_LINUX_TRACING
CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
endif
diff --git a/hostapd/README b/hostapd/README
index 5d5fd36..cb37c8e 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2017, 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 e382c40..1715cc8 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -199,3 +199,6 @@
# These extentions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
+
+# Include internal line edit mode in hostapd_cli.
+CONFIG_WPA_CLI_EDIT=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index c35d5ae..9e95440 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -129,9 +129,6 @@
struct mac_acl_entry *newacl;
int vlan_id;
- if (!fname)
- return 0;
-
f = fopen(fname, "r");
if (!f) {
wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
@@ -208,7 +205,8 @@
fclose(f);
- qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+ if (*acl)
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
return 0;
}
@@ -223,9 +221,6 @@
int line = 0, ret = 0, num_methods;
struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
- if (!fname)
- return 0;
-
if (os_strncmp(fname, "sqlite:", 7) == 0) {
#ifdef CONFIG_SQLITE
os_free(conf->eap_user_sqlite);
@@ -522,15 +517,10 @@
fclose(f);
if (ret == 0) {
- user = conf->eap_user;
- while (user) {
- struct hostapd_eap_user *prev;
-
- prev = user;
- user = user->next;
- hostapd_config_free_eap_user(prev);
- }
+ hostapd_config_free_eap_users(conf->eap_user);
conf->eap_user = new_user;
+ } else {
+ hostapd_config_free_eap_users(new_user);
}
return ret;
@@ -636,8 +626,7 @@
}
-static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
- const char *val)
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
{
char *secret;
@@ -645,7 +634,7 @@
if (secret == NULL)
return -1;
- secret++;
+ *secret++ = '\0';
if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
return -1;
@@ -685,12 +674,12 @@
val |= WPA_KEY_MGMT_PSK;
else if (os_strcmp(start, "WPA-EAP") == 0)
val |= WPA_KEY_MGMT_IEEE8021X;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
else if (os_strcmp(start, "FT-PSK") == 0)
val |= WPA_KEY_MGMT_FT_PSK;
else if (os_strcmp(start, "FT-EAP") == 0)
val |= WPA_KEY_MGMT_FT_IEEE8021X;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
val |= WPA_KEY_MGMT_PSK_SHA256;
@@ -711,6 +700,18 @@
else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ else if (os_strcmp(start, "FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA256;
+ else if (os_strcmp(start, "FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA384;
+#ifdef CONFIG_IEEE80211R_AP
+ else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA256;
+ else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA384;
+#endif /* CONFIG_IEEE80211R_AP */
+#endif /* CONFIG_FILS */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -756,7 +757,25 @@
{
size_t len = os_strlen(val);
- if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+ if (keyidx < 0 || keyidx > 3)
+ return -1;
+
+ if (len == 0) {
+ int i, set = 0;
+
+ bin_clear_free(wep->key[keyidx], wep->len[keyidx]);
+ wep->key[keyidx] = NULL;
+ wep->len[keyidx] = 0;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (wep->key[i])
+ set++;
+ }
+ if (!set)
+ wep->keys_set = 0;
+ return 0;
+ }
+
+ if (wep->key[keyidx] != NULL)
return -1;
if (val[0] == '"') {
@@ -979,7 +998,7 @@
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static int add_r0kh(struct hostapd_bss_config *bss, char *value)
{
struct ft_remote_r0kh *r0kh;
@@ -1069,7 +1088,7 @@
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
@@ -1920,31 +1939,6 @@
#endif /* CONFIG_HS20 */
-#ifdef CONFIG_WPS_NFC
-static struct wpabuf * hostapd_parse_bin(const char *buf)
-{
- size_t len;
- struct wpabuf *ret;
-
- len = os_strlen(buf);
- if (len & 0x01)
- return NULL;
- len /= 2;
-
- ret = wpabuf_alloc(len);
- if (ret == NULL)
- return NULL;
-
- if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
- wpabuf_free(ret);
- return NULL;
- }
-
- return ret;
-}
-#endif /* CONFIG_WPS_NFC */
-
-
#ifdef CONFIG_ACS
static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
char *pos)
@@ -1987,6 +1981,54 @@
#endif /* CONFIG_ACS */
+static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf,
+ const char *val)
+{
+ struct wpabuf *elems;
+
+ if (val[0] == '\0') {
+ wpabuf_free(*buf);
+ *buf = NULL;
+ return 0;
+ }
+
+ elems = wpabuf_parse_bin(val);
+ if (!elems) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
+ line, name, val);
+ return -1;
+ }
+
+ wpabuf_free(*buf);
+ *buf = elems;
+
+ return 0;
+}
+
+
+#ifdef CONFIG_FILS
+static int parse_fils_realm(struct hostapd_bss_config *bss, const char *val)
+{
+ struct fils_realm *realm;
+ size_t len;
+
+ len = os_strlen(val);
+ realm = os_zalloc(sizeof(*realm) + len + 1);
+ if (!realm)
+ return -1;
+
+ os_memcpy(realm->realm, val, len);
+ if (fils_domain_name_hash(val, realm->hash) < 0) {
+ os_free(realm);
+ return -1;
+ }
+ dl_list_add_tail(&bss->fils_realms, &realm->list);
+
+ return 0;
+}
+#endif /* CONFIG_FILS */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -2002,20 +2044,21 @@
os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge));
} else if (os_strcmp(buf, "driver") == 0) {
int j;
- /* clear to get error below if setting is invalid */
- conf->driver = NULL;
+ const struct wpa_driver_ops *driver = NULL;
+
for (j = 0; wpa_drivers[j]; j++) {
if (os_strcmp(pos, wpa_drivers[j]->name) == 0) {
- conf->driver = wpa_drivers[j];
+ driver = wpa_drivers[j];
break;
}
}
- if (conf->driver == NULL) {
+ if (!driver) {
wpa_printf(MSG_ERROR,
"Line %d: invalid/unknown driver '%s'",
line, pos);
return 1;
}
+ conf->driver = driver;
} else if (os_strcmp(buf, "driver_params") == 0) {
os_free(conf->driver_params);
conf->driver_params = os_strdup(pos);
@@ -2059,13 +2102,16 @@
} else if (os_strcmp(buf, "utf8_ssid") == 0) {
bss->ssid.utf8_ssid = atoi(pos) > 0;
} else if (os_strcmp(buf, "macaddr_acl") == 0) {
- bss->macaddr_acl = atoi(pos);
- if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
- bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
- bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ enum macaddr_acl acl = atoi(pos);
+
+ if (acl != ACCEPT_UNLESS_DENIED &&
+ acl != DENY_UNLESS_ACCEPTED &&
+ acl != USE_EXTERNAL_RADIUS_AUTH) {
wpa_printf(MSG_ERROR, "Line %d: unknown macaddr_acl %d",
- line, bss->macaddr_acl);
+ line, acl);
+ return 1;
}
+ bss->macaddr_acl = acl;
} else if (os_strcmp(buf, "accept_mac_file") == 0) {
if (hostapd_config_read_maclist(pos, &bss->accept_mac,
&bss->num_accept_mac)) {
@@ -2101,13 +2147,15 @@
} else if (os_strcmp(buf, "ieee8021x") == 0) {
bss->ieee802_1x = atoi(pos);
} else if (os_strcmp(buf, "eapol_version") == 0) {
- bss->eapol_version = atoi(pos);
- if (bss->eapol_version < 1 || bss->eapol_version > 2) {
+ int eapol_version = atoi(pos);
+
+ if (eapol_version < 1 || eapol_version > 2) {
wpa_printf(MSG_ERROR,
"Line %d: invalid EAPOL version (%d): '%s'.",
- line, bss->eapol_version, pos);
+ line, eapol_version, pos);
return 1;
}
+ bss->eapol_version = eapol_version;
wpa_printf(MSG_DEBUG, "eapol_version=%d", bss->eapol_version);
#ifdef EAP_SERVER
} else if (os_strcmp(buf, "eap_authenticator") == 0) {
@@ -2235,24 +2283,25 @@
os_free(bss->erp_domain);
bss->erp_domain = os_strdup(pos);
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
- bss->default_wep_key_len = atoi(pos);
- if (bss->default_wep_key_len > 13) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %lu (= %lu bits)",
- line,
- (unsigned long) bss->default_wep_key_len,
- (unsigned long)
- bss->default_wep_key_len * 8);
+ int val = atoi(pos);
+
+ if (val < 0 || val > 13) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid WEP key len %d (= %d bits)",
+ line, val, val * 8);
return 1;
}
+ bss->default_wep_key_len = val;
} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
- bss->individual_wep_key_len = atoi(pos);
- if (bss->individual_wep_key_len < 0 ||
- bss->individual_wep_key_len > 13) {
- wpa_printf(MSG_ERROR, "Line %d: invalid WEP key len %d (= %d bits)",
- line, bss->individual_wep_key_len,
- bss->individual_wep_key_len * 8);
+ int val = atoi(pos);
+
+ if (val < 0 || val > 13) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid WEP key len %d (= %d bits)",
+ line, val, val * 8);
return 1;
}
+ bss->individual_wep_key_len = val;
} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
bss->wep_rekeying_period = atoi(pos);
if (bss->wep_rekeying_period < 0) {
@@ -2411,6 +2460,9 @@
bss->radius_das_time_window = atoi(pos);
} else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
bss->radius_das_require_event_timestamp = atoi(pos);
+ } else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
+ 0) {
+ bss->radius_das_require_message_authenticator = atoi(pos);
#endif /* CONFIG_NO_RADIUS */
} else if (os_strcmp(buf, "auth_algs") == 0) {
bss->auth_algs = atoi(pos);
@@ -2437,6 +2489,28 @@
bss->wpa_gmk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
bss->wpa_ptk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_group_update_count") == 0) {
+ char *endp;
+ unsigned long val = strtoul(pos, &endp, 0);
+
+ if (*endp || val < 1 || val > (u32) -1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wpa_group_update_count=%lu; allowed range 1..4294967295",
+ line, val);
+ return 1;
+ }
+ bss->wpa_group_update_count = (u32) val;
+ } else if (os_strcmp(buf, "wpa_pairwise_update_count") == 0) {
+ char *endp;
+ unsigned long val = strtoul(pos, &endp, 0);
+
+ if (*endp || val < 1 || val > (u32) -1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid wpa_pairwise_update_count=%lu; allowed range 1..4294967295",
+ line, val);
+ return 1;
+ }
+ bss->wpa_pairwise_update_count = (u32) val;
} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
int len = os_strlen(pos);
if (len < 8 || len > 63) {
@@ -2519,7 +2593,7 @@
} else if (os_strcmp(buf, "peerkey") == 0) {
bss->peerkey = atoi(pos);
#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
} else if (os_strcmp(buf, "mobility_domain") == 0) {
if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
hexstr2bin(pos, bss->mobility_domain,
@@ -2557,7 +2631,9 @@
bss->pmk_r1_push = atoi(pos);
} else if (os_strcmp(buf, "ft_over_ds") == 0) {
bss->ft_over_ds = atoi(pos);
-#endif /* CONFIG_IEEE80211R */
+ } else if (os_strcmp(buf, "ft_psk_generate_local") == 0) {
+ bss->ft_psk_generate_local = atoi(pos);
+#endif /* CONFIG_IEEE80211R_AP */
#ifndef CONFIG_NO_CTRL_IFACE
} else if (os_strcmp(buf, "ctrl_interface") == 0) {
os_free(bss->ctrl_interface);
@@ -2685,12 +2761,14 @@
}
#endif /* CONFIG_ACS */
} else if (os_strcmp(buf, "dtim_period") == 0) {
- bss->dtim_period = atoi(pos);
- if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+ int val = atoi(pos);
+
+ if (val < 1 || val > 255) {
wpa_printf(MSG_ERROR, "Line %d: invalid dtim_period %d",
- line, bss->dtim_period);
+ line, val);
return 1;
}
+ bss->dtim_period = val;
} else if (os_strcmp(buf, "bss_load_update_period") == 0) {
bss->bss_load_update_period = atoi(pos);
if (bss->bss_load_update_period < 0 ||
@@ -2739,6 +2817,40 @@
line);
return 1;
}
+ } else if (os_strcmp(buf, "beacon_rate") == 0) {
+ int val;
+
+ if (os_strncmp(pos, "ht:", 3) == 0) {
+ val = atoi(pos + 3);
+ if (val < 0 || val > 31) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate HT-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_HT;
+ conf->beacon_rate = val;
+ } else if (os_strncmp(pos, "vht:", 4) == 0) {
+ val = atoi(pos + 4);
+ if (val < 0 || val > 9) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate VHT-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_VHT;
+ conf->beacon_rate = val;
+ } else {
+ val = atoi(pos);
+ if (val < 10 || val > 10000) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid legacy beacon_rate %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_LEGACY;
+ conf->beacon_rate = val;
+ }
} else if (os_strcmp(buf, "preamble") == 0) {
if (atoi(pos))
conf->preamble = SHORT_PREAMBLE;
@@ -2893,7 +3005,27 @@
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
} else if (os_strcmp(buf, "vendor_vht") == 0) {
bss->vendor_vht = atoi(pos);
+ } else if (os_strcmp(buf, "use_sta_nsts") == 0) {
+ bss->use_sta_nsts = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ } else if (os_strcmp(buf, "ieee80211ax") == 0) {
+ conf->ieee80211ax = atoi(pos);
+ } else if (os_strcmp(buf, "he_su_beamformer") == 0) {
+ conf->he_phy_capab.he_su_beamformer = atoi(pos);
+ } else if (os_strcmp(buf, "he_su_beamformee") == 0) {
+ conf->he_phy_capab.he_su_beamformee = atoi(pos);
+ } else if (os_strcmp(buf, "he_mu_beamformer") == 0) {
+ conf->he_phy_capab.he_mu_beamformer = atoi(pos);
+ } else if (os_strcmp(buf, "he_bss_color") == 0) {
+ conf->he_op.he_bss_color = atoi(pos);
+ } else if (os_strcmp(buf, "he_default_pe_duration") == 0) {
+ conf->he_op.he_default_pe_duration = atoi(pos);
+ } else if (os_strcmp(buf, "he_twt_required") == 0) {
+ 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);
+#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
@@ -3031,15 +3163,15 @@
bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
wpabuf_free(bss->wps_nfc_dh_pubkey);
- bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_dh_pubkey = wpabuf_parse_bin(pos);
bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
wpabuf_free(bss->wps_nfc_dh_privkey);
- bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_dh_privkey = wpabuf_parse_bin(pos);
bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
wpabuf_free(bss->wps_nfc_dev_pw);
- bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+ bss->wps_nfc_dev_pw = wpabuf_parse_bin(pos);
bss->wps_nfc_pw_from_config = 1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
@@ -3206,7 +3338,15 @@
if (parse_anqp_elem(bss, pos, line) < 0)
return 1;
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
- bss->gas_frag_limit = atoi(pos);
+ int val = atoi(pos);
+
+ if (val <= 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid gas_frag_limit '%s'",
+ line, pos);
+ return 1;
+ }
+ bss->gas_frag_limit = val;
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
bss->gas_comeback_delay = atoi(pos);
} else if (os_strcmp(buf, "qos_map_set") == 0) {
@@ -3346,7 +3486,15 @@
WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
bss->bss_load_test_set = 1;
} else if (os_strcmp(buf, "radio_measurements") == 0) {
- bss->radio_measurements = atoi(pos);
+ /*
+ * DEPRECATED: This parameter will be removed in the future.
+ * Use rrm_neighbor_report instead.
+ */
+ int val = atoi(pos);
+
+ if (val & BIT(0))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
} else if (os_strcmp(buf, "own_ie_override") == 0) {
struct wpabuf *tmp;
size_t len = os_strlen(pos) / 2;
@@ -3367,35 +3515,11 @@
bss->own_ie_override = tmp;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strcmp(buf, "vendor_elements") == 0) {
- struct wpabuf *elems;
- size_t len = os_strlen(pos);
- if (len & 0x01) {
- wpa_printf(MSG_ERROR,
- "Line %d: Invalid vendor_elements '%s'",
- line, pos);
+ if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
return 1;
- }
- len /= 2;
- if (len == 0) {
- wpabuf_free(bss->vendor_elements);
- bss->vendor_elements = NULL;
- return 0;
- }
-
- elems = wpabuf_alloc(len);
- if (elems == NULL)
+ } else if (os_strcmp(buf, "assocresp_elements") == 0) {
+ if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
return 1;
-
- if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
- wpabuf_free(elems);
- wpa_printf(MSG_ERROR,
- "Line %d: Invalid vendor_elements '%s'",
- line, pos);
- return 1;
- }
-
- wpabuf_free(bss->vendor_elements);
- bss->vendor_elements = elems;
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
bss->sae_anti_clogging_threshold = atoi(pos);
} else if (os_strcmp(buf, "sae_groups") == 0) {
@@ -3487,6 +3611,68 @@
} else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
os_free(bss->no_auth_if_seen_on);
bss->no_auth_if_seen_on = os_strdup(pos);
+ } else if (os_strcmp(buf, "lci") == 0) {
+ wpabuf_free(conf->lci);
+ conf->lci = wpabuf_parse_bin(pos);
+ if (conf->lci && wpabuf_len(conf->lci) == 0) {
+ wpabuf_free(conf->lci);
+ conf->lci = NULL;
+ }
+ } else if (os_strcmp(buf, "civic") == 0) {
+ wpabuf_free(conf->civic);
+ conf->civic = wpabuf_parse_bin(pos);
+ if (conf->civic && wpabuf_len(conf->civic) == 0) {
+ wpabuf_free(conf->civic);
+ conf->civic = NULL;
+ }
+ } else if (os_strcmp(buf, "rrm_neighbor_report") == 0) {
+ if (atoi(pos))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+ } else if (os_strcmp(buf, "rrm_beacon_report") == 0) {
+ if (atoi(pos))
+ bss->radio_measurements[0] |=
+ WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+ } else if (os_strcmp(buf, "gas_address3") == 0) {
+ bss->gas_address3 = atoi(pos);
+ } else if (os_strcmp(buf, "stationary_ap") == 0) {
+ conf->stationary_ap = atoi(pos);
+ } else if (os_strcmp(buf, "ftm_responder") == 0) {
+ bss->ftm_responder = atoi(pos);
+ } else if (os_strcmp(buf, "ftm_initiator") == 0) {
+ bss->ftm_initiator = atoi(pos);
+#ifdef CONFIG_FILS
+ } else if (os_strcmp(buf, "fils_cache_id") == 0) {
+ if (hexstr2bin(pos, bss->fils_cache_id, FILS_CACHE_ID_LEN)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid fils_cache_id '%s'",
+ line, pos);
+ return 1;
+ }
+ bss->fils_cache_id_set = 1;
+ } else if (os_strcmp(buf, "fils_realm") == 0) {
+ if (parse_fils_realm(bss, pos) < 0)
+ return 1;
+ } else if (os_strcmp(buf, "dhcp_server") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->dhcp_server)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "dhcp_rapid_commit_proxy") == 0) {
+ bss->dhcp_rapid_commit_proxy = atoi(pos);
+ } else if (os_strcmp(buf, "fils_hlp_wait_time") == 0) {
+ bss->fils_hlp_wait_time = atoi(pos);
+ } else if (os_strcmp(buf, "dhcp_server_port") == 0) {
+ bss->dhcp_server_port = atoi(pos);
+ } else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
+ bss->dhcp_relay_port = atoi(pos);
+#endif /* CONFIG_FILS */
+ } else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
+ bss->multicast_to_unicast = 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 a87f117..62feaa4 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -25,6 +25,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/module_tests.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
#include "common/ctrl_iface_common.h"
@@ -47,6 +48,8 @@
#include "ap/wnm_ap.h"
#include "ap/wpa_auth.h"
#include "ap/beacon.h"
+#include "ap/neighbor_db.h"
+#include "ap/rrm.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "fst/fst_ctrl_iface.h"
@@ -1014,14 +1017,16 @@
if (ret != 3) {
wpa_printf(MSG_DEBUG,
"MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
- return -1;
+ ret = -1;
+ goto fail;
}
if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
wpa_printf(MSG_DEBUG,
"Invalid MBO transition reason code %u",
mbo_reason);
- return -1;
+ ret = -1;
+ goto fail;
}
/* Valid values for Cellular preference are: 0, 1, 255 */
@@ -1029,7 +1034,8 @@
wpa_printf(MSG_DEBUG,
"Invalid MBO cellular capability %u",
cell_pref);
- return -1;
+ ret = -1;
+ goto fail;
}
if (reassoc_delay > 65535 ||
@@ -1037,7 +1043,8 @@
!(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
wpa_printf(MSG_DEBUG,
"MBO: Assoc retry delay is only valid in disassoc imminent mode");
- return -1;
+ ret = -1;
+ goto fail;
}
*mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
@@ -1063,6 +1070,9 @@
nei_pos > nei_rep ? nei_rep : NULL,
nei_pos - nei_rep, mbo_len ? mbo : NULL,
mbo_len);
+#ifdef CONFIG_MBO
+fail:
+#endif /* CONFIG_MBO */
os_free(url);
return ret;
}
@@ -1093,7 +1103,7 @@
return pos - buf;
pos += ret;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "FT-PSK ");
if (os_snprintf_error(end - pos, ret))
@@ -1114,7 +1124,21 @@
pos += ret;
}
#endif /* CONFIG_SAE */
-#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_FILS
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "FT-FILS-SHA256 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "FT-FILS-SHA384 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
@@ -1151,6 +1175,20 @@
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_FILS
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "FILS-SHA256 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "FILS-SHA384 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
if (pos > buf && *(pos - 1) == ' ') {
*(pos - 1) = '\0';
@@ -1316,14 +1354,6 @@
wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
wps_corrupt_pkhash);
#endif /* CONFIG_WPS_TESTING */
-#ifdef CONFIG_INTERWORKING
- } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
- int val = atoi(value);
- if (val <= 0)
- ret = -1;
- else
- hapd->gas_frag_limit = val;
-#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
hapd->ext_mgmt_frame_handling = atoi(value);
@@ -1531,6 +1561,76 @@
}
+static int hostapd_ctrl_iface_mgmt_rx_process(struct hostapd_data *hapd,
+ char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf;
+ int freq = 0, datarate = 0, ssi_signal = 0;
+ union wpa_event_data event;
+
+ if (!hapd->ext_mgmt_frame_handling)
+ return -1;
+
+ /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+ pos = cmd;
+ param = os_strstr(pos, "freq=");
+ if (param) {
+ param += 5;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " datarate=");
+ if (param) {
+ param += 10;
+ datarate = atoi(param);
+ }
+
+ param = os_strstr(pos, " ssi_signal=");
+ if (param) {
+ param += 12;
+ ssi_signal = atoi(param);
+ }
+
+ param = os_strstr(pos, " frame=");
+ if (param == NULL)
+ return -1;
+ param += 7;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.freq = freq;
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.datarate = datarate;
+ hapd->ext_mgmt_frame_handling = 0;
+ wpa_supplicant_event(hapd, EVENT_RX_MGMT, &event);
+ hapd->ext_mgmt_frame_handling = 1;
+
+ os_free(buf);
+
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
{
char *pos;
@@ -1588,8 +1688,8 @@
#define HWSIM_PACKETLEN 1500
#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
-void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
+static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct hostapd_data *hapd = ctx;
const struct ether_header *eth;
@@ -1776,8 +1876,6 @@
static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
char *pos;
wpa_trace_fail_after = atoi(cmd);
@@ -1801,9 +1899,6 @@
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
wpa_trace_fail_func);
#else /* WPA_TRACE_BFD */
@@ -1815,8 +1910,6 @@
static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
char *pos;
wpa_trace_test_fail_after = atoi(cmd);
@@ -1840,9 +1933,6 @@
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
wpa_trace_test_fail_func);
#else /* WPA_TRACE_BFD */
@@ -2047,6 +2137,9 @@
struct hostapd_sta_info *info;
struct os_reltime now;
+ if (!iface->num_sta_seen)
+ return 0;
+
sta_track_expire(iface, 0);
pos = buf;
@@ -2059,8 +2152,9 @@
int ret;
os_reltime_sub(&now, &info->last_seen, &age);
- ret = os_snprintf(pos, end - pos, MACSTR " %u\n",
- MAC2STR(info->addr), (unsigned int) age.sec);
+ ret = os_snprintf(pos, end - pos, MACSTR " %u %d\n",
+ MAC2STR(info->addr), (unsigned int) age.sec,
+ info->ssi_signal);
if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
@@ -2071,6 +2165,272 @@
#endif /* NEED_AP_MLME */
+static int hostapd_ctrl_iface_req_lci(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_INFO, "CTRL: REQ_LCI: Invalid MAC address");
+ return -1;
+ }
+
+ return hostapd_send_lci_req(hapd, addr);
+}
+
+
+static int hostapd_ctrl_iface_req_range(struct hostapd_data *hapd, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ char *token, *context = NULL;
+ int random_interval, min_ap;
+ u8 responders[ETH_ALEN * RRM_RANGE_REQ_MAX_RESPONDERS];
+ unsigned int n_responders;
+
+ token = str_token(cmd, " ", &context);
+ if (!token || hwaddr_aton(token, addr)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - Bad destination address");
+ return -1;
+ }
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ random_interval = atoi(token);
+ if (random_interval < 0 || random_interval > 0xffff)
+ return -1;
+
+ token = str_token(cmd, " ", &context);
+ if (!token)
+ return -1;
+
+ min_ap = atoi(token);
+ if (min_ap <= 0 || min_ap > WLAN_RRM_RANGE_REQ_MAX_MIN_AP)
+ return -1;
+
+ n_responders = 0;
+ while ((token = str_token(cmd, " ", &context))) {
+ if (n_responders == RRM_RANGE_REQ_MAX_RESPONDERS) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Too many responders");
+ return -1;
+ }
+
+ if (hwaddr_aton(token, responders + n_responders * ETH_ALEN)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE: Bad responder address");
+ return -1;
+ }
+
+ n_responders++;
+ }
+
+ if (!n_responders) {
+ wpa_printf(MSG_INFO,
+ "CTRL: REQ_RANGE - No FTM responder address");
+ return -1;
+ }
+
+ return hostapd_send_range_req(hapd, addr, random_interval, min_ap,
+ responders, n_responders);
+}
+
+
+static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd,
+ const char *cmd, char *reply,
+ size_t reply_size)
+{
+ u8 addr[ETH_ALEN];
+ const char *pos;
+ struct wpabuf *req;
+ int ret;
+ u8 req_mode = 0;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ if (os_strncmp(pos, "req_mode=", 9) == 0) {
+ int val = hex2byte(pos + 9);
+
+ if (val < 0)
+ return -1;
+ req_mode = val;
+ pos += 11;
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+ }
+ req = wpabuf_parse_bin(pos);
+ if (!req)
+ return -1;
+
+ ret = hostapd_send_beacon_req(hapd, addr, req_mode, req);
+ wpabuf_free(req);
+ if (ret >= 0)
+ ret = os_snprintf(reply, reply_size, "%d", ret);
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ struct wpabuf *nr, *lci = NULL, *civic = NULL;
+ int stationary = 0;
+ char *tmp;
+ int ret;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Neighbor report is not enabled");
+ return -1;
+ }
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: SET_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad or missing SSID");
+ return -1;
+ }
+ buf = os_strchr(tmp + 6, tmp[5] == '"' ? '"' : ' ');
+ if (!buf)
+ return -1;
+
+ tmp = os_strstr(buf, "nr=");
+ if (!tmp) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Missing Neighbor Report element");
+ return -1;
+ }
+
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+
+ nr = wpabuf_parse_bin(tmp + 3);
+ if (!nr) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad Neighbor Report element");
+ return -1;
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "lci=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ lci = wpabuf_parse_bin(tmp + 4);
+ if (!lci) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad LCI subelement");
+ wpabuf_free(nr);
+ return -1;
+ }
+ }
+
+ if (!buf)
+ goto set;
+
+ tmp = os_strstr(buf, "civic=");
+ if (tmp) {
+ buf = os_strchr(tmp, ' ');
+ if (buf)
+ *buf++ = '\0';
+ civic = wpabuf_parse_bin(tmp + 6);
+ if (!civic) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad civic subelement");
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ return -1;
+ }
+ }
+
+ if (!buf)
+ goto set;
+
+ if (os_strstr(buf, "stat"))
+ stationary = 1;
+
+set:
+ ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic,
+ stationary);
+
+ wpabuf_free(nr);
+ wpabuf_free(lci);
+ wpabuf_free(civic);
+
+ return ret;
+}
+
+
+static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd,
+ char *buf)
+{
+ struct wpa_ssid_value ssid;
+ u8 bssid[ETH_ALEN];
+ char *tmp;
+
+ if (hwaddr_aton(buf, bssid)) {
+ wpa_printf(MSG_ERROR, "CTRL: REMOVE_NEIGHBOR: Bad BSSID");
+ return -1;
+ }
+
+ tmp = os_strstr(buf, "ssid=");
+ if (!tmp || ssid_parse(tmp + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID");
+ return -1;
+ }
+
+ return hostapd_neighbor_remove(hapd, bssid, &ssid);
+}
+
+
+static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf,
+ size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) iface->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (iface->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -2153,6 +2513,14 @@
} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
reply_len = -1;
+#ifdef CONFIG_TAXONOMY
+ } else if (os_strncmp(buf, "SIGNATURE ", 10) == 0) {
+ reply_len = hostapd_ctrl_iface_signature(hapd, buf + 10,
+ reply, reply_size);
+#endif /* CONFIG_TAXONOMY */
+ } else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
+ if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
+ reply_len = -1;
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (hostapd_ctrl_iface_stop_ap(hapd))
reply_len = -1;
@@ -2258,6 +2626,9 @@
} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
reply_len = -1;
+ } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+ if (hostapd_ctrl_iface_mgmt_rx_process(hapd, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
reply_len = -1;
@@ -2312,6 +2683,26 @@
reply_size);
} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
hostapd_ctrl_iface_pmksa_flush(hapd);
+ } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) {
+ if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) {
+ if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_LCI ", 8) == 0) {
+ if (hostapd_ctrl_iface_req_lci(hapd, buf + 8))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_RANGE ", 10) == 0) {
+ if (hostapd_ctrl_iface_req_range(hapd, buf + 10))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) {
+ reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11,
+ reply, reply_size);
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply,
+ reply_size);
+ } else if (os_strcmp(buf, "TERMINATE") == 0) {
+ eloop_terminate();
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -3142,7 +3533,6 @@
reply_len = -1;
#ifdef CONFIG_MODULE_TESTS
} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
- int hapd_module_tests(void);
if (hapd_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
@@ -3242,8 +3632,6 @@
}
}
- dl_list_init(&interface->global_ctrl_dst);
- interface->global_ctrl_sock = -1;
os_get_random(gcookie, COOKIE_LEN);
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
diff --git a/hostapd/defconfig b/hostapd/defconfig
index f7b60e0..9ade580 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -157,6 +157,12 @@
# IEEE 802.11ac (Very High Throughput) support
#CONFIG_IEEE80211AC=y
+# IEEE 802.11ax HE support
+# Note: This is experimental and work in progress. The definitions are still
+# subject to change and this should not be expected to interoperate with the
+# final IEEE 802.11ax version.
+#CONFIG_IEEE80211AX=y
+
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
@@ -166,6 +172,9 @@
# Disabled by default.
#CONFIG_DEBUG_FILE=y
+# Send debug messages to syslog instead of stdout
+#CONFIG_DEBUG_SYSLOG=y
+
# Add support for sending all debug messages (regardless of debug verbosity)
# to the Linux kernel tracing facility. This helps debug the entire stack by
# making it easy to record everything happening from the driver up into the
@@ -337,3 +346,18 @@
# These extentions facilitate efficient use of multiple frequency bands
# available to the AP and the devices that may associate with it.
#CONFIG_MBO=y
+
+# Client Taxonomy
+# Has the AP retain the Probe Request and (Re)Association Request frames from
+# a client, from which a signature can be produced which can identify the model
+# of client device like "Nexus 6P" or "iPhone 5s".
+#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
+
+# Include internal line edit mode in hostapd_cli. This can be used to provide
+# limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
diff --git a/hostapd/hapd_module_tests.c b/hostapd/hapd_module_tests.c
index f7887eb..a5016f2 100644
--- a/hostapd/hapd_module_tests.c
+++ b/hostapd/hapd_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
int hapd_module_tests(void)
{
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 2117d34..5caa779 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -973,7 +973,7 @@
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
- "Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n"
+ "Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
new file mode 100644
index 0000000..672e188
--- /dev/null
+++ b/hostapd/hostapd.android.rc
@@ -0,0 +1,20 @@
+#
+# init.rc fragment for hostapd on Android
+# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+on post-fs-data
+ mkdir /data/misc/wifi/hostapd 0770 wifi wifi
+
+service hostapd /vendor/bin/hostapd \
+ -e /data/misc/wifi/entropy.bin \
+ /data/misc/wifi/hostapd.conf
+ class main
+ user wifi
+ group wifi net_raw net_admin
+ writepid /data/misc/wifi/hostapd.pid
+ disabled
+ oneshot
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index d943a43..c4eebff 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -3,6 +3,8 @@
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
# management frames with the Host AP driver); wlan0 with many nl80211 drivers
+# Note: This attribute can be overridden by the values supplied with the '-i'
+# command line parameter.
interface=wlan0
# In case of atheros and nl80211 driver interfaces, an additional
@@ -225,6 +227,19 @@
#basic_rates=10 20 55 110
#basic_rates=60 120 240
+# Beacon frame TX rate configuration
+# This sets the TX rate that is used to transmit Beacon frames. If this item is
+# not included, the driver default rate (likely lowest rate) is used.
+# Legacy (CCK/OFDM rates):
+# beacon_rate=<legacy rate in 100 kbps>
+# HT:
+# beacon_rate=ht:<HT MCS>
+# VHT:
+# beacon_rate=vht:<VHT MCS>
+#
+# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
+#beacon_rate=10
+
# Short Preamble
# This parameter can be used to enable optional use of short preamble for
# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
@@ -283,9 +298,16 @@
# one or more elements)
#vendor_elements=dd0411223301
+# Additional vendor specific elements for (Re)Association Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the (Re)Association Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#assocresp_elements=dd0411223301
+
# TX queue parameters (EDCF / bursting)
# tx_queue_<queue name>_<param>
-# queues: data0, data1, data2, data3, after_beacon, beacon
+# queues: data0, data1, data2, data3
# (data0 is the highest priority queue)
# parameters:
# aifs: AIFS (default 2)
@@ -473,6 +495,22 @@
# <station count>:<channel utilization>:<available admission capacity>
#bss_load_test=12:80:20000
+# Multicast to unicast conversion
+# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and
+# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent
+# to each station separately, with the DA replaced by their own MAC address
+# rather than the group address.
+#
+# Note that this may break certain expectations of the receiver, such as the
+# ability to drop unicast IP packets received within multicast L2 frames, or the
+# ability to not send ICMP destination unreachable messages for packets received
+# in L2 multicast (which is required, but the receiver can't tell the difference
+# if this new option is enabled).
+#
+# This also doesn't implement the 802.11 DMS (directed multicast service).
+#
+#multicast_to_unicast=0
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -676,6 +714,54 @@
#
#vht_oper_centr_freq_seg1_idx=159
+# Workaround to use station's nsts capability in (Re)Association Response frame
+# This may be needed with some deployed devices as an interoperability
+# workaround for beamforming if the AP's capability is greater than the
+# station's capability. This is disabled by default and can be enabled by
+# setting use_sta_nsts=1.
+#use_sta_nsts=0
+
+##### IEEE 802.11ax related configuration #####################################
+
+#ieee80211ax: Whether IEEE 802.11ax (HE) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+#ieee80211ax=1
+
+#he_su_beamformer: HE single user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#he_su_beamformer=1
+
+#he_su_beamformee: HE single user beamformee support
+# 0 = not supported (default)
+# 1 = supported
+#he_su_beamformee=1
+
+#he_mu_beamformer: HE multiple user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#he_mu_beamformer=1
+
+# he_bss_color: BSS color
+# 0 = no BSS color (default)
+# unsigned integer = BSS color
+#he_bss_color=0
+
+#he_default_pe_duration: The duration of PE field in an HE PPDU in us
+# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
+#he_default_pe_duration=0
+
+#he_twt_required: Whether TWT is required
+# 0 = not required (default)
+# 1 = required
+#he_twt_required=0
+
+#he_rts_threshold: Duration of STA transmission
+# 0 = not set (default)
+# unsigned integer = duration in units of 16 us
+#he_rts_threshold=0
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -1079,6 +1165,9 @@
#
# DAS require Event-Timestamp
#radius_das_require_event_timestamp=1
+#
+# DAS require Message-Authenticator
+#radius_das_require_message_authenticator=1
##### RADIUS authentication server configuration ##############################
@@ -1144,6 +1233,10 @@
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
# added to enable SHA256-based stronger algorithms.
+# FILS-SHA256 = Fast Initial Link Setup with SHA256
+# FILS-SHA384 = Fast Initial Link Setup with SHA384
+# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
+# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
# (dot11RSNAConfigAuthenticationSuitesTable)
#wpa_key_mgmt=WPA-PSK WPA-EAP
@@ -1169,6 +1262,15 @@
# (dot11RSNAConfigGroupRekeyStrict)
#wpa_strict_rekey=1
+# The number of times EAPOL-Key Message 1/2 in the RSN Group Key Handshake is
+#retried per GTK Handshake attempt. (dot11RSNAConfigGroupUpdateCount)
+# This value should only be increased when stations are constantly
+# deauthenticated during GTK rekeying with the log message
+# "group key handshake failed...".
+# You should consider to also increase wpa_pairwise_update_count then.
+# Range 1..4294967295; default: 4
+#wpa_group_update_count=4
+
# Time interval for rekeying GMK (master key used internally to generate GTKs
# (in seconds).
#wpa_gmk_rekey=86400
@@ -1177,6 +1279,12 @@
# PTK to mitigate some attacks against TKIP deficiencies.
#wpa_ptk_rekey=600
+# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
+# Handshake are retried per 4-Way Handshake attempt.
+# (dot11RSNAConfigPairwiseUpdateCount)
+# Range 1..4294967295; default: 4
+#wpa_pairwise_update_count=4
+
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
# authentication and key handshake before actually associating with a new AP.
@@ -1254,6 +1362,44 @@
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
#sae_groups=19 20 21 25 26
+# FILS Cache Identifier (16-bit value in hexdump format)
+#fils_cache_id=0011
+
+# FILS Realm Information
+# One or more FILS realms need to be configured when FILS is enabled. This list
+# of realms is used to define which realms (used in keyName-NAI by the client)
+# can be used with FILS shared key authentication for ERP.
+#fils_realm=example.com
+#fils_realm=example.org
+
+# DHCP server for FILS HLP
+# If configured, hostapd will act as a DHCP relay for all FILS HLP requests
+# that include a DHCPDISCOVER message and send them to the specific DHCP
+# server for processing. hostapd will then wait for a response from that server
+# before replying with (Re)Association Response frame that encapsulates this
+# DHCP response. own_ip_addr is used as the local address for the communication
+# with the DHCP server.
+#dhcp_server=127.0.0.1
+
+# DHCP server UDP port
+# Default: 67
+#dhcp_server_port=67
+
+# DHCP relay UDP port on the local device
+# Default: 67; 0 means not to bind any specific port
+#dhcp_relay_port=67
+
+# DHCP rapid commit proxy
+# If set to 1, this enables hostapd to act as a DHCP rapid commit proxy to
+# allow the rapid commit options (two message DHCP exchange) to be used with a
+# server that supports only the four message DHCP exchange. This is disabled by
+# default (= 0) and can be enabled by setting this to 1.
+#dhcp_rapid_commit_proxy=0
+
+# Wait time for FILS HLP (dot11HLPWaitTime) in TUs
+# default: 30 TUs (= 30.72 milliseconds)
+#fils_hlp_wait_time=30
+
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -1307,6 +1453,14 @@
# 1 = FT-over-DS enabled (default)
#ft_over_ds=1
+# Whether to generate FT response locally for PSK networks
+# This avoids use of PMK-R1 push/pull from other APs with FT-PSK networks as
+# the required information (PSK and other session data) is already locally
+# available.
+# 0 = disabled (default)
+# 1 = enabled
+#ft_psk_generate_local=0
+
##### Neighbor table ##########################################################
# Maximum number of entries kept in AP table (either for neigbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
@@ -1740,6 +1894,13 @@
# For example, AP Civic Location ANQP-element with unknown location:
#anqp_elem=266:000000
+# GAS Address 3 behavior
+# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default
+# based on GAS request Address3
+# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3
+# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases)
+#gas_address3=0
+
# QoS Map Set configuration
#
# Comma delimited QoS Map Set in decimal values
@@ -1879,6 +2040,36 @@
# Transitioning between states).
#fst_llt=100
+##### Radio measurements / location ###########################################
+
+# The content of a LCI measurement subelement
+#lci=<Hexdump of binary data of the LCI report>
+
+# The content of a location civic measurement subelement
+#civic=<Hexdump of binary data of the location civic report>
+
+# Enable neighbor report via radio measurements
+#rrm_neighbor_report=1
+
+# Enable beacon report via radio measurements
+#rrm_beacon_report=1
+
+# Publish fine timing measurement (FTM) responder functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality
+# This parameter only controls publishing via Extended Capabilities element.
+# Actual functionality is managed outside hostapd.
+#ftm_initiator=0
+#
+# Stationary AP config indicates that the AP doesn't move hence location data
+# can be considered as always up to date. If configured, LCI data will be sent
+# as a radio measurement even if the request doesn't contain a max age element
+# that allows sending of such data. Default: 0.
+#stationary_ap=0
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index bf86d37..f8d1eda 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-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,80 +15,13 @@
#include "utils/eloop.h"
#include "utils/edit.h"
#include "common/version.h"
+#include "common/cli.h"
#ifndef CONFIG_NO_CTRL_IFACE
static const char *const hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const hostapd_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const hostapd_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-" notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-" notice, this list of conditions and the following disclaimer in the\n"
-" documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-" names of its contributors may be used to endorse or promote products\n"
-" derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
-
-static const char *const commands_help =
-"Commands:\n"
-" mib get MIB variables (dot1x, dot11, radius)\n"
-" sta <addr> get MIB variables for one station\n"
-" all_sta get MIB variables for all stations\n"
-" new_sta <addr> add a new station\n"
-" deauthenticate <addr> deauthenticate a station\n"
-" disassociate <addr> disassociate a station\n"
-#ifdef CONFIG_IEEE80211W
-" sa_query <addr> send SA Query to a station\n"
-#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_WPS
-" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
-" wps_check_pin <PIN> verify PIN checksum\n"
-" wps_pbc indicate button pushed to initiate PBC\n"
-" wps_cancel cancel the pending WPS operation\n"
-#ifdef CONFIG_WPS_NFC
-" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
-" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
-" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
-#endif /* CONFIG_WPS_NFC */
-" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
-" wps_config <SSID> <auth> <encr> <key> configure AP\n"
-" wps_get_status show current WPS status\n"
-#endif /* CONFIG_WPS */
-" get_config show current configuration\n"
-" help show this usage help\n"
-" interface [ifname] show interfaces/select interface\n"
-" level <debug level> change debug level\n"
-" license show full hostapd_cli license\n"
-" quit exit hostapd_cli\n";
+"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
@@ -105,6 +38,15 @@
static const char *action_file = NULL;
static int ping_interval = 5;
static int interactive = 0;
+static int event_handler_registered = 0;
+
+static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
+
+static void print_help(FILE *stream, const char *cmd);
+static char ** list_cmd_list(void);
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
+static void update_stations(struct wpa_ctrl *ctrl);
+static void cli_event(const char *str);
static void usage(void)
@@ -129,9 +71,32 @@
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
- " socket path)\n\n"
- "%s",
- commands_help);
+ " socket path)\n\n");
+ print_help(stderr, NULL);
+}
+
+
+static void register_event_handler(struct wpa_ctrl *ctrl)
+{
+ if (!ctrl_conn)
+ return;
+ if (interactive) {
+ event_handler_registered =
+ !eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
+ hostapd_cli_receive,
+ NULL, NULL);
+ }
+}
+
+
+static void unregister_event_handler(struct wpa_ctrl *ctrl)
+{
+ if (!ctrl_conn)
+ return;
+ if (interactive && event_handler_registered) {
+ eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
+ event_handler_registered = 0;
+ }
}
@@ -174,6 +139,7 @@
if (ctrl_conn == NULL)
return;
+ unregister_event_handler(ctrl_conn);
if (hostapd_cli_attached) {
wpa_ctrl_detach(ctrl_conn);
hostapd_cli_attached = 0;
@@ -183,13 +149,45 @@
}
+static int hostapd_cli_reconnect(const char *ifname)
+{
+ char *next_ctrl_ifname;
+
+ hostapd_cli_close_connection();
+
+ if (!ifname)
+ return -1;
+
+ next_ctrl_ifname = os_strdup(ifname);
+ os_free(ctrl_ifname);
+ ctrl_ifname = next_ctrl_ifname;
+ if (!ctrl_ifname)
+ return -1;
+
+ ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+ if (!ctrl_conn)
+ return -1;
+ if (!interactive && !action_file)
+ return 0;
+ if (wpa_ctrl_attach(ctrl_conn) == 0) {
+ hostapd_cli_attached = 1;
+ register_event_handler(ctrl_conn);
+ update_stations(ctrl_conn);
+ } else {
+ printf("Warning: Failed to attach to hostapd.\n");
+ }
+ return 0;
+}
+
+
static void hostapd_cli_msg_cb(char *msg, size_t len)
{
+ cli_event(msg);
printf("%s\n", msg);
}
-static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
{
char buf[4096];
size_t len;
@@ -217,42 +215,12 @@
}
-static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
{
return _wpa_ctrl_command(ctrl, cmd, 1);
}
-static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
- char *argv[])
-{
- int i, res;
- char *pos, *end;
-
- pos = buf;
- end = buf + buflen;
-
- res = os_snprintf(pos, end - pos, "%s", cmd);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
-
- for (i = 0; i < argc; i++) {
- res = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
- }
-
- buf[buflen - 1] = '\0';
- return 0;
-
-fail:
- printf("Too long command\n");
- return -1;
-}
-
-
static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
int min_args, int argc, char *argv[])
{
@@ -352,6 +320,21 @@
}
+static char ** hostapd_complete_stations(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -402,6 +385,22 @@
}
+#ifdef CONFIG_TAXONOMY
+static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+
+ if (argc != 1) {
+ printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
+ return -1;
+ }
+ os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
#ifdef CONFIG_IEEE80211W
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
char *argv[])
@@ -721,8 +720,8 @@
}
-static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
- char *addr, size_t addr_len)
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
+ char *addr, size_t addr_len, int print)
{
char buf[4096], *pos;
size_t len;
@@ -746,7 +745,8 @@
buf[len] = '\0';
if (memcmp(buf, "FAIL", 4) == 0)
return -1;
- printf("%s", buf);
+ if (print)
+ printf("%s", buf);
pos = buf;
while (*pos != '\0' && *pos != '\n')
@@ -762,27 +762,59 @@
{
char addr[32], cmd[64];
- if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
return 0;
do {
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
- } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
return -1;
}
+static int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char addr[32], cmd[64];
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return 0;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ printf("%s\n", addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+
+ return 0;
+}
+
+
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- printf("%s", commands_help);
+ print_help(stdout, argc > 0 ? argv[0] : NULL);
return 0;
}
+static char ** hostapd_cli_complete_help(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = list_cmd_list();
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
+ printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
return 0;
}
@@ -893,6 +925,47 @@
}
+static void update_stations(struct wpa_ctrl *ctrl)
+{
+ char addr[32], cmd[64];
+
+ if (!ctrl || !interactive)
+ return;
+
+ cli_txt_list_flush(&stations);
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ cli_txt_list_add(&stations, addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+}
+
+
+static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
+ struct dl_list *interfaces)
+{
+ struct dirent *dent;
+ DIR *dir;
+
+ if (!ctrl || !interfaces)
+ return;
+ dir = opendir(ctrl_iface_dir);
+ if (dir == NULL)
+ return;
+
+ while ((dent = readdir(dir))) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ cli_txt_list_add(interfaces, dent->d_name);
+ }
+ closedir(dir);
+}
+
+
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
struct dirent *dent;
@@ -923,22 +996,7 @@
hostapd_cli_list_interfaces(ctrl);
return 0;
}
-
- hostapd_cli_close_connection();
- os_free(ctrl_ifname);
- ctrl_ifname = os_strdup(argv[0]);
- if (ctrl_ifname == NULL)
- return -1;
-
- if (hostapd_cli_open_connection(ctrl_ifname)) {
- printf("Connected to interface '%s.\n", ctrl_ifname);
- if (wpa_ctrl_attach(ctrl_conn) == 0) {
- hostapd_cli_attached = 1;
- } else {
- printf("Warning: Failed to attach to "
- "hostapd.\n");
- }
- } else {
+ if (hostapd_cli_reconnect(argv[0]) != 0) {
printf("Could not connect to interface '%s' - re-trying\n",
ctrl_ifname);
}
@@ -946,6 +1004,24 @@
}
+static char ** hostapd_complete_interface(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+ DEFINE_DL_LIST(interfaces);
+
+ switch (arg) {
+ case 1:
+ hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
+ res = cli_txt_list_array(&interfaces);
+ cli_txt_list_flush(&interfaces);
+ break;
+ }
+
+ return res;
+}
+
+
static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -966,6 +1042,44 @@
}
+static char ** hostapd_complete_set(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+#ifdef CONFIG_WPS_TESTING
+ "wps_version_number", "wps_testing_dummy_cred",
+ "wps_corrupt_pkhash",
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+ "gas_frag_limit",
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_TESTING_OPTIONS
+ "ext_mgmt_frame_handling", "ext_eapol_frame_io",
+#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_MBO
+ "mbo_assoc_disallow",
+#endif /* CONFIG_MBO */
+ "deny_mac_file", "accept_mac_file",
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **res;
+
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (!res)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(fields[i]);
+ if (!res[i])
+ return res;
+ }
+ return res;
+ }
+ return NULL;
+}
+
+
static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -986,6 +1100,31 @@
}
+static char ** hostapd_complete_get(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ "version", "tls_library",
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+
+ if (arg == 1) {
+ char **res;
+
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (!res)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(fields[i]);
+ if (!res[i])
+ return res;
+ }
+ return res;
+ }
+ return NULL;
+}
+
+
#ifdef CONFIG_FST
static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
@@ -1143,71 +1282,260 @@
}
+static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[2048];
+ int res;
+
+ if (argc < 3 || argc > 6) {
+ printf("Invalid set_neighbor command: needs 3-6 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s",
+ argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
+ argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : "");
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long SET_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[400];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid remove_neighbor command: needs 2 arguments\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
+ argv[0], argv[1]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long REMOVE_NEIGHBOR command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid req_lci command - requires destination address\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long REQ_LCI command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc < 4) {
+ printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
+ return -1;
+ }
+
+ return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+ char ** (*completion)(const char *str, int pos);
+ const char *usage;
};
static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
- { "ping", hostapd_cli_cmd_ping },
- { "mib", hostapd_cli_cmd_mib },
- { "relog", hostapd_cli_cmd_relog },
- { "status", hostapd_cli_cmd_status },
- { "sta", hostapd_cli_cmd_sta },
- { "all_sta", hostapd_cli_cmd_all_sta },
- { "new_sta", hostapd_cli_cmd_new_sta },
- { "deauthenticate", hostapd_cli_cmd_deauthenticate },
- { "disassociate", hostapd_cli_cmd_disassociate },
+ { "ping", hostapd_cli_cmd_ping, NULL,
+ "= pings hostapd" },
+ { "mib", hostapd_cli_cmd_mib, NULL,
+ "= get MIB variables (dot1x, dot11, radius)" },
+ { "relog", hostapd_cli_cmd_relog, NULL,
+ "= reload/truncate debug log output file" },
+ { "status", hostapd_cli_cmd_status, NULL,
+ "= show interface status info" },
+ { "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
+ "<addr> = get MIB variables for one station" },
+ { "all_sta", hostapd_cli_cmd_all_sta, NULL,
+ "= get MIB variables for all stations" },
+ { "list_sta", hostapd_cli_cmd_list_sta, NULL,
+ "= list all stations" },
+ { "new_sta", hostapd_cli_cmd_new_sta, NULL,
+ "<addr> = add a new station" },
+ { "deauthenticate", hostapd_cli_cmd_deauthenticate,
+ hostapd_complete_stations,
+ "<addr> = deauthenticate a station" },
+ { "disassociate", hostapd_cli_cmd_disassociate,
+ hostapd_complete_stations,
+ "<addr> = disassociate a station" },
+#ifdef CONFIG_TAXONOMY
+ { "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
+ "<addr> = get taxonomy signature for a station" },
+#endif /* CONFIG_TAXONOMY */
#ifdef CONFIG_IEEE80211W
- { "sa_query", hostapd_cli_cmd_sa_query },
+ { "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
+ "<addr> = send SA Query to a station" },
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
- { "wps_pin", hostapd_cli_cmd_wps_pin },
- { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
- { "wps_pbc", hostapd_cli_cmd_wps_pbc },
- { "wps_cancel", hostapd_cli_cmd_wps_cancel },
+ { "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
+ "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
+ { "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
+ "<PIN> = verify PIN checksum" },
+ { "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
+ "= indicate button pushed to initiate PBC" },
+ { "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
+ "= cancel the pending WPS operation" },
#ifdef CONFIG_WPS_NFC
- { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
- { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
- { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
- { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
+ { "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
+ "<hexdump> = report read NFC tag with WPS data" },
+ { "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
+ "<WPS/NDEF> = build NFC configuration token" },
+ { "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
+ "<WPS/NDEF/enable/disable> = manager NFC password token" },
+ { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
+ NULL },
#endif /* CONFIG_WPS_NFC */
- { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
- { "wps_config", hostapd_cli_cmd_wps_config },
- { "wps_get_status", hostapd_cli_cmd_wps_get_status },
+ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
+ "<cmd> [params..] = enable/disable AP PIN" },
+ { "wps_config", hostapd_cli_cmd_wps_config, NULL,
+ "<SSID> <auth> <encr> <key> = configure AP" },
+ { "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
+ "= show current WPS status" },
#endif /* CONFIG_WPS */
- { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
- { "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
- { "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
- { "get_config", hostapd_cli_cmd_get_config },
- { "help", hostapd_cli_cmd_help },
- { "interface", hostapd_cli_cmd_interface },
+ { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
+ "= send Disassociation Imminent notification" },
+ { "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
+ "= send ESS Dissassociation Imminent notification" },
+ { "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
+ "= send BSS Transition Management Request" },
+ { "get_config", hostapd_cli_cmd_get_config, NULL,
+ "= show current configuration" },
+ { "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
+ "= show this usage help" },
+ { "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
+ "[ifname] = show interfaces/select interface" },
#ifdef CONFIG_FST
- { "fst", hostapd_cli_cmd_fst },
+ { "fst", hostapd_cli_cmd_fst, NULL,
+ "<params...> = send FST-MANAGER control interface command" },
#endif /* CONFIG_FST */
- { "raw", hostapd_cli_cmd_raw },
- { "level", hostapd_cli_cmd_level },
- { "license", hostapd_cli_cmd_license },
- { "quit", hostapd_cli_cmd_quit },
- { "set", hostapd_cli_cmd_set },
- { "get", hostapd_cli_cmd_get },
- { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
- { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
- { "chan_switch", hostapd_cli_cmd_chan_switch },
- { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
- { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
- { "vendor", hostapd_cli_cmd_vendor },
- { "enable", hostapd_cli_cmd_enable },
- { "reload", hostapd_cli_cmd_reload },
- { "disable", hostapd_cli_cmd_disable },
- { "erp_flush", hostapd_cli_cmd_erp_flush },
- { "log_level", hostapd_cli_cmd_log_level },
- { "pmksa", hostapd_cli_cmd_pmksa },
- { "pmksa_flush", hostapd_cli_cmd_pmksa_flush },
- { NULL, NULL }
+ { "raw", hostapd_cli_cmd_raw, NULL,
+ "<params..> = send unprocessed command" },
+ { "level", hostapd_cli_cmd_level, NULL,
+ "<debug level> = change debug level" },
+ { "license", hostapd_cli_cmd_license, NULL,
+ "= show full hostapd_cli license" },
+ { "quit", hostapd_cli_cmd_quit, NULL,
+ "= exit hostapd_cli" },
+ { "set", hostapd_cli_cmd_set, hostapd_complete_set,
+ "<name> <value> = set runtime variables" },
+ { "get", hostapd_cli_cmd_get, hostapd_complete_get,
+ "<name> = get runtime info" },
+ { "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
+ "<arg,arg,...> = set QoS Map set element" },
+ { "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
+ hostapd_complete_stations,
+ "<addr> = send QoS Map Configure frame" },
+ { "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
+ "<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
+ " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
+ " = initiate channel switch announcement" },
+ { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
+ "<addr> <url>\n"
+ " = send WNM-Notification Subscription Remediation Request" },
+ { "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
+ "<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
+ " = send WNM-Notification imminent deauthentication indication" },
+ { "vendor", hostapd_cli_cmd_vendor, NULL,
+ "<vendor id> <sub command id> [<hex formatted data>]\n"
+ " = send vendor driver command" },
+ { "enable", hostapd_cli_cmd_enable, NULL,
+ "= enable hostapd on current interface" },
+ { "reload", hostapd_cli_cmd_reload, NULL,
+ "= reload configuration for current interface" },
+ { "disable", hostapd_cli_cmd_disable, NULL,
+ "= disable hostapd on current interface" },
+ { "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
+ "= drop all ERP keys"},
+ { "log_level", hostapd_cli_cmd_log_level, NULL,
+ "[level] = show/change log verbosity level" },
+ { "pmksa", hostapd_cli_cmd_pmksa, NULL,
+ " = show PMKSA cache entries" },
+ { "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
+ " = flush PMKSA cache" },
+ { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
+ "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
+ " = add AP to neighbor database" },
+ { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
+ "<addr> <ssid=> = remove AP from neighbor database" },
+ { "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
+ "<addr> = send LCI request to a station"},
+ { "req_range", hostapd_cli_cmd_req_range, NULL,
+ " = send FTM range request"},
+ { "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
+ " = show supported driver flags"},
+ { NULL, NULL, NULL, NULL }
};
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
+ const char *pad)
+{
+ char c;
+ size_t n;
+
+ if (cmd->usage == NULL)
+ return;
+ fprintf(stream, "%s%s ", pad, cmd->cmd);
+ for (n = 0; (c = cmd->usage[n]); n++) {
+ fprintf(stream, "%c", c);
+ if (c == '\n')
+ fprintf(stream, "%s", pad);
+ }
+ fprintf(stream, "\n");
+}
+
+
+static void print_help(FILE *stream, const char *cmd)
+{
+ int n;
+
+ fprintf(stream, "commands:\n");
+ for (n = 0; hostapd_cli_commands[n].cmd; n++) {
+ if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
+ print_cmd_help(stream, &hostapd_cli_commands[n], " ");
+ }
+}
+
+
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
const struct hostapd_cli_cmd *cmd, *match = NULL;
@@ -1247,6 +1575,34 @@
}
+static void cli_event(const char *str)
+{
+ const char *start, *s;
+
+ start = os_strchr(str, '>');
+ if (start == NULL)
+ return;
+
+ start++;
+
+ if (str_starts(start, AP_STA_CONNECTED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_add(&stations, s + 1);
+ return;
+ }
+
+ if (str_starts(start, AP_STA_DISCONNECTED)) {
+ s = os_strchr(start, ' ');
+ if (s == NULL)
+ return;
+ cli_txt_list_del_addr(&stations, s + 1);
+ return;
+ }
+}
+
+
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
int action_monitor)
{
@@ -1261,6 +1617,7 @@
if (action_monitor)
hostapd_cli_action_process(buf, len);
else {
+ cli_event(buf);
if (in_read && first)
printf("\n");
first = 0;
@@ -1274,35 +1631,9 @@
}
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
+static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
- char *pos;
- int argc = 0;
-
- pos = cmd;
- for (;;) {
- while (*pos == ' ')
- pos++;
- if (*pos == '\0')
- break;
- argv[argc] = pos;
- argc++;
- if (argc == max_args)
- break;
- if (*pos == '"') {
- char *pos2 = os_strrchr(pos, '"');
- if (pos2)
- pos = pos2 + 1;
- }
- while (*pos != '\0' && *pos != ' ')
- pos++;
- if (*pos == ' ')
- *pos++ = '\0';
- }
-
- return argc;
+ hostapd_cli_recv_pending(ctrl_conn, 0, 0);
}
@@ -1312,18 +1643,8 @@
printf("Connection to hostapd lost - trying to reconnect\n");
hostapd_cli_close_connection();
}
- if (!ctrl_conn) {
- ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
- if (ctrl_conn) {
- printf("Connection to hostapd re-established\n");
- if (wpa_ctrl_attach(ctrl_conn) == 0) {
- hostapd_cli_attached = 1;
- } else {
- printf("Warning: Failed to attach to "
- "hostapd.\n");
- }
- }
- }
+ if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0)
+ printf("Connection to hostapd re-established\n");
if (ctrl_conn)
hostapd_cli_recv_pending(ctrl_conn, 1, 0);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
@@ -1352,18 +1673,100 @@
}
+static char ** list_cmd_list(void)
+{
+ char **res;
+ int i, count;
+
+ count = ARRAY_SIZE(hostapd_cli_commands);
+ res = os_calloc(count + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+
+ for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+ res[i] = os_strdup(hostapd_cli_commands[i].cmd);
+ if (res[i] == NULL)
+ break;
+ }
+
+ return res;
+}
+
+
+static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
+ int pos)
+{
+ int i;
+
+ for (i = 0; hostapd_cli_commands[i].cmd; i++) {
+ if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
+ continue;
+ if (hostapd_cli_commands[i].completion)
+ return hostapd_cli_commands[i].completion(str, pos);
+ if (!hostapd_cli_commands[i].usage)
+ return NULL;
+ edit_clear_line();
+ printf("\r%s\n", hostapd_cli_commands[i].usage);
+ edit_redraw();
+ break;
+ }
+
+ return NULL;
+}
+
+
+static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
+ int pos)
+{
+ char **res;
+ const char *end;
+ char *cmd;
+
+ end = os_strchr(str, ' ');
+ if (end == NULL || str + pos < end)
+ return list_cmd_list();
+
+ cmd = os_malloc(pos + 1);
+ if (cmd == NULL)
+ return NULL;
+ os_memcpy(cmd, str, pos);
+ cmd[end - str] = '\0';
+ res = hostapd_cli_cmd_completion(cmd, str, pos);
+ os_free(cmd);
+ return res;
+}
+
+
static void hostapd_cli_interactive(void)
{
+ char *hfile = NULL;
+ char *home;
+
printf("\nInteractive mode\n\n");
+#ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR
+ home = CONFIG_HOSTAPD_CLI_HISTORY_DIR;
+#else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
+ home = getenv("HOME");
+#endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
+ if (home) {
+ const char *fname = ".hostapd_cli_history";
+ int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
+ hfile = os_malloc(hfile_len);
+ if (hfile)
+ os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
+ }
+
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
- NULL, NULL, NULL, NULL);
+ hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
eloop_run();
- edit_deinit(NULL, NULL);
+ cli_txt_list_flush(&stations);
+ edit_deinit(hfile, NULL);
+ os_free(hfile);
eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
}
@@ -1466,8 +1869,7 @@
interactive = (argc == optind) && (action_file == NULL);
if (interactive) {
- printf("%s\n\n%s\n\n", hostapd_cli_version,
- hostapd_cli_license);
+ printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
}
if (eloop_init())
@@ -1491,7 +1893,7 @@
closedir(dir);
}
}
- ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+ hostapd_cli_reconnect(ctrl_ifname);
if (ctrl_conn) {
if (warning_displayed)
printf("Connection established.\n");
@@ -1512,16 +1914,8 @@
continue;
}
- if (interactive || action_file) {
- if (wpa_ctrl_attach(ctrl_conn) == 0) {
- hostapd_cli_attached = 1;
- } else {
- printf("Warning: Failed to attach to hostapd.\n");
- if (action_file)
- return -1;
- }
- }
-
+ if (action_file && !hostapd_cli_attached)
+ return -1;
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
return -1;
@@ -1532,6 +1926,7 @@
else
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+ unregister_event_handler(ctrl_conn);
os_free(ctrl_ifname);
eloop_destroy();
hostapd_cli_cleanup();
diff --git a/hostapd/main.c b/hostapd/main.c
index 1d9e63e..593267c 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -108,6 +108,10 @@
module_str ? module_str : "",
module_str ? ": " : "", txt);
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog)
+ conf_stdout = 0;
+#endif /* CONFIG_DEBUG_SYSLOG */
if ((conf_stdout & module) && level >= conf_stdout_level) {
wpa_debug_print_timestamp();
wpa_printf(MSG_INFO, "%s", format);
@@ -217,11 +221,20 @@
iface->drv_flags = capa.flags;
iface->smps_modes = capa.smps_modes;
iface->probe_resp_offloads = capa.probe_resp_offloads;
+ /*
+ * Use default extended capa values from per-radio information
+ */
iface->extended_capa = capa.extended_capa;
iface->extended_capa_mask = capa.extended_capa_mask;
iface->extended_capa_len = capa.extended_capa_len;
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
+ /*
+ * Override extended capa with per-interface type (AP), if
+ * available from the driver.
+ */
+ hostapd_get_ext_capa(iface);
+
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
if (triggs && hapd->driver->set_wowlan) {
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
@@ -242,7 +255,7 @@
* interfaces. No actiual driver operations are started.
*/
static struct hostapd_iface *
-hostapd_interface_init(struct hapd_interfaces *interfaces,
+hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
const char *config_fname, int debug)
{
struct hostapd_iface *iface;
@@ -252,6 +265,12 @@
iface = hostapd_init(interfaces, config_fname);
if (!iface)
return NULL;
+
+ if (if_name) {
+ os_strlcpy(iface->conf->bss[0]->iface, if_name,
+ sizeof(iface->conf->bss[0]->iface));
+ }
+
iface->interfaces = interfaces;
for (k = 0; k < debug; k++) {
@@ -261,7 +280,8 @@
if (iface->conf->bss[0]->iface[0] == '\0' &&
!hostapd_drv_none(iface->bss[0])) {
- wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+ wpa_printf(MSG_ERROR,
+ "Interface name not specified in %s, nor by '-i' parameter",
config_fname);
hostapd_interface_deinit_free(iface);
return NULL;
@@ -330,6 +350,7 @@
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
return -1;
}
+ interfaces->eloop_initialized = 1;
random_init(entropy_file);
@@ -357,7 +378,7 @@
}
-static void hostapd_global_deinit(const char *pid_file)
+static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
{
int i;
@@ -375,7 +396,8 @@
random_deinit();
- eloop_destroy();
+ if (eloop_initialized)
+ eloop_destroy();
#ifndef CONFIG_NATIVE_WINDOWS
closelog();
@@ -433,7 +455,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-2016, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -445,7 +467,8 @@
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
- " [-g <global ctrl_iface>] [-G <group>] \\\n"
+ " [-g <global ctrl_iface>] [-G <group>]\\\n"
+ " [-i <comma-separated list of interface names>]\\\n"
" <configuration file(s)>\n"
"\n"
"options:\n"
@@ -461,9 +484,13 @@
" -f log output to debug file instead of stdout\n"
#endif /* CONFIG_DEBUG_FILE */
#ifdef CONFIG_DEBUG_LINUX_TRACING
- " -T = record to Linux tracing in addition to logging\n"
+ " -T record to Linux tracing in addition to logging\n"
" (records all messages regardless of debug verbosity)\n"
#endif /* CONFIG_DEBUG_LINUX_TRACING */
+ " -i list of interface names to use\n"
+#ifdef CONFIG_DEBUG_SYSLOG
+ " -s log output to syslog instead of stdout\n"
+#endif /* CONFIG_DEBUG_SYSLOG */
" -S start all the interfaces synchronously\n"
" -t include timestamps in some debug messages\n"
" -v show hostapd version\n");
@@ -527,6 +554,43 @@
}
+static int hostapd_get_interface_names(char ***if_names,
+ size_t *if_names_size,
+ char *arg)
+{
+ char *if_name, *tmp, **nnames;
+ size_t i;
+
+ if (!arg)
+ return -1;
+ if_name = strtok_r(arg, ",", &tmp);
+
+ while (if_name) {
+ nnames = os_realloc_array(*if_names, 1 + *if_names_size,
+ sizeof(char *));
+ if (!nnames)
+ goto fail;
+ *if_names = nnames;
+
+ (*if_names)[*if_names_size] = os_strdup(if_name);
+ if (!(*if_names)[*if_names_size])
+ goto fail;
+ (*if_names_size)++;
+ if_name = strtok_r(NULL, ",", &tmp);
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < *if_names_size; i++)
+ os_free((*if_names)[i]);
+ os_free(*if_names);
+ *if_names = NULL;
+ *if_names_size = 0;
+ return -1;
+}
+
+
#ifdef CONFIG_WPS
static int gen_uuid(const char *txt_addr)
{
@@ -585,6 +649,8 @@
int enable_trace_dbg = 0;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
int start_ifaces_in_sync = 0;
+ char **if_names = NULL;
+ size_t if_names_size = 0;
if (os_program_init())
return -1;
@@ -602,7 +668,7 @@
dl_list_init(&interfaces.global_ctrl_dst);
for (;;) {
- c = getopt(argc, argv, "b:Bde:f:hKP:STtu:vg:G:");
+ c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
if (c < 0)
break;
switch (c) {
@@ -659,6 +725,11 @@
bss_config = tmp_bss;
bss_config[num_bss_configs++] = optarg;
break;
+#ifdef CONFIG_DEBUG_SYSLOG
+ case 's':
+ wpa_debug_syslog = 1;
+ break;
+#endif /* CONFIG_DEBUG_SYSLOG */
case 'S':
start_ifaces_in_sync = 1;
break;
@@ -666,6 +737,11 @@
case 'u':
return gen_uuid(optarg);
#endif /* CONFIG_WPS */
+ case 'i':
+ if (hostapd_get_interface_names(&if_names,
+ &if_names_size, optarg))
+ goto out;
+ break;
default:
usage();
break;
@@ -682,6 +758,10 @@
wpa_debug_open_file(log_file);
else
wpa_debug_setup_stdout();
+#ifdef CONFIG_DEBUG_SYSLOG
+ if (wpa_debug_syslog)
+ wpa_debug_open_syslog();
+#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (enable_trace_dbg) {
int tret = wpa_debug_open_linux_tracing();
@@ -723,7 +803,13 @@
/* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
+ char *if_name = NULL;
+
+ if (i < if_names_size)
+ if_name = if_names[i];
+
interfaces.iface[i] = hostapd_interface_init(&interfaces,
+ if_name,
argv[optind + i],
debug);
if (!interfaces.iface[i]) {
@@ -807,16 +893,22 @@
}
os_free(interfaces.iface);
- eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
- hostapd_global_deinit(pid_file);
+ if (interfaces.eloop_initialized)
+ eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
+ hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
os_free(pid_file);
+ wpa_debug_close_syslog();
if (log_file)
wpa_debug_close_file();
wpa_debug_close_linux_tracing();
os_free(bss_config);
+ for (i = 0; i < if_names_size; i++)
+ os_free(if_names[i]);
+ os_free(if_names);
+
fst_global_deinit();
os_program_deinit();
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index c05c57d..d73feb1 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2134,7 +2134,7 @@
char fname[255];
FILE *f;
struct osu_data *osu = NULL, *last = NULL;
- size_t osu_count, i, j;
+ size_t osu_count = 0, i, j;
int ret;
write_summary(ctx, "OSU provider selection");
diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt
index 001d6f2..20774a6 100644
--- a/hs20/server/hs20-osu-server.txt
+++ b/hs20/server/hs20-osu-server.txt
@@ -110,8 +110,8 @@
./clean.sh
rm -fr rootCA"
old_hostname=myserver.local
-./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" -d $old_hostname \
- -I "Hotspot 2.0 Intermediate CA - CT" -o $old_hostname-osu-client \
+./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \
+ -o $old_hostname-osu-client \
-O $old_hostname-oscp -p lanforge -S $old_hostname \
-V $old_hostname-osu-revoked \
-m local -u http://$old_hostname:8888/
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index 33e3fa1..51c1d96 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -1823,10 +1823,8 @@
}
if (strcasecmp(req_reason, "User input completed") == 0) {
- if (devinfo)
- db_add_session_devinfo(ctx, session_id, devinfo);
- if (devdetail)
- db_add_session_devdetail(ctx, session_id, devdetail);
+ db_add_session_devinfo(ctx, session_id, devinfo);
+ db_add_session_devdetail(ctx, session_id, devdetail);
ret = hs20_user_input_complete(ctx, user, realm, dmacc,
session_id);
hs20_eventlog_node(ctx, user, realm, session_id,
diff --git a/hs20/server/www/spp.php b/hs20/server/www/spp.php
index dde4434..002d028 100644
--- a/hs20/server/www/spp.php
+++ b/hs20/server/www/spp.php
@@ -96,7 +96,8 @@
putenv("HS20USER");
putenv("HS20REALM=$realm");
-putenv("HS20POST=$HTTP_RAW_POST_DATA");
+$postdata = file_get_contents("php://input");
+putenv("HS20POST=$postdata");
$addr = $_SERVER["REMOTE_ADDR"];
putenv("HS20ADDR=$addr");
diff --git a/src/ap/Makefile b/src/ap/Makefile
index 98788fe..1c65bd6 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -13,9 +13,11 @@
CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_INTERWORKING
CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R_AP
CFLAGS += -DCONFIG_IEEE80211W
CFLAGS += -DCONFIG_WPS
CFLAGS += -DCONFIG_PROXYARP
+CFLAGS += -DCONFIG_IPV6
CFLAGS += -DCONFIG_IAPP
LIB_OBJS= \
@@ -43,14 +45,18 @@
ieee802_11_shared.o \
ieee802_11_vht.o \
ieee802_1x.o \
+ neighbor_db.o \
ndisc_snoop.o \
p2p_hostapd.o \
peerkey_auth.o \
pmksa_cache_auth.o \
preauth_auth.o \
+ rrm.o \
sta_info.o \
tkip_countermeasures.o \
utils.o \
+ vlan.o \
+ vlan_ifconfig.o \
vlan_init.o \
wmm.o \
wnm_ap.o \
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 854174e..0aacc3c 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -50,11 +50,6 @@
return NULL;
}
- if (radius_msg_make_authenticator(msg) < 0) {
- wpa_printf(MSG_INFO, "Could not make Request Authenticator");
- goto fail;
- }
-
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
status_type)) {
wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 66b843c..9abcab7 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -13,6 +13,7 @@
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
#include "common/eapol_common.h"
+#include "common/dhcp.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
@@ -55,6 +56,8 @@
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ bss->wpa_group_update_count = 4;
+ bss->wpa_pairwise_update_count = 4;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
bss->wpa_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP;
@@ -88,13 +91,22 @@
/* Set to -1 as defaults depends on HT in setup */
bss->wmm_enabled = -1;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
bss->ft_over_ds = 1;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
bss->radius_das_time_window = 300;
bss->sae_anti_clogging_threshold = 5;
+
+ bss->gas_frag_limit = 1400;
+
+#ifdef CONFIG_FILS
+ dl_list_init(&bss->fils_realms);
+ bss->fils_hlp_wait_time = 30;
+ bss->dhcp_server_port = DHCP_SERVER_PORT;
+ bss->dhcp_relay_port = DHCP_SERVER_PORT;
+#endif /* CONFIG_FILS */
}
@@ -329,13 +341,7 @@
ssid->wpa_psk->group = 1;
}
- if (ssid->wpa_psk_file) {
- if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
- &conf->ssid))
- return -1;
- }
-
- return 0;
+ return hostapd_config_read_wpa_psk(ssid->wpa_psk_file, &conf->ssid);
}
@@ -384,6 +390,18 @@
}
+void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
+{
+ struct hostapd_eap_user *prev_user;
+
+ while (user) {
+ prev_user = user;
+ user = user->next;
+ hostapd_config_free_eap_user(prev_user);
+ }
+}
+
+
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
@@ -420,10 +438,22 @@
}
+static void hostapd_config_free_fils_realms(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_FILS
+ struct fils_realm *realm;
+
+ while ((realm = dl_list_first(&conf->fils_realms, struct fils_realm,
+ list))) {
+ dl_list_del(&realm->list);
+ os_free(realm);
+ }
+#endif /* CONFIG_FILS */
+}
+
+
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
- struct hostapd_eap_user *user, *prev_user;
-
if (conf == NULL)
return;
@@ -436,12 +466,7 @@
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
- user = conf->eap_user;
- while (user) {
- prev_user = user;
- user = user->next;
- hostapd_config_free_eap_user(prev_user);
- }
+ hostapd_config_free_eap_users(conf->eap_user);
os_free(conf->eap_user_sqlite);
os_free(conf->eap_req_id_text);
@@ -477,7 +502,7 @@
hostapd_config_free_vlan(conf);
os_free(conf->time_zone);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
{
struct ft_remote_r0kh *r0kh, *r0kh_prev;
struct ft_remote_r1kh *r1kh, *r1kh_prev;
@@ -498,7 +523,7 @@
os_free(r1kh_prev);
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_WPS
os_free(conf->wps_pin_requests);
@@ -567,6 +592,7 @@
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+ wpabuf_free(conf->assocresp_elements);
os_free(conf->sae_groups);
@@ -581,6 +607,8 @@
os_free(conf->no_probe_resp_if_seen_on);
os_free(conf->no_auth_if_seen_on);
+ hostapd_config_free_fils_realms(conf);
+
os_free(conf);
}
@@ -606,6 +634,8 @@
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
#endif /* CONFIG_ACS */
+ wpabuf_free(conf->lci);
+ wpabuf_free(conf->civic);
os_free(conf);
}
@@ -799,7 +829,7 @@
}
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
(bss->nas_identifier == NULL ||
os_strlen(bss->nas_identifier) < 1 ||
@@ -809,7 +839,7 @@
"string");
return -1;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211N
if (full_config && conf->ieee80211n &&
@@ -838,6 +868,25 @@
}
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (full_config && conf->ieee80211ac &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11ac = 1;
+ wpa_printf(MSG_ERROR,
+ "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
+ }
+
+ if (full_config && conf->ieee80211ac && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+ {
+ bss->disable_11ac = 1;
+ wpa_printf(MSG_ERROR,
+ "VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
+ }
+#endif /* CONFIG_IEEE80211AC */
+
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2d07c67..fdd5a1a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -41,6 +41,10 @@
#define MESH_CONF_SEC_AUTH BIT(1)
#define MESH_CONF_SEC_AMPE BIT(2)
unsigned int security;
+ enum mfp_options ieee80211w;
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ unsigned int mgmt_group_cipher;
int dot11MeshMaxRetries;
int dot11MeshRetryTimeout; /* msec */
int dot11MeshConfirmTimeout; /* msec */
@@ -220,6 +224,12 @@
struct wpabuf *payload;
};
+struct fils_realm {
+ struct dl_list list;
+ u8 hash[2];
+ char realm[];
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
@@ -259,6 +269,7 @@
int radius_das_port;
unsigned int radius_das_time_window;
int radius_das_require_event_timestamp;
+ int radius_das_require_message_authenticator;
struct hostapd_ip_addr radius_das_client_addr;
u8 *radius_das_shared_secret;
size_t radius_das_shared_secret_len;
@@ -282,7 +293,7 @@
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
* frames */
- enum {
+ enum macaddr_acl {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
USE_EXTERNAL_RADIUS_AUTH = 2
@@ -319,12 +330,14 @@
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ u32 wpa_group_update_count;
+ u32 wpa_pairwise_update_count;
int rsn_pairwise;
int rsn_preauth;
char *rsn_preauth_interfaces;
int peerkey;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
/* IEEE 802.11r - Fast BSS Transition */
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r1_key_holder[FT_R1KH_ID_LEN];
@@ -334,7 +347,8 @@
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
int ft_over_ds;
-#endif /* CONFIG_IEEE80211R */
+ int ft_psk_generate_local;
+#endif /* CONFIG_IEEE80211R_AP */
char *ctrl_interface; /* directory for UNIX domain sockets */
#ifndef CONFIG_NATIVE_WINDOWS
@@ -503,7 +517,8 @@
struct dl_list anqp_elem; /* list of struct anqp_element */
u16 gas_comeback_delay;
- int gas_frag_limit;
+ size_t gas_frag_limit;
+ int gas_address3;
u8 qos_map_set[16 + 2 * 21];
unsigned int qos_map_set_len;
@@ -557,6 +572,7 @@
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
+ struct wpabuf *assocresp_elements;
unsigned int sae_anti_clogging_threshold;
int *sae_groups;
@@ -572,9 +588,10 @@
#define MESH_ENABLED BIT(0)
int mesh;
- int radio_measurements;
+ u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
int vendor_vht;
+ int use_sta_nsts;
char *no_probe_resp_if_seen_on;
char *no_auth_if_seen_on;
@@ -584,8 +601,42 @@
#ifdef CONFIG_MBO
int mbo_enabled;
#endif /* CONFIG_MBO */
+
+ int ftm_responder;
+ int ftm_initiator;
+
+#ifdef CONFIG_FILS
+ u8 fils_cache_id[FILS_CACHE_ID_LEN];
+ int fils_cache_id_set;
+ struct dl_list fils_realms; /* list of struct fils_realm */
+ struct hostapd_ip_addr dhcp_server;
+ int dhcp_rapid_commit_proxy;
+ unsigned int fils_hlp_wait_time;
+ u16 dhcp_server_port;
+ u16 dhcp_relay_port;
+#endif /* CONFIG_FILS */
+
+ int multicast_to_unicast;
};
+/**
+ * struct he_phy_capabilities_info - HE PHY capabilities
+ */
+struct he_phy_capabilities_info {
+ Boolean he_su_beamformer;
+ Boolean he_su_beamformee;
+ Boolean he_mu_beamformer;
+};
+
+/**
+ * struct he_operation - HE operation
+ */
+struct he_operation {
+ u8 he_bss_color;
+ u8 he_default_pe_duration;
+ u8 he_twt_required;
+ u8 he_rts_threshold;
+};
/**
* struct hostapd_config - Per-radio interface configuration
@@ -609,6 +660,8 @@
int *supported_rates;
int *basic_rates;
+ unsigned int beacon_rate;
+ enum beacon_rate_type rate_type;
const struct wpa_driver_ops *driver;
char *driver_params;
@@ -693,6 +746,16 @@
} *acs_chan_bias;
unsigned int num_acs_chan_bias;
#endif /* CONFIG_ACS */
+
+ struct wpabuf *lci;
+ struct wpabuf *civic;
+ int stationary_ap;
+
+ int ieee80211ax;
+#ifdef CONFIG_IEEE80211AX
+ struct he_phy_capabilities_info he_phy_capab;
+ struct he_operation he_op;
+#endif /* CONFIG_IEEE80211AX */
};
@@ -700,6 +763,7 @@
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
+void hostapd_config_free_eap_users(struct hostapd_eap_user *user);
void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index b89f60e..f139465 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -179,6 +179,7 @@
add_buf(&beacon, hapd->conf->vendor_elements);
add_buf(&proberesp, hapd->conf->vendor_elements);
+ add_buf(&assocresp, hapd->conf->assocresp_elements);
*beacon_ret = beacon;
*proberesp_ret = proberesp;
@@ -362,7 +363,8 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo, u8 vht_opmode, int set)
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+ int set)
{
struct hostapd_sta_add_params params;
@@ -384,6 +386,7 @@
params.vht_opmode = vht_opmode;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
+ params.support_p2p_ps = supp_p2p_ps;
params.set = set;
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
}
@@ -620,7 +623,7 @@
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len, int noack)
{
- if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+ if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
NULL, 0);
@@ -641,7 +644,7 @@
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
- if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+ if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
return 0;
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
reason);
@@ -651,7 +654,7 @@
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
- if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+ if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
return 0;
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
@@ -672,6 +675,36 @@
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
{
+ const u8 *bssid;
+ const u8 wildcard_bssid[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
+ return 0;
+ bssid = hapd->own_addr;
+ if (!is_multicast_ether_addr(dst) &&
+ len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+ struct sta_info *sta;
+
+ /*
+ * Public Action frames to a STA that is not a member of the BSS
+ * shall use wildcard BSSID value.
+ */
+ sta = ap_get_sta(hapd, dst);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC))
+ bssid = wildcard_bssid;
+ }
+ return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+ hapd->own_addr, bssid, data, len, 0);
+}
+
+
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *data, size_t len)
+{
if (hapd->driver == NULL || hapd->driver->send_action == NULL)
return 0;
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
@@ -721,7 +754,7 @@
int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
const u8 *qos_map_set, u8 qos_map_set_len)
{
- if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
+ if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
return 0;
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
qos_map_set_len);
@@ -747,6 +780,20 @@
}
+void hostapd_get_ext_capa(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+
+ if (!hapd->driver || !hapd->driver->get_ext_capab)
+ return;
+
+ hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
+ &iface->extended_capa,
+ &iface->extended_capa_mask,
+ &iface->extended_capa_len);
+}
+
+
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 757a706..0bb7954 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -41,7 +41,8 @@
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
- u32 flags, u8 qosinfo, u8 vht_opmode, int set);
+ u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
+ int set);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
@@ -98,6 +99,10 @@
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len);
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *data, size_t len);
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg);
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
@@ -123,6 +128,8 @@
int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
u8 qos_map_set_len);
+void hostapd_get_ext_capa(struct hostapd_iface *iface);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
@@ -153,7 +160,7 @@
static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
const u8 *addr)
{
- if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+ if (!hapd->driver || !hapd->driver->sta_remove || !hapd->drv_priv)
return 0;
return hapd->driver->sta_remove(hapd->drv_priv, addr);
}
@@ -276,7 +283,7 @@
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
- if (hapd->driver == NULL || hapd->driver->status == NULL)
+ if (!hapd->driver || !hapd->driver->status || !hapd->drv_priv)
return -1;
return hapd->driver->status(hapd->drv_priv, buf, buflen);
}
@@ -335,7 +342,7 @@
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
{
- if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+ if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
return 0;
return hapd->driver->stop_ap(hapd->drv_priv);
}
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index e7308a0..db8a267 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -57,7 +57,11 @@
HOSTAPD_LEVEL_DEBUG,
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
- if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
+ if (sta->auth_alg != WLAN_AUTH_FT &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
+ sta->auth_alg != WLAN_AUTH_FILS_PK &&
+ !(sta->flags & WLAN_STA_MFP))
mlme_deletekeys_request(hapd, sta);
ap_sta_clear_disconnect_timeouts(hapd, sta);
}
@@ -105,7 +109,10 @@
HOSTAPD_LEVEL_DEBUG,
"MLME-ASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
- if (sta->auth_alg != WLAN_AUTH_FT)
+ if (sta->auth_alg != WLAN_AUTH_FT &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
+ sta->auth_alg != WLAN_AUTH_FILS_PK)
mlme_deletekeys_request(hapd, sta);
ap_sta_clear_disconnect_timeouts(hapd, sta);
}
@@ -130,7 +137,10 @@
HOSTAPD_LEVEL_DEBUG,
"MLME-REASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
- if (sta->auth_alg != WLAN_AUTH_FT)
+ if (sta->auth_alg != WLAN_AUTH_FT &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK &&
+ sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
+ sta->auth_alg != WLAN_AUTH_FILS_PK)
mlme_deletekeys_request(hapd, sta);
ap_sta_clear_disconnect_timeouts(hapd, sta);
}
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 19bff7b..c6bbda3 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -29,6 +29,7 @@
#include "beacon.h"
#include "hs20.h"
#include "dfs.h"
+#include "taxonomy.h"
#ifdef NEED_AP_MLME
@@ -36,18 +37,21 @@
static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
size_t len)
{
- if (!hapd->conf->radio_measurements || len < 2 + 4)
+ size_t i;
+
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i])
+ break;
+ }
+
+ if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
return eid;
*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
- *eid++ = 5;
- *eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
- WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- *eid++ = 0x00;
- return eid;
+ *eid++ = RRM_CAPABILITIES_IE_LEN;
+ os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
+
+ return eid + RRM_CAPABILITIES_IE_LEN;
}
@@ -388,6 +392,13 @@
2 + sizeof(struct ieee80211_vht_operation);
}
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ buflen += 4 + sizeof (struct ieee80211_he_capabilities) +
+ 4 + sizeof (struct ieee80211_he_operation);
+ }
+#endif
+
buflen += hostapd_mbo_ie_len(hapd);
resp = os_zalloc(buflen);
@@ -482,15 +493,27 @@
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
}
+#endif /* CONFIG_IEEE80211AC */
+
+ pos = hostapd_eid_fils_indic(hapd, pos, 0);
+
+#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ pos = hostapd_eid_vendor_he_capab(hapd, pos);
+ pos = hostapd_eid_vendor_he_operation(hapd, pos);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -596,7 +619,7 @@
MAC2STR(info->addr));
dl_list_del(&info->list);
iface->num_sta_seen--;
- os_free(info);
+ sta_track_del(info);
}
}
@@ -614,7 +637,7 @@
}
-void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal)
{
struct hostapd_sta_info *info;
@@ -624,13 +647,17 @@
dl_list_del(&info->list);
dl_list_add_tail(&iface->sta_seen, &info->list);
os_get_reltime(&info->last_seen);
+ info->ssi_signal = ssi_signal;
return;
}
/* Add a new entry */
info = os_zalloc(sizeof(*info));
+ if (info == NULL)
+ return;
os_memcpy(info->addr, addr, ETH_ALEN);
os_get_reltime(&info->last_seen);
+ info->ssi_signal = ssi_signal;
if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
/* Expire oldest entry to make room for a new one */
@@ -670,6 +697,23 @@
}
+#ifdef CONFIG_TAXONOMY
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+ struct wpabuf **probe_ie_taxonomy)
+{
+ struct hostapd_sta_info *info;
+
+ info = sta_track_get(iface, addr);
+ if (!info)
+ return;
+
+ wpabuf_free(*probe_ie_taxonomy);
+ *probe_ie_taxonomy = info->probe_ie_taxonomy;
+ info->probe_ie_taxonomy = NULL;
+}
+#endif /* CONFIG_TAXONOMY */
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@@ -689,7 +733,7 @@
return;
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
if (hapd->iconf->track_sta_max_num)
- sta_track_add(hapd->iface, mgmt->sa);
+ sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
ie_len = len - IEEE80211_HDRLEN;
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
@@ -779,6 +823,21 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_TAXONOMY
+ {
+ struct sta_info *sta;
+ struct hostapd_sta_info *info;
+
+ if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
+ taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
+ } else if ((info = sta_track_get(hapd->iface,
+ mgmt->sa)) != NULL) {
+ taxonomy_hostapd_sta_info_probe_req(hapd, info,
+ ie, ie_len);
+ }
+ }
+#endif /* CONFIG_TAXONOMY */
+
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
elems.ssid_list, elems.ssid_list_len);
if (res == NO_SSID_MATCH) {
@@ -947,6 +1006,16 @@
#endif /* NEED_AP_MLME */
+void sta_track_del(struct hostapd_sta_info *info)
+{
+#ifdef CONFIG_TAXONOMY
+ wpabuf_free(info->probe_ie_taxonomy);
+ info->probe_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+ os_free(info);
+}
+
+
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@@ -985,6 +1054,13 @@
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ tail_len += 4 + sizeof (struct ieee80211_he_capabilities) +
+ 4 + sizeof (struct ieee80211_he_operation);
+ }
+#endif
+
tail_len += hostapd_mbo_ie_len(hapd);
tailpos = tail = os_malloc(tail_len);
@@ -1102,15 +1178,27 @@
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
}
+#endif /* CONFIG_IEEE80211AC */
+
+ tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+
+#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ tailpos = hostapd_eid_vendor_he_capab(hapd, tailpos);
+ tailpos = hostapd_eid_vendor_he_operation(hapd, tailpos);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -1163,6 +1251,8 @@
params->dtim_period = hapd->conf->dtim_period;
params->beacon_int = hapd->iconf->beacon_int;
params->basic_rates = hapd->iface->basic_rates;
+ params->beacon_rate = hapd->iconf->beacon_rate;
+ params->rate_type = hapd->iconf->rate_type;
params->ssid = hapd->conf->ssid.ssid;
params->ssid_len = hapd->conf->ssid.ssid_len;
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
@@ -1226,6 +1316,7 @@
params->osen = 1;
}
#endif /* CONFIG_HS20 */
+ params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
params->pbss = hapd->conf->pbss;
return 0;
}
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index d98f42e..a26e308 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -21,10 +21,13 @@
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params);
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
-void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal);
+void sta_track_del(struct hostapd_sta_info *info);
void sta_track_expire(struct hostapd_iface *iface, int force);
struct hostapd_data *
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
const char *ifname);
+void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
+ struct wpabuf **probe_ie_taxonomy);
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 317b238..a760e3a 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -23,6 +23,7 @@
#include "ctrl_iface_ap.h"
#include "ap_drv_ops.h"
#include "mbo_ap.h"
+#include "taxonomy.h"
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
@@ -36,9 +37,9 @@
return 0;
ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
- "rx_bytes=%llu\ntx_bytes=%llu\n",
+ "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
data.rx_packets, data.tx_packets,
- data.rx_bytes, data.tx_bytes);
+ data.rx_bytes, data.tx_bytes, data.inactive_msec);
if (os_snprintf_error(buflen, ret))
return 0;
return ret;
@@ -258,7 +259,7 @@
int ret;
u8 *pos;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
mgmt = os_zalloc(sizeof(*mgmt) + 100);
@@ -269,7 +270,7 @@
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
" with minor reason code %u (stype=%u (%s))",
MAC2STR(addr), minor_reason_code, stype,
- fc2str(mgmt->frame_control));
+ fc2str(le_to_host16(mgmt->frame_control)));
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -325,7 +326,7 @@
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
@@ -352,7 +353,10 @@
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_deauth(hapd, addr, reason);
+ if (os_strstr(txtaddr, " tx=0"))
+ hostapd_drv_sta_remove(hapd, addr);
+ else
+ hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_deauthenticate(hapd, sta, reason);
@@ -385,7 +389,7 @@
if (pos) {
struct ieee80211_mgmt mgmt;
int encrypt;
- if (hapd->driver->send_frame == NULL)
+ if (!hapd->drv_priv || !hapd->driver->send_frame)
return -1;
pos += 6;
encrypt = atoi(pos);
@@ -412,7 +416,10 @@
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_disassoc(hapd, addr, reason);
+ if (os_strstr(txtaddr, " tx=0"))
+ hostapd_drv_sta_remove(hapd, addr);
+ else
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
ap_sta_disassociate(hapd, sta, reason);
@@ -423,6 +430,49 @@
}
+#ifdef CONFIG_TAXONOMY
+int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
+}
+#endif /* CONFIG_TAXONOMY */
+
+
+int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta)
+ return -1;
+
+ hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
+ sta->flags & WLAN_STA_WMM);
+ return 0;
+}
+
+
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
@@ -487,20 +537,28 @@
"channel=%u\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
- "ieee80211ac=%d\n"
- "vht_oper_chwidth=%d\n"
- "vht_oper_centr_freq_seg0_idx=%d\n"
- "vht_oper_centr_freq_seg1_idx=%d\n",
+ "ieee80211ac=%d\n",
iface->conf->channel,
- iface->conf->secondary_channel,
- iface->conf->ieee80211n,
- iface->conf->ieee80211ac,
- iface->conf->vht_oper_chwidth,
- iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx);
+ iface->conf->ieee80211n && !hapd->conf->disable_11n ?
+ iface->conf->secondary_channel : 0,
+ iface->conf->ieee80211n && !hapd->conf->disable_11n,
+ iface->conf->ieee80211ac &&
+ !hapd->conf->disable_11ac);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+ if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "vht_oper_chwidth=%d\n"
+ "vht_oper_centr_freq_seg0_idx=%d\n"
+ "vht_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *bss = iface->bss[i];
@@ -581,3 +639,60 @@
{
wpa_auth_pmksa_flush(hapd->wpa_auth);
}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
+ const u8 *addr, char *buf, size_t len)
+{
+ return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
+}
+
+
+void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
+{
+ u8 spa[ETH_ALEN];
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN_MAX];
+ char *pos;
+ int expiration;
+
+ /*
+ * Entry format:
+ * <BSSID> <PMKID> <PMK> <expiration in seconds>
+ */
+
+ if (hwaddr_aton(cmd, spa))
+ return NULL;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return NULL;
+ pos++;
+
+ if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
+ return NULL;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return NULL;
+ pos++;
+
+ if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
+ return NULL;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return NULL;
+ pos++;
+
+ if (sscanf(pos, "%d", &expiration) != 1)
+ return NULL;
+
+ return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index 3ad622f..3b61cac 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -19,6 +19,11 @@
const char *txtaddr);
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
const char *txtaddr);
+int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
+ const char *txtaddr,
+ char *buf, size_t buflen);
+int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
+ const char *txtaddr);
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
size_t buflen);
int hostapd_parse_csa_settings(const char *pos,
@@ -27,5 +32,8 @@
int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
size_t len);
void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
+int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
+ const u8 *addr, char *buf, size_t len);
+void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index 3a77225..b9a36d7 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -7,10 +7,9 @@
*/
#include "utils/includes.h"
-#include <netinet/ip.h>
-#include <netinet/udp.h>
#include "utils/common.h"
+#include "common/dhcp.h"
#include "l2_packet/l2_packet.h"
#include "hostapd.h"
#include "sta_info.h"
@@ -18,29 +17,6 @@
#include "x_snoop.h"
#include "dhcp_snoop.h"
-struct bootp_pkt {
- struct iphdr iph;
- struct udphdr udph;
- u8 op;
- u8 htype;
- u8 hlen;
- u8 hops;
- be32 xid;
- be16 secs;
- be16 flags;
- be32 client_ip;
- be32 your_ip;
- be32 server_ip;
- be32 relay_ip;
- u8 hw_addr[16];
- u8 serv_name[64];
- u8 boot_file[128];
- u8 exten[312];
-} STRUCT_PACKED;
-
-#define DHCPACK 5
-static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
-
static const char * ipaddr_str(u32 addr)
{
@@ -74,24 +50,26 @@
if (tot_len > (unsigned int) (len - ETH_HLEN))
return;
- if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
+ if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
end = (const u8 *) b + tot_len;
pos = &b->exten[4];
- while (pos < end && *pos != 0xff) {
+ while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;
- if (*opt == 0) /* padding */
+ if (*opt == DHCP_OPT_PAD)
continue;
+ if (pos >= end || 1 + *pos > end - pos)
+ break;
pos += *pos + 1;
if (pos >= end)
break;
switch (*opt) {
- case 1: /* subnet mask */
+ case DHCP_OPT_SUBNET_MASK:
if (opt[1] == 4)
subnet_mask = WPA_GET_BE32(&opt[2]);
if (subnet_mask == 0)
@@ -101,7 +79,7 @@
prefixlen--;
}
break;
- case 53: /* message type */
+ case DHCP_OPT_MSG_TYPE:
if (opt[1])
msgtype = opt[2];
break;
@@ -121,7 +99,8 @@
wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
" @ IPv4 address %s/%d",
- MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
+ MAC2STR(sta->addr),
+ ipaddr_str(be_to_host32(b->your_ip)),
prefixlen);
if (sta->ipaddr == b->your_ip)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3ab5bf3..f69c655 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -45,10 +45,10 @@
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@@ -116,8 +116,15 @@
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
- res = hostapd_check_acl(hapd, addr, NULL);
- if (res != HOSTAPD_ACL_ACCEPT) {
+ /*
+ * ACL configurations to the drivers (implementing AP SME and ACL
+ * offload) without hostapd's knowledge, can result in a disconnection
+ * though the driver accepts the connection. Skip the hostapd check for
+ * ACL if the driver supports ACL offload to avoid potentially
+ * conflicting ACL rules.
+ */
+ if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
+ hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
MAC2STR(addr));
reason = WLAN_REASON_UNSPECIFIED;
@@ -286,7 +293,7 @@
sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
req_ies_len);
@@ -300,7 +307,7 @@
goto fail;
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -368,7 +375,7 @@
skip_wpa_check:
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
sta->auth_alg, req_ies, req_ies_len);
@@ -376,11 +383,11 @@
if (sta->auth_alg == WLAN_AUTH_FT)
ap_sta_set_authorized(hapd, sta, 1);
-#else /* CONFIG_IEEE80211R */
+#else /* CONFIG_IEEE80211R_AP */
/* Keep compiler silent about unused variables */
if (status) {
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -407,9 +414,9 @@
return 0;
fail:
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
return -1;
@@ -464,8 +471,7 @@
HOSTAPD_LEVEL_INFO,
"disconnected due to excessive missing ACKs");
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
- if (sta)
- ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
+ ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
}
@@ -683,7 +689,7 @@
#ifdef HOSTAPD
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
const u8 *bssid,
u16 auth_transaction, u16 status,
@@ -702,7 +708,7 @@
hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
static void hostapd_notif_auth(struct hostapd_data *hapd,
@@ -723,7 +729,7 @@
}
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
sta->auth_alg = WLAN_AUTH_FT;
if (sta->wpa_sm == NULL)
@@ -741,7 +747,7 @@
hostapd_notify_auth_ft_finish, hapd);
return;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
fail:
hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
status, resp_ies, resp_ies_len);
@@ -774,13 +780,13 @@
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
return;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (mgmt->u.action.category == WLAN_ACTION_FT) {
const u8 *payload = drv_mgmt->frame + 24 + 1;
wpa_ft_action_rx(sta->wpa_sm, payload, plen);
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
ieee802_11_sa_query_action(
@@ -916,11 +922,24 @@
size_t len, u16 stype, int ok)
{
struct ieee80211_hdr *hdr;
+ struct hostapd_data *orig_hapd = hapd;
hdr = (struct ieee80211_hdr *) buf;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
- if (hapd == NULL || hapd == HAPD_BROADCAST)
+ if (!hapd)
return;
+ if (hapd == HAPD_BROADCAST) {
+ if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
+ buf[24] != WLAN_ACTION_PUBLIC)
+ return;
+ hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
+ if (!hapd || hapd == HAPD_BROADCAST)
+ return;
+ /*
+ * Allow processing of TX status for a Public Action frame that
+ * used wildcard BBSID.
+ */
+ }
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
}
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
new file mode 100644
index 0000000..40d9be1
--- /dev/null
+++ b/src/ap/fils_hlp.c
@@ -0,0 +1,636 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * 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 "common/dhcp.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ieee802_11.h"
+#include "fils_hlp.h"
+
+
+static be16 ip_checksum(const void *buf, size_t len)
+{
+ u32 sum = 0;
+ const u16 *pos;
+
+ for (pos = buf; len >= 2; len -= 2)
+ sum += ntohs(*pos++);
+ if (len)
+ sum += ntohs(*pos << 8);
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += sum >> 16;
+ return htons(~sum);
+}
+
+
+static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta,
+ struct dhcp_data *dhcpoffer, u8 *dhcpofferend)
+{
+ u8 *pos, *end;
+ struct dhcp_data *dhcp;
+ struct sockaddr_in addr;
+ ssize_t res;
+ const u8 *server_id = NULL;
+
+ if (!sta->hlp_dhcp_discover) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No pending HLP DHCPDISCOVER available");
+ return -1;
+ }
+
+ /* Convert to DHCPREQUEST, remove rapid commit option, replace requested
+ * IP address option with yiaddr. */
+ pos = wpabuf_mhead(sta->hlp_dhcp_discover);
+ end = pos + wpabuf_len(sta->hlp_dhcp_discover);
+ dhcp = (struct dhcp_data *) pos;
+ pos = (u8 *) (dhcp + 1);
+ pos += 4; /* skip magic */
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ *pos = DHCPREQUEST;
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ case DHCP_OPT_REQUESTED_IP_ADDRESS:
+ case DHCP_OPT_SERVER_ID:
+ /* Remove option */
+ pos -= 2;
+ os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen);
+ end -= 2 + olen;
+ olen = 0;
+ break;
+ }
+ pos += olen;
+ }
+ if (pos >= end || *pos != DHCP_OPT_END) {
+ wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER");
+ return -1;
+ }
+ sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp;
+
+ /* Copy Server ID option from DHCPOFFER to DHCPREQUEST */
+ pos = (u8 *) (dhcpoffer + 1);
+ end = dhcpofferend;
+ pos += 4; /* skip magic */
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_SERVER_ID:
+ server_id = pos - 2;
+ break;
+ }
+ pos += olen;
+ }
+
+ if (wpabuf_resize(&sta->hlp_dhcp_discover,
+ 6 + 1 + (server_id ? 2 + server_id[1] : 0)))
+ return -1;
+ if (server_id)
+ wpabuf_put_data(sta->hlp_dhcp_discover, server_id,
+ 2 + server_id[1]);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, 4);
+ wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END);
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_server_port);
+ res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover),
+ wpabuf_len(sta->hlp_dhcp_discover), 0,
+ (const struct sockaddr *) &addr, sizeof(addr));
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "FILS: Acting as DHCP rapid commit proxy for %s:%d",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+ sta->fils_dhcp_rapid_commit_proxy = 1;
+ return 0;
+}
+
+
+static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = sock_ctx;
+ struct sta_info *sta;
+ u8 buf[1500], *pos, *end, *end_opt = NULL;
+ struct dhcp_data *dhcp;
+ struct sockaddr_in addr;
+ socklen_t addr_len;
+ ssize_t res;
+ u8 msgtype = 0;
+ int rapid_commit = 0;
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct wpabuf *resp;
+ const u8 *rpos;
+ size_t left, len;
+
+ addr_len = sizeof(addr);
+ res = recvfrom(sd, buf, sizeof(buf), 0,
+ (struct sockaddr *) &addr, &addr_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s",
+ strerror(errno));
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res);
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res);
+ if ((size_t) res < sizeof(*dhcp))
+ return;
+ dhcp = (struct dhcp_data *) buf;
+ if (dhcp->op != 2)
+ return; /* Not a BOOTREPLY */
+ if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - DHCP response to unknown relay address 0x%x",
+ dhcp->relay_ip);
+ return;
+ }
+ dhcp->relay_ip = 0;
+ pos = (u8 *) (dhcp + 1);
+ end = &buf[res];
+
+ if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) {
+ wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response");
+ return;
+ }
+ pos += 4;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response",
+ pos, end - pos);
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ msgtype = pos[0];
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ rapid_commit = 1;
+ break;
+ }
+ pos += olen;
+ }
+ if (pos < end && *pos == DHCP_OPT_END)
+ end_opt = pos;
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr="
+ MACSTR ")",
+ msgtype, rapid_commit, MAC2STR(dhcp->hw_addr));
+
+ sta = ap_get_sta(hapd, dhcp->hw_addr);
+ if (!sta || !sta->fils_pending_assoc_req) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No pending HLP DHCP exchange with hw_addr"
+ MACSTR, MAC2STR(dhcp->hw_addr));
+ return;
+ }
+
+ if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER &&
+ !rapid_commit) {
+ /* Use hostapd to take care of 4-message exchange and convert
+ * the final DHCPACK to rapid commit version. */
+ if (fils_dhcp_request(hapd, sta, dhcp, end) == 0)
+ return;
+ /* failed, so send the server response as-is */
+ } else if (msgtype != DHCPACK) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No DHCPACK available from the server and cannot do rapid commit proxying");
+ }
+
+ pos = buf;
+ resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 +
+ sizeof(*iph) + sizeof(*udph) + (end - pos) + 2);
+ if (!resp)
+ return;
+ wpabuf_put_data(resp, sta->addr, ETH_ALEN);
+ wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN);
+ wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
+ wpabuf_put_be16(resp, ETH_P_IP);
+ iph = wpabuf_put(resp, sizeof(*iph));
+ iph->version = 4;
+ iph->ihl = sizeof(*iph) / 4;
+ iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+ iph->ttl = 1;
+ iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
+ iph->daddr = dhcp->client_ip;
+ iph->check = ip_checksum(iph, sizeof(*iph));
+ udph = wpabuf_put(resp, sizeof(*udph));
+ udph->uh_sport = htons(DHCP_SERVER_PORT);
+ udph->uh_dport = htons(DHCP_CLIENT_PORT);
+ udph->len = htons(sizeof(*udph) + (end - pos));
+ udph->check = htons(0x0000); /* TODO: calculate checksum */
+ if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK &&
+ !rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) {
+ /* Add rapid commit option */
+ wpabuf_put_data(resp, pos, end_opt - pos);
+ wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT);
+ wpabuf_put_u8(resp, 0);
+ wpabuf_put_data(resp, end_opt, end - end_opt);
+ } else {
+ wpabuf_put_data(resp, pos, end - pos);
+ }
+ if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) +
+ 2 * wpabuf_len(resp) / 255 + 100)) {
+ wpabuf_free(resp);
+ return;
+ }
+
+ rpos = wpabuf_head(resp);
+ left = wpabuf_len(resp);
+
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */
+ if (left <= 254)
+ len = 1 + left;
+ else
+ len = 255;
+ wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER);
+ /* Destination MAC Address, Source MAC Address, HLP Packet.
+ * HLP Packet is in MSDU format (i.e., including the LLC/SNAP header
+ * when LPD is used). */
+ wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1);
+ rpos += len - 1;
+ left -= len - 1;
+ while (left) {
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT);
+ len = left > 255 ? 255 : left;
+ wpabuf_put_u8(sta->fils_hlp_resp, len);
+ wpabuf_put_data(sta->fils_hlp_resp, rpos, len);
+ rpos += len;
+ left -= len;
+ }
+ wpabuf_free(resp);
+ fils_hlp_finish_assoc(hapd, sta);
+}
+
+
+static int fils_process_hlp_dhcp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *msg, size_t len)
+{
+ const struct dhcp_data *dhcp;
+ struct wpabuf *dhcp_buf;
+ struct dhcp_data *dhcp_msg;
+ u8 msgtype = 0;
+ int rapid_commit = 0;
+ const u8 *pos = msg, *end;
+ struct sockaddr_in addr;
+ ssize_t res;
+
+ if (len < sizeof(*dhcp))
+ return 0;
+ dhcp = (const struct dhcp_data *) pos;
+ end = pos + len;
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x",
+ dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops,
+ ntohl(dhcp->xid));
+ pos += sizeof(*dhcp);
+ if (dhcp->op != 1)
+ return 0; /* Not a BOOTREQUEST */
+
+ if (end - pos < 4)
+ return 0;
+ if (WPA_GET_BE32(pos) != DHCP_MAGIC) {
+ wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic");
+ return 0;
+ }
+ pos += 4;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos);
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ msgtype = pos[0];
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ rapid_commit = 1;
+ break;
+ }
+ pos += olen;
+ }
+
+ wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype);
+ if (msgtype != DHCPDISCOVER)
+ return 0;
+
+ if (hapd->conf->dhcp_server.af != AF_INET ||
+ hapd->conf->dhcp_server.u.v4.s_addr == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - no DHCPv4 server configured - drop request");
+ return 0;
+ }
+
+ if (hapd->conf->own_ip_addr.af != AF_INET ||
+ hapd->conf->own_ip_addr.u.v4.s_addr == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - no IPv4 own_ip_addr configured - drop request");
+ return 0;
+ }
+
+ if (hapd->dhcp_sock < 0) {
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to open DHCP socket: %s",
+ strerror(errno));
+ return 0;
+ }
+
+ if (hapd->conf->dhcp_relay_port) {
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr =
+ hapd->conf->own_ip_addr.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_relay_port);
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to bind DHCP socket: %s",
+ strerror(errno));
+ close(s);
+ return 0;
+ }
+ }
+ if (eloop_register_sock(s, EVENT_TYPE_READ,
+ fils_dhcp_handler, NULL, hapd)) {
+ close(s);
+ return 0;
+ }
+
+ hapd->dhcp_sock = s;
+ }
+
+ dhcp_buf = wpabuf_alloc(len);
+ if (!dhcp_buf)
+ return 0;
+ dhcp_msg = wpabuf_put(dhcp_buf, len);
+ os_memcpy(dhcp_msg, msg, len);
+ dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr;
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_server_port);
+ res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0,
+ (const struct sockaddr *) &addr, sizeof(addr));
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+ strerror(errno));
+ wpabuf_free(dhcp_buf);
+ /* Close the socket to try to recover from error */
+ eloop_unregister_read_sock(hapd->dhcp_sock);
+ close(hapd->dhcp_sock);
+ hapd->dhcp_sock = -1;
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
+ rapid_commit);
+ if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) {
+ /* Store a copy of the DHCPDISCOVER for rapid commit proxying
+ * purposes if the server does not support the rapid commit
+ * option. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Store DHCPDISCOVER for rapid commit proxy");
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = dhcp_buf;
+ } else {
+ wpabuf_free(dhcp_buf);
+ }
+
+ return 1;
+}
+
+
+static int fils_process_hlp_udp(struct hostapd_data *hapd,
+ struct sta_info *sta, const u8 *dst,
+ const u8 *pos, size_t len)
+{
+ const struct iphdr *iph;
+ const struct udphdr *udph;
+ u16 sport, dport, ulen;
+
+ if (len < sizeof(*iph) + sizeof(*udph))
+ return 0;
+ iph = (const struct iphdr *) pos;
+ udph = (const struct udphdr *) (iph + 1);
+ sport = ntohs(udph->uh_sport);
+ dport = ntohs(udph->uh_dport);
+ ulen = ntohs(udph->uh_ulen);
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x",
+ sport, dport, ulen, ntohs(udph->uh_sum));
+ /* TODO: Check UDP checksum */
+ if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph))
+ return 0;
+
+ if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) {
+ return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1),
+ ulen - sizeof(*udph));
+ }
+
+ return 0;
+}
+
+
+static int fils_process_hlp_ip(struct hostapd_data *hapd,
+ struct sta_info *sta, const u8 *dst,
+ const u8 *pos, size_t len)
+{
+ const struct iphdr *iph;
+ u16 tot_len;
+
+ if (len < sizeof(*iph))
+ return 0;
+ iph = (const struct iphdr *) pos;
+ if (ip_checksum(iph, sizeof(*iph)) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request IPv4 packet had invalid header checksum - dropped");
+ return 0;
+ }
+ tot_len = ntohs(iph->tot_len);
+ if (tot_len > len)
+ return 0;
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
+ iph->saddr, iph->daddr, iph->protocol);
+ switch (iph->protocol) {
+ case 17:
+ return fils_process_hlp_udp(hapd, sta, dst, pos, len);
+ }
+
+ return 0;
+}
+
+
+static int fils_process_hlp_req(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *pos, size_t len)
+{
+ const u8 *pkt, *end;
+
+ wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
+ " src=" MACSTR " len=%u)",
+ MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
+ (unsigned int) len);
+ if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Ignore HLP request with unexpected source address"
+ MACSTR, MAC2STR(pos + ETH_ALEN));
+ return 0;
+ }
+
+ end = pos + len;
+ pkt = pos + 2 * ETH_ALEN;
+ if (end - pkt >= 6 &&
+ os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+ pkt += 6; /* Remove SNAP/LLC header */
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
+
+ if (end - pkt < 2)
+ return 0;
+
+ switch (WPA_GET_BE16(pkt)) {
+ case ETH_P_IP:
+ return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
+ end - pkt - 2);
+ }
+
+ return 0;
+}
+
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, int left)
+{
+ const u8 *end = pos + left;
+ u8 *tmp, *tmp_pos;
+ int ret = 0;
+
+ /* Old DHCPDISCOVER is not needed anymore, if it was still pending */
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+ sta->fils_dhcp_rapid_commit_proxy = 0;
+
+ /* Check if there are any FILS HLP Container elements */
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ return 0;
+ if (pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + 2 * ETH_ALEN &&
+ pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ pos += 2 + pos[1];
+ }
+ if (end - pos < 2)
+ return 0; /* No FILS HLP Container elements */
+
+ tmp = os_malloc(end - pos);
+ if (!tmp)
+ return 0;
+
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos ||
+ pos[0] != WLAN_EID_EXTENSION ||
+ pos[1] < 1 + 2 * ETH_ALEN ||
+ pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ tmp_pos = tmp;
+ os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
+ tmp_pos += pos[1] - 1;
+ pos += 2 + pos[1];
+
+ /* Add possible fragments */
+ while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
+ 2 + pos[1] <= end - pos) {
+ os_memcpy(tmp_pos, pos + 2, pos[1]);
+ tmp_pos += pos[1];
+ pos += 2 + pos[1];
+ }
+
+ if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0)
+ ret = 1;
+ }
+
+ os_free(tmp);
+
+ return ret;
+}
+
+
+void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->dhcp_sock >= 0) {
+ eloop_unregister_read_sock(hapd->dhcp_sock);
+ close(hapd->dhcp_sock);
+ hapd->dhcp_sock = -1;
+ }
+}
diff --git a/src/ap/fils_hlp.h b/src/ap/fils_hlp.h
new file mode 100644
index 0000000..e14a6bf
--- /dev/null
+++ b/src/ap/fils_hlp.h
@@ -0,0 +1,27 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef FILS_HLP_H
+#define FILS_HLP_H
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, int left);
+
+#ifdef CONFIG_FILS
+
+void fils_hlp_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_FILS */
+
+static inline void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_FILS */
+
+#endif /* FILS_HLP_H */
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 179dc7a..96cd703 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -50,9 +50,12 @@
sta->flags |= WLAN_STA_GAS;
/*
* The default inactivity is 300 seconds. We don't need
- * it to be that long.
+ * it to be that long. Use five second timeout and increase this
+ * with the comeback_delay for testing cases.
*/
- ap_sta_session_timeout(hapd, sta, 5);
+ ap_sta_session_timeout(hapd, sta,
+ hapd->conf->gas_comeback_delay / 1024 +
+ 5);
} else {
ap_sta_replenish_timeout(hapd, sta, 5);
}
@@ -255,20 +258,29 @@
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
+ if (get_anqp_elem(hapd, ANQP_TDLS_CAPABILITY))
+ wpabuf_put_le16(buf, ANQP_TDLS_CAPABILITY);
if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
- for (id = 273; id < 277; id++) {
- if (get_anqp_elem(hapd, id))
- wpabuf_put_le16(buf, id);
- }
+#ifdef CONFIG_FILS
+ if (!dl_list_empty(&hapd->conf->fils_realms) ||
+ get_anqp_elem(hapd, ANQP_FILS_REALM_INFO))
+ wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
+#endif /* CONFIG_FILS */
+ if (get_anqp_elem(hapd, ANQP_CAG))
+ wpabuf_put_le16(buf, ANQP_CAG);
if (get_anqp_elem(hapd, ANQP_VENUE_URL))
wpabuf_put_le16(buf, ANQP_VENUE_URL);
if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
+ for (id = 280; id < 300; id++) {
+ if (get_anqp_elem(hapd, id))
+ wpabuf_put_le16(buf, id);
+ }
#ifdef CONFIG_HS20
anqp_add_hs_capab_list(hapd, buf);
#endif /* CONFIG_HS20 */
@@ -548,6 +560,36 @@
}
+#ifdef CONFIG_FILS
+static void anqp_add_fils_realm_info(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ size_t count;
+
+ if (anqp_add_override(hapd, buf, ANQP_FILS_REALM_INFO))
+ return;
+
+ count = dl_list_len(&hapd->conf->fils_realms);
+ if (count > 10000)
+ count = 10000;
+ if (count) {
+ struct fils_realm *realm;
+
+ wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
+ wpabuf_put_le16(buf, 2 * count);
+
+ dl_list_for_each(realm, &hapd->conf->fils_realms,
+ struct fils_realm, list) {
+ if (count == 0)
+ break;
+ wpabuf_put_data(buf, realm->hash, 2);
+ count--;
+ }
+ }
+}
+#endif /* CONFIG_FILS */
+
+
#ifdef CONFIG_HS20
static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
@@ -649,7 +691,7 @@
/* OSU Method List */
count = wpabuf_put(buf, 1);
- for (i = 0; p->method_list[i] >= 0; i++)
+ for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
wpabuf_put_u8(buf, p->method_list[i]);
*count = i;
@@ -821,6 +863,10 @@
len += 1000;
if (request & ANQP_REQ_ICON_REQUEST)
len += 65536;
+#ifdef CONFIG_FILS
+ if (request & ANQP_FILS_REALM_INFO)
+ len += 2 * dl_list_len(&hapd->conf->fils_realms);
+#endif /* CONFIG_FILS */
len += anqp_get_required_len(hapd, extra_req, num_extra_req);
buf = wpabuf_alloc(len);
@@ -860,8 +906,15 @@
if (request & ANQP_REQ_EMERGENCY_NAI)
anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
- for (i = 0; i < num_extra_req; i++)
+ for (i = 0; i < num_extra_req; i++) {
+#ifdef CONFIG_FILS
+ if (extra_req[i] == ANQP_FILS_REALM_INFO) {
+ anqp_add_fils_realm_info(hapd, buf);
+ continue;
+ }
+#endif /* CONFIG_FILS */
anqp_add_elem(hapd, buf, extra_req[i]);
+ }
#ifdef CONFIG_HS20
if (request & ANQP_REQ_HS_CAPABILITY_LIST)
@@ -984,6 +1037,13 @@
get_anqp_elem(hapd, info_id) != NULL, qi);
break;
default:
+#ifdef CONFIG_FILS
+ if (info_id == ANQP_FILS_REALM_INFO &&
+ !dl_list_empty(&hapd->conf->fils_realms)) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: FILS Realm Information (local)");
+ } else
+#endif /* CONFIG_FILS */
if (!get_anqp_elem(hapd, info_id)) {
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
info_id);
@@ -1166,7 +1226,8 @@
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
- struct anqp_query_info *qi, int prot)
+ struct anqp_query_info *qi, int prot,
+ int std_addr3)
{
struct wpabuf *buf, *tx_buf;
@@ -1188,7 +1249,7 @@
}
#endif /* CONFIG_P2P */
- if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+ if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
hapd->conf->gas_comeback_delay) {
struct gas_dialog_info *di;
u16 comeback_delay = 1;
@@ -1227,15 +1288,22 @@
return;
if (prot)
convert_to_protected_dual(tx_buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
}
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len, int prot)
+ const u8 *data, size_t len, int prot,
+ int std_addr3)
{
const u8 *pos = data;
const u8 *end = data + len;
@@ -1287,8 +1355,15 @@
wpabuf_put_le16(buf, 0); /* Query Response Length */
if (prot)
convert_to_protected_dual(buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(buf), wpabuf_len(buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(buf),
+ wpabuf_len(buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd,
+ hapd->iface->freq, 0,
+ sa, wpabuf_head(buf),
+ wpabuf_len(buf));
wpabuf_free(buf);
return;
}
@@ -1338,13 +1413,15 @@
pos += elen;
}
- gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
+ gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
+ std_addr3);
}
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len, int prot)
+ const u8 *data, size_t len, int prot,
+ int std_addr3)
{
struct gas_dialog_info *dialog;
struct wpabuf *buf, *tx_buf;
@@ -1376,8 +1453,8 @@
}
frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
- if (frag_len > hapd->gas_frag_limit) {
- frag_len = hapd->gas_frag_limit;
+ if (frag_len > hapd->conf->gas_frag_limit) {
+ frag_len = hapd->conf->gas_frag_limit;
more = 1;
}
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
@@ -1420,8 +1497,14 @@
send_resp:
if (prot)
convert_to_protected_dual(tx_buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
}
@@ -1432,7 +1515,7 @@
struct hostapd_data *hapd = ctx;
const struct ieee80211_mgmt *mgmt;
const u8 *sa, *data;
- int prot;
+ int prot, std_addr3;
mgmt = (const struct ieee80211_mgmt *) buf;
if (len < IEEE80211_HDRLEN + 2)
@@ -1447,14 +1530,22 @@
*/
prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
sa = mgmt->sa;
+ if (hapd->conf->gas_address3 == 1)
+ std_addr3 = 1;
+ else if (hapd->conf->gas_address3 == 2)
+ std_addr3 = 0;
+ else
+ std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
len -= IEEE80211_HDRLEN + 1;
data = buf + IEEE80211_HDRLEN + 1;
switch (data[0]) {
case WLAN_PA_GAS_INITIAL_REQ:
- gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
case WLAN_PA_GAS_COMEBACK_REQ:
- gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
}
}
@@ -1464,9 +1555,6 @@
{
hapd->public_action_cb2 = gas_serv_rx_public_action;
hapd->public_action_cb2_ctx = hapd;
- hapd->gas_frag_limit = 1400;
- if (hapd->conf->gas_frag_limit > 0)
- hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
return 0;
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ee80f4f..cf8a8cb 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -43,6 +43,9 @@
#include "x_snoop.h"
#include "dhcp_snoop.h"
#include "ndisc_snoop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
+#include "fils_hlp.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -73,6 +76,9 @@
{
struct hostapd_ssid *ssid;
+ if (!hapd->started)
+ return;
+
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
#endif /* CONFIG_NO_RADIUS */
@@ -204,10 +210,12 @@
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
- char *ifname)
+ const char *ifname)
{
int i;
+ if (!ifname || !hapd->drv_priv)
+ return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
0, NULL, 0, NULL, 0)) {
@@ -335,6 +343,9 @@
wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL;
#endif /* CONFIG_MESH */
+
+ hostapd_clean_rrm(hapd);
+ fils_hlp_deinit(hapd);
}
@@ -351,8 +362,10 @@
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
hapd->conf->iface);
if (hapd->iface->interfaces &&
- hapd->iface->interfaces->ctrl_iface_deinit)
+ hapd->iface->interfaces->ctrl_iface_deinit) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
hapd->iface->interfaces->ctrl_iface_deinit(hapd);
+ }
hostapd_free_hapd_data(hapd);
}
@@ -368,7 +381,7 @@
list))) {
dl_list_del(&info->list);
iface->num_sta_seen--;
- os_free(info);
+ sta_track_del(info);
}
}
@@ -950,10 +963,10 @@
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (is_zero_ether_addr(conf->r1_key_holder))
os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_MESH
if (hapd->iface->mconf == NULL)
@@ -1037,6 +1050,8 @@
das_conf.time_window = conf->radius_das_time_window;
das_conf.require_event_timestamp =
conf->radius_das_require_event_timestamp;
+ das_conf.require_message_authenticator =
+ conf->radius_das_require_message_authenticator;
das_conf.ctx = hapd;
das_conf.disconnect = hostapd_das_disconnect;
hapd->radius_das = radius_das_init(&das_conf);
@@ -1524,6 +1539,126 @@
#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 */
+}
+
+
static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
int err)
{
@@ -1649,7 +1784,6 @@
hostapd_tx_queue_params(iface);
ap_list_init(iface);
- dl_list_init(&iface->sta_seen);
hostapd_set_acl(hapd);
@@ -1709,6 +1843,9 @@
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
iface->interfaces->terminate_on_error--;
+ for (j = 0; j < iface->num_bss; j++)
+ hostapd_set_own_neighbor_report(iface->bss[j]);
+
return 0;
fail:
@@ -1867,9 +2004,12 @@
hapd->iconf = conf;
hapd->conf = bss;
hapd->iface = hapd_iface;
- hapd->driver = hapd->iconf->driver;
+ if (conf)
+ hapd->driver = conf->driver;
hapd->ctrl_sock = -1;
dl_list_init(&hapd->ctrl_dst);
+ dl_list_init(&hapd->nr_db);
+ hapd->dhcp_sock = -1;
return hapd;
}
@@ -1877,6 +2017,8 @@
static void hostapd_bss_deinit(struct hostapd_data *hapd)
{
+ if (!hapd)
+ return;
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
hapd->conf->iface);
hostapd_bss_deinit_no_free(hapd);
@@ -1911,8 +2053,11 @@
}
#endif /* CONFIG_FST */
- for (j = iface->num_bss - 1; j >= 0; j--)
+ for (j = iface->num_bss - 1; j >= 0; j--) {
+ if (!iface->bss)
+ break;
hostapd_bss_deinit(iface->bss[j]);
+ }
}
@@ -1921,6 +2066,8 @@
size_t j;
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
for (j = 0; j < iface->num_bss; j++) {
+ if (!iface->bss)
+ break;
wpa_printf(MSG_DEBUG, "%s: free hapd %p",
__func__, iface->bss[j]);
os_free(iface->bss[j]);
@@ -1929,6 +2076,20 @@
}
+struct hostapd_iface * hostapd_alloc_iface(void)
+{
+ struct hostapd_iface *hapd_iface;
+
+ hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ if (!hapd_iface)
+ return NULL;
+
+ dl_list_init(&hapd_iface->sta_seen);
+
+ return hapd_iface;
+}
+
+
/**
* hostapd_init - Allocate and initialize per-interface data
* @config_file: Path to the configuration file
@@ -1946,7 +2107,7 @@
struct hostapd_data *hapd;
size_t i;
- hapd_iface = os_zalloc(sizeof(*hapd_iface));
+ hapd_iface = hostapd_alloc_iface();
if (hapd_iface == NULL)
goto fail;
@@ -2282,7 +2443,7 @@
return NULL;
interfaces->iface = iface;
hapd_iface = interfaces->iface[interfaces->count] =
- os_zalloc(sizeof(*hapd_iface));
+ hostapd_alloc_iface();
if (hapd_iface == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
"the interface", __func__);
@@ -2682,7 +2843,16 @@
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
- if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
+ if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: %s: canceled wired ap_handle_timer timeout for "
+ MACSTR,
+ hapd->conf->iface, __func__,
+ MAC2STR(sta->addr));
+ }
+ } else if (!(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
wpa_printf(MSG_DEBUG,
"%s: %s: reschedule ap_handle_timer timeout for "
MACSTR " (%d seconds - ap_max_inactivity)",
@@ -2721,8 +2891,8 @@
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
{
wpa_printf(MSG_INFO, "%s: interface state %s->%s",
- iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
- hostapd_state_text(s));
+ iface->conf ? iface->conf->bss[0]->iface : "N/A",
+ hostapd_state_text(iface->state), hostapd_state_text(s));
iface->state = s;
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 75a7c04..5ab623d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -53,6 +53,7 @@
#ifndef CONFIG_NO_VLAN
struct dynamic_iface *vlan_priv;
#endif /* CONFIG_NO_VLAN */
+ int eloop_initialized;
};
enum hostapd_chan_status {
@@ -99,6 +100,17 @@
u8 peer_addr[ETH_ALEN];
};
+struct hostapd_neighbor_entry {
+ struct dl_list list;
+ u8 bssid[ETH_ALEN];
+ struct wpa_ssid_value ssid;
+ struct wpabuf *nr;
+ struct wpabuf *lci;
+ struct wpabuf *civic;
+ /* LCI update time */
+ struct os_time lci_date;
+ int stationary;
+};
/**
* struct hostapd_data - hostapd per-BSS data structure
@@ -248,9 +260,6 @@
int noa_start;
int noa_duration;
#endif /* CONFIG_P2P */
-#ifdef CONFIG_INTERWORKING
- size_t gas_frag_limit;
-#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_PROXYARP
struct l2_packet_data *sock_dhcp;
struct l2_packet_data *sock_ndisc;
@@ -286,6 +295,16 @@
#ifdef CONFIG_MBO
unsigned int mbo_assoc_disallow;
#endif /* CONFIG_MBO */
+
+ struct dl_list nr_db;
+
+ u8 beacon_req_token;
+ u8 lci_req_token;
+ u8 range_req_token;
+ unsigned int lci_req_active:1;
+ unsigned int range_req_active:1;
+
+ int dhcp_sock; /* UDP socket used with the DHCP server */
};
@@ -293,6 +312,10 @@
struct dl_list list;
u8 addr[ETH_ALEN];
struct os_reltime last_seen;
+ int ssi_signal;
+#ifdef CONFIG_TAXONOMY
+ struct wpabuf *probe_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
};
/**
@@ -453,6 +476,7 @@
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
+struct hostapd_iface * hostapd_alloc_iface(void);
struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
const char *config_file);
struct hostapd_iface *
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 16887ac..2d6cef1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -329,6 +329,8 @@
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
+ iface->conf->vht_oper_centr_freq_seg0_idx = 0;
+ iface->conf->vht_oper_centr_freq_seg1_idx = 0;
res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -621,41 +623,6 @@
#ifdef CONFIG_IEEE80211AC
-
-static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
-{
- u32 req_cap = conf & cap;
-
- /*
- * Make sure we support all requested capabilities.
- * NOTE: We assume that 'cap' represents a capability mask,
- * not a discrete value.
- */
- if ((hw & req_cap) != req_cap) {
- wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
- name);
- return 0;
- }
- return 1;
-}
-
-
-static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
- unsigned int shift,
- const char *name)
-{
- u32 hw_max = hw & mask;
- u32 conf_val = conf & mask;
-
- if (conf_val > hw_max) {
- wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
- name, conf_val >> shift, hw_max >> shift);
- return 0;
- }
- return 1;
-}
-
-
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
{
struct hostapd_hw_modes *mode = iface->current_mode;
@@ -683,45 +650,7 @@
}
}
-#define VHT_CAP_CHECK(cap) \
- do { \
- if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
- return 0; \
- } while (0)
-
-#define VHT_CAP_CHECK_MAX(cap) \
- do { \
- if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
- #cap)) \
- return 0; \
- } while (0)
-
- VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
- VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
- VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
- VHT_CAP_CHECK(VHT_CAP_RXLDPC);
- VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
- VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
- VHT_CAP_CHECK(VHT_CAP_TXSTBC);
- VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
- VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
- VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
- VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
- VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
- VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
- VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
- VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
- VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
- VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
- VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
-
-#undef VHT_CAP_CHECK
-#undef VHT_CAP_CHECK_MAX
-
- return 1;
+ return ieee80211ac_cap_check(hw, conf);
}
#endif /* CONFIG_IEEE80211AC */
@@ -785,6 +714,8 @@
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
}
+ wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
+ channel, primary ? "primary" : "secondary");
return 0;
}
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index 07672ce..2556da3 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -381,6 +381,7 @@
struct sockaddr_in *paddr, uaddr;
struct iapp_data *iapp;
struct ip_mreqn mreq;
+ int reuseaddr = 1;
iapp = os_zalloc(sizeof(*iapp));
if (iapp == NULL)
@@ -443,6 +444,18 @@
os_memset(&uaddr, 0, sizeof(uaddr));
uaddr.sin_family = AF_INET;
uaddr.sin_port = htons(IAPP_UDP_PORT);
+
+ if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+ sizeof(reuseaddr)) < 0) {
+ wpa_printf(MSG_INFO,
+ "iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
+ strerror(errno));
+ /*
+ * Ignore this and try to continue. This is fine for single
+ * BSS cases, but may fail if multiple BSSes enable IAPP.
+ */
+ }
+
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 45ecbfb..c6234dc 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -43,6 +43,9 @@
#include "ieee802_11.h"
#include "dfs.h"
#include "mbo_ap.h"
+#include "rrm.h"
+#include "taxonomy.h"
+#include "fils_hlp.h"
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -140,6 +143,7 @@
int capab = WLAN_CAPABILITY_ESS;
int privacy;
int dfs;
+ int i;
/* Check if any of configured channels require DFS */
dfs = hostapd_is_dfs_required(hapd->iface);
@@ -187,8 +191,12 @@
(hapd->iconf->spectrum_mgmt_required || dfs))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
- if (hapd->conf->radio_measurements)
- capab |= IEEE80211_CAP_RRM;
+ for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
+ if (hapd->conf->radio_measurements[i]) {
+ capab |= IEEE80211_CAP_RRM;
+ break;
+ }
+ }
return capab;
}
@@ -296,7 +304,7 @@
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 status,
const u8 *ies, size_t ies_len)
@@ -327,7 +335,7 @@
sta->flags |= WLAN_STA_AUTH;
mlme_authenticate_indication(hapd, sta);
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
@@ -512,6 +520,9 @@
if (sae_check_big_sync(sta))
return;
sta->sae->sync++;
+ wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
+ " (sync=%d state=%d)",
+ MAC2STR(sta->addr), sta->sae->sync, sta->sae->state);
switch (sta->sae->state) {
case SAE_COMMITTED:
@@ -609,7 +620,7 @@
* message now to get alternating sequence of
* Authentication frames between the AP and STA.
* Confirm will be sent in
- * Commited -> Confirmed/Accepted transition
+ * Committed -> Confirmed/Accepted transition
* when receiving Confirm from STA.
*/
}
@@ -718,6 +729,44 @@
}
+static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct sae_data *sae = sta->sae;
+ int i, *groups = hapd->conf->sae_groups;
+
+ if (sae->state != SAE_COMMITTED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
+
+ for (i = 0; groups && groups[i] > 0; i++) {
+ if (sae->group == groups[i])
+ break;
+ }
+
+ if (!groups || groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Previously selected group not found from the current configuration");
+ return;
+ }
+
+ for (;;) {
+ i++;
+ if (groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No alternative group enabled");
+ return;
+ }
+
+ if (sae_set_group(sae, groups[i]) < 0)
+ continue;
+
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
@@ -805,6 +854,16 @@
return;
}
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ sta->sae->tmp) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Peer did not accept our SAE group");
+ sae_pick_next_group(hapd, sta);
+ goto remove_sta;
+ }
+
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
@@ -922,6 +981,410 @@
#endif /* CONFIG_SAE */
+static u16 wpa_res_to_status_code(int res)
+{
+ if (res == WPA_INVALID_GROUP)
+ return WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ if (res == WPA_INVALID_PAIRWISE)
+ return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ if (res == WPA_INVALID_AKMP)
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ if (res == WPA_ALLOC_FAIL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+#ifdef CONFIG_IEEE80211W
+ if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+ if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+#endif /* CONFIG_IEEE80211W */
+ if (res == WPA_INVALID_MDIE)
+ return WLAN_STATUS_INVALID_MDIE;
+ if (res != WPA_IE_OK)
+ return WLAN_STATUS_INVALID_IE;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+#ifdef CONFIG_FILS
+
+static void handle_auth_fils_finish(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 resp,
+ struct rsn_pmksa_cache_entry *pmksa,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len);
+
+static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ u16 auth_transaction, u16 status_code)
+{
+ u16 resp = WLAN_STATUS_SUCCESS;
+ const u8 *pos, *end;
+ struct ieee802_11_elems elems;
+ int res;
+ struct wpa_ie_data rsn;
+ struct rsn_pmksa_cache_entry *pmksa = NULL;
+
+ if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
+ return;
+
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
+ pos, end - pos);
+
+ /* TODO: Finite Cyclic Group when using PK or PFS */
+ /* TODO: Element when using PK or PFS */
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
+ if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ /* RSNE */
+ wpa_hexdump(MSG_DEBUG, "FILS: RSN element",
+ elems.rsn_ie, elems.rsn_ie_len);
+ if (!elems.rsn_ie ||
+ wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: No valid RSN element");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
+ NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to initialize RSN state machine");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ elems.mdie, elems.mdie_len);
+ resp = wpa_res_to_status_code(res);
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ /* TODO: MDE when using FILS+FT */
+ /* TODO: FTE when using FILS+FT */
+
+ if (!elems.fils_nonce) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ /* PMKID List */
+ if (rsn.pmkid && rsn.num_pmkid > 0) {
+ u8 num;
+ const u8 *pmkid;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
+ rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
+
+ pmkid = rsn.pmkid;
+ num = rsn.num_pmkid;
+ while (num) {
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
+ pmkid);
+ if (pmksa)
+ break;
+ pmkid += PMKID_LEN;
+ num--;
+ }
+ }
+ if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore",
+ wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp);
+ pmksa = NULL;
+ }
+ if (pmksa)
+ wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry");
+
+ /* FILS Session */
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN);
+
+ /* FILS Wrapped Data */
+ if (elems.fils_wrapped_data) {
+ wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
+ elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ if (!pmksa) {
+#ifndef CONFIG_NO_RADIUS
+ if (!sta->eapol_sm) {
+ sta->eapol_sm =
+ ieee802_1x_alloc_eapol_sm(hapd, sta);
+ }
+ wpa_printf(MSG_DEBUG,
+ "FILS: Forward EAP-Identity/Re-auth Start to authentication server");
+ ieee802_1x_encapsulate_radius(
+ hapd, sta, elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ wpa_printf(MSG_DEBUG,
+ "FILS: Will send Authentication frame once the response from authentication server is available");
+ sta->flags |= WLAN_STA_PENDING_FILS_ERP;
+ return;
+#else /* CONFIG_NO_RADIUS */
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+#endif /* CONFIG_NO_RADIUS */
+ }
+ }
+
+fail:
+ handle_auth_fils_finish(hapd, sta, resp, pmksa, NULL, NULL, 0);
+}
+
+
+static void handle_auth_fils_finish(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 resp,
+ struct rsn_pmksa_cache_entry *pmksa,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len)
+{
+ u8 fils_nonce[FILS_NONCE_LEN];
+ size_t ielen;
+ struct wpabuf *data = NULL;
+ const u8 *ie;
+ u8 *ie_buf = NULL;
+ const u8 *pmk = NULL;
+ size_t pmk_len = 0;
+ u8 pmk_buf[PMK_LEN_MAX];
+
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
+ if (!ie) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (pmksa) {
+ /* Add PMKID of the selected PMKSA into RSNE */
+ ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
+ if (!ie_buf) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ os_memcpy(ie_buf, ie, ielen);
+ if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ ie = ie_buf;
+ }
+
+ if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
+ fils_nonce, FILS_NONCE_LEN);
+
+ data = wpabuf_alloc(1000 + ielen);
+ if (!data) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ /* TODO: Finite Cyclic Group when using PK or PFS */
+ /* TODO: Element when using PK or PFS */
+
+ /* RSNE */
+ wpabuf_put_data(data, ie, ielen);
+
+ /* TODO: MDE when using FILS+FT */
+ /* TODO: FTE when using FILS+FT */
+
+ /* FILS Nonce */
+ wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN);
+
+ /* FILS Wrapped Data */
+ if (!pmksa && erp_resp) {
+ wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_buf(data, erp_resp);
+
+ if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
+ msk, msk_len, sta->fils_snonce, fils_nonce,
+ NULL, 0, pmk_buf, &pmk_len)) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(data);
+ data = NULL;
+ goto fail;
+ }
+ pmk = pmk_buf;
+ } else if (pmksa) {
+ pmk = pmksa->pmk;
+ pmk_len = pmksa->pmk_len;
+ }
+
+ if (!pmk) {
+ wpa_printf(MSG_DEBUG, "FILS: No PMK available");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(data);
+ data = NULL;
+ goto fail;
+ }
+
+ if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
+ sta->fils_snonce, fils_nonce) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_free(data);
+ data = NULL;
+ goto fail;
+ }
+
+fail:
+ send_auth_reply(hapd, sta->addr, hapd->own_addr, WLAN_AUTH_FILS_SK, 2,
+ resp,
+ data ? wpabuf_head(data) : (u8 *) "",
+ data ? wpabuf_len(data) : 0);
+ wpabuf_free(data);
+
+ if (resp == WLAN_STATUS_SUCCESS) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "authentication OK (FILS)");
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->auth_alg = WLAN_AUTH_FILS_SK;
+ mlme_authenticate_indication(hapd, sta);
+ }
+
+ os_free(ie_buf);
+}
+
+
+void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
+ struct sta_info *sta, int success,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len)
+{
+ sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ handle_auth_fils_finish(hapd, sta, success ? WLAN_STATUS_SUCCESS :
+ WLAN_STATUS_UNSPECIFIED_FAILURE, NULL,
+ erp_resp, msk, msk_len);
+}
+
+#endif /* CONFIG_FILS */
+
+
+static int
+ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len, u32 *session_timeout,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
+{
+ int res;
+
+ os_memset(vlan_id, 0, sizeof(*vlan_id));
+ res = hostapd_allowed_address(hapd, addr, msg, len,
+ session_timeout, acct_interim_interval,
+ vlan_id, psk, identity, radius_cui);
+
+ if (res == HOSTAPD_ACL_REJECT) {
+ wpa_printf(MSG_INFO,
+ "Station " MACSTR " not allowed to authenticate",
+ MAC2STR(addr));
+ return HOSTAPD_ACL_REJECT;
+ }
+
+ if (res == HOSTAPD_ACL_PENDING) {
+ wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+ " waiting for an external authentication",
+ MAC2STR(addr));
+ /* Authentication code will re-send the authentication frame
+ * after it has received (and cached) information from the
+ * external source. */
+ return HOSTAPD_ACL_PENDING;
+ }
+
+ return res;
+}
+
+
+static int
+ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int res, u32 session_timeout,
+ u32 acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
+{
+ if (vlan_id->notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_id->untagged,
+ vlan_id->tagged[0] ? "+" : "");
+ return -1;
+ }
+ if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
+ return -1;
+ if (sta->vlan_id)
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+
+ hostapd_free_psk_list(sta->psk);
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ sta->psk = *psk;
+ *psk = NULL;
+ } else {
+ sta->psk = NULL;
+ }
+
+ sta->identity = *identity;
+ *identity = NULL;
+ sta->radius_cui = *radius_cui;
+ *radius_cui = NULL;
+
+ if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
+ sta->acct_interim_interval = acct_interim_interval;
+ if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+ ap_sta_session_timeout(hapd, sta, session_timeout);
+ else
+ ap_sta_no_session_timeout(hapd, sta);
+
+ return 0;
+}
+
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -940,8 +1403,6 @@
char *radius_cui = NULL;
u16 seq_ctrl;
- os_memset(&vlan_id, 0, sizeof(vlan_id));
-
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
(unsigned long) len);
@@ -995,14 +1456,18 @@
if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
auth_alg == WLAN_AUTH_OPEN) ||
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
(hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_FT) ||
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
(hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_SAE) ||
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
+ auth_alg == WLAN_AUTH_FILS_SK) ||
+#endif /* CONFIG_FILS */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
@@ -1081,29 +1546,19 @@
}
}
- res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
- &session_timeout,
- &acct_interim_interval, &vlan_id,
- &psk, &identity, &radius_cui);
-
+ res = ieee802_11_allowed_address(
+ hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
+ &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
- wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
- MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- if (res == HOSTAPD_ACL_PENDING) {
- wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
- " waiting for an external authentication",
- MAC2STR(mgmt->sa));
- /* Authentication code will re-send the authentication frame
- * after it has received (and cached) information from the
- * external source. */
+ if (res == HOSTAPD_ACL_PENDING)
return;
- }
sta = ap_get_sta(hapd, mgmt->sa);
if (sta) {
+ sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
if ((fc & WLAN_FC_RETRY) &&
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
sta->last_seq_ctrl == seq_ctrl &&
@@ -1152,47 +1607,17 @@
sta->last_seq_ctrl = seq_ctrl;
sta->last_subtype = WLAN_FC_STYPE_AUTH;
- if (vlan_id.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &vlan_id)) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO,
- "Invalid VLAN %d%s received from RADIUS server",
- vlan_id.untagged,
- vlan_id.tagged[0] ? "+" : "");
+ res = ieee802_11_set_radius_info(
+ hapd, sta, res, session_timeout, acct_interim_interval,
+ &vlan_id, &psk, &identity, &radius_cui);
+ if (res) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- if (sta->vlan_id)
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
-
- hostapd_free_psk_list(sta->psk);
- if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- sta->psk = psk;
- psk = NULL;
- } else {
- sta->psk = NULL;
- }
-
- sta->identity = identity;
- identity = NULL;
- sta->radius_cui = radius_cui;
- radius_cui = NULL;
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
- if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
- sta->acct_interim_interval = acct_interim_interval;
- if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- ap_sta_session_timeout(hapd, sta, session_timeout);
- else
- ap_sta_no_session_timeout(hapd, sta);
-
/*
* If the driver supports full AP client state, add a station to the
* driver before sending authentication reply to make sure the driver
@@ -1205,8 +1630,15 @@
*
* In mesh mode, the station was already added to the driver when the
* NEW_PEER_CANDIDATE event is received.
+ *
+ * If PMF was negotiated for the existing association, skip this to
+ * avoid dropping the STA entry and the associated keys. This is needed
+ * to allow the original connection work until the attempt can complete
+ * (re)association, so that unprotected Authentication frame cannot be
+ * used to bypass PMF protection.
*/
if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+ (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) &&
!(sta->added_unassoc)) {
/*
@@ -1220,8 +1652,8 @@
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
WLAN_STA_AUTHORIZED);
- if (hostapd_sta_add(hapd, sta->addr, 0, 0, 0, 0, 0,
- NULL, NULL, sta->flags, 0, 0, 0)) {
+ if (hostapd_sta_add(hapd, sta->addr, 0, 0, NULL, 0, 0,
+ NULL, NULL, sta->flags, 0, 0, 0, 0)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
@@ -1258,7 +1690,7 @@
}
break;
#endif /* CONFIG_NO_RC4 */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
if (sta->wpa_sm == NULL)
@@ -1277,7 +1709,7 @@
handle_auth_ft_finish, hapd);
/* handle_auth_ft_finish() callback will complete auth. */
return;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
case WLAN_AUTH_SAE:
#ifdef CONFIG_MESH
@@ -1299,6 +1731,12 @@
status_code);
return;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WLAN_AUTH_FILS_SK:
+ handle_auth_fils(hapd, sta, mgmt, len, auth_transaction,
+ status_code);
+ return;
+#endif /* CONFIG_FILS */
}
fail:
@@ -1328,6 +1766,9 @@
return 0;
}
+ if (TEST_FAIL())
+ return -1;
+
for (i = 0; i < AID_WORDS; i++) {
if (hapd->sta_aid[i] == (u32) -1)
continue;
@@ -1398,6 +1839,11 @@
static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
struct ieee802_11_elems *elems)
{
+ /* Supported rates not used in IEEE 802.11ad/DMG */
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD)
+ return WLAN_STATUS_SUCCESS;
+
if (!elems->supp_rates) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1584,24 +2030,7 @@
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
wpa_ie, wpa_ie_len,
elems.mdie, elems.mdie_len);
- if (res == WPA_INVALID_GROUP)
- resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_PAIRWISE)
- resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_AKMP)
- resp = WLAN_STATUS_AKMP_NOT_VALID;
- else if (res == WPA_ALLOC_FAIL)
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
- resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
- else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
- resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
-#endif /* CONFIG_IEEE80211W */
- else if (res == WPA_INVALID_MDIE)
- resp = WLAN_STATUS_INVALID_MDIE;
- else if (res != WPA_IE_OK)
- resp = WLAN_STATUS_INVALID_IE;
+ resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
#ifdef CONFIG_IEEE80211W
@@ -1629,7 +2058,7 @@
sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
if (!reassoc) {
wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
@@ -1644,7 +2073,7 @@
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_SAE
if (wpa_auth_uses_sae(sta->wpa_sm) &&
@@ -1743,6 +2172,12 @@
ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
elems.supp_op_classes_len);
+ if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) &&
+ elems.rrm_enabled &&
+ elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa))
+ os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled,
+ sizeof(sta->rrm_enabled_capa));
+
return WLAN_STATUS_SUCCESS;
}
@@ -1815,7 +2250,8 @@
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
- sta->vht_opmode, set)) {
+ sta->vht_opmode, sta->p2p_ie ? 1 : 0,
+ set)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
"Could not %s STA to kernel driver",
@@ -1836,21 +2272,32 @@
static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
- u16 status_code, int reassoc, const u8 *ies,
- size_t ies_len)
+ const u8 *addr, u16 status_code, int reassoc,
+ const u8 *ies, size_t ies_len)
{
int send_len;
- u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+ u8 *buf;
+ size_t buflen;
struct ieee80211_mgmt *reply;
u8 *p;
+ u16 res = WLAN_STATUS_SUCCESS;
- os_memset(buf, 0, sizeof(buf));
+ buflen = sizeof(struct ieee80211_mgmt) + 1024;
+#ifdef CONFIG_FILS
+ if (sta && sta->fils_hlp_resp)
+ buflen += wpabuf_len(sta->fils_hlp_resp);
+#endif /* CONFIG_FILS */
+ buf = os_zalloc(buflen);
+ if (!buf) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
reply = (struct ieee80211_mgmt *) buf;
reply->frame_control =
IEEE80211_FC(WLAN_FC_TYPE_MGMT,
(reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
WLAN_FC_STYPE_ASSOC_RESP));
- os_memcpy(reply->da, sta->addr, ETH_ALEN);
+ os_memcpy(reply->da, addr, ETH_ALEN);
os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
@@ -1859,24 +2306,26 @@
reply->u.assoc_resp.capab_info =
host_to_le16(hostapd_own_capab_info(hapd));
reply->u.assoc_resp.status_code = host_to_le16(status_code);
- reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
+
+ reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) |
+ BIT(14) | BIT(15));
/* Supported rates */
p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
-#ifdef CONFIG_IEEE80211R
- if (status_code == WLAN_STATUS_SUCCESS) {
+#ifdef CONFIG_IEEE80211R_AP
+ if (sta && status_code == WLAN_STATUS_SUCCESS) {
/* IEEE 802.11r: Mobility Domain Information, Fast BSS
* Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
- buf + sizeof(buf) - p,
+ buf + buflen - p,
sta->auth_alg, ies, ies_len);
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
- if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
+ if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
#endif /* CONFIG_IEEE80211W */
@@ -1887,14 +2336,30 @@
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
- p = hostapd_eid_vht_capabilities(hapd, p);
+ u32 nsts = 0, sta_nsts;
+
+ if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
+ struct ieee80211_vht_capabilities *capa;
+
+ nsts = (hapd->iface->conf->vht_capab >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ capa = sta->vht_capabilities;
+ sta_nsts = (le_to_host32(capa->vht_capabilities_info) >>
+ VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+
+ if (nsts < sta_nsts)
+ nsts = 0;
+ else
+ nsts = sta_nsts;
+ }
+ p = hostapd_eid_vht_capabilities(hapd, p, nsts);
p = hostapd_eid_vht_operation(hapd, p);
}
#endif /* CONFIG_IEEE80211AC */
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
- if (sta->qos_map_enabled)
+ if (sta && sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
#ifdef CONFIG_FST
@@ -1906,16 +2371,17 @@
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+ if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
p = hostapd_eid_vendor_vht(hapd, p);
#endif /* CONFIG_IEEE80211AC */
- if (sta->flags & WLAN_STA_WMM)
+ if (sta && (sta->flags & WLAN_STA_WMM))
p = hostapd_eid_wmm(hapd, p);
#ifdef CONFIG_WPS
- if ((sta->flags & WLAN_STA_WPS) ||
- ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
+ if (sta &&
+ ((sta->flags & WLAN_STA_WPS) ||
+ ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) {
struct wpabuf *wps = wps_build_assoc_resp_ie();
if (wps) {
os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -1926,7 +2392,7 @@
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
- if (sta->p2p_ie && hapd->p2p_group) {
+ if (sta && sta->p2p_ie && hapd->p2p_group) {
struct wpabuf *p2p_resp_ie;
enum p2p_status_code status;
switch (status_code) {
@@ -1955,20 +2421,109 @@
p = hostapd_eid_p2p_manage(hapd, p);
#endif /* CONFIG_P2P_MANAGER */
- p = hostapd_eid_mbo(hapd, p, buf + sizeof(buf) - p);
+ p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
+
+ if (hapd->conf->assocresp_elements &&
+ (size_t) (buf + buflen - p) >=
+ wpabuf_len(hapd->conf->assocresp_elements)) {
+ os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
+ wpabuf_len(hapd->conf->assocresp_elements));
+ p += wpabuf_len(hapd->conf->assocresp_elements);
+ }
send_len += p - reply->u.assoc_resp.variable;
+#ifdef CONFIG_FILS
+ if (sta &&
+ (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) &&
+ status_code == WLAN_STATUS_SUCCESS) {
+ struct ieee802_11_elems elems;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
+ ParseFailed || !elems.fils_session) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
+
+ /* FILS Session */
+ *p++ = WLAN_EID_EXTENSION; /* Element ID */
+ *p++ = 1 + FILS_SESSION_LEN; /* Length */
+ *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
+ os_memcpy(p, elems.fils_session, FILS_SESSION_LEN);
+ send_len += 2 + 1 + FILS_SESSION_LEN;
+
+ send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
+ buflen, sta->fils_hlp_resp);
+ if (send_len < 0) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
+ }
+#endif /* CONFIG_FILS */
+
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- return WLAN_STATUS_SUCCESS;
+done:
+ os_free(buf);
+ return res;
}
+#ifdef CONFIG_FILS
+
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ u16 reply_res;
+
+ wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
+ MAC2STR(sta->addr));
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ if (!sta->fils_pending_assoc_req)
+ return;
+ 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);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+
+ /*
+ * Remove the station in case tranmission of a success response fails
+ * (the STA was added associated to the driver) or if the station was
+ * previously added unassociated.
+ */
+ if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
+}
+
+
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = eloop_data;
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP response timeout - continue with association response for "
+ MACSTR, MAC2STR(sta->addr));
+ fils_hlp_finish_assoc(hapd, sta);
+}
+
+#endif /* CONFIG_FILS */
+
+
static void handle_assoc(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int reassoc)
@@ -1978,6 +2533,13 @@
const u8 *pos;
int left, i;
struct sta_info *sta;
+ u8 *tmp = NULL;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
+ char *identity = NULL;
+ char *radius_cui = NULL;
+#ifdef CONFIG_FILS
+ int delay_assoc = 0;
+#endif /* CONFIG_FILS */
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
@@ -2035,7 +2597,7 @@
}
sta = ap_get_sta(hapd, mgmt->sa);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta && sta->auth_alg == WLAN_AUTH_FT &&
(sta->flags & WLAN_STA_AUTH) == 0) {
wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
@@ -2048,24 +2610,72 @@
*/
sta->flags |= WLAN_STA_AUTH;
} else
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
- hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "Station tried to "
- "associate before authentication "
- "(aid=%d flags=0x%x)",
- sta ? sta->aid : -1,
- sta ? sta->flags : 0);
- send_deauth(hapd, mgmt->sa,
- WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
- return;
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode ==
+ HOSTAPD_MODE_IEEE80211AD) {
+ int acl_res;
+ u32 session_timeout, acct_interim_interval;
+ struct vlan_description vlan_id;
+
+ acl_res = ieee802_11_allowed_address(
+ hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &session_timeout, &acct_interim_interval,
+ &vlan_id, &psk, &identity, &radius_cui);
+ if (acl_res == HOSTAPD_ACL_REJECT) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (acl_res == HOSTAPD_ACL_PENDING)
+ return;
+
+ /* DMG/IEEE 802.11ad does not use authentication.
+ * Allocate sta entry upon association. */
+ sta = ap_sta_add(hapd, mgmt->sa);
+ if (!sta) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Failed to add STA");
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+ acl_res = ieee802_11_set_radius_info(
+ hapd, sta, acl_res, session_timeout,
+ acct_interim_interval, &vlan_id, &psk,
+ &identity, &radius_cui);
+ if (acl_res) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Skip authentication for DMG/IEEE 802.11ad");
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->auth_alg = WLAN_AUTH_OPEN;
+ } else {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Station tried to associate before authentication (aid=%d flags=0x%x)",
+ sta ? sta->aid : -1,
+ sta ? sta->flags : 0);
+ send_deauth(hapd, mgmt->sa,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+ return;
+ }
}
if ((fc & WLAN_FC_RETRY) &&
sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
sta->last_seq_ctrl == seq_ctrl &&
- sta->last_subtype == reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
- WLAN_FC_STYPE_ASSOC_REQ) {
+ sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
+ WLAN_FC_STYPE_ASSOC_REQ)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Drop repeated association frame seq_ctrl=0x%x",
@@ -2097,6 +2707,36 @@
}
#endif /* CONFIG_MBO */
+ /*
+ * sta->capability is used in check_assoc_ies() for RRM enabled
+ * capability element.
+ */
+ sta->capability = capab_info;
+
+#ifdef CONFIG_FILS
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ /* The end of the payload is encrypted. Need to decrypt it
+ * before parsing. */
+
+ tmp = os_malloc(left);
+ if (!tmp) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ os_memcpy(tmp, pos, left);
+
+ left = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt,
+ len, tmp, left);
+ if (left < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ pos = tmp;
+ }
+#endif /* CONFIG_FILS */
+
/* followed by SSID and Supported rates; and HT capabilities if 802.11n
* is used */
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
@@ -2110,7 +2750,6 @@
goto fail;
}
- sta->capability = capab_info;
sta->listen_interval = listen_interval;
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
@@ -2180,7 +2819,26 @@
* remove the STA immediately. */
sta->timeout_next = STA_NULLFUNC;
+#ifdef CONFIG_TAXONOMY
+ taxonomy_sta_info_assoc_req(hapd, sta, pos, left);
+#endif /* CONFIG_TAXONOMY */
+
+ sta->pending_wds_enable = 0;
+
+#ifdef CONFIG_FILS
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ if (fils_process_hlp(hapd, sta, pos, left) > 0)
+ delay_assoc = 1;
+ }
+#endif /* CONFIG_FILS */
+
fail:
+ os_free(identity);
+ os_free(radius_cui);
+ hostapd_free_psk_list(psk);
+
/*
* In case of a successful response, add the station to the driver.
* Otherwise, the kernel may ignore Data frames before we process the
@@ -2199,18 +2857,43 @@
* issues with processing other non-Data Class 3 frames during this
* window.
*/
- if (resp == WLAN_STATUS_SUCCESS && add_associated_sta(hapd, sta))
+ if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta))
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
- reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+#ifdef CONFIG_FILS
+ if (sta) {
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ }
+ if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
+ sta->fils_pending_assoc_req = tmp;
+ sta->fils_pending_assoc_req_len = left;
+ sta->fils_pending_assoc_is_reassoc = reassoc;
+ wpa_printf(MSG_DEBUG,
+ "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
+ MACSTR, MAC2STR(sta->addr));
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
+ fils_hlp_timeout, hapd, sta);
+ return;
+ }
+#endif /* CONFIG_FILS */
+
+ reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
+ left);
+ os_free(tmp);
/*
* Remove the station in case tranmission of a success response fails
* (the STA was added associated to the driver) or if the station was
* previously added unassociated.
*/
- if ((reply_res != WLAN_STATUS_SUCCESS &&
- resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc) {
+ if (sta && ((reply_res != WLAN_STATUS_SUCCESS &&
+ resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -2267,6 +2950,17 @@
mlme_disassociate_indication(
hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
+
+ /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon
+ * disassociation. */
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ sta->flags &= ~WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "deauthenticated");
+ ap_free_sta(hapd, sta);
+ }
}
@@ -2378,7 +3072,7 @@
(sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
"frame (category=%u) from unassociated STA " MACSTR,
- MAC2STR(mgmt->sa), mgmt->u.action.category);
+ mgmt->u.action.category, MAC2STR(mgmt->sa));
return 0;
}
@@ -2415,14 +3109,14 @@
}
switch (mgmt->u.action.category) {
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
case WLAN_ACTION_FT:
if (!sta ||
wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
len - IEEE80211_HDRLEN))
break;
return 1;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
return 1;
@@ -2477,6 +3171,9 @@
return 1;
}
break;
+ case WLAN_ACTION_RADIO_MEASUREMENT:
+ hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len);
+ return 1;
}
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -2484,8 +3181,9 @@
"handle_action - unknown action category %d or invalid "
"frame",
mgmt->u.action.category);
- if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
- !(mgmt->sa[0] & 0x01)) {
+ if (!is_multicast_ether_addr(mgmt->da) &&
+ !(mgmt->u.action.category & 0x80) &&
+ !is_multicast_ether_addr(mgmt->sa)) {
struct ieee80211_mgmt *resp;
/*
@@ -2532,7 +3230,6 @@
struct hostapd_frame_info *fi)
{
struct ieee80211_mgmt *mgmt;
- int broadcast;
u16 fc, stype;
int ret = 0;
@@ -2548,11 +3245,7 @@
return 1;
}
- broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
- mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
- mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
-
- if (!broadcast &&
+ if (!is_broadcast_ether_addr(mgmt->bssid) &&
#ifdef CONFIG_P2P
/* Invitation responses can be sent with the peer MAC as BSSID */
!((hapd->conf->p2p & P2P_GROUP_OWNER) &&
@@ -2582,7 +3275,7 @@
}
if (hapd->iconf->track_sta_max_num)
- sta_track_add(hapd->iface, mgmt->sa);
+ sta_track_add(hapd->iface, mgmt->sa, fi->ssi_signal);
switch (stype) {
case WLAN_FC_STYPE_AUTH:
@@ -2756,11 +3449,15 @@
new_assoc = 0;
sta->flags |= WLAN_STA_ASSOC;
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
- if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) ||
+ if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+ !hapd->conf->osen) ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK ||
sta->auth_alg == WLAN_AUTH_FT) {
/*
- * Open, static WEP, or FT protocol; no separate authorization
- * step.
+ * Open, static WEP, FT protocol, or FILS; no separate
+ * authorization step.
*/
ap_sta_set_authorized(hapd, sta, 1);
}
@@ -2774,16 +3471,6 @@
sta->sa_query_timed_out = 0;
#endif /* CONFIG_IEEE80211W */
- if (sta->flags & WLAN_STA_WDS) {
- int ret;
- char ifname_wds[IFNAMSIZ + 1];
-
- ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
- sta->aid, 1);
- if (!ret)
- hostapd_set_wds_encryption(hapd, sta, ifname_wds);
- }
-
if (sta->eapol_sm == NULL) {
/*
* This STA does not use RADIUS server for EAP authentication,
@@ -2800,6 +3487,27 @@
hostapd_set_sta_flags(hapd, sta);
+ if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) {
+ wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA "
+ MACSTR " based on pending request",
+ MAC2STR(sta->addr));
+ sta->pending_wds_enable = 0;
+ sta->flags |= WLAN_STA_WDS;
+ }
+
+ if (sta->flags & WLAN_STA_WDS) {
+ int ret;
+ char ifname_wds[IFNAMSIZ + 1];
+
+ wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA "
+ MACSTR " (aid %u)",
+ MAC2STR(sta->addr), sta->aid);
+ ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
+ sta->aid, 1);
+ if (!ret)
+ hostapd_set_wds_encryption(hapd, sta, ifname_wds);
+ }
+
if (sta->auth_alg == WLAN_AUTH_FT)
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
else
@@ -2807,6 +3515,18 @@
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+#ifdef CONFIG_FILS
+ if ((sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) &&
+ fils_set_tk(sta->wpa_sm) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: TK configuration failed");
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ return;
+ }
+#endif /* CONFIG_FILS */
+
if (sta->pending_eapol_rx) {
struct os_reltime now, age;
@@ -2833,7 +3553,7 @@
size_t len, int ok)
{
struct sta_info *sta;
- if (mgmt->da[0] & 0x01)
+ if (is_multicast_ether_addr(mgmt->da))
return;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2857,7 +3577,7 @@
size_t len, int ok)
{
struct sta_info *sta;
- if (mgmt->da[0] & 0x01)
+ if (is_multicast_ether_addr(mgmt->da))
return;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -2876,6 +3596,35 @@
}
+static void handle_action_cb(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok)
+{
+ struct sta_info *sta;
+ const struct rrm_measurement_report_element *report;
+
+ if (is_multicast_ether_addr(mgmt->da))
+ return;
+ sta = ap_get_sta(hapd, mgmt->da);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR
+ " not found", MAC2STR(mgmt->da));
+ return;
+ }
+
+ if (len < 24 + 5 + sizeof(*report))
+ return;
+ report = (const struct rrm_measurement_report_element *)
+ &mgmt->u.action.u.rrm.variable[2];
+ if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST &&
+ report->eid == WLAN_EID_MEASURE_REQUEST &&
+ report->len >= 3 &&
+ report->type == MEASURE_TYPE_BEACON)
+ hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok);
+}
+
+
/**
* ieee802_11_mgmt_cb - Process management frame TX status callback
* @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -2925,6 +3674,7 @@
break;
case WLAN_FC_STYPE_ACTION:
wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok);
+ handle_action_cb(hapd, mgmt, len, ok);
break;
default:
wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype);
@@ -3022,6 +3772,8 @@
}
if (sta == NULL)
return;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR,
+ MAC2STR(sta->addr));
if (!(sta->flags & WLAN_STA_PENDING_POLL))
return;
@@ -3037,10 +3789,22 @@
struct sta_info *sta;
sta = ap_get_sta(hapd, src);
- if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+ if (sta &&
+ ((sta->flags & WLAN_STA_ASSOC) ||
+ ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) {
if (!hapd->conf->wds_sta)
return;
+ if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) ==
+ WLAN_STA_ASSOC_REQ_OK) {
+ wpa_printf(MSG_DEBUG,
+ "Postpone 4-address WDS mode enabling for STA "
+ MACSTR " since TX status for AssocResp is not yet known",
+ MAC2STR(sta->addr));
+ sta->pending_wds_enable = 1;
+ return;
+ }
+
if (wds && !(sta->flags & WLAN_STA_WDS)) {
int ret;
char ifname_wds[IFNAMSIZ + 1];
@@ -3060,7 +3824,7 @@
wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
MACSTR, MAC2STR(src));
- if (src[0] & 0x01) {
+ if (is_multicast_ether_addr(src)) {
/* Broadcast bit set in SA?! Ignore the frame silently. */
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 71b3b49..ce3abcb 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -50,11 +50,13 @@
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_he_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_he_operation(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,
@@ -135,4 +137,12 @@
const u8 *supp_op_classes,
size_t supp_op_classes_len);
+u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid);
+void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
+ struct sta_info *sta, int success,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len);
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
+
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 9609152..1e0358c 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -457,7 +457,7 @@
if (passphraselen < MIN_PASSPHRASE_LEN ||
passphraselen > MAX_PASSPHRASE_LEN + 1)
- continue;
+ goto free_pass;
/*
* passphrase does not contain the NULL termination.
@@ -484,6 +484,7 @@
}
skip:
os_free(psk);
+free_pass:
os_free(passphrase);
}
}
@@ -664,9 +665,11 @@
#ifndef CONFIG_NO_RADIUS
hostapd_acl_cache_free(hapd->acl_cache);
+ hapd->acl_cache = NULL;
#endif /* CONFIG_NO_RADIUS */
query = hapd->acl_queries;
+ hapd->acl_queries = NULL;
while (query) {
prev = query;
query = query->next;
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
new file mode 100644
index 0000000..7d6a84f
--- /dev/null
+++ b/src/ap/ieee802_11_he.c
@@ -0,0 +1,101 @@
+/*
+ * hostapd / IEEE 802.11ax HE
+ * Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
+ *
+ * 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 "common/ieee802_11_defs.h"
+#include "common/qca-vendor.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+#include "dfs.h"
+
+u8 * hostapd_eid_vendor_he_capab(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_capabilities *cap;
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ /* For now, use a vendor specific element since the P802.11ax draft is
+ * still subject to changes and the contents of this element may change.
+ * This can be replaced with the actual element once P802.11ax is
+ * finalized. */
+ /* Vendor HE Capabilities element */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 /* The Vendor OUI, subtype */ +
+ sizeof(struct ieee80211_he_capabilities);
+
+ WPA_PUT_BE32(pos, (OUI_QCA << 8) | QCA_VENDOR_ELEM_HE_CAPAB);
+ pos += 4;
+ cap = (struct ieee80211_he_capabilities *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+
+ if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
+ HE_PHYCAP_SU_BEAMFORMER_CAPAB;
+
+ if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
+ HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
+
+ if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
+ cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
+ HE_PHYCAP_MU_BEAMFORMER_CAPAB;
+
+ pos += sizeof(*cap);
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_vendor_he_operation(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ /* For now, use a vendor specific element since the P802.11ax draft is
+ * still subject to changes and the contents of this element may change.
+ * This can be replaced with the actual element once P802.11ax is
+ * finalized. */
+ /* Vendor HE Operation element */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 /* The Vendor OUI, subtype */ +
+ sizeof(struct ieee80211_he_operation);
+
+ WPA_PUT_BE32(pos, (OUI_QCA << 8) | QCA_VENDOR_ELEM_HE_OPER);
+ pos += 4;
+ oper = (struct ieee80211_he_operation *) pos;
+ os_memset(oper, 0, sizeof(*oper));
+
+ if (hapd->iface->conf->he_op.he_bss_color)
+ oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
+
+ if (hapd->iface->conf->he_op.he_default_pe_duration)
+ oper->he_oper_params |=
+ (hapd->iface->conf->he_op.he_default_pe_duration <<
+ HE_OPERATION_DFLT_PE_DURATION_OFFSET);
+
+ if (hapd->iface->conf->he_op.he_twt_required)
+ oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
+
+ if (hapd->iface->conf->he_op.he_rts_threshold)
+ oper->he_oper_params |=
+ (hapd->iface->conf->he_op.he_rts_threshold <<
+ HE_OPERATION_RTS_THRESHOLD_OFFSET);
+
+ pos += sizeof(*oper);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 5eb1060..146e447 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -340,8 +340,8 @@
* that did not specify a valid WMM IE in the (Re)Association Request
* frame.
*/
- if (!ht_capab ||
- !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
+ if (!ht_capab || !(sta->flags & WLAN_STA_WMM) ||
+ !hapd->iconf->ieee80211n || hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index af858f0..daacf7e 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -218,6 +218,20 @@
if (hapd->conf->ssid.utf8_ssid)
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
break;
+ case 7: /* Bits 56-63 */
+ break;
+ case 8: /* Bits 64-71 */
+ if (hapd->conf->ftm_responder)
+ *pos |= 0x40; /* Bit 70 - FTM responder */
+ if (hapd->conf->ftm_initiator)
+ *pos |= 0x80; /* Bit 71 - FTM initiator */
+ case 9: /* Bits 72-79 */
+#ifdef CONFIG_FILS
+ if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
+ wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
+ *pos |= 0x01;
+#endif /* CONFIG_FILS */
+ break;
}
}
@@ -237,6 +251,9 @@
len = 1;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
+ if (len < 9 &&
+ (hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
+ len = 9;
#ifdef CONFIG_WNM
if (len < 4)
len = 4;
@@ -249,6 +266,11 @@
if (hapd->conf->mbo_enabled && len < 6)
len = 6;
#endif /* CONFIG_MBO */
+#ifdef CONFIG_FILS
+ if ((!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+ !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
+ len = 10;
+#endif /* CONFIG_FILS */
if (len < hapd->iface->extended_capa_len)
len = hapd->iface->extended_capa_len;
if (len == 0)
@@ -575,3 +597,63 @@
os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
supp_op_classes_len);
}
+
+
+u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
+{
+ u8 *pos = eid;
+#ifdef CONFIG_FILS
+ u8 *len;
+ u16 fils_info = 0;
+ size_t realms;
+ struct fils_realm *realm;
+
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+ !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
+ return pos;
+
+ realms = dl_list_len(&hapd->conf->fils_realms);
+ if (realms > 7)
+ realms = 7; /* 3 bit count field limits this to max 7 */
+
+ *pos++ = WLAN_EID_FILS_INDICATION;
+ len = pos++;
+ /* TODO: B0..B2: Number of Public Key Identifiers */
+ if (hapd->conf->erp_domain) {
+ /* B3..B5: Number of Realm Identifiers */
+ fils_info |= realms << 3;
+ }
+ /* TODO: B6: FILS IP Address Configuration */
+ if (hapd->conf->fils_cache_id_set)
+ fils_info |= BIT(7);
+ if (hessid && !is_zero_ether_addr(hapd->conf->hessid))
+ fils_info |= BIT(8); /* HESSID Included */
+ /* FILS Shared Key Authentication without PFS Supported */
+ fils_info |= BIT(9);
+ /* TODO: B10: FILS Shared Key Authentication with PFS Supported */
+ /* TODO: B11: FILS Public Key Authentication Supported */
+ /* B12..B15: Reserved */
+ WPA_PUT_LE16(pos, fils_info);
+ pos += 2;
+ if (hapd->conf->fils_cache_id_set) {
+ os_memcpy(pos, hapd->conf->fils_cache_id, FILS_CACHE_ID_LEN);
+ pos += FILS_CACHE_ID_LEN;
+ }
+ if (hessid && !is_zero_ether_addr(hapd->conf->hessid)) {
+ os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+ pos += ETH_ALEN;
+ }
+
+ dl_list_for_each(realm, &hapd->conf->fils_realms, struct fils_realm,
+ list) {
+ if (realms == 0)
+ break;
+ realms--;
+ os_memcpy(pos, realm->hash, 2);
+ pos += 2;
+ }
+ *len = pos - len - 1;
+#endif /* CONFIG_FILS */
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 0841898..8d06620 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -20,7 +20,7 @@
#include "dfs.h"
-u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
{
struct ieee80211_vht_capabilities *cap;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
@@ -50,6 +50,18 @@
cap->vht_capabilities_info = host_to_le32(
hapd->iface->conf->vht_capab);
+ if (nsts != 0) {
+ u32 hapd_nsts;
+
+ hapd_nsts = le_to_host32(cap->vht_capabilities_info);
+ hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
+ cap->vht_capabilities_info &=
+ ~(host_to_le32(hapd_nsts <<
+ VHT_CAP_BEAMFORMEE_STS_OFFSET));
+ cap->vht_capabilities_info |=
+ host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ }
+
/* Supported MCS set comes from hw */
os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
@@ -322,7 +334,7 @@
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
- hapd->conf->disable_11ac ||
+ !hapd->iconf->ieee80211ac || hapd->conf->disable_11ac ||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
os_free(sta->vht_capabilities);
@@ -398,7 +410,7 @@
WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
pos += 4;
*pos++ = VENDOR_VHT_SUBTYPE;
- pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
return pos;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 42b0299..fccdc72 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -31,6 +31,8 @@
#include "ap_drv_ops.h"
#include "wps_hostapd.h"
#include "hs20.h"
+/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */
+#include "ieee802_11.h"
#include "ieee802_1x.h"
@@ -316,6 +318,7 @@
hdr->code != EAP_CODE_INITIATE))
return;
+ eap_erp_update_identity(sm->eap, eap, len);
identity = eap_get_identity(sm->eap, &identity_len);
if (identity == NULL)
return;
@@ -414,6 +417,7 @@
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_PORT) &&
+ sta->aid > 0 &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
wpa_printf(MSG_ERROR, "Could not add NAS-Port");
return -1;
@@ -471,7 +475,7 @@
}
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
sta->wpa_sm &&
(wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
@@ -484,7 +488,7 @@
wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id");
return -1;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
@@ -587,9 +591,9 @@
}
-static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
- struct sta_info *sta,
- const u8 *eap, size_t len)
+void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *eap, size_t len)
{
struct radius_msg *msg;
struct eapol_state_machine *sm = sta->eapol_sm;
@@ -844,7 +848,7 @@
}
-static struct eapol_state_machine *
+struct eapol_state_machine *
ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
{
int flags = 0;
@@ -1153,7 +1157,7 @@
sta->eapol_sm->eap_if->portEnabled = TRUE;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
@@ -1172,7 +1176,29 @@
/* TODO: get vlan_id from R0KH using RRB message */
return;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_FILS
+ if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+ sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG,
+ "PMK from FILS - skip IEEE 802.1X/EAP");
+ /* Setup EAPOL state machines to already authenticated state
+ * because of existing FILS information. */
+ sta->eapol_sm->keyRun = TRUE;
+ sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+ sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+ sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+ sta->eapol_sm->authSuccess = TRUE;
+ sta->eapol_sm->authFail = FALSE;
+ sta->eapol_sm->portValid = TRUE;
+ if (sta->eapol_sm->eap)
+ eap_sm_notify_cached(sta->eapol_sm->eap);
+ return;
+ }
+#endif /* CONFIG_FILS */
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
@@ -1836,6 +1862,19 @@
if (override_eapReq)
sm->eap_if->aaaEapReq = FALSE;
+#ifdef CONFIG_FILS
+#ifdef NEED_AP_MLME
+ if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
+ /* TODO: Add a PMKSA entry on success? */
+ ieee802_11_finish_fils_auth(
+ hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
+ sm->eap_if->aaaEapReqData,
+ sm->eap_if->aaaEapKeyData,
+ sm->eap_if->aaaEapKeyDataLen);
+ }
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_FILS */
+
eapol_auth_step(sm);
return RADIUS_RX_QUEUED;
@@ -1923,7 +1962,7 @@
wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
eapol->default_wep_key_idx);
-
+
if (ieee802_1x_rekey_broadcast(hapd)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "failed to generate a "
@@ -2325,6 +2364,16 @@
MAC2STR(sta->addr), xhdr->version, xhdr->type,
be_to_host16(xhdr->length), ack);
+#ifdef CONFIG_WPS
+ if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack &&
+ (sta->flags & WLAN_STA_WPS) &&
+ ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Indicate EAP completion on ACK for EAP-Failure");
+ hostapd_wps_eap_completed(hapd);
+ }
+#endif /* CONFIG_WPS */
+
if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
return 0;
@@ -2698,15 +2747,6 @@
* EAP-FAST with anonymous provisioning, may require another
* EAPOL authentication to be started to complete connection.
*/
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
- "disconnection after EAP-Failure");
- /* Add a small sleep to increase likelihood of previously
- * requested EAP-Failure TX getting out before this should the
- * driver reorder operations.
- */
- os_sleep(0, 10000);
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
- hostapd_wps_eap_completed(hapd);
+ ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
}
}
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index ec80199..9594661 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -57,5 +57,10 @@
struct hostapd_radius_attr *req_attr,
struct sta_info *sta,
struct radius_msg *msg);
+void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *eap, size_t len);
+struct eapol_state_machine *
+ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* IEEE802_1X_H */
diff --git a/src/ap/mbo_ap.c b/src/ap/mbo_ap.c
index 5e0f92a..43b0bf1 100644
--- a/src/ap/mbo_ap.c
+++ b/src/ap/mbo_ap.c
@@ -38,17 +38,16 @@
size_t num_chan, i;
int ret;
- if (len <= 4)
+ if (len <= 3)
return; /* Not enough room for any channels */
- num_chan = len - 4;
+ num_chan = len - 3;
info = os_zalloc(sizeof(*info) + num_chan);
if (!info)
return;
info->op_class = buf[0];
- info->pref = buf[len - 3];
- info->reason_code = buf[len - 2];
- info->reason_detail = buf[len - 1];
+ info->pref = buf[len - 2];
+ info->reason_code = buf[len - 1];
info->num_channels = num_chan;
buf++;
os_memcpy(info->channels, buf, num_chan);
@@ -75,9 +74,9 @@
}
wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
- " non-preferred channel list (op class %u, pref %u, reason code %u, reason detail %u, channels %s)",
+ " non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)",
MAC2STR(sta->addr), info->op_class, info->pref,
- info->reason_code, info->reason_detail, channels);
+ info->reason_code, channels);
}
@@ -133,9 +132,9 @@
char *pos2 = pos;
ret = os_snprintf(pos2, end - pos2,
- "non_pref_chan[%u]=%u:%u:%u:%u:",
+ "non_pref_chan[%u]=%u:%u:%u:",
count, info->op_class, info->pref,
- info->reason_code, info->reason_detail);
+ info->reason_code);
count++;
if (os_snprintf_error(end - pos2, ret))
break;
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
index 4a87721..3c086bf 100644
--- a/src/ap/ndisc_snoop.c
+++ b/src/ap/ndisc_snoop.c
@@ -17,6 +17,7 @@
#include "ap_drv_ops.h"
#include "list.h"
#include "x_snoop.h"
+#include "ndisc_snoop.h"
struct ip6addr {
struct in6_addr addr;
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
new file mode 100644
index 0000000..b8fd592
--- /dev/null
+++ b/src/ap/neighbor_db.c
@@ -0,0 +1,136 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * 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 "hostapd.h"
+#include "neighbor_db.h"
+
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
+ (!ssid ||
+ (ssid->ssid_len == nr->ssid.ssid_len &&
+ os_memcmp(ssid->ssid, nr->ssid.ssid,
+ ssid->ssid_len) == 0)))
+ return nr;
+ }
+ return NULL;
+}
+
+
+static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
+{
+ wpabuf_free(nr->nr);
+ nr->nr = NULL;
+ wpabuf_free(nr->lci);
+ nr->lci = NULL;
+ wpabuf_free(nr->civic);
+ nr->civic = NULL;
+ os_memset(nr->bssid, 0, sizeof(nr->bssid));
+ os_memset(&nr->ssid, 0, sizeof(nr->ssid));
+ nr->stationary = 0;
+}
+
+
+static struct hostapd_neighbor_entry *
+hostapd_neighbor_add(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ nr = os_zalloc(sizeof(struct hostapd_neighbor_entry));
+ if (!nr)
+ return NULL;
+
+ dl_list_add(&hapd->nr_db, &nr->list);
+
+ return nr;
+}
+
+
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid,
+ const struct wpabuf *nr, const struct wpabuf *lci,
+ const struct wpabuf *civic, int stationary)
+{
+ struct hostapd_neighbor_entry *entry;
+
+ entry = hostapd_neighbor_get(hapd, bssid, ssid);
+ if (!entry)
+ entry = hostapd_neighbor_add(hapd);
+ if (!entry)
+ return -1;
+
+ hostapd_neighbor_clear_entry(entry);
+
+ os_memcpy(entry->bssid, bssid, ETH_ALEN);
+ os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
+
+ entry->nr = wpabuf_dup(nr);
+ if (!entry->nr)
+ goto fail;
+
+ if (lci && wpabuf_len(lci)) {
+ entry->lci = wpabuf_dup(lci);
+ if (!entry->lci || os_get_time(&entry->lci_date))
+ goto fail;
+ }
+
+ if (civic && wpabuf_len(civic)) {
+ entry->civic = wpabuf_dup(civic);
+ if (!entry->civic)
+ goto fail;
+ }
+
+ entry->stationary = stationary;
+
+ return 0;
+
+fail:
+ hostapd_neighbor_remove(hapd, bssid, ssid);
+ return -1;
+}
+
+
+int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid)
+{
+ struct hostapd_neighbor_entry *nr;
+
+ nr = hostapd_neighbor_get(hapd, bssid, ssid);
+ if (!nr)
+ return -1;
+
+ hostapd_neighbor_clear_entry(nr);
+ dl_list_del(&nr->list);
+ os_free(nr);
+
+ return 0;
+}
+
+
+void hostpad_free_neighbor_db(struct hostapd_data *hapd)
+{
+ struct hostapd_neighbor_entry *nr, *prev;
+
+ dl_list_for_each_safe(nr, prev, &hapd->nr_db,
+ struct hostapd_neighbor_entry, list) {
+ hostapd_neighbor_clear_entry(nr);
+ dl_list_del(&nr->list);
+ os_free(nr);
+ }
+}
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
new file mode 100644
index 0000000..ba46d88
--- /dev/null
+++ b/src/ap/neighbor_db.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / Neighboring APs DB
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NEIGHBOR_DB_H
+#define NEIGHBOR_DB_H
+
+struct hostapd_neighbor_entry *
+hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid);
+int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
+ const struct wpa_ssid_value *ssid,
+ const struct wpabuf *nr, const struct wpabuf *lci,
+ const struct wpabuf *civic, int stationary);
+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);
+
+#endif /* NEIGHBOR_DB_H */
diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
index efc1d7e..93e775b 100644
--- a/src/ap/peerkey_auth.c
+++ b/src/ap/peerkey_auth.c
@@ -19,17 +19,6 @@
#ifdef CONFIG_PEERKEY
-static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
-{
-#if 0
- struct wpa_authenticator *wpa_auth = eloop_ctx;
- struct wpa_stsl_negotiation *neg = timeout_ctx;
-#endif
-
- /* TODO: ? */
-}
-
-
struct wpa_stsl_search {
const u8 *addr;
struct wpa_state_machine *sm;
@@ -110,7 +99,6 @@
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
- /* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
@@ -285,7 +273,6 @@
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
- /* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
@@ -365,32 +352,4 @@
wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
}
-
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
- struct wpa_stsl_negotiation *neg)
-{
- struct wpa_stsl_negotiation *pos, *prev;
-
- if (wpa_auth == NULL)
- return -1;
- pos = wpa_auth->stsl_negotiations;
- prev = NULL;
- while (pos) {
- if (pos == neg) {
- if (prev)
- prev->next = pos->next;
- else
- wpa_auth->stsl_negotiations = pos->next;
-
- eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
- os_free(pos);
- return 0;
- }
- prev = pos;
- pos = pos->next;
- }
-
- return -1;
-}
-
#endif /* CONFIG_PEERKEY */
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index d610e7e..bce5abf 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -282,7 +282,42 @@
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
{
- struct rsn_pmksa_cache_entry *entry, *pos;
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, kck, kck_len,
+ aa, spa, session_timeout, eapol,
+ akmp);
+
+ if (pmksa_cache_auth_add_entry(pmksa, entry) < 0)
+ return NULL;
+
+ return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_create_entry - Create a PMKSA cache entry
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @session_timeout: Session timeout
+ * @eapol: Pointer to EAPOL state machine data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function creates a PMKSA entry.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, int session_timeout,
+ struct eapol_state_machine *eapol, int akmp)
+{
+ struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
if (pmk_len > PMK_LEN_MAX)
@@ -315,9 +350,30 @@
os_memcpy(entry->spa, spa, ETH_ALEN);
pmksa_cache_from_eapol_data(entry, eapol);
+ return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_add_entry - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @entry: Pointer to PMKSA cache entry
+ *
+ * This function adds PMKSA cache entry to the PMKSA cache. If an old entry is
+ * already in the cache for the same Supplicant, this entry will be replaced
+ * with the new entry. PMKID will be calculated based on the PMK.
+ */
+int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ struct rsn_pmksa_cache_entry *pos;
+
+ if (entry == NULL)
+ return -1;
+
/* Replace an old entry for the same STA (if found) with the new entry
*/
- pos = pmksa_cache_auth_get(pmksa, spa, NULL);
+ pos = pmksa_cache_auth_get(pmksa, entry->spa, NULL);
if (pos)
pmksa_cache_free_entry(pmksa, pos);
@@ -331,7 +387,7 @@
pmksa_cache_link_entry(pmksa, entry);
- return entry;
+ return 0;
}
@@ -605,3 +661,70 @@
}
return pos - buf;
}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+/**
+ * pmksa_cache_auth_list_mesh - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @addr: MAC address of the peer (NULL means any)
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA_GET command to store
+ * in external storage.
+ */
+int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
+ char *buf, size_t len)
+{
+ int ret;
+ char *pos, *end;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ pos = buf;
+ end = buf + len;
+ os_get_reltime(&now);
+
+
+ /*
+ * Entry format:
+ * <BSSID> <PMKID> <PMK> <expiration in seconds>
+ */
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0)
+ continue;
+
+ ret = os_snprintf(pos, end - pos, MACSTR " ",
+ MAC2STR(entry->spa));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos, entry->pmkid,
+ PMKID_LEN);
+
+ ret = os_snprintf(pos, end - pos, " ");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos, entry->pmk,
+ entry->pmk_len);
+
+ ret = os_snprintf(pos, end - pos, " %d\n",
+ (int) (entry->expiration - now.sec));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index d8d9c5a..bd1b672 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -53,6 +53,13 @@
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, int session_timeout,
+ struct eapol_state_machine *eapol, int akmp);
+int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa, const u8 *pmkid);
@@ -65,5 +72,7 @@
struct radius_das_attrs *attr);
int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
+int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
+ char *buf, size_t len);
#endif /* PMKSA_CACHE_H */
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
new file mode 100644
index 0000000..56ed29c
--- /dev/null
+++ b/src/ap/rrm.c
@@ -0,0 +1,674 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ * Copyright (c) 2016-2017, 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 "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "eloop.h"
+#include "neighbor_db.h"
+#include "rrm.h"
+
+#define HOSTAPD_RRM_REQUEST_TIMEOUT 5
+
+
+static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out",
+ hapd->lci_req_token);
+ hapd->lci_req_active = 0;
+}
+
+
+static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token,
+ const u8 *pos, size_t len)
+{
+ if (!hapd->lci_req_active || hapd->lci_req_token != token) {
+ wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token);
+ return;
+ }
+
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
+ wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len);
+}
+
+
+static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx)
+{
+ struct hostapd_data *hapd = eloop_data;
+
+ wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out",
+ hapd->range_req_token);
+ hapd->range_req_active = 0;
+}
+
+
+static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
+ const u8 *pos, size_t len)
+{
+ if (!hapd->range_req_active || hapd->range_req_token != token) {
+ wpa_printf(MSG_DEBUG, "Unexpected range report, token %u",
+ token);
+ return;
+ }
+
+ hapd->range_req_active = 0;
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
+ wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len);
+}
+
+
+static void hostapd_handle_beacon_report(struct hostapd_data *hapd,
+ const u8 *addr, u8 token, u8 rep_mode,
+ const u8 *pos, size_t len)
+{
+ char report[2 * 255 + 1];
+
+ wpa_printf(MSG_DEBUG, "Beacon report token %u len %zu from " MACSTR,
+ token, len, MAC2STR(addr));
+ /* Skip to the beginning of the Beacon report */
+ if (len < 3)
+ return;
+ pos += 3;
+ len -= 3;
+ report[0] = '\0';
+ if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0)
+ return;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
+ MAC2STR(addr), token, rep_mode, report);
+}
+
+
+static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+ const u8 *pos, *ie, *end;
+ u8 token, rep_mode;
+
+ end = buf + len;
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+
+ while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
+ if (ie[1] < 3) {
+ wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
+ break;
+ }
+
+ rep_mode = ie[3];
+ wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u",
+ rep_mode, ie[4]);
+
+ switch (ie[4]) {
+ case MEASURE_TYPE_LCI:
+ hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]);
+ break;
+ case MEASURE_TYPE_FTM_RANGE:
+ hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
+ break;
+ case MEASURE_TYPE_BEACON:
+ hostapd_handle_beacon_report(hapd, mgmt->sa, token,
+ rep_mode, ie + 2, ie[1]);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Measurement report type %u is not supported",
+ ie[4]);
+ break;
+ }
+
+ pos = ie + ie[1] + 2;
+ }
+}
+
+
+static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
+{
+ const u8 *subelem;
+
+ /* Range Request element + Location Subject + Maximum Age subelement */
+ if (len < 3 + 1 + 4)
+ return 0;
+
+ /* Subelements are arranged as IEs */
+ subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
+ if (subelem && subelem[1] == 2)
+ return WPA_GET_LE16(subelem + 2);
+
+ return 0;
+}
+
+
+static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
+{
+ struct os_time curr, diff;
+ unsigned long diff_l;
+
+ if (nr->stationary || max_age == 0xffff)
+ return 1;
+
+ if (!max_age)
+ return 0;
+
+ if (os_get_time(&curr))
+ return 0;
+
+ os_time_sub(&curr, &nr->lci_date, &diff);
+
+ /* avoid overflow */
+ if (diff.sec > 0xffff)
+ return 0;
+
+ /* LCI age is calculated in 10th of a second units. */
+ diff_l = diff.sec * 10 + diff.usec / 100000;
+
+ return max_age > diff_l;
+}
+
+
+static size_t hostapd_neighbor_report_len(struct wpabuf *buf,
+ struct hostapd_neighbor_entry *nr,
+ int send_lci, int send_civic)
+{
+ size_t len = 2 + wpabuf_len(nr->nr);
+
+ if (send_lci && nr->lci)
+ len += 2 + wpabuf_len(nr->lci);
+
+ if (send_civic && nr->civic)
+ len += 2 + wpabuf_len(nr->civic);
+
+ return len;
+}
+
+
+static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
+ const u8 *addr, u8 dialog_token,
+ struct wpa_ssid_value *ssid, u8 lci,
+ u8 civic, u16 lci_max_age)
+{
+ struct hostapd_neighbor_entry *nr;
+ struct wpabuf *buf;
+ u8 *msmt_token;
+
+ /*
+ * The number and length of the Neighbor Report elements in a Neighbor
+ * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes
+ * of RRM header.
+ */
+ buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE);
+ if (!buf)
+ return;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE);
+ wpabuf_put_u8(buf, dialog_token);
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ int send_lci;
+ size_t len;
+
+ if (ssid->ssid_len != nr->ssid.ssid_len ||
+ os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0)
+ continue;
+
+ send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age);
+ len = hostapd_neighbor_report_len(buf, nr, send_lci, civic);
+
+ if (len - 2 > 0xff) {
+ wpa_printf(MSG_DEBUG,
+ "NR entry for " MACSTR " exceeds 0xFF bytes",
+ MAC2STR(nr->bssid));
+ continue;
+ }
+
+ if (len > wpabuf_tailroom(buf))
+ break;
+
+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+ wpabuf_put_u8(buf, len - 2);
+ wpabuf_put_buf(buf, nr->nr);
+
+ if (send_lci && nr->lci) {
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->lci));
+ /*
+ * Override measurement token - the first byte of the
+ * Measurement Report element.
+ */
+ msmt_token = wpabuf_put(buf, 0);
+ wpabuf_put_buf(buf, nr->lci);
+ *msmt_token = lci;
+ }
+
+ if (civic && nr->civic) {
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->civic));
+ /*
+ * Override measurement token - the first byte of the
+ * Measurement Report element.
+ */
+ msmt_token = wpabuf_put(buf, 0);
+ wpabuf_put_buf(buf, nr->civic);
+ *msmt_token = civic;
+ }
+ }
+
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+}
+
+
+static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+ const u8 *pos, *ie, *end;
+ struct wpa_ssid_value ssid = {
+ .ssid_len = 0
+ };
+ u8 token;
+ u8 lci = 0, civic = 0; /* Measurement tokens */
+ u16 lci_max_age = 0;
+
+ if (!(hapd->conf->radio_measurements[0] &
+ WLAN_RRM_CAPS_NEIGHBOR_REPORT))
+ return;
+
+ end = buf + len;
+
+ token = mgmt->u.action.u.rrm.dialog_token;
+ pos = mgmt->u.action.u.rrm.variable;
+ len = end - pos;
+
+ ie = get_ie(pos, len, WLAN_EID_SSID);
+ if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) {
+ ssid.ssid_len = ie[1];
+ os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len);
+ } else {
+ ssid.ssid_len = hapd->conf->ssid.ssid_len;
+ os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
+ }
+
+ while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) {
+ if (ie[1] < 3)
+ break;
+
+ wpa_printf(MSG_DEBUG,
+ "Neighbor report request, measure type %u",
+ ie[4]);
+
+ switch (ie[4]) { /* Measurement Type */
+ case MEASURE_TYPE_LCI:
+ lci = ie[2]; /* Measurement Token */
+ lci_max_age = hostapd_parse_location_lci_req_age(ie + 2,
+ ie[1]);
+ break;
+ case MEASURE_TYPE_LOCATION_CIVIC:
+ civic = ie[2]; /* Measurement token */
+ break;
+ }
+
+ pos = ie + ie[1] + 2;
+ len = end - pos;
+ }
+
+ hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic,
+ lci_max_age);
+}
+
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+ const u8 *buf, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
+
+ /*
+ * Check for enough bytes: header + (1B)Category + (1B)Action +
+ * (1B)Dialog Token.
+ */
+ if (len < IEEE80211_HDRLEN + 3)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
+ mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
+
+ switch (mgmt->u.action.u.rrm.action) {
+ case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
+ hostapd_handle_radio_msmt_report(hapd, buf, len);
+ break;
+ case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
+ hostapd_handle_nei_report_req(hapd, buf, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
+ mgmt->u.action.u.rrm.action);
+ break;
+ }
+}
+
+
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ int ret;
+
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Request LCI: Destination address is not connected");
+ return -1;
+ }
+
+ if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
+ wpa_printf(MSG_INFO,
+ "Request LCI: Station does not support LCI in RRM");
+ return -1;
+ }
+
+ if (hapd->lci_req_active) {
+ wpa_printf(MSG_DEBUG,
+ "Request LCI: LCI request is already in process, overriding");
+ hapd->lci_req_active = 0;
+ eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
+ NULL);
+ }
+
+ /* Measurement request (5) + Measurement element with LCI (10) */
+ buf = wpabuf_alloc(5 + 10);
+ if (!buf)
+ return -1;
+
+ hapd->lci_req_token++;
+ /* For wraparounds - the token must be nonzero */
+ if (!hapd->lci_req_token)
+ hapd->lci_req_token++;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->lci_req_token);
+ wpabuf_put_le16(buf, 0); /* Number of repetitions */
+
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, 3 + 1 + 4);
+
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ /*
+ * Parallel and Enable bits are 0, Duration, Request, and Report are
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
+
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+ wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+ wpabuf_put_u8(buf, 2);
+ wpabuf_put_le16(buf, 0xffff);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret)
+ return ret;
+
+ hapd->lci_req_active = 1;
+
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_lci_rep_timeout_handler, hapd, NULL);
+
+ return 0;
+}
+
+
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+ u16 random_interval, u8 min_ap,
+ const u8 *responders, unsigned int n_responders)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta;
+ u8 *len;
+ unsigned int i;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
+ " rand interval %u min AP %u n_responders %u", MAC2STR(addr),
+ random_interval, min_ap, n_responders);
+
+ if (min_ap == 0 || min_ap > n_responders) {
+ wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Request range: Destination address is not connected");
+ return -1;
+ }
+
+ if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
+ wpa_printf(MSG_ERROR,
+ "Request range: Destination station does not support FTM range report in RRM");
+ return -1;
+ }
+
+ if (hapd->range_req_active) {
+ wpa_printf(MSG_DEBUG,
+ "Request range: Range request is already in process; overriding");
+ hapd->range_req_active = 0;
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd,
+ NULL);
+ }
+
+ /* Action + measurement type + token + reps + EID + len = 7 */
+ buf = wpabuf_alloc(7 + 255);
+ if (!buf)
+ return -1;
+
+ hapd->range_req_token++;
+ if (!hapd->range_req_token) /* For wraparounds */
+ hapd->range_req_token++;
+
+ /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
+ wpabuf_put_le16(buf, 0); /* Number of Repetitions */
+
+ /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ len = wpabuf_put(buf, 1); /* Length will be set later */
+
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ /*
+ * Parallel and Enable bits are 0; Duration, Request, and Report are
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
+
+ /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
+ wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
+ wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
+
+ /* FTM Range Subelements */
+
+ /*
+ * Taking the neighbor report part of the range request from neighbor
+ * database instead of requesting the separate bits of data from the
+ * user.
+ */
+ for (i = 0; i < n_responders; i++) {
+ struct hostapd_neighbor_entry *nr;
+
+ nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
+ NULL);
+ if (!nr) {
+ wpa_printf(MSG_INFO, "Missing neighbor report for "
+ MACSTR, MAC2STR(responders + ETH_ALEN * i));
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
+ wpa_printf(MSG_ERROR, "Too long range request");
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
+ wpabuf_put_u8(buf, wpabuf_len(nr->nr));
+ wpabuf_put_buf(buf, nr->nr);
+ }
+
+ /* Action + measurement type + token + reps + EID + len = 7 */
+ *len = wpabuf_len(buf) - 7;
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret)
+ return ret;
+
+ hapd->range_req_active = 1;
+
+ eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
+ hostapd_range_rep_timeout_handler, hapd, NULL);
+
+ return 0;
+}
+
+
+void hostapd_clean_rrm(struct hostapd_data *hapd)
+{
+ hostpad_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);
+ hapd->range_req_active = 0;
+}
+
+
+int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
+ u8 req_mode, const struct wpabuf *req)
+{
+ struct wpabuf *buf;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+ int ret;
+ enum beacon_report_mode mode;
+ const u8 *pos;
+
+ /* Request data:
+ * Operating Class (1), Channel Number (1), Randomization Interval (2),
+ * Measurement Duration (2), Measurement Mode (1), BSSID (6),
+ * Optional Subelements (variable)
+ */
+ if (wpabuf_len(req) < 13) {
+ wpa_printf(MSG_INFO, "Beacon request: Too short request data");
+ return -1;
+ }
+ pos = wpabuf_head(req);
+ mode = pos[6];
+
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR " is not connected",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ switch (mode) {
+ case BEACON_REPORT_MODE_PASSIVE:
+ if (!(sta->rrm_enabled_capa[0] &
+ WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR
+ " does not support passive beacon report",
+ MAC2STR(addr));
+ return -1;
+ }
+ break;
+ case BEACON_REPORT_MODE_ACTIVE:
+ if (!(sta->rrm_enabled_capa[0] &
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR
+ " does not support active beacon report",
+ MAC2STR(addr));
+ return -1;
+ }
+ break;
+ case BEACON_REPORT_MODE_TABLE:
+ if (!(sta->rrm_enabled_capa[0] &
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) {
+ wpa_printf(MSG_INFO,
+ "Beacon request: " MACSTR
+ " does not support table beacon report",
+ MAC2STR(addr));
+ return -1;
+ }
+ break;
+ default:
+ wpa_printf(MSG_INFO,
+ "Beacon request: Unknown measurement mode %d", mode);
+ return -1;
+ }
+
+ buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req));
+ if (!buf)
+ return -1;
+
+ hapd->beacon_req_token++;
+ if (!hapd->beacon_req_token)
+ hapd->beacon_req_token++;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
+ wpabuf_put_u8(buf, hapd->beacon_req_token);
+ wpabuf_put_le16(buf, 0); /* Number of repetitions */
+
+ /* Measurement Request element */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, 3 + wpabuf_len(req));
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+ wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */
+ wpabuf_put_buf(buf, req);
+
+ ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpabuf_free(buf);
+ if (ret < 0)
+ return ret;
+
+ return hapd->beacon_req_token;
+}
+
+
+void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok)
+{
+ if (len < 24 + 3)
+ return;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR
+ " %u ack=%d", MAC2STR(mgmt->da),
+ mgmt->u.action.u.rrm.dialog_token, ok);
+}
diff --git a/src/ap/rrm.h b/src/ap/rrm.h
new file mode 100644
index 0000000..02cd522
--- /dev/null
+++ b/src/ap/rrm.h
@@ -0,0 +1,33 @@
+/*
+ * hostapd / Radio Measurement (RRM)
+ * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
+ * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RRM_H
+#define RRM_H
+
+/*
+ * Max measure request length is 255, -6 of the body we have 249 for the
+ * neighbor report elements. Each neighbor report element is at least 2 + 13
+ * bytes, so we can't have more than 16 responders in the request.
+ */
+#define RRM_RANGE_REQ_MAX_RESPONDERS 16
+
+void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
+ const u8 *buf, size_t len);
+int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
+ u16 random_interval, u8 min_ap,
+ const u8 *responders, unsigned int n_responders);
+void hostapd_clean_rrm(struct hostapd_data *hapd);
+int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr,
+ u8 req_mode, const struct wpabuf *req);
+void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int ok);
+
+#endif /* RRM_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index c36842b..af8c754 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1,6 +1,6 @@
/*
* hostapd / Station table
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,6 +36,7 @@
#include "ndisc_snoop.h"
#include "sta_info.h"
#include "vlan.h"
+#include "wps_hostapd.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
@@ -47,6 +48,7 @@
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_IEEE80211W */
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -222,6 +224,13 @@
hapd->iface->num_sta_ht_20mhz--;
}
+#ifdef CONFIG_TAXONOMY
+ wpabuf_free(sta->probe_ie_taxonomy);
+ sta->probe_ie_taxonomy = NULL;
+ wpabuf_free(sta->assoc_ie_taxonomy);
+ sta->assoc_ie_taxonomy = NULL;
+#endif /* CONFIG_TAXONOMY */
+
#ifdef CONFIG_IEEE80211N
ht40_intolerant_remove(hapd->iface, sta);
#endif /* CONFIG_IEEE80211N */
@@ -330,6 +339,13 @@
mbo_ap_sta_free(sta);
os_free(sta->supp_op_classes);
+#ifdef CONFIG_FILS
+ os_free(sta->fils_pending_assoc_req);
+ wpabuf_free(sta->fils_hlp_resp);
+ wpabuf_free(sta->hlp_dhcp_discover);
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+#endif /* CONFIG_FILS */
+
os_free(sta);
}
@@ -660,6 +676,11 @@
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
dl_list_init(&sta->ip6addr);
+#ifdef CONFIG_TAXONOMY
+ sta_track_claim_taxonomy_info(hapd->iface, addr,
+ &sta->probe_ie_taxonomy);
+#endif /* CONFIG_TAXONOMY */
+
return sta;
}
@@ -733,9 +754,17 @@
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
- sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ /* Skip deauthentication in DMG/IEEE 802.11ad */
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+ WLAN_STA_ASSOC_REQ_OK);
+ sta->timeout_next = STA_REMOVE;
+ } else {
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ sta->timeout_next = STA_DEAUTH;
+ }
ap_sta_set_authorized(hapd, sta, 0);
- sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
"for " MACSTR " (%d seconds - "
"AP_MAX_INACTIVITY_AFTER_DISASSOC)",
@@ -771,6 +800,14 @@
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ ap_sta_disassociate(hapd, sta, reason);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
@@ -1217,6 +1254,20 @@
ap_handle_timer, hapd, sta);
sta->timeout_next = STA_REMOVE;
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ sta->disassoc_reason = reason;
+ sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+ eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ eloop_register_timeout(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
+ 2 : 0, 0, ap_sta_disassoc_cb_timeout,
+ hapd, sta);
+ return;
+ }
+
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
@@ -1263,6 +1314,15 @@
"%s: Removed ap_sta_disassoc_cb_timeout timeout for "
MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
+ if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
+ MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+ if (sta->flags & WLAN_STA_WPS)
+ hostapd_wps_eap_completed(hapd);
+ }
}
@@ -1297,3 +1357,45 @@
return res;
}
+
+
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "IEEE 802.1X: Scheduled disconnection of " MACSTR
+ " after EAP-Failure", MAC2STR(sta->addr));
+
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+ if (sta->flags & WLAN_STA_WPS)
+ hostapd_wps_eap_completed(hapd);
+}
+
+
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "IEEE 802.1X: Force disconnection of " MACSTR
+ " after EAP-Failure in 10 ms", MAC2STR(sta->addr));
+
+ /*
+ * Add a small sleep to increase likelihood of previously requested
+ * EAP-Failure TX getting out before this should the driver reorder
+ * operations.
+ */
+ eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
+ eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
+ hapd, sta);
+}
+
+
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
+ hapd, sta);
+}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 3d9a928..6f55403 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -12,10 +12,12 @@
#ifdef CONFIG_MESH
/* needed for mesh_plink_state enum */
#include "common/defs.h"
+#include "common/wpa_common.h"
#endif /* CONFIG_MESH */
#include "list.h"
#include "vlan.h"
+#include "common/ieee802_11_defs.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -37,6 +39,7 @@
#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
#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_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -51,7 +54,6 @@
u8 op_class;
u8 pref;
u8 reason_code;
- u8 reason_detail;
u8 num_channels;
u8 channels[];
};
@@ -79,13 +81,22 @@
enum mesh_plink_state plink_state;
u16 peer_lid;
u16 my_lid;
+ u16 peer_aid;
u16 mpm_close_reason;
int mpm_retries;
- u8 my_nonce[32];
- u8 peer_nonce[32];
+ u8 my_nonce[WPA_NONCE_LEN];
+ u8 peer_nonce[WPA_NONCE_LEN];
u8 aek[32]; /* SHA256 digest length */
- u8 mtk[16];
- u8 mgtk[16];
+ u8 mtk[WPA_TK_MAX_LEN];
+ size_t mtk_len;
+ u8 mgtk_rsc[6];
+ u8 mgtk_key_id;
+ u8 mgtk[WPA_TK_MAX_LEN];
+ size_t mgtk_len;
+ u8 igtk_rsc[6];
+ u8 igtk[WPA_TK_MAX_LEN];
+ size_t igtk_len;
+ u16 igtk_key_id;
u8 sae_auth_retry;
#endif /* CONFIG_MESH */
@@ -104,6 +115,7 @@
unsigned int radius_das_match:1;
unsigned int ecsa_supported:1;
unsigned int added_unassoc:1;
+ unsigned int pending_wds_enable:1;
u16 auth_alg;
@@ -202,6 +214,24 @@
u8 *supp_op_classes; /* Supported Operating Classes element, if
* received, starting from the Length field */
+
+ u8 rrm_enabled_capa[5];
+
+#ifdef CONFIG_TAXONOMY
+ struct wpabuf *probe_ie_taxonomy;
+ struct wpabuf *assoc_ie_taxonomy;
+#endif /* CONFIG_TAXONOMY */
+
+#ifdef CONFIG_FILS
+ u8 fils_snonce[FILS_NONCE_LEN];
+ u8 fils_session[FILS_SESSION_LEN];
+ u8 *fils_pending_assoc_req;
+ size_t fils_pending_assoc_req_len;
+ unsigned int fils_pending_assoc_is_reassoc:1;
+ unsigned int fils_dhcp_rapid_commit_proxy:1;
+ struct wpabuf *fils_hlp_resp;
+ struct wpabuf *hlp_dhcp_discover;
+#endif /* CONFIG_FILS */
};
@@ -273,5 +303,9 @@
struct sta_info *sta);
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta);
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta);
#endif /* STA_INFO_H */
diff --git a/src/ap/taxonomy.c b/src/ap/taxonomy.c
new file mode 100644
index 0000000..ae157a7
--- /dev/null
+++ b/src/ap/taxonomy.c
@@ -0,0 +1,292 @@
+/*
+ * hostapd / Client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Parse a series of IEs, as in Probe Request or (Re)Association Request frames,
+ * and render them to a descriptive string. The tag number of standard options
+ * is written to the string, while the vendor ID and subtag are written for
+ * vendor options.
+ *
+ * Example strings:
+ * 0,1,50,45,221(00904c,51)
+ * 0,1,33,36,48,45,221(00904c,51),221(0050f2,2)
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "taxonomy.h"
+
+
+/* Copy a string with no funny schtuff allowed; only alphanumerics. */
+static void no_mischief_strncpy(char *dst, const char *src, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ unsigned char s = src[i];
+ int is_lower = s >= 'a' && s <= 'z';
+ int is_upper = s >= 'A' && s <= 'Z';
+ int is_digit = s >= '0' && s <= '9';
+
+ if (is_lower || is_upper || is_digit) {
+ /* TODO: if any manufacturer uses Unicode within the
+ * WPS header, it will get mangled here. */
+ dst[i] = s;
+ } else {
+ /* Note that even spaces will be transformed to
+ * underscores, so 'Nexus 7' will turn into 'Nexus_7'.
+ * This is deliberate, to make the string easier to
+ * parse. */
+ dst[i] = '_';
+ }
+ }
+}
+
+
+static int get_wps_name(char *name, size_t name_len,
+ const u8 *data, size_t data_len)
+{
+ /* Inside the WPS IE are a series of attributes, using two byte IDs
+ * and two byte lengths. We're looking for the model name, if
+ * present. */
+ while (data_len >= 4) {
+ u16 id, elen;
+
+ id = WPA_GET_BE16(data);
+ elen = WPA_GET_BE16(data + 2);
+ data += 4;
+ data_len -= 4;
+
+ if (elen > data_len)
+ return 0;
+
+ if (id == 0x1023) {
+ /* Model name, like 'Nexus 7' */
+ size_t n = (elen < name_len) ? elen : name_len;
+ no_mischief_strncpy(name, (const char *) data, n);
+ return n;
+ }
+
+ data += elen;
+ data_len -= elen;
+ }
+
+ return 0;
+}
+
+
+static void ie_to_string(char *fstr, size_t fstr_len, const struct wpabuf *ies)
+{
+ char *fpos = fstr;
+ char *fend = fstr + fstr_len;
+ char htcap[7 + 4 + 1]; /* ",htcap:" + %04hx + trailing NUL */
+ char htagg[7 + 2 + 1]; /* ",htagg:" + %02hx + trailing NUL */
+ char htmcs[7 + 8 + 1]; /* ",htmcs:" + %08x + trailing NUL */
+ char vhtcap[8 + 8 + 1]; /* ",vhtcap:" + %08x + trailing NUL */
+ char vhtrxmcs[10 + 8 + 1]; /* ",vhtrxmcs:" + %08x + trailing NUL */
+ char vhttxmcs[10 + 8 + 1]; /* ",vhttxmcs:" + %08x + trailing NUL */
+#define MAX_EXTCAP 254
+ char extcap[8 + 2 * MAX_EXTCAP + 1]; /* ",extcap:" + hex + trailing NUL
+ */
+ char txpow[7 + 4 + 1]; /* ",txpow:" + %04hx + trailing NUL */
+#define WPS_NAME_LEN 32
+ char wps[WPS_NAME_LEN + 5 + 1]; /* room to prepend ",wps:" + trailing
+ * NUL */
+ int num = 0;
+ const u8 *ie;
+ size_t ie_len;
+ int ret;
+
+ os_memset(htcap, 0, sizeof(htcap));
+ os_memset(htagg, 0, sizeof(htagg));
+ os_memset(htmcs, 0, sizeof(htmcs));
+ os_memset(vhtcap, 0, sizeof(vhtcap));
+ os_memset(vhtrxmcs, 0, sizeof(vhtrxmcs));
+ os_memset(vhttxmcs, 0, sizeof(vhttxmcs));
+ os_memset(extcap, 0, sizeof(extcap));
+ os_memset(txpow, 0, sizeof(txpow));
+ os_memset(wps, 0, sizeof(wps));
+ *fpos = '\0';
+
+ if (!ies)
+ return;
+ ie = wpabuf_head(ies);
+ ie_len = wpabuf_len(ies);
+
+ while (ie_len >= 2) {
+ u8 id, elen;
+ char *sep = (num++ == 0) ? "" : ",";
+
+ id = *ie++;
+ elen = *ie++;
+ ie_len -= 2;
+
+ if (elen > ie_len)
+ break;
+
+ if (id == WLAN_EID_VENDOR_SPECIFIC && elen >= 4) {
+ /* Vendor specific */
+ if (WPA_GET_BE32(ie) == WPS_IE_VENDOR_TYPE) {
+ /* WPS */
+ char model_name[WPS_NAME_LEN + 1];
+ const u8 *data = &ie[4];
+ size_t data_len = elen - 4;
+
+ os_memset(model_name, 0, sizeof(model_name));
+ if (get_wps_name(model_name, WPS_NAME_LEN, data,
+ data_len)) {
+ os_snprintf(wps, sizeof(wps),
+ ",wps:%s", model_name);
+ }
+ }
+
+ ret = os_snprintf(fpos, fend - fpos,
+ "%s%d(%02x%02x%02x,%d)",
+ sep, id, ie[0], ie[1], ie[2], ie[3]);
+ } else {
+ if (id == WLAN_EID_HT_CAP && elen >= 2) {
+ /* HT Capabilities (802.11n) */
+ os_snprintf(htcap, sizeof(htcap),
+ ",htcap:%04hx",
+ WPA_GET_LE16(ie));
+ }
+ if (id == WLAN_EID_HT_CAP && elen >= 3) {
+ /* HT Capabilities (802.11n), A-MPDU information
+ */
+ os_snprintf(htagg, sizeof(htagg),
+ ",htagg:%02hx", (u16) ie[2]);
+ }
+ if (id == WLAN_EID_HT_CAP && elen >= 7) {
+ /* HT Capabilities (802.11n), MCS information */
+ os_snprintf(htmcs, sizeof(htmcs),
+ ",htmcs:%08hx",
+ (u16) WPA_GET_LE32(ie + 3));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 4) {
+ /* VHT Capabilities (802.11ac) */
+ os_snprintf(vhtcap, sizeof(vhtcap),
+ ",vhtcap:%08x",
+ WPA_GET_LE32(ie));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 8) {
+ /* VHT Capabilities (802.11ac), RX MCS
+ * information */
+ os_snprintf(vhtrxmcs, sizeof(vhtrxmcs),
+ ",vhtrxmcs:%08x",
+ WPA_GET_LE32(ie + 4));
+ }
+ if (id == WLAN_EID_VHT_CAP && elen >= 12) {
+ /* VHT Capabilities (802.11ac), TX MCS
+ * information */
+ os_snprintf(vhttxmcs, sizeof(vhttxmcs),
+ ",vhttxmcs:%08x",
+ WPA_GET_LE32(ie + 8));
+ }
+ if (id == WLAN_EID_EXT_CAPAB) {
+ /* Extended Capabilities */
+ int i;
+ int len = (elen < MAX_EXTCAP) ? elen :
+ MAX_EXTCAP;
+ char *p = extcap;
+
+ p += os_snprintf(extcap, sizeof(extcap),
+ ",extcap:");
+ for (i = 0; i < len; i++) {
+ int lim;
+
+ lim = sizeof(extcap) -
+ os_strlen(extcap);
+ if (lim <= 0)
+ break;
+ p += os_snprintf(p, lim, "%02x",
+ *(ie + i));
+ }
+ }
+ if (id == WLAN_EID_PWR_CAPABILITY && elen == 2) {
+ /* TX Power */
+ os_snprintf(txpow, sizeof(txpow),
+ ",txpow:%04hx",
+ WPA_GET_LE16(ie));
+ }
+
+ ret = os_snprintf(fpos, fend - fpos, "%s%d", sep, id);
+ }
+ if (os_snprintf_error(fend - fpos, ret))
+ goto fail;
+ fpos += ret;
+
+ ie += elen;
+ ie_len -= elen;
+ }
+
+ ret = os_snprintf(fpos, fend - fpos, "%s%s%s%s%s%s%s%s%s",
+ htcap, htagg, htmcs, vhtcap, vhtrxmcs, vhttxmcs,
+ txpow, extcap, wps);
+ if (os_snprintf_error(fend - fpos, ret)) {
+ fail:
+ fstr[0] = '\0';
+ }
+}
+
+
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+ struct sta_info *sta, char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+
+ if (!sta->probe_ie_taxonomy || !sta->assoc_ie_taxonomy)
+ return 0;
+
+ ret = os_snprintf(buf, buflen, "wifi4|probe:");
+ if (os_snprintf_error(buflen, ret))
+ return 0;
+ pos = buf + ret;
+ end = buf + buflen;
+
+ ie_to_string(pos, end - pos, sta->probe_ie_taxonomy);
+ pos = os_strchr(pos, '\0');
+ if (pos >= end)
+ return 0;
+ ret = os_snprintf(pos, end - pos, "|assoc:");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie_to_string(pos, end - pos, sta->assoc_ie_taxonomy);
+ pos = os_strchr(pos, '\0');
+ return pos - buf;
+}
+
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(sta->probe_ie_taxonomy);
+ sta->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct hostapd_sta_info *info,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(info->probe_ie_taxonomy);
+ info->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
+
+
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len)
+{
+ wpabuf_free(sta->assoc_ie_taxonomy);
+ sta->assoc_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
+}
diff --git a/src/ap/taxonomy.h b/src/ap/taxonomy.h
new file mode 100644
index 0000000..80f245c
--- /dev/null
+++ b/src/ap/taxonomy.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / Station client taxonomy
+ * Copyright (c) 2015 Google, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TAXONOMY_H
+#define TAXONOMY_H
+
+void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len);
+void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
+ struct hostapd_sta_info *sta,
+ const u8 *ie, size_t ie_len);
+void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *ie, size_t ie_len);
+int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
+ struct sta_info *sta, char *buf, size_t buflen);
+
+#endif /* TAXONOMY_H */
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 314e244..8054c5d 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -21,11 +21,6 @@
#include "wmm.h"
-/* TODO: maintain separate sequence and fragment numbers for each AC
- * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
- * if only WMM stations are receiving a certain group */
-
-
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
{
u8 ret;
@@ -157,8 +152,9 @@
int wmm_process_tspec(struct wmm_tspec_element *tspec)
{
- int medium_time, pps, duration;
- int up, psb, dir, tid;
+ u64 medium_time;
+ unsigned int pps, duration;
+ unsigned int up, psb, dir, tid;
u16 val, surplus;
up = (tspec->ts_info[1] >> 3) & 0x07;
@@ -206,8 +202,9 @@
return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
}
- medium_time = surplus * pps * duration / 0x2000;
- wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
+ medium_time = (u64) surplus * pps * duration / 0x2000;
+ wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %lu",
+ (unsigned long) medium_time);
/*
* TODO: store list of granted (and still active) TSPECs and check
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 02daa9b..adb66c1 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -95,8 +95,8 @@
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Response action frame");
- os_free(wnmtfs_ie);
- return -1;
+ res = -1;
+ goto fail;
}
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -118,11 +118,8 @@
(int) gtk_elem_len);
#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
- if (res < 0) {
- os_free(wnmtfs_ie);
- os_free(mgmt);
- return -1;
- }
+ if (res < 0)
+ goto fail;
igtk_elem_len = res;
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
@@ -184,6 +181,7 @@
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
+fail:
os_free(wnmtfs_ie);
os_free(mgmt);
return res;
@@ -214,7 +212,8 @@
u8 ie_len = pos[1];
if (pos + 2 + ie_len > frm + len)
break;
- if (*pos == WLAN_EID_WNMSLEEP)
+ if (*pos == WLAN_EID_WNMSLEEP &&
+ ie_len >= (int) sizeof(*wnmsleep_ie) - 2)
wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_REQ) {
if (!tfsreq_ie_start)
@@ -258,20 +257,14 @@
static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
const u8 *addr,
- u8 dialog_token,
- const char *url)
+ u8 dialog_token)
{
struct ieee80211_mgmt *mgmt;
- size_t url_len, len;
+ size_t len;
u8 *pos;
int res;
- if (url)
- url_len = os_strlen(url);
- else
- url_len = 0;
-
- mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0));
+ mgmt = os_zalloc(sizeof(*mgmt));
if (mgmt == NULL)
return -1;
os_memcpy(mgmt->da, addr, ETH_ALEN);
@@ -286,11 +279,6 @@
mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
mgmt->u.action.u.bss_tm_req.validity_interval = 1;
pos = mgmt->u.action.u.bss_tm_req.variable;
- if (url) {
- *pos++ += url_len;
- os_memcpy(pos, url, url_len);
- pos += url_len;
- }
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
@@ -333,7 +321,7 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
- ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL);
+ ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index bf10cc1..85e85e0 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -13,7 +13,9 @@
#include "utils/state_machine.h"
#include "utils/bitfield.h"
#include "common/ieee802_11_defs.h"
+#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
+#include "crypto/aes_siv.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
@@ -35,6 +37,10 @@
static int wpa_sm_step(struct wpa_state_machine *sm);
static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
size_t data_len);
+#ifdef CONFIG_FILS
+static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *buf, size_t buf_len, u16 *_key_data_len);
+#endif /* CONFIG_FILS */
static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
@@ -52,9 +58,8 @@
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
-static const u32 dot11RSNAConfigGroupUpdateCount = 4;
-static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
static const u32 eapol_key_timeout_first = 100; /* ms */
static const u32 eapol_key_timeout_subseq = 1000; /* ms */
static const u32 eapol_key_timeout_first_group = 500; /* ms */
@@ -68,8 +73,8 @@
static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
- if (wpa_auth->cb.mic_failure_report)
- return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ if (wpa_auth->cb->mic_failure_report)
+ return wpa_auth->cb->mic_failure_report(wpa_auth->cb_ctx, addr);
return 0;
}
@@ -77,8 +82,8 @@
static inline void wpa_auth_psk_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
- if (wpa_auth->cb.psk_failure_report)
- wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
+ if (wpa_auth->cb->psk_failure_report)
+ wpa_auth->cb->psk_failure_report(wpa_auth->cb_ctx, addr);
}
@@ -86,17 +91,17 @@
const u8 *addr, wpa_eapol_variable var,
int value)
{
- if (wpa_auth->cb.set_eapol)
- wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);
+ if (wpa_auth->cb->set_eapol)
+ wpa_auth->cb->set_eapol(wpa_auth->cb_ctx, addr, var, value);
}
static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var)
{
- if (wpa_auth->cb.get_eapol == NULL)
+ if (wpa_auth->cb->get_eapol == NULL)
return -1;
- return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);
+ return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var);
}
@@ -105,19 +110,19 @@
const u8 *p2p_dev_addr,
const u8 *prev_psk)
{
- if (wpa_auth->cb.get_psk == NULL)
+ if (wpa_auth->cb->get_psk == NULL)
return NULL;
- return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, p2p_dev_addr,
- prev_psk);
+ return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
+ prev_psk);
}
static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
const u8 *addr, u8 *msk, size_t *len)
{
- if (wpa_auth->cb.get_msk == NULL)
+ if (wpa_auth->cb->get_msk == NULL)
return -1;
- return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len);
+ return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len);
}
@@ -126,19 +131,19 @@
enum wpa_alg alg, const u8 *addr, int idx,
u8 *key, size_t key_len)
{
- if (wpa_auth->cb.set_key == NULL)
+ if (wpa_auth->cb->set_key == NULL)
return -1;
- return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
+ key, key_len);
}
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb.get_seqnum == NULL)
+ if (wpa_auth->cb->get_seqnum == NULL)
return -1;
- return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+ return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
}
@@ -146,10 +151,10 @@
wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *data, size_t data_len, int encrypt)
{
- if (wpa_auth->cb.send_eapol == NULL)
+ if (wpa_auth->cb->send_eapol == NULL)
return -1;
- return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len,
- encrypt);
+ return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len,
+ encrypt);
}
@@ -157,9 +162,9 @@
static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
- if (wpa_auth->cb.start_ampe == NULL)
+ if (wpa_auth->cb->start_ampe == NULL)
return -1;
- return wpa_auth->cb.start_ampe(wpa_auth->cb.ctx, addr);
+ return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr);
}
#endif /* CONFIG_MESH */
@@ -168,9 +173,9 @@
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb.for_each_sta == NULL)
+ if (wpa_auth->cb->for_each_sta == NULL)
return 0;
- return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);
+ return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx);
}
@@ -178,18 +183,18 @@
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx)
{
- if (wpa_auth->cb.for_each_auth == NULL)
+ if (wpa_auth->cb->for_each_auth == NULL)
return 0;
- return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx);
+ return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx);
}
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
- if (wpa_auth->cb.logger == NULL)
+ if (wpa_auth->cb->logger == NULL)
return;
- wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);
+ wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt);
}
@@ -200,7 +205,7 @@
int maxlen;
va_list ap;
- if (wpa_auth->cb.logger == NULL)
+ if (wpa_auth->cb->logger == NULL)
return;
maxlen = os_strlen(fmt) + 100;
@@ -221,21 +226,21 @@
static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
const u8 *addr)
{
- if (wpa_auth->cb.disconnect == NULL)
+ if (wpa_auth->cb->disconnect == NULL)
return;
wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
- wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ wpa_auth->cb->disconnect(wpa_auth->cb_ctx, addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
}
static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
{
int ret = 0;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
ret = 1;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
ret = 1;
@@ -409,7 +414,8 @@
*/
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
- struct wpa_auth_callbacks *cb)
+ const struct wpa_auth_callbacks *cb,
+ void *cb_ctx)
{
struct wpa_authenticator *wpa_auth;
@@ -418,7 +424,8 @@
return NULL;
os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
- os_memcpy(&wpa_auth->cb, cb, sizeof(*cb));
+ wpa_auth->cb = cb;
+ wpa_auth->cb_ctx = cb_ctx;
if (wpa_auth_gen_wpa_ie(wpa_auth)) {
wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
@@ -443,7 +450,7 @@
return NULL;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
if (wpa_auth->ft_pmk_cache == NULL) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
@@ -453,7 +460,7 @@
os_free(wpa_auth);
return NULL;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (wpa_auth->conf.wpa_gmk_rekey) {
eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
@@ -506,17 +513,12 @@
eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
-#ifdef CONFIG_PEERKEY
- while (wpa_auth->stsl_negotiations)
- wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
-#endif /* CONFIG_PEERKEY */
-
pmksa_cache_auth_deinit(wpa_auth->pmksa);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
wpa_auth->ft_pmk_cache = NULL;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
bitfield_free(wpa_auth->ip_pool);
@@ -599,16 +601,28 @@
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return -1;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (sm->ft_completed) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"FT authentication already completed - do not "
"start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+ sm->Pair = TRUE;
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_FILS
+ if (sm->fils_completed) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "FILS authentication already completed - do not start 4-way handshake");
+ /* Go to PTKINITDONE state to allow GTK rekeying */
+ sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+ sm->Pair = TRUE;
+ return 0;
+ }
+#endif /* CONFIG_FILS */
if (sm->started) {
os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
@@ -660,10 +674,10 @@
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
os_free(sm->assoc_resp_ftie);
wpabuf_free(sm->ft_pending_req_ies);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
wpa_group_put(sm->wpa_auth, sm->group);
@@ -739,7 +753,7 @@
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
struct wpa_eapol_ie_parse *kde)
@@ -786,7 +800,7 @@
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
@@ -830,6 +844,7 @@
const u8 *pmk = NULL;
unsigned int pmk_len;
+ os_memset(&PTK, 0, sizeof(PTK));
for (;;) {
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
@@ -842,7 +857,8 @@
pmk_len = sm->pmk_len;
}
- wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK);
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
== 0) {
@@ -877,39 +893,42 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
u16 key_info, key_data_length;
enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
SMK_M1, SMK_M3, SMK_ERROR } msg;
char *msgtxt;
struct wpa_eapol_ie_parse kde;
- int ft;
- const u8 *eapol_key_ie, *key_data;
- size_t eapol_key_ie_len, keyhdrlen, mic_len;
+ const u8 *key_data;
+ size_t keyhdrlen, mic_len;
+ u8 *mic;
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return;
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len);
mic_len = wpa_mic_len(sm->wpa_key_mgmt);
- keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+ keyhdrlen = sizeof(*key) + mic_len + 2;
- if (data_len < sizeof(*hdr) + keyhdrlen)
+ if (data_len < sizeof(*hdr) + keyhdrlen) {
+ wpa_printf(MSG_DEBUG, "WPA: Ignore too short EAPOL-Key frame");
return;
+ }
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
- key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ mic = (u8 *) (key + 1);
key_info = WPA_GET_BE16(key->key_info);
- if (mic_len == 24) {
- key_data = (const u8 *) (key192 + 1);
- key_data_length = WPA_GET_BE16(key192->key_data_length);
- } else {
- key_data = (const u8 *) (key + 1);
- key_data_length = WPA_GET_BE16(key->key_data_length);
- }
+ key_data = mic + mic_len + 2;
+ key_data_length = WPA_GET_BE16(mic + mic_len);
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
- " key_info=0x%x type=%u key_data_length=%u",
- MAC2STR(sm->addr), key_info, key->type, key_data_length);
+ " key_info=0x%x type=%u mic_len=%u key_data_length=%u",
+ MAC2STR(sm->addr), key_info, key->type,
+ (unsigned int) mic_len, key_data_length);
+ wpa_hexdump(MSG_MSGDUMP,
+ "WPA: EAPOL-Key header (ending before Key MIC)",
+ key, sizeof(*key));
+ wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC",
+ mic, mic_len);
if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
"key_data overflow (%d > %lu)",
@@ -968,7 +987,9 @@
} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
msg = GROUP_2;
msgtxt = "2/2 Group";
- } else if (key_data_length == 0) {
+ } else if (key_data_length == 0 ||
+ (mic_len == 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
+ key_data_length == AES_BLOCK_SIZE)) {
msg = PAIRWISE_4;
msgtxt = "4/4 Pairwise";
} else {
@@ -985,6 +1006,7 @@
if (wpa_use_aes_cmac(sm) &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
!wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+ !wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -995,6 +1017,7 @@
}
if (!wpa_use_aes_cmac(sm) &&
+ !wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -1004,7 +1027,8 @@
}
}
- if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+ if ((wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+ wpa_key_mgmt_fils(sm->wpa_key_mgmt)) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
@@ -1092,6 +1116,15 @@
}
continue_processing:
+#ifdef CONFIG_FILS
+ if (sm->wpa == WPA_VERSION_WPA2 && mic_len == 0 &&
+ !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "WPA: Encr Key Data bit not set even though AEAD cipher is supposed to be used - drop frame");
+ return;
+ }
+#endif /* CONFIG_FILS */
+
switch (msg) {
case PAIRWISE_2:
if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
@@ -1122,67 +1155,6 @@
wpa_sta_disconnect(wpa_auth, sm->addr);
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 msg 2/4 with "
- "invalid Key Data contents");
- return;
- }
- if (kde.rsn_ie) {
- eapol_key_ie = kde.rsn_ie;
- eapol_key_ie_len = kde.rsn_ie_len;
- } else if (kde.osen) {
- eapol_key_ie = kde.osen;
- eapol_key_ie_len = kde.osen_len;
- } else {
- eapol_key_ie = kde.wpa_ie;
- eapol_key_ie_len = kde.wpa_ie_len;
- }
- ft = sm->wpa == WPA_VERSION_WPA2 &&
- wpa_key_mgmt_ft(sm->wpa_key_mgmt);
- if (sm->wpa_ie == NULL ||
- wpa_compare_rsn_ie(ft,
- sm->wpa_ie, sm->wpa_ie_len,
- eapol_key_ie, eapol_key_ie_len)) {
- wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
- "WPA IE from (Re)AssocReq did not "
- "match with msg 2/4");
- if (sm->wpa_ie) {
- wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
- sm->wpa_ie, sm->wpa_ie_len);
- }
- wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
- eapol_key_ie, eapol_key_ie_len);
- /* MLME-DEAUTHENTICATE.request */
- wpa_sta_disconnect(wpa_auth, sm->addr);
- return;
- }
-#ifdef CONFIG_IEEE80211R
- if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
- wpa_sta_disconnect(wpa_auth, sm->addr);
- return;
- }
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_P2P
- if (kde.ip_addr_req && kde.ip_addr_req[0] &&
- wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
- int idx;
- wpa_printf(MSG_DEBUG, "P2P: IP address requested in "
- "EAPOL-Key exchange");
- idx = bitfield_get_first_zero(wpa_auth->ip_pool);
- if (idx >= 0) {
- u32 start = WPA_GET_BE32(wpa_auth->conf.
- ip_addr_start);
- bitfield_set(wpa_auth->ip_pool, idx);
- WPA_PUT_BE32(sm->ip_addr, start + idx);
- wpa_printf(MSG_DEBUG, "P2P: Assigned IP "
- "address %u.%u.%u.%u to " MACSTR,
- sm->ip_addr[0], sm->ip_addr[1],
- sm->ip_addr[2], sm->ip_addr[3],
- MAC2STR(sm->addr));
- }
- }
-#endif /* CONFIG_P2P */
break;
case PAIRWISE_4:
if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
@@ -1239,15 +1211,26 @@
return;
}
- if (!(key_info & WPA_KEY_INFO_MIC)) {
+ if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+ !(key_info & WPA_KEY_INFO_MIC)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received invalid EAPOL-Key: Key MIC not set");
return;
}
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+ (key_info & WPA_KEY_INFO_MIC)) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received invalid EAPOL-Key: Key MIC set");
+ return;
+ }
+#endif /* CONFIG_FILS */
+
sm->MICVerified = FALSE;
if (sm->PTK_valid && !sm->update_snonce) {
- if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
+ if (mic_len &&
+ wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
data_len) &&
(msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
wpa_try_alt_snonce(sm, data, data_len))) {
@@ -1255,6 +1238,15 @@
"received EAPOL-Key with invalid MIC");
return;
}
+#ifdef CONFIG_FILS
+ if (!mic_len &&
+ wpa_aead_decrypt(sm, &sm->PTK, data, data_len,
+ &key_data_length) < 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key with invalid MIC");
+ return;
+ }
+#endif /* CONFIG_FILS */
sm->MICVerified = TRUE;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
@@ -1412,24 +1404,24 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
size_t len, mic_len, keyhdrlen;
int alg;
int key_data_len, pad_len = 0;
u8 *buf, *pos;
int version, pairwise;
int i;
- u8 *key_data;
+ u8 *key_mic, *key_data;
mic_len = wpa_mic_len(sm->wpa_key_mgmt);
- keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+ keyhdrlen = sizeof(*key) + mic_len + 2;
len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
if (force_version)
version = force_version;
else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
- wpa_key_mgmt_suite_b(sm->wpa_key_mgmt))
+ wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
+ wpa_key_mgmt_fils(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
@@ -1463,6 +1455,8 @@
}
len += key_data_len;
+ if (!mic_len && encr)
+ len += AES_BLOCK_SIZE;
hdr = os_zalloc(len);
if (hdr == NULL)
@@ -1471,7 +1465,7 @@
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
- key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ key_mic = (u8 *) (key + 1);
key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
key->type = sm->wpa == WPA_VERSION_WPA2 ?
@@ -1484,9 +1478,11 @@
WPA_PUT_BE16(key->key_info, key_info);
alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
- WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
- if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+ if ((key_info & WPA_KEY_INFO_SMK_MESSAGE) ||
+ (sm->wpa == WPA_VERSION_WPA2 && !pairwise))
WPA_PUT_BE16(key->key_length, 0);
+ else
+ WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
/* FIX: STSL: what to use as key_replay_counter? */
for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
@@ -1510,10 +1506,31 @@
if (kde && !encr) {
os_memcpy(key_data, kde, kde_len);
- if (mic_len == 24)
- WPA_PUT_BE16(key192->key_data_length, kde_len);
- else
- WPA_PUT_BE16(key->key_data_length, kde_len);
+ WPA_PUT_BE16(key_mic + mic_len, kde_len);
+#ifdef CONFIG_FILS
+ } else if (!mic_len) {
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ WPA_PUT_BE16(key_mic, AES_BLOCK_SIZE + kde_len);
+ wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
+ kde, kde_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK",
+ sm->PTK.kek, sm->PTK.kek_len);
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = (u8 *) hdr;
+ aad_len[0] = key_mic + 2 - (u8 *) hdr;
+ if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len, kde, kde_len,
+ 1, aad, aad_len, key_mic + 2) < 0) {
+ wpa_printf(MSG_DEBUG, "WPA: AES-SIV encryption failed");
+ return;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPA: Encrypted Key Data from SIV",
+ key_mic + 2, AES_BLOCK_SIZE + kde_len);
+#endif /* CONFIG_FILS */
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
if (buf == NULL) {
@@ -1539,12 +1556,7 @@
os_free(buf);
return;
}
- if (mic_len == 24)
- WPA_PUT_BE16(key192->key_data_length,
- key_data_len);
- else
- WPA_PUT_BE16(key->key_data_length,
- key_data_len);
+ WPA_PUT_BE16(key_mic + mic_len, key_data_len);
#ifndef CONFIG_NO_RC4
} else if (sm->PTK.kek_len == 16) {
u8 ek[32];
@@ -1555,12 +1567,7 @@
os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
os_memcpy(key_data, buf, key_data_len);
rc4_skip(ek, 32, 256, key_data, key_data_len);
- if (mic_len == 24)
- WPA_PUT_BE16(key192->key_data_length,
- key_data_len);
- else
- WPA_PUT_BE16(key->key_data_length,
- key_data_len);
+ WPA_PUT_BE16(key_mic + mic_len, key_data_len);
#endif /* CONFIG_NO_RC4 */
} else {
os_free(hdr);
@@ -1571,9 +1578,7 @@
}
if (key_info & WPA_KEY_INFO_MIC) {
- u8 *key_mic;
-
- if (!sm->PTK_valid) {
+ if (!sm->PTK_valid || !mic_len) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PTK not valid when sending EAPOL-Key "
"frame");
@@ -1581,7 +1586,6 @@
return;
}
- key_mic = key192->key_mic; /* same offset for key and key192 */
wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_key_mgmt, version,
(u8 *) hdr, len, key_mic);
@@ -1613,7 +1617,7 @@
{
int timeout_ms;
int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
- int ctr;
+ u32 ctr;
if (sm == NULL)
return;
@@ -1630,7 +1634,7 @@
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
sm->pending_1_of_4_timeout = 1;
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
- "counter %d)", timeout_ms, ctr);
+ "counter %u)", timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
wpa_send_eapol_timeout, wpa_auth, sm);
}
@@ -1641,10 +1645,9 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
u16 key_info;
int ret = 0;
- u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN], *mic_pos;
size_t mic_len = wpa_mic_len(akmp);
if (data_len < sizeof(*hdr) + sizeof(*key))
@@ -1652,16 +1655,16 @@
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
- key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ mic_pos = (u8 *) (key + 1);
key_info = WPA_GET_BE16(key->key_info);
- os_memcpy(mic, key192->key_mic, mic_len);
- os_memset(key192->key_mic, 0, mic_len);
+ os_memcpy(mic, mic_pos, mic_len);
+ os_memset(mic_pos, 0, mic_len);
if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
key_info & WPA_KEY_INFO_TYPE_MASK,
- data, data_len, key192->key_mic) ||
- os_memcmp_const(mic, key192->key_mic, mic_len) != 0)
+ data, data_len, mic_pos) ||
+ os_memcmp_const(mic, mic_pos, mic_len) != 0)
ret = -1;
- os_memcpy(key192->key_mic, mic, mic_len);
+ os_memcpy(mic_pos, mic, mic_len);
return ret;
}
@@ -1670,7 +1673,10 @@
{
sm->PTK_valid = FALSE;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
- wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0);
+ if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
+ 0))
+ wpa_printf(MSG_DEBUG,
+ "RSN: PTK removal from the driver failed");
sm->pairwise_set = FALSE;
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
}
@@ -1734,7 +1740,7 @@
sm->ReAuthenticationRequest = TRUE;
break;
case WPA_ASSOC_FT:
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
"after association");
wpa_ft_install_ptk(sm);
@@ -1742,22 +1748,27 @@
/* Using FT protocol, not WPA auth state machine */
sm->ft_completed = 1;
return 0;
-#else /* CONFIG_IEEE80211R */
+#else /* CONFIG_IEEE80211R_AP */
break;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
case WPA_DRV_STA_REMOVED:
sm->tk_already_set = FALSE;
return 0;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
sm->ft_completed = 0;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (sm->mgmt_frame_prot && event == WPA_AUTH)
remove_ptk = 0;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_FILS
+ if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
+ (event == WPA_AUTH || event == WPA_ASSOC))
+ remove_ptk = 0;
+#endif /* CONFIG_FILS */
if (remove_ptk) {
sm->PTK_valid = FALSE;
@@ -1922,9 +1933,9 @@
size_t len = 2 * PMK_LEN;
SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
sm->xxkey_len = 0;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (sm->pmksa) {
wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
@@ -1932,7 +1943,7 @@
} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
unsigned int pmk_len;
- if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt))
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
@@ -1948,15 +1959,15 @@
}
os_memcpy(sm->PMK, msk, pmk_len);
sm->pmk_len = pmk_len;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (len >= 2 * PMK_LEN) {
os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
sm->xxkey_len = PMK_LEN;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
} else {
wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
- sm->wpa_auth->cb.get_msk);
+ sm->wpa_auth->cb->get_msk);
sm->Disconnect = TRUE;
return;
}
@@ -1983,10 +1994,10 @@
if (psk) {
os_memcpy(sm->PMK, psk, PMK_LEN);
sm->pmk_len = PMK_LEN;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
os_memcpy(sm->xxkey, psk, PMK_LEN);
sm->xxkey_len = PMK_LEN;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
}
sm->req_replay_counter_used = 0;
}
@@ -2003,7 +2014,7 @@
sm->alt_snonce_valid = FALSE;
sm->TimeoutCtr++;
- if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -2049,10 +2060,10 @@
const u8 *pmk, unsigned int pmk_len,
struct wpa_ptk *ptk)
{
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
@@ -2060,16 +2071,401 @@
}
+#ifdef CONFIG_FILS
+
+int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *snonce, const u8 *anonce)
+{
+ u8 ick[FILS_ICK_MAX_LEN];
+ size_t ick_len;
+ int res;
+
+ res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
+ snonce, anonce, &sm->PTK, ick, &ick_len,
+ sm->wpa_key_mgmt, sm->pairwise);
+ if (res < 0)
+ return res;
+ sm->PTK_valid = TRUE;
+
+ res = fils_key_auth_sk(ick, ick_len, snonce, anonce,
+ sm->addr, sm->wpa_auth->addr,
+ NULL, 0, NULL, 0, /* TODO: SK+PFS */
+ sm->wpa_key_mgmt, sm->fils_key_auth_sta,
+ sm->fils_key_auth_ap,
+ &sm->fils_key_auth_len);
+ os_memset(ick, 0, sizeof(ick));
+
+ /* Store nonces for (Re)Association Request/Response frame processing */
+ os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
+ os_memcpy(sm->ANonce, anonce, FILS_NONCE_LEN);
+
+ return res;
+}
+
+
+static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *buf, size_t buf_len, u16 *_key_data_len)
+{
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ u8 *pos;
+ u16 key_data_len;
+ u8 *tmp;
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ hdr = (struct ieee802_1x_hdr *) buf;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ pos = (u8 *) (key + 1);
+ key_data_len = WPA_GET_BE16(pos);
+ if (key_data_len < AES_BLOCK_SIZE ||
+ key_data_len > buf_len - sizeof(*hdr) - sizeof(*key) - 2) {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "No room for AES-SIV data in the frame");
+ return -1;
+ }
+ pos += 2; /* Pointing at the Encrypted Key Data field */
+
+ tmp = os_malloc(key_data_len);
+ if (!tmp)
+ return -1;
+
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = buf;
+ aad_len[0] = pos - buf;
+ if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, key_data_len,
+ 1, aad, aad_len, tmp) < 0) {
+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "Invalid AES-SIV data in the frame");
+ bin_clear_free(tmp, key_data_len);
+ return -1;
+ }
+
+ /* AEAD decryption and validation completed successfully */
+ key_data_len -= AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Decrypted Key Data",
+ tmp, key_data_len);
+
+ /* Replace Key Data field with the decrypted version */
+ os_memcpy(pos, tmp, key_data_len);
+ pos -= 2; /* Key Data Length field */
+ WPA_PUT_BE16(pos, key_data_len);
+ bin_clear_free(tmp, key_data_len);
+ if (_key_data_len)
+ *_key_data_len = key_data_len;
+ return 0;
+}
+
+
+int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
+ const struct ieee80211_mgmt *mgmt, size_t frame_len,
+ u8 *pos, size_t left)
+{
+ u16 fc, stype;
+ const u8 *end, *ie_start, *ie, *session, *crypt;
+ struct ieee802_11_elems elems;
+ const u8 *aad[5];
+ size_t aad_len[5];
+
+ if (!sm || !sm->PTK_valid) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No KEK to decrypt Assocication Request frame");
+ return -1;
+ }
+
+ if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Not a FILS AKM - reject association");
+ return -1;
+ }
+
+ end = ((const u8 *) mgmt) + frame_len;
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+ if (stype == WLAN_FC_STYPE_REASSOC_REQ)
+ ie_start = mgmt->u.reassoc_req.variable;
+ else
+ ie_start = mgmt->u.assoc_req.variable;
+ ie = ie_start;
+
+ /*
+ * Find FILS Session element which is the last unencrypted element in
+ * the frame.
+ */
+ session = NULL;
+ while (ie + 1 < end) {
+ if (ie + 2 + ie[1] > end)
+ break;
+ if (ie[0] == WLAN_EID_EXTENSION &&
+ ie[1] >= 1 + FILS_SESSION_LEN &&
+ ie[2] == WLAN_EID_EXT_FILS_SESSION) {
+ session = ie;
+ break;
+ }
+ ie += 2 + ie[1];
+ }
+
+ if (!session) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Could not find FILS Session element in Association Request frame - reject");
+ return -1;
+ }
+ if (os_memcmp(fils_session, session + 3, FILS_SESSION_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+ fils_session, FILS_SESSION_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
+ session + 3, FILS_SESSION_LEN);
+ return -1;
+ }
+ crypt = session + 2 + session[1];
+
+ if (end - crypt < AES_BLOCK_SIZE) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Too short frame to include AES-SIV data");
+ return -1;
+ }
+
+ /* AES-SIV AAD vectors */
+
+ /* The STA's MAC address */
+ aad[0] = mgmt->sa;
+ aad_len[0] = ETH_ALEN;
+ /* The AP's BSSID */
+ aad[1] = mgmt->da;
+ aad_len[1] = ETH_ALEN;
+ /* The STA's nonce */
+ aad[2] = sm->SNonce;
+ aad_len[2] = FILS_NONCE_LEN;
+ /* The AP's nonce */
+ aad[3] = sm->ANonce;
+ aad_len[3] = FILS_NONCE_LEN;
+ /*
+ * The (Re)Association Request frame from the Capability Information
+ * field to the FILS Session element (both inclusive).
+ */
+ aad[4] = (const u8 *) &mgmt->u.assoc_req.capab_info;
+ aad_len[4] = crypt - aad[4];
+
+ if (aes_siv_decrypt(sm->PTK.kek, sm->PTK.kek_len, crypt, end - crypt,
+ 5, aad, aad_len, pos + (crypt - ie_start)) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Invalid AES-SIV data in the frame");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: Decrypted Association Request elements",
+ pos, left - AES_BLOCK_SIZE);
+
+ if (ieee802_11_parse_elems(pos, left - AES_BLOCK_SIZE, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to parse decrypted elements");
+ return -1;
+ }
+ if (!elems.fils_key_confirm) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
+ return -1;
+ }
+ if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unexpected Key-Auth length %d (expected %d)",
+ elems.fils_key_confirm_len,
+ (int) sm->fils_key_auth_len);
+ return -1;
+ }
+ if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_sta,
+ sm->fils_key_auth_len) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
+ sm->fils_key_auth_sta, sm->fils_key_auth_len);
+ return -1;
+ }
+
+ return left - AES_BLOCK_SIZE;
+}
+
+
+int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
+ size_t current_len, size_t max_len,
+ const struct wpabuf *hlp)
+{
+ u8 *end = buf + max_len;
+ u8 *pos = buf + current_len;
+ struct ieee80211_mgmt *mgmt;
+ struct wpabuf *plain;
+ u8 *len, *tmp, *tmp2;
+ u8 hdr[2];
+ u8 *gtk, dummy_gtk[32];
+ size_t gtk_len;
+ struct wpa_group *gsm;
+ const u8 *aad[5];
+ size_t aad_len[5];
+
+ if (!sm || !sm->PTK_valid)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG,
+ "FILS: Association Response frame before FILS processing",
+ buf, current_len);
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+
+ /* AES-SIV AAD vectors */
+
+ /* The AP's BSSID */
+ aad[0] = mgmt->sa;
+ aad_len[0] = ETH_ALEN;
+ /* The STA's MAC address */
+ aad[1] = mgmt->da;
+ aad_len[1] = ETH_ALEN;
+ /* The AP's nonce */
+ aad[2] = sm->ANonce;
+ aad_len[2] = FILS_NONCE_LEN;
+ /* The STA's nonce */
+ aad[3] = sm->SNonce;
+ aad_len[3] = FILS_NONCE_LEN;
+ /*
+ * The (Re)Association Response frame from the Capability Information
+ * field (the same offset in both Association and Reassociation
+ * Response frames) to the FILS Session element (both inclusive).
+ */
+ aad[4] = (const u8 *) &mgmt->u.assoc_resp.capab_info;
+ aad_len[4] = pos - aad[4];
+
+ /* The following elements will be encrypted with AES-SIV */
+
+ plain = wpabuf_alloc(1000);
+ if (!plain)
+ return -1;
+
+ /* TODO: FILS Public Key */
+
+ /* FILS Key Confirmation */
+ wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(plain, 1 + sm->fils_key_auth_len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(plain, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+ wpabuf_put_data(plain, sm->fils_key_auth_ap, sm->fils_key_auth_len);
+
+ /* FILS HLP Container */
+ if (hlp)
+ wpabuf_put_buf(plain, hlp);
+
+ /* TODO: FILS IP Address Assignment */
+
+ /* Key Delivery */
+ gsm = sm->group;
+ wpabuf_put_u8(plain, WLAN_EID_EXTENSION); /* Element ID */
+ len = wpabuf_put(plain, 1);
+ wpabuf_put_u8(plain, WLAN_EID_EXT_KEY_DELIVERY);
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN,
+ wpabuf_put(plain, WPA_KEY_RSC_LEN));
+ /* GTK KDE */
+ gtk = gsm->GTK[gsm->GN - 1];
+ gtk_len = gsm->GTK_len;
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
+ wpabuf_free(plain);
+ return -1;
+ }
+ gtk = dummy_gtk;
+ }
+ hdr[0] = gsm->GN & 0x03;
+ hdr[1] = 0;
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = wpa_add_kde(tmp, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+ gtk, gtk_len);
+ wpabuf_put(plain, tmp2 - tmp);
+
+ /* IGTK KDE */
+ tmp = wpabuf_put(plain, 0);
+ tmp2 = ieee80211w_kde_add(sm, tmp);
+ wpabuf_put(plain, tmp2 - tmp);
+
+ *len = (u8 *) wpabuf_put(plain, 0) - len - 1;
+
+ if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Not enough room for FILS elements");
+ wpabuf_free(plain);
+ return -1;
+ }
+
+ wpa_hexdump_buf_key(MSG_DEBUG, "FILS: Association Response plaintext",
+ plain);
+
+ if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
+ wpabuf_head(plain), wpabuf_len(plain),
+ 5, aad, aad_len, pos) < 0) {
+ wpabuf_free(plain);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG,
+ "FILS: Encrypted Association Response elements",
+ pos, AES_BLOCK_SIZE + wpabuf_len(plain));
+ current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
+ wpabuf_free(plain);
+
+ sm->fils_completed = 1;
+
+ return current_len;
+}
+
+
+int fils_set_tk(struct wpa_state_machine *sm)
+{
+ enum wpa_alg alg;
+ int klen;
+
+ if (!sm || !sm->PTK_valid)
+ return -1;
+
+ alg = wpa_cipher_to_alg(sm->pairwise);
+ klen = wpa_cipher_key_len(sm->pairwise);
+
+ wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+ sm->PTK.tk, klen)) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_FILS */
+
+
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
struct wpa_ptk PTK;
int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
unsigned int pmk_len;
+ int ft;
+ const u8 *eapol_key_ie, *key_data, *mic;
+ u16 key_data_length;
+ size_t mic_len, eapol_key_ie_len;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ struct wpa_eapol_ie_parse kde;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
sm->update_snonce = FALSE;
+ os_memset(&PTK, 0, sizeof(PTK));
+
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
/* WPA with IEEE 802.1X: use the derived PMK from EAP
* WPA-PSK: iterate through possible PSKs and select the one matching
@@ -2087,15 +2483,26 @@
pmk_len = sm->pmk_len;
}
- wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ break;
- if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
+ if (mic_len &&
+ wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
ok = 1;
break;
}
+#ifdef CONFIG_FILS
+ if (!mic_len &&
+ wpa_aead_decrypt(sm, &PTK, sm->last_rx_eapol_key,
+ sm->last_rx_eapol_key_len, NULL) == 0) {
+ ok = 1;
+ break;
+ }
+#endif /* CONFIG_FILS */
+
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
break;
}
@@ -2108,7 +2515,77 @@
return;
}
-#ifdef CONFIG_IEEE80211R
+ /*
+ * 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 msg 2/4 with invalid Key Data contents");
+ return;
+ }
+ if (kde.rsn_ie) {
+ eapol_key_ie = kde.rsn_ie;
+ eapol_key_ie_len = kde.rsn_ie_len;
+ } else if (kde.osen) {
+ eapol_key_ie = kde.osen;
+ eapol_key_ie_len = kde.osen_len;
+ } else {
+ eapol_key_ie = kde.wpa_ie;
+ eapol_key_ie_len = kde.wpa_ie_len;
+ }
+ ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt);
+ if (sm->wpa_ie == NULL ||
+ wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len,
+ eapol_key_ie, eapol_key_ie_len)) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "WPA IE from (Re)AssocReq did not match with msg 2/4");
+ if (sm->wpa_ie) {
+ wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
+ sm->wpa_ie, sm->wpa_ie_len);
+ }
+ wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
+ eapol_key_ie, eapol_key_ie_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr);
+ return;
+ }
+#ifdef CONFIG_IEEE80211R_AP
+ if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
+ wpa_sta_disconnect(wpa_auth, sm->addr);
+ return;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_P2P
+ if (kde.ip_addr_req && kde.ip_addr_req[0] &&
+ wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
+ int idx;
+ wpa_printf(MSG_DEBUG,
+ "P2P: IP address requested in EAPOL-Key exchange");
+ idx = bitfield_get_first_zero(wpa_auth->ip_pool);
+ if (idx >= 0) {
+ u32 start = WPA_GET_BE32(wpa_auth->conf.ip_addr_start);
+ bitfield_set(wpa_auth->ip_pool, idx);
+ WPA_PUT_BE32(sm->ip_addr, start + idx);
+ wpa_printf(MSG_DEBUG,
+ "P2P: Assigned IP address %u.%u.%u.%u to "
+ MACSTR, sm->ip_addr[0], sm->ip_addr[1],
+ sm->ip_addr[2], sm->ip_addr[3],
+ MAC2STR(sm->addr));
+ }
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_IEEE80211R_AP
if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
/*
* Verify that PMKR1Name from EAPOL-Key message 2/4 matches
@@ -2127,7 +2604,7 @@
return;
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
@@ -2229,7 +2706,7 @@
sm->TimeoutEvt = FALSE;
sm->TimeoutCtr++;
- if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -2297,12 +2774,12 @@
kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
if (gtk)
kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
kde_len += 300; /* FTIE + 2 * TIE */
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr) > 0)
kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
@@ -2314,7 +2791,7 @@
pos = kde;
os_memcpy(pos, wpa_ie, wpa_ie_len);
pos += wpa_ie_len;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
size_t elen;
@@ -2330,7 +2807,7 @@
pos -= wpa_ie_len;
pos += elen;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (gtk) {
u8 hdr[2];
hdr[0] = keyidx & 0x03;
@@ -2340,7 +2817,7 @@
}
pos = ieee80211w_kde_add(sm, pos);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
int res;
struct wpa_auth_config *conf;
@@ -2380,7 +2857,7 @@
WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
pos += 4;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
if (WPA_GET_BE32(sm->ip_addr) > 0) {
u8 addr[3 * 4];
@@ -2393,7 +2870,8 @@
#endif /* CONFIG_P2P */
wpa_send_eapol(sm->wpa_auth, sm,
- (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
+ (secure ? WPA_KEY_INFO_SECURE : 0) |
+ (wpa_mic_len(sm->wpa_key_mgmt) ? WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
_rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
@@ -2449,9 +2927,9 @@
"pairwise key handshake completed (%s)",
sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
}
@@ -2526,11 +3004,12 @@
sm->EAPOLKeyPairwise)
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
else if (sm->TimeoutCtr >
- (int) dot11RSNAConfigPairwiseUpdateCount) {
+ sm->wpa_auth->conf.wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKSTART: Retry limit %d reached",
- dot11RSNAConfigPairwiseUpdateCount);
+ wpa_auth_vlogger(
+ sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKSTART: Retry limit %u reached",
+ sm->wpa_auth->conf.wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKSTART);
@@ -2554,12 +3033,12 @@
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- (int) dot11RSNAConfigPairwiseUpdateCount) {
+ sm->wpa_auth->conf.wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKINITNEGOTIATING: Retry limit %d "
- "reached",
- dot11RSNAConfigPairwiseUpdateCount);
+ wpa_auth_vlogger(
+ sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKINITNEGOTIATING: Retry limit %u reached",
+ sm->wpa_auth->conf.wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -2594,7 +3073,7 @@
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
sm->GTimeoutCtr++;
- if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+ if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -2640,10 +3119,11 @@
}
wpa_send_eapol(sm->wpa_auth, sm,
- WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_SECURE |
+ (wpa_mic_len(sm->wpa_key_mgmt) ? WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK |
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
- rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+ rsc, NULL, kde, kde_len, gsm->GN, 1);
os_free(kde_buf);
}
@@ -2672,6 +3152,10 @@
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
sm->Disconnect = TRUE;
+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "group key handshake failed (%s) after %u tries",
+ sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
+ sm->wpa_auth->conf.wpa_group_update_count);
}
@@ -2691,7 +3175,7 @@
!sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
else if (sm->GTimeoutCtr >
- (int) dot11RSNAConfigGroupUpdateCount)
+ sm->wpa_auth->conf.wpa_group_update_count)
SM_ENTER(WPA_PTK_GROUP, KEYERROR);
else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
@@ -3151,8 +3635,8 @@
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
RSN_VERSION,
!!wpa_auth->conf.wpa_strict_rekey,
- dot11RSNAConfigGroupUpdateCount,
- dot11RSNAConfigPairwiseUpdateCount,
+ wpa_auth->conf.wpa_group_update_count,
+ wpa_auth->conf.wpa_pairwise_update_count,
wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
@@ -3320,7 +3804,7 @@
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
- if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
if (pmk_len > PMK_LEN_SUITE_B_192)
pmk_len = PMK_LEN_SUITE_B_192;
} else if (pmk_len > PMK_LEN) {
@@ -3404,12 +3888,65 @@
}
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ char *buf, size_t len)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return 0;
+
+ return pmksa_cache_auth_list_mesh(wpa_auth->pmksa, addr, buf, len);
+}
+
+
struct rsn_pmksa_cache_entry *
-wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
+ const u8 *pmkid, int expiration)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ entry = pmksa_cache_auth_create_entry(pmk, PMK_LEN, pmkid, NULL, 0, aa,
+ spa, 0, NULL, WPA_KEY_MGMT_SAE);
+ if (!entry)
+ return NULL;
+
+ os_get_reltime(&now);
+ entry->expiration = now.sec + expiration;
+ return entry;
+}
+
+
+int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ int ret;
+
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return -1;
+
+ ret = pmksa_cache_auth_add_entry(wpa_auth->pmksa, entry);
+ if (ret < 0)
+ wpa_printf(MSG_DEBUG,
+ "RSN: Failed to store external PMKSA cache for "
+ MACSTR, MAC2STR(entry->spa));
+
+ return ret;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *pmkid)
{
if (!wpa_auth || !wpa_auth->pmksa)
return NULL;
- return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+ return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, pmkid);
}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index e66f08b..387d146 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -144,6 +144,8 @@
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ u32 wpa_group_update_count;
+ u32 wpa_pairwise_update_count;
int rsn_pairwise;
int rsn_preauth;
int eapol_version;
@@ -157,7 +159,7 @@
enum mfp_options ieee80211w;
int group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@@ -170,7 +172,8 @@
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
int ft_over_ds;
-#endif /* CONFIG_IEEE80211R */
+ int ft_psk_generate_local;
+#endif /* CONFIG_IEEE80211R_AP */
int disable_gtk;
int ap_mlme;
#ifdef CONFIG_TESTING_OPTIONS
@@ -197,7 +200,6 @@
} wpa_eapol_variable;
struct wpa_auth_callbacks {
- void *ctx;
void (*logger)(void *ctx, const u8 *addr, logger_level level,
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
@@ -220,13 +222,13 @@
void *ctx), void *cb_ctx);
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
size_t data_len);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
size_t tspec_ielen);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_MESH
int (*start_ampe)(void *ctx, const u8 *sta_addr);
#endif /* CONFIG_MESH */
@@ -234,7 +236,8 @@
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
- struct wpa_auth_callbacks *cb);
+ const struct wpa_auth_callbacks *cb,
+ void *cb_ctx);
int wpa_init_keys(struct wpa_authenticator *wpa_auth);
void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
@@ -302,8 +305,16 @@
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
size_t len);
void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
+int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ char *buf, size_t len);
struct rsn_pmksa_cache_entry *
-wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr);
+wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
+ const u8 *pmkid, int expiration);
+int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
+ struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
+ const u8 *pmkid);
void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
struct wpa_state_machine *sm,
struct wpa_authenticator *wpa_auth,
@@ -312,7 +323,7 @@
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
const u8 *req_ies, size_t req_ies_len);
@@ -328,7 +339,7 @@
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
const u8 *data, size_t data_len);
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
@@ -347,5 +358,14 @@
int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id);
int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id);
+int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
+ size_t pmk_len, const u8 *snonce, const u8 *anonce);
+int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
+ const struct ieee80211_mgmt *mgmt, size_t frame_len,
+ u8 *pos, size_t left);
+int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
+ size_t current_len, size_t max_len,
+ const struct wpabuf *hlp);
+int fils_set_tk(struct wpa_state_machine *sm);
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e63b99a..210d300 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -22,7 +22,7 @@
#include "wpa_auth_i.h"
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
const u8 *current_ap, const u8 *sta_addr,
@@ -33,30 +33,41 @@
static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
const u8 *data, size_t data_len)
{
- if (wpa_auth->cb.send_ether == NULL)
+ if (wpa_auth->cb->send_ether == NULL)
return -1;
wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
- return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
- data, data_len);
+ return wpa_auth->cb->send_ether(wpa_auth->cb_ctx, dst, ETH_P_RRB,
+ data, data_len);
}
static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
const u8 *dst, const u8 *data, size_t data_len)
{
- if (wpa_auth->cb.send_ft_action == NULL)
+ if (wpa_auth->cb->send_ft_action == NULL)
return -1;
- return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
- data, data_len);
+ return wpa_auth->cb->send_ft_action(wpa_auth->cb_ctx, dst,
+ data, data_len);
+}
+
+
+static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, const u8 *p2p_dev_addr,
+ const u8 *prev_psk)
+{
+ if (wpa_auth->cb->get_psk == NULL)
+ return NULL;
+ return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
+ prev_psk);
}
static struct wpa_state_machine *
wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
{
- if (wpa_auth->cb.add_sta == NULL)
+ if (wpa_auth->cb->add_sta == NULL)
return NULL;
- return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
+ return wpa_auth->cb->add_sta(wpa_auth->cb_ctx, sta_addr);
}
@@ -64,12 +75,12 @@
const u8 *sta_addr,
u8 *tspec_ie, size_t tspec_ielen)
{
- if (wpa_auth->cb.add_tspec == NULL) {
+ if (wpa_auth->cb->add_tspec == NULL) {
wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
return -1;
}
- return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
- tspec_ielen);
+ return wpa_auth->cb->add_tspec(wpa_auth->cb_ctx, sta_addr, tspec_ie,
+ tspec_ielen);
}
@@ -373,6 +384,7 @@
const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
+ int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
@@ -380,20 +392,25 @@
return -1;
}
- wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
- r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
+ if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+ r0kh, r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
- sm->pairwise);
+ if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
+ wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
+ sm->pairwise);
- wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
- pmk_r1, sm->pmk_r1_name);
+ if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, sm->pmk_r1_name) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
- wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
- sm->pairwise);
+ if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
+ wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1,
+ sm->pmk_r1_name, sm->pairwise);
return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, sm->pmk_r1_name,
@@ -404,9 +421,9 @@
static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
const u8 *addr, int idx, u8 *seq)
{
- if (wpa_auth->cb.get_seqnum == NULL)
+ if (wpa_auth->cb->get_seqnum == NULL)
return -1;
- return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+ return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
}
@@ -759,10 +776,10 @@
enum wpa_alg alg, const u8 *addr, int idx,
u8 *key, size_t key_len)
{
- if (wpa_auth->cb.set_key == NULL)
+ if (wpa_auth->cb->set_key == NULL)
return -1;
- return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
- key, key_len);
+ return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
+ key, key_len);
}
@@ -804,6 +821,89 @@
}
+/* Derive PMK-R1 from PSK, check all available PSK */
+static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm,
+ const u8 *req_pmk_r1_name,
+ u8 *out_pmk_r1, int *out_pairwise)
+{
+ const u8 *pmk = NULL;
+ u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ const u8 *mdid = wpa_auth->conf.mobility_domain;
+ const u8 *r0kh = sm->r0kh_id;
+ size_t r0kh_len = sm->r0kh_id_len;
+ const u8 *r1kh = wpa_auth->conf.r1_key_holder;
+ const u8 *ssid = wpa_auth->conf.ssid;
+ size_t ssid_len = wpa_auth->conf.ssid_len;
+ int pairwise;
+
+ pairwise = sm->pairwise;
+
+ for (;;) {
+ pmk = wpa_ft_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr,
+ pmk);
+ if (pmk == NULL)
+ break;
+
+ if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
+ r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name) < 0 ||
+ wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, pmk_r1_name) < 0 ||
+ os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
+ WPA_PMK_NAME_LEN) != 0)
+ continue;
+
+ /* We found a PSK that matches the requested pmk_r1_name */
+ wpa_printf(MSG_DEBUG,
+ "FT: Found PSK to generate PMK-R1 locally");
+ os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN);
+ if (out_pairwise)
+ *out_pairwise = pairwise;
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "FT: Did not find PSK to generate PMK-R1 locally");
+ return -1;
+}
+
+
+/* Detect the configuration the station asked for.
+ * Required to detect FT-PSK and pairwise cipher.
+ */
+static int wpa_ft_set_key_mgmt(struct wpa_state_machine *sm,
+ struct wpa_ft_ies *parse)
+{
+ int key_mgmt, ciphers;
+
+ if (sm->wpa_key_mgmt)
+ return 0;
+
+ key_mgmt = parse->key_mgmt & sm->wpa_auth->conf.wpa_key_mgmt;
+ if (!key_mgmt) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid key mgmt (0x%x) from "
+ MACSTR, parse->key_mgmt, MAC2STR(sm->addr));
+ return -1;
+ }
+ if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+ else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
+ ciphers = parse->pairwise_cipher & sm->wpa_auth->conf.rsn_pairwise;
+ if (!ciphers) {
+ wpa_printf(MSG_DEBUG, "FT: Invalid pairwise cipher (0x%x) from "
+ MACSTR,
+ parse->pairwise_cipher, MAC2STR(sm->addr));
+ return -1;
+ }
+ sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
+
+ return 0;
+}
+
+
static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
const u8 *ies, size_t ies_len,
u8 **resp_ies, size_t *resp_ies_len)
@@ -865,16 +965,24 @@
return WLAN_STATUS_INVALID_PMKID;
}
+ if (wpa_ft_set_key_mgmt(sm, &parse) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
parse.rsn_pmkid, WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1_name(parse.rsn_pmkid,
- sm->wpa_auth->conf.r1_key_holder, sm->addr,
- pmk_r1_name);
+ if (wpa_derive_pmk_r1_name(parse.rsn_pmkid,
+ sm->wpa_auth->conf.r1_key_holder, sm->addr,
+ pmk_r1_name) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
pmk_r1_name, WPA_PMK_NAME_LEN);
- if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
- &pairwise) < 0) {
+ if (conf->ft_psk_generate_local &&
+ wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) {
+ if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise) < 0)
+ return WLAN_STATUS_INVALID_PMKID;
+ } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name,
+ pmk_r1, &pairwise) < 0) {
if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) {
wpa_printf(MSG_DEBUG, "FT: Did not have matching "
"PMK-R1 and unknown R0KH-ID");
@@ -913,41 +1021,35 @@
buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
2 + FT_R1KH_ID_LEN + 200;
*resp_ies = os_zalloc(buflen);
- if (*resp_ies == NULL) {
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (*resp_ies == NULL)
+ goto fail;
pos = *resp_ies;
end = *resp_ies + buflen;
ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
ret = wpa_write_mdie(conf, pos, end - pos);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
*resp_ies_len = pos - *resp_ies;
return WLAN_STATUS_SUCCESS;
+fail:
+ os_free(*resp_ies);
+ *resp_ies = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
@@ -1051,7 +1153,7 @@
ftie->snonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
sm->SNonce, WPA_NONCE_LEN);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
@@ -1060,13 +1162,13 @@
ftie->anonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
sm->ANonce, WPA_NONCE_LEN);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.r0kh_id == NULL) {
wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
@@ -1078,12 +1180,12 @@
parse.r0kh_id, parse.r0kh_id_len);
wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
sm->r0kh_id, sm->r0kh_id_len);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.r1kh_id == NULL) {
wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
@@ -1094,7 +1196,7 @@
parse.r1kh_id, FT_R1KH_ID_LEN);
wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
- return -1;
+ return WLAN_STATUS_INVALID_FTIE;
}
if (parse.rsn_pmkid == NULL ||
@@ -1102,7 +1204,7 @@
{
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
- return -1;
+ return WLAN_STATUS_INVALID_PMKID;
}
count = 3;
@@ -1112,7 +1214,7 @@
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
ftie->mic_control[1], count);
- return -1;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
@@ -1199,6 +1301,11 @@
wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
+ if (!sm->wpa_auth->conf.ft_over_ds) {
+ wpa_printf(MSG_DEBUG, "FT: Over-DS option disabled - reject");
+ return -1;
+ }
+
/* RRB - Forward action frame to the target AP */
frame = os_malloc(sizeof(*frame) + len);
if (frame == NULL)
@@ -1384,8 +1491,11 @@
return -1;
}
- wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
- r.pmk_r1, r.pmk_r1_name);
+ if (wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
+ r.pmk_r1, r.pmk_r1_name) < 0) {
+ os_memset(pmk_r0, 0, PMK_LEN);
+ return -1;
+ }
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
WPA_PMK_NAME_LEN);
@@ -1437,12 +1547,10 @@
{
struct ft_r0kh_r1kh_resp_frame *frame = ctx;
- if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
- return 0;
- if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
- FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
- return 0;
- if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
+ if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0 ||
+ os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
+ FT_R0KH_R1KH_PULL_NONCE_LEN) != 0 ||
+ sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
return 0;
wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
@@ -1726,10 +1834,10 @@
}
-static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
- struct wpa_ft_pmk_r0_sa *pmk_r0,
- struct ft_remote_r1kh *r1kh,
- const u8 *s1kh_id, int pairwise)
+static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
+ struct wpa_ft_pmk_r0_sa *pmk_r0,
+ struct ft_remote_r1kh *r1kh,
+ const u8 *s1kh_id, int pairwise)
{
struct ft_r0kh_r1kh_push_frame frame, f;
struct os_time now;
@@ -1747,8 +1855,9 @@
os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
- s1kh_id, f.pmk_r1, f.pmk_r1_name);
+ if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
+ s1kh_id, f.pmk_r1, f.pmk_r1_name) < 0)
+ return -1;
wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
@@ -1764,9 +1873,10 @@
if (aes_wrap(r1kh->key, sizeof(r1kh->key),
(FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
plain, crypt) < 0)
- return;
+ return -1;
wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
+ return 0;
}
@@ -1799,4 +1909,4 @@
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 5fe0987..394f77a 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -41,6 +41,8 @@
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
+ wconf->wpa_group_update_count = conf->wpa_group_update_count;
+ wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
@@ -53,7 +55,7 @@
wconf->ieee80211w = conf->ieee80211w;
wconf->group_mgmt_cipher = conf->group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_MAX_LEN)
wconf->ssid_len = SSID_MAX_LEN;
@@ -73,7 +75,8 @@
wconf->r1kh_list = conf->r1kh_list;
wconf->pmk_r1_push = conf->pmk_r1_push;
wconf->ft_over_ds = conf->ft_over_ds;
-#endif /* CONFIG_IEEE80211R */
+ wconf->ft_psk_generate_local = conf->ft_psk_generate_local;
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_HS20
wconf->disable_gtk = conf->disable_dgaf;
if (conf->osen) {
@@ -401,7 +404,7 @@
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
struct wpa_auth_ft_iface_iter_data {
struct hostapd_data *src_hapd;
@@ -440,7 +443,7 @@
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
@@ -465,7 +468,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (proto == ETH_P_RRB && hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
int res;
@@ -480,7 +483,7 @@
if (res == 1)
return data_len;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (hapd->driver && hapd->driver->send_ether)
return hapd->driver->send_ether(hapd->drv_priv, dst,
@@ -503,7 +506,7 @@
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
const u8 *data, size_t data_len)
@@ -588,13 +591,33 @@
return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
int hostapd_setup_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config _conf;
- struct wpa_auth_callbacks cb;
+ static const struct wpa_auth_callbacks cb = {
+ .logger = hostapd_wpa_auth_logger,
+ .disconnect = hostapd_wpa_auth_disconnect,
+ .mic_failure_report = hostapd_wpa_auth_mic_failure_report,
+ .psk_failure_report = hostapd_wpa_auth_psk_failure_report,
+ .set_eapol = hostapd_wpa_auth_set_eapol,
+ .get_eapol = hostapd_wpa_auth_get_eapol,
+ .get_psk = hostapd_wpa_auth_get_psk,
+ .get_msk = hostapd_wpa_auth_get_msk,
+ .set_key = hostapd_wpa_auth_set_key,
+ .get_seqnum = hostapd_wpa_auth_get_seqnum,
+ .send_eapol = hostapd_wpa_auth_send_eapol,
+ .for_each_sta = hostapd_wpa_auth_for_each_sta,
+ .for_each_auth = hostapd_wpa_auth_for_each_auth,
+ .send_ether = hostapd_wpa_auth_send_ether,
+#ifdef CONFIG_IEEE80211R_AP
+ .send_ft_action = hostapd_wpa_auth_send_ft_action,
+ .add_sta = hostapd_wpa_auth_add_sta,
+ .add_tspec = hostapd_wpa_auth_add_tspec,
+#endif /* CONFIG_IEEE80211R_AP */
+ };
const u8 *wpa_ie;
size_t wpa_ie_len;
@@ -603,28 +626,7 @@
_conf.tx_status = 1;
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
_conf.ap_mlme = 1;
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = hapd;
- cb.logger = hostapd_wpa_auth_logger;
- cb.disconnect = hostapd_wpa_auth_disconnect;
- cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
- cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report;
- cb.set_eapol = hostapd_wpa_auth_set_eapol;
- cb.get_eapol = hostapd_wpa_auth_get_eapol;
- cb.get_psk = hostapd_wpa_auth_get_psk;
- cb.get_msk = hostapd_wpa_auth_get_msk;
- cb.set_key = hostapd_wpa_auth_set_key;
- cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
- cb.send_eapol = hostapd_wpa_auth_send_eapol;
- cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
- cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
- cb.send_ether = hostapd_wpa_auth_send_ether;
-#ifdef CONFIG_IEEE80211R
- cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
- cb.add_sta = hostapd_wpa_auth_add_sta;
- cb.add_tspec = hostapd_wpa_auth_add_tspec;
-#endif /* CONFIG_IEEE80211R */
- hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
+ hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
return -1;
@@ -649,8 +651,8 @@
return -1;
}
-#ifdef CONFIG_IEEE80211R
- if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds &&
+#ifdef CONFIG_IEEE80211R_AP
+ if (!hostapd_drv_none(hapd) &&
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
hapd->conf->bridge :
@@ -664,7 +666,7 @@
return -1;
}
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
return 0;
@@ -702,8 +704,8 @@
}
ieee802_1x_deinit(hapd);
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
l2_packet_deinit(hapd->l2);
hapd->l2 = NULL;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 7fd8f05..9564f24 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -14,13 +14,6 @@
struct wpa_group;
-struct wpa_stsl_negotiation {
- struct wpa_stsl_negotiation *next;
- u8 initiator[ETH_ALEN];
- u8 peer[ETH_ALEN];
-};
-
-
struct wpa_state_machine {
struct wpa_authenticator *wpa_auth;
struct wpa_group *group;
@@ -48,8 +41,8 @@
Boolean AuthenticationRequest;
Boolean ReAuthenticationRequest;
Boolean Disconnect;
- int TimeoutCtr;
- int GTimeoutCtr;
+ u32 TimeoutCtr;
+ u32 GTimeoutCtr;
Boolean TimeoutEvt;
Boolean EAPOLKeyReceived;
Boolean EAPOLKeyPairwise;
@@ -89,10 +82,10 @@
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
unsigned int alt_snonce_valid:1;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
@@ -113,7 +106,7 @@
u32 dot11RSNAStatsTKIPLocalMICFailures;
u32 dot11RSNAStatsTKIPRemoteMICFailures;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
size_t xxkey_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
@@ -132,13 +125,20 @@
u8 ft_pending_pull_nonce[FT_R0KH_R1KH_PULL_NONCE_LEN];
u8 ft_pending_auth_transaction;
u8 ft_pending_current_ap[ETH_ALEN];
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
int pending_1_of_4_timeout;
#ifdef CONFIG_P2P
u8 ip_addr[4];
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_FILS
+ u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
+ u8 fils_key_auth_ap[FILS_MAX_KEY_AUTH_LEN];
+ size_t fils_key_auth_len;
+ unsigned int fils_completed:1;
+#endif /* CONFIG_FILS */
};
@@ -194,10 +194,9 @@
unsigned int dot11RSNATKIPCounterMeasuresInvoked;
unsigned int dot11RSNA4WayHandshakeFailures;
- struct wpa_stsl_negotiation *stsl_negotiations;
-
struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
+ const struct wpa_auth_callbacks *cb;
+ void *cb_ctx;
u8 *wpa_ie;
size_t wpa_ie_len;
@@ -232,8 +231,6 @@
void *cb_ctx);
#ifdef CONFIG_PEERKEY
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
- struct wpa_stsl_negotiation *neg);
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *key_data, size_t key_data_len);
@@ -245,7 +242,7 @@
const u8 *key_data, size_t key_data_len);
#endif /* CONFIG_PEERKEY */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
size_t r0kh_id_len,
@@ -257,6 +254,6 @@
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#endif /* WPA_AUTH_I_H */
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index f79783b..c770d62 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -164,7 +164,7 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
pos += RSN_SELECTOR_LEN;
@@ -175,7 +175,7 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
@@ -210,6 +210,30 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+#ifdef CONFIG_FILS
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#ifdef CONFIG_IEEE80211R_AP
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
+#endif /* CONFIG_FILS */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -407,7 +431,7 @@
return res;
pos += res;
}
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
@@ -415,7 +439,7 @@
return res;
pos += res;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
res = wpa_write_wpa_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos);
@@ -509,12 +533,24 @@
selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R_AP
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+ selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+ selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+#endif /* CONFIG_IEEE80211R_AP */
+ else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
+ selector = RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
+ selector = RSN_AUTH_KEY_MGMT_FILS_SHA256;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
@@ -591,12 +627,24 @@
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R_AP
+ else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+#endif /* CONFIG_IEEE80211R_AP */
+ else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
+ else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_IEEE80211W
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -655,7 +703,7 @@
sm->mgmt_frame_prot = 1;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
@@ -668,8 +716,12 @@
"MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
return WPA_INVALID_MDIE;
}
+ } else if (mdie != NULL) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Trying to use non-FT AKM suite, but MDIE included");
+ return WPA_INVALID_AKMP;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
if (sm->pairwise < 0)
@@ -908,14 +960,14 @@
if (*pos == WLAN_EID_RSN) {
ie->rsn_ie = pos;
ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
ie->mdie = pos;
ie->mdie_len = pos[1] + 2;
} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
ie->ftie = pos;
ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index d2067ba..5c3bd18 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -33,12 +33,12 @@
const u8 *igtk;
size_t igtk_len;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_IEEE80211R_AP
const u8 *mdie;
size_t mdie_len;
const u8 *ftie;
size_t ftie_len;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
const u8 *ip_addr_req;
const u8 *ip_addr_alloc;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index faf38c9..95b40da 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -269,12 +269,6 @@
}
-static int str_starts(const char *str, const char *start)
-{
- return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
static void wps_reload_config(void *eloop_data, void *user_ctx)
{
struct hostapd_iface *iface = eloop_data;
diff --git a/src/common/cli.c b/src/common/cli.c
new file mode 100644
index 0000000..b583d1c
--- /dev/null
+++ b/src/common/cli.c
@@ -0,0 +1,267 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functions
+ * Copyright (c) 2004-2016, 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 "utils/common.h"
+#include "common/cli.h"
+
+
+const char *const cli_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
+
+const char *const cli_full_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright\n"
+" notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+" notice, this list of conditions and the following disclaimer in the\n"
+" documentation and/or other materials provided with the distribution.\n"
+"\n"
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+" names of its contributors may be used to endorse or promote products\n"
+" derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+
+
+void cli_txt_list_free(struct cli_txt_entry *e)
+{
+ dl_list_del(&e->list);
+ os_free(e->txt);
+ os_free(e);
+}
+
+
+void cli_txt_list_flush(struct dl_list *list)
+{
+ struct cli_txt_entry *e;
+
+ while ((e = dl_list_first(list, struct cli_txt_entry, list)))
+ cli_txt_list_free(e);
+}
+
+
+struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
+ const char *txt)
+{
+ struct cli_txt_entry *e;
+
+ dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+ if (os_strcmp(e->txt, txt) == 0)
+ return e;
+ }
+ return NULL;
+}
+
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
+{
+ struct cli_txt_entry *e;
+
+ e = cli_txt_list_get(txt_list, txt);
+ if (e)
+ cli_txt_list_free(e);
+}
+
+
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
+{
+ u8 addr[ETH_ALEN];
+ char buf[18];
+
+ if (hwaddr_aton(txt, addr) < 0)
+ return;
+ os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ cli_txt_list_del(txt_list, buf);
+}
+
+
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+ int separator)
+{
+ const char *end;
+ char *buf;
+
+ end = os_strchr(txt, separator);
+ if (end == NULL)
+ end = txt + os_strlen(txt);
+ buf = dup_binstr(txt, end - txt);
+ if (buf == NULL)
+ return;
+ cli_txt_list_del(txt_list, buf);
+ os_free(buf);
+}
+
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
+{
+ struct cli_txt_entry *e;
+
+ e = cli_txt_list_get(txt_list, txt);
+ if (e)
+ return 0;
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return -1;
+ e->txt = os_strdup(txt);
+ if (e->txt == NULL) {
+ os_free(e);
+ return -1;
+ }
+ dl_list_add(txt_list, &e->list);
+ return 0;
+}
+
+
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
+{
+ u8 addr[ETH_ALEN];
+ char buf[18];
+
+ if (hwaddr_aton(txt, addr) < 0)
+ return -1;
+ os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ return cli_txt_list_add(txt_list, buf);
+}
+
+
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+ int separator)
+{
+ const char *end;
+ char *buf;
+ int ret;
+
+ end = os_strchr(txt, separator);
+ if (end == NULL)
+ end = txt + os_strlen(txt);
+ buf = dup_binstr(txt, end - txt);
+ if (buf == NULL)
+ return -1;
+ ret = cli_txt_list_add(txt_list, buf);
+ os_free(buf);
+ return ret;
+}
+
+
+char ** cli_txt_list_array(struct dl_list *txt_list)
+{
+ unsigned int i, count = dl_list_len(txt_list);
+ char **res;
+ struct cli_txt_entry *e;
+
+ res = os_calloc(count + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+
+ i = 0;
+ dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+ res[i] = os_strdup(e->txt);
+ if (res[i] == NULL)
+ break;
+ i++;
+ }
+
+ return res;
+}
+
+
+int get_cmd_arg_num(const char *str, int pos)
+{
+ int arg = 0, i;
+
+ for (i = 0; i <= pos; i++) {
+ if (str[i] != ' ') {
+ arg++;
+ while (i <= pos && str[i] != ' ')
+ i++;
+ }
+ }
+
+ if (arg > 0)
+ arg--;
+ return arg;
+}
+
+
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, char *argv[])
+{
+ int i, res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos, "%s", cmd);
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+
+ for (i = 0; i < argc; i++) {
+ res = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (os_snprintf_error(end - pos, res))
+ goto fail;
+ pos += res;
+ }
+
+ buf[buflen - 1] = '\0';
+ return 0;
+
+fail:
+ printf("Too long command\n");
+ return -1;
+}
+
+
+int tokenize_cmd(char *cmd, char *argv[])
+{
+ char *pos;
+ int argc = 0;
+
+ pos = cmd;
+ for (;;) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[argc] = pos;
+ argc++;
+ if (argc == max_args)
+ break;
+ if (*pos == '"') {
+ char *pos2 = os_strrchr(pos, '"');
+ if (pos2)
+ pos = pos2 + 1;
+ }
+ while (*pos != '\0' && *pos != ' ')
+ pos++;
+ if (*pos == ' ')
+ *pos++ = '\0';
+ }
+
+ return argc;
+}
diff --git a/src/common/cli.h b/src/common/cli.h
new file mode 100644
index 0000000..41ef329
--- /dev/null
+++ b/src/common/cli.h
@@ -0,0 +1,47 @@
+/*
+ * Common hostapd/wpa_supplicant command line interface functionality
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CLI_H
+#define CLI_H
+
+#include "utils/list.h"
+
+extern const char *const cli_license;
+extern const char *const cli_full_license;
+
+struct cli_txt_entry {
+ struct dl_list list;
+ char *txt;
+};
+
+void cli_txt_list_free(struct cli_txt_entry *e);
+void cli_txt_list_flush(struct dl_list *list);
+
+struct cli_txt_entry *
+cli_txt_list_get(struct dl_list *txt_list, const char *txt);
+
+void cli_txt_list_del(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt);
+void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
+ int separator);
+
+int cli_txt_list_add(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt);
+int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
+ int separator);
+
+char ** cli_txt_list_array(struct dl_list *txt_list);
+
+int get_cmd_arg_num(const char *str, int pos);
+int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+ char *argv[]);
+
+#define max_args 10
+int tokenize_cmd(char *cmd, char *argv[]);
+
+#endif /* CLI_H */
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index d69448b..0b596bb 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
@@ -52,12 +53,38 @@
18, ParseOK, 9 },
{ (u8 *) "\x8b\x00", 2, ParseOK, 1 },
{ (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
+ { (u8 *) "\xed\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xef\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xef\x01\x11", 3, ParseOK, 1 },
+ { (u8 *) "\xf0\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xf1\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xf1\x02\x11\x22", 4, ParseOK, 1 },
+ { (u8 *) "\xf2\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xff\x00", 2, ParseUnknown, 1 },
+ { (u8 *) "\xff\x01\x00", 3, ParseUnknown, 1 },
+ { (u8 *) "\xff\x01\x01", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x02\x01\x00", 4, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x02", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x04\x02\x11\x22\x33", 6, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x04", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x05", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x0d\x05\x11\x22\x33\x44\x55\x55\x11\x22\x33\x44\x55\x55",
+ 15, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x06", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x02\x06\x00", 4, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x07", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x09\x07\x11\x22\x33\x44\x55\x66\x77\x88", 11,
+ ParseOK, 1 },
+ { (u8 *) "\xff\x01\x0c", 3, ParseOK, 1 },
+ { (u8 *) "\xff\x02\x0c\x00", 4, ParseOK, 1 },
+ { (u8 *) "\xff\x01\x0d", 3, ParseOK, 1 },
{ NULL, 0, ParseOK, 0 }
};
static int ieee802_11_parse_tests(void)
{
int i, ret = 0;
+ struct wpabuf *buf;
wpa_printf(MSG_INFO, "ieee802_11_parse tests");
@@ -83,6 +110,35 @@
ret = -1;
}
+ buf = ieee802_11_vendor_ie_concat((const u8 *) "\xdd\x05\x11\x22\x33\x44\x01\xdd\x05\x11\x22\x33\x44\x02\x00\x01",
+ 16, 0x11223344);
+ do {
+ const u8 *pos;
+
+ if (!buf) {
+ wpa_printf(MSG_ERROR,
+ "ieee802_11_vendor_ie_concat test 2 failed");
+ ret = -1;
+ break;
+ }
+
+ if (wpabuf_len(buf) != 2) {
+ wpa_printf(MSG_ERROR,
+ "ieee802_11_vendor_ie_concat test 3 failed");
+ ret = -1;
+ break;
+ }
+
+ pos = wpabuf_head(buf);
+ if (pos[0] != 0x01 || pos[1] != 0x02) {
+ wpa_printf(MSG_ERROR,
+ "ieee802_11_vendor_ie_concat test 3 failed");
+ ret = -1;
+ break;
+ }
+ } while (0);
+ wpabuf_free(buf);
+
return ret;
}
diff --git a/src/common/defs.h b/src/common/defs.h
index 6ef929c..eaccced 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -51,6 +51,10 @@
#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
+#define WPA_KEY_MGMT_FILS_SHA256 BIT(18)
+#define WPA_KEY_MGMT_FILS_SHA384 BIT(19)
+#define WPA_KEY_MGMT_FT_FILS_SHA256 BIT(20)
+#define WPA_KEY_MGMT_FT_FILS_SHA384 BIT(21)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
@@ -60,7 +64,11 @@
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
- WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
+ WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -76,7 +84,14 @@
{
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_SAE));
+ WPA_KEY_MGMT_FT_SAE |
+ WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384));
+}
+
+static inline int wpa_key_mgmt_ft_psk(int akm)
+{
+ return !!(akm & WPA_KEY_MGMT_FT_PSK);
}
static inline int wpa_key_mgmt_sae(int akm)
@@ -85,17 +100,29 @@
WPA_KEY_MGMT_FT_SAE));
}
+static inline int wpa_key_mgmt_fils(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA384));
+}
+
static inline int wpa_key_mgmt_sha256(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_OSEN |
- WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FT_FILS_SHA256));
}
static inline int wpa_key_mgmt_sha384(int akm)
{
- return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+ return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
+ WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA384));
}
static inline int wpa_key_mgmt_suite_b(int akm)
@@ -108,6 +135,7 @@
{
return wpa_key_mgmt_wpa_ieee8021x(akm) ||
wpa_key_mgmt_wpa_psk(akm) ||
+ wpa_key_mgmt_fils(akm) ||
wpa_key_mgmt_sae(akm);
}
@@ -132,6 +160,7 @@
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
#define WPA_AUTH_ALG_SAE BIT(4)
+#define WPA_AUTH_ALG_FILS BIT(5)
enum wpa_alg {
@@ -320,13 +349,13 @@
#define EAP_MAX_METHODS 8
enum mesh_plink_state {
- PLINK_LISTEN = 1,
- PLINK_OPEN_SENT,
- PLINK_OPEN_RCVD,
+ PLINK_IDLE = 1,
+ PLINK_OPN_SNT,
+ PLINK_OPN_RCVD,
PLINK_CNF_RCVD,
PLINK_ESTAB,
PLINK_HOLDING,
- PLINK_BLOCKED,
+ PLINK_BLOCKED, /* not defined in the IEEE 802.11 standard */
};
enum set_band {
@@ -341,4 +370,14 @@
BAND_60_GHZ = BIT(2),
};
+enum beacon_rate_type {
+ BEACON_RATE_LEGACY,
+ BEACON_RATE_HT,
+ BEACON_RATE_VHT
+};
+
+enum eap_proxy_sim_state {
+ SIM_STATE_ERROR,
+};
+
#endif /* DEFS_H */
diff --git a/src/common/dhcp.h b/src/common/dhcp.h
new file mode 100644
index 0000000..f2ef61e
--- /dev/null
+++ b/src/common/dhcp.h
@@ -0,0 +1,257 @@
+/*
+ * DHCP definitions
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#define DHCP_SERVER_PORT 67
+#define DHCP_CLIENT_PORT 68
+
+struct dhcp_data {
+ u8 op;
+ u8 htype;
+ u8 hlen;
+ u8 hops;
+ be32 xid;
+ be16 secs;
+ be16 flags;
+ be32 client_ip;
+ be32 your_ip;
+ be32 server_ip;
+ be32 relay_ip;
+ u8 hw_addr[16];
+ u8 serv_name[64];
+ u8 boot_file[128];
+} STRUCT_PACKED;
+
+struct bootp_pkt {
+ struct iphdr iph;
+ struct udphdr udph;
+ u8 op;
+ u8 htype;
+ u8 hlen;
+ u8 hops;
+ be32 xid;
+ be16 secs;
+ be16 flags;
+ be32 client_ip;
+ be32 your_ip;
+ be32 server_ip;
+ be32 relay_ip;
+ u8 hw_addr[16];
+ u8 serv_name[64];
+ u8 boot_file[128];
+ u8 exten[312];
+} STRUCT_PACKED;
+
+#define DHCP_MAGIC 0x63825363
+
+/*
+ * IANA DHCP/BOOTP registry
+ * http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
+*/
+enum dhcp_options {
+ DHCP_OPT_PAD = 0,
+ DHCP_OPT_SUBNET_MASK = 1,
+ DHCP_OPT_TIME_OFFSET = 2,
+ DHCP_OPT_ROUTER = 3,
+ DHCP_OPT_TIME_SERVER = 4,
+ DHCP_OPT_NAME_SERVER = 5,
+ DHCP_OPT_DOMAIN_NAME_SERVER = 6,
+ DHCP_OPT_LOG_SERVER = 7,
+ DHCP_OPT_QUOTES_SERVER = 8,
+ DHCP_OPT_LPR_SERVER = 9,
+ DHCP_OPT_IMPRESS_SERVER = 10,
+ DHCP_OPT_RLP_SERVER = 11,
+ DHCP_OPT_HOSTNAME = 12,
+ DHCP_OPT_BOOT_FILE_SIZE = 13,
+ DHCP_OPT_MERIT_DUMP_FILE = 14,
+ DHCP_OPT_DOMAIN_NAME = 15,
+ DHCP_OPT_SWAP_SERVER = 16,
+ DHCP_OPT_ROOT_PATH = 17,
+ DHCP_OPT_EXTENSION_PATH = 18,
+ DHCP_OPT_FORWARD = 19,
+ DHCP_OPT_SRC_RTE = 20,
+ DHCP_OPT_POLICY_FILTER = 21,
+ DHCP_OPT_MAX_DG_ASSEMBLY = 22,
+ DHCP_OPT_DEFAULT_IP_TTL = 23,
+ DHCP_OPT_MTU_TIMEOUT = 24,
+ DHCP_OPT_MTU_PLATEAU = 25,
+ DHCP_OPT_MTU_INTERFACE = 26,
+ DHCP_OPT_ALL_SUBNETS_LOCAL = 27,
+ DHCP_OPT_BROADCAST_ADDRESS = 28,
+ DHCP_OPT_MASK_DISCOVERY = 29,
+ DHCP_OPT_MASK_SUPPLIER = 30,
+ DHCP_OPT_ROUTER_DISCOVERY = 31,
+ DHCP_OPT_ROUTER_SOLICITATION_ADDRESS = 32,
+ DHCP_OPT_STATIC_ROUTE = 33,
+ DHCP_OPT_TRAILERS = 34,
+ DHCP_OPT_ARP_TIMEOUT = 35,
+ DHCP_OPT_ETHERNET = 36,
+ DHCP_OPT_TCP_DEFAULT_TTL = 37,
+ DHCP_OPT_TCP_KEEPALIVE_INTERVAL = 38,
+ DHCP_OPT_TCP_KEEPALIVE_GARBAGE = 39,
+ DHCP_OPT_NIS_DOMAIN = 40,
+ DHCP_OPT_NIS_SERVERS = 41,
+ DHCP_OPT_NTP_SERVERS = 42,
+ DHCP_OPT_VENDOR_SPECIFIC = 43,
+ DHCP_OPT_NETBIOS_NAME_SERVER = 44,
+ DHCP_OPT_NETBIOS_DISTRIBUTION_SERVER = 45,
+ DHCP_OPT_NETBIOS_NODE_TYPE = 46,
+ DHCP_OPT_NETBIOS_SCOPE = 47,
+ DHCP_OPT_FONT_SERVER = 48,
+ DHCP_OPT_DISPLAY_MANAGER = 49,
+ DHCP_OPT_REQUESTED_IP_ADDRESS = 50,
+ DHCP_OPT_IP_ADDRESS_LEASE_TIME = 51,
+ DHCP_OPT_OVERLOAD = 52,
+ DHCP_OPT_MSG_TYPE = 53,
+ DHCP_OPT_SERVER_ID = 54,
+ DHCP_OPT_PARAMETER_REQ_LIST = 55,
+ DHCP_OPT_MESSAGE = 56,
+ DHCP_OPT_MAX_MESSAGE_SIZE = 57,
+ DHCP_OPT_RENEWAL_TIME = 58,
+ DHCP_OPT_REBINDING_TIME = 59,
+ DHCP_OPT_VENDOR_CLASS_ID = 60,
+ DHCP_OPT_CLIENT_ID = 61,
+ DHCP_OPT_NETWARE_IP_DOMAIN = 62,
+ DHCP_OPT_NETWARE_IP_OPTION = 63,
+ DHCP_OPT_NIS_V3_DOMAIN = 64,
+ DHCP_OPT_NIS_V3_SERVERS = 65,
+ DHCP_OPT_TFTP_SERVER_NAME = 66,
+ DHCP_OPT_BOOT_FILE_NAME = 67,
+ DHCP_OPT_HOME_AGENT_ADDRESSES = 68,
+ DHCP_OPT_SMTP_SERVER = 69,
+ DHCP_OPT_POP3_SERVER = 70,
+ DHCP_OPT_NNTP_SERVER = 71,
+ DHCP_OPT_WWW_SERVER = 72,
+ DHCP_OPT_FINGER_SERVER = 73,
+ DHCP_OPT_IRC_SERVER = 74,
+ DHCP_OPT_STREETTALK_SERVER = 75,
+ DHCP_OPT_STDA_SERVER = 76,
+ DHCP_OPT_USER_CLASS = 77,
+ DHCP_OPT_DIRECTORY_AGENT = 78,
+ DHCP_OPT_SERVICE_SCOPE = 79,
+ DHCP_OPT_RAPID_COMMIT = 80,
+ DHCP_OPT_CLIENT_FQDN = 81,
+ DHCP_OPT_RELAY_AGENT_INFO = 82,
+ DHCP_OPT_ISNS = 83,
+ DHCP_OPT_NDS_SERVERS = 85,
+ DHCP_OPT_NDS_TREE_NAME = 86,
+ DHCP_OPT_NDS_CONTEXT = 87,
+ DHCP_OPT_BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88,
+ DHCP_OPT_BCMCS_CONTROLLER_IPV4_ADDRESS = 89,
+ DHCP_OPT_AUTHENTICATION = 90,
+ DHCP_OPT_CLIENT_LAST_TRANSACTION_TIME = 91,
+ DHCP_OPT_ASSOCIATED_IP = 92,
+ DHCP_OPT_CLIENT_SYSYEM = 93,
+ DHCP_OPT_CLIENT_NDI = 94,
+ DHCP_OPT_LDAP = 95,
+ DHCP_OPT_UUID_GUID = 97,
+ DHCP_OPT_USER_AUTH = 98,
+ DHCP_OPT_GEOCONF_CIVIC = 99,
+ DHCP_OPT_PCODE = 100,
+ DHCP_OPT_TCODE = 101,
+ DHCP_OPT_NETINFO_ADDRESS = 112,
+ DHCP_OPT_NETINFO_TAG = 113,
+ DHCP_OPT_URL = 114,
+ DHCP_OPT_AUTO_CONFIG = 116,
+ DHCP_OPT_NAME_SERVICE_SEARCH = 117,
+ DHCP_OPT_SUBNET_SELECTION = 118,
+ DHCP_OPT_DOMAIN_SEARCH = 119,
+ DHCP_OPT_SIP_SERVERS_DCP = 120,
+ DHCP_OPT_CLASSLESS_STATIC_ROUTE = 121,
+ DHCP_OPT_CCC = 122,
+ DHCP_OPT_GEOCONF = 123,
+ DHCP_OPT_V_I_VENDOR_CLASS = 124,
+ DHCP_OPT_V_I_VENDOR_SPECIFIC_INFO = 125,
+ DHCP_OPT_PANA_AGENT = 136,
+ DHCP_OPT_V4_LOST = 137,
+ DHCP_OPT_CAPWAP_AC_V4 = 138,
+ DHCP_OPT_IPV4_ADDRESS_MOS = 139,
+ DHCP_OPT_IPV4_FQDN_MOS = 140,
+ DHCP_OPT_SIP_UA_CONF = 141,
+ DHCP_OPT_IPV4_ADDRESS_ANDSF = 142,
+ DHCP_OPT_GEOLOC = 144,
+ DHCP_OPT_FORCERENEW_NONCE_CAPABLE = 145,
+ DHCP_OPT_RDNSS_SELECTION = 146,
+ DHCP_OPT_TFTP_SERVER_ADDRESS = 150,
+ DHCP_OPT_STATUS_CODE = 151,
+ DHCP_OPT_BASE_TIME = 152,
+ DHCP_OPT_START_TIME_OF_STATE = 153,
+ DHCP_OPT_QUERY_START_TIME = 154,
+ DHCP_OPT_QUERY_END_TIME = 155,
+ DHCP_OPT_STATE = 156,
+ DHCP_OPT_DATA_SOURCE = 157,
+ DHCP_OPT_V4_PCP_SERVER = 158,
+ DHCP_OPT_V4_PORTPARAMS = 159,
+ DHCP_OPT_CAPTIVE_PORTAL = 160,
+ DHCP_OPT_CONF_FILE = 209,
+ DHCP_OPT_PATH_PREFIX = 210,
+ DHCP_OPT_REBOOT_TIME = 211,
+ DHCP_OPT_6RD = 212,
+ DHCP_OPT_V4_ACCESS_DOMAIN = 213,
+ DHCP_OPT_SUBNET_ALLOCATION = 220,
+ DHCP_OPT_VSS = 221,
+ DHCP_OPT_END = 255
+};
+
+enum dhcp_message_types {
+ DHCPDISCOVER = 1,
+ DHCPOFFER = 2,
+ DHCPREQUEST = 3,
+ DHCPDECLINE = 4,
+ DHCPACK = 5,
+ DHCPNAK = 6,
+ DHCPRELEASE = 7,
+ DHCPINFORM = 8,
+ DHCPFORCERENEW = 9,
+ DHCPLEASEQUERY = 10,
+ DHCPLEASEUNASSIGNED = 11,
+ DHCPLEASEUNKNOWN = 12,
+ DHCPLEASEACTIVE = 13,
+ DHCPBULKLEASEQUERY = 14,
+ DHCPLEASEQUERYDONE = 15,
+ DHCPACTIVELEASEQUERY = 16,
+ DHCPLEASEQUERYSTATUS = 17,
+ DHCPTLS = 18,
+};
+
+enum dhcp_relay_agent_suboptions {
+ DHCP_RELAY_OPT_AGENT_CIRCUIT_ID = 1,
+ DHCP_RELAY_OPT_AGENT_REMOTE_ID = 2,
+ DHCP_RELAY_OPT_DOCSIS_DEVICE_CLASS = 4,
+ DHCP_RELAY_OPT_LINK_SELECTION = 5,
+ DHCP_RELAY_OPT_SUBSCRIBE_ID = 6,
+ DHCP_RELAY_OPT_RADIUS_ATTRIBUTES = 7,
+ DHCP_RELAY_OPT_AUTHENTICATION = 8,
+ DHCP_RELAY_OPT_VEDOR_SPECIFIC = 9,
+ DHCP_RELAY_OPT_RELAY_AGENT_FLAGS = 10,
+ DHCP_RELAY_OPT_SERVER_ID_OVERRIDE = 11,
+ DHCP_RELAY_OPT_RELAY_AGENT_ID = 12,
+ DHCP_RELAY_OPT_ACCESS_TECHNOLOGY_TYPE = 13,
+ DHCP_RELAY_OPT_ACCESS_NETWORK_NAME = 14,
+ DHCP_RELAY_OPT_ACCESS_POINT_NAME = 15,
+ DHCP_RELAY_OPT_ACCESS_POINT_BSSID = 16,
+ DHCP_RELAY_OPT_OPERATOR_ID = 17,
+ DHCP_RELAY_OPT_OPERATOR_REALM = 18,
+ DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION = 151,
+ DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION_CONTROL = 152,
+};
+
+enum access_technology_types {
+ ACCESS_TECHNOLOGY_VIRTUAL = 1,
+ ACCESS_TECHNOLOGY_PPP = 2,
+ ACCESS_TECHNOLOGY_ETHERNET = 3,
+ ACCESS_TECHNOLOGY_WLAN = 4,
+ ACCESS_TECHNOLOGY_WIMAX = 5,
+};
+
+#endif /* DHCP_H */
diff --git a/src/common/eapol_common.h b/src/common/eapol_common.h
index 6958661..d773348 100644
--- a/src/common/eapol_common.h
+++ b/src/common/eapol_common.h
@@ -25,7 +25,7 @@
struct ieee8023_hdr {
u8 dest[ETH_ALEN];
u8 src[ETH_ALEN];
- u16 ethertype;
+ be16 ethertype;
} STRUCT_PACKED;
#ifdef _MSC_VER
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 9c37ea6..7a96f96 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -388,8 +388,10 @@
/* fall through */
case VHT_CHANWIDTH_80MHZ:
data->bandwidth = 80;
- if ((vht_oper_chwidth == 1 && center_segment1) ||
- (vht_oper_chwidth == 3 && !center_segment1) ||
+ if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
+ center_segment1) ||
+ (vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
+ !center_segment1) ||
!sec_channel_offset)
return -1;
if (!center_segment0) {
@@ -453,3 +455,102 @@
return 0;
}
+
+
+void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
+ int disabled)
+{
+ /* Masking these out disables HT40 */
+ le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+ HT_CAP_INFO_SHORT_GI40MHZ);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+}
+
+
+#ifdef CONFIG_IEEE80211AC
+
+static int _ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap,
+ const char *name)
+{
+ u32 req_cap = conf & cap;
+
+ /*
+ * Make sure we support all requested capabilities.
+ * NOTE: We assume that 'cap' represents a capability mask,
+ * not a discrete value.
+ */
+ if ((hw & req_cap) != req_cap) {
+ wpa_printf(MSG_ERROR,
+ "Driver does not support configured VHT capability [%s]",
+ name);
+ return 0;
+ }
+ return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
+ unsigned int shift,
+ const char *name)
+{
+ u32 hw_max = hw & mask;
+ u32 conf_val = conf & mask;
+
+ if (conf_val > hw_max) {
+ wpa_printf(MSG_ERROR,
+ "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
+ name, conf_val >> shift, hw_max >> shift);
+ return 0;
+ }
+ return 1;
+}
+
+
+int ieee80211ac_cap_check(u32 hw, u32 conf)
+{
+#define VHT_CAP_CHECK(cap) \
+ do { \
+ if (!_ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+ return 0; \
+ } while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) \
+ do { \
+ if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
+ #cap)) \
+ return 0; \
+ } while (0)
+
+ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
+ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
+ VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+ VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+ VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+ VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+ VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+ VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
+ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+ VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+ VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+ return 1;
+}
+
+#endif /* CONFIG_IEEE80211AC */
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 7360b4e..9cddbd5 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -35,5 +35,8 @@
int vht_enabled, int sec_channel_offset,
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps);
+void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
+ int disabled);
+int ieee80211ac_cap_check(u32 hw, u32 conf);
#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 5b05b68..a8d68e5 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -179,6 +179,90 @@
}
+static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
+ struct ieee802_11_elems *elems,
+ int show_errors)
+{
+ u8 ext_id;
+
+ if (elen < 1) {
+ if (show_errors) {
+ wpa_printf(MSG_MSGDUMP,
+ "short information element (Ext)");
+ }
+ return -1;
+ }
+
+ ext_id = *pos++;
+ elen--;
+
+ switch (ext_id) {
+ case WLAN_EID_EXT_ASSOC_DELAY_INFO:
+ if (elen != 1)
+ break;
+ elems->assoc_delay_info = pos;
+ break;
+ case WLAN_EID_EXT_FILS_REQ_PARAMS:
+ if (elen < 3)
+ break;
+ elems->fils_req_params = pos;
+ elems->fils_req_params_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_KEY_CONFIRM:
+ elems->fils_key_confirm = pos;
+ elems->fils_key_confirm_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_SESSION:
+ if (elen != FILS_SESSION_LEN)
+ break;
+ elems->fils_session = pos;
+ break;
+ case WLAN_EID_EXT_FILS_HLP_CONTAINER:
+ if (elen < 2 * ETH_ALEN)
+ break;
+ elems->fils_hlp = pos;
+ elems->fils_hlp_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN:
+ if (elen < 1)
+ break;
+ elems->fils_ip_addr_assign = pos;
+ elems->fils_ip_addr_assign_len = elen;
+ break;
+ case WLAN_EID_EXT_KEY_DELIVERY:
+ if (elen < WPA_KEY_RSC_LEN)
+ break;
+ elems->key_delivery = pos;
+ elems->key_delivery_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_WRAPPED_DATA:
+ elems->fils_wrapped_data = pos;
+ elems->fils_wrapped_data_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_PUBLIC_KEY:
+ if (elen < 1)
+ break;
+ elems->fils_pk = pos;
+ elems->fils_pk_len = elen;
+ break;
+ case WLAN_EID_EXT_FILS_NONCE:
+ if (elen != FILS_NONCE_LEN)
+ break;
+ elems->fils_nonce = pos;
+ break;
+ default:
+ if (show_errors) {
+ wpa_printf(MSG_MSGDUMP,
+ "IEEE 802.11 element parsing ignored unknown element extension (ext_id=%u elen=%u)",
+ ext_id, (unsigned int) elen);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
@@ -375,6 +459,39 @@
elems->supp_op_classes = pos;
elems->supp_op_classes_len = elen;
break;
+ case WLAN_EID_RRM_ENABLED_CAPABILITIES:
+ elems->rrm_enabled = pos;
+ elems->rrm_enabled_len = elen;
+ break;
+ case WLAN_EID_CAG_NUMBER:
+ elems->cag_number = pos;
+ elems->cag_number_len = elen;
+ break;
+ case WLAN_EID_AP_CSN:
+ if (elen < 1)
+ break;
+ elems->ap_csn = pos;
+ break;
+ case WLAN_EID_FILS_INDICATION:
+ if (elen < 2)
+ break;
+ elems->fils_indic = pos;
+ elems->fils_indic_len = elen;
+ break;
+ case WLAN_EID_DILS:
+ if (elen < 2)
+ break;
+ elems->dils = pos;
+ elems->dils_len = elen;
+ break;
+ case WLAN_EID_FRAGMENT:
+ /* TODO */
+ break;
+ case WLAN_EID_EXTENSION:
+ if (ieee802_11_parse_extension(pos, elen, elems,
+ show_errors))
+ unknown++;
+ break;
default:
unknown++;
if (!show_errors)
@@ -677,6 +794,25 @@
return HOSTAPD_MODE_IEEE80211A;
}
+ /* 5 GHz, channels 52..64 */
+ if (freq >= 5260 && freq <= 5320) {
+ if ((freq - 5000) % 5)
+ return NUM_HOSTAPD_MODES;
+
+ if (vht_opclass)
+ *op_class = vht_opclass;
+ else if (sec_channel == 1)
+ *op_class = 119;
+ else if (sec_channel == -1)
+ *op_class = 120;
+ else
+ *op_class = 118;
+
+ *channel = (freq - 5000) / 5;
+
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
/* 5 GHz, channels 149..169 */
if (freq >= 5745 && freq <= 5845) {
if ((freq - 5000) % 5)
@@ -1313,3 +1449,148 @@
return 6 + attr_len;
}
+
+
+static const struct country_op_class us_op_class[] = {
+ { 1, 115 },
+ { 2, 118 },
+ { 3, 124 },
+ { 4, 121 },
+ { 5, 125 },
+ { 12, 81 },
+ { 22, 116 },
+ { 23, 119 },
+ { 24, 122 },
+ { 25, 126 },
+ { 26, 126 },
+ { 27, 117 },
+ { 28, 120 },
+ { 29, 123 },
+ { 30, 127 },
+ { 31, 127 },
+ { 32, 83 },
+ { 33, 84 },
+ { 34, 180 },
+};
+
+static const struct country_op_class eu_op_class[] = {
+ { 1, 115 },
+ { 2, 118 },
+ { 3, 121 },
+ { 4, 81 },
+ { 5, 116 },
+ { 6, 119 },
+ { 7, 122 },
+ { 8, 117 },
+ { 9, 120 },
+ { 10, 123 },
+ { 11, 83 },
+ { 12, 84 },
+ { 17, 125 },
+ { 18, 180 },
+};
+
+static const struct country_op_class jp_op_class[] = {
+ { 1, 115 },
+ { 30, 81 },
+ { 31, 82 },
+ { 32, 118 },
+ { 33, 118 },
+ { 34, 121 },
+ { 35, 121 },
+ { 36, 116 },
+ { 37, 119 },
+ { 38, 119 },
+ { 39, 122 },
+ { 40, 122 },
+ { 41, 117 },
+ { 42, 120 },
+ { 43, 120 },
+ { 44, 123 },
+ { 45, 123 },
+ { 56, 83 },
+ { 57, 84 },
+ { 58, 121 },
+ { 59, 180 },
+};
+
+static const struct country_op_class cn_op_class[] = {
+ { 1, 115 },
+ { 2, 118 },
+ { 3, 125 },
+ { 4, 116 },
+ { 5, 119 },
+ { 6, 126 },
+ { 7, 81 },
+ { 8, 83 },
+ { 9, 84 },
+};
+
+static u8
+global_op_class_from_country_array(u8 op_class, size_t array_size,
+ const struct country_op_class *country_array)
+{
+ size_t i;
+
+ for (i = 0; i < array_size; i++) {
+ if (country_array[i].country_op_class == op_class)
+ return country_array[i].global_op_class;
+ }
+
+ return 0;
+}
+
+
+u8 country_to_global_op_class(const char *country, u8 op_class)
+{
+ const struct country_op_class *country_array;
+ size_t size;
+ u8 g_op_class;
+
+ if (country_match(us_op_class_cc, country)) {
+ country_array = us_op_class;
+ size = ARRAY_SIZE(us_op_class);
+ } else if (country_match(eu_op_class_cc, country)) {
+ country_array = eu_op_class;
+ size = ARRAY_SIZE(eu_op_class);
+ } else if (country_match(jp_op_class_cc, country)) {
+ country_array = jp_op_class;
+ size = ARRAY_SIZE(jp_op_class);
+ } else if (country_match(cn_op_class_cc, country)) {
+ country_array = cn_op_class;
+ size = ARRAY_SIZE(cn_op_class);
+ } else {
+ /*
+ * Countries that do not match any of the above countries use
+ * global operating classes
+ */
+ return op_class;
+ }
+
+ g_op_class = global_op_class_from_country_array(op_class, size,
+ country_array);
+
+ /*
+ * If the given operating class did not match any of the country's
+ * operating classes, assume that global operating class is used.
+ */
+ return g_op_class ? g_op_class : op_class;
+}
+
+
+const struct oper_class_map * get_oper_class(const char *country, u8 op_class)
+{
+ const struct oper_class_map *op;
+
+ if (country)
+ op_class = country_to_global_op_class(country, op_class);
+
+ op = &global_op_class[0];
+ while (op->op_class && op->op_class != op_class)
+ op++;
+
+ if (!op->op_class)
+ return NULL;
+
+ return op;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index d9fecd6..966eeac 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -63,6 +63,21 @@
const u8 *mic;
const u8 *pref_freq_list;
const u8 *supp_op_classes;
+ const u8 *rrm_enabled;
+ const u8 *cag_number;
+ const u8 *ap_csn;
+ const u8 *fils_indic;
+ const u8 *dils;
+ const u8 *assoc_delay_info;
+ const u8 *fils_req_params;
+ const u8 *fils_key_confirm;
+ const u8 *fils_session;
+ const u8 *fils_hlp;
+ const u8 *fils_ip_addr_assign;
+ const u8 *key_delivery;
+ const u8 *fils_wrapped_data;
+ const u8 *fils_pk;
+ const u8 *fils_nonce;
u8 ssid_len;
u8 supp_rates_len;
@@ -94,6 +109,17 @@
u8 mic_len;
u8 pref_freq_list_len;
u8 supp_op_classes_len;
+ u8 rrm_enabled_len;
+ u8 cag_number_len;
+ u8 fils_indic_len;
+ u8 dils_len;
+ u8 fils_req_params_len;
+ u8 fils_key_confirm_len;
+ u8 fils_hlp_len;
+ u8 fils_ip_addr_assign_len;
+ u8 key_delivery_len;
+ u8 fils_wrapped_data_len;
+ u8 fils_pk_len;
struct mb_ies_info mb_ies;
};
@@ -151,4 +177,13 @@
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
+struct country_op_class {
+ u8 country_op_class;
+ u8 global_op_class;
+};
+
+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);
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index e1a8ef7..15f6d42 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -81,6 +81,9 @@
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_SAE 3
+#define WLAN_AUTH_FILS_SK 4
+#define WLAN_AUTH_FILS_SK_PFS 5
+#define WLAN_AUTH_FILS_PK 6
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -102,7 +105,7 @@
#define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14)
#define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15)
-/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
+/* Status codes (IEEE Std 802.11-2016, 9.4.1.9, Table 9-46) */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
@@ -119,27 +122,23 @@
#define WLAN_STATUS_AUTH_TIMEOUT 16
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* IEEE 802.11b */
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
-/* IEEE 802.11h */
#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
-/* IEEE 802.11g */
#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
#define WLAN_STATUS_R0KH_UNREACHABLE 28
#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
-/* IEEE 802.11w */
#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_DENIED_INSUFFICIENT_BANDWIDTH 33
+#define WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS 34
+#define WLAN_STATUS_DENIED_QOS_NOT_SUPPORTED 35
#define WLAN_STATUS_REQUEST_DECLINED 37
#define WLAN_STATUS_INVALID_PARAMETERS 38
-/* IEEE 802.11i */
+#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES 39
#define WLAN_STATUS_INVALID_IE 40
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
@@ -152,11 +151,13 @@
#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
-/* IEEE 802.11r */
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
#define WLAN_STATUS_INVALID_PMKID 53
#define WLAN_STATUS_INVALID_MDIE 54
#define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_REQUESTED_TCLAS_NOT_SUPPORTED 56
+#define WLAN_STATUS_INSUFFICIENT_TCLAS_PROCESSING_RESOURCES 57
+#define WLAN_STATUS_TRY_ANOTHER_BSS 58
#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
@@ -167,16 +168,43 @@
#define WLAN_STATUS_REQ_REFUSED_SSPN 67
#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_U_APSD_COEX_NOT_SUPPORTED 73
+#define WLAN_STATUS_U_APSD_COEX_MODE_NOT_SUPPORTED 74
+#define WLAN_STATUS_BAD_INTERVAL_WITH_U_APSD_COEX 75
#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
+#define WLAN_STATUS_CANNOT_FIND_ALT_TBTT 78
#define WLAN_STATUS_TRANSMISSION_FAILURE 79
+#define WLAN_STATUS_REQ_TCLAS_NOT_SUPPORTED 80
+#define WLAN_STATUS_TCLAS_RESOURCES_EXCHAUSTED 81
#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82
+#define WLAN_STATUS_REJECT_WITH_SCHEDULE 83
+#define WLAN_STATUS_REJECT_NO_WAKEUP_SPECIFIED 84
+#define WLAN_STATUS_SUCCESS_POWER_SAVE_MODE 85
#define WLAN_STATUS_PENDING_ADMITTING_FST_SESSION 86
+#define WLAN_STATUS_PERFORMING_FST_NOW 87
+#define WLAN_STATUS_PENDING_GAP_IN_BA_WINDOW 88
+#define WLAN_STATUS_REJECT_U_PID_SETTING 89
+#define WLAN_STATUS_REFUSED_EXTERNAL_REASON 92
+#define WLAN_STATUS_REFUSED_AP_OUT_OF_MEMORY 93
+#define WLAN_STATUS_REJECTED_EMERGENCY_SERVICE_NOT_SUPPORTED 94
#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
+#define WLAN_STATUS_REJECT_DSE_BAND 96
+#define WLAN_STATUS_TCLAS_PROCESSING_TERMINATED 97
+#define WLAN_STATUS_TS_SCHEDULE_CONFLICT 98
#define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99
+#define WLAN_STATUS_MCCAOP_RESERVATION_CONFLICT 100
+#define WLAN_STATUS_MAF_LIMIT_EXCEEDED 101
+#define WLAN_STATUS_MCCA_TRACK_LIMIT_EXCEEDED 102
+#define WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT 103
#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
+#define WLAN_STATUS_ENABLEMENT_DENIED 105
+#define WLAN_STATUS_RESTRICTION_FROM_AUTHORIZED_GDB 106
+#define WLAN_STATUS_AUTHORIZATION_DEENABLED 107
+#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
+#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
-/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
+/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
#define WLAN_REASON_DEAUTH_LEAVING 3
@@ -186,10 +214,9 @@
#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
-/* IEEE 802.11h */
#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
-/* IEEE 802.11i */
+#define WLAN_REASON_BSS_TRANSITION_DISASSOC 12
#define WLAN_REASON_INVALID_IE 13
#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
@@ -204,9 +231,26 @@
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
-/* IEEE 802.11e */
+#define WLAN_REASON_SSP_REQUESTED_DISASSOC 27
+#define WLAN_REASON_NO_SSP_ROAMING_AGREEMENT 28
+#define WLAN_REASON_BAD_CIPHER_OR_AKM 29
+#define WLAN_REASON_NOT_AUTHORIZED_THIS_LOCATION 30
+#define WLAN_REASON_SERVICE_CHANGE_PRECLUDES_TS 31
+#define WLAN_REASON_UNSPECIFIED_QOS_REASON 32
+#define WLAN_REASON_NOT_ENOUGH_BANDWIDTH 33
#define WLAN_REASON_DISASSOC_LOW_ACK 34
-/* IEEE 802.11s */
+#define WLAN_REASON_EXCEEDED_TXOP 35
+#define WLAN_REASON_STA_LEAVING 36
+#define WLAN_REASON_END_TS_BA_DLS 37
+#define WLAN_REASON_UNKNOWN_TS_BA 38
+#define WLAN_REASON_TIMEOUT 39
+#define WLAN_REASON_PEERKEY_MISMATCH 45
+#define WLAN_REASON_AUTHORIZED_ACCESS_LIMIT_REACHED 46
+#define WLAN_REASON_EXTERNAL_SERVICE_REQUIREMENTS 47
+#define WLAN_REASON_INVALID_FT_ACTION_FRAME_COUNT 48
+#define WLAN_REASON_INVALID_PMKID 49
+#define WLAN_REASON_INVALID_MDE 50
+#define WLAN_REASON_INVALID_FTE 51
#define WLAN_REASON_MESH_PEERING_CANCELLED 52
#define WLAN_REASON_MESH_MAX_PEERS 53
#define WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION 54
@@ -216,20 +260,29 @@
#define WLAN_REASON_MESH_INVALID_GTK 58
#define WLAN_REASON_MESH_INCONSISTENT_PARAMS 59
#define WLAN_REASON_MESH_INVALID_SECURITY_CAP 60
+#define WLAN_REASON_MESH_PATH_ERROR_NO_PROXY_INFO 61
+#define WLAN_REASON_MESH_PATH_ERROR_NO_FORWARDING_INFO 62
+#define WLAN_REASON_MESH_PATH_ERROR_DEST_UNREACHABLE 63
+#define WLAN_REASON_MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS 64
+#define WLAN_REASON_MESH_CHANNEL_SWITCH_REGULATORY_REQ 65
+#define WLAN_REASON_MESH_CHANNEL_SWITCH_UNSPECIFIED 66
-/* Information Element IDs */
+/* Information Element IDs (IEEE Std 802.11-2016, 9.4.2.1, Table 9-77) */
#define WLAN_EID_SSID 0
#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
#define WLAN_EID_DS_PARAMS 3
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_REQUEST 10
#define WLAN_EID_BSS_LOAD 11
+#define WLAN_EID_EDCA_PARAM_SET 12
+#define WLAN_EID_TSPEC 13
+#define WLAN_EID_TCLAS 14
+#define WLAN_EID_SCHEDULE 15
#define WLAN_EID_CHALLENGE 16
-/* EIDs defined by IEEE 802.11h - START */
#define WLAN_EID_PWR_CONSTRAINT 32
#define WLAN_EID_PWR_CAPABILITY 33
#define WLAN_EID_TPC_REQUEST 34
@@ -238,50 +291,139 @@
#define WLAN_EID_CHANNEL_SWITCH 37
#define WLAN_EID_MEASURE_REQUEST 38
#define WLAN_EID_MEASURE_REPORT 39
-#define WLAN_EID_QUITE 40
+#define WLAN_EID_QUIET 40
#define WLAN_EID_IBSS_DFS 41
-/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_TS_DELAY 43
+#define WLAN_EID_TCLAS_PROCESSING 44
#define WLAN_EID_HT_CAP 45
#define WLAN_EID_QOS 46
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_AP_CHANNEL_REPORT 51
#define WLAN_EID_NEIGHBOR_REPORT 52
+#define WLAN_EID_RCPI 53
#define WLAN_EID_MOBILITY_DOMAIN 54
#define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_DSE_REGISTERED_LOCATION 58
#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
#define WLAN_EID_EXT_CHANSWITCH_ANN 60
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
-#define WLAN_EID_WAPI 68
+#define WLAN_EID_BSS_AVERAGE_ACCESS_DELAY 63
+#define WLAN_EID_ANTENNA 64
+#define WLAN_EID_RSNI 65
+#define WLAN_EID_MEASUREMENT_PILOT_TRANSMISSION 66
+#define WLAN_EID_BSS_AVAILABLE_ADM_CAPA 67
+#define WLAN_EID_BSS_AC_ACCESS_DELAY 68 /* note: also used by WAPI */
#define WLAN_EID_TIME_ADVERTISEMENT 69
#define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
+#define WLAN_EID_MULTIPLE_BSSID 71
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_RIC_DESCRIPTOR 75
#define WLAN_EID_MMIE 76
+#define WLAN_EID_EVENT_REQUEST 78
+#define WLAN_EID_EVENT_REPORT 79
+#define WLAN_EID_DIAGNOSTIC_REQUEST 80
+#define WLAN_EID_DIAGNOSTIC_REPORT 81
+#define WLAN_EID_LOCATION_PARAMETERS 82
+#define WLAN_EID_NONTRANSMITTED_BSSID_CAPA 83
#define WLAN_EID_SSID_LIST 84
+#define WLAN_EID_MLTIPLE_BSSID_INDEX 85
+#define WLAN_EID_FMS_DESCRIPTOR 86
+#define WLAN_EID_FMS_REQUEST 87
+#define WLAN_EID_FMS_RESPONSE 88
+#define WLAN_EID_QOS_TRAFFIC_CAPABILITY 89
#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
#define WLAN_EID_TFS_REQ 91
#define WLAN_EID_TFS_RESP 92
#define WLAN_EID_WNMSLEEP 93
+#define WLAN_EID_TIM_BROADCAST_REQUEST 94
+#define WLAN_EID_TIM_BROADCAST_RESPONSE 95
+#define WLAN_EID_COLLOCATED_INTERFERENCE_REPORT 96
+#define WLAN_EID_CHANNEL_USAGE 97
#define WLAN_EID_TIME_ZONE 98
+#define WLAN_EID_DMS_REQUEST 99
+#define WLAN_EID_DMS_RESPONSE 100
#define WLAN_EID_LINK_ID 101
+#define WLAN_EID_WAKEUP_SCHEDULE 102
+#define WLAN_EID_CHANNEL_SWITCH_TIMING 104
+#define WLAN_EID_PTI_CONTROL 105
+#define WLAN_EID_TPU_BUFFER_STATUS 106
#define WLAN_EID_INTERWORKING 107
#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_EXPEDITED_BANDWIDTH_REQ 109
#define WLAN_EID_QOS_MAP_SET 110
#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_EMERGENCY_ALERT_ID 112
#define WLAN_EID_MESH_CONFIG 113
#define WLAN_EID_MESH_ID 114
+#define WLAN_EID_MESH_LINK_METRIC_REPORT 115
+#define WLAN_EID_CONGESTION_NOTIFICATION 116
#define WLAN_EID_PEER_MGMT 117
+#define WLAN_EID_MESH_CHANNEL_SWITCH_PARAMETERS 118
+#define WLAN_EID_MESH_AWAKE_WINDOW 119
+#define WLAN_EID_BEACON_TIMING 120
+#define WLAN_EID_MCCAOP_SETUP_REQUEST 121
+#define WLAN_EID_MCCAOP_SETUP_REPLY 122
+#define WLAN_EID_MCCAOP_ADVERTISEMENT 123
+#define WLAN_EID_MCCAOP_TEARDOWN 124
+#define WLAN_EID_GANN 125
+#define WLAN_EID_RANN 126
#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_PREQ 130
+#define WLAN_EID_PREP 131
+#define WLAN_EID_PERR 132
+#define WLAN_EID_PXU 137
+#define WLAN_EID_PXUC 138
#define WLAN_EID_AMPE 139
#define WLAN_EID_MIC 140
+#define WLAN_EID_DESTINATION_URI 141
+#define WLAN_EID_U_APSD_COEX 142
+#define WLAN_EID_DMG_WAKEUP_SCHEDULE 143
+#define WLAN_EID_EXTENDED_SCHEDULE 144
+#define WLAN_EID_STA_AVAILABILITY 145
+#define WLAN_EID_DMG_TSPEC 146
+#define WLAN_EID_NEXT_DMG_ATI 147
+#define WLAN_EID_DMG_CAPABILITIES 148
+#define WLAN_EID_DMG_OPERATION 151
+#define WLAN_EID_DMG_BSS_PARAMETER_CHANGE 152
+#define WLAN_EID_DMG_BEAM_REFINEMENT 153
+#define WLAN_EID_CHANNEL_MEASUREMENT_FEEDBACK 154
#define WLAN_EID_CCKM 156
+#define WLAN_EID_AWAKE_WINDOW 157
#define WLAN_EID_MULTI_BAND 158
+#define WLAN_EID_ADDBA_EXTENSION 159
+#define WLAN_EID_NEXTPCP_LIST 160
+#define WLAN_EID_PCP_HANDOVER 161
+#define WLAN_EID_DMG_LINK_MARGIN 162
+#define WLAN_EID_SWITCHING_STREAM 163
#define WLAN_EID_SESSION_TRANSITION 164
+#define WLAN_EID_DYNAMIC_TONE_PAIRING_REPORT 165
+#define WLAN_EID_CLUSTER_REPORT 166
+#define WLAN_EID_REPLAY_CAPABILITIES 167
+#define WLAN_EID_RELAY_TRANSFER_PARAM_SET 168
+#define WLAN_EID_BEAMLINK_MAINTENANCE 169
+#define WLAN_EID_MULTIPLE_MAC_SUBLAYERS 170
+#define WLAN_EID_U_PID 171
+#define WLAN_EID_DMG_LINK_ADAPTATION_ACK 172
+#define WLAN_EID_MCCAOP_ADVERTISEMENT_OVERVIEW 174
+#define WLAN_EID_QUIET_PERIOD_REQUEST 175
+#define WLAN_EID_QUIET_PERIOD_RESPONSE 177
+#define WLAN_EID_QMF_POLICY 181
+#define WLAN_EID_ECAPC_POLICY 182
+#define WLAN_EID_CLUSTER_TIME_OFFSET 183
+#define WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY 184
+#define WLAN_EID_SCS_DESCRIPTOR 185
+#define WLAN_EID_QLOAD_REPORT 186
+#define WLAN_EID_HCCA_TXOP_UPDATE_COUNT 187
+#define WLAN_EID_HIGHER_LAYER_STREAM_ID 188
+#define WLAN_EID_GCR_GROUP_ADDRESS 189
+#define WLAN_EID_ANTENNA_SECTOR_ID_PATTERN 190
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
@@ -291,10 +433,38 @@
#define WLAN_EID_VHT_AID 197
#define WLAN_EID_VHT_QUIET_CHANNEL 198
#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
+#define WLAN_EID_UPSIM 200
+#define WLAN_EID_REDUCED_NEIGHBOR_REPORT 201
+#define WLAN_EID_TVHT_OPERATION 202
+#define WLAN_EID_DEVICE_LOCATION 204
+#define WLAN_EID_WHITE_SPACE_MAP 205
+#define WLAN_EID_FTM_PARAMETERS 206
#define WLAN_EID_VENDOR_SPECIFIC 221
+#define WLAN_EID_CAG_NUMBER 237
+#define WLAN_EID_AP_CSN 239
+#define WLAN_EID_FILS_INDICATION 240
+#define WLAN_EID_DILS 241
+#define WLAN_EID_FRAGMENT 242
+#define WLAN_EID_EXTENSION 255
+
+/* Element ID Extension (EID 255) values */
+#define WLAN_EID_EXT_ASSOC_DELAY_INFO 1
+#define WLAN_EID_EXT_FILS_REQ_PARAMS 2
+#define WLAN_EID_EXT_FILS_KEY_CONFIRM 3
+#define WLAN_EID_EXT_FILS_SESSION 4
+#define WLAN_EID_EXT_FILS_HLP_CONTAINER 5
+#define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6
+#define WLAN_EID_EXT_KEY_DELIVERY 7
+#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8
+#define WLAN_EID_EXT_FTM_SYNC_INFO 9
+#define WLAN_EID_EXT_EXTENDED_REQUEST 10
+#define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11
+#define WLAN_EID_EXT_FILS_PUBLIC_KEY 12
+#define WLAN_EID_EXT_FILS_NONCE 13
+#define WLAN_EID_EXT_FUTURE_CHANNEL_GUIDANCE 14
-/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
+/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
#define WLAN_ACTION_QOS 1
#define WLAN_ACTION_DLS 2
@@ -308,21 +478,59 @@
#define WLAN_ACTION_WNM 10
#define WLAN_ACTION_UNPROTECTED_WNM 11
#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_MESH 13
+#define WLAN_ACTION_MULTIHOP 14
#define WLAN_ACTION_SELF_PROTECTED 15
+#define WLAN_ACTION_DMG 16
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_FST 18
+#define WLAN_ACTION_ROBUST_AV_STREAMING 19
+#define WLAN_ACTION_UNPROTECTED_DMG 20
+#define WLAN_ACTION_VHT 21
+#define WLAN_ACTION_FILS 26
+#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
#define WLAN_ACTION_VENDOR_SPECIFIC 127
+/* Note: 128-255 used to report errors by setting category | 0x80 */
-/* Public action codes */
+/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */
#define WLAN_PA_20_40_BSS_COEX 0
+#define WLAN_PA_DSE_ENABLEMENT 1
+#define WLAN_PA_DSE_DEENABLEMENT 2
+#define WLAN_PA_DSE_REG_LOCATION_ANNOUNCE 3
+#define WLAN_PA_EXT_CHANNEL_SWITCH_ANNOUNCE 4
+#define WLAN_PA_DSE_MEASUREMENT_REQ 5
+#define WLAN_PA_DSE_MEASUREMENT_RESP 6
+#define WLAN_PA_MEASUREMENT_PILOT 7
+#define WLAN_PA_DSE_POWER_CONSTRAINT 8
#define WLAN_PA_VENDOR_SPECIFIC 9
#define WLAN_PA_GAS_INITIAL_REQ 10
#define WLAN_PA_GAS_INITIAL_RESP 11
#define WLAN_PA_GAS_COMEBACK_REQ 12
#define WLAN_PA_GAS_COMEBACK_RESP 13
#define WLAN_TDLS_DISCOVERY_RESPONSE 14
+#define WLAN_PA_LOCATION_TRACK_NOTIFICATION 15
+#define WLAN_PA_QAB_REQUEST_FRAME 16
+#define WLAN_PA_QAB_RESPONSE_FRAME 17
+#define WLAN_PA_QMF_POLICY 18
+#define WLAN_PA_QMF_POLICY_CHANGE 19
+#define WLAN_PA_QLOAD_REQUEST 20
+#define WLAN_PA_QLOAD_REPORT 21
+#define WLAN_PA_HCCA_TXOP_ADVERTISEMENT 22
+#define WLAN_PA_HCCA_TXOP_RESPONSE 23
+#define WLAN_PA_PUBLIC_KEY 24
+#define WLAN_PA_CHANNEL_AVAILABILITY_QUERY 25
+#define WLAN_PA_CHANNEL_SCHEDULE_MANAGEMENT 26
+#define WLAN_PA_CONTACT_VERIFICATION_SIGNAL 27
+#define WLAN_PA_GDD_ENABLEMENT_REQ 28
+#define WLAN_PA_GDD_ENABLEMENT_RESP 29
+#define WLAN_PA_NETWORK_CHANNEL_CONTROL 30
+#define WLAN_PA_WHITE_SPACE_MAP_ANNOUNCEMENT 31
+#define WLAN_PA_FTM_REQUEST 32
+#define WLAN_PA_FTM 33
+#define WLAN_PA_FILS_DISCOVERY 34
-/* Protected Dual of Public Action frames */
+/* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11,
+ * Table 9-332) */
#define WLAN_PROT_DSE_ENABLEMENT 1
#define WLAN_PROT_DSE_DEENABLEMENT 2
#define WLAN_PROT_EXT_CSA 4
@@ -334,6 +542,21 @@
#define WLAN_PROT_GAS_INITIAL_RESP 11
#define WLAN_PROT_GAS_COMEBACK_REQ 12
#define WLAN_PROT_GAS_COMEBACK_RESP 13
+#define WLAN_PROT_QAB_REQUEST_FRAME 16
+#define WLAN_PROT_QAB_RESPONSE_FRAME 17
+#define WLAN_PROT_QMF_POLICY 18
+#define WLAN_PROT_QMF_POLICY_CHANGE 19
+#define WLAN_PROT_QLOAD_REQUEST 20
+#define WLAN_PROT_QLOAD_REPORT 21
+#define WLAN_PROT_HCCA_TXOP_ADVERTISEMENT 22
+#define WLAN_PROT_HCCA_TXOP_RESPONSE 23
+#define WLAN_PROT_CHANNEL_AVAILABILITY_QUERY 25
+#define WLAN_PROT_CHANNEL_SCHEDULE_MANAGEMENT 26
+#define WLAN_PROT_CONTACT_VERIFICATION_SIGNAL 27
+#define WLAN_PROT_GDD_ENABLEMENT_REQ 28
+#define WLAN_PROT_GDD_ENABLEMENT_RESP 29
+#define WLAN_PROT_NETWORK_CHANNEL_CONTROL 30
+#define WLAN_PROT_WHITE_SPACE_MAP_ANNOUNCEMENT 31
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
#define WLAN_SA_QUERY_REQUEST 0
@@ -362,10 +585,24 @@
#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
-/* Radio Measurement capabilities (from RRM Capabilities IE) */
+/* Radio Measurement capabilities (from RM Enabled Capabilities element)
+ * IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
/* byte 1 (out of 5) */
#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+#define WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE BIT(4)
+#define WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE BIT(5)
+#define WLAN_RRM_CAPS_BEACON_REPORT_TABLE BIT(6)
+/* byte 2 (out of 5) */
+#define WLAN_RRM_CAPS_LCI_MEASUREMENT BIT(4)
+/* byte 5 (out of 5) */
+#define WLAN_RRM_CAPS_FTM_RANGE_REPORT BIT(2)
+
+/*
+ * IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 (Fine Timing Measurement Range
+ * request) - Minimum AP count
+ */
+#define WLAN_RRM_RANGE_REQ_MAX_MIN_AP 15
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
@@ -388,16 +625,18 @@
#define INTERWORKING_ANT_TEST 6
#define INTERWORKING_ANT_WILDCARD 15
-/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
+/* Advertisement Protocol ID definitions (IEEE Std 802.11-2016, Table 9-215) */
enum adv_proto_id {
ACCESS_NETWORK_QUERY_PROTOCOL = 0,
MIH_INFO_SERVICE = 1,
MIH_CMD_AND_EVENT_DISCOVERY = 2,
EMERGENCY_ALERT_SYSTEM = 3,
+ REGISTERED_LOCATION_QUERY_PROTO = 4,
ADV_PROTO_VENDOR_SPECIFIC = 221
};
-/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11-2016,
+ * Table 9-271; P802.11ai) */
enum anqp_info_id {
ANQP_QUERY_LIST = 256,
ANQP_CAPABILITY_LIST = 257,
@@ -416,9 +655,14 @@
ANQP_TDLS_CAPABILITY = 270,
ANQP_EMERGENCY_NAI = 271,
ANQP_NEIGHBOR_REPORT = 272,
+ ANQP_QUERY_AP_LIST = 273,
+ ANQP_AP_LIST_RESPONSE = 274,
+ ANQP_FILS_REALM_INFO = 275,
+ ANQP_CAG = 276,
ANQP_VENUE_URL = 277,
ANQP_ADVICE_OF_CHARGE = 278,
ANQP_LOCAL_CONTENT = 279,
+ ANQP_NETWORK_AUTH_TYPE_TIMESTAMP = 280,
ANQP_VENDOR_SPECIFIC = 56797
};
@@ -453,6 +697,53 @@
NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
};
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
+ * measurement requests
+ */
+enum measure_type {
+ MEASURE_TYPE_BASIC = 0,
+ MEASURE_TYPE_CCA = 1,
+ MEASURE_TYPE_RPI_HIST = 2,
+ MEASURE_TYPE_CHANNEL_LOAD = 3,
+ MEASURE_TYPE_NOISE_HIST = 4,
+ MEASURE_TYPE_BEACON = 5,
+ MEASURE_TYPE_FRAME = 6,
+ MEASURE_TYPE_STA_STATISTICS = 7,
+ MEASURE_TYPE_LCI = 8,
+ MEASURE_TYPE_TRANSMIT_STREAM = 9,
+ MEASURE_TYPE_MULTICAST_DIAG = 10,
+ MEASURE_TYPE_LOCATION_CIVIC = 11,
+ MEASURE_TYPE_LOCATION_ID = 12,
+ MEASURE_TYPE_DIRECTIONAL_CHAN_QUALITY = 13,
+ MEASURE_TYPE_DIRECTIONAL_MEASURE = 14,
+ MEASURE_TYPE_DIRECTIONAL_STATS = 15,
+ MEASURE_TYPE_FTM_RANGE = 16,
+ MEASURE_TYPE_MEASURE_PAUSE = 255,
+};
+
+/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */
+enum location_subject {
+ LOCATION_SUBJECT_LOCAL = 0,
+ LOCATION_SUBJECT_REMOTE = 1,
+ LOCATION_SUBJECT_3RD_PARTY = 2,
+};
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request
+ */
+enum lci_req_subelem {
+ LCI_REQ_SUBELEM_AZIMUTH_REQ = 1,
+ LCI_REQ_SUBELEM_ORIGINATOR_MAC_ADDR = 2,
+ LCI_REQ_SUBELEM_TARGET_MAC_ADDR = 3,
+ LCI_REQ_SUBELEM_MAX_AGE = 4,
+};
+
+#define FILS_NONCE_LEN 16
+#define FILS_SESSION_LEN 8
+#define FILS_CACHE_ID_LEN 2
+#define FILS_MAX_KEY_AUTH_LEN 48
+
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
@@ -633,12 +924,19 @@
u8 action;
u8 variable[];
} STRUCT_PACKED fst_action;
+ struct {
+ u8 action;
+ u8 dialog_token;
+ u8 variable[];
+ } STRUCT_PACKED rrm;
} u;
} STRUCT_PACKED action;
} u;
} STRUCT_PACKED;
+#define IEEE80211_MAX_MMPDU_SIZE 2304
+
/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
#define IEEE80211_HT_MCS_MASK_LEN 10
@@ -698,9 +996,14 @@
u8 selected_pairwise_suite[4];
u8 local_nonce[32];
u8 peer_nonce[32];
- u8 mgtk[16];
- u8 key_rsc[8];
- u8 key_expiration[4];
+ /* Followed by
+ * Key Replay Counter[8] (optional)
+ * (only in Mesh Group Key Inform/Acknowledge frames)
+ * GTKdata[variable] (optional)
+ * (MGTK[variable] || Key RSC[8] || GTKExpirationTime[4])
+ * IGTKdata[variable] (optional)
+ * (Key ID[2], IPN[6], IGTK[variable] in IGTK KDE format)
+ */
} STRUCT_PACKED;
#ifdef _MSC_VER
@@ -1116,6 +1419,10 @@
WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3,
};
+/* MBO v0.0_r25, 4.3: MBO ANQP-elements */
+#define MBO_ANQP_OUI_TYPE 0x12
+#define MBO_ANQP_SUBTYPE_CELL_CONN_PREF 1
+
/* Wi-Fi Direct (P2P) */
#define P2P_OUI_TYPE 9
@@ -1273,6 +1580,14 @@
#define MESH_PATH_PROTOCOL_VENDOR 255
#define MESH_PATH_METRIC_AIRTIME 1
#define MESH_PATH_METRIC_VENDOR 255
+/* IEEE 802.11s - Mesh Capability */
+#define MESH_CAP_ACCEPT_ADDITIONAL_PEER BIT(0)
+#define MESH_CAP_MCCA_SUPPORTED BIT(1)
+#define MESH_CAP_MCCA_ENABLED BIT(2)
+#define MESH_CAP_FORWARDING BIT(3)
+#define MESH_CAP_MBCA_ENABLED BIT(4)
+#define MESH_CAP_TBTT_ADJUSTING BIT(5)
+#define MESH_CAP_MESH_PS_LEVEL BIT(6)
enum plink_action_field {
PLINK_OPEN = 1,
@@ -1287,41 +1602,6 @@
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
-/* cipher suite selectors */
-#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
-#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
-#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
-/* reserved: 0x000FAC03 */
-#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
-#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
-#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
-#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07
-#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
-#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09
-#define WLAN_CIPHER_SUITE_CCMP_256 0x000FAC0A
-#define WLAN_CIPHER_SUITE_BIP_GMAC_128 0x000FAC0B
-#define WLAN_CIPHER_SUITE_BIP_GMAC_256 0x000FAC0C
-#define WLAN_CIPHER_SUITE_BIP_CMAC_256 0x000FAC0D
-
-#define WLAN_CIPHER_SUITE_SMS4 0x00147201
-
-#define WLAN_CIPHER_SUITE_CKIP 0x00409600
-#define WLAN_CIPHER_SUITE_CKIP_CMIC 0x00409601
-#define WLAN_CIPHER_SUITE_CMIC 0x00409602
-#define WLAN_CIPHER_SUITE_KRK 0x004096FF /* for nl80211 use only */
-
-/* AKM suite selectors */
-#define WLAN_AKM_SUITE_8021X 0x000FAC01
-#define WLAN_AKM_SUITE_PSK 0x000FAC02
-#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03
-#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04
-#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
-#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
-#define WLAN_AKM_SUITE_8021X_SUITE_B 0x000FAC11
-#define WLAN_AKM_SUITE_8021X_SUITE_B_192 0x000FAC12
-#define WLAN_AKM_SUITE_CCKM 0x00409600
-#define WLAN_AKM_SUITE_OSEN 0x506f9a01
-
/* IEEE 802.11v - WNM Action field values */
enum wnm_action {
@@ -1375,14 +1655,25 @@
WNM_BSS_TM_REJECT_LEAVING_ESS = 8
};
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for
+ * neighbor report
+ */
#define WNM_NEIGHBOR_TSF 1
#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2
#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3
#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4
#define WNM_NEIGHBOR_BEARING 5
+#define WNM_NEIGHBOR_WIDE_BW_CHAN 6
+#define WNM_NEIGHBOR_MEASUREMENT_REPORT 39
+#define WNM_NEIGHBOR_HT_CAPAB 45
+#define WNM_NEIGHBOR_HT_OPER 61
+#define WNM_NEIGHBOR_SEC_CHAN_OFFSET 62
#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66
#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70
#define WNM_NEIGHBOR_MULTIPLE_BSSID 71
+#define WNM_NEIGHBOR_VHT_CAPAB 191
+#define WNM_NEIGHBOR_VHT_OPER 192
/* QoS action */
enum qos_action {
@@ -1451,6 +1742,8 @@
u8 link_margin;
} STRUCT_PACKED;
+#define RRM_CAPABILITIES_IE_LEN 5
+
/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
struct rrm_link_measurement_request {
u8 dialog_token;
@@ -1470,7 +1763,101 @@
u8 variable[0];
} STRUCT_PACKED;
-#define SSID_MAX_LEN 32
+/* IEEE Std 802.11-2016, 9.4.2.21 - Measurement Request element */
+struct rrm_measurement_request_element {
+ u8 eid; /* Element ID */
+ u8 len; /* Length */
+ u8 token; /* Measurement Token */
+ u8 mode; /* Measurement Request Mode */
+ u8 type; /* Measurement Type */
+ u8 variable[0]; /* Measurement Request */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-148 - Measurement Request Mode field */
+#define MEASUREMENT_REQUEST_MODE_PARALLEL BIT(0)
+#define MEASUREMENT_REQUEST_MODE_ENABLE BIT(1)
+#define MEASUREMENT_REQUEST_MODE_REQUEST BIT(2)
+#define MEASUREMENT_REQUEST_MODE_REPORT BIT(3)
+#define MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY BIT(4)
+
+/* IEEE Std 802.11-2016, 9.4.2.21.7 - Beacon request */
+struct rrm_measurement_beacon_request {
+ u8 oper_class; /* Operating Class */
+ u8 channel; /* Channel Number */
+ le16 rand_interval; /* Randomization Interval (in TUs) */
+ le16 duration; /* Measurement Duration (in TUs) */
+ u8 mode; /* Measurement Mode */
+ u8 bssid[ETH_ALEN]; /* BSSID */
+ u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/*
+ * IEEE Std 802.11-2016, Table 9-87 - Measurement Mode definitions for Beacon
+ * request
+ */
+enum beacon_report_mode {
+ BEACON_REPORT_MODE_PASSIVE = 0,
+ BEACON_REPORT_MODE_ACTIVE = 1,
+ BEACON_REPORT_MODE_TABLE = 2,
+};
+
+/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */
+#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_VENDOR 221
+
+/*
+ * IEEE Std 802.11-2016, Table 9-90 - Reporting Detail values
+ */
+enum beacon_report_detail {
+ /* No fixed-length fields or elements */
+ BEACON_REPORT_DETAIL_NONE = 0,
+ /* All fixed-length fields and any requested elements in the Request
+ * element if present */
+ BEACON_REPORT_DETAIL_REQUESTED_ONLY = 1,
+ /* All fixed-length fields and elements (default, used when Reporting
+ * Detail subelement is not included in a Beacon request) */
+ BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS = 2,
+};
+
+/* IEEE Std 802.11-2016, 9.4.2.22 - Measurement Report element */
+struct rrm_measurement_report_element {
+ u8 eid; /* Element ID */
+ u8 len; /* Length */
+ u8 token; /* Measurement Token */
+ u8 mode; /* Measurement Report Mode */
+ u8 type; /* Measurement Type */
+ u8 variable[0]; /* Measurement Report */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Figure 9-192 - Measurement Report Mode field */
+#define MEASUREMENT_REPORT_MODE_ACCEPT 0
+#define MEASUREMENT_REPORT_MODE_REJECT_LATE BIT(0)
+#define MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE BIT(1)
+#define MEASUREMENT_REPORT_MODE_REJECT_REFUSED BIT(2)
+
+/* IEEE Std 802.11-2016, 9.4.2.22.7 - Beacon report */
+struct rrm_measurement_beacon_report {
+ u8 op_class; /* Operating Class */
+ u8 channel; /* Channel Number */
+ le64 start_time; /* Actual Measurement Start Time
+ * (in TSF of the BSS requesting the measurement) */
+ le16 duration; /* in TUs */
+ u8 report_info; /* Reported Frame Information */
+ u8 rcpi; /* RCPI */
+ u8 rsni; /* RSNI */
+ u8 bssid[ETH_ALEN]; /* BSSID */
+ u8 antenna_id; /* Antenna ID */
+ le32 parent_tsf; /* Parent TSF */
+ u8 variable[0]; /* Optional Subelements */
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */
+#define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY 1
+#define WLAN_BEACON_REPORT_SUBELEM_VENDOR 221
/* IEEE Std 802.11ad-2012 - Multi-band element */
struct multi_band_ie {
@@ -1542,7 +1929,7 @@
PHY_TYPE_VHT = 9,
};
-/* IEEE Std 802.11-2012, 8.4.2.39 - Neighbor Report element */
+/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
/* BSSID Information Field */
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
@@ -1557,5 +1944,69 @@
#define NEI_REP_BSSID_INFO_IMM_BA BIT(9)
#define NEI_REP_BSSID_INFO_MOBILITY_DOMAIN BIT(10)
#define NEI_REP_BSSID_INFO_HT BIT(11)
+#define NEI_REP_BSSID_INFO_VHT BIT(12)
+#define NEI_REP_BSSID_INFO_FTM BIT(13)
+
+/*
+ * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
+ * subfields.
+ * Note: These definitions are not the same as other VHT_CHANWIDTH_*.
+ */
+enum nr_chan_width {
+ NR_CHAN_WIDTH_20 = 0,
+ NR_CHAN_WIDTH_40 = 1,
+ NR_CHAN_WIDTH_80 = 2,
+ NR_CHAN_WIDTH_160 = 3,
+ NR_CHAN_WIDTH_80P80 = 4,
+};
+
+struct ieee80211_he_capabilities {
+ u8 he_mac_capab_info[5];
+ u8 he_phy_capab_info[9];
+ u16 he_txrx_mcs_support;
+ /* possibly followed by Tx Rx MCS NSS descriptor */
+ u8 variable[];
+ /* PPE Thresholds (optional) */
+} STRUCT_PACKED;
+
+struct ieee80211_he_operation {
+ u32 he_oper_params;
+ u8 he_mcs_nss_set[3];
+ u8 vht_op_info_chwidth;
+ u8 vht_op_info_chan_center_freq_seg0_idx;
+ u8 vht_op_info_chan_center_freq_seg1_idx;
+} STRUCT_PACKED;
+
+/* HE Capabilities Information defines */
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX 3
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB ((u8) BIT(7))
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX 4
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB ((u8) BIT(0))
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX 4
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
+
+/* HE Operation defines */
+#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) | \
+ 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))
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/ieee802_1x_defs.h b/src/common/ieee802_1x_defs.h
index cc88caa..280c439 100644
--- a/src/common/ieee802_1x_defs.h
+++ b/src/common/ieee802_1x_defs.h
@@ -10,7 +10,7 @@
#define IEEE802_1X_DEFS_H
#define CS_ID_LEN 8
-#define CS_ID_GCM_AES_128 {0x00, 0x80, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01}
+#define CS_ID_GCM_AES_128 0x0080020001000001ULL
#define CS_NAME_GCM_AES_128 "GCM-AES-128"
enum macsec_policy {
@@ -25,6 +25,12 @@
* Disabled MACsec - do not secure sessions.
*/
DO_NOT_SECURE,
+
+ /**
+ * Should secure sessions, and try to use encryption.
+ * Like @SHOULD_SECURE, this follows the key server's decision.
+ */
+ SHOULD_ENCRYPT,
};
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index 8dff303..0f47518 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -9,6 +9,7 @@
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
+#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
enum privsep_cmd {
@@ -29,8 +30,17 @@
PRIVSEP_CMD_AUTHENTICATE,
};
-struct privsep_cmd_authenticate
-{
+#define PRIVSEP_MAX_SCAN_FREQS 50
+
+struct privsep_cmd_scan {
+ unsigned int num_ssids;
+ u8 ssids[WPAS_MAX_SCAN_SSIDS][32];
+ u8 ssid_lens[WPAS_MAX_SCAN_SSIDS];
+ unsigned int num_freqs;
+ u16 freqs[PRIVSEP_MAX_SCAN_FREQS];
+};
+
+struct privsep_cmd_authenticate {
int freq;
u8 bssid[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
@@ -42,13 +52,12 @@
int wep_tx_keyidx;
int local_state_change;
int p2p;
- size_t sae_data_len;
+ size_t auth_data_len;
/* followed by ie_len bytes of ie */
- /* followed by sae_data_len bytes of sae_data */
+ /* followed by auth_data_len bytes of auth_data */
};
-struct privsep_cmd_associate
-{
+struct privsep_cmd_associate {
u8 bssid[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
@@ -64,8 +73,7 @@
/* followed by wpa_ie_len bytes of wpa_ie */
};
-struct privsep_cmd_set_key
-{
+struct privsep_cmd_set_key {
int alg;
u8 addr[ETH_ALEN];
int key_idx;
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 87bbc05..934f09d 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,6 +1,6 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
- * Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -89,6 +89,205 @@
* @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver,
* which supports DFS offloading, to indicate a radar pattern has been
* detected. The channel is now unusable.
+ *
+ * @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
+ * information elements to the device driver and firmware.
+ * Uses the attributes defines in
+ * enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: Command/event used to
+ * indicate stop request/response of the P2P Listen offload function in
+ * device. As an event, it indicates either the feature stopped after it
+ * was already running or feature has actually failed to start. Uses the
+ * attributes defines in enum qca_wlan_vendor_attr_p2p_listen_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH: After AP starts
+ * beaconing, this sub command provides the driver, the frequencies on the
+ * 5 GHz band to check for any radar activity. Driver selects one channel
+ * from this priority list provided through
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST and starts
+ * to check for radar activity on it. If no radar activity is detected
+ * during the channel availability check period, driver internally switches
+ * to the selected frequency of operation. If the frequency is zero, driver
+ * internally selects a channel. The status of this conditional switch is
+ * indicated through an event using the same sub command through
+ * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are
+ * listed in qca_wlan_vendor_attr_sap_conditional_chan_switch.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND: Set GPIO pins. This uses the
+ * attributes defined in enum qca_wlan_gpio_attr.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY: Fetch hardware capabilities.
+ * This uses @QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY to indicate which
+ * capabilities are to be fetched and other
+ * enum qca_wlan_vendor_attr_get_hw_capability attributes to return the
+ * requested capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT: Link layer statistics extension.
+ * enum qca_wlan_vendor_attr_ll_stats_ext attributes are used with this
+ * command and event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA: Get capabilities for
+ * indoor location features. Capabilities are reported in
+ * QCA_WLAN_VENDOR_ATTR_LOC_CAPA.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION: Start an FTM
+ * (fine timing measurement) session with one or more peers.
+ * Specify Session cookie in QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE and
+ * peer information in QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS.
+ * On success, 0 or more QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT
+ * events will be reported, followed by
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE event to indicate
+ * end of session.
+ * Refer to IEEE P802.11-REVmc/D7.0, 11.24.6
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION: Abort a running session.
+ * A QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE will be reported with
+ * status code indicating session was aborted.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT: Event with measurement
+ * results for one peer. Results are reported in
+ * QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE: Event triggered when
+ * FTM session is finished, either successfully or aborted by
+ * request.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER: Configure FTM responder
+ * mode. QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE specifies whether
+ * to enable or disable the responder. LCI/LCR reports can be
+ * configured with QCA_WLAN_VENDOR_ATTR_FTM_LCI and
+ * QCA_WLAN_VENDOR_ATTR_FTM_LCR. Can be called multiple
+ * times to update the LCI/LCR reports.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS: Perform a standalone AOA (angle of
+ * arrival) measurement with a single peer. Specify peer MAC address in
+ * QCA_WLAN_VENDOR_ATTR_MAC_ADDR and optionally frequency (MHz) in
+ * QCA_WLAN_VENDOR_ATTR_FREQ (if not specified, locate peer in kernel
+ * scan results cache and use the frequency from there).
+ * Also specify measurement type in QCA_WLAN_VENDOR_ATTR_AOA_TYPE.
+ * Measurement result is reported in
+ * QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT event.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS: Abort an AOA measurement. Specify
+ * peer MAC address in QCA_WLAN_VENDOR_ATTR_MAC_ADDR.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT: Event that reports
+ * the AOA measurement result.
+ * Peer MAC address reported in QCA_WLAN_VENDOR_ATTR_MAC_ADDR.
+ * success/failure status is reported in
+ * QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS.
+ * Measurement data is reported in QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT.
+ * The antenna array(s) used in the measurement are reported in
+ * QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST: Encrypt/decrypt the given
+ * data as per the given parameters.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI: Get antenna RSSI value for a
+ * specific chain.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG: Get low level
+ * configuration for a DMG RF sector. Specify sector index in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX, sector type in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE and RF modules
+ * to return sector information for in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_MODULE_MASK. Returns sector configuration
+ * in QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG. Also return the
+ * exact time where information was captured in
+ * QCA_WLAN_VENDOR_ATTR_TSF.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG: Set low level
+ * configuration for a DMG RF sector. Specify sector index in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX, sector type in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE and sector configuration
+ * for one or more DMG RF modules in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR: Get selected
+ * DMG RF sector for a station. This is the sector that the HW
+ * will use to communicate with the station. Specify the MAC address
+ * of associated station/AP/PCP in QCA_WLAN_VENDOR_ATTR_MAC_ADDR (not
+ * needed for unassociated station). Specify sector type to return in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE. Returns the selected
+ * sector index in QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX.
+ * Also return the exact time where the information was captured
+ * in QCA_WLAN_VENDOR_ATTR_TSF.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR: Set the
+ * selected DMG RF sector for a station. This is the sector that
+ * the HW will use to communicate with the station.
+ * Specify the MAC address of associated station/AP/PCP in
+ * QCA_WLAN_VENDOR_ATTR_MAC_ADDR, the sector type to select in
+ * QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE and the sector index
+ * in QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX.
+ * The selected sector will be locked such that it will not be
+ * modified like it normally does (for example when station
+ * moves around). To unlock the selected sector for a station
+ * pass the special value 0xFFFF in the sector index. To unlock
+ * all connected stations also pass a broadcast MAC address.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS: Configure the TDLS behavior
+ * in the host driver. The different TDLS configurations are defined
+ * by the attributes in enum qca_wlan_vendor_attr_tdls_configuration.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES: Query device IEEE 802.11ax HE
+ * capabilities. The response uses the attributes defined in
+ * enum qca_wlan_vendor_attr_get_he_capabilities.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN: Abort an ongoing vendor scan that was
+ * started with QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN. This command
+ * carries the scan cookie of the corresponding scan request. The scan
+ * cookie is represented by QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS: Set the Specific
+ * Absorption Rate (SAR) power limits. A critical regulation for
+ * FCC compliance, OEMs require methods to set SAR limits on TX
+ * power of WLAN/WWAN. enum qca_vendor_attr_sar_limits
+ * attributes are used with this command.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS: This command/event is used by the
+ * host driver for offloading the implementation of Auto Channel Selection
+ * (ACS) to an external user space entity. This interface is used as the
+ * event from the host driver to the user space entity and also as the
+ * request from the user space entity to the host driver. The event from
+ * the host driver is used by the user space entity as an indication to
+ * start the ACS functionality. The attributes used by this event are
+ * represented by the enum qca_wlan_vendor_attr_external_acs_event.
+ * User space entity uses the same interface to inform the host driver with
+ * selected channels after the ACS operation using the attributes defined
+ * by enum qca_wlan_vendor_attr_external_acs_channels.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE: Vendor event carrying the
+ * requisite information leading to a power save failure. The information
+ * carried as part of this event is represented by the
+ * enum qca_attr_chip_power_save_failure attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET: Start/Stop the NUD statistics
+ * collection. Uses attributes defined in enum qca_attr_nud_stats_set.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET: Get the NUD statistics. These
+ * statistics are represented by the enum qca_attr_nud_stats_get
+ * attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS: Sub-command to fetch
+ * the BSS transition status, whether accept or reject, for a list of
+ * candidate BSSIDs provided by the userspace. This uses the vendor
+ * attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO. The userspace shall specify
+ * the attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and an
+ * array of QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID nested in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO in the request. In the response
+ * the driver shall specify array of
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID and
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS pairs nested in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL: Set the trace level for a
+ * specific QCA module. The trace levels are represented by
+ * enum qca_attr_trace_level attributes.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -98,7 +297,7 @@
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11,
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
- QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
+ QCA_NL80211_VENDOR_SUBCMD_STATS_EXT = 13,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET = 14,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET = 15,
QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR = 16,
@@ -140,7 +339,23 @@
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58,
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59,
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
- /* 61-90 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO = 61,
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START = 62,
+ QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP = 63,
+ QCA_NL80211_VENDOR_SUBCMD_ROAM = 64,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SSID_HOTLIST = 65,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SSID_HOTLIST = 66,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_SSID_FOUND = 67,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_SSID_LOST = 68,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST = 69,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST = 70,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_RESET_PASSPOINT_LIST = 71,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND = 72,
+ QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND = 73,
+ /* Wi-Fi configuration subcommands */
+ QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
+ QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75,
+ /* 76-90 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
@@ -162,9 +377,44 @@
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
/* 110..114 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
- /* 116..118 - reserved for QCA */
+ /* 116..117 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118,
QCA_NL80211_VENDOR_SUBCMD_TSF = 119,
QCA_NL80211_VENDOR_SUBCMD_WISA = 120,
+ /* 121 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122,
+ QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123,
+ QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124,
+ QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND = 125,
+ QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY = 126,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT = 127,
+ /* FTM/indoor location subcommands */
+ QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT = 131,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE = 132,
+ QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER = 133,
+ QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
+ QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
+ QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
+ QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137,
+ QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI = 138,
+ /* DMG low level RF sector operations */
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG = 139,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
+ QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143,
+ QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES = 144,
+ QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN = 145,
+ QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146,
+ QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS = 147,
+ QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE = 148,
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149,
+ QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150,
+ QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS = 151,
+ QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL = 152,
};
@@ -194,6 +444,136 @@
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
/* Unsigned 32-bit value from enum qca_set_band. */
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
+ /* Dummy (NOP) attribute for 64 bit padding */
+ QCA_WLAN_VENDOR_ATTR_PAD = 13,
+ /* Unique FTM session cookie (Unsigned 64 bit). Specified in
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. Reported in
+ * the session in QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT and
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_SESSION_COOKIE = 14,
+ /* Indoor location capabilities, returned by
+ * QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA.
+ * see enum qca_wlan_vendor_attr_loc_capa.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA = 15,
+ /* Array of nested attributes containing information about each peer
+ * in FTM measurement session. See enum qca_wlan_vendor_attr_peer_info
+ * for supported attributes for each peer.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEERS = 16,
+ /* Array of nested attributes containing measurement results for
+ * one or more peers, reported by the
+ * QCA_NL80211_VENDOR_SUBCMD_FTM_MEAS_RESULT event.
+ * See enum qca_wlan_vendor_attr_peer_result for list of supported
+ * attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PEER_RESULTS = 17,
+ /* Flag attribute for enabling or disabling responder functionality. */
+ QCA_WLAN_VENDOR_ATTR_FTM_RESPONDER_ENABLE = 18,
+ /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ * command to specify the LCI report that will be sent by
+ * the responder during a measurement exchange. The format is
+ * defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.10.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_LCI = 19,
+ /* Used in the QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ * command to specify the location civic report that will
+ * be sent by the responder during a measurement exchange.
+ * The format is defined in IEEE P802.11-REVmc/D7.0, 9.4.2.22.13.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_LCR = 20,
+ /* Session/measurement completion status code,
+ * reported in QCA_NL80211_VENDOR_SUBCMD_FTM_SESSION_DONE and
+ * QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
+ * see enum qca_vendor_attr_loc_session_status.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS = 21,
+ /* Initial dialog token used by responder (0 if not specified),
+ * unsigned 8 bit value.
+ */
+ QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN = 22,
+ /* AOA measurement type. Requested in QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS
+ * and optionally in QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION if
+ * AOA measurements are needed as part of an FTM session.
+ * Reported by QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT. See
+ * enum qca_wlan_vendor_attr_aoa_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23,
+ /* A bit mask (unsigned 32 bit value) of antenna arrays used
+ * by indoor location measurements. Refers to the antenna
+ * arrays described by QCA_VENDOR_ATTR_LOC_CAPA_ANTENNA_ARRAYS.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24,
+ /* AOA measurement data. Its contents depends on the AOA measurement
+ * type and antenna array mask:
+ * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: array of U16 values,
+ * phase of the strongest CIR path for each antenna in the measured
+ * array(s).
+ * QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16
+ * values, phase and amplitude of the strongest CIR path for each
+ * antenna in the measured array(s).
+ */
+ QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
+ * to specify the chain number (unsigned 32 bit value) to inquire
+ * the corresponding antenna RSSI value */
+ QCA_WLAN_VENDOR_ATTR_CHAIN_INDEX = 26,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI command
+ * to report the specific antenna RSSI value (unsigned 32 bit value) */
+ QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI = 27,
+ /* Frequency in MHz, various uses. Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_FREQ = 28,
+ /* TSF timer value, unsigned 64 bit value.
+ * May be returned by various commands.
+ */
+ QCA_WLAN_VENDOR_ATTR_TSF = 29,
+ /* DMG RF sector index, unsigned 16 bit number. Valid values are
+ * 0..127 for sector indices or 65535 as special value used to
+ * unlock sector selection in
+ * QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_INDEX = 30,
+ /* DMG RF sector type, unsigned 8 bit value. One of the values
+ * in enum qca_wlan_vendor_attr_dmg_rf_sector_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE = 31,
+ /* Bitmask of DMG RF modules for which information is requested. Each
+ * bit corresponds to an RF module with the same index as the bit
+ * number. Unsigned 32 bit number but only low 8 bits can be set since
+ * all DMG chips currently have up to 8 RF modules.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_MODULE_MASK = 32,
+ /* Array of nested attributes where each entry is DMG RF sector
+ * configuration for a single RF module.
+ * Attributes for each entry are taken from enum
+ * qca_wlan_vendor_attr_dmg_rf_sector_cfg.
+ * Specified in QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG
+ * and returned by QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG.
+ */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG = 33,
+ /* Used in QCA_NL80211_VENDOR_SUBCMD_STATS_EXT command
+ * to report frame aggregation statistics to userspace.
+ */
+ QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM = 34,
+ QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO = 35,
+ /* Unsigned 8-bit value representing MBO transition reason code as
+ * provided by the AP used by subcommand
+ * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS. This is
+ * specified by the userspace in the request to the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON = 36,
+ /* Array of nested attributes, BSSID and status code, used by subcommand
+ * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, where each
+ * entry is taken from enum qca_wlan_vendor_attr_btm_candidate_info.
+ * The userspace space specifies the list/array of candidate BSSIDs in
+ * the order of preference in the request. The driver specifies the
+ * status code, for each BSSID in the list, in the response. The
+ * acceptable candidates are listed in the order preferred by the
+ * driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO = 37,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -221,6 +601,43 @@
QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1
};
+enum qca_wlan_vendor_attr_p2p_listen_offload {
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INVALID = 0,
+ /* A 32-bit unsigned value; the P2P listen frequency (MHz); must be one
+ * of the social channels.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+ /* A 32-bit unsigned value; the P2P listen offload period (ms).
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+ /* A 32-bit unsigned value; the P2P listen interval duration (ms).
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+ /* A 32-bit unsigned value; number of interval times the firmware needs
+ * to run the offloaded P2P listen operation before it stops.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+ /* An array of arbitrary binary data with one or more 8-byte values.
+ * The device types include both primary and secondary device types.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+ /* An array of unsigned 8-bit characters; vendor information elements.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+ /* A 32-bit unsigned value; a control flag to indicate whether listen
+ * results need to be flushed to wpa_supplicant.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG,
+ /* A 8-bit unsigned value; reason code for P2P listen offload stop
+ * event.
+ */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX =
+ QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1
+};
+
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
@@ -259,12 +676,19 @@
* band selection based on channel selection results.
* @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports
* simultaneous off-channel operations.
+ * @QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P
+ * Listen offload; a mechanism where the station's firmware takes care of
+ * responding to incoming Probe Request frames received from other P2P
+ * Devices whilst in Listen state, rather than having the user space
+ * wpa_supplicant do it. Information from received P2P requests are
+ * forwarded from firmware to host whenever the host processor wakes up.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2,
+ QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD = 3,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -338,6 +762,25 @@
};
/**
+ * enum qca_access_policy - Access control policy
+ *
+ * Access control policy is applied on the configured IE
+ * (QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE).
+ * To be set with QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY.
+ *
+ * @QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED: Deny Wi-Fi connections which match
+ * the specific configuration (IE) set, i.e., allow all the
+ * connections which do not match the configuration.
+ * @QCA_ACCESS_POLICY_DENY_UNLESS_LISTED: Accept Wi-Fi connections which match
+ * the specific configuration (IE) set, i.e., deny all the
+ * connections which do not match the configuration.
+ */
+enum qca_access_policy {
+ QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED,
+ QCA_ACCESS_POLICY_DENY_UNLESS_LISTED,
+};
+
+/**
* enum qca_vendor_attr_get_tsf: Vendor attributes for TSF capture
* @QCA_WLAN_VENDOR_ATTR_TSF_CMD: enum qca_tsf_operation (u32)
* @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Unsigned 64 bit TSF timer value
@@ -404,9 +847,53 @@
*
* This vendor element may be included in GO Negotiation Request, P2P
* Invitation Request, and Provision Discovery Request frames.
+ *
+ * @QCA_VENDOR_ELEM_HE_CAPAB: HE Capabilities element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID. The payload of this
+ * vendor specific element is defined by the latest P802.11ax draft.
+ * Please note that the draft is still work in progress and this element
+ * payload is subject to change.
+ *
+ * @QCA_VENDOR_ELEM_HE_OPER: HE Operation element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID. The payload of this
+ * vendor specific element is defined by the latest P802.11ax draft.
+ * Please note that the draft is still work in progress and this element
+ * payload is subject to change.
+ *
+ * @QCA_VENDOR_ELEM_RAPS: RAPS element (OFDMA-based Random Access Parameter Set
+ * element).
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID extension. The payload of
+ * this vendor specific element is defined by the latest P802.11ax draft
+ * (not including the Element ID Extension field). Please note that the
+ * draft is still work in progress and this element payload is subject to
+ * change.
+ *
+ * @QCA_VENDOR_ELEM_MU_EDCA_PARAMS: MU EDCA Parameter Set element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID extension. The payload of
+ * this vendor specific element is defined by the latest P802.11ax draft
+ * (not including the Element ID Extension field). Please note that the
+ * draft is still work in progress and this element payload is subject to
+ * change.
+ *
+ * @QCA_VENDOR_ELEM_BSS_COLOR_CHANGE: BSS Color Change Announcement element.
+ * This element can be used for pre-standard publication testing of HE
+ * before P802.11ax draft assigns the element ID extension. The payload of
+ * this vendor specific element is defined by the latest P802.11ax draft
+ * (not including the Element ID Extension field). Please note that the
+ * draft is still work in progress and this element payload is subject to
+ * change.
*/
enum qca_vendor_element_id {
QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
+ QCA_VENDOR_ELEM_HE_CAPAB = 1,
+ QCA_VENDOR_ELEM_HE_OPER = 2,
+ QCA_VENDOR_ELEM_RAPS = 3,
+ QCA_VENDOR_ELEM_MU_EDCA_PARAMS = 4,
+ QCA_VENDOR_ELEM_BSS_COLOR_CHANGE = 5,
};
/**
@@ -429,19 +916,22 @@
* scan flag is set
* @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with
* randomisation
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the
+ * specific BSSID to scan for.
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
- QCA_WLAN_VENDOR_ATTR_SCAN_IE,
- QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES,
- QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS,
- QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES,
- QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE,
- QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS,
- QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE,
- QCA_WLAN_VENDOR_ATTR_SCAN_STATUS,
- QCA_WLAN_VENDOR_ATTR_SCAN_MAC,
- QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK,
+ QCA_WLAN_VENDOR_ATTR_SCAN_IE = 1,
+ QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES = 2,
+ QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS = 3,
+ QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES = 4,
+ QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE = 5,
+ QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS = 6,
+ QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE = 7,
+ QCA_WLAN_VENDOR_ATTR_SCAN_STATUS = 8,
+ QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9,
+ QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
+ QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -507,4 +997,2429 @@
QCA_WLAN_VENDOR_ATTR_TXPOWER_DECR_DB_AFTER_LAST - 1
};
+/* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION and
+ * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION subcommands.
+ */
+enum qca_wlan_vendor_attr_config {
+ QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID = 0,
+ /* Unsigned 32-bit value to set the DTIM period.
+ * Whether the wifi chipset wakes at every dtim beacon or a multiple of
+ * the DTIM period. If DTIM is set to 3, the STA shall wake up every 3
+ * DTIM beacons.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM = 1,
+ /* Unsigned 32-bit value to set the wifi_iface stats averaging factor
+ * used to calculate statistics like average the TSF offset or average
+ * number of frame leaked.
+ * For instance, upon Beacon frame reception:
+ * current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000
+ * For instance, when evaluating leaky APs:
+ * current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 - factor)) / 0x10000
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR = 2,
+ /* Unsigned 32-bit value to configure guard time, i.e., when
+ * implementing IEEE power management based on frame control PM bit, how
+ * long the driver waits before shutting down the radio and after
+ * receiving an ACK frame for a Data frame with PM bit set.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME = 3,
+ /* Unsigned 32-bit value to change the FTM capability dynamically */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT = 4,
+ /* Unsigned 16-bit value to configure maximum TX rate dynamically */
+ QCA_WLAN_VENDOR_ATTR_CONF_TX_RATE = 5,
+ /* Unsigned 32-bit value to configure the number of continuous
+ * Beacon Miss which shall be used by the firmware to penalize
+ * the RSSI.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS = 6,
+ /* Unsigned 8-bit value to configure the channel avoidance indication
+ * behavior. Firmware to send only one indication and ignore duplicate
+ * indications when set to avoid multiple Apps wakeups.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND = 7,
+ /* 8-bit unsigned value to configure the maximum TX MPDU for
+ * aggregation. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION = 8,
+ /* 8-bit unsigned value to configure the maximum RX MPDU for
+ * aggregation. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION = 9,
+ /* 8-bit unsigned value to configure the Non aggregrate/11g sw
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY = 10,
+ /* 8-bit unsigned value to configure the aggregrate sw
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY = 11,
+ /* 8-bit unsigned value to configure the MGMT frame
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY = 12,
+ /* 8-bit unsigned value to configure the CTRL frame
+ * retry threshold (0 disable, 31 max). */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY = 13,
+ /* 8-bit unsigned value to configure the propagation delay for
+ * 2G/5G band (0~63, units in us) */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY = 14,
+ /* Unsigned 32-bit value to configure the number of unicast TX fail
+ * packet count. The peer is disconnected once this threshold is
+ * reached. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT = 15,
+ /* Attribute used to set scan default IEs to the driver.
+ *
+ * These IEs can be used by scan operations that will be initiated by
+ * the driver/firmware.
+ *
+ * For further scan requests coming to the driver, these IEs should be
+ * merged with the IEs received along with scan request coming to the
+ * driver. If a particular IE is present in the scan default IEs but not
+ * present in the scan request, then that IE should be added to the IEs
+ * sent in the Probe Request frames for that scan request. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES = 16,
+ /* Unsigned 32-bit attribute for generic commands */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND = 17,
+ /* Unsigned 32-bit value attribute for generic commands */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE = 18,
+ /* Unsigned 32-bit data attribute for generic command response */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA = 19,
+ /* Unsigned 32-bit length attribute for
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH = 20,
+ /* Unsigned 32-bit flags attribute for
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS = 21,
+ /* Unsigned 32-bit, defining the access policy.
+ * See enum qca_access_policy. Used with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY = 22,
+ /* Sets the list of full set of IEs for which a specific access policy
+ * has to be applied. Used along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access.
+ * Zero length payload can be used to clear this access constraint. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST = 23,
+ /* Unsigned 32-bit, specifies the interface index (netdev) for which the
+ * corresponding configurations are applied. If the interface index is
+ * not specified, the configurations are attributed to the respective
+ * wiphy. */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX = 24,
+ /* 8-bit unsigned value to trigger QPower: 1-Enable, 0-Disable */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25,
+ /* 8-bit unsigned value to configure the driver and below layers to
+ * ignore the assoc disallowed set by APs while connecting
+ * 1-Ignore, 0-Don't ignore */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED = 26,
+ /* 32-bit unsigned value to trigger antenna diversity features:
+ * 1-Enable, 0-Disable */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA = 27,
+ /* 32-bit unsigned value to configure specific chain antenna */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN = 28,
+ /* 32-bit unsigned value to trigger cycle selftest
+ * 1-Enable, 0-Disable */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST = 29,
+ /* 32-bit unsigned to configure the cycle time of selftest
+ * the unit is micro-second */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL = 30,
+ /* 32-bit unsigned value to set reorder timeout for AC_VO */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VOICE = 31,
+ /* 32-bit unsigned value to set reorder timeout for AC_VI */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VIDEO = 32,
+ /* 32-bit unsigned value to set reorder timeout for AC_BE */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BESTEFFORT = 33,
+ /* 32-bit unsigned value to set reorder timeout for AC_BK */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BACKGROUND = 34,
+ /* 6-byte MAC address to point out the specific peer */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_PEER_MAC = 35,
+ /* 32-bit unsigned value to set window size for specific peer */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_WINLIMIT = 36,
+ /* 8-bit unsigned value to set the beacon miss threshold in 2.4 GHz */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_24 = 37,
+ /* 8-bit unsigned value to set the beacon miss threshold in 5 GHz */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_5 = 38,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration
+ */
+enum qca_wlan_vendor_attr_sap_config {
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0,
+ /* 1 - reserved for QCA */
+ /* List of frequencies on which AP is expected to operate.
+ * This is irrespective of ACS configuration. This list is a priority
+ * based one and is looked for before the AP is created to ensure the
+ * best concurrency sessions (avoid MCC and use DBS/SCC) co-exist in
+ * the system.
+ */
+ QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2,
+
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_sap_conditional_chan_switch - Parameters for AP
+ * conditional channel switch
+ */
+enum qca_wlan_vendor_attr_sap_conditional_chan_switch {
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0,
+ /* Priority based frequency list (an array of u32 values in host byte
+ * order) */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1,
+ /* Status of the conditional switch (u32).
+ * 0: Success, Non-zero: Failure
+ */
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS = 2,
+
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_gpio_attr - Parameters for GPIO configuration
+ */
+enum qca_wlan_gpio_attr {
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INVALID = 0,
+ /* Unsigned 32-bit attribute for GPIO command */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND,
+ /* Unsigned 32-bit attribute for GPIO PIN number to configure */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM,
+ /* Unsigned 32-bit attribute for GPIO value to configure */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE,
+ /* Unsigned 32-bit attribute for GPIO pull type */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE,
+ /* Unsigned 32-bit attribute for GPIO interrupt mode */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST,
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_hw_capability - Wi-Fi hardware capability
+ */
+enum qca_wlan_vendor_attr_get_hw_capability {
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_INVALID,
+ /* Antenna isolation
+ * An attribute used in the response.
+ * The content of this attribute is encoded in a byte array. Each byte
+ * value is an antenna isolation value. The array length is the number
+ * of antennas.
+ */
+ QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION,
+ /* Request HW capability
+ * An attribute used in the request.
+ * The content of this attribute is a u32 array for one or more of
+ * hardware capabilities (attribute IDs) that are being requested. Each
+ * u32 value has a value from this
+ * enum qca_wlan_vendor_attr_get_hw_capability
+ * identifying which capabilities are requested.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_HW_CAPABILITY,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_MAX =
+ QCA_WLAN_VENDOR_ATTR_HW_CAPABILITY_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ll_stats_ext - Attributes for MAC layer monitoring
+ * offload which is an extension for LL_STATS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD: Monitoring period. Unit in ms.
+ * If MAC counters do not exceed the threshold, FW will report monitored
+ * link layer counters periodically as this setting. The first report is
+ * always triggered by this timer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD: It is a percentage (1-99).
+ * For each MAC layer counter, FW holds two copies. One is the current value.
+ * The other is the last report. Once a current counter's increment is larger
+ * than the threshold, FW will indicate that counter to host even if the
+ * monitoring timer does not expire.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG: Peer STA power state change
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID: TID of MSDU
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU: Count of MSDU with the same
+ * failure code.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS: TX failure code
+ * 1: TX packet discarded
+ * 2: No ACK
+ * 3: Postpone
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS: peer MAC address
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE: Peer STA current state
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL: Global threshold.
+ * Threshold for all monitored parameters. If per counter dedicated threshold
+ * is not enabled, this threshold will take effect.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE: Indicate what triggers this
+ * event, PERORID_TIMEOUT == 1, THRESH_EXCEED == 0.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID: interface ID
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID: peer ID
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP: bitmap for TX counters
+ * Bit0: TX counter unit in MSDU
+ * Bit1: TX counter unit in MPDU
+ * Bit2: TX counter unit in PPDU
+ * Bit3: TX counter unit in byte
+ * Bit4: Dropped MSDUs
+ * Bit5: Dropped Bytes
+ * Bit6: MPDU retry counter
+ * Bit7: MPDU failure counter
+ * Bit8: PPDU failure counter
+ * Bit9: MPDU aggregation counter
+ * Bit10: MCS counter for ACKed MPDUs
+ * Bit11: MCS counter for Failed MPDUs
+ * Bit12: TX Delay counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP: bitmap for RX counters
+ * Bit0: MAC RX counter unit in MPDU
+ * Bit1: MAC RX counter unit in byte
+ * Bit2: PHY RX counter unit in PPDU
+ * Bit3: PHY RX counter unit in byte
+ * Bit4: Disorder counter
+ * Bit5: Retry counter
+ * Bit6: Duplication counter
+ * Bit7: Discard counter
+ * Bit8: MPDU aggregation size counter
+ * Bit9: MCS counter
+ * Bit10: Peer STA power state change (wake to sleep) counter
+ * Bit11: Peer STA power save counter, total time in PS mode
+ * Bit12: Probe request counter
+ * Bit13: Other management frames counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP: bitmap for CCA
+ * Bit0: Idle time
+ * Bit1: TX time
+ * Bit2: time RX in current bss
+ * Bit3: Out of current bss time
+ * Bit4: Wireless medium busy time
+ * Bit5: RX in bad condition time
+ * Bit6: TX in bad condition time
+ * Bit7: time wlan card not available
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP: bitmap for signal
+ * Bit0: Per channel SNR counter
+ * Bit1: Per channel noise floor counter
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM: number of peers
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM: number of channels
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_AC_RX_NUM: number of RX stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS: per channel BSS CCA stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER: container for per PEER stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU: Number of total TX MSDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU: Number of total TX MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU: Number of total TX PPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES: bytes of TX data
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP: Number of dropped TX packets
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES: Bytes dropped
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY: waiting time without an ACK
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK: number of MPDU not-ACKed
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK: number of PPDU not-ACKed
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM:
+ * aggregation stats buffer length
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM: length of mcs stats
+ * buffer for ACKed MPDUs.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM: length of mcs stats
+ * buffer for failed MPDUs.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE:
+ * length of delay stats array.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR: TX aggregation stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS: MCS stats for ACKed MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS: MCS stats for failed MPDUs
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY: tx delay stats
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU: MPDUs received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES: bytes received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU: PPDU received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES: PPDU bytes received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST: packets lost
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY: number of RX packets
+ * flagged as retransmissions
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP: number of RX packets
+ * flagged as duplicated
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD: number of RX
+ * packets discarded
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM: length of RX aggregation
+ * stats buffer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM: length of RX mcs
+ * stats buffer.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS: RX mcs stats buffer
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR: aggregation stats buffer
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES: times STAs go to sleep
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION: STAs' total sleep time
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ: number of probe
+ * requests received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT: number of other mgmt
+ * frames received
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME: Percentage of idle time
+ * there is no TX, nor RX, nor interference.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME: percentage of time
+ * transmitting packets.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME: percentage of time
+ * for receiving.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY: percentage of time
+ * interference detected.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD: percentage of time
+ * receiving packets with errors.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD: percentage of time
+ * TX no-ACK.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL: percentage of time
+ * the chip is unable to work in normal conditions.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME: percentage of time
+ * receiving packets in current BSS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME: percentage of time
+ * receiving packets not in current BSS.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM: number of antennas
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL:
+ * This is a container for per antenna signal stats.
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR: per antenna SNR value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF: per antenna NF value
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON: RSSI of beacon
+ * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON: SNR of beacon
+ */
+enum qca_wlan_vendor_attr_ll_stats_ext {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0,
+
+ /* Attributes for configurations */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD,
+
+ /* Peer STA power state change */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG,
+
+ /* TX failure event */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
+
+ /* MAC counters */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER,
+
+ /* Sub-attributes for PEER_AC_TX */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY,
+
+ /* Sub-attributes for PEER_AC_RX */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT,
+
+ /* Sub-attributes for CCA_BSS */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL,
+
+ /* sub-attribute for BSS_RX_TIME */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME,
+
+ /* Sub-attributes for PEER_SIGNAL */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF,
+
+ /* Sub-attributes for IFACE_BSS */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST - 1
+};
+
+/* Attributes for FTM commands and events */
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa - Indoor location capabilities
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS: Various flags. See
+ * enum qca_wlan_vendor_attr_loc_capa_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS: Maximum number
+ * of measurement sessions that can run concurrently.
+ * Default is one session (no session concurrency).
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS: The total number of unique
+ * peers that are supported in running sessions. For example,
+ * if the value is 8 and maximum number of sessions is 2, you can
+ * have one session with 8 unique peers, or 2 sessions with 4 unique
+ * peers each, and so on.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP: Maximum number
+ * of bursts per peer, as an exponent (2^value). Default is 0,
+ * meaning no multi-burst support.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST: Maximum number
+ * of measurement exchanges allowed in a single burst.
+ * @QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES: Supported AOA measurement
+ * types. A bit mask (unsigned 32 bit value), each bit corresponds
+ * to an AOA type as defined by enum qca_vendor_attr_aoa_type.
+ */
+enum qca_wlan_vendor_attr_loc_capa {
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_INVALID,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAGS,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_SESSIONS,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_PEERS,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_NUM_BURSTS_EXP,
+ QCA_WLAN_VENDOR_ATTR_FTM_CAPA_MAX_MEAS_PER_BURST,
+ QCA_WLAN_VENDOR_ATTR_AOA_CAPA_SUPPORTED_TYPES,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_MAX =
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_loc_capa_flags: Indoor location capability flags
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER: Set if driver
+ * can be configured as an FTM responder (for example, an AP that
+ * services FTM requests). QCA_NL80211_VENDOR_SUBCMD_FTM_CFG_RESPONDER
+ * will be supported if set.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR: Set if driver
+ * can run FTM sessions. QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION
+ * will be supported if set.
+* @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP: Set if FTM responder
+ * supports immediate (ASAP) response.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA: Set if driver supports standalone
+ * AOA measurement using QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM: Set if driver supports
+ * requesting AOA measurements as part of an FTM session.
+ */
+enum qca_wlan_vendor_attr_loc_capa_flags {
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_RESPONDER = 1 << 0,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_FTM_INITIATOR = 1 << 1,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_ASAP = 1 << 2,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA = 1 << 3,
+ QCA_WLAN_VENDOR_ATTR_LOC_CAPA_FLAG_AOA_IN_FTM = 1 << 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_info: Information about
+ * a single peer in a measurement session.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR: The MAC address of the peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS: Various flags related
+ * to measurement. See enum qca_wlan_vendor_attr_ftm_peer_meas_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS: Nested attribute of
+ * FTM measurement parameters, as specified by IEEE P802.11-REVmc/D7.0
+ * 9.4.2.167. See enum qca_wlan_vendor_attr_ftm_meas_param for
+ * list of supported attributes.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID: Initial token ID for
+ * secure measurement.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA
+ * measurement every <value> bursts. If 0 or not specified,
+ * AOA measurements will be disabled for this peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ: Frequency in MHz where
+ * the measurement frames are exchanged. Optional; if not
+ * specified, try to locate the peer in the kernel scan
+ * results cache and use frequency from there.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_info {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_meas_flags: Measurement request flags,
+ * per-peer
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP: If set, request
+ * immediate (ASAP) response from peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI: If set, request
+ * LCI report from peer. The LCI report includes the absolute
+ * location of the peer in "official" coordinates (similar to GPS).
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR: If set, request
+ * Location civic report from peer. The LCR includes the location
+ * of the peer in free-form format. See IEEE P802.11-REVmc/D7.0,
+ * 11.24.6.7 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE: If set,
+ * request a secure measurement.
+ * QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID must also be provided.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_meas_flags {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_ASAP = 1 << 0,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCI = 1 << 1,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_LCR = 1 << 2,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE = 1 << 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas_param: Measurement parameters
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST: Number of measurements
+ * to perform in a single burst.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP: Number of bursts to
+ * perform, specified as an exponent (2^value).
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION: Duration of burst
+ * instance, as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD: Time between bursts,
+ * as specified in IEEE P802.11-REVmc/D7.0, 9.4.2.167. Must
+ * be larger than QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION.
+ */
+enum qca_wlan_vendor_attr_ftm_meas_param {
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MEAS_PER_BURST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_NUM_BURSTS_EXP,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_DURATION,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_PARAM_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result: Per-peer results
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR: MAC address of the reported
+ * peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS: Status of measurement
+ * request for this peer.
+ * See enum qca_wlan_vendor_attr_ftm_peer_result_status.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS: Various flags related
+ * to measurement results for this peer.
+ * See enum qca_wlan_vendor_attr_ftm_peer_result_flags.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS: Specified when
+ * request failed and peer requested not to send an additional request
+ * for this number of seconds.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI: LCI report when received
+ * from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
+ * 9.4.2.22.10.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR: Location civic report when
+ * received from peer. In the format specified by IEEE P802.11-REVmc/D7.0,
+ * 9.4.2.22.13.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS: Reported when peer
+ * overridden some measurement request parameters. See
+ * enum qca_wlan_vendor_attr_ftm_meas_param.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS: AOA measurement
+ * for this peer. Same contents as @QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS: Array of measurement
+ * results. Each entry is a nested attribute defined
+ * by enum qca_wlan_vendor_attr_ftm_meas.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAC_ADDR,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAGS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCI,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_LCR,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAMS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AOA_MEAS,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_status
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK: Request sent ok and results
+ * will be provided. Peer may have overridden some measurement parameters,
+ * in which case overridden parameters will be report by
+ * QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_MEAS_PARAM attribute.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE: Peer is incapable
+ * of performing the measurement request. No more results will be sent
+ * for this peer in this session.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED: Peer reported request
+ * failed, and requested not to send an additional request for number
+ * of seconds specified by QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_VALUE_SECONDS
+ * attribute.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID: Request validation
+ * failed. Request was not sent over the air.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_status {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_OK,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INCAPABLE,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_FAILED,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_STATUS_INVALID,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_peer_result_flags: Various flags
+ * for measurement result, per-peer
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE: If set,
+ * measurement completed for this peer. No more results will be reported
+ * for this peer in this session.
+ */
+enum qca_wlan_vendor_attr_ftm_peer_result_flags {
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_RES_FLAG_DONE = 1 << 0,
+};
+
+/**
+ * enum qca_vendor_attr_loc_session_status: Session completion status code
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK: Session completed
+ * successfully.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED: Session aborted
+ * by request.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID: Session request
+ * was invalid and was not started.
+ * @QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED: Session had an error
+ * and did not complete normally (for example out of resources).
+ */
+enum qca_vendor_attr_loc_session_status {
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_OK,
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_ABORTED,
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_INVALID,
+ QCA_WLAN_VENDOR_ATTR_LOC_SESSION_STATUS_FAILED,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_ftm_meas: Single measurement data
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1: Time of departure (TOD) of FTM packet as
+ * recorded by responder, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2: Time of arrival (TOA) of FTM packet at
+ * initiator, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3: TOD of ACK packet as recorded by
+ * initiator, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4: TOA of ACK packet at
+ * responder, in picoseconds.
+ * See IEEE P802.11-REVmc/D7.0, 11.24.6.4 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI: RSSI (signal level) as recorded
+ * during this measurement exchange. Optional and will be provided if
+ * the hardware can measure it.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR: TOD error reported by
+ * responder. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR: TOA error reported by
+ * responder. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR: TOD error measured by
+ * initiator. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by
+ * initiator. Not always provided.
+ * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding.
+ */
+enum qca_wlan_vendor_attr_ftm_meas {
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T1,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T2,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T3,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_T4,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_RSSI,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOD_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_TOA_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOD_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_MAX =
+ QCA_WLAN_VENDOR_ATTR_FTM_MEAS_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_aoa_type - AOA measurement type
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE: Phase of the strongest
+ * CIR (channel impulse response) path for each antenna.
+ * @QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: Phase and amplitude
+ * of the strongest CIR path for each antenna.
+ */
+enum qca_wlan_vendor_attr_aoa_type {
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE,
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP,
+ QCA_WLAN_VENDOR_ATTR_AOA_TYPE_MAX
+};
+
+/**
+ * enum qca_wlan_vendor_attr_encryption_test - Attributes to
+ * validate encryption engine
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION: Flag attribute.
+ * This will be included if the request is for decryption; if not included,
+ * the request is treated as a request for encryption by default.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER: Unsigned 32-bit value
+ * indicating the key cipher suite. Takes same values as
+ * NL80211_ATTR_KEY_CIPHER.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID: Unsigned 8-bit value
+ * Key Id to be used for encryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK: Array of 8-bit values.
+ * Key (TK) to be used for encryption/decryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN: Array of 8-bit values.
+ * Packet number to be specified for encryption/decryption
+ * 6 bytes for TKIP/CCMP/GCMP.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA: Array of 8-bit values
+ * representing the 802.11 packet (header + payload + FCS) that
+ * needs to be encrypted/decrypted.
+ * Encrypted/decrypted response from the driver will also be sent
+ * to userspace with the same attribute.
+ */
+enum qca_wlan_vendor_attr_encryption_test {
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX =
+ QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_dmg_rf_sector_type - Type of
+ * sector for DMG RF sector operations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_RX: RX sector
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_TX: TX sector
+ */
+enum qca_wlan_vendor_attr_dmg_rf_sector_type {
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_RX,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_TX,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_TYPE_MAX
+};
+
+/**
+ * enum qca_wlan_vendor_attr_dmg_rf_sector_cfg - Attributes for
+ * DMG RF sector configuration for a single RF module.
+ * The values are defined in a compact way which closely matches
+ * the way it is stored in HW registers.
+ * The configuration provides values for 32 antennas and 8 distribution
+ * amplifiers, and together describes the characteristics of the RF
+ * sector - such as a beam in some direction with some gain.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX: Index
+ * of RF module for this configuration.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE0: Bit 0 of edge
+ * amplifier gain index. Unsigned 32 bit number containing
+ * bits for all 32 antennas.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE1: Bit 1 of edge
+ * amplifier gain index. Unsigned 32 bit number containing
+ * bits for all 32 antennas.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE2: Bit 2 of edge
+ * amplifier gain index. Unsigned 32 bit number containing
+ * bits for all 32 antennas.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_HI: Phase values
+ * for first 16 antennas, 2 bits per antenna.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_LO: Phase values
+ * for last 16 antennas, 2 bits per antenna.
+ * @QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16: Contains
+ * DTYPE values (3 bits) for each distribution amplifier, followed
+ * by X16 switch bits for each distribution amplifier. There are
+ * total of 8 distribution amplifiers.
+ */
+enum qca_wlan_vendor_attr_dmg_rf_sector_cfg {
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX = 1,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE0 = 2,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE1 = 3,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_ETYPE2 = 4,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_HI = 5,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_PSH_LO = 6,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16 = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_MAX =
+ QCA_WLAN_VENDOR_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1
+};
+
+enum qca_wlan_vendor_attr_ll_stats_set {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_INVALID = 0,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD = 1,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING = 2,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_clr {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID = 0,
+ /* Unsigned 32bit bitmap for clearing statistics
+ * All radio statistics 0x00000001
+ * cca_busy_time (within radio statistics) 0x00000002
+ * All channel stats (within radio statistics) 0x00000004
+ * All scan statistics (within radio statistics) 0x00000008
+ * All interface statistics 0x00000010
+ * All tx rate statistics (within interface statistics) 0x00000020
+ * All ac statistics (with in interface statistics) 0x00000040
+ * All contention (min, max, avg) statistics (within ac statisctics)
+ * 0x00000080.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK = 1,
+ /* Unsigned 8 bit value: Request to stop statistics collection */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ = 2,
+
+ /* Unsigned 32 bit bitmap: Response from the driver
+ * for the cleared statistics
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK = 3,
+ /* Unsigned 8 bit value: Response from driver/firmware
+ * for the stop request
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP = 4,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_get {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID = 0,
+ /* Unsigned 32 bit value provided by the caller issuing the GET stats
+ * command. When reporting the stats results, the driver uses the same
+ * value to indicate which GET request the results correspond to.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID = 1,
+ /* Unsigned 32 bit value - bit mask to identify what statistics are
+ * requested for retrieval.
+ * Radio Statistics 0x00000001
+ * Interface Statistics 0x00000020
+ * All Peer Statistics 0x00000040
+ * Peer Statistics 0x00000080
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK = 2,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_results {
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0,
+ /* Unsigned 32bit value. Used by the driver; must match the request id
+ * provided with the QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET command.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID = 1,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX = 2,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX = 3,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX = 4,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX = 5,
+ /* Signed 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT = 6,
+ /* Signed 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA = 7,
+ /* Signed 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK = 8,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_* are
+ * nested within the interface stats.
+ */
+
+ /* Interface mode, e.g., STA, SOFTAP, IBSS, etc.
+ * Type = enum wifi_interface_mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE = 9,
+ /* Interface MAC address. An array of 6 Unsigned int8 */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR = 10,
+ /* Type = enum wifi_connection_state, e.g., DISCONNECTED,
+ * AUTHENTICATING, etc. valid for STA, CLI only.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE = 11,
+ /* Type = enum wifi_roam_state. Roaming state, e.g., IDLE or ACTIVE
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING = 12,
+ /* Unsigned 32 bit value. WIFI_CAPABILITY_XXX */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES = 13,
+ /* NULL terminated SSID. An array of 33 Unsigned 8bit values */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID = 14,
+ /* BSSID. An array of 6 unsigned 8 bit values */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID = 15,
+ /* Country string advertised by AP. An array of 3 unsigned 8 bit
+ * values.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR = 16,
+ /* Country string for this association. An array of 3 unsigned 8 bit
+ * values.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR = 17,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* could
+ * be nested within the interface stats.
+ */
+
+ /* Type = enum wifi_traffic_ac, e.g., V0, VI, BE and BK */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC = 18,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU = 19,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU = 20,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST = 21,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST = 22,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU = 23,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU = 24,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST = 25,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES = 26,
+ /* Unsigned int 32 value corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT = 27,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG = 28,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN = 29,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX = 30,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG = 31,
+ /* Unsigned int 32 values corresponding to respective AC */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES = 32,
+ /* Unsigned 32 bit value. Number of peers */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS = 33,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_* are
+ * nested within the interface stats.
+ */
+
+ /* Type = enum wifi_peer_type. Peer type, e.g., STA, AP, P2P GO etc. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE = 34,
+ /* MAC addr corresponding to respective peer. An array of 6 unsigned
+ * 8 bit values.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS = 35,
+ /* Unsigned int 32 bit value representing capabilities corresponding
+ * to respective peer.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES = 36,
+ /* Unsigned 32 bit value. Number of rates */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES = 37,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_*
+ * are nested within the rate stat.
+ */
+
+ /* Wi-Fi Rate - separate attributes defined for individual fields */
+
+ /* Unsigned int 8 bit value; 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE = 38,
+ /* Unsigned int 8 bit value; 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS = 39,
+ /* Unsigned int 8 bit value; 0:20 MHz, 1:40 MHz, 2:80 MHz, 3:160 MHz */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW = 40,
+ /* Unsigned int 8 bit value; OFDM/CCK rate code would be as per IEEE Std
+ * in the units of 0.5 Mbps HT/VHT it would be MCS index */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX = 41,
+
+ /* Unsigned 32 bit value. Bit rate in units of 100 kbps */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE = 42,
+
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_STAT_* could be
+ * nested within the peer info stats.
+ */
+
+ /* Unsigned int 32 bit value. Number of successfully transmitted data
+ * packets, i.e., with ACK received corresponding to the respective
+ * rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU = 43,
+ /* Unsigned int 32 bit value. Number of received data packets
+ * corresponding to the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU = 44,
+ /* Unsigned int 32 bit value. Number of data packet losses, i.e., no ACK
+ * received corresponding to the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST = 45,
+ /* Unsigned int 32 bit value. Total number of data packet retries for
+ * the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES = 46,
+ /* Unsigned int 32 bit value. Total number of short data packet retries
+ * for the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT = 47,
+ /* Unsigned int 32 bit value. Total number of long data packet retries
+ * for the respective rate.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG = 48,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID = 49,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake
+ * accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME = 50,
+ /* Unsigned 32 bit value. Total number of msecs the radio is
+ * transmitting accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME = 51,
+ /* Unsigned 32 bit value. Total number of msecs the radio is in active
+ * receive accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME = 52,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to all scan accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN = 53,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to NAN accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD = 54,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to GSCAN accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN = 55,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to roam scan accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN = 56,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to PNO scan accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN = 57,
+ /* Unsigned 32 bit value. Total number of msecs the radio is awake due
+ * to Hotspot 2.0 scans and GAS exchange accruing over time.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20 = 58,
+ /* Unsigned 32 bit value. Number of channels. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS = 59,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_* could
+ * be nested within the channel stats.
+ */
+
+ /* Type = enum wifi_channel_width. Channel width, e.g., 20, 40, 80 */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH = 60,
+ /* Unsigned 32 bit value. Primary 20 MHz channel. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ = 61,
+ /* Unsigned 32 bit value. Center frequency (MHz) first segment. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0 = 62,
+ /* Unsigned 32 bit value. Center frequency (MHz) second segment. */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1 = 63,
+
+ /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_* could be
+ * nested within the radio stats.
+ */
+
+ /* Unsigned int 32 bit value representing total number of msecs the
+ * radio is awake on that channel accruing over time, corresponding to
+ * the respective channel.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME = 64,
+ /* Unsigned int 32 bit value representing total number of msecs the CCA
+ * register is busy accruing over time corresponding to the respective
+ * channel.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME = 65,
+
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS = 66,
+
+ /* Signifies the nested list of channel attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67,
+
+ /* Signifies the nested list of peer info attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO = 68,
+
+ /* Signifies the nested list of rate info attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO = 69,
+
+ /* Signifies the nested list of wmm info attributes
+ * QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_*
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO = 70,
+
+ /* Unsigned 8 bit value. Used by the driver; if set to 1, it indicates
+ * that more stats, e.g., peers or radio, are to follow in the next
+ * QCA_NL80211_VENDOR_SUBCMD_LL_STATS_*_RESULTS event.
+ * Otherwise, it is set to 0.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA = 71,
+
+ /* Unsigned 64 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET = 72,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED = 73,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED = 74,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME = 75,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE = 76,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS = 77,
+
+ /* Number of msecs the radio spent in transmitting for each power level
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL = 78,
+
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT = 79,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT = 80,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT = 81,
+ /* Unsigned 32 bit value */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT = 82,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_ll_stats_type
+{
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_INVALID = 0,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO = 1,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE = 2,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS = 3,
+
+ /* keep last */
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_AFTER_LAST,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_MAX =
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_tdls_configuration - Attributes for
+ * TDLS configuration to the host driver.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE: Configure the TDLS trigger
+ * mode in the host driver. enum qca_wlan_vendor_tdls_trigger_mode
+ * represents the different TDLS trigger modes.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD: Duration (u32) within
+ * which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD number
+ * of packets shall meet the criteria for implicit TDLS setup.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD: Number (u32) of Tx/Rx packets
+ * within a duration QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD
+ * to initiate a TDLS setup.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD: Time (u32) to initiate
+ * a TDLS Discovery to the peer.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT: Max number (u32) of
+ * discovery attempts to know the TDLS capability of the peer. A peer is
+ * marked as TDLS not capable if there is no response for all the attempts.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT: Represents a duration (u32)
+ * within which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD
+ * number of TX / RX frames meet the criteria for TDLS teardown.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD: Minimum number (u32)
+ * of Tx/Rx packets within a duration
+ * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT to tear down a TDLS link.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD: Threshold
+ * corresponding to the RSSI of the peer below which a TDLS setup is
+ * triggered.
+ * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD: Threshold
+ * corresponding to the RSSI of the peer above which a TDLS teardown is
+ * triggered.
+ */
+enum qca_wlan_vendor_attr_tdls_configuration {
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE = 1,
+
+ /* Attributes configuring the TDLS Implicit Trigger */
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD = 2,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD = 3,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD = 4,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT = 5,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT = 6,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD = 7,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD = 8,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD = 9,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_tdls_trigger_mode: Represents the TDLS trigger mode in
+ * the driver
+ *
+ * The following are the different values for
+ * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE.
+ *
+ * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: The trigger to initiate/teardown
+ * the TDLS connection to a respective peer comes from the user space.
+ * wpa_supplicant provides the commands TDLS_SETUP, TDLS_TEARDOWN,
+ * TDLS_DISCOVER to do this.
+ * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: Host driver triggers this TDLS
+ * setup/teardown to the eligible peer once the configured criteria
+ * (such as TX/RX threshold, RSSI) is met. The attributes
+ * in QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IMPLICIT_PARAMS correspond to
+ * the different configuration criteria for the TDLS trigger from the
+ * host driver.
+ * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: Enables the driver to trigger
+ * the TDLS setup / teardown through the implicit mode only to the
+ * configured MAC addresses (wpa_supplicant, with tdls_external_control=1,
+ * configures the MAC address through TDLS_SETUP / TDLS_TEARDOWN commands).
+ * External mode works on top of the implicit mode. Thus the host driver
+ * is expected to configure in TDLS Implicit mode too to operate in
+ * External mode.
+ * Configuring External mode alone without Implicit mode is invalid.
+ *
+ * All the above implementations work as expected only when the host driver
+ * advertises the capability WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP - representing
+ * that the TDLS message exchange is not internal to the host driver, but
+ * depends on wpa_supplicant to do the message exchange.
+ */
+enum qca_wlan_vendor_tdls_trigger_mode {
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = 1 << 0,
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = 1 << 1,
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = 1 << 2,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits_selections - Source of SAR power limits
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0: Select SAR profile #0
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1: Select SAR profile #1
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2: Select SAR profile #2
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3: Select SAR profile #3
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4: Select SAR profile #4
+ * that is hard-coded in the Board Data File (BDF).
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE: Do not select any
+ * source of SAR power limits, thereby disabling the SAR power
+ * limit feature.
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: Select the SAR power
+ * limits configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR.
+ *
+ * This enumerates the valid set of values that may be supplied for
+ * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT in an instance of
+ * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command.
+ */
+enum qca_vendor_attr_sar_limits_selections {
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 = 0,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1 = 1,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2 = 2,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3 = 3,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4 = 4,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE = 5,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER = 6,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits_spec_modulations -
+ * SAR limits specification modulation
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK -
+ * CCK modulation
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM -
+ * OFDM modulation
+ *
+ * This enumerates the valid set of values that may be supplied for
+ * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION in an
+ * instance of attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC in an
+ * instance of the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor
+ * command.
+ */
+enum qca_vendor_attr_sar_limits_spec_modulations {
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK = 0,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM = 1,
+};
+
+/**
+ * enum qca_vendor_attr_sar_limits - Attributes for SAR power limits
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT: Optional (u32) value to
+ * select which SAR power limit table should be used. Valid
+ * values are enumerated in enum
+ * %qca_vendor_attr_sar_limits_selections. The existing SAR
+ * power limit selection is unchanged if this attribute is not
+ * present.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS: Optional (u32) value
+ * which specifies the number of SAR power limit specifications
+ * which will follow.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC: Nested array of SAR power
+ * limit specifications. The number of specifications is
+ * specified by @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS. Each
+ * specification contains a set of
+ * QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_* attributes. A
+ * specification is uniquely identified by the attributes
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND,
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN, and
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION and always
+ * contains as a payload the attribute
+ * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND: Optional (u32) value to
+ * indicate for which band this specification applies. Valid
+ * values are enumerated in enum %nl80211_band (although not all
+ * bands may be supported by a given device). If the attribute is
+ * not supplied then the specification will be applied to all
+ * supported bands.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN: Optional (u32) value
+ * to indicate for which antenna chain this specification
+ * applies, i.e. 1 for chain 1, 2 for chain 2, etc. If the
+ * attribute is not supplied then the specification will be
+ * applied to all chains.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION: Optional (u32)
+ * value to indicate for which modulation scheme this
+ * specification applies. Valid values are enumerated in enum
+ * %qca_vendor_attr_sar_limits_spec_modulations. If the attribute
+ * is not supplied then the specification will be applied to all
+ * modulation schemes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT: Required (u32)
+ * value to specify the actual power limit value in units of 0.5
+ * dBm (i.e., a value of 11 represents 5.5 dBm).
+ *
+ * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS.
+ */
+enum qca_vendor_attr_sar_limits {
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE = 1,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS = 2,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC = 3,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND = 4,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN = 5,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION = 6,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT = 7,
+
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX =
+ QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_wifi_info: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO sub command.
+ */
+enum qca_wlan_vendor_attr_get_wifi_info {
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1,
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX =
+ QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_wifi_logger_start: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START sub command.
+ */
+enum qca_wlan_vendor_attr_wifi_logger_start {
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL = 2,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_GET_MAX =
+ QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_logger_results {
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_INVALID = 0,
+
+ /* Unsigned 32-bit value; must match the request Id supplied by
+ * Wi-Fi HAL in the corresponding subcmd NL msg.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_REQUEST_ID = 1,
+
+ /* Unsigned 32-bit value; used to indicate the size of memory
+ * dump to be allocated.
+ */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX =
+ QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_roaming_config_params {
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0,
+
+ QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD = 1,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID = 2,
+
+ /* Attributes for wifi_set_ssid_white_list */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS = 3,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST = 4,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID = 5,
+
+ /* Attributes for set_roam_params */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD = 6,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD = 7,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR = 8,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR = 9,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST = 10,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS = 11,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER = 12,
+
+ /* Attribute for set_lazy_roam */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE = 13,
+
+ /* Attribute for set_lazy_roam with preferences */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS = 14,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID = 15,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17,
+
+ /* Attribute for set_blacklist bssid params */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_roam_subcmd: Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_ROAM sub command.
+ */
+enum qca_wlan_vendor_attr_roam_subcmd {
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_gscan_config_params {
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_INVALID = 0,
+
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID = 1,
+
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS sub command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND
+ = 2,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS
+ = 3,
+
+ /* Attributes for input params used by
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_START sub command.
+ */
+
+ /* Unsigned 32-bit value; channel frequency */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CHANNEL = 4,
+ /* Unsigned 32-bit value; dwell time in ms. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_DWELL_TIME = 5,
+ /* Unsigned 8-bit value; 0: active; 1: passive; N/A for DFS */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_PASSIVE = 6,
+ /* Unsigned 8-bit value; channel class */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_CLASS = 7,
+
+ /* Unsigned 8-bit value; bucket index, 0 based */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_INDEX = 8,
+ /* Unsigned 8-bit value; band. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BAND = 9,
+ /* Unsigned 32-bit value; desired period, in ms. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_PERIOD = 10,
+ /* Unsigned 8-bit value; report events semantics. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_REPORT_EVENTS = 11,
+ /* Unsigned 32-bit value. Followed by a nested array of
+ * GSCAN_CHANNEL_SPEC_* attributes.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS = 12,
+
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC_* attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CHANNEL_SPEC = 13,
+
+ /* Unsigned 32-bit value; base timer period in ms. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_BASE_PERIOD = 14,
+ /* Unsigned 32-bit value; number of APs to store in each scan in the
+ * BSSID/RSSI history buffer (keep the highest RSSI APs).
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN = 15,
+ /* Unsigned 8-bit value; in %, when scan buffer is this much full, wake
+ * up AP.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT
+ = 16,
+
+ /* Unsigned 8-bit value; number of scan bucket specs; followed by a
+ * nested array of_GSCAN_BUCKET_SPEC_* attributes and values. The size
+ * of the array is determined by NUM_BUCKETS.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS = 17,
+
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_* attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC = 18,
+
+ /* Unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH
+ = 19,
+ /* Unsigned 32-bit value; maximum number of results to be returned. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX
+ = 20,
+
+ /* An array of 6 x unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_BSSID = 21,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_LOW = 22,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH = 23,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_CHANNEL = 24,
+
+ /* Number of hotlist APs as unsigned 32-bit value, followed by a nested
+ * array of AP_THRESHOLD_PARAM attributes and values. The size of the
+ * array is determined by NUM_AP.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_NUM_AP = 25,
+
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM_* attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_AP_THRESHOLD_PARAM = 26,
+
+ /* Unsigned 32-bit value; number of samples for averaging RSSI. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE
+ = 27,
+ /* Unsigned 32-bit value; number of samples to confirm AP loss. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE
+ = 28,
+ /* Unsigned 32-bit value; number of APs breaching threshold. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING = 29,
+ /* Unsigned 32-bit value; number of APs. Followed by an array of
+ * AP_THRESHOLD_PARAM attributes. Size of the array is NUM_AP.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP = 30,
+ /* Unsigned 32-bit value; number of samples to confirm AP loss. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE
+ = 31,
+ /* Unsigned 32-bit value. If max_period is non zero or different than
+ * period, then this bucket is an exponential backoff bucket.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_MAX_PERIOD = 32,
+ /* Unsigned 32-bit value. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_BASE = 33,
+ /* Unsigned 32-bit value. For exponential back off bucket, number of
+ * scans to perform for a given period.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_BUCKET_SPEC_STEP_COUNT = 34,
+ /* Unsigned 8-bit value; in number of scans, wake up AP after these
+ * many scans.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS
+ = 35,
+
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SSID_HOTLIST sub command.
+ */
+ /* Unsigned 3-2bit value; number of samples to confirm SSID loss. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE
+ = 36,
+ /* Number of hotlist SSIDs as unsigned 32-bit value, followed by a
+ * nested array of SSID_THRESHOLD_PARAM_* attributes and values. The
+ * size of the array is determined by NUM_SSID.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_NUM_SSID = 37,
+ /* Array of QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_*
+ * attributes.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_HOTLIST_PARAMS_NUM_SSID
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM = 38,
+
+ /* An array of 33 x unsigned 8-bit value; NULL terminated SSID */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_SSID = 39,
+ /* Unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_BAND = 40,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW = 41,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH = 42,
+ /* Unsigned 32-bit value; a bitmask with additional gscan config flag.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CONFIGURATION_FLAGS = 43,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_gscan_results {
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_INVALID = 0,
+
+ /* Unsigned 32-bit value; must match the request Id supplied by
+ * Wi-Fi HAL in the corresponding subcmd NL msg.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_REQUEST_ID = 1,
+
+ /* Unsigned 32-bit value; used to indicate the status response from
+ * firmware/driver for the vendor sub-command.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_STATUS = 2,
+
+ /* GSCAN Valid Channels attributes */
+ /* Unsigned 32bit value; followed by a nested array of CHANNELS. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_CHANNELS = 3,
+ /* An array of NUM_CHANNELS x unsigned 32-bit value integers
+ * representing channel numbers.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CHANNELS = 4,
+
+ /* GSCAN Capabilities attributes */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE = 5,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS = 6,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN
+ = 7,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE
+ = 8,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD
+ = 9,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS = 10,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS
+ = 11,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES
+ = 12,
+
+ /* GSCAN Attributes used with
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE sub-command.
+ */
+
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE = 13,
+
+ /* GSCAN attributes used with
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT sub-command.
+ */
+
+ /* An array of NUM_RESULTS_AVAILABLE x
+ * QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_*
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST = 14,
+
+ /* Unsigned 64-bit value; age of sample at the time of retrieval */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_TIME_STAMP = 15,
+ /* 33 x unsigned 8-bit value; NULL terminated SSID */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_SSID = 16,
+ /* An array of 6 x unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BSSID = 17,
+ /* Unsigned 32-bit value; channel frequency in MHz */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CHANNEL = 18,
+ /* Signed 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RSSI = 19,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT = 20,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_RTT_SD = 21,
+ /* Unsigned 16-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD = 22,
+ /* Unsigned 16-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_CAPABILITY = 23,
+ /* Unsigned 32-bit value; size of the IE DATA blob */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_LENGTH = 24,
+ /* An array of IE_LENGTH x unsigned 8-bit value; blob of all the
+ * information elements found in the beacon; this data should be a
+ * packed list of wifi_information_element objects, one after the
+ * other.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_IE_DATA = 25,
+
+ /* Unsigned 8-bit value; set by driver to indicate more scan results are
+ * available.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_RESULT_MORE_DATA = 26,
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT sub-command.
+ */
+ /* Unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_TYPE = 27,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SCAN_EVENT_STATUS = 28,
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND sub-command.
+ */
+ /* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+ * to indicate number of results.
+ * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the
+ * list of results.
+ */
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE sub-command.
+ */
+ /* An array of 6 x unsigned 8-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID = 29,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL
+ = 30,
+ /* Unsigned 32-bit value. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI
+ = 31,
+ /* A nested array of signed 32-bit RSSI values. Size of the array is
+ * determined by (NUM_RSSI of SIGNIFICANT_CHANGE_RESULT_NUM_RSSI.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST
+ = 32,
+
+ /* GSCAN attributes used with
+ * QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS sub-command.
+ */
+ /* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+ * to indicate number of gscan cached results returned.
+ * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST to indicate
+ * the list of gscan cached results.
+ */
+
+ /* An array of NUM_RESULTS_AVAILABLE x
+ * QCA_NL80211_VENDOR_ATTR_GSCAN_CACHED_RESULTS_*
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_LIST = 33,
+ /* Unsigned 32-bit value; a unique identifier for the scan unit. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_SCAN_ID = 34,
+ /* Unsigned 32-bit value; a bitmask w/additional information about scan.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_CACHED_RESULTS_FLAGS = 35,
+ /* Use attr QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE
+ * to indicate number of wifi scan results/bssids retrieved by the scan.
+ * Also, use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the
+ * list of wifi scan results returned for each cached result block.
+ */
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND sub-command.
+ */
+ /* Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE for
+ * number of results.
+ * Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the nested
+ * list of wifi scan results returned for each
+ * wifi_passpoint_match_result block.
+ * Array size: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_NUM_RESULTS_AVAILABLE.
+ */
+
+ /* GSCAN attributes for
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND sub-command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES
+ = 36,
+ /* A nested array of
+ * QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_*
+ * attributes. Array size =
+ * *_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST = 37,
+
+ /* Unsigned 32-bit value; network block id for the matched network */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID = 38,
+ /* Use QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_LIST to indicate the nested
+ * list of wifi scan results returned for each
+ * wifi_passpoint_match_result block.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN = 39,
+ /* An array size of PASSPOINT_MATCH_ANQP_LEN of unsigned 8-bit values;
+ * ANQP data in the information_element format.
+ */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP = 40,
+
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS = 41,
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS = 42,
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID
+ = 43,
+ /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID
+ = 44,
+
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED = 45,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX =
+ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST - 1,
+};
+
+enum qca_wlan_vendor_attr_pno_config_params {
+ QCA_WLAN_VENDOR_ATTR_PNO_INVALID = 0,
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST sub command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM = 1,
+ /* Array of nested QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_*
+ * attributes. Array size =
+ * QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY = 2,
+
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID = 3,
+ /* An array of 256 x unsigned 8-bit value; NULL terminated UTF-8 encoded
+ * realm, 0 if unspecified.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM = 4,
+ /* An array of 16 x unsigned 32-bit value; roaming consortium ids to
+ * match, 0 if unspecified.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID = 5,
+ /* An array of 6 x unsigned 8-bit value; MCC/MNC combination, 0s if
+ * unspecified.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN = 6,
+
+ /* Attributes for data used by
+ * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST sub command.
+ */
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS = 7,
+ /* Array of nested
+ * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_*
+ * attributes. Array size =
+ * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST = 8,
+ /* An array of 33 x unsigned 8-bit value; NULL terminated SSID */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID = 9,
+ /* Signed 8-bit value; threshold for considering this SSID as found,
+ * required granularity for this threshold is 4 dBm to 8 dBm.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD
+ = 10,
+ /* Unsigned 8-bit value; WIFI_PNO_FLAG_XXX */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS = 11,
+ /* Unsigned 8-bit value; auth bit field for matching WPA IE */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT = 12,
+ /* Unsigned 8-bit to indicate ePNO type;
+ * It takes values from qca_wlan_epno_type
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_TYPE = 13,
+
+ /* Nested attribute to send the channel list */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_CHANNEL_LIST = 14,
+
+ /* Unsigned 32-bit value; indicates the interval between PNO scan
+ * cycles in msec.
+ */
+ QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_SCAN_INTERVAL = 15,
+ QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI = 16,
+ QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI = 17,
+ QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX = 18,
+ QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS = 19,
+ QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS = 20,
+ QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS = 21,
+ QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS = 22,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PNO_MAX =
+ QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_acs_select_reason: This represents the different reasons why
+ * the ACS has to be triggered. These values are used by
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_REASON and
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON
+ */
+enum qca_wlan_vendor_acs_select_reason {
+ /* Represents the reason that the ACS triggered during the AP start */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_INIT,
+ /* Represents the reason that DFS found with the current channel */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS,
+ /* Represents the reason that LTE co-exist in the current band. */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX,
+};
+
+/**
+ * qca_wlan_vendor_channel_prop_flags: This represent the flags for a channel.
+ * This is used by QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS.
+ */
+enum qca_wlan_vendor_channel_prop_flags {
+ /* Bits 0, 1, 2, and 3 are reserved */
+
+ /* Turbo channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_TURBO = 1 << 4,
+ /* CCK channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_CCK = 1 << 5,
+ /* OFDM channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_OFDM = 1 << 6,
+ /* 2.4 GHz spectrum channel. */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_2GHZ = 1 << 7,
+ /* 5 GHz spectrum channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_5GHZ = 1 << 8,
+ /* Only passive scan allowed */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_PASSIVE = 1 << 9,
+ /* Dynamic CCK-OFDM channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_DYN = 1 << 10,
+ /* GFSK channel (FHSS PHY) */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_GFSK = 1 << 11,
+ /* Radar found on channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_RADAR = 1 << 12,
+ /* 11a static turbo channel only */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_STURBO = 1 << 13,
+ /* Half rate channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HALF = 1 << 14,
+ /* Quarter rate channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_QUARTER = 1 << 15,
+ /* HT 20 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT20 = 1 << 16,
+ /* HT 40 with extension channel above */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS = 1 << 17,
+ /* HT 40 with extension channel below */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40MINUS = 1 << 18,
+ /* HT 40 intolerant */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40INTOL = 1 << 19,
+ /* VHT 20 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT20 = 1 << 20,
+ /* VHT 40 with extension channel above */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40PLUS = 1 << 21,
+ /* VHT 40 with extension channel below */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40MINUS = 1 << 22,
+ /* VHT 80 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80 = 1 << 23,
+ /* HT 40 intolerant mark bit for ACS use */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40INTOLMARK = 1 << 24,
+ /* Channel temporarily blocked due to noise */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_BLOCKED = 1 << 25,
+ /* VHT 160 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT160 = 1 << 26,
+ /* VHT 80+80 channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80_80 = 1 << 27,
+};
+
+/**
+ * qca_wlan_vendor_channel_prop_flags_ext: This represent the extended flags for
+ * each channel. This is used by
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAG_EXT.
+ */
+enum qca_wlan_vendor_channel_prop_flags_ext {
+ /* Radar found on channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_RADAR_FOUND = 1 << 0,
+ /* DFS required on channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS = 1 << 1,
+ /* DFS required on channel for 2nd band of 80+80 */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS_CFREQ2 = 1 << 2,
+ /* If channel has been checked for DFS */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS_CLEAR = 1 << 3,
+ /* Excluded in 802.11d */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_11D_EXCLUDED = 1 << 4,
+ /* Channel Switch Announcement received on this channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_CSA_RECEIVED = 1 << 5,
+ /* Ad-hoc is not allowed */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_ADHOC = 1 << 6,
+ /* Station only channel */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_HOSTAP = 1 << 7,
+ /* DFS radar history for slave device (STA mode) */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_HISTORY_RADAR = 1 << 8,
+ /* DFS CAC valid for slave device (STA mode) */
+ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_CAC_VALID = 1 << 9,
+};
+
+/**
+ * qca_wlan_vendor_external_acs_event_chan_info_attr: Represents per channel
+ * information. These attributes are sent as part of
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO. Each set of the following
+ * attributes correspond to a single channel.
+ */
+enum qca_wlan_vendor_external_acs_event_chan_info_attr {
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_INVALID = 0,
+
+ /* A bitmask (u32) with flags specified in
+ * enum qca_wlan_vendor_channel_prop_flags.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS = 1,
+ /* A bitmask (u32) with flags specified in
+ * enum qca_wlan_vendor_channel_prop_flags_ext.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAG_EXT = 2,
+ /* frequency in MHz (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ = 3,
+ /* maximum regulatory transmission power (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_REG_POWER = 4,
+ /* maximum transmission power (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_POWER = 5,
+ /* minimum transmission power (u32) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MIN_POWER = 6,
+ /* regulatory class id (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_REG_CLASS_ID = 7,
+ /* maximum antenna gain in (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_ANTENNA_GAIN = 8,
+ /* VHT segment 0 (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0 = 9,
+ /* VHT segment 1 (u8) */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1 = 10,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_pcl: Represents attributes for
+ * preferred channel list (PCL). These attributes are sent as part of
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL.
+ */
+enum qca_wlan_vendor_attr_pcl {
+ QCA_WLAN_VENDOR_ATTR_PCL_INVALID = 0,
+
+ /* Channel number (u8) */
+ QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL = 1,
+ /* Channel weightage (u8) */
+ QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT = 2,
+};
+
+/**
+ * qca_wlan_vendor_attr_external_acs_event: Attribute to vendor sub-command
+ * QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This attribute will be sent by
+ * host driver.
+ */
+enum qca_wlan_vendor_attr_external_acs_event {
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_INVALID = 0,
+
+ /* This reason (u8) refers to enum qca_wlan_vendor_acs_select_reason.
+ * This helps ACS module to understand why ACS needs to be started.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_REASON = 1,
+ /* Flag attribute to indicate if driver supports spectral scanning */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_SPECTRAL_SUPPORTED = 2,
+ /* Flag attribute to indicate if 11ac is offloaded to firmware */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_OFFLOAD_ENABLED = 3,
+ /* Flag attribute to indicate if driver provides additional channel
+ * capability as part of scan operation */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_ADD_CHAN_STATS_SUPPORT = 4,
+ /* Flag attribute to indicate interface status is UP */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AP_UP = 5,
+ /* Operating mode (u8) of interface. Takes one of enum nl80211_iftype
+ * values. */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_SAP_MODE = 6,
+ /* Channel width (u8). It takes one of enum nl80211_chan_width values.
+ * This is the upper bound of channel width. ACS logic should try to get
+ * a channel with the specified width and if not found, look for lower
+ * values.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_WIDTH = 7,
+ /* This (u8) will hold values of one of enum nl80211_bands */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_BAND = 8,
+ /* PHY/HW mode (u8). Takes one of enum qca_wlan_vendor_acs_hw_mode
+ * values */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PHY_MODE = 9,
+ /* Array of (u32) supported frequency list among which ACS should choose
+ * best frequency.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_FREQ_LIST = 10,
+ /* Preferred channel list by the driver which will have array of nested
+ * values as per enum qca_wlan_vendor_attr_pcl attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL = 11,
+ /* Array of nested attribute for each channel. It takes attr as defined
+ * in enum qca_wlan_vendor_external_acs_event_chan_info_attr.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO = 12,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_MAX =
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_external_acs_channels: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS. This carries a list of channels
+ * in priority order as decided after ACS operation in userspace.
+ */
+enum qca_wlan_vendor_attr_external_acs_channels {
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0,
+
+ /* One of reason code (u8) from enum qca_wlan_vendor_acs_select_reason
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON = 1,
+
+ /* Array of nested values for each channel with following attributes:
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_BAND,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1,
+ * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST = 2,
+ /* This (u8) will hold values of one of enum nl80211_bands */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_BAND = 3,
+ /* Primary channel (u8) */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY = 4,
+ /* Secondary channel (u8) used for HT 40 MHz channels */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY = 5,
+ /* VHT seg0 channel (u8) */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 = 6,
+ /* VHT seg1 channel (u8) */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 = 7,
+ /* Channel width (u8). Takes one of enum nl80211_chan_width values. */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH = 8,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST,
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX =
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST - 1
+};
+
+enum qca_chip_power_save_failure_reason {
+ /* Indicates if the reason for the failure is due to a protocol
+ * layer/module.
+ */
+ QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL = 0,
+ /* Indicates if the reason for the failure is due to a hardware issue.
+ */
+ QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE = 1,
+};
+
+/**
+ * qca_attr_chip_power_save_failure: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE. This carries the requisite
+ * information leading to the power save failure.
+ */
+enum qca_attr_chip_power_save_failure {
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID = 0,
+ /* Reason to cause the power save failure.
+ * These reasons are represented by
+ * enum qca_chip_power_save_failure_reason.
+ */
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON = 1,
+
+ /* keep last */
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST,
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX =
+ QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_attr_nud_stats_set: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET. This carries the requisite
+ * information to start/stop the NUD statistics collection.
+ */
+enum qca_attr_nud_stats_set {
+ QCA_ATTR_NUD_STATS_SET_INVALID = 0,
+
+ /* Flag to start/stop the NUD statistics collection.
+ * Start - If included, Stop - If not included
+ */
+ QCA_ATTR_NUD_STATS_SET_START = 1,
+ /* IPv4 address of the default gateway (in network byte order) */
+ QCA_ATTR_NUD_STATS_GW_IPV4 = 2,
+
+ /* keep last */
+ QCA_ATTR_NUD_STATS_SET_LAST,
+ QCA_ATTR_NUD_STATS_SET_MAX =
+ QCA_ATTR_NUD_STATS_SET_LAST - 1,
+};
+
+/**
+ * qca_attr_nud_stats_get: Attributes to vendor subcmd
+ * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carries the requisite
+ * NUD statistics collected when queried.
+ */
+enum qca_attr_nud_stats_get {
+ QCA_ATTR_NUD_STATS_GET_INVALID = 0,
+ /* ARP Request count from netdev */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1,
+ /* ARP Request count sent to lower MAC from upper MAC */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2,
+ /* ARP Request count received by lower MAC from upper MAC */
+ QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3,
+ /* ARP Request count successfully transmitted by the device */
+ QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4,
+ /* ARP Response count received by lower MAC */
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5,
+ /* ARP Response count received by upper MAC */
+ QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6,
+ /* ARP Response count delivered to netdev */
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7,
+ /* ARP Response count delivered to netdev */
+ QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8,
+ /* Flag indicating if the station's link to the AP is active.
+ * Active Link - If included, Inactive link - If not included
+ */
+ QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE= 9,
+ /* Flag indicating if there is any duplicate address detected (DAD).
+ * Yes - If detected, No - If not detected.
+ */
+ QCA_ATTR_NUD_STATS_IS_DAD = 9,
+
+ /* keep last */
+ QCA_ATTR_NUD_STATS_GET_LAST,
+ QCA_ATTR_NUD_STATS_GET_MAX =
+ QCA_ATTR_NUD_STATS_GET_LAST - 1,
+};
+
+enum qca_wlan_btm_candidate_status {
+ QCA_STATUS_ACCEPT = 0,
+ QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED = 1,
+ QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED = 2,
+ QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY = 3,
+ QCA_STATUS_REJECT_LOW_RSSI = 4,
+ QCA_STATUS_REJECT_HIGH_INTERFERENCE = 5,
+ QCA_STATUS_REJECT_UNKNOWN = 6,
+};
+
+enum qca_wlan_vendor_attr_btm_candidate_info {
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_INVALID = 0,
+
+ /* 6-byte MAC address representing the BSSID of transition candidate */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID = 1,
+ /* Unsigned 32-bit value from enum qca_wlan_btm_candidate_status
+ * returned by the driver. It says whether the BSSID provided in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID is acceptable by
+ * the driver, if not it specifies the reason for rejection.
+ * Note that the user-space can overwrite the transition reject reason
+ * codes provided by driver based on more information.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST - 1,
+};
+
+enum qca_attr_trace_level {
+ QCA_ATTR_TRACE_LEVEL_INVALID = 0,
+ /*
+ * Nested array of the following attributes:
+ * QCA_ATTR_TRACE_LEVEL_MODULE,
+ * QCA_ATTR_TRACE_LEVEL_MASK.
+ */
+ QCA_ATTR_TRACE_LEVEL_PARAM = 1,
+ /*
+ * Specific QCA host driver module. Please refer to the QCA host
+ * driver implementation to get the specific module ID.
+ */
+ QCA_ATTR_TRACE_LEVEL_MODULE = 2,
+ /* Different trace level masks represented in the QCA host driver. */
+ QCA_ATTR_TRACE_LEVEL_MASK = 3,
+
+ /* keep last */
+ QCA_ATTR_TRACE_LEVEL_AFTER_LAST,
+ QCA_ATTR_TRACE_LEVEL_MAX =
+ QCA_ATTR_TRACE_LEVEL_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_he_capabilities - IEEE 802.11ax HE capabilities
+ */
+enum qca_wlan_vendor_attr_get_he_capabilities {
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0,
+ /* Whether HE capabilities is supported
+ * (u8 attribute: 0 = not supported, 1 = supported) */
+ QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED = 1,
+ /* HE PHY capabilities, array of 3 u32 values */
+ QCA_WLAN_VENDOR_ATTR_PHY_CAPAB = 2,
+ /* HE MAC capabilities (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_MAC_CAPAB = 3,
+ /* HE MCS map (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_HE_MCS = 4,
+ /* Number of SS (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_NUM_SS = 5,
+ /* RU count (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK = 6,
+ /* PPE threshold data, array of 8 u32 values */
+ QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX =
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/version.h b/src/common/version.h
index ae5c9d4..16c1004 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.6-devel" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX
+#define VERSION_STR "2.7-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 d6295b2..fd167d6 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -22,25 +22,49 @@
static unsigned int wpa_kck_len(int akmp)
{
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ switch (akmp) {
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
return 24;
- return 16;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 0;
+ default:
+ return 16;
+ }
}
static unsigned int wpa_kek_len(int akmp)
{
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ switch (akmp) {
+ case WPA_KEY_MGMT_FILS_SHA384:
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 64;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
return 32;
- return 16;
+ default:
+ return 16;
+ }
}
unsigned int wpa_mic_len(int akmp)
{
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ switch (akmp) {
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
return 24;
- return 16;
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return 0;
+ default:
+ return 16;
+ }
}
@@ -170,12 +194,12 @@
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
-#ifdef CONFIG_SUITEB192
+#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
if (wpa_key_mgmt_sha384(akmp))
sha384_prf(pmk, pmk_len, label, data, sizeof(data),
tmp, ptk_len);
else
-#endif /* CONFIG_SUITEB192 */
+#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
@@ -204,6 +228,227 @@
return 0;
}
+#ifdef CONFIG_FILS
+
+int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
+ const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
+ size_t dh_ss_len, u8 *pmk, size_t *pmk_len)
+{
+ u8 nonces[2 * FILS_NONCE_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+ size_t num_elem;
+ int res;
+
+ /* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */
+ wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation");
+
+ if (wpa_key_mgmt_sha384(akmp))
+ *pmk_len = SHA384_MAC_LEN;
+ else if (wpa_key_mgmt_sha256(akmp))
+ *pmk_len = SHA256_MAC_LEN;
+ else
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len);
+
+ os_memcpy(nonces, snonce, FILS_NONCE_LEN);
+ os_memcpy(&nonces[FILS_NONCE_LEN], anonce, FILS_NONCE_LEN);
+ addr[0] = rmsk;
+ len[0] = rmsk_len;
+ num_elem = 1;
+ if (dh_ss) {
+ addr[1] = dh_ss;
+ len[1] = dh_ss_len;
+ num_elem++;
+ }
+ if (wpa_key_mgmt_sha384(akmp))
+ res = hmac_sha384_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
+ addr, len, pmk);
+ else
+ res = hmac_sha256_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
+ addr, len, pmk);
+ if (res == 0)
+ wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
+ return res;
+}
+
+
+int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
+ u8 *pmkid)
+{
+ const u8 *addr[1];
+ size_t len[1];
+ u8 hash[SHA384_MAC_LEN];
+ int res;
+
+ /* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */
+ addr[0] = reauth;
+ len[0] = reauth_len;
+ if (wpa_key_mgmt_sha384(akmp))
+ res = sha384_vector(1, addr, len, hash);
+ else if (wpa_key_mgmt_sha256(akmp))
+ res = sha256_vector(1, addr, len, hash);
+ else
+ return -1;
+ if (res)
+ return res;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
+ return 0;
+}
+
+
+int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
+ const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
+ u8 *ick, size_t *ick_len, int akmp, int cipher)
+{
+ u8 data[2 * ETH_ALEN + 2 * FILS_NONCE_LEN];
+ u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t key_data_len;
+ const char *label = "FILS PTK Derivation";
+
+ /*
+ * FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
+ * SPA || AA || SNonce || ANonce)
+ * ICK = L(FILS-Key-Data, 0, ICK_bits)
+ * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits)
+ * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits)
+ * If doing FT initial mobility domain association:
+ * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
+ * FILS-FT_bits)
+ */
+ os_memcpy(data, spa, ETH_ALEN);
+ os_memcpy(data + ETH_ALEN, aa, ETH_ALEN);
+ os_memcpy(data + 2 * ETH_ALEN, snonce, FILS_NONCE_LEN);
+ os_memcpy(data + 2 * ETH_ALEN + FILS_NONCE_LEN, anonce, FILS_NONCE_LEN);
+
+ ptk->kck_len = 0;
+ ptk->kek_len = wpa_kek_len(akmp);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ if (wpa_key_mgmt_sha384(akmp))
+ *ick_len = 48;
+ else if (wpa_key_mgmt_sha256(akmp))
+ *ick_len = 32;
+ else
+ return -1;
+ key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
+
+ if (wpa_key_mgmt_sha384(akmp))
+ sha384_prf(pmk, pmk_len, label, data, sizeof(data),
+ tmp, key_data_len);
+ else if (sha256_prf(pmk, pmk_len, label, data, sizeof(data),
+ tmp, key_data_len) < 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "FILS: PTK derivation - SPA=" MACSTR
+ " AA=" MACSTR, MAC2STR(spa), MAC2STR(aa));
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, pmk_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
+
+ os_memcpy(ick, tmp, *ick_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
+
+ os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
+
+ os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
+
+ /* TODO: FILS-FT */
+
+ os_memset(tmp, 0, sizeof(tmp));
+ return 0;
+}
+
+
+int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
+ const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
+ const u8 *g_sta, size_t g_sta_len,
+ const u8 *g_ap, size_t g_ap_len,
+ int akmp, u8 *key_auth_sta, u8 *key_auth_ap,
+ size_t *key_auth_len)
+{
+ const u8 *addr[6];
+ size_t len[6];
+ size_t num_elem = 4;
+ int res;
+
+ /*
+ * For (Re)Association Request frame (STA->AP):
+ * Key-Auth = HMAC-Hash(ICK, SNonce || ANonce || STA-MAC || AP-BSSID
+ * [ || gSTA || gAP ])
+ */
+ addr[0] = snonce;
+ len[0] = FILS_NONCE_LEN;
+ addr[1] = anonce;
+ len[1] = FILS_NONCE_LEN;
+ addr[2] = sta_addr;
+ len[2] = ETH_ALEN;
+ addr[3] = bssid;
+ len[3] = ETH_ALEN;
+ if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ addr[4] = g_sta;
+ len[4] = g_sta_len;
+ addr[5] = g_ap;
+ len[5] = g_ap_len;
+ num_elem = 6;
+ }
+
+ if (wpa_key_mgmt_sha384(akmp)) {
+ *key_auth_len = 48;
+ res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_sta);
+ } else if (wpa_key_mgmt_sha256(akmp)) {
+ *key_auth_len = 32;
+ res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_sta);
+ } else {
+ return -1;
+ }
+ if (res < 0)
+ return res;
+
+ /*
+ * For (Re)Association Response frame (AP->STA):
+ * Key-Auth = HMAC-Hash(ICK, ANonce || SNonce || AP-BSSID || STA-MAC
+ * [ || gAP || gSTA ])
+ */
+ addr[0] = anonce;
+ addr[1] = snonce;
+ addr[2] = bssid;
+ addr[3] = sta_addr;
+ if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ addr[4] = g_ap;
+ len[4] = g_ap_len;
+ addr[5] = g_sta;
+ len[5] = g_sta_len;
+ }
+
+ if (wpa_key_mgmt_sha384(akmp))
+ res = hmac_sha384_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_ap);
+ else if (wpa_key_mgmt_sha256(akmp))
+ res = hmac_sha256_vector(ick, ick_len, num_elem, addr, len,
+ key_auth_ap);
+ if (res < 0)
+ return res;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (STA)",
+ key_auth_sta, *key_auth_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: Key-Auth (AP)",
+ key_auth_ap, *key_auth_len);
+
+ return 0;
+}
+
+#endif /* CONFIG_FILS */
+
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
@@ -376,6 +621,8 @@
}
if (data.num_pmkid == 1 && data.pmkid)
parse->rsn_pmkid = data.pmkid;
+ parse->key_mgmt = data.key_mgmt;
+ parse->pairwise_cipher = data.pairwise_cipher;
break;
case WLAN_EID_MOBILITY_DOMAIN:
if (len < sizeof(struct rsn_mdie))
@@ -510,6 +757,14 @@
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA256)
+ return WPA_KEY_MGMT_FILS_SHA256;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FILS_SHA384)
+ return WPA_KEY_MGMT_FILS_SHA384;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA256)
+ return WPA_KEY_MGMT_FT_FILS_SHA256;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_FILS_SHA384)
+ return WPA_KEY_MGMT_FT_FILS_SHA384;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
return WPA_KEY_MGMT_OSEN;
return 0;
@@ -849,10 +1104,10 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.3
*/
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
- const u8 *ssid, size_t ssid_len,
- const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
{
u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
@@ -869,7 +1124,7 @@
* PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
*/
if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
- return;
+ return -1;
pos = buf;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
@@ -882,8 +1137,9 @@
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
- r0_key_data, sizeof(r0_key_data));
+ if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, sizeof(r0_key_data)) < 0)
+ return -1;
os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
/*
@@ -894,8 +1150,10 @@
addr[1] = r0_key_data + PMK_LEN;
len[1] = 16;
- sha256_vector(2, addr, len, hash);
+ if (sha256_vector(2, addr, len, hash) < 0)
+ return -1;
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+ return 0;
}
@@ -904,8 +1162,8 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+ const u8 *s1kh_id, u8 *pmk_r1_name)
{
u8 hash[32];
const u8 *addr[4];
@@ -924,8 +1182,10 @@
addr[3] = s1kh_id;
len[3] = ETH_ALEN;
- sha256_vector(4, addr, len, hash);
+ if (sha256_vector(4, addr, len, hash) < 0)
+ return -1;
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+ return 0;
}
@@ -934,9 +1194,9 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
- const u8 *r1kh_id, const u8 *s1kh_id,
- u8 *pmk_r1, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ u8 *pmk_r1, u8 *pmk_r1_name)
{
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
u8 *pos;
@@ -948,9 +1208,12 @@
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+ if (sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf,
+ pmk_r1, PMK_LEN) < 0)
+ return -1;
- wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+ return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
+ pmk_r1_name);
}
@@ -990,7 +1253,9 @@
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
- sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
+ if (sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf,
+ tmp, ptk_len) < 0)
+ return -1;
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -1009,7 +1274,8 @@
addr[5] = sta_addr;
len[5] = ETH_ALEN;
- sha256_vector(6, addr, len, hash);
+ if (sha256_vector(6, addr, len, hash) < 0)
+ return -1;
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
os_memcpy(ptk->kck, tmp, ptk->kck_len);
@@ -1184,6 +1450,8 @@
"WPA2-PSK" : "WPA-PSK";
case WPA_KEY_MGMT_NONE:
return "NONE";
+ case WPA_KEY_MGMT_WPA_NONE:
+ return "WPA-NONE";
case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
return "IEEE 802.1X (no WPA)";
#ifdef CONFIG_IEEE80211R
@@ -1210,6 +1478,14 @@
return "WPA2-EAP-SUITE-B";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
return "WPA2-EAP-SUITE-B-192";
+ case WPA_KEY_MGMT_FILS_SHA256:
+ return "FILS-SHA256";
+ case WPA_KEY_MGMT_FILS_SHA384:
+ return "FILS-SHA384";
+ case WPA_KEY_MGMT_FT_FILS_SHA256:
+ return "FT-FILS-SHA256";
+ case WPA_KEY_MGMT_FT_FILS_SHA384:
+ return "FT-FILS-SHA384";
default:
return "UNKNOWN";
}
@@ -1219,27 +1495,33 @@
u32 wpa_akm_to_suite(int akm)
{
if (akm & WPA_KEY_MGMT_FT_IEEE8021X)
- return WLAN_AKM_SUITE_FT_8021X;
+ return RSN_AUTH_KEY_MGMT_FT_802_1X;
if (akm & WPA_KEY_MGMT_FT_PSK)
- return WLAN_AKM_SUITE_FT_PSK;
- if (akm & WPA_KEY_MGMT_IEEE8021X)
- return WLAN_AKM_SUITE_8021X;
+ return RSN_AUTH_KEY_MGMT_FT_PSK;
if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256)
- return WLAN_AKM_SUITE_8021X_SHA256;
+ return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
if (akm & WPA_KEY_MGMT_IEEE8021X)
- return WLAN_AKM_SUITE_8021X;
+ return RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (akm & WPA_KEY_MGMT_PSK_SHA256)
- return WLAN_AKM_SUITE_PSK_SHA256;
+ return RSN_AUTH_KEY_MGMT_PSK_SHA256;
if (akm & WPA_KEY_MGMT_PSK)
- return WLAN_AKM_SUITE_PSK;
+ return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
if (akm & WPA_KEY_MGMT_CCKM)
- return WLAN_AKM_SUITE_CCKM;
+ return RSN_AUTH_KEY_MGMT_CCKM;
if (akm & WPA_KEY_MGMT_OSEN)
- return WLAN_AKM_SUITE_OSEN;
+ return RSN_AUTH_KEY_MGMT_OSEN;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
- return WLAN_AKM_SUITE_8021X_SUITE_B;
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
- return WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
+ if (akm & WPA_KEY_MGMT_FILS_SHA256)
+ return RSN_AUTH_KEY_MGMT_FILS_SHA256;
+ if (akm & WPA_KEY_MGMT_FILS_SHA384)
+ return RSN_AUTH_KEY_MGMT_FILS_SHA384;
+ if (akm & WPA_KEY_MGMT_FT_FILS_SHA256)
+ return RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
+ if (akm & WPA_KEY_MGMT_FT_FILS_SHA384)
+ return RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
return 0;
}
@@ -1281,7 +1563,7 @@
}
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
@@ -1380,7 +1662,7 @@
return 0;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_FILS */
int wpa_cipher_key_len(int cipher)
@@ -1419,7 +1701,7 @@
}
-int wpa_cipher_to_alg(int cipher)
+enum wpa_alg wpa_cipher_to_alg(int cipher)
{
switch (cipher) {
case WPA_CIPHER_CCMP_256:
@@ -1703,3 +1985,29 @@
return WPA_CIPHER_CCMP_256;
return WPA_CIPHER_CCMP;
}
+
+
+#ifdef CONFIG_FILS
+int fils_domain_name_hash(const char *domain, u8 *hash)
+{
+ char buf[255], *wpos = buf;
+ const char *pos = domain;
+ size_t len;
+ const u8 *addr[1];
+ u8 mac[SHA256_MAC_LEN];
+
+ for (len = 0; len < sizeof(buf) && *pos; len++) {
+ if (isalpha(*pos) && isupper(*pos))
+ *wpos++ = tolower(*pos);
+ else
+ *wpos++ = *pos;
+ pos++;
+ }
+
+ addr[0] = (const u8 *) buf;
+ if (sha256_vector(1, addr, &len, mac) < 0)
+ return -1;
+ os_memcpy(hash, mac, 2);
+ return 0;
+}
+#endif /* CONFIG_FILS */
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 1021ccb..5733c75 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -48,10 +48,8 @@
#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
-#ifdef CONFIG_IEEE80211R
#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#endif /* CONFIG_IEEE80211R */
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
@@ -61,15 +59,21 @@
#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_AUTH_KEY_MGMT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 14)
+#define RSN_AUTH_KEY_MGMT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 15)
+#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
+#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
+#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#if 0
#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#endif
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
@@ -78,6 +82,12 @@
#define RSN_CIPHER_SUITE_BIP_GMAC_128 RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
#define RSN_CIPHER_SUITE_BIP_GMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define RSN_CIPHER_SUITE_BIP_CMAC_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
+#define RSN_CIPHER_SUITE_SMS4 RSN_SELECTOR(0x00, 0x14, 0x72, 1)
+#define RSN_CIPHER_SUITE_CKIP RSN_SELECTOR(0x00, 0x40, 0x96, 0)
+#define RSN_CIPHER_SUITE_CKIP_CMIC RSN_SELECTOR(0x00, 0x40, 0x96, 1)
+#define RSN_CIPHER_SUITE_CMIC RSN_SELECTOR(0x00, 0x40, 0x96, 2)
+/* KRK is defined for nl80211 use only */
+#define RSN_CIPHER_SUITE_KRK RSN_SELECTOR(0x00, 0x40, 0x96, 255)
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
@@ -179,30 +189,16 @@
u8 key_iv[16];
u8 key_rsc[WPA_KEY_RSC_LEN];
u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
- u8 key_mic[16];
- u8 key_data_length[2]; /* big endian */
- /* followed by key_data_length bytes of key_data */
-} STRUCT_PACKED;
-
-struct wpa_eapol_key_192 {
- u8 type;
- /* Note: key_info, key_length, and key_data_length are unaligned */
- u8 key_info[2]; /* big endian */
- u8 key_length[2]; /* big endian */
- u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
- u8 key_nonce[WPA_NONCE_LEN];
- u8 key_iv[16];
- u8 key_rsc[WPA_KEY_RSC_LEN];
- u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
- u8 key_mic[24];
- u8 key_data_length[2]; /* big endian */
- /* followed by key_data_length bytes of key_data */
+ /* variable length Key MIC field */
+ /* big endian 2-octet Key Data Length field */
+ /* followed by Key Data Length bytes of Key Data */
} STRUCT_PACKED;
#define WPA_EAPOL_KEY_MIC_MAX_LEN 24
#define WPA_KCK_MAX_LEN 24
-#define WPA_KEK_MAX_LEN 32
+#define WPA_KEK_MAX_LEN 64
#define WPA_TK_MAX_LEN 32
+#define FILS_ICK_MAX_LEN 48
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -352,6 +348,20 @@
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
struct wpa_ptk *ptk, int akmp, int cipher);
+int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
+ const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
+ size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
+int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
+ u8 *pmkid);
+int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
+ const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
+ u8 *ick, size_t *ick_len, int akmp, int cipher);
+int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
+ const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
+ const u8 *g_sta, size_t g_sta_len,
+ const u8 *g_ap, size_t g_ap_len,
+ int akmp, u8 *key_auth_sta, u8 *key_auth_ap,
+ size_t *key_auth_len);
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
@@ -360,15 +370,15 @@
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
- const u8 *ssid, size_t ssid_len,
- const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name);
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
- const u8 *r1kh_id, const u8 *s1kh_id,
- u8 *pmk_r1, u8 *pmk_r1_name);
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+ const u8 *s1kh_id, u8 *pmk_r1_name);
+int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ u8 *pmk_r1, u8 *pmk_r1_name);
int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
@@ -442,13 +452,15 @@
size_t igtk_len;
const u8 *ric;
size_t ric_len;
+ int key_mgmt;
+ int pairwise_cipher;
};
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
-int wpa_cipher_to_alg(int cipher);
+enum wpa_alg wpa_cipher_to_alg(int cipher);
int wpa_cipher_valid_group(int cipher);
int wpa_cipher_valid_pairwise(int cipher);
int wpa_cipher_valid_mgmt_group(int cipher);
@@ -461,5 +473,6 @@
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
unsigned int wpa_mic_len(int akmp);
+int fils_domain_name_hash(const char *domain, u8 *hash);
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index d9641bb..4649eab 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -74,8 +74,12 @@
#define WPA_EVENT_NETWORK_NOT_FOUND "CTRL-EVENT-NETWORK-NOT-FOUND "
/** Change in the signal level was reported by the driver */
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
+/** Beacon loss reported by the driver */
+#define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS "
/** Regulatory domain channel */
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
+/** Channel switch (followed by freq=<MHz> and other channel parameters) */
+#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
/** IP subnet status change notification
*
@@ -187,6 +191,7 @@
#define P2P_EVENT_SERV_ASP_RESP "P2P-SERV-ASP-RESP "
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_INVITATION_ACCEPTED "P2P-INVITATION-ACCEPTED "
#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
#define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE "
@@ -225,6 +230,11 @@
/* parameters: <addr> <result> */
#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+#define RX_ANQP "RX-ANQP "
+#define RX_HS20_ANQP "RX-HS20-ANQP "
+#define RX_HS20_ANQP_ICON "RX-HS20-ANQP-ICON "
+#define RX_HS20_ICON "RX-HS20-ICON "
+
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
@@ -245,6 +255,7 @@
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
+#define AP_STA_POLL_OK "AP-STA-POLL-OK "
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
@@ -267,6 +278,9 @@
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
+#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
+#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
+
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
@@ -276,6 +290,20 @@
/* BSS Transition Management Request received with MBO transition reason */
#define MBO_TRANSITION_REASON "MBO-TRANSITION-REASON "
+/* parameters: <STA address> <dialog token> <ack=0/1> */
+#define BEACON_REQ_TX_STATUS "BEACON-REQ-TX-STATUS "
+/* parameters: <STA address> <dialog token> <report mode> <beacon report> */
+#define BEACON_RESP_RX "BEACON-RESP-RX "
+
+/* PMKSA cache entry added; parameters: <BSSID> <network_id> */
+#define PMKSA_CACHE_ADDED "PMKSA-CACHE-ADDED "
+/* PMKSA cache entry removed; parameters: <BSSID> <network_id> */
+#define PMKSA_CACHE_REMOVED "PMKSA-CACHE-REMOVED "
+
+/* FILS HLP Container receive; parameters: dst=<addr> src=<addr> frame=<hexdump>
+ */
+#define FILS_HLP_RX "FILS-HLP-RX "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
@@ -301,6 +329,9 @@
#define WPA_BSS_MASK_SNR BIT(19)
#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20)
#define WPA_BSS_MASK_FST BIT(21)
+#define WPA_BSS_MASK_UPDATE_IDX BIT(22)
+#define WPA_BSS_MASK_BEACON_IE BIT(23)
+#define WPA_BSS_MASK_FILS_INDICATION BIT(24)
/* VENDOR_ELEM_* frame id values */
@@ -319,6 +350,7 @@
VENDOR_ELEM_P2P_ASSOC_REQ = 11,
VENDOR_ELEM_P2P_ASSOC_RESP = 12,
VENDOR_ELEM_ASSOC_REQ = 13,
+ VENDOR_ELEM_PROBE_REQ = 14,
NUM_VENDOR_ELEM_FRAMES
};
diff --git a/src/crypto/aes-ctr.c b/src/crypto/aes-ctr.c
index d4d874d..e27f3bb 100644
--- a/src/crypto/aes-ctr.c
+++ b/src/crypto/aes-ctr.c
@@ -1,5 +1,5 @@
/*
- * AES-128 CTR
+ * AES-128/192/256 CTR
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -14,15 +14,16 @@
#include "aes_wrap.h"
/**
- * aes_128_ctr_encrypt - AES-128 CTR mode encryption
- * @key: Key for encryption (16 bytes)
+ * aes_ctr_encrypt - AES-128/192/256 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @key_len: Length of the key (16, 24, or 32 bytes)
* @nonce: Nonce for counter mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* Returns: 0 on success, -1 on failure
*/
-int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
- u8 *data, size_t data_len)
+int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
+ u8 *data, size_t data_len)
{
void *ctx;
size_t j, len, left = data_len;
@@ -30,7 +31,7 @@
u8 *pos = data;
u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
- ctx = aes_encrypt_init(key, 16);
+ ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memcpy(counter, nonce, AES_BLOCK_SIZE);
@@ -53,3 +54,18 @@
aes_encrypt_deinit(ctx);
return 0;
}
+
+
+/**
+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (key_len bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len)
+{
+ return aes_ctr_encrypt(key, 16, nonce, data, data_len);
+}
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
index 5ac82c2..2bb79b5 100644
--- a/src/crypto/aes-siv.c
+++ b/src/crypto/aes-siv.c
@@ -61,26 +61,33 @@
}
-static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
- size_t *len, u8 *mac)
+static int aes_s2v(const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
{
u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
u8 *buf = NULL;
int ret;
size_t i;
+ const u8 *data[1];
+ size_t data_len[1];
if (!num_elem) {
os_memcpy(tmp, zero, sizeof(zero));
tmp[AES_BLOCK_SIZE - 1] = 1;
- return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ data[0] = tmp;
+ data_len[0] = sizeof(tmp);
+ return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
- ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+ data[0] = zero;
+ data_len[0] = sizeof(zero);
+ ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp);
if (ret)
return ret;
for (i = 0; i < num_elem - 1; i++) {
- ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+ ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i],
+ tmp2);
if (ret)
return ret;
@@ -94,7 +101,8 @@
os_memcpy(buf, addr[i], len[i]);
xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
- ret = omac1_aes_128(key, buf, len[i], mac);
+ data[0] = buf;
+ ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac);
bin_clear_free(buf, len[i]);
return ret;
}
@@ -103,24 +111,32 @@
pad_block(tmp2, addr[i], len[i]);
xor(tmp, tmp2);
- return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ data[0] = tmp;
+ data_len[0] = sizeof(tmp);
+ return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
}
-int aes_siv_encrypt(const u8 *key, const u8 *pw,
- size_t pwlen, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *out)
+int aes_siv_encrypt(const u8 *key, size_t key_len,
+ const u8 *pw, size_t pwlen,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
- const u8 *k1 = key, *k2 = key + 16;
+ const u8 *k1, *k2;
u8 v[AES_BLOCK_SIZE];
size_t i;
u8 *iv, *crypt_pw;
- if (num_elem > ARRAY_SIZE(_addr) - 1)
+ if (num_elem > ARRAY_SIZE(_addr) - 1 ||
+ (key_len != 32 && key_len != 48 && key_len != 64))
return -1;
+ key_len /= 2;
+ k1 = key;
+ k2 = key + key_len;
+
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
_len[i] = len[i];
@@ -128,7 +144,7 @@
_addr[num_elem] = pw;
_len[num_elem] = pwlen;
- if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+ if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v))
return -1;
iv = out;
@@ -140,26 +156,31 @@
/* zero out 63rd and 31st bits of ctr (from right) */
v[8] &= 0x7f;
v[12] &= 0x7f;
- return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+ return aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen);
}
-int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+int aes_siv_decrypt(const u8 *key, size_t key_len,
+ const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out)
{
const u8 *_addr[6];
size_t _len[6];
- const u8 *k1 = key, *k2 = key + 16;
+ const u8 *k1, *k2;
size_t crypt_len;
size_t i;
int ret;
u8 iv[AES_BLOCK_SIZE];
u8 check[AES_BLOCK_SIZE];
- if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1)
+ if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 ||
+ (key_len != 32 && key_len != 48 && key_len != 64))
return -1;
crypt_len = iv_c_len - AES_BLOCK_SIZE;
+ key_len /= 2;
+ k1 = key;
+ k2 = key + key_len;
for (i = 0; i < num_elem; i++) {
_addr[i] = addr[i];
@@ -174,11 +195,11 @@
iv[8] &= 0x7f;
iv[12] &= 0x7f;
- ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+ ret = aes_ctr_encrypt(k2, key_len, iv, out, crypt_len);
if (ret)
return ret;
- ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+ ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check);
if (ret)
return ret;
if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
diff --git a/src/crypto/aes_siv.h b/src/crypto/aes_siv.h
index 463cf65..fb05d80 100644
--- a/src/crypto/aes_siv.h
+++ b/src/crypto/aes_siv.h
@@ -9,10 +9,12 @@
#ifndef AES_SIV_H
#define AES_SIV_H
-int aes_siv_encrypt(const u8 *key, const u8 *pw,
- size_t pwlen, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *out);
-int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+int aes_siv_encrypt(const u8 *key, size_t key_len,
+ const u8 *pw, size_t pwlen,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out);
+int aes_siv_decrypt(const u8 *key, size_t key_len,
+ const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *out);
diff --git a/src/crypto/aes_wrap.h b/src/crypto/aes_wrap.h
index 4a14209..b70b1d2 100644
--- a/src/crypto/aes_wrap.h
+++ b/src/crypto/aes_wrap.h
@@ -3,7 +3,7 @@
*
* - AES Key Wrap Algorithm (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
- * - AES-128 CTR mode encryption
+ * - AES-128/192/256 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
* - AES-GCM
@@ -33,6 +33,8 @@
int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+int __must_check aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
+ u8 *data, size_t data_len);
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
int __must_check aes_128_eax_encrypt(const u8 *key,
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index 087953b..0fa06d9 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "crypto/aes_siv.h"
#include "crypto/aes_wrap.h"
#include "crypto/aes.h"
@@ -16,6 +17,7 @@
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
static int test_siv(void)
@@ -91,7 +93,7 @@
addr[0] = ad;
len[0] = sizeof(ad);
- if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
+ if (aes_siv_encrypt(key, sizeof(key), plaintext, sizeof(plaintext),
1, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
return 1;
@@ -102,7 +104,8 @@
return 1;
}
- if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
+ if (aes_siv_decrypt(key, sizeof(key), iv_c, sizeof(iv_c),
+ 1, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
return 1;
}
@@ -120,7 +123,8 @@
addr[2] = nonce_2;
len[2] = sizeof(nonce_2);
- if (aes_siv_encrypt(key_2, plaintext_2, sizeof(plaintext_2),
+ if (aes_siv_encrypt(key_2, sizeof(key_2),
+ plaintext_2, sizeof(plaintext_2),
3, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
return 1;
@@ -131,7 +135,8 @@
return 1;
}
- if (aes_siv_decrypt(key_2, iv_c_2, sizeof(iv_c_2), 3, addr, len, out)) {
+ if (aes_siv_decrypt(key_2, sizeof(key_2), iv_c_2, sizeof(iv_c_2),
+ 3, addr, len, out)) {
wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
return 1;
}
@@ -1266,7 +1271,7 @@
}
-const struct {
+static const struct {
char *data;
u8 hash[32];
} tests[] = {
@@ -1290,14 +1295,15 @@
}
};
-const struct hmac_test {
- u8 key[80];
+static const struct hmac_test {
+ u8 key[150];
size_t key_len;
- u8 data[128];
+ u8 data[160];
size_t data_len;
- u8 hash[32];
+ u8 hash[32]; /* HMAC-SHA-256 */
+ u8 hash384[48]; /* HMAC-SHA-384 */
} hmac_tests[] = {
- /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+ /* draft-ietf-ipsec-ciph-sha-256-01.txt; RFC 4231 */
{
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -1312,7 +1318,8 @@
0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
- }
+ },
+ { }
},
{
{
@@ -1329,7 +1336,8 @@
0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
- }
+ },
+ { }
},
{
{
@@ -1347,7 +1355,8 @@
0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
- }
+ },
+ { }
},
{
{
@@ -1364,9 +1373,34 @@
0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 1 */
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+ },
+ 20,
+ "Hi There",
+ 8,
+ {
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+ 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+ 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+ 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7
+ },
+ {
+ 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+ 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+ 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+ 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+ 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6
}
},
- {
+ { /* RFC 4231 - Test Case 2 */
"Jefe",
4,
"what do ya want for nothing?",
@@ -1376,6 +1410,14 @@
0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ },
+ {
+ 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+ 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+ 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+ 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+ 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49
}
},
{
@@ -1401,6 +1443,39 @@
0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 3 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 20,
+ {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ },
+ 50,
+ {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+ 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+ 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+ 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe
+ },
+ {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a,
+ 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f,
+ 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b,
+ 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9,
+ 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27
}
},
{
@@ -1427,6 +1502,40 @@
0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 4 */
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ 25,
+ {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ },
+ 50,
+ {
+ 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+ 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+ 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+ 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b
+ },
+ {
+ 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85,
+ 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7,
+ 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+ 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e,
+ 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79,
+ 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb
}
},
{
@@ -1444,7 +1553,8 @@
0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
- }
+ },
+ { }
},
{
{
@@ -1467,6 +1577,45 @@
0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 6 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ 54,
+ {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+ 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+ 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+ },
+ {
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+ 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+ 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+ 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+ 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52
}
},
{
@@ -1491,6 +1640,45 @@
0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 7 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ 152,
+ {
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+ 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+ 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+ 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2
+ },
+ {
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+ 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+ 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+ 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+ 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e
}
}
};
@@ -1605,6 +1793,96 @@
}
+static int test_sha384(void)
+{
+#ifdef CONFIG_SHA384
+ unsigned int i;
+ u8 hash[48];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+ const char *data = "hello";
+ const u8 hash_res[] = {
+ 0x59, 0xe1, 0x74, 0x87, 0x77, 0x44, 0x8c, 0x69,
+ 0xde, 0x6b, 0x80, 0x0d, 0x7a, 0x33, 0xbb, 0xfb,
+ 0x9f, 0xf1, 0xb4, 0x63, 0xe4, 0x43, 0x54, 0xc3,
+ 0x55, 0x3b, 0xcd, 0xb9, 0xc6, 0x66, 0xfa, 0x90,
+ 0x12, 0x5a, 0x3c, 0x79, 0xf9, 0x03, 0x97, 0xbd,
+ 0xf5, 0xf6, 0xa1, 0x3d, 0xe8, 0x28, 0x68, 0x4f
+ };
+
+ addr[0] = (const u8 *) data;
+ len[0] = 5;
+ if (sha384_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: OK");
+ }
+
+ addr[0] = (const u8 *) data;
+ len[0] = 4;
+ addr[1] = (const u8 *) data + 4;
+ len[1] = 1;
+ if (sha384_vector(2, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: OK");
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+ const struct hmac_test *t = &hmac_tests[i];
+
+ if (t->hash384[0] == 0 && t->hash384[1] == 0 &&
+ t->hash384[2] == 0 && t->hash384[3] == 0)
+ continue;
+ wpa_printf(MSG_INFO, "HMAC-SHA384 test case %d:", i + 1);
+
+ if (hmac_sha384(t->key, t->key_len, t->data, t->data_len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ addr[0] = t->data;
+ len[0] = t->data_len;
+ if (hmac_sha384_vector(t->key, t->key_len, 1, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = t->data;
+ len[0] = 1;
+ addr[1] = t->data + 1;
+ len[1] = t->data_len - 1;
+ if (hmac_sha384_vector(t->key, t->key_len, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "SHA384 test cases passed");
+ return errors;
+#else /* CONFIG_SHA384 */
+ return 0;
+#endif /* CONFIG_SHA384 */
+}
+
+
static int test_fips186_2_prf(void)
{
/* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
@@ -1750,6 +2028,7 @@
test_md5() ||
test_sha1() ||
test_sha256() ||
+ test_sha384() ||
test_fips186_2_prf() ||
test_ms_funcs())
ret = -1;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index c5a28ce..5f7896c 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -29,6 +29,8 @@
#include "sha1.h"
#include "sha256.h"
#include "sha384.h"
+#include "md5.h"
+#include "aes_wrap.h"
#include "crypto.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
@@ -47,6 +49,8 @@
static void HMAC_CTX_free(HMAC_CTX *ctx)
{
+ if (!ctx)
+ return;
HMAC_CTX_cleanup(ctx);
bin_clear_free(ctx, sizeof(*ctx));
}
@@ -65,6 +69,9 @@
static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
{
+ if (!ctx)
+ return;
+ EVP_MD_CTX_cleanup(ctx);
bin_clear_free(ctx, sizeof(*ctx));
}
@@ -72,7 +79,11 @@
static BIGNUM * get_group5_prime(void)
{
-#ifdef OPENSSL_IS_BORINGSSL
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ return BN_get_rfc3526_prime_1536(NULL);
+#elif !defined(OPENSSL_IS_BORINGSSL)
+ return get_rfc3526_prime_1536(NULL);
+#else
static const unsigned char RFC3526_PRIME_1536[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
@@ -92,14 +103,15 @@
0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
-#else /* OPENSSL_IS_BORINGSSL */
- return get_rfc3526_prime_1536(NULL);
-#endif /* OPENSSL_IS_BORINGSSL */
+#endif
}
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
#endif
+#ifdef OPENSSL_NO_SHA512
+#define NO_SHA384_WRAPPER
+#endif
static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
@@ -233,6 +245,14 @@
}
#endif /* NO_SHA256_WRAPPER */
+#ifndef NO_SHA384_WRAPPER
+int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ return openssl_digest_vector(EVP_sha384(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA384_WRAPPER */
+
static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
{
@@ -363,6 +383,8 @@
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
@@ -377,6 +399,8 @@
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
@@ -602,11 +626,13 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
*priv = NULL;
+ wpabuf_free(*publ);
*publ = NULL;
dh = DH_new();
@@ -645,11 +671,63 @@
wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
+#else
+ DH *dh;
+ struct wpabuf *pubkey = NULL, *privkey = NULL;
+ size_t publen, privlen;
+ BIGNUM *p = NULL, *g;
+ const BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ g = BN_new();
+ p = get_group5_prime();
+ if (!g || BN_set_word(g, 2) != 1 || !p ||
+ DH_set0_pqg(dh, p, NULL, g) != 1)
+ goto err;
+ p = NULL;
+ g = NULL;
+
+ if (DH_generate_key(dh) != 1)
+ goto err;
+
+ DH_get0_key(dh, &pub_key, &priv_key);
+ publen = BN_num_bytes(pub_key);
+ pubkey = wpabuf_alloc(publen);
+ if (!pubkey)
+ goto err;
+ privlen = BN_num_bytes(priv_key);
+ privkey = wpabuf_alloc(privlen);
+ if (!privkey)
+ goto err;
+
+ BN_bn2bin(pub_key, wpabuf_put(pubkey, publen));
+ BN_bn2bin(priv_key, wpabuf_put(privkey, privlen));
+
+ *priv = privkey;
+ *publ = pubkey;
+ return dh;
+
+err:
+ BN_free(p);
+ BN_free(g);
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
+ DH_free(dh);
+ return NULL;
+#endif
}
void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
DH *dh;
dh = DH_new();
@@ -680,6 +758,42 @@
err:
DH_free(dh);
return NULL;
+#else
+ DH *dh;
+ BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL;
+
+ dh = DH_new();
+ if (dh == NULL)
+ return NULL;
+
+ g = BN_new();
+ p = get_group5_prime();
+ if (!g || BN_set_word(g, 2) != 1 || !p ||
+ DH_set0_pqg(dh, p, NULL, g) != 1)
+ goto err;
+ p = NULL;
+ g = NULL;
+
+ priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+ pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+ if (!priv_key || !pub_key || DH_set0_key(dh, pub_key, priv_key) != 1)
+ goto err;
+ pub_key = NULL;
+ priv_key = NULL;
+
+ if (DH_generate_key(dh) != 1)
+ goto err;
+
+ return dh;
+
+err:
+ BN_free(p);
+ BN_free(g);
+ BN_free(pub_key);
+ BN_clear_free(priv_key);
+ DH_free(dh);
+ return NULL;
+#endif
}
@@ -917,7 +1031,7 @@
const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
- len, mac, 32);
+ len, mac, 48);
}
diff --git a/src/crypto/des-internal.c b/src/crypto/des-internal.c
index dec39ef..ebd9952 100644
--- a/src/crypto/des-internal.c
+++ b/src/crypto/des-internal.c
@@ -48,7 +48,7 @@
static const u32 bytebit[8] =
{
- 0200, 0100, 040, 020, 010, 04, 02, 01
+ 0200, 0100, 040, 020, 010, 04, 02, 01
};
static const u32 bigbyte[24] =
@@ -58,22 +58,22 @@
0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
0x800UL, 0x400UL, 0x200UL, 0x100UL,
0x80UL, 0x40UL, 0x20UL, 0x10UL,
- 0x8UL, 0x4UL, 0x2UL, 0x1L
+ 0x8UL, 0x4UL, 0x2UL, 0x1L
};
/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
static const u8 pc1[56] = {
- 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
- 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
- 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
};
static const u8 totrot[16] = {
1, 2, 4, 6,
- 8, 10, 12, 14,
- 15, 17, 19, 21,
+ 8, 10, 12, 14,
+ 15, 17, 19, 21,
23, 25, 27, 28
};
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index 9d094b8..4697e04 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -76,12 +76,11 @@
/* w_i = G(t, XVAL) */
os_memcpy(_t, t, 20);
sha1_transform(_t, xkey);
- _t[0] = host_to_be32(_t[0]);
- _t[1] = host_to_be32(_t[1]);
- _t[2] = host_to_be32(_t[2]);
- _t[3] = host_to_be32(_t[3]);
- _t[4] = host_to_be32(_t[4]);
- os_memcpy(xpos, _t, 20);
+ WPA_PUT_BE32(xpos, _t[0]);
+ WPA_PUT_BE32(xpos + 4, _t[1]);
+ WPA_PUT_BE32(xpos + 8, _t[2]);
+ WPA_PUT_BE32(xpos + 12, _t[3]);
+ WPA_PUT_BE32(xpos + 16, _t[4]);
/* XKEY = (1 + XKEY + w_i) mod 2^b */
carry = 1;
diff --git a/src/crypto/sha1-internal.c b/src/crypto/sha1-internal.c
index ffcba66..a491707 100644
--- a/src/crypto/sha1-internal.c
+++ b/src/crypto/sha1-internal.c
@@ -53,7 +53,7 @@
100% Public Domain
-----------------
-Modified 7/98
+Modified 7/98
By James H. Brown <jbrown@burgoyne.com>
Still 100% Public Domain
@@ -75,7 +75,7 @@
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s).
-I also changed the declaration of variables i & j in SHA1Update to
+I also changed the declaration of variables i & j in SHA1Update to
unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since
@@ -102,7 +102,7 @@
Modified 4/01
By Saul Kravitz <Saul.Kravitz@celera.com>
Still 100% PD
-Modified to run on Compaq Alpha hardware.
+Modified to run on Compaq Alpha hardware.
-----------------
Modified 4/01
@@ -162,7 +162,7 @@
{
printf("%s (%d,%d) %x %x %x %x %x\n",
msg,
- context->count[0], context->count[1],
+ context->count[0], context->count[1],
context->state[0],
context->state[1],
context->state[2],
diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c
index 86a548e..ff1e2ba 100644
--- a/src/crypto/sha256-internal.c
+++ b/src/crypto/sha256-internal.c
@@ -69,7 +69,7 @@
( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
@@ -100,7 +100,7 @@
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
W[i - 16];
- }
+ }
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i) \
@@ -111,7 +111,7 @@
for (i = 0; i < 64; ++i) {
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
- t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
}
diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c
new file mode 100644
index 0000000..ee136ce
--- /dev/null
+++ b/src/crypto/sha384.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2003-2017, 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 "sha384.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha384_vector - HMAC-SHA384 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 (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384_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[48];
+ 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 = SHA384(key) */
+ if (key_len > 128) {
+ if (sha384_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 48;
+ }
+
+ /* the HMAC_SHA384 transform looks like:
+ *
+ * SHA384(K XOR opad, SHA384(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 SHA384 */
+ _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 (sha384_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 SHA384 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA384_MAC_LEN;
+ return sha384_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha384 - HMAC-SHA384 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 (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/src/crypto/sha512-internal.c b/src/crypto/sha512-internal.c
index 66ef331..76c4fe7 100644
--- a/src/crypto/sha512-internal.c
+++ b/src/crypto/sha512-internal.c
@@ -242,7 +242,7 @@
md->curlen = 0;
}
- /* pad upto 120 bytes of zeroes
+ /* pad up to 120 bytes of zeroes
* note: that from 112 to 120 is the 64 MSB of the length. We assume
* that you won't hash > 2^64 bits of data... :-)
*/
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 15a3bcf..11d504a 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -336,29 +336,36 @@
struct tls_random *data);
/**
- * tls_connection_prf - Use TLS-PRF to derive keying material
+ * tls_connection_export_key - Derive keying material from a TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @label: Label (e.g., description of the key) for PRF
- * @server_random_first: seed is 0 = client_random|server_random,
- * 1 = server_random|client_random
- * @skip_keyblock: Skip TLS key block from the beginning of PRF output
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
- * tls_connection_prf() is required so that further keying material can be
- * derived from the master secret. Example implementation of this function is in
- * tls_prf_sha1_md5() when it is called with seed set to
- * client_random|server_random (or server_random|client_random). For TLSv1.2 and
- * newer, a different PRF is needed, though.
+ * Exports keying material using the mechanism described in RFC 5705.
*/
-int __must_check tls_connection_prf(void *tls_ctx,
- struct tls_connection *conn,
- const char *label,
- int server_random_first,
- int skip_keyblock,
- u8 *out, size_t out_len);
+int __must_check tls_connection_export_key(void *tls_ctx,
+ struct tls_connection *conn,
+ const char *label,
+ u8 *out, size_t out_len);
+
+/**
+ * tls_connection_get_eap_fast_key - Derive key material for EAP-FAST
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * Exports key material after the normal TLS key block for use with
+ * EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST
+ * uses a different legacy mechanism.
+ */
+int __must_check tls_connection_get_eap_fast_key(void *tls_ctx,
+ struct tls_connection *conn,
+ u8 *out, size_t out_len);
/**
* tls_connection_handshake - Process TLS handshake (client side)
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index c4cd3c1..8c76bfa 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -402,7 +402,7 @@
return -1;
}
- /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
+ /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
if (params->ca_cert) {
@@ -810,15 +810,22 @@
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, u8 *out, size_t out_len)
{
- if (conn == NULL || conn->session == NULL || skip_keyblock)
+ if (conn == NULL || conn->session == NULL)
return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
- server_random_first, 0, NULL, out_len, (char *) out);
+ 0 /* client_random first */, 0, NULL, out_len,
+ (char *) out);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ return -1;
}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 01a7c97..c7cb5de 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -394,9 +394,9 @@
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+static int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ int skip_keyblock, u8 *out, size_t out_len)
{
int ret = -1, skip = 0;
u8 *tmp_out = NULL;
@@ -434,6 +434,21 @@
}
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, u8 *out, size_t out_len)
+{
+ return tls_connection_prf(tls_ctx, conn, label, 0, 0, out, out_len);
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+ return tls_connection_prf(tls_ctx, conn, "key expansion", 1, 1, out,
+ out_len);
+}
+
+
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index ae392ad..dd5681e 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -86,9 +86,15 @@
}
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, u8 *out, size_t out_len)
+{
+ return -1;
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
{
return -1;
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index ebcc545..4521891 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -18,6 +18,7 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
+#include <openssl/opensslv.h>
#include <openssl/pkcs12.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_NO_ENGINE
@@ -37,6 +38,12 @@
#include "tls.h"
#include "tls_openssl.h"
+#if !defined(CONFIG_FIPS) && \
+ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
+ defined(EAP_SERVER_FAST))
+#define OPENSSL_NEED_EAP_FAST_PRF
+#endif
+
#if defined(OPENSSL_IS_BORINGSSL)
/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
typedef size_t stack_index_t;
@@ -51,10 +58,13 @@
#endif /* OPENSSL_NO_TLSEXT */
#endif /* SSL_set_tlsext_status_type */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ defined(LIBRESSL_VERSION_NUMBER)) && \
+ !defined(BORINGSSL_API_VERSION)
/*
* SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
- * 1.1.0. Provide compatibility wrappers for older versions.
+ * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
+ * older versions.
*/
static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
@@ -77,6 +87,7 @@
}
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
unsigned char *out, size_t outlen)
{
@@ -88,6 +99,7 @@
os_memcpy(out, session->master_key, outlen);
return outlen;
}
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
#endif
@@ -618,7 +630,8 @@
wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
"system certificate store: subject='%s'", buf);
- if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
+ cert)) {
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert to OpenSSL "
"certificate store");
@@ -716,10 +729,16 @@
engine = ENGINE_by_id(id);
if (engine) {
- ENGINE_free(engine);
wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
"available", id);
- return 0;
+ /*
+ * If it was auto-loaded by ENGINE_by_id() we might still
+ * need to tell it which PKCS#11 module to use in legacy
+ * (non-p11-kit) environments. Do so now; even if it was
+ * properly initialised before, setting it again will be
+ * harmless.
+ */
+ goto found;
}
ERR_clear_error();
@@ -756,7 +775,7 @@
id, ERR_error_string(ERR_get_error(), NULL));
return -1;
}
-
+ found:
while (post && post[0]) {
wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
@@ -900,7 +919,7 @@
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
@@ -953,6 +972,14 @@
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+#ifdef SSL_MODE_NO_AUTO_CHAIN
+ /* Number of deployed use cases assume the default OpenSSL behavior of
+ * auto chaining the local certificate is in use. BoringSSL removed this
+ * functionality by default, so we need to restore it here to avoid
+ * breaking existing use cases. */
+ SSL_CTX_clear_mode(ssl, SSL_MODE_NO_AUTO_CHAIN);
+#endif /* SSL_MODE_NO_AUTO_CHAIN */
+
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
SSL_CTX_set_app_data(ssl, context);
if (data->tls_session_lifetime > 0) {
@@ -1024,7 +1051,7 @@
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
@@ -2061,7 +2088,7 @@
#ifdef ANDROID
/* Single alias */
if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
- if (tls_add_ca_from_keystore(ssl_ctx->cert_store,
+ if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
&ca_cert[11]) < 0)
return -1;
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
@@ -2081,7 +2108,7 @@
alias = strtok_r(aliases, delim, &savedptr);
for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
if (tls_add_ca_from_keystore_encoded(
- ssl_ctx->cert_store, alias)) {
+ SSL_CTX_get_cert_store(ssl_ctx), alias)) {
wpa_printf(MSG_WARNING,
"OpenSSL: %s - Failed to add ca_cert %s from keystore",
__func__, alias);
@@ -2235,10 +2262,8 @@
#ifdef SSL_OP_NO_TICKET
if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_set_options(ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
else
SSL_clear_options(ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
#ifdef SSL_OP_NO_TLSv1
@@ -2315,7 +2340,7 @@
return 0;
#ifdef PKCS12_FUNCS
-#if OPENSSL_VERSION_NUMBER < 0x10002000L
+#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
/*
* Clear previously set extra chain certificates, if any, from PKCS#12
* processing in tls_parse_pkcs12() to allow OpenSSL to build a new
@@ -2344,15 +2369,26 @@
BIO *bio = BIO_from_keystore(&client_cert[11]);
X509 *x509 = NULL;
int ret = -1;
- if (bio) {
+ if (bio)
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- BIO_free(bio);
- }
+
if (x509) {
if (SSL_use_certificate(conn->ssl, x509) == 1)
ret = 0;
X509_free(x509);
}
+
+ /* Read additional certificates into the chain. */
+ while (bio) {
+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (x509) {
+ /* Takes ownership of x509 */
+ SSL_add0_chain_cert(conn->ssl, x509);
+ } else {
+ BIO_free(bio);
+ bio = NULL;
+ }
+ }
return ret;
}
#endif /* ANDROID */
@@ -3083,7 +3119,7 @@
}
-#ifndef CONFIG_FIPS
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
static int openssl_get_keyblock_size(SSL *ssl)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
@@ -3138,18 +3174,24 @@
EVP_CIPHER_iv_length(c));
#endif
}
-#endif /* CONFIG_FIPS */
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
-static int openssl_tls_prf(struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
+int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
+ const char *label, u8 *out, size_t out_len)
{
-#ifdef CONFIG_FIPS
- wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
- "mode");
- return -1;
-#else /* CONFIG_FIPS */
+ if (!conn ||
+ SSL_export_keying_material(conn->ssl, out, out_len, label,
+ os_strlen(label), NULL, 0, 0) != 1)
+ return -1;
+ return 0;
+}
+
+
+int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
+ u8 *out, size_t out_len)
+{
+#ifdef OPENSSL_NEED_EAP_FAST_PRF
SSL *ssl;
SSL_SESSION *sess;
u8 *rnd;
@@ -3164,9 +3206,9 @@
const char *ver;
/*
- * TLS library did not support key generation, so get the needed TLS
- * session parameters and use an internal implementation of TLS PRF to
- * derive the key.
+ * TLS library did not support EAP-FAST key generation, so get the
+ * needed TLS session parameters and use an internal implementation of
+ * TLS PRF to derive the key.
*/
if (conn == NULL)
@@ -3179,15 +3221,13 @@
if (!ver || !sess)
return -1;
- if (skip_keyblock) {
- skip = openssl_get_keyblock_size(ssl);
- if (skip < 0)
- return -1;
- tmp_out = os_malloc(skip + out_len);
- if (!tmp_out)
- return -1;
- _out = tmp_out;
- }
+ skip = openssl_get_keyblock_size(ssl);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
if (!rnd) {
@@ -3200,54 +3240,31 @@
master_key_len = SSL_SESSION_get_master_key(sess, master_key,
sizeof(master_key));
- if (server_random_first) {
- os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
- SSL3_RANDOM_SIZE);
- } else {
- os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
- os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
- SSL3_RANDOM_SIZE);
- }
+ os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, SSL3_RANDOM_SIZE);
if (os_strcmp(ver, "TLSv1.2") == 0) {
tls_prf_sha256(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len);
ret = 0;
} else if (tls_prf_sha1_md5(master_key, master_key_len,
- label, rnd, 2 * SSL3_RANDOM_SIZE,
+ "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
_out, skip + out_len) == 0) {
ret = 0;
}
os_memset(master_key, 0, sizeof(master_key));
os_free(rnd);
- if (ret == 0 && skip_keyblock)
+ if (ret == 0)
os_memcpy(out, _out + skip, out_len);
bin_clear_free(tmp_out, skip);
return ret;
-#endif /* CONFIG_FIPS */
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- int skip_keyblock, u8 *out, size_t out_len)
-{
- if (conn == NULL)
- return -1;
- if (server_random_first || skip_keyblock)
- return openssl_tls_prf(conn, label,
- server_random_first, skip_keyblock,
- out, out_len);
- if (SSL_export_keying_material(conn->ssl, out, out_len, label,
- os_strlen(label), NULL, 0, 0) == 1) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
- return 0;
- }
- return openssl_tls_prf(conn, label, server_random_first,
- skip_keyblock, out, out_len);
+#else /* OPENSSL_NEED_EAP_FAST_PRF */
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
+ return -1;
+#endif /* OPENSSL_NEED_EAP_FAST_PRF */
}
@@ -3976,7 +3993,7 @@
engine_id = "pkcs11";
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
if (params->flags & TLS_CONN_EAP_FAST) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Use TLSv1_method() for EAP-FAST");
@@ -4120,10 +4137,8 @@
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
-#ifdef SSL_CTX_clear_options
else
SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
#endif /* SSL_OP_NO_TICKET */
#ifdef HAVE_OCSP
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b7e0d16..7b3a6bd 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1,6 +1,6 @@
/*
* Driver interface definition
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,6 +21,9 @@
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
+#ifdef CONFIG_MACSEC
+#include "pae/ieee802_1x_kay.h"
+#endif /* CONFIG_MACSEC */
#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
@@ -54,6 +57,13 @@
#define HOSTAPD_CHAN_VHT_130_30 0x04000000
#define HOSTAPD_CHAN_VHT_150_10 0x08000000
+/* Filter gratuitous ARP */
+#define WPA_DATA_FRAME_FILTER_FLAG_ARP BIT(0)
+/* Filter unsolicited Neighbor Advertisement */
+#define WPA_DATA_FRAME_FILTER_FLAG_NA BIT(1)
+/* Filter unicast IP packets encrypted using the GTK */
+#define WPA_DATA_FRAME_FILTER_FLAG_GTK BIT(2)
+
/**
* enum reg_change_initiator - Regulatory change initiator
*/
@@ -126,6 +136,29 @@
unsigned int dfs_cac_ms;
};
+#define HE_MAX_NUM_SS 8
+#define HE_MAX_PHY_CAPAB_SIZE 3
+
+/**
+ * struct he_ppe_threshold - IEEE 802.11ax HE PPE Threshold
+ */
+struct he_ppe_threshold {
+ u32 numss_m1;
+ u32 ru_count;
+ u32 ppet16_ppet8_ru3_ru0[HE_MAX_NUM_SS];
+};
+
+/**
+ * struct he_capabilities - IEEE 802.11ax HE capabilities
+ */
+struct he_capabilities {
+ u8 he_supported;
+ u32 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
+ u32 mac_cap;
+ u32 mcs;
+ struct he_ppe_threshold ppet;
+};
+
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
@@ -184,6 +217,11 @@
u8 vht_mcs_set[8];
unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+
+ /**
+ * he_capab - HE (IEEE 802.11ax) capabilities
+ */
+ struct he_capabilities he_capab;
};
@@ -226,6 +264,9 @@
* @est_throughput: Estimated throughput in kbps (this is calculated during
* scan result processing if left zero by the driver wrapper)
* @snr: Signal-to-noise ratio in dB (calculated during scan result processing)
+ * @parent_tsf: Time when the Beacon/Probe Response frame was received in terms
+ * of TSF of the BSS specified by %tsf_bssid.
+ * @tsf_bssid: The BSS that %parent_tsf TSF time refers to.
* @ie_len: length of the following IE field in octets
* @beacon_ie_len: length of the following Beacon IE field in octets
*
@@ -256,6 +297,8 @@
unsigned int age;
unsigned int est_throughput;
int snr;
+ u64 parent_tsf;
+ u8 tsf_bssid[ETH_ALEN];
size_t ie_len;
size_t beacon_ie_len;
/* Followed by ie_len + beacon_ie_len octets of IE data */
@@ -448,6 +491,68 @@
*/
const u8 *bssid;
+ /**
+ * scan_cookie - Unique identification representing the scan request
+ *
+ * This scan_cookie carries a unique identification representing the
+ * scan request if the host driver/kernel supports concurrent scan
+ * requests. This cookie is returned from the corresponding driver
+ * interface.
+ *
+ * Note: Unlike other parameters in this structure, scan_cookie is used
+ * only to return information instead of setting parameters for the
+ * scan.
+ */
+ u64 scan_cookie;
+
+ /**
+ * duration - Dwell time on each channel
+ *
+ * This optional parameter can be used to set the dwell time on each
+ * channel. In TUs.
+ */
+ u16 duration;
+
+ /**
+ * duration_mandatory - Whether the specified duration is mandatory
+ *
+ * If this is set, the duration specified by the %duration field is
+ * mandatory (and the driver should reject the scan request if it is
+ * unable to comply with the specified duration), otherwise it is the
+ * maximum duration and the actual duration may be shorter.
+ */
+ unsigned int duration_mandatory:1;
+
+ /**
+ * relative_rssi_set - Whether relative RSSI parameters are set
+ */
+ unsigned int relative_rssi_set:1;
+
+ /**
+ * relative_rssi - Relative RSSI for reporting better BSSs
+ *
+ * Amount of RSSI by which a BSS should be better than the current
+ * connected BSS to report the new BSS to user space.
+ */
+ s8 relative_rssi;
+
+ /**
+ * relative_adjust_band - Band to which RSSI should be adjusted
+ *
+ * The relative_adjust_rssi should be added to the band specified
+ * by relative_adjust_band.
+ */
+ enum set_band relative_adjust_band;
+
+ /**
+ * relative_adjust_rssi - RSSI to be added to relative_adjust_band
+ *
+ * An amount of relative_band_rssi should be added to the BSSs that
+ * belong to the band specified by relative_adjust_band while comparing
+ * with other bands for BSS reporting.
+ */
+ s8 relative_adjust_rssi;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -478,17 +583,18 @@
int p2p;
/**
- * sae_data - SAE elements for Authentication frame
+ * auth_data - Additional elements for Authentication frame
*
* This buffer starts with the Authentication transaction sequence
- * number field. If SAE is not used, this pointer is %NULL.
+ * number field. If no special handling of such elements is needed, this
+ * pointer is %NULL. This is used with SAE and FILS.
*/
- const u8 *sae_data;
+ const u8 *auth_data;
/**
- * sae_data_len - Length of sae_data buffer in octets
+ * auth_data_len - Length of auth_data buffer in octets
*/
- size_t sae_data_len;
+ size_t auth_data_len;
};
/**
@@ -875,6 +981,27 @@
* AP as usual. Valid for DMG network only.
*/
int pbss;
+
+ /**
+ * fils_kek - KEK for FILS association frame protection (AES-SIV)
+ */
+ const u8 *fils_kek;
+
+ /**
+ * fils_kek_len: Length of fils_kek in bytes
+ */
+ size_t fils_kek_len;
+
+ /**
+ * fils_nonces - Nonces for FILS association frame protection
+ * (AES-SIV AAD)
+ */
+ const u8 *fils_nonces;
+
+ /**
+ * fils_nonces_len: Length of fils_nonce in bytes
+ */
+ size_t fils_nonces_len;
};
enum hide_ssid {
@@ -933,6 +1060,22 @@
int *basic_rates;
/**
+ * beacon_rate: Beacon frame data rate
+ *
+ * This parameter can be used to set a specific Beacon frame data rate
+ * for the BSS. The interpretation of this value depends on the
+ * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS). If
+ * beacon_rate == 0 and rate_type == 0 (BEACON_RATE_LEGACY), the default
+ * Beacon frame data rate is used.
+ */
+ unsigned int beacon_rate;
+
+ /**
+ * beacon_rate_type: Beacon data rate type (legacy/HT/VHT)
+ */
+ enum beacon_rate_type rate_type;
+
+ /**
* proberesp - Probe Response template
*
* This is used by drivers that reply to Probe Requests internally in
@@ -1108,16 +1251,43 @@
* infrastructure BSS. Valid only for DMG network.
*/
int pbss;
+
+ /**
+ * multicast_to_unicast - Whether to use multicast_to_unicast
+ *
+ * If this is non-zero, the AP is requested to perform multicast to
+ * unicast conversion for ARP, IPv4, and IPv6 frames (possibly within
+ * 802.1Q). If enabled, such frames are to be sent to each station
+ * separately, with the DA replaced by their own MAC address rather
+ * than the group address.
+ *
+ * Note that this may break certain expectations of the receiver, such
+ * as the ability to drop unicast IP packets received within multicast
+ * L2 frames, or the ability to not send ICMP destination unreachable
+ * messages for packets received in L2 multicast (which is required,
+ * but the receiver can't tell the difference if this new option is
+ * enabled.)
+ *
+ * This also doesn't implement the 802.11 DMS (directed multicast
+ * service).
+ */
+ int multicast_to_unicast;
};
struct wpa_driver_mesh_bss_params {
-#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+#define WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT 0x00000002
+#define WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS 0x00000004
+#define WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE 0x00000008
/*
* TODO: Other mesh configuration parameters would go here.
* See NL80211_MESHCONF_* for all the mesh config parameters.
*/
unsigned int flags;
+ int auto_plinks;
int peer_link_timeout;
+ int max_peer_links;
+ u16 ht_opmode;
};
struct wpa_driver_mesh_join_params {
@@ -1128,7 +1298,7 @@
int ie_len;
struct hostapd_freq_params freq;
int beacon_int;
- int max_peer_links;
+ int dtim_period;
struct wpa_driver_mesh_bss_params conf;
#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002
@@ -1271,6 +1441,24 @@
#define WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS 0x0000008000000000ULL
/** Driver supports full AP client state */
#define WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE 0x0000010000000000ULL
+/** Driver supports P2P Listen offload */
+#define WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD 0x0000020000000000ULL
+/** Driver supports FILS */
+#define WPA_DRIVER_FLAGS_SUPPORT_FILS 0x0000040000000000ULL
+/** Driver supports Beacon frame TX rate configuration (legacy rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY 0x0000080000000000ULL
+/** Driver supports Beacon frame TX rate configuration (HT rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_HT 0x0000100000000000ULL
+/** Driver supports Beacon frame TX rate configuration (VHT rates) */
+#define WPA_DRIVER_FLAGS_BEACON_RATE_VHT 0x0000200000000000ULL
+/** Driver supports mgmt_tx with random TX address in non-connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA 0x0000400000000000ULL
+/** Driver supports mgmt_tx with random TX addr in connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED 0x0000800000000000ULL
+/** Driver supports better BSS reporting with sched_scan in connected mode */
+#define WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI 0x0001000000000000ULL
+/** Driver supports HE capabilities */
+#define WPA_DRIVER_FLAGS_HE_CAPABILITIES 0x0002000000000000ULL
u64 flags;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -1365,6 +1553,17 @@
* offset, namely the 6th byte in the Action frame body.
*/
#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
+/**
+ * Driver supports RRM. With this support, the driver will accept to use RRM in
+ * (Re)Association Request frames, without supporting quiet period.
+ */
+#define WPA_DRIVER_FLAGS_SUPPORT_RRM 0x00000010
+
+/** Driver supports setting the scan dwell time */
+#define WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL 0x00000020
+/** Driver supports Beacon Report Measurement */
+#define WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT 0x00000040
+
u32 rrm_flags;
/* Driver concurrency capabilities */
@@ -1410,6 +1609,7 @@
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
enum mesh_plink_state plink_state;
+ u16 peer_aid;
#endif /* CONFIG_MESH */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
@@ -1419,6 +1619,7 @@
size_t supp_channels_len;
const u8 *supp_oper_classes;
size_t supp_oper_classes_len;
+ int support_p2p_ps;
};
struct mac_address {
@@ -2650,6 +2851,9 @@
* transmitted on that channel; alternatively the frame may be sent on
* the current operational channel (if in associated state in station
* mode or while operating as an AP.)
+ *
+ * If @src differs from the device MAC address, use of a random
+ * transmitter address is requested for this message exchange.
*/
int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
const u8 *dst, const u8 *src, const u8 *bssid,
@@ -3272,6 +3476,14 @@
int (*macsec_deinit)(void *priv);
/**
+ * macsec_get_capability - Inform MKA of this driver's capability
+ * @priv: Private driver interface data
+ * @cap: Driver's capability
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*macsec_get_capability)(void *priv, enum macsec_cap *cap);
+
+ /**
* enable_protect_frames - Set protect frames status
* @priv: Private driver interface data
* @enabled: TRUE = protect frames enabled
@@ -3281,6 +3493,15 @@
int (*enable_protect_frames)(void *priv, Boolean enabled);
/**
+ * enable_encrypt - Set encryption status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = encrypt outgoing traffic
+ * FALSE = integrity-only protection on outgoing traffic
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+ int (*enable_encrypt)(void *priv, Boolean enabled);
+
+ /**
* set_replay_protect - Set replay protect status and window size
* @priv: Private driver interface data
* @enabled: TRUE = replay protect enabled
@@ -3294,11 +3515,9 @@
* set_current_cipher_suite - Set current cipher suite
* @priv: Private driver interface data
* @cs: EUI64 identifier
- * @cs_len: Length of the cs buffer in octets
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*set_current_cipher_suite)(void *priv, const u8 *cs,
- size_t cs_len);
+ int (*set_current_cipher_suite)(void *priv, u64 cs);
/**
* enable_controlled_port - Set controlled port status
@@ -3312,155 +3531,129 @@
/**
* get_receive_lowest_pn - Get receive lowest pn
* @priv: Private driver interface data
- * @channel: secure channel
- * @an: association number
- * @lowest_pn: lowest accept pn
+ * @sa: secure association
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*get_receive_lowest_pn)(void *priv, u32 channel, u8 an,
- u32 *lowest_pn);
+ int (*get_receive_lowest_pn)(void *priv, struct receive_sa *sa);
/**
* get_transmit_next_pn - Get transmit next pn
* @priv: Private driver interface data
- * @channel: secure channel
- * @an: association number
- * @next_pn: next pn
+ * @sa: secure association
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*get_transmit_next_pn)(void *priv, u32 channel, u8 an,
- u32 *next_pn);
+ int (*get_transmit_next_pn)(void *priv, struct transmit_sa *sa);
/**
* set_transmit_next_pn - Set transmit next pn
* @priv: Private driver interface data
- * @channel: secure channel
- * @an: association number
- * @next_pn: next pn
+ * @sa: secure association
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*set_transmit_next_pn)(void *priv, u32 channel, u8 an,
- u32 next_pn);
-
- /**
- * get_available_receive_sc - get available receive channel
- * @priv: Private driver interface data
- * @channel: secure channel
- * Returns: 0 on success, -1 on failure (or if not supported)
- */
- int (*get_available_receive_sc)(void *priv, u32 *channel);
+ int (*set_transmit_next_pn)(void *priv, struct transmit_sa *sa);
/**
* create_receive_sc - create secure channel for receiving
* @priv: Private driver interface data
- * @channel: secure channel
- * @sci_addr: secure channel identifier - address
- * @sci_port: secure channel identifier - port
+ * @sc: secure channel
* @conf_offset: confidentiality offset (0, 30, or 50)
* @validation: frame validation policy (0 = Disabled, 1 = Checked,
* 2 = Strict)
* Returns: 0 on success, -1 on failure (or if not supported)
*/
- int (*create_receive_sc)(void *priv, u32 channel, const u8 *sci_addr,
- u16 sci_port, unsigned int conf_offset,
+ int (*create_receive_sc)(void *priv, struct receive_sc *sc,
+ unsigned int conf_offset,
int validation);
/**
* delete_receive_sc - delete secure connection for receiving
* @priv: private driver interface data from init()
- * @channel: secure channel
+ * @sc: secure channel
* Returns: 0 on success, -1 on failure
*/
- int (*delete_receive_sc)(void *priv, u32 channel);
+ int (*delete_receive_sc)(void *priv, struct receive_sc *sc);
/**
* create_receive_sa - create secure association for receive
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
- * @lowest_pn: the lowest packet number can be received
- * @sak: the secure association key
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*create_receive_sa)(void *priv, u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak);
+ int (*create_receive_sa)(void *priv, struct receive_sa *sa);
+
+ /**
+ * delete_receive_sa - Delete secure association for receive
+ * @priv: Private driver interface data from init()
+ * @sa: Secure association
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*delete_receive_sa)(void *priv, struct receive_sa *sa);
/**
* enable_receive_sa - enable the SA for receive
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*enable_receive_sa)(void *priv, u32 channel, u8 an);
+ int (*enable_receive_sa)(void *priv, struct receive_sa *sa);
/**
* disable_receive_sa - disable SA for receive
* @priv: private driver interface data from init()
- * @channel: secure channel index
- * @an: association number
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*disable_receive_sa)(void *priv, u32 channel, u8 an);
-
- /**
- * get_available_transmit_sc - get available transmit channel
- * @priv: Private driver interface data
- * @channel: secure channel
- * Returns: 0 on success, -1 on failure (or if not supported)
- */
- int (*get_available_transmit_sc)(void *priv, u32 *channel);
+ int (*disable_receive_sa)(void *priv, struct receive_sa *sa);
/**
* create_transmit_sc - create secure connection for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @sci_addr: secure channel identifier - address
- * @sci_port: secure channel identifier - port
+ * @sc: secure channel
+ * @conf_offset: confidentiality offset (0, 30, or 50)
* Returns: 0 on success, -1 on failure
*/
- int (*create_transmit_sc)(void *priv, u32 channel, const u8 *sci_addr,
- u16 sci_port, unsigned int conf_offset);
+ int (*create_transmit_sc)(void *priv, struct transmit_sc *sc,
+ unsigned int conf_offset);
/**
* delete_transmit_sc - delete secure connection for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
+ * @sc: secure channel
* Returns: 0 on success, -1 on failure
*/
- int (*delete_transmit_sc)(void *priv, u32 channel);
+ int (*delete_transmit_sc)(void *priv, struct transmit_sc *sc);
/**
* create_transmit_sa - create secure association for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel index
- * @an: association number
- * @next_pn: the packet number used as next transmit packet
- * @confidentiality: True if the SA is to provide confidentiality
- * as well as integrity
- * @sak: the secure association key
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*create_transmit_sa)(void *priv, u32 channel, u8 an, u32 next_pn,
- Boolean confidentiality, const u8 *sak);
+ int (*create_transmit_sa)(void *priv, struct transmit_sa *sa);
+
+ /**
+ * delete_transmit_sa - Delete secure association for transmit
+ * @priv: Private driver interface data from init()
+ * @sa: Secure association
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*delete_transmit_sa)(void *priv, struct transmit_sa *sa);
/**
* enable_transmit_sa - enable SA for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*enable_transmit_sa)(void *priv, u32 channel, u8 an);
+ int (*enable_transmit_sa)(void *priv, struct transmit_sa *sa);
/**
* disable_transmit_sa - disable SA for transmit
* @priv: private driver interface data from init()
- * @channel: secure channel
- * @an: association number
+ * @sa: secure association
* Returns: 0 on success, -1 on failure
*/
- int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
+ int (*disable_transmit_sa)(void *priv, struct transmit_sa *sa);
#endif /* CONFIG_MACSEC */
/**
@@ -3534,9 +3727,87 @@
/**
* abort_scan - Request the driver to abort an ongoing scan
* @priv: Private driver interface data
+ * @scan_cookie: Cookie identifying the scan request. This is used only
+ * when the vendor interface QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN
+ * was used to trigger scan. Otherwise, 0 is used.
* Returns 0 on success, -1 on failure
*/
- int (*abort_scan)(void *priv);
+ int (*abort_scan)(void *priv, u64 scan_cookie);
+
+ /**
+ * configure_data_frame_filters - Request to configure frame filters
+ * @priv: Private driver interface data
+ * @filter_flags: The type of frames to filter (bitfield of
+ * WPA_DATA_FRAME_FILTER_FLAG_*)
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*configure_data_frame_filters)(void *priv, u32 filter_flags);
+
+ /**
+ * get_ext_capab - Get extended capabilities for the specified interface
+ * @priv: Private driver interface data
+ * @type: Interface type for which to get extended capabilities
+ * @ext_capab: Extended capabilities fetched
+ * @ext_capab_mask: Extended capabilities mask
+ * @ext_capab_len: Length of the extended capabilities
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*get_ext_capab)(void *priv, enum wpa_driver_if_type type,
+ const u8 **ext_capab, const u8 **ext_capab_mask,
+ unsigned int *ext_capab_len);
+
+ /**
+ * p2p_lo_start - Start offloading P2P listen to device
+ * @priv: Private driver interface data
+ * @freq: Listening frequency (MHz) for P2P listen
+ * @period: Length of the listen operation in milliseconds
+ * @interval: Interval for running the listen operation in milliseconds
+ * @count: Number of times to run the listen operation
+ * @device_types: Device primary and secondary types
+ * @dev_types_len: Number of bytes for device_types
+ * @ies: P2P IE and WSC IE for Probe Response frames
+ * @ies_len: Length of ies in bytes
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*p2p_lo_start)(void *priv, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count,
+ const u8 *device_types, size_t dev_types_len,
+ const u8 *ies, size_t ies_len);
+
+ /**
+ * p2p_lo_stop - Stop P2P listen offload
+ * @priv: Private driver interface data
+ * Returns: 0 on success or -1 on failure
+ */
+ int (*p2p_lo_stop)(void *priv);
+
+ /**
+ * set_default_scan_ies - Set default scan IEs
+ * @priv: Private driver interface data
+ * @ies: Scan default IEs buffer
+ * @ies_len: Length of IEs in bytes
+ * Returns: 0 on success or -1 on failure
+ *
+ * The driver can use these by default when there are no scan IEs coming
+ * in the subsequent scan requests. Also in case of one or more of IEs
+ * given in set_default_scan_ies() are missing in the subsequent scan
+ * request, the driver should merge the missing scan IEs in the scan
+ * request from the IEs set by set_default_scan_ies() in the Probe
+ * Request frames sent.
+ */
+ int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len);
+
+ /**
+ * set_tdls_mode - Set TDLS trigger mode to the host driver
+ * @priv: Private driver interface data
+ * @tdls_external_control: Represents if TDLS external trigger control
+ * mode is enabled/disabled.
+ *
+ * This optional callback can be used to configure the TDLS external
+ * trigger control mode to the host driver.
+ */
+ int (*set_tdls_mode)(void *priv, int tdls_external_control);
};
@@ -3957,7 +4228,7 @@
* EVENT_DFS_CAC_ABORTED - Notify that channel availability check has been aborted
*
* The CAC was not successful, and the channel remains in the previous
- * state. This may happen due to a radar beeing detected or other
+ * state. This may happen due to a radar being detected or other
* external influences.
*/
EVENT_DFS_CAC_ABORTED,
@@ -4021,6 +4292,20 @@
* on a DFS frequency by a driver that supports DFS Offload.
*/
EVENT_DFS_CAC_STARTED,
+
+ /**
+ * EVENT_P2P_LO_STOP - Notify that P2P listen offload is stopped
+ */
+ EVENT_P2P_LO_STOP,
+
+ /**
+ * EVENT_BEACON_LOSS - Beacon loss detected
+ *
+ * This event indicates that no Beacon frames has been received from
+ * the current AP. This may indicate that the AP is not anymore in
+ * range.
+ */
+ EVENT_BEACON_LOSS,
};
@@ -4113,6 +4398,16 @@
size_t resp_ies_len;
/**
+ * resp_frame - (Re)Association Response frame
+ */
+ const u8 *resp_frame;
+
+ /**
+ * resp_frame_len - (Re)Association Response frame length
+ */
+ size_t resp_frame_len;
+
+ /**
* beacon_ies - Beacon or Probe Response IEs
*
* Optional Beacon/ProbeResp data: IEs included in Beacon or
@@ -4406,6 +4701,17 @@
* status_code - Status Code from (Re)association Response
*/
u16 status_code;
+
+ /**
+ * timed_out - Whether failure is due to timeout (etc.) rather
+ * than explicit rejection response from the AP.
+ */
+ int timed_out;
+
+ /**
+ * timeout_reason - Reason for the timeout
+ */
+ const char *timeout_reason;
} assoc_reject;
struct timeout_event {
@@ -4489,6 +4795,11 @@
* @external_scan: Whether the scan info is for an external scan
* @nl_scan_event: 1 if the source of this scan event is a normal scan,
* 0 if the source of the scan event is a vendor scan
+ * @scan_start_tsf: Time when the scan started in terms of TSF of the
+ * BSS that the interface that requested the scan is connected to
+ * (if available).
+ * @scan_start_tsf_bssid: The BSSID according to which %scan_start_tsf
+ * is set.
*/
struct scan_info {
int aborted;
@@ -4498,6 +4809,8 @@
size_t num_ssids;
int external_scan;
int nl_scan_event;
+ u64 scan_start_tsf;
+ u8 scan_start_tsf_bssid[ETH_ALEN];
} scan_info;
/**
@@ -4587,9 +4900,12 @@
/**
* struct low_ack - Data for EVENT_STATION_LOW_ACK events
* @addr: station address
+ * @num_packets: Number of packets lost (consecutive packets not
+ * acknowledged)
*/
struct low_ack {
u8 addr[ETH_ALEN];
+ u32 num_packets;
} low_ack;
/**
@@ -4740,6 +5056,27 @@
u16 ch_width;
enum hostapd_hw_mode hw_mode;
} acs_selected_channels;
+
+ /**
+ * struct p2p_lo_stop - Reason code for P2P Listen offload stop event
+ * @reason_code: Reason for stopping offload
+ * P2P_LO_STOPPED_REASON_COMPLETE: Listen offload finished as
+ * scheduled.
+ * P2P_LO_STOPPED_REASON_RECV_STOP_CMD: Host requested offload to
+ * be stopped.
+ * P2P_LO_STOPPED_REASON_INVALID_PARAM: Invalid listen offload
+ * parameters.
+ * P2P_LO_STOPPED_REASON_NOT_SUPPORTED: Listen offload not
+ * supported by device.
+ */
+ struct p2p_lo_stop {
+ enum {
+ P2P_LO_STOPPED_REASON_COMPLETE = 0,
+ P2P_LO_STOPPED_REASON_RECV_STOP_CMD,
+ P2P_LO_STOPPED_REASON_INVALID_PARAM,
+ P2P_LO_STOPPED_REASON_NOT_SUPPORTED,
+ } reason_code;
+ } p2p_lo_stop;
};
/**
@@ -4819,8 +5156,56 @@
struct wowlan_triggers *
wpa_get_wowlan_triggers(const char *wowlan_triggers,
const struct wpa_driver_capa *capa);
+/* Convert driver flag to string */
+const char * driver_flag_to_string(u64 flag);
/* NULL terminated array of linked in driver wrappers */
extern const struct wpa_driver_ops *const wpa_drivers[];
+
+/* Available drivers */
+
+#ifdef CONFIG_DRIVER_WEXT
+extern const struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+/* driver_nl80211.c */
+extern const struct wpa_driver_ops wpa_driver_nl80211_ops;
+#endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_HOSTAP
+extern const struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_BSD
+extern const struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+/* driver_openbsd.c */
+extern const struct wpa_driver_ops wpa_driver_openbsd_ops;
+#endif /* CONFIG_DRIVER_OPENBSD */
+#ifdef CONFIG_DRIVER_NDIS
+extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+extern const struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
+#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_MACSEC_QCA
+/* driver_macsec_qca.c */
+extern const struct wpa_driver_ops wpa_driver_macsec_qca_ops;
+#endif /* CONFIG_DRIVER_MACSEC_QCA */
+#ifdef CONFIG_DRIVER_MACSEC_LINUX
+/* driver_macsec_linux.c */
+extern const struct wpa_driver_ops wpa_driver_macsec_linux_ops;
+#endif /* CONFIG_DRIVER_MACSEC_LINUX */
+#ifdef CONFIG_DRIVER_ROBOSWITCH
+/* driver_roboswitch.c */
+extern const struct wpa_driver_ops wpa_driver_roboswitch_ops;
+#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+/* driver_atheros.c */
+extern const struct wpa_driver_ops wpa_driver_atheros_ops;
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+extern const struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
+#endif /* CONFIG_DRIVER_NONE */
+
#endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index ba3cad0..a88345f 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -868,6 +868,16 @@
return;
}
+ if (stype == WLAN_FC_STYPE_ACTION &&
+ (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 ||
+ is_broadcast_ether_addr(mgmt->bssid))) {
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+ return;
+ }
+
if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
__func__);
@@ -889,12 +899,6 @@
iebuf = mgmt->u.reassoc_req.variable;
drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
break;
- case WLAN_FC_STYPE_ACTION:
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = buf;
- event.rx_mgmt.frame_len = len;
- wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
- break;
case WLAN_FC_STYPE_AUTH:
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
break;
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index fd73f2e..8621aa0 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -726,7 +726,7 @@
}
-static int
+static int
bsd_flush(void *priv)
{
u8 allsta[IEEE80211_ADDR_LEN];
@@ -1376,11 +1376,16 @@
result->caps = sr->isr_capinfo;
result->qual = sr->isr_rssi;
result->noise = sr->isr_noise;
+
+#ifdef __FreeBSD__
/*
* the rssi value reported by the kernel is in 0.5dB steps relative to
* the reported noise floor. see ieee80211_node.h for details.
*/
result->level = sr->isr_rssi / 2 + sr->isr_noise;
+#else
+ result->level = sr->isr_rssi;
+#endif
pos = (u8 *)(result + 1);
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index b32d35f..b6bcbca 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -1,6 +1,6 @@
/*
* Common driver-related functions
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -80,6 +80,8 @@
E2S(NEW_PEER_CANDIDATE);
E2S(ACS_CHANNEL_SELECTED);
E2S(DFS_CAC_STARTED);
+ E2S(P2P_LO_STOP);
+ E2S(BEACON_LOSS);
}
return "UNKNOWN";
@@ -218,3 +220,55 @@
os_free(buf);
return triggers;
}
+
+
+const char * driver_flag_to_string(u64 flag)
+{
+#define DF2S(x) case WPA_DRIVER_FLAGS_ ## x: return #x
+ switch (flag) {
+ DF2S(DRIVER_IE);
+ DF2S(SET_KEYS_AFTER_ASSOC);
+ DF2S(DFS_OFFLOAD);
+ DF2S(4WAY_HANDSHAKE);
+ DF2S(WIRED);
+ DF2S(SME);
+ DF2S(AP);
+ DF2S(SET_KEYS_AFTER_ASSOC_DONE);
+ DF2S(HT_2040_COEX);
+ DF2S(P2P_CONCURRENT);
+ DF2S(P2P_DEDICATED_INTERFACE);
+ DF2S(P2P_CAPABLE);
+ DF2S(AP_TEARDOWN_SUPPORT);
+ DF2S(P2P_MGMT_AND_NON_P2P);
+ DF2S(SANE_ERROR_CODES);
+ DF2S(OFFCHANNEL_TX);
+ DF2S(EAPOL_TX_STATUS);
+ DF2S(DEAUTH_TX_STATUS);
+ DF2S(BSS_SELECTION);
+ DF2S(TDLS_SUPPORT);
+ DF2S(TDLS_EXTERNAL_SETUP);
+ DF2S(PROBE_RESP_OFFLOAD);
+ DF2S(AP_UAPSD);
+ DF2S(INACTIVITY_TIMER);
+ DF2S(AP_MLME);
+ DF2S(SAE);
+ DF2S(OBSS_SCAN);
+ DF2S(IBSS);
+ DF2S(RADAR);
+ DF2S(DEDICATED_P2P_DEVICE);
+ DF2S(QOS_MAPPING);
+ DF2S(AP_CSA);
+ DF2S(MESH);
+ DF2S(ACS_OFFLOAD);
+ DF2S(KEY_MGMT_OFFLOAD);
+ DF2S(TDLS_CHANNEL_SWITCH);
+ DF2S(HT_IBSS);
+ DF2S(VHT_IBSS);
+ DF2S(SUPPORT_HW_MODE_ANY);
+ DF2S(OFFCHANNEL_SIMULTANEOUS);
+ DF2S(FULL_AP_CLIENT_STATE);
+ DF2S(P2P_LISTEN_OFFLOAD);
+ }
+ return "UNKNOWN";
+#undef DF2S
+}
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
new file mode 100644
index 0000000..5dab77a
--- /dev/null
+++ b/src/drivers/driver_macsec_linux.c
@@ -0,0 +1,1265 @@
+/*
+ * Driver interaction with Linux MACsec kernel module
+ * Copyright (c) 2016, Sabrina Dubroca <sd@queasysnail.net> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/macsec.h>
+#include <linux/if_macsec.h>
+#include <inttypes.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "pae/ieee802_1x_kay.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+
+#define DRV_PREFIX "macsec_linux: "
+
+#define UNUSED_SCI 0xffffffffffffffff
+
+struct cb_arg {
+ struct macsec_drv_data *drv;
+ u32 *pn;
+ int ifindex;
+ u8 txsa;
+ u8 rxsa;
+ u64 rxsci;
+};
+
+struct macsec_genl_ctx {
+ struct nl_sock *sk;
+ int macsec_genl_id;
+ struct cb_arg cb_arg;
+};
+
+struct macsec_drv_data {
+ struct driver_wired_common_data common;
+ struct rtnl_link *link;
+ struct nl_cache *link_cache;
+ struct nl_sock *sk;
+ struct macsec_genl_ctx ctx;
+
+ struct netlink_data *netlink;
+ struct nl_handle *nl;
+ char ifname[IFNAMSIZ + 1];
+ int ifi;
+ int parent_ifi;
+
+ Boolean created_link;
+
+ Boolean controlled_port_enabled;
+ Boolean controlled_port_enabled_set;
+
+ Boolean protect_frames;
+ Boolean protect_frames_set;
+
+ Boolean encrypt;
+ Boolean encrypt_set;
+
+ Boolean replay_protect;
+ Boolean replay_protect_set;
+
+ u32 replay_window;
+
+ u8 encoding_sa;
+ Boolean encoding_sa_set;
+};
+
+
+static int dump_callback(struct nl_msg *msg, void *argp);
+
+
+static struct nl_msg * msg_prepare(enum macsec_nl_commands cmd,
+ const struct macsec_genl_ctx *ctx,
+ unsigned int ifindex)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc message");
+ return NULL;
+ }
+
+ if (!genlmsg_put(msg, 0, 0, ctx->macsec_genl_id, 0, 0, cmd, 0)) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to put header");
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_U32(msg, MACSEC_ATTR_IFINDEX, ifindex);
+
+ return msg;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+static int nla_put_rxsc_config(struct nl_msg *msg, u64 sci)
+{
+ struct nlattr *nest = nla_nest_start(msg, MACSEC_ATTR_RXSC_CONFIG);
+
+ if (!nest)
+ return -1;
+
+ NLA_PUT_U64(msg, MACSEC_RXSC_ATTR_SCI, sci);
+
+ nla_nest_end(msg, nest);
+
+ return 0;
+
+nla_put_failure:
+ return -1;
+}
+
+
+static int init_genl_ctx(struct macsec_drv_data *drv)
+{
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ ctx->sk = nl_socket_alloc();
+ if (!ctx->sk) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
+ return -1;
+ }
+
+ if (genl_connect(ctx->sk) < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "connection to genl socket failed");
+ goto out_free;
+ }
+
+ ctx->macsec_genl_id = genl_ctrl_resolve(ctx->sk, "macsec");
+ if (ctx->macsec_genl_id < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "genl resolve failed");
+ goto out_free;
+ }
+
+ memset(&ctx->cb_arg, 0, sizeof(ctx->cb_arg));
+ ctx->cb_arg.drv = drv;
+
+ nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, dump_callback,
+ &ctx->cb_arg);
+
+ return 0;
+
+out_free:
+ nl_socket_free(ctx->sk);
+ ctx->sk = NULL;
+ return -1;
+}
+
+
+static int try_commit(struct macsec_drv_data *drv)
+{
+ int err;
+
+ if (!drv->link)
+ return 0;
+
+ if (drv->controlled_port_enabled_set) {
+ struct rtnl_link *change = rtnl_link_alloc();
+
+ if (!change)
+ return -1;
+
+ rtnl_link_set_name(change, drv->ifname);
+
+ if (drv->controlled_port_enabled)
+ rtnl_link_set_flags(change, IFF_UP);
+ else
+ rtnl_link_unset_flags(change, IFF_UP);
+
+ err = rtnl_link_change(drv->sk, change, change, 0);
+ if (err < 0)
+ return err;
+
+ rtnl_link_put(change);
+
+ drv->controlled_port_enabled_set = FALSE;
+ }
+
+ if (drv->protect_frames_set)
+ rtnl_link_macsec_set_protect(drv->link, drv->protect_frames);
+
+ if (drv->encrypt_set)
+ rtnl_link_macsec_set_encrypt(drv->link, drv->encrypt);
+
+ if (drv->replay_protect_set) {
+ rtnl_link_macsec_set_replay_protect(drv->link,
+ drv->replay_protect);
+ if (drv->replay_protect)
+ rtnl_link_macsec_set_window(drv->link,
+ drv->replay_window);
+ }
+
+ if (drv->encoding_sa_set)
+ rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
+
+ err = rtnl_link_add(drv->sk, drv->link, 0);
+ if (err < 0)
+ return err;
+
+ drv->protect_frames_set = FALSE;
+ drv->encrypt_set = FALSE;
+ drv->replay_protect_set = FALSE;
+
+ return 0;
+}
+
+
+static void macsec_drv_wpa_deinit(void *priv)
+{
+ struct macsec_drv_data *drv = priv;
+
+ driver_wired_deinit_common(&drv->common);
+ os_free(drv);
+}
+
+
+static void * macsec_drv_wpa_init(void *ctx, const char *ifname)
+{
+ struct macsec_drv_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (!drv)
+ return NULL;
+
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ drv->sk = nl_socket_alloc();
+ if (!drv->sk)
+ return -1;
+
+ err = nl_connect(drv->sk, NETLINK_ROUTE);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "Unable to connect NETLINK_ROUTE socket: %s",
+ strerror(errno));
+ goto sock;
+ }
+
+ err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s",
+ strerror(errno));
+ goto sock;
+ }
+
+ drv->parent_ifi = rtnl_link_name2i(drv->link_cache, drv->common.ifname);
+ if (drv->parent_ifi == 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "couldn't find ifindex for interface %s",
+ drv->common.ifname);
+ goto cache;
+ }
+
+ err = init_genl_ctx(drv);
+ if (err < 0)
+ goto cache;
+
+ return 0;
+
+cache:
+ nl_cache_free(drv->link_cache);
+ drv->link_cache = NULL;
+sock:
+ nl_socket_free(drv->sk);
+ drv->sk = NULL;
+ return -1;
+}
+
+
+static int macsec_drv_macsec_deinit(void *priv)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ if (drv->sk)
+ nl_socket_free(drv->sk);
+ drv->sk = NULL;
+
+ if (drv->link_cache)
+ nl_cache_free(drv->link_cache);
+ drv->link_cache = NULL;
+
+ if (drv->ctx.sk)
+ nl_socket_free(drv->ctx.sk);
+
+ return 0;
+}
+
+
+static int macsec_drv_get_capability(void *priv, enum macsec_cap *cap)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ *cap = MACSEC_CAP_INTEG_AND_CONF;
+
+ return 0;
+}
+
+
+/**
+ * macsec_drv_enable_protect_frames - Set protect frames status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = protect frames enabled
+ * FALSE = protect frames disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_protect_frames(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->protect_frames_set = TRUE;
+ drv->protect_frames = enabled;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_enable_encrypt - Set protect frames status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = protect frames enabled
+ * FALSE = protect frames disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_encrypt(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->encrypt_set = TRUE;
+ drv->encrypt = enabled;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_set_replay_protect - Set replay protect status and window size
+ * @priv: Private driver interface data
+ * @enabled: TRUE = replay protect enabled
+ * FALSE = replay protect disabled
+ * @window: replay window size, valid only when replay protect enabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_replay_protect(void *priv, Boolean enabled,
+ u32 window)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
+ enabled ? "TRUE" : "FALSE", window);
+
+ drv->replay_protect_set = TRUE;
+ drv->replay_protect = enabled;
+ if (enabled)
+ drv->replay_window = window;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_set_current_cipher_suite - Set current cipher suite
+ * @priv: Private driver interface data
+ * @cs: EUI64 identifier
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
+{
+ wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
+ return 0;
+}
+
+
+/**
+ * macsec_drv_enable_controlled_port - Set controlled port status
+ * @priv: Private driver interface data
+ * @enabled: TRUE = controlled port enabled
+ * FALSE = controlled port disabled
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_enable_controlled_port(void *priv, Boolean enabled)
+{
+ struct macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ drv->controlled_port_enabled = enabled;
+ drv->controlled_port_enabled_set = TRUE;
+
+ return try_commit(drv);
+}
+
+
+static struct nla_policy sa_policy[MACSEC_SA_ATTR_MAX + 1] = {
+ [MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
+ [MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
+ [MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
+ [MACSEC_SA_ATTR_KEYID] = { .type = NLA_BINARY },
+};
+
+static struct nla_policy sc_policy[MACSEC_RXSC_ATTR_MAX + 1] = {
+ [MACSEC_RXSC_ATTR_SCI] = { .type = NLA_U64 },
+ [MACSEC_RXSC_ATTR_ACTIVE] = { .type = NLA_U8 },
+ [MACSEC_RXSC_ATTR_SA_LIST] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy main_policy[MACSEC_ATTR_MAX + 1] = {
+ [MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
+ [MACSEC_ATTR_SECY] = { .type = NLA_NESTED },
+ [MACSEC_ATTR_TXSA_LIST] = { .type = NLA_NESTED },
+ [MACSEC_ATTR_RXSC_LIST] = { .type = NLA_NESTED },
+};
+
+static int dump_callback(struct nl_msg *msg, void *argp)
+{
+ struct nlmsghdr *ret_hdr = nlmsg_hdr(msg);
+ struct nlattr *tb_msg[MACSEC_ATTR_MAX + 1];
+ struct cb_arg *arg = (struct cb_arg *) argp;
+ struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(ret_hdr);
+ int err;
+
+ if (ret_hdr->nlmsg_type != arg->drv->ctx.macsec_genl_id)
+ return 0;
+
+ err = nla_parse(tb_msg, MACSEC_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), main_policy);
+ if (err < 0)
+ return 0;
+
+ if (!tb_msg[MACSEC_ATTR_IFINDEX])
+ return 0;
+
+ if (nla_get_u32(tb_msg[MACSEC_ATTR_IFINDEX]) != (u32) arg->ifindex)
+ return 0;
+
+ if (arg->txsa < 4 && !tb_msg[MACSEC_ATTR_TXSA_LIST]) {
+ return 0;
+ } else if (arg->txsa < 4) {
+ struct nlattr *nla;
+ int rem;
+
+ nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_TXSA_LIST], rem) {
+ struct nlattr *tb[MACSEC_SA_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb, MACSEC_SA_ATTR_MAX, nla,
+ sa_policy);
+ if (err < 0)
+ continue;
+ if (!tb[MACSEC_SA_ATTR_AN])
+ continue;
+ if (nla_get_u8(tb[MACSEC_SA_ATTR_AN]) != arg->txsa)
+ continue;
+ if (!tb[MACSEC_SA_ATTR_PN])
+ return 0;
+ *arg->pn = nla_get_u32(tb[MACSEC_SA_ATTR_PN]);
+ return 0;
+ }
+
+ return 0;
+ }
+
+ if (arg->rxsci == UNUSED_SCI)
+ return 0;
+
+ if (tb_msg[MACSEC_ATTR_RXSC_LIST]) {
+ struct nlattr *nla;
+ int rem;
+
+ nla_for_each_nested(nla, tb_msg[MACSEC_ATTR_RXSC_LIST], rem) {
+ struct nlattr *tb[MACSEC_RXSC_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb, MACSEC_RXSC_ATTR_MAX, nla,
+ sc_policy);
+ if (err < 0)
+ return 0;
+ if (!tb[MACSEC_RXSC_ATTR_SCI])
+ continue;
+ if (nla_get_u64(tb[MACSEC_RXSC_ATTR_SCI]) != arg->rxsci)
+ continue;
+ if (!tb[MACSEC_RXSC_ATTR_SA_LIST])
+ return 0;
+
+ nla_for_each_nested(nla, tb[MACSEC_RXSC_ATTR_SA_LIST],
+ rem) {
+ struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+ err = nla_parse_nested(tb_sa,
+ MACSEC_SA_ATTR_MAX, nla,
+ sa_policy);
+ if (err < 0)
+ continue;
+ if (!tb_sa[MACSEC_SA_ATTR_AN])
+ continue;
+ if (nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]) !=
+ arg->rxsa)
+ continue;
+ if (!tb_sa[MACSEC_SA_ATTR_PN])
+ return 0;
+ *arg->pn =
+ nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static int nl_send_recv(struct nl_sock *sk, struct nl_msg *msg)
+{
+ int ret;
+
+ ret = nl_send_auto_complete(sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to send: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ return ret;
+ }
+
+ ret = nl_recvmsgs_default(sk);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+ return ret;
+}
+
+
+static int do_dump(struct macsec_drv_data *drv, u8 txsa, u64 rxsci, u8 rxsa,
+ u32 *pn)
+{
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 1;
+
+ ctx->cb_arg.ifindex = drv->ifi;
+ ctx->cb_arg.rxsci = rxsci;
+ ctx->cb_arg.rxsa = rxsa;
+ ctx->cb_arg.txsa = txsa;
+ ctx->cb_arg.pn = pn;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to alloc message",
+ __func__);
+ return 1;
+ }
+
+ if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->macsec_genl_id, 0,
+ NLM_F_DUMP, MACSEC_CMD_GET_TXSC, 0)) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to put header",
+ __func__);
+ goto out_free_msg;
+ }
+
+ 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));
+
+ ctx->cb_arg.pn = 0;
+
+out_free_msg:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_get_receive_lowest_pn - Get 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_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s", __func__);
+
+ err = do_dump(drv, 0xff, mka_sci_u64(&sa->sc->sci), sa->an,
+ &sa->lowest_pn);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: result %d", __func__,
+ sa->lowest_pn);
+
+ return err;
+}
+
+
+/**
+ * macsec_drv_get_transmit_next_pn - Get transmit next PN
+ * @priv: Private driver interface data
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ err = do_dump(drv, sa->an, UNUSED_SCI, 0xff, &sa->next_pn);
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: err %d result %d", __func__, err,
+ sa->next_pn);
+ return err;
+}
+
+
+/**
+ * macsec_drv_set_transmit_next_pn - Set transmit next 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_transmit_next_pn(void *priv, struct transmit_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, "%s -> %d: %d", __func__, sa->an, sa->next_pn);
+
+ msg = msg_prepare(MACSEC_CMD_UPD_TXSA, 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;
+}
+
+
+#define SCISTR MACSTR "::%hx"
+#define SCI2STR(addr, port) MAC2STR(addr), htons(port)
+
+/**
+ * macsec_drv_create_receive_sc - Create secure channel for receiving
+ * @priv: Private driver interface data
+ * @sc: secure channel
+ * @sci_addr: secure channel identifier - address
+ * @sci_port: secure channel identifier - port
+ * @conf_offset: confidentiality offset (0, 30, or 50)
+ * @validation: frame validation policy (0 = Disabled, 1 = Checked,
+ * 2 = Strict)
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int macsec_drv_create_receive_sc(void *priv, struct receive_sc *sc,
+ unsigned int conf_offset,
+ int validation)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
+ SCI2STR(sc->sci.addr, sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_ADD_RXSC, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
+ goto nla_put_failure;
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_receive_sc - Delete secure connection for receiving
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_receive_sc(void *priv, struct receive_sc *sc)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ wpa_printf(MSG_DEBUG, "%s -> " SCISTR, __func__,
+ SCI2STR(sc->sci.addr, sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_DEL_RXSC, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sc->sci)))
+ goto nla_put_failure;
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_create_receive_sa - Create secure association for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_receive_sa(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, "%s -> %d on " SCISTR, __func__, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_ADD_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
+ 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_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_receive);
+ NLA_PUT_U32(msg, MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
+ &sa->pkey->key_identifier);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_receive_sa - Delete secure association for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_receive_sa(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, "%s -> %d on " SCISTR, __func__, sa->an,
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port));
+
+ msg = msg_prepare(MACSEC_CMD_DEL_RXSA, ctx, drv->ifi);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, mka_sci_u64(&sa->sc->sci)))
+ goto nla_put_failure;
+
+ 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_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int set_active_rx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
+ u64 sci, unsigned char an, Boolean state)
+{
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ msg = msg_prepare(MACSEC_CMD_UPD_RXSA, ctx, ifindex);
+ if (!msg)
+ return ret;
+
+ if (nla_put_rxsc_config(msg, sci))
+ goto nla_put_failure;
+
+ nest = nla_nest_start(msg, MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_AN, an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0)
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_enable_receive_sa - Enable the SA for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, 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),
+ sa->an, TRUE);
+}
+
+
+/**
+ * macsec_drv_disable_receive_sa - Disable SA for receive
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d on " SCISTR, __func__, 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),
+ sa->an, FALSE);
+}
+
+
+static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci)
+{
+ struct rtnl_link *needle;
+ void *match;
+
+ needle = rtnl_link_macsec_alloc();
+ if (!needle)
+ return NULL;
+
+ rtnl_link_set_link(needle, parent);
+ rtnl_link_macsec_set_sci(needle, sci);
+
+ match = nl_cache_find(cache, (struct nl_object *) needle);
+ rtnl_link_put(needle);
+
+ return (struct rtnl_link *) match;
+}
+
+
+/**
+ * macsec_drv_create_transmit_sc - Create secure connection for transmit
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * @conf_offset: confidentiality offset
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_transmit_sc(
+ void *priv, struct transmit_sc *sc,
+ enum confidentiality_offset conf_offset)
+{
+ struct macsec_drv_data *drv = priv;
+ struct rtnl_link *link;
+ char *ifname;
+ u64 sci;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ link = rtnl_link_macsec_alloc();
+ if (!link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_link(link, drv->parent_ifi);
+
+ sci = mka_sci_u64(&sc->sci);
+ rtnl_link_macsec_set_sci(link, sci);
+
+ drv->created_link = TRUE;
+
+ err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
+ if (err == -NLE_BUSY) {
+ wpa_printf(MSG_INFO,
+ DRV_PREFIX "link already exists, using it");
+ drv->created_link = FALSE;
+ } else if (err < 0) {
+ rtnl_link_put(link);
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't create link: err %d",
+ err);
+ return err;
+ }
+
+ rtnl_link_put(link);
+
+ nl_cache_refill(drv->sk, drv->link_cache);
+ link = lookup_sc(drv->link_cache, drv->parent_ifi, sci);
+ if (!link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link");
+ return -1;
+ }
+
+ drv->ifi = rtnl_link_get_ifindex(link);
+ ifname = rtnl_link_get_name(link);
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ rtnl_link_put(link);
+
+ drv->link = rtnl_link_macsec_alloc();
+ if (!drv->link) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_name(drv->link, drv->ifname);
+
+ /* In case some settings have already been done but we couldn't apply
+ * them. */
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_delete_transmit_sc - Delete secure connection for transmit
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_transmit_sc(void *priv, struct transmit_sc *sc)
+{
+ struct macsec_drv_data *drv = priv;
+ int err;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ if (!drv->created_link) {
+ rtnl_link_put(drv->link);
+ drv->link = NULL;
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "we didn't create the link, leave it alone");
+ return 0;
+ }
+
+ err = rtnl_link_delete(drv->sk, drv->link);
+ if (err < 0)
+ wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't delete link");
+ rtnl_link_put(drv->link);
+ drv->link = NULL;
+
+ return err;
+}
+
+
+/**
+ * macsec_drv_create_transmit_sa - Create secure association for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_create_transmit_sa(void *priv, struct transmit_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, "%s -> %d", __func__, sa->an);
+
+ msg = msg_prepare(MACSEC_CMD_ADD_TXSA, 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_PUT(msg, MACSEC_SA_ATTR_KEYID, sizeof(sa->pkey->key_identifier),
+ &sa->pkey->key_identifier);
+ NLA_PUT(msg, MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, sa->enable_transmit);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_delete_transmit_sa - Delete secure association for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_delete_transmit_sa(void *priv, struct transmit_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, "%s -> %d", __func__, sa->an);
+
+ msg = msg_prepare(MACSEC_CMD_DEL_TXSA, 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_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int set_active_tx_sa(const struct macsec_genl_ctx *ctx, int ifindex,
+ unsigned char an, Boolean state)
+{
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ int ret = -1;
+
+ msg = msg_prepare(MACSEC_CMD_UPD_TXSA, ctx, ifindex);
+ 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, an);
+ NLA_PUT_U8(msg, MACSEC_SA_ATTR_ACTIVE, !!state);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "%s: failed to communicate: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * macsec_drv_enable_transmit_sa - Enable SA for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+
+ ret = set_active_tx_sa(ctx, drv->ifi, sa->an, TRUE);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to enable txsa");
+ return ret;
+ }
+
+ drv->encoding_sa_set = TRUE;
+ drv->encoding_sa = sa->an;
+
+ return try_commit(drv);
+}
+
+
+/**
+ * macsec_drv_disable_transmit_sa - Disable SA for transmit
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_drv_disable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct macsec_drv_data *drv = priv;
+ struct macsec_genl_ctx *ctx = &drv->ctx;
+
+ wpa_printf(MSG_DEBUG, "%s -> %d", __func__, sa->an);
+
+ return set_active_tx_sa(ctx, drv->ifi, sa->an, FALSE);
+}
+
+
+const struct wpa_driver_ops wpa_driver_macsec_linux_ops = {
+ .name = "macsec_linux",
+ .desc = "MACsec Ethernet driver for Linux",
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
+ .init = macsec_drv_wpa_init,
+ .deinit = macsec_drv_wpa_deinit,
+
+ .macsec_init = macsec_drv_macsec_init,
+ .macsec_deinit = macsec_drv_macsec_deinit,
+ .macsec_get_capability = macsec_drv_get_capability,
+ .enable_protect_frames = macsec_drv_enable_protect_frames,
+ .enable_encrypt = macsec_drv_enable_encrypt,
+ .set_replay_protect = macsec_drv_set_replay_protect,
+ .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,
+ .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,
+ .delete_receive_sc = macsec_drv_delete_receive_sc,
+ .create_receive_sa = macsec_drv_create_receive_sa,
+ .delete_receive_sa = macsec_drv_delete_receive_sa,
+ .enable_receive_sa = macsec_drv_enable_receive_sa,
+ .disable_receive_sa = macsec_drv_disable_receive_sa,
+ .create_transmit_sc = macsec_drv_create_transmit_sc,
+ .delete_transmit_sc = macsec_drv_delete_transmit_sc,
+ .create_transmit_sa = macsec_drv_create_transmit_sa,
+ .delete_transmit_sa = macsec_drv_delete_transmit_sa,
+ .enable_transmit_sa = macsec_drv_enable_transmit_sa,
+ .disable_transmit_sa = macsec_drv_disable_transmit_sa,
+};
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index 3eae2f8..d3be19c 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -11,6 +11,7 @@
#include "includes.h"
#include <sys/ioctl.h>
#include <net/if.h>
+#include <inttypes.h>
#ifdef __linux__
#include <netpacket/packet.h>
#include <net/if_arp.h>
@@ -28,7 +29,9 @@
#include "utils/eloop.h"
#include "common/defs.h"
#include "common/ieee802_1x_defs.h"
+#include "pae/ieee802_1x_kay.h"
#include "driver.h"
+#include "driver_wired_common.h"
#include "nss_macsec_secy.h"
#include "nss_macsec_secy_rx.h"
@@ -51,17 +54,14 @@
#pragma pack(pop)
#endif /* _MSC_VER */
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+struct channel_map {
+ struct ieee802_1x_mka_sci sci;
+};
struct macsec_qca_data {
- char ifname[IFNAMSIZ + 1];
- u32 secy_id;
- void *ctx;
+ struct driver_wired_common_data common;
- int sock; /* raw packet socket for driver access */
- int pf_sock;
- int membership, multi, iff_allmulti, iff_up;
+ u32 secy_id;
/* shadow */
Boolean always_include_sci;
@@ -70,194 +70,12 @@
Boolean protect_frames;
Boolean replay_protect;
u32 replay_window;
+
+ struct channel_map receive_channel_map[MAXSC];
+ struct channel_map transmit_channel_map[MAXSC];
};
-static int macsec_qca_multicast_membership(int sock, int ifindex,
- const u8 *addr, int add)
-{
-#ifdef __linux__
- struct packet_mreq mreq;
-
- if (sock < 0)
- return -1;
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
- if (setsockopt(sock, SOL_PACKET,
- add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
- return -1;
- }
- return 0;
-#else /* __linux__ */
- return -1;
-#endif /* __linux__ */
-}
-
-
-static int macsec_qca_get_ssid(void *priv, u8 *ssid)
-{
- ssid[0] = 0;
- return 0;
-}
-
-
-static int macsec_qca_get_bssid(void *priv, u8 *bssid)
-{
- /* Report PAE group address as the "BSSID" for macsec connection. */
- os_memcpy(bssid, pae_group_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int macsec_qca_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_WIRED;
- return 0;
-}
-
-
-static int macsec_qca_get_ifflags(const char *ifname, int *flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-static int macsec_qca_set_ifflags(const char *ifname, int flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-static int macsec_qca_get_ifstatus(const char *ifname, int *status)
-{
- struct ifmediareq ifmr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_print(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifmr, 0, sizeof(ifmr));
- os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
- (IFM_ACTIVE | IFM_AVALID);
-
- return 0;
-}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-
-
-static int macsec_qca_multi(const char *ifname, const u8 *addr, int add)
-{
- struct ifreq ifr;
- int s;
-
-#ifdef __sun__
- return -1;
-#endif /* __sun__ */
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-#ifdef __linux__
- ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
- os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- struct sockaddr_dl *dlp;
- dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
- dlp->sdl_len = sizeof(struct sockaddr_dl);
- dlp->sdl_family = AF_LINK;
- dlp->sdl_index = 0;
- dlp->sdl_nlen = 0;
- dlp->sdl_alen = ETH_ALEN;
- dlp->sdl_slen = 0;
- os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
- {
- struct sockaddr *sap;
- sap = (struct sockaddr *) &ifr.ifr_addr;
- sap->sa_len = sizeof(struct sockaddr);
- sap->sa_family = AF_UNSPEC;
- os_memcpy(sap->sa_data, addr, ETH_ALEN);
- }
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
-
- if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
static void __macsec_drv_init(struct macsec_qca_data *drv)
{
int ret = 0;
@@ -308,76 +126,23 @@
static void * macsec_qca_init(void *ctx, const char *ifname)
{
struct macsec_qca_data *drv;
- int flags;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ctx = ctx;
/* Board specific settings */
- if (os_memcmp("eth2", drv->ifname, 4) == 0)
+ if (os_memcmp("eth2", ifname, 4) == 0)
drv->secy_id = 1;
- else if (os_memcmp("eth3", drv->ifname, 4) == 0)
+ else if (os_memcmp("eth3", ifname, 4) == 0)
drv->secy_id = 2;
else
drv->secy_id = -1;
-#ifdef __linux__
- drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
- if (drv->pf_sock < 0)
- wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
-#else /* __linux__ */
- drv->pf_sock = -1;
-#endif /* __linux__ */
-
- if (macsec_qca_get_ifflags(ifname, &flags) == 0 &&
- !(flags & IFF_UP) &&
- macsec_qca_set_ifflags(ifname, flags | IFF_UP) == 0) {
- drv->iff_up = 1;
- }
-
- if (macsec_qca_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Added multicast membership with packet socket",
- __func__);
- drv->membership = 1;
- } else if (macsec_qca_multi(ifname, pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Added multicast membership with SIOCADDMULTI",
- __func__);
- drv->multi = 1;
- } else if (macsec_qca_get_ifflags(ifname, &flags) < 0) {
- wpa_printf(MSG_INFO, "%s: Could not get interface flags",
- __func__);
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
os_free(drv);
return NULL;
- } else if (flags & IFF_ALLMULTI) {
- wpa_printf(MSG_DEBUG,
- "%s: Interface is already configured for multicast",
- __func__);
- } else if (macsec_qca_set_ifflags(ifname, flags | IFF_ALLMULTI) < 0) {
- wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
- __func__);
- os_free(drv);
- return NULL;
- } else {
- wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
- drv->iff_allmulti = 1;
}
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- int status;
- wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
- __func__);
- while (macsec_qca_get_ifstatus(ifname, &status) == 0 &&
- status == 0)
- sleep(1);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
return drv;
}
@@ -386,42 +151,8 @@
static void macsec_qca_deinit(void *priv)
{
struct macsec_qca_data *drv = priv;
- int flags;
- if (drv->membership &&
- macsec_qca_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Failed to remove PAE multicast group (PACKET)",
- __func__);
- }
-
- if (drv->multi &&
- macsec_qca_multi(drv->ifname, pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
- __func__);
- }
-
- if (drv->iff_allmulti &&
- (macsec_qca_get_ifflags(drv->ifname, &flags) < 0 ||
- macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_ALLMULTI) < 0)) {
- wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
- __func__);
- }
-
- if (drv->iff_up &&
- macsec_qca_get_ifflags(drv->ifname, &flags) == 0 &&
- (flags & IFF_UP) &&
- macsec_qca_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
- __func__);
- }
-
- if (drv->pf_sock != -1)
- close(drv->pf_sock);
-
+ driver_wired_deinit_common(&drv->common);
os_free(drv);
}
@@ -456,6 +187,16 @@
}
+static int macsec_qca_get_capability(void *priv, enum macsec_cap *cap)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+
+ *cap = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
+
+ return 0;
+}
+
+
static int macsec_qca_enable_protect_frames(void *priv, Boolean enabled)
{
struct macsec_qca_data *drv = priv;
@@ -485,15 +226,12 @@
}
-static int macsec_qca_set_current_cipher_suite(void *priv, const u8 *cs,
- size_t cs_len)
+static int macsec_qca_set_current_cipher_suite(void *priv, u64 cs)
{
- u8 default_cs_id[] = CS_ID_GCM_AES_128;
-
- if (cs_len != CS_ID_LEN ||
- os_memcmp(cs, default_cs_id, cs_len) != 0) {
- wpa_hexdump(MSG_ERROR, "macsec: NOT supported CipherSuite",
- cs, cs_len);
+ if (cs != CS_ID_GCM_AES_128) {
+ wpa_printf(MSG_ERROR,
+ "%s: NOT supported CipherSuite: %016" PRIx64,
+ __func__, cs);
return -1;
}
@@ -517,16 +255,82 @@
}
-static int macsec_qca_get_receive_lowest_pn(void *priv, u32 channel, u8 an,
- u32 *lowest_pn)
+static int macsec_qca_lookup_channel(struct channel_map *map,
+ struct ieee802_1x_mka_sci *sci,
+ u32 *channel)
+{
+ u32 i;
+
+ for (i = 0; i < MAXSC; i++) {
+ if (os_memcmp(&map[i].sci, sci,
+ sizeof(struct ieee802_1x_mka_sci)) == 0) {
+ *channel = i;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+static void macsec_qca_register_channel(struct channel_map *map,
+ struct ieee802_1x_mka_sci *sci,
+ u32 channel)
+{
+ os_memcpy(&map[channel].sci, sci, sizeof(struct ieee802_1x_mka_sci));
+}
+
+
+static int macsec_qca_lookup_receive_channel(struct macsec_qca_data *drv,
+ struct receive_sc *sc,
+ u32 *channel)
+{
+ return macsec_qca_lookup_channel(drv->receive_channel_map, &sc->sci,
+ channel);
+}
+
+
+static void macsec_qca_register_receive_channel(struct macsec_qca_data *drv,
+ struct receive_sc *sc,
+ u32 channel)
+{
+ macsec_qca_register_channel(drv->receive_channel_map, &sc->sci,
+ channel);
+}
+
+
+static int macsec_qca_lookup_transmit_channel(struct macsec_qca_data *drv,
+ struct transmit_sc *sc,
+ u32 *channel)
+{
+ return macsec_qca_lookup_channel(drv->transmit_channel_map, &sc->sci,
+ channel);
+}
+
+
+static void macsec_qca_register_transmit_channel(struct macsec_qca_data *drv,
+ struct transmit_sc *sc,
+ u32 channel)
+{
+ macsec_qca_register_channel(drv->transmit_channel_map, &sc->sci,
+ channel);
+}
+
+
+static int macsec_qca_get_receive_lowest_pn(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
u32 next_pn = 0;
bool enabled = FALSE;
u32 win;
+ u32 channel;
- ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, an,
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
+
+ ret += nss_macsec_secy_rx_sa_next_pn_get(drv->secy_id, channel, sa->an,
&next_pn);
ret += nss_macsec_secy_rx_sc_replay_protect_get(drv->secy_id, channel,
&enabled);
@@ -534,40 +338,49 @@
channel, &win);
if (enabled)
- *lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
+ sa->lowest_pn = (next_pn > win) ? (next_pn - win) : 1;
else
- *lowest_pn = next_pn;
+ sa->lowest_pn = next_pn;
- wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, *lowest_pn);
+ wpa_printf(MSG_DEBUG, "%s: lpn=0x%x", __func__, sa->lowest_pn);
return ret;
}
-static int macsec_qca_get_transmit_next_pn(void *priv, u32 channel, u8 an,
- u32 *next_pn)
+static int macsec_qca_get_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
+ u32 channel;
- ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, an,
- next_pn);
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, *next_pn);
+ ret += nss_macsec_secy_tx_sa_next_pn_get(drv->secy_id, channel, sa->an,
+ &sa->next_pn);
+
+ wpa_printf(MSG_DEBUG, "%s: npn=0x%x", __func__, sa->next_pn);
return ret;
}
-int macsec_qca_set_transmit_next_pn(void *priv, u32 channel, u8 an, u32 next_pn)
+int macsec_qca_set_transmit_next_pn(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
int ret = 0;
+ u32 channel;
- ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, an,
- next_pn);
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, next_pn);
+ ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
+ sa->next_pn);
+
+ wpa_printf(MSG_INFO, "%s: npn=0x%x", __func__, sa->next_pn);
return ret;
}
@@ -600,8 +413,7 @@
}
-static int macsec_qca_create_receive_sc(void *priv, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+static int macsec_qca_create_receive_sc(void *priv, struct receive_sc *sc,
unsigned int conf_offset,
int validation)
{
@@ -610,6 +422,13 @@
fal_rx_prc_lut_t entry;
fal_rx_sc_validate_frame_e vf;
enum validate_frames validate_frames = validation;
+ u32 channel;
+ const u8 *sci_addr = sc->sci.addr;
+ u16 sci_port = be_to_host16(sc->sci.port);
+
+ ret = macsec_qca_get_available_receive_sc(priv, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -644,15 +463,22 @@
channel,
drv->replay_window);
+ macsec_qca_register_receive_channel(drv, sc, channel);
+
return ret;
}
-static int macsec_qca_delete_receive_sc(void *priv, u32 channel)
+static int macsec_qca_delete_receive_sc(void *priv, struct receive_sc *sc)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_rx_prc_lut_t entry;
+ u32 channel;
+
+ ret = macsec_qca_lookup_receive_channel(priv, sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -666,49 +492,68 @@
}
-static int macsec_qca_create_receive_sa(void *priv, u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak)
+static int macsec_qca_create_receive_sa(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_rx_sak_t rx_sak;
int i = 0;
+ u32 channel;
+
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s, channel=%d, an=%d, lpn=0x%x",
- __func__, channel, an, lowest_pn);
+ __func__, channel, sa->an, sa->lowest_pn);
os_memset(&rx_sak, 0, sizeof(rx_sak));
for (i = 0; i < 16; i++)
- rx_sak.sak[i] = sak[15 - i];
+ rx_sak.sak[i] = sa->pkey->key[15 - i];
- ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, an);
- ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, an, &rx_sak);
+ ret += nss_macsec_secy_rx_sa_create(drv->secy_id, channel, sa->an);
+ ret += nss_macsec_secy_rx_sak_set(drv->secy_id, channel, sa->an,
+ &rx_sak);
return ret;
}
-static int macsec_qca_enable_receive_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_enable_receive_sa(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, TRUE);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
+
+ ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
+ TRUE);
return ret;
}
-static int macsec_qca_disable_receive_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_disable_receive_sa(void *priv, struct receive_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ ret = macsec_qca_lookup_receive_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, an, FALSE);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
+
+ ret += nss_macsec_secy_rx_sa_en_set(drv->secy_id, channel, sa->an,
+ FALSE);
return ret;
}
@@ -717,14 +562,12 @@
static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
u32 sc_ch = 0;
bool in_use = FALSE;
for (sc_ch = 0; sc_ch < MAXSC; sc_ch++) {
- ret = nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
- &in_use);
- if (ret)
+ if (nss_macsec_secy_tx_sc_in_used_get(drv->secy_id, sc_ch,
+ &in_use))
continue;
if (!in_use) {
@@ -741,14 +584,18 @@
}
-static int macsec_qca_create_transmit_sc(void *priv, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+static int macsec_qca_create_transmit_sc(void *priv, struct transmit_sc *sc,
unsigned int conf_offset)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_tx_class_lut_t entry;
u8 psci[ETH_ALEN + 2];
+ u32 channel;
+
+ ret = macsec_qca_get_available_transmit_sc(priv, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -759,9 +606,9 @@
entry.action = FAL_TX_CLASS_ACTION_FORWARD;
entry.channel = channel;
- os_memcpy(psci, sci_addr, ETH_ALEN);
- psci[6] = (sci_port >> 8) & 0xf;
- psci[7] = sci_port & 0xf;
+ os_memcpy(psci, sc->sci.addr, ETH_ALEN);
+ psci[6] = (sc->sci.port >> 8) & 0xf;
+ psci[7] = sc->sci.port & 0xf;
ret += nss_macsec_secy_tx_class_lut_set(drv->secy_id, channel, &entry);
ret += nss_macsec_secy_tx_sc_create(drv->secy_id, channel, psci, 8);
@@ -771,15 +618,22 @@
channel,
conf_offset);
+ macsec_qca_register_transmit_channel(drv, sc, channel);
+
return ret;
}
-static int macsec_qca_delete_transmit_sc(void *priv, u32 channel)
+static int macsec_qca_delete_transmit_sc(void *priv, struct transmit_sc *sc)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
fal_tx_class_lut_t entry;
+ u32 channel;
+
+ ret = macsec_qca_lookup_transmit_channel(priv, sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG, "%s: channel=%d", __func__, channel);
@@ -793,19 +647,22 @@
}
-static int macsec_qca_create_transmit_sa(void *priv, u32 channel, u8 an,
- u32 next_pn, Boolean confidentiality,
- const u8 *sak)
+static int macsec_qca_create_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
u8 tci = 0;
fal_tx_sak_t tx_sak;
int i;
+ u32 channel;
+
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
wpa_printf(MSG_DEBUG,
"%s: channel=%d, an=%d, next_pn=0x%x, confidentiality=%d",
- __func__, channel, an, next_pn, confidentiality);
+ __func__, channel, sa->an, sa->next_pn, sa->confidentiality);
if (drv->always_include_sci)
tci |= TCI_SC;
@@ -814,45 +671,60 @@
else if (drv->use_scb)
tci |= TCI_SCB;
- if (confidentiality)
+ if (sa->confidentiality)
tci |= TCI_E | TCI_C;
os_memset(&tx_sak, 0, sizeof(tx_sak));
for (i = 0; i < 16; i++)
- tx_sak.sak[i] = sak[15 - i];
+ tx_sak.sak[i] = sa->pkey->key[15 - i];
- ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, an,
- next_pn);
- ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, an, &tx_sak);
+ ret += nss_macsec_secy_tx_sa_next_pn_set(drv->secy_id, channel, sa->an,
+ sa->next_pn);
+ ret += nss_macsec_secy_tx_sak_set(drv->secy_id, channel, sa->an,
+ &tx_sak);
ret += nss_macsec_secy_tx_sc_tci_7_2_set(drv->secy_id, channel,
(tci >> 2));
- ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, an);
+ ret += nss_macsec_secy_tx_sc_an_set(drv->secy_id, channel, sa->an);
return ret;
}
-static int macsec_qca_enable_transmit_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_enable_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, TRUE);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
+
+ ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
+ TRUE);
return ret;
}
-static int macsec_qca_disable_transmit_sa(void *priv, u32 channel, u8 an)
+static int macsec_qca_disable_transmit_sa(void *priv, struct transmit_sa *sa)
{
struct macsec_qca_data *drv = priv;
- int ret = 0;
+ int ret;
+ u32 channel;
- wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel, an);
+ ret = macsec_qca_lookup_transmit_channel(priv, sa->sc, &channel);
+ if (ret != 0)
+ return ret;
- ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, an, FALSE);
+ wpa_printf(MSG_DEBUG, "%s: channel=%d, an=%d", __func__, channel,
+ sa->an);
+
+ ret += nss_macsec_secy_tx_sa_en_set(drv->secy_id, channel, sa->an,
+ FALSE);
return ret;
}
@@ -861,14 +733,15 @@
const struct wpa_driver_ops wpa_driver_macsec_qca_ops = {
.name = "macsec_qca",
.desc = "QCA MACsec Ethernet driver",
- .get_ssid = macsec_qca_get_ssid,
- .get_bssid = macsec_qca_get_bssid,
- .get_capa = macsec_qca_get_capa,
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
.init = macsec_qca_init,
.deinit = macsec_qca_deinit,
.macsec_init = macsec_qca_macsec_init,
.macsec_deinit = macsec_qca_macsec_deinit,
+ .macsec_get_capability = macsec_qca_get_capability,
.enable_protect_frames = macsec_qca_enable_protect_frames,
.set_replay_protect = macsec_qca_set_replay_protect,
.set_current_cipher_suite = macsec_qca_set_current_cipher_suite,
@@ -876,13 +749,11 @@
.get_receive_lowest_pn = macsec_qca_get_receive_lowest_pn,
.get_transmit_next_pn = macsec_qca_get_transmit_next_pn,
.set_transmit_next_pn = macsec_qca_set_transmit_next_pn,
- .get_available_receive_sc = macsec_qca_get_available_receive_sc,
.create_receive_sc = macsec_qca_create_receive_sc,
.delete_receive_sc = macsec_qca_delete_receive_sc,
.create_receive_sa = macsec_qca_create_receive_sa,
.enable_receive_sa = macsec_qca_enable_receive_sa,
.disable_receive_sa = macsec_qca_disable_receive_sa,
- .get_available_transmit_sc = macsec_qca_get_available_transmit_sc,
.create_transmit_sc = macsec_qca_create_transmit_sc,
.delete_transmit_sc = macsec_qca_delete_transmit_sc,
.create_transmit_sa = macsec_qca_create_transmit_sa,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 08945bd..e9107b3 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -29,6 +29,7 @@
#include "common/qca-vendor-attr.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_common.h"
#include "l2_packet/l2_packet.h"
#include "netlink.h"
#include "linux_defines.h"
@@ -200,6 +201,12 @@
static int i802_set_iface_flags(struct i802_bss *bss, int up);
static int nl80211_set_param(void *priv, const char *param);
+#ifdef CONFIG_MESH
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+ struct wpa_driver_mesh_bss_params *params);
+#endif /* CONFIG_MESH */
+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
+ int reason);
/* Converts nl80211_chan_width to a common format */
@@ -445,6 +452,8 @@
void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg, int flags, uint8_t cmd)
{
+ if (TEST_FAIL())
+ return NULL;
return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
0, flags, cmd, 0);
}
@@ -667,6 +676,7 @@
struct nl80211_wiphy_data *w;
int wiphy_idx, found = 0;
struct i802_bss *tmp_bss;
+ u8 channel;
if (bss->wiphy_data != NULL)
return bss->wiphy_data;
@@ -686,29 +696,35 @@
dl_list_init(&w->bsss);
dl_list_init(&w->drvs);
- w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!w->nl_cb) {
- os_free(w);
- return NULL;
- }
- nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
- nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
- w);
+ /* Beacon frames not supported in IEEE 802.11ad */
+ if (ieee80211_freq_to_chan(bss->freq, &channel) !=
+ HOSTAPD_MODE_IEEE80211AD) {
+ w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!w->nl_cb) {
+ os_free(w);
+ return NULL;
+ }
+ nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+ no_seq_check, NULL);
+ nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+ process_beacon_event, w);
- w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
- "wiphy beacons");
- if (w->nl_beacons == NULL) {
- os_free(w);
- return NULL;
- }
+ w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+ "wiphy beacons");
+ if (w->nl_beacons == NULL) {
+ os_free(w);
+ return NULL;
+ }
- if (nl80211_register_beacons(bss->drv, w)) {
- nl_destroy_handles(&w->nl_beacons);
- os_free(w);
- return NULL;
- }
+ if (nl80211_register_beacons(bss->drv, w)) {
+ nl_destroy_handles(&w->nl_beacons);
+ os_free(w);
+ return NULL;
+ }
- nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
+ nl80211_register_eloop_read(&w->nl_beacons,
+ nl80211_recv_beacons, w);
+ }
dl_list_add(&nl80211_wiphys, &w->list);
@@ -755,7 +771,8 @@
if (!dl_list_empty(&w->bsss))
return;
- nl80211_destroy_eloop_handle(&w->nl_beacons);
+ if (w->nl_beacons)
+ nl80211_destroy_eloop_handle(&w->nl_beacons);
nl_cb_put(w->nl_cb);
dl_list_del(&w->list);
@@ -1175,16 +1192,108 @@
}
-unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+struct nl80211_get_assoc_freq_arg {
+ struct wpa_driver_nl80211_data *drv;
+ unsigned int assoc_freq;
+ unsigned int ibss_freq;
+ u8 assoc_bssid[ETH_ALEN];
+ u8 assoc_ssid[SSID_MAX_LEN];
+ u8 assoc_ssid_len;
+};
+
+static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ };
+ struct nl80211_get_assoc_freq_arg *ctx = arg;
+ enum nl80211_bss_status status;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS] ||
+ nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy) ||
+ !bss[NL80211_BSS_STATUS])
+ return NL_SKIP;
+
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ ctx->assoc_freq);
+ }
+ if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ ctx->ibss_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
+ ctx->ibss_freq);
+ }
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_BSSID]) {
+ os_memcpy(ctx->assoc_bssid,
+ nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(ctx->assoc_bssid));
+ }
+
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ const u8 *ie, *ssid;
+ size_t ie_len;
+
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ssid = get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid && ssid[1] > 0 && ssid[1] <= SSID_MAX_LEN) {
+ ctx->assoc_ssid_len = ssid[1];
+ os_memcpy(ctx->assoc_ssid, ssid + 2, ssid[1]);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid)
{
struct nl_msg *msg;
int ret;
- struct nl80211_bss_info_arg arg;
+ struct nl80211_get_assoc_freq_arg arg;
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
arg.drv = drv;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg);
+ if (ret == 0) {
+ os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len);
+ return arg.assoc_ssid_len;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int ret;
+ struct nl80211_get_assoc_freq_arg arg;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ os_memset(&arg, 0, sizeof(arg));
+ arg.drv = drv;
+ ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler,
+ &arg);
if (ret == 0) {
unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
arg.ibss_freq : arg.assoc_freq;
@@ -1989,6 +2098,10 @@
if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
ret = -1;
+ /* Radio Measurement - Radio Measurement Request */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x00", 2) < 0)
+ ret = -1;
+
/* Radio Measurement - Link Measurement Request */
if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
(nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
@@ -2060,6 +2173,9 @@
/* RRM Measurement Report */
if (nl80211_register_action_frame(bss, (u8 *) "\x05\x01", 2) < 0)
ret = -1;
+ /* RRM Link Measurement Report */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x03", 2) < 0)
+ ret = -1;
/* RRM Neighbor Report Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x05\x04", 2) < 0)
ret = -1;
@@ -2131,9 +2247,6 @@
if (nl80211_register_spurious_class3(bss))
goto out_err;
- if (nl80211_get_wiphy_data_ap(bss) == NULL)
- goto out_err;
-
nl80211_mgmt_handle_register_eloop(bss);
return 0;
@@ -2326,7 +2439,8 @@
if (drv->hostapd || bss->static_ap)
nlmode = NL80211_IFTYPE_AP;
- else if (bss->if_dynamic)
+ else if (bss->if_dynamic ||
+ nl80211_get_ifmode(bss) == NL80211_IFTYPE_MESH_POINT)
nlmode = nl80211_get_ifmode(bss);
else
nlmode = NL80211_IFTYPE_STATION;
@@ -2387,12 +2501,14 @@
}
-static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
+static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss)
{
struct nl_msg *msg;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
drv->ifindex);
+ nl80211_put_wiphy_data_ap(bss);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
return send_and_recv_msgs(drv, msg, NULL, NULL);
}
@@ -2408,6 +2524,7 @@
static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ unsigned int i;
wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
bss->ifname, drv->disabled_11b_rates);
@@ -2444,7 +2561,7 @@
nl80211_remove_monitor_interface(drv);
if (is_ap_interface(drv->nlmode))
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
if (drv->eapol_sock >= 0) {
eloop_unregister_read_sock(drv->eapol_sock);
@@ -2504,6 +2621,10 @@
os_free(drv->extended_capa);
os_free(drv->extended_capa_mask);
+ for (i = 0; i < drv->num_iface_ext_capa; i++) {
+ os_free(drv->iface_ext_capa[i].ext_capa);
+ os_free(drv->iface_ext_capa[i].ext_capa_mask);
+ }
os_free(drv->first_bss);
os_free(drv);
}
@@ -2514,30 +2635,30 @@
switch (alg) {
case WPA_ALG_WEP:
if (key_len == 5)
- return WLAN_CIPHER_SUITE_WEP40;
- return WLAN_CIPHER_SUITE_WEP104;
+ return RSN_CIPHER_SUITE_WEP40;
+ return RSN_CIPHER_SUITE_WEP104;
case WPA_ALG_TKIP:
- return WLAN_CIPHER_SUITE_TKIP;
+ return RSN_CIPHER_SUITE_TKIP;
case WPA_ALG_CCMP:
- return WLAN_CIPHER_SUITE_CCMP;
+ return RSN_CIPHER_SUITE_CCMP;
case WPA_ALG_GCMP:
- return WLAN_CIPHER_SUITE_GCMP;
+ return RSN_CIPHER_SUITE_GCMP;
case WPA_ALG_CCMP_256:
- return WLAN_CIPHER_SUITE_CCMP_256;
+ return RSN_CIPHER_SUITE_CCMP_256;
case WPA_ALG_GCMP_256:
- return WLAN_CIPHER_SUITE_GCMP_256;
+ return RSN_CIPHER_SUITE_GCMP_256;
case WPA_ALG_IGTK:
- return WLAN_CIPHER_SUITE_AES_CMAC;
+ return RSN_CIPHER_SUITE_AES_128_CMAC;
case WPA_ALG_BIP_GMAC_128:
- return WLAN_CIPHER_SUITE_BIP_GMAC_128;
+ return RSN_CIPHER_SUITE_BIP_GMAC_128;
case WPA_ALG_BIP_GMAC_256:
- return WLAN_CIPHER_SUITE_BIP_GMAC_256;
+ return RSN_CIPHER_SUITE_BIP_GMAC_256;
case WPA_ALG_BIP_CMAC_256:
- return WLAN_CIPHER_SUITE_BIP_CMAC_256;
+ return RSN_CIPHER_SUITE_BIP_CMAC_256;
case WPA_ALG_SMS4:
- return WLAN_CIPHER_SUITE_SMS4;
+ return RSN_CIPHER_SUITE_SMS4;
case WPA_ALG_KRK:
- return WLAN_CIPHER_SUITE_KRK;
+ return RSN_CIPHER_SUITE_KRK;
case WPA_ALG_NONE:
case WPA_ALG_PMK:
wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
@@ -2555,21 +2676,21 @@
{
switch (cipher) {
case WPA_CIPHER_CCMP_256:
- return WLAN_CIPHER_SUITE_CCMP_256;
+ return RSN_CIPHER_SUITE_CCMP_256;
case WPA_CIPHER_GCMP_256:
- return WLAN_CIPHER_SUITE_GCMP_256;
+ return RSN_CIPHER_SUITE_GCMP_256;
case WPA_CIPHER_CCMP:
- return WLAN_CIPHER_SUITE_CCMP;
+ return RSN_CIPHER_SUITE_CCMP;
case WPA_CIPHER_GCMP:
- return WLAN_CIPHER_SUITE_GCMP;
+ return RSN_CIPHER_SUITE_GCMP;
case WPA_CIPHER_TKIP:
- return WLAN_CIPHER_SUITE_TKIP;
+ return RSN_CIPHER_SUITE_TKIP;
case WPA_CIPHER_WEP104:
- return WLAN_CIPHER_SUITE_WEP104;
+ return RSN_CIPHER_SUITE_WEP104;
case WPA_CIPHER_WEP40:
- return WLAN_CIPHER_SUITE_WEP40;
+ return RSN_CIPHER_SUITE_WEP40;
case WPA_CIPHER_GTK_NOT_USED:
- return WLAN_CIPHER_SUITE_NO_GROUP_ADDR;
+ return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED;
}
return 0;
@@ -2582,19 +2703,19 @@
int num_suites = 0;
if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
- suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256;
+ suites[num_suites++] = RSN_CIPHER_SUITE_CCMP_256;
if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
- suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256;
+ suites[num_suites++] = RSN_CIPHER_SUITE_GCMP_256;
if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
- suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+ suites[num_suites++] = RSN_CIPHER_SUITE_CCMP;
if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
- suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
+ suites[num_suites++] = RSN_CIPHER_SUITE_GCMP;
if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
- suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+ suites[num_suites++] = RSN_CIPHER_SUITE_TKIP;
if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
- suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+ suites[num_suites++] = RSN_CIPHER_SUITE_WEP104;
if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
- suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+ suites[num_suites++] = RSN_CIPHER_SUITE_WEP40;
return num_suites;
}
@@ -2852,8 +2973,8 @@
params->wep_key[i]) ||
nla_put_u32(msg, NL80211_KEY_CIPHER,
params->wep_key_len[i] == 5 ?
- WLAN_CIPHER_SUITE_WEP40 :
- WLAN_CIPHER_SUITE_WEP104) ||
+ RSN_CIPHER_SUITE_WEP40 :
+ RSN_CIPHER_SUITE_WEP104) ||
nla_put_u8(msg, NL80211_KEY_IDX, i) ||
(i == params->wep_tx_keyidx &&
nla_put_flag(msg, NL80211_KEY_DEFAULT)))
@@ -3079,11 +3200,11 @@
if (params->ie &&
nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
goto fail;
- if (params->sae_data) {
- wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data,
- params->sae_data_len);
- if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
- params->sae_data))
+ if (params->auth_data) {
+ wpa_hexdump(MSG_DEBUG, " * auth_data", params->auth_data,
+ params->auth_data_len);
+ if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->auth_data_len,
+ params->auth_data))
goto fail;
}
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
@@ -3096,6 +3217,8 @@
type = NL80211_AUTHTYPE_FT;
else if (params->auth_alg & WPA_AUTH_ALG_SAE)
type = NL80211_AUTHTYPE_SAE;
+ else if (params->auth_alg & WPA_AUTH_ALG_FILS)
+ type = NL80211_AUTHTYPE_FILS_SK;
else
goto fail;
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
@@ -3457,6 +3580,189 @@
}
+static int nl80211_put_dtim_period(struct nl_msg *msg, int dtim_period)
+{
+ if (dtim_period > 0) {
+ wpa_printf(MSG_DEBUG, " * dtim_period=%d", dtim_period);
+ return nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_MESH
+static int nl80211_set_mesh_config(void *priv,
+ struct wpa_driver_mesh_bss_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
+ if (!msg)
+ return -1;
+
+ ret = nl80211_put_mesh_config(msg, params);
+ if (ret < 0) {
+ nlmsg_free(msg);
+ return ret;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Mesh config set failed: %d (%s)",
+ ret, strerror(-ret));
+ return ret;
+ }
+ return 0;
+}
+#endif /* CONFIG_MESH */
+
+
+static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *bands, *band;
+ struct nl80211_txrate_vht vht_rate;
+
+ if (!params->freq ||
+ (params->beacon_rate == 0 &&
+ params->rate_type == BEACON_RATE_LEGACY))
+ return 0;
+
+ bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
+ if (!bands)
+ return -1;
+
+ switch (params->freq->mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211G:
+ band = nla_nest_start(msg, NL80211_BAND_2GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ band = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ band = nla_nest_start(msg, NL80211_BAND_60GHZ);
+ break;
+ default:
+ return 0;
+ }
+
+ if (!band)
+ return -1;
+
+ os_memset(&vht_rate, 0, sizeof(vht_rate));
+
+ switch (params->rate_type) {
+ case BEACON_RATE_LEGACY:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (legacy)");
+ return -1;
+ }
+
+ if (nla_put_u8(msg, NL80211_TXRATE_LEGACY,
+ (u8) params->beacon_rate / 5) ||
+ nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, " * beacon_rate = legacy:%u (* 100 kbps)",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_HT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_HT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (HT)");
+ return -1;
+ }
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
+ nla_put_u8(msg, NL80211_TXRATE_HT, params->beacon_rate) ||
+ (params->freq->vht_enabled &&
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate)))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = HT-MCS %u",
+ params->beacon_rate);
+ break;
+ case BEACON_RATE_VHT:
+ if (!(flags & WPA_DRIVER_FLAGS_BEACON_RATE_VHT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (VHT)");
+ return -1;
+ }
+ vht_rate.mcs[0] = BIT(params->beacon_rate);
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_HT, 0, NULL))
+ return -1;
+ if (nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
+ params->beacon_rate);
+ break;
+ }
+
+ nla_nest_end(msg, band);
+ nla_nest_end(msg, bands);
+
+ return 0;
+}
+
+
+static int nl80211_set_multicast_to_unicast(struct i802_bss *bss,
+ int multicast_to_unicast)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MULTICAST_TO_UNICAST);
+ if (!msg ||
+ (multicast_to_unicast &&
+ nla_put_flag(msg, NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED))) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to build NL80211_CMD_SET_MULTICAST_TO_UNICAST msg for %s",
+ bss->ifname);
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ switch (ret) {
+ case 0:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: multicast to unicast %s on interface %s",
+ multicast_to_unicast ? "enabled" : "disabled",
+ bss->ifname);
+ break;
+ case -EOPNOTSUPP:
+ if (!multicast_to_unicast)
+ break;
+ wpa_printf(MSG_INFO,
+ "nl80211: multicast to unicast not supported on interface %s",
+ bss->ifname);
+ break;
+ default:
+ wpa_printf(MSG_ERROR,
+ "nl80211: %s multicast to unicast failed with %d (%s) on interface %s",
+ multicast_to_unicast ? "enabling" : "disabling",
+ ret, strerror(-ret), bss->ifname);
+ break;
+ }
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
@@ -3470,6 +3776,9 @@
int smps_mode;
u32 suites[10], suite;
u32 ver;
+#ifdef CONFIG_MESH
+ struct wpa_driver_mesh_bss_params mesh_params;
+#endif /* CONFIG_MESH */
beacon_set = params->reenable ? 0 : bss->beacon_set;
@@ -3477,6 +3786,9 @@
beacon_set);
if (beacon_set)
cmd = NL80211_CMD_SET_BEACON;
+ else if (!drv->device_ap_sme && !drv->use_monitor &&
+ !nl80211_get_wiphy_data_ap(bss))
+ return -ENOBUFS;
wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
params->head, params->head_len);
@@ -3484,6 +3796,8 @@
params->tail, params->tail_len);
wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
+ 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);
@@ -3493,7 +3807,8 @@
nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
params->tail) ||
nl80211_put_beacon_int(msg, params->beacon_int) ||
- nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
+ nl80211_put_beacon_rate(msg, drv->capa.flags, params) ||
+ nl80211_put_dtim_period(msg, params->dtim_period) ||
nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
if (params->proberesp && params->proberesp_len) {
@@ -3555,17 +3870,19 @@
params->key_mgmt_suites);
num_suites = 0;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
- suites[num_suites++] = WLAN_AKM_SUITE_8021X;
+ suites[num_suites++] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
- suites[num_suites++] = WLAN_AKM_SUITE_PSK;
+ suites[num_suites++] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
if (num_suites &&
nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
suites))
goto fail;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
- params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
- nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+ (!params->pairwise_ciphers ||
+ params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
+ (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
goto fail;
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
@@ -3668,6 +3985,8 @@
nl80211_set_bss(bss, params->cts_protect, params->preamble,
params->short_slot_time, params->ht_opmode,
params->isolate, params->basic_rates);
+ nl80211_set_multicast_to_unicast(bss,
+ params->multicast_to_unicast);
if (beacon_set && params->freq &&
params->freq->bandwidth != bss->bandwidth) {
wpa_printf(MSG_DEBUG,
@@ -3684,7 +4003,7 @@
"nl80211: Frequency set succeeded for ht2040 coex");
bss->bandwidth = params->freq->bandwidth;
}
- } else if (!beacon_set) {
+ } else if (!beacon_set && params->freq) {
/*
* cfg80211 updates the driver on frequence change in AP
* mode only at the point when beaconing is started, so
@@ -3693,6 +4012,18 @@
bss->bandwidth = params->freq->bandwidth;
}
}
+
+#ifdef CONFIG_MESH
+ if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) {
+ os_memset(&mesh_params, 0, sizeof(mesh_params));
+ mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE;
+ mesh_params.ht_opmode = params->ht_opmode;
+ ret = nl80211_set_mesh_config(priv, &mesh_params);
+ if (ret < 0)
+ return ret;
+ }
+#endif /* CONFIG_MESH */
+
return ret;
fail:
nlmsg_free(msg);
@@ -3766,6 +4097,12 @@
wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
return -ENOBUFS;
+ } else {
+ wpa_printf(MSG_DEBUG, " * channel_type=%d",
+ NL80211_CHAN_NO_HT);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_NO_HT))
+ return -ENOBUFS;
}
return 0;
}
@@ -3828,11 +4165,11 @@
static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
{
switch (state) {
- case PLINK_LISTEN:
+ case PLINK_IDLE:
return NL80211_PLINK_LISTEN;
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_SNT:
return NL80211_PLINK_OPN_SNT;
- case PLINK_OPEN_RCVD:
+ case PLINK_OPN_RCVD:
return NL80211_PLINK_OPN_RCVD;
case PLINK_CNF_RCVD:
return NL80211_PLINK_CNF_RCVD;
@@ -3919,6 +4256,13 @@
params->ext_capab_len, params->ext_capab))
goto fail;
}
+
+ if (is_ap_interface(drv->nlmode) &&
+ nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
+ params->support_p2p_ps ?
+ NL80211_P2P_PS_SUPPORTED :
+ NL80211_P2P_PS_UNSUPPORTED))
+ goto fail;
}
if (!params->set) {
if (params->aid) {
@@ -4014,6 +4358,15 @@
if (!(params->flags & WPA_STA_ASSOCIATED))
upd.mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
}
+#ifdef CONFIG_MESH
+ } else {
+ if (params->plink_state == PLINK_ESTAB && params->peer_aid) {
+ ret = nla_put_u16(msg, NL80211_ATTR_MESH_PEER_AID,
+ params->peer_aid);
+ if (ret)
+ goto fail;
+ }
+#endif /* CONFIG_MESH */
}
wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
@@ -4151,7 +4504,7 @@
}
-static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+const char * nl80211_iftype_str(enum nl80211_iftype mode)
{
switch (mode) {
case NL80211_IFTYPE_ADHOC:
@@ -4333,7 +4686,8 @@
if (drv->device_ap_sme && !drv->use_monitor)
if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
- return -1;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
if (!drv->device_ap_sme && drv->use_monitor &&
nl80211_create_monitor_interface(drv) &&
@@ -4366,6 +4720,7 @@
else
nl80211_mgmt_unsubscribe(bss, "AP teardown");
+ nl80211_put_wiphy_data_ap(bss);
bss->beacon_set = 0;
}
@@ -4714,6 +5069,9 @@
struct wpa_driver_associate_params *params,
struct nl_msg *msg)
{
+ if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+ return -1;
+
if (params->bssid) {
wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
MAC2STR(params->bssid));
@@ -4815,39 +5173,39 @@
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
- int mgmt = WLAN_AKM_SUITE_PSK;
+ int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
switch (params->key_mgmt_suite) {
case WPA_KEY_MGMT_CCKM:
- mgmt = WLAN_AKM_SUITE_CCKM;
+ mgmt = RSN_AUTH_KEY_MGMT_CCKM;
break;
case WPA_KEY_MGMT_IEEE8021X:
- mgmt = WLAN_AKM_SUITE_8021X;
+ mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
break;
case WPA_KEY_MGMT_FT_IEEE8021X:
- mgmt = WLAN_AKM_SUITE_FT_8021X;
+ mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X;
break;
case WPA_KEY_MGMT_FT_PSK:
- mgmt = WLAN_AKM_SUITE_FT_PSK;
+ mgmt = RSN_AUTH_KEY_MGMT_FT_PSK;
break;
case WPA_KEY_MGMT_IEEE8021X_SHA256:
- mgmt = WLAN_AKM_SUITE_8021X_SHA256;
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
break;
case WPA_KEY_MGMT_PSK_SHA256:
- mgmt = WLAN_AKM_SUITE_PSK_SHA256;
+ mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256;
break;
case WPA_KEY_MGMT_OSEN:
- mgmt = WLAN_AKM_SUITE_OSEN;
+ mgmt = RSN_AUTH_KEY_MGMT_OSEN;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
- mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
break;
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
- mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
break;
case WPA_KEY_MGMT_PSK:
default:
- mgmt = WLAN_AKM_SUITE_PSK;
+ mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
break;
}
wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
@@ -4858,15 +5216,24 @@
if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
return -1;
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ (params->pairwise_suite == WPA_CIPHER_NONE ||
+ params->pairwise_suite == WPA_CIPHER_WEP104 ||
+ params->pairwise_suite == WPA_CIPHER_WEP40) &&
+ (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) ||
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
+ return -1;
+
if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
return -1;
if (params->rrm_used) {
u32 drv_rrm_flags = drv->capa.rrm_flags;
- if (!(drv_rrm_flags &
- WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
- !(drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET) ||
+ if ((!((drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
+ (drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
+ !(drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) ||
nla_put_flag(msg, NL80211_ATTR_USE_RRM))
return -1;
}
@@ -5045,6 +5412,22 @@
if (ret)
goto fail;
+ if (params->fils_kek) {
+ wpa_printf(MSG_DEBUG, " * FILS KEK (len=%u)",
+ (unsigned int) params->fils_kek_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_KEK, params->fils_kek_len,
+ params->fils_kek))
+ goto fail;
+ }
+ if (params->fils_nonces) {
+ wpa_hexdump(MSG_DEBUG, " * FILS nonces (for AAD)",
+ params->fils_nonces,
+ params->fils_nonces_len);
+ if (nla_put(msg, NL80211_ATTR_FILS_NONCES,
+ params->fils_nonces_len, params->fils_nonces))
+ goto fail;
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
@@ -5100,6 +5483,9 @@
int res;
int mode_switch_res;
+ if (TEST_FAIL())
+ return -1;
+
mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
mode_switch_res = 0;
@@ -5519,8 +5905,6 @@
{
struct nl_msg *msg;
- os_memset(data, 0, sizeof(*data));
-
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
nlmsg_free(msg);
@@ -5626,6 +6010,7 @@
struct hostap_sta_driver_data data;
int ret;
+ os_memset(&data, 0, sizeof(data));
data.inactive_msec = (unsigned long) -1;
ret = i802_read_sta_data(priv, &data, addr);
if (ret == -ENOENT)
@@ -5651,6 +6036,14 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ u8 channel;
+
+ if (ieee80211_freq_to_chan(bss->freq, &channel) ==
+ HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ return i802_sta_disassoc(priv, own_addr, addr, reason);
+ }
if (is_mesh_interface(drv->nlmode))
return -1;
@@ -6364,7 +6757,7 @@
wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
nl80211_teardown_ap(bss);
if (!bss->added_if && !drv->first_bss->next)
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
nl80211_destroy_bss(bss);
if (!bss->added_if)
i802_set_iface_flags(bss, 0);
@@ -6488,6 +6881,14 @@
os_memcpy(hdr->addr2, src, ETH_ALEN);
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
+ if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
+ MAC2STR(src));
+ os_memcpy(bss->rand_addr, src, ETH_ALEN);
+ } else {
+ os_memset(bss->rand_addr, 0, ETH_ALEN);
+ }
+
if (is_ap_interface(drv->nlmode) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
(int) freq == bss->freq || drv->device_ap_sme ||
@@ -6726,7 +7127,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!is_ap_interface(drv->nlmode))
return -1;
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
bss->beacon_set = 0;
/*
@@ -6746,7 +7147,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!is_ap_interface(drv->nlmode))
return -1;
- wpa_driver_nl80211_del_beacon(drv);
+ wpa_driver_nl80211_del_beacon(bss);
bss->beacon_set = 0;
return 0;
}
@@ -6878,15 +7279,15 @@
static int nl80211_set_param(void *priv, const char *param)
{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
if (param == NULL)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
#ifdef CONFIG_P2P
if (os_strstr(param, "use_p2p_group_interface=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
-
wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
"interface");
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
@@ -6894,22 +7295,18 @@
}
#endif /* CONFIG_P2P */
- if (os_strstr(param, "use_monitor=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
+ if (os_strstr(param, "use_monitor=1"))
drv->use_monitor = 1;
- }
if (os_strstr(param, "force_connect_cmd=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
drv->force_connect_cmd = 1;
}
+ if (os_strstr(param, "force_bss_selection=1"))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+
if (os_strstr(param, "no_offchannel_tx=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
drv->test_use_roc_tx = 1;
}
@@ -7439,6 +7836,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
enum nl80211_tdls_operation nl80211_oper;
+ int res;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
return -EOPNOTSUPP;
@@ -7474,7 +7872,11 @@
return -ENOBUFS;
}
- return send_and_recv_msgs(drv, msg, NULL, NULL);
+ res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR
+ " --> res=%d (%s)", nl80211_oper, MAC2STR(peer), res,
+ strerror(-res));
+ return res;
}
@@ -7632,6 +8034,8 @@
const u8 *addr)
{
struct i802_bss *bss = priv;
+
+ os_memset(data, 0, sizeof(*data));
return i802_read_sta_data(bss, data, addr);
}
@@ -7683,7 +8087,7 @@
}
-const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
+static const u8 * wpa_driver_nl80211_get_macaddr(void *priv)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -8291,6 +8695,9 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
int new_addr = addr != NULL;
+ if (TEST_FAIL())
+ return -1;
+
if (!addr)
addr = drv->perm_addr;
@@ -8351,6 +8758,46 @@
}
+static int nl80211_put_mesh_config(struct nl_msg *msg,
+ struct wpa_driver_mesh_bss_params *params)
+{
+ struct nlattr *container;
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+ if (!container)
+ return -1;
+
+ if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+ nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ params->auto_plinks)) ||
+ ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS) &&
+ nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+ params->max_peer_links)))
+ return -1;
+
+ /*
+ * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+ * the timer could disconnect stations even in that case.
+ */
+ if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT) &&
+ nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+ params->peer_link_timeout)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+ return -1;
+ }
+
+ if ((params->flags & WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE) &&
+ nla_put_u16(msg, NL80211_MESHCONF_HT_OPMODE, params->ht_opmode)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set HT_OP_MODE");
+ return -1;
+ }
+
+ nla_nest_end(msg, container);
+
+ return 0;
+}
+
+
static int nl80211_join_mesh(struct i802_bss *bss,
struct wpa_driver_mesh_join_params *params)
{
@@ -8365,7 +8812,8 @@
nl80211_put_freq_params(msg, ¶ms->freq) ||
nl80211_put_basic_rates(msg, params->basic_rates) ||
nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
- nl80211_put_beacon_int(msg, params->beacon_int))
+ nl80211_put_beacon_int(msg, params->beacon_int) ||
+ nl80211_put_dtim_period(msg, params->dtim_period))
goto fail;
wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
@@ -8394,30 +8842,12 @@
goto fail;
nla_nest_end(msg, container);
- container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
- if (!container)
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_PEER_LINK_TIMEOUT;
+ params->conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_MAX_PEER_LINKS;
+ if (nl80211_put_mesh_config(msg, ¶ms->conf) < 0)
goto fail;
- if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
- nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
- goto fail;
- if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
- nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
- params->max_peer_links))
- goto fail;
-
- /*
- * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
- * the timer could disconnect stations even in that case.
- */
- if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
- params->conf.peer_link_timeout)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
- goto fail;
- }
-
- nla_nest_end(msg, container);
-
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
@@ -8426,7 +8856,7 @@
goto fail;
}
ret = 0;
- bss->freq = params->freq.freq;
+ drv->assoc_freq = bss->freq = params->freq.freq;
wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
fail:
@@ -9092,9 +9522,266 @@
return 0;
}
+
+static int nl80211_p2p_lo_start(void *priv, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count, const u8 *device_types,
+ size_t dev_types_len,
+ const u8 *ies, size_t ies_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Start P2P Listen offload: freq=%u, period=%u, interval=%u, count=%u",
+ freq, period, interval, count);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+ 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_P2P_LISTEN_OFFLOAD_START))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL,
+ freq) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD,
+ period) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL,
+ interval) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT,
+ count) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES,
+ dev_types_len, device_types) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE,
+ ies_len, ies))
+ goto fail;
+
+ nla_nest_end(msg, container);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to send P2P Listen offload vendor command");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_p2p_lo_stop(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Stop P2P Listen offload");
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
+ 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_P2P_LISTEN_OFFLOAD_STOP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+static int nl80211_set_tdls_mode(void *priv, int tdls_external_control)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+ u32 tdls_mode;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set TDKS mode: tdls_external_control=%d",
+ tdls_external_control);
+
+ if (tdls_external_control == 1)
+ tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT |
+ QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL;
+ else
+ tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
+
+ 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_CONFIGURE_TDLS))
+ goto fail;
+
+ params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!params)
+ goto fail;
+
+ if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE,
+ tdls_mode))
+ goto fail;
+
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Set TDLS mode failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ return 0;
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
+static int nl80211_write_to_file(const char *name, unsigned int val)
+{
+ int fd, len;
+ char tmp[128];
+
+ fd = open(name, O_RDWR);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to open %s: %s",
+ name, strerror(errno));
+ return fd;
+ }
+
+ len = os_snprintf(tmp, sizeof(tmp), "%u\n", val);
+ len = write(fd, tmp, len);
+ if (len < 0)
+ wpa_printf(MSG_ERROR, "nl80211: Failed to write to %s: %s",
+ name, strerror(errno));
+ close(fd);
+
+ return 0;
+}
+
+
+static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
+ filter_flags);
+
+ /* Configure filtering of unicast frame encrypted using GTK */
+ ret = os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
+ bss->ifname);
+ if (os_snprintf_error(sizeof(path), ret))
+ return -1;
+
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_GTK));
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to set IPv4 unicast in multicast filter");
+ return ret;
+ }
+
+ os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
+ bss->ifname);
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_GTK));
+
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to set IPv6 unicast in multicast filter");
+ return ret;
+ }
+
+ /* Configure filtering of unicast frame encrypted using GTK */
+ os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
+ bss->ifname);
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_ARP));
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed set gratuitous ARP filter");
+ return ret;
+ }
+
+ /* Configure filtering of IPv6 NA frames */
+ os_snprintf(path, sizeof(path),
+ "/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
+ bss->ifname);
+ ret = nl80211_write_to_file(path,
+ !!(filter_flags &
+ WPA_DATA_FRAME_FILTER_FLAG_NA));
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to set unsolicited NA filter");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type,
+ const u8 **ext_capa, const u8 **ext_capa_mask,
+ unsigned int *ext_capa_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ enum nl80211_iftype nlmode;
+ unsigned int i;
+
+ if (!ext_capa || !ext_capa_mask || !ext_capa_len)
+ return -1;
+
+ nlmode = wpa_driver_nl80211_if_type(type);
+
+ /* By default, use the per-radio values */
+ *ext_capa = drv->extended_capa;
+ *ext_capa_mask = drv->extended_capa_mask;
+ *ext_capa_len = drv->extended_capa_len;
+
+ /* Replace the default value if a per-interface type value exists */
+ for (i = 0; i < drv->num_iface_ext_capa; i++) {
+ if (nlmode == drv->iface_ext_capa[i].iftype) {
+ *ext_capa = drv->iface_ext_capa[i].ext_capa;
+ *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask;
+ *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -9189,9 +9876,6 @@
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
.set_wowlan = nl80211_set_wowlan,
-#ifdef CONFIG_DRIVER_NL80211_QCA
- .roaming = nl80211_roaming,
-#endif /* CONFIG_DRIVER_NL80211_QCA */
.set_mac_addr = nl80211_set_mac_addr,
#ifdef CONFIG_MESH
.init_mesh = wpa_driver_nl80211_init_mesh,
@@ -9206,9 +9890,16 @@
.del_tx_ts = nl80211_del_ts,
.get_ifindex = nl80211_get_ifindex,
#ifdef CONFIG_DRIVER_NL80211_QCA
+ .roaming = nl80211_roaming,
.do_acs = wpa_driver_do_acs,
.set_band = nl80211_set_band,
.get_pref_freq_list = nl80211_get_pref_freq_list,
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
+ .p2p_lo_start = nl80211_p2p_lo_start,
+ .p2p_lo_stop = nl80211_p2p_lo_stop,
+ .set_default_scan_ies = nl80211_set_default_scan_ies,
+ .set_tdls_mode = nl80211_set_tdls_mode,
#endif /* CONFIG_DRIVER_NL80211_QCA */
+ .configure_data_frame_filters = nl80211_configure_data_frame_filters,
+ .get_ext_capab = nl80211_get_ext_capab,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index b0d2b6d..bdc79c5 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -78,6 +78,7 @@
struct nl80211_wiphy_data *wiphy_data;
struct dl_list wiphy_list;
+ u8 rand_addr[ETH_ALEN];
};
struct wpa_driver_nl80211_data {
@@ -96,6 +97,13 @@
struct wpa_driver_capa capa;
u8 *extended_capa, *extended_capa_mask;
unsigned int extended_capa_len;
+ struct drv_nl80211_ext_capa {
+ enum nl80211_iftype iftype;
+ u8 *ext_capa, *ext_capa_mask;
+ unsigned int ext_capa_len;
+ } iface_ext_capa[NL80211_IFTYPE_MAX];
+ unsigned int num_iface_ext_capa;
+
int has_capability;
int operstate;
@@ -152,6 +160,8 @@
unsigned int set_prob_oper_freq:1;
unsigned int scan_vendor_cmd_avail:1;
unsigned int connect_reassoc:1;
+ unsigned int set_wifi_conf_vendor_cmd_avail:1;
+ unsigned int he_capab_vendor_cmd_avail:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -200,6 +210,8 @@
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
*/
int last_scan_cmd;
+
+ struct he_capabilities he_capab;
};
struct nl_msg;
@@ -220,6 +232,7 @@
void *arg, int use_existing);
void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx);
unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv);
+int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid);
enum chan_width convert2width(int width);
void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv);
struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
@@ -251,6 +264,8 @@
int process_global_event(struct nl_msg *msg, void *arg);
int process_bss_event(struct nl_msg *msg, void *arg);
+const char * nl80211_iftype_str(enum nl80211_iftype mode);
+
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
int android_pno_start(struct i802_bss *bss,
@@ -272,15 +287,6 @@
/* driver_nl80211_scan.c */
-struct nl80211_bss_info_arg {
- struct wpa_driver_nl80211_data *drv;
- struct wpa_scan_results *res;
- unsigned int assoc_freq;
- unsigned int ibss_freq;
- u8 assoc_bssid[ETH_ALEN];
-};
-
-int bss_info_handler(struct nl_msg *msg, void *arg);
void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
int wpa_driver_nl80211_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
@@ -289,8 +295,9 @@
int wpa_driver_nl80211_stop_sched_scan(void *priv);
struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
-int wpa_driver_nl80211_abort_scan(void *priv);
+int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie);
int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 004d88e..7064ce1 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -12,8 +12,8 @@
#include <netlink/genl/genl.h>
#include "utils/common.h"
-#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_common.h"
#include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h"
#include "driver_nl80211.h"
@@ -66,7 +66,6 @@
unsigned int device_ap_sme:1;
unsigned int poll_command_supported:1;
unsigned int data_tx_status:1;
- unsigned int monitor_supported:1;
unsigned int auth_supported:1;
unsigned int connect_supported:1;
unsigned int p2p_go_supported:1;
@@ -129,9 +128,6 @@
case NL80211_IFTYPE_P2P_CLIENT:
info->p2p_client_supported = 1;
break;
- case NL80211_IFTYPE_MONITOR:
- info->monitor_supported = 1;
- break;
}
}
}
@@ -270,40 +266,40 @@
c >> 24, (c >> 16) & 0xff,
(c >> 8) & 0xff, c & 0xff);
switch (c) {
- case WLAN_CIPHER_SUITE_CCMP_256:
+ case RSN_CIPHER_SUITE_CCMP_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
break;
- case WLAN_CIPHER_SUITE_GCMP_256:
+ case RSN_CIPHER_SUITE_GCMP_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
break;
- case WLAN_CIPHER_SUITE_CCMP:
+ case RSN_CIPHER_SUITE_CCMP:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
break;
- case WLAN_CIPHER_SUITE_GCMP:
+ case RSN_CIPHER_SUITE_GCMP:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
break;
- case WLAN_CIPHER_SUITE_TKIP:
+ case RSN_CIPHER_SUITE_TKIP:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
break;
- case WLAN_CIPHER_SUITE_WEP104:
+ case RSN_CIPHER_SUITE_WEP104:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
break;
- case WLAN_CIPHER_SUITE_WEP40:
+ case RSN_CIPHER_SUITE_WEP40:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
+ case RSN_CIPHER_SUITE_AES_128_CMAC:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case RSN_CIPHER_SUITE_BIP_GMAC_128:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ case RSN_CIPHER_SUITE_BIP_GMAC_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
break;
- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ case RSN_CIPHER_SUITE_BIP_CMAC_256:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
break;
- case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
+ case RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED:
info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
break;
}
@@ -352,13 +348,56 @@
struct nlattr *tb)
{
struct wpa_driver_capa *capa = info->capa;
+ u8 *ext_features;
+ int len;
if (tb == NULL)
return;
- if (ext_feature_isset(nla_data(tb), nla_len(tb),
- NL80211_EXT_FEATURE_VHT_IBSS))
+ ext_features = nla_data(tb);
+ len = nla_len(tb);
+
+ if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_VHT_IBSS))
capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
+
+ if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_RRM))
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_RRM;
+
+ if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_FILS_STA))
+ capa->flags |= WPA_DRIVER_FLAGS_SUPPORT_FILS;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_LEGACY;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_HT))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_HT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_VHT))
+ capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL))
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SCAN_START_TIME) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BSS_PARENT_TSF) &&
+ ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL))
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
+ capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
+ capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI))
+ capa->flags |= WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI;
}
@@ -479,6 +518,74 @@
}
+static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb)
+{
+ int rem = 0, i;
+ struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr;
+
+ if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+ return;
+
+ nla_for_each_nested(attr, tb, rem) {
+ unsigned int len;
+ struct drv_nl80211_ext_capa *capa;
+
+ nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr),
+ nla_len(attr), NULL);
+
+ if (!tb1[NL80211_ATTR_IFTYPE] ||
+ !tb1[NL80211_ATTR_EXT_CAPA] ||
+ !tb1[NL80211_ATTR_EXT_CAPA_MASK])
+ continue;
+
+ capa = &drv->iface_ext_capa[drv->num_iface_ext_capa];
+ capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver-advertised extended capabilities for interface type %s",
+ nl80211_iftype_str(capa->iftype));
+
+ len = nla_len(tb1[NL80211_ATTR_EXT_CAPA]);
+ capa->ext_capa = os_malloc(len);
+ if (!capa->ext_capa)
+ goto err;
+
+ os_memcpy(capa->ext_capa, nla_data(tb1[NL80211_ATTR_EXT_CAPA]),
+ len);
+ capa->ext_capa_len = len;
+ wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities",
+ capa->ext_capa, capa->ext_capa_len);
+
+ len = nla_len(tb1[NL80211_ATTR_EXT_CAPA_MASK]);
+ capa->ext_capa_mask = os_malloc(len);
+ if (!capa->ext_capa_mask)
+ goto err;
+
+ os_memcpy(capa->ext_capa_mask,
+ nla_data(tb1[NL80211_ATTR_EXT_CAPA_MASK]), len);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask",
+ capa->ext_capa_mask, capa->ext_capa_len);
+
+ drv->num_iface_ext_capa++;
+ if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX)
+ break;
+ }
+
+ return;
+
+err:
+ /* Cleanup allocated memory on error */
+ for (i = 0; i < NL80211_IFTYPE_MAX; i++) {
+ os_free(drv->iface_ext_capa[i].ext_capa);
+ drv->iface_ext_capa[i].ext_capa = NULL;
+ os_free(drv->iface_ext_capa[i].ext_capa_mask);
+ drv->iface_ext_capa[i].ext_capa_mask = NULL;
+ drv->iface_ext_capa[i].ext_capa_len = 0;
+ }
+ drv->num_iface_ext_capa = 0;
+}
+
+
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -569,6 +676,9 @@
nla_len(tb[NL80211_ATTR_EXT_CAPA]));
drv->extended_capa_len =
nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+ wpa_hexdump(MSG_DEBUG,
+ "nl80211: Driver-advertised extended capabilities (default)",
+ drv->extended_capa, drv->extended_capa_len);
}
drv->extended_capa_mask =
os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
@@ -576,6 +686,10 @@
os_memcpy(drv->extended_capa_mask,
nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+ wpa_hexdump(MSG_DEBUG,
+ "nl80211: Driver-advertised extended capabilities mask (default)",
+ drv->extended_capa_mask,
+ drv->extended_capa_len);
} else {
os_free(drv->extended_capa);
drv->extended_capa = NULL;
@@ -583,6 +697,8 @@
}
}
+ wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
+
if (tb[NL80211_ATTR_VENDOR_DATA]) {
struct nlattr *nl;
int rem;
@@ -625,6 +741,12 @@
case QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN:
drv->scan_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
+ drv->set_wifi_conf_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES:
+ drv->he_capab_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -794,6 +916,100 @@
}
+static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct he_capabilities *he_capab = arg;
+ struct nlattr *nl_vend;
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX + 1];
+ size_t len;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_VENDOR_DATA])
+ return NL_SKIP;
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]) {
+ u8 he_supported;
+
+ he_supported = nla_get_u8(
+ tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]);
+ wpa_printf(MSG_DEBUG, "nl80211: HE capabilities supported: %u",
+ he_supported);
+ he_capab->he_supported = he_supported;
+ if (!he_supported)
+ return NL_SKIP;
+ }
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]) {
+ len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]);
+
+ if (len > sizeof(he_capab->phy_cap))
+ len = sizeof(he_capab->phy_cap);
+ os_memcpy(he_capab->phy_cap,
+ nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]),
+ len);
+ }
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB])
+ he_capab->mac_cap =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS])
+ he_capab->mcs =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS])
+ he_capab->ppet.numss_m1 =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK])
+ he_capab->ppet.ru_count =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]) {
+ len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]);
+
+ if (len > sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0))
+ len = sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0);
+ os_memcpy(he_capab->ppet.ppet16_ppet8_ru3_ru0,
+ nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]),
+ len);
+ }
+
+ return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_he_capab(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ if (!drv->he_capab_vendor_cmd_avail)
+ return;
+
+ 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_HE_CAPABILITIES)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, qca_nl80211_he_capab_handler,
+ &drv->he_capab);
+ if (!ret && drv->he_capab.he_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_HE_CAPABILITIES;
+}
+
+
struct features_info {
u8 *flags;
size_t flags_len;
@@ -888,6 +1104,8 @@
if (check_feature(QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS,
&info))
drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS;
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD;
os_free(info.flags);
}
@@ -949,21 +1167,8 @@
* If poll command and tx status are supported, mac80211 is new enough
* to have everything we need to not need monitor interfaces.
*/
- drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-
- if (drv->device_ap_sme && drv->use_monitor) {
- /*
- * Non-mac80211 drivers may not support monitor interface.
- * Make sure we do not get stuck with incorrect capability here
- * by explicitly testing this.
- */
- if (!info.monitor_supported) {
- wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
- "with device_ap_sme since no monitor mode "
- "support detected");
- drv->use_monitor = 0;
- }
- }
+ drv->use_monitor = !info.device_ap_sme &&
+ (!info.poll_command_supported || !info.data_tx_status);
/*
* If we aren't going to use monitor interfaces, but the
@@ -976,6 +1181,7 @@
#ifdef CONFIG_DRIVER_NL80211_QCA
qca_nl80211_check_dfs_capa(drv);
qca_nl80211_get_features(drv);
+ qca_nl80211_check_he_capab(drv);
/*
* To enable offchannel simultaneous support in wpa_supplicant, the
@@ -1684,6 +1890,7 @@
os_free(result.modes[i].rates);
}
os_free(result.modes);
+ *num_modes = 0;
return NULL;
}
return wpa_driver_nl80211_postprocess_modes(result.modes,
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index bd16edb..ed2cbe4 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -1,6 +1,6 @@
/*
* Driver interaction with Linux nl80211/cfg80211 - Event processing
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
* Copyright (c) 2009-2010, Atheros Communications
*
@@ -206,6 +206,7 @@
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
u16 status;
+ int ssid_len;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
drv->force_connect_cmd) {
@@ -247,6 +248,8 @@
os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
os_memset(&event, 0, sizeof(event));
+ event.assoc_info.resp_frame = frame;
+ event.assoc_info.resp_frame_len = len;
if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
event.assoc_info.resp_ies_len =
@@ -255,6 +258,16 @@
event.assoc_info.freq = drv->assoc_freq;
+ /* When this association was initiated outside of wpa_supplicant,
+ * drv->ssid needs to be set here to satisfy later checking. */
+ ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid);
+ if (ssid_len > 0) {
+ drv->ssid_len = ssid_len;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on scan res info to '%s'",
+ wpa_ssid_txt(drv->ssid, drv->ssid_len));
+ }
+
nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
@@ -265,6 +278,8 @@
enum nl80211_commands cmd, struct nlattr *status,
struct nlattr *addr, struct nlattr *req_ie,
struct nlattr *resp_ie,
+ struct nlattr *timed_out,
+ struct nlattr *timeout_reason,
struct nlattr *authorized,
struct nlattr *key_replay_ctr,
struct nlattr *ptk_kck,
@@ -272,8 +287,9 @@
struct nlattr *subnet_status)
{
union wpa_event_data event;
- const u8 *ssid;
+ const u8 *ssid = NULL;
u16 status_code;
+ int ssid_len;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
/*
@@ -322,6 +338,25 @@
event.assoc_reject.resp_ies_len = nla_len(resp_ie);
}
event.assoc_reject.status_code = status_code;
+ event.assoc_reject.timed_out = timed_out != NULL;
+ if (timed_out && timeout_reason) {
+ enum nl80211_timeout_reason reason;
+
+ reason = nla_get_u32(timeout_reason);
+ switch (reason) {
+ case NL80211_TIMEOUT_SCAN:
+ event.assoc_reject.timeout_reason = "scan";
+ break;
+ case NL80211_TIMEOUT_AUTH:
+ event.assoc_reject.timeout_reason = "auth";
+ break;
+ case NL80211_TIMEOUT_ASSOC:
+ event.assoc_reject.timeout_reason = "assoc";
+ break;
+ default:
+ break;
+ }
+ }
wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
return;
}
@@ -343,6 +378,10 @@
if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
drv->ssid_len = ssid[1];
os_memcpy(drv->ssid, ssid + 2, ssid[1]);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on req_ie to '%s'",
+ wpa_ssid_txt(drv->ssid,
+ drv->ssid_len));
}
}
}
@@ -353,6 +392,16 @@
event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+ if ((!ssid || ssid[1] == 0 || ssid[1] > 32) &&
+ (ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) {
+ /* When this connection was initiated outside of wpa_supplicant,
+ * drv->ssid needs to be set here to satisfy later checking. */
+ drv->ssid_len = ssid_len;
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set drv->ssid based on scan res info to '%s'",
+ wpa_ssid_txt(drv->ssid, drv->ssid_len));
+ }
+
if (authorized && nla_get_u8(authorized)) {
event.assoc_info.authorized = 1;
wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
@@ -514,6 +563,7 @@
data.ch_switch.cf2 = nla_get_u32(cf2);
bss->freq = data.ch_switch.freq;
+ drv->assoc_freq = data.ch_switch.freq;
wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
}
@@ -829,6 +879,8 @@
MAC2STR(data + 4 + ETH_ALEN));
if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ (is_zero_ether_addr(bss->rand_addr) ||
+ os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
"for foreign address", bss->ifname);
@@ -914,6 +966,7 @@
struct nlattr *tb[])
{
unsigned int freq;
+ union wpa_event_data event;
if (tb[NL80211_ATTR_MAC] == NULL) {
wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
@@ -933,7 +986,10 @@
drv->first_bss->freq = freq;
}
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_info.freq = freq;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
}
@@ -1075,6 +1131,16 @@
wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
msg);
}
+
+ if (tb[NL80211_ATTR_SCAN_START_TIME_TSF] &&
+ tb[NL80211_ATTR_SCAN_START_TIME_TSF_BSSID]) {
+ info->scan_start_tsf =
+ nla_get_u64(tb[NL80211_ATTR_SCAN_START_TIME_TSF]);
+ os_memcpy(info->scan_start_tsf_bssid,
+ nla_data(tb[NL80211_ATTR_SCAN_START_TIME_TSF_BSSID]),
+ ETH_ALEN);
+ }
+
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
}
@@ -1087,6 +1153,10 @@
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_BEACON_LOSS_EVENT] = { .type = NLA_FLAG },
};
struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
enum nl80211_cqm_rssi_threshold_event event;
@@ -1108,12 +1178,39 @@
return;
os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
ETH_ALEN);
+ ed.low_ack.num_packets =
+ nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]);
+ wpa_printf(MSG_DEBUG, "nl80211: Packet loss event for " MACSTR
+ " (num_packets %u)",
+ MAC2STR(ed.low_ack.addr), ed.low_ack.num_packets);
wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
return;
}
- if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+ if (cqm[NL80211_ATTR_CQM_BEACON_LOSS_EVENT]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Beacon loss event");
+ wpa_supplicant_event(drv->ctx, EVENT_BEACON_LOSS, NULL);
return;
+ }
+
+ if (cqm[NL80211_ATTR_CQM_TXE_RATE] &&
+ cqm[NL80211_ATTR_CQM_TXE_PKTS] &&
+ cqm[NL80211_ATTR_CQM_TXE_INTVL] &&
+ cqm[NL80211_ATTR_MAC]) {
+ wpa_printf(MSG_DEBUG, "nl80211: CQM TXE event for " MACSTR
+ " (rate: %u pkts: %u interval: %u)",
+ MAC2STR((u8 *) nla_data(cqm[NL80211_ATTR_MAC])),
+ nla_get_u32(cqm[NL80211_ATTR_CQM_TXE_RATE]),
+ nla_get_u32(cqm[NL80211_ATTR_CQM_TXE_PKTS]),
+ nla_get_u32(cqm[NL80211_ATTR_CQM_TXE_INTVL]));
+ return;
+ }
+
+ if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Not a CQM RSSI threshold event");
+ return;
+ }
event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
@@ -1124,8 +1221,12 @@
wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
"event: RSSI low");
ed.signal_change.above_threshold = 0;
- } else
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unknown CQM RSSI threshold event: %d",
+ event);
return;
+ }
res = nl80211_get_link_signal(drv, &sig);
if (res == 0) {
@@ -1644,6 +1745,7 @@
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+ NULL, NULL,
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
@@ -1869,6 +1971,31 @@
external_scan);
}
+
+static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv,
+ u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1];
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: P2P listen offload stop vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.p2p_lo_stop.reason_code =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON]);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: P2P Listen offload stop reason: %d",
+ event.p2p_lo_stop.reason_code);
+ wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event);
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -1902,6 +2029,9 @@
case QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE:
qca_nl80211_scan_done_event(drv, data, len);
break;
+ case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP:
+ qca_nl80211_p2p_lo_stop_event(drv, data, len);
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
default:
wpa_printf(MSG_DEBUG,
@@ -2078,9 +2208,10 @@
case NL80211_CMD_NEW_SCAN_RESULTS:
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: New scan results available");
+ if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
+ drv->scan_state = SCAN_COMPLETED;
drv->scan_complete_events = 1;
if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
- drv->scan_state = SCAN_COMPLETED;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
drv, drv->ctx);
drv->last_scan_cmd = 0;
@@ -2097,8 +2228,9 @@
break;
case NL80211_CMD_SCAN_ABORTED:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
- if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
+ if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
drv->scan_state = SCAN_ABORTED;
+ if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
/*
* Need to indicate that scan results are available in
* order not to make wpa_supplicant stop its scanning.
@@ -2132,6 +2264,8 @@
tb[NL80211_ATTR_MAC],
tb[NL80211_ATTR_REQ_IE],
tb[NL80211_ATTR_RESP_IE],
+ tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_TIMEOUT_REASON],
NULL, NULL, NULL, NULL, NULL);
break;
case NL80211_CMD_CH_SWITCH_NOTIFY:
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
index 45385da..9376d11 100644
--- a/src/drivers/driver_nl80211_monitor.c
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -136,7 +136,7 @@
break;
case IEEE80211_RADIOTAP_TX_FLAGS:
injected = 1;
- failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+ failed = le_to_host16((*(le16 *) iter.this_arg)) &
IEEE80211_RADIOTAP_F_TX_FAIL;
break;
case IEEE80211_RADIOTAP_DATA_RETRIES:
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index c089891..4417721 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -20,6 +20,14 @@
#include "driver_nl80211.h"
+#define MAX_NL80211_NOISE_FREQS 50
+
+struct nl80211_noise_info {
+ u32 freq[MAX_NL80211_NOISE_FREQS];
+ s8 noise[MAX_NL80211_NOISE_FREQS];
+ unsigned int count;
+};
+
static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -29,9 +37,10 @@
[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
};
- struct wpa_scan_results *scan_results = arg;
- struct wpa_scan_res *scan_res;
- size_t i;
+ struct nl80211_noise_info *info = arg;
+
+ if (info->count >= MAX_NL80211_NOISE_FREQS)
+ return NL_STOP;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -55,36 +64,83 @@
if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
return NL_SKIP;
- for (i = 0; i < scan_results->num; ++i) {
- scan_res = scan_results->res[i];
- if (!scan_res)
- continue;
- if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
- scan_res->freq)
- continue;
- if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
- continue;
- scan_res->noise = (s8)
- nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
- scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
- }
+ info->freq[info->count] =
+ nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
+ info->noise[info->count] =
+ (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ info->count++;
return NL_SKIP;
}
static int nl80211_get_noise_for_scan_results(
- struct wpa_driver_nl80211_data *drv,
- struct wpa_scan_results *scan_res)
+ struct wpa_driver_nl80211_data *drv, struct nl80211_noise_info *info)
{
struct nl_msg *msg;
+ os_memset(info, 0, sizeof(*info));
msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
- scan_res);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results, info);
}
+static int nl80211_abort_scan(struct i802_bss *bss)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+}
+
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static int nl80211_abort_vendor_scan(struct wpa_driver_nl80211_data *drv,
+ u64 scan_cookie)
+{
+ struct nl_msg *msg;
+ struct nlattr *params;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Abort vendor scan with cookie 0x%llx",
+ (long long unsigned int) scan_cookie);
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u64(msg, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, scan_cookie))
+ goto fail;
+
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Aborting vendor scan with cookie 0x%llx failed: ret=%d (%s)",
+ (long long unsigned int) scan_cookie, ret,
+ strerror(-ret));
+ goto fail;
+ }
+ return 0;
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
/**
* wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
* @eloop_ctx: Driver private data
@@ -98,7 +154,13 @@
struct wpa_driver_nl80211_data *drv = eloop_ctx;
wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it");
- if (!wpa_driver_nl80211_abort_scan(drv->first_bss))
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (drv->vendor_scan_cookie &&
+ nl80211_abort_vendor_scan(drv, drv->vendor_scan_cookie) == 0)
+ return;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ if (!drv->vendor_scan_cookie &&
+ nl80211_abort_scan(drv->first_bss) == 0)
return;
wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
@@ -206,6 +268,19 @@
}
}
+ if (params->duration) {
+ if (!(drv->capa.rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) ||
+ nla_put_u16(msg, NL80211_ATTR_MEASUREMENT_DURATION,
+ params->duration))
+ goto fail;
+
+ if (params->duration_mandatory &&
+ nla_put_flag(msg,
+ NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY))
+ goto fail;
+ }
+
if (scan_flags &&
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
goto fail;
@@ -487,6 +562,39 @@
nla_nest_end(msg, match_sets);
}
+ if (params->relative_rssi_set) {
+ struct nl80211_bss_select_rssi_adjust rssi_adjust;
+
+ os_memset(&rssi_adjust, 0, sizeof(rssi_adjust));
+ wpa_printf(MSG_DEBUG, "nl80211: Relative RSSI: %d",
+ params->relative_rssi);
+ if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+ params->relative_rssi))
+ goto fail;
+
+ if (params->relative_adjust_rssi) {
+ int pref_band_set = 1;
+
+ switch (params->relative_adjust_band) {
+ case WPA_SETBAND_5G:
+ rssi_adjust.band = NL80211_BAND_5GHZ;
+ break;
+ case WPA_SETBAND_2G:
+ rssi_adjust.band = NL80211_BAND_2GHZ;
+ break;
+ default:
+ pref_band_set = 0;
+ break;
+ }
+ rssi_adjust.delta = params->relative_adjust_rssi;
+
+ if (pref_band_set &&
+ nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+ sizeof(rssi_adjust), &rssi_adjust))
+ goto fail;
+ }
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
/* TODO: if we get an error here, we should fall back to normal scan */
@@ -562,7 +670,9 @@
}
-int bss_info_handler(struct nl_msg *msg, void *arg)
+static struct wpa_scan_res *
+nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
@@ -579,50 +689,21 @@
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC },
};
- struct nl80211_bss_info_arg *_arg = arg;
- struct wpa_scan_results *res = _arg->res;
- struct wpa_scan_res **tmp;
struct wpa_scan_res *r;
const u8 *ie, *beacon_ie;
size_t ie_len, beacon_ie_len;
u8 *pos;
- size_t i;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[NL80211_ATTR_BSS])
- return NL_SKIP;
+ return NULL;
if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
bss_policy))
- return NL_SKIP;
- if (bss[NL80211_BSS_STATUS]) {
- enum nl80211_bss_status status;
- status = nla_get_u32(bss[NL80211_BSS_STATUS]);
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->assoc_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
- _arg->assoc_freq);
- }
- if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->ibss_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
- _arg->ibss_freq);
- }
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_BSSID]) {
- os_memcpy(_arg->assoc_bssid,
- nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
- wpa_printf(MSG_DEBUG, "nl80211: Associated with "
- MACSTR, MAC2STR(_arg->assoc_bssid));
- }
- }
- if (!res)
- return NL_SKIP;
+ return NULL;
if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
@@ -638,13 +719,13 @@
beacon_ie_len = 0;
}
- if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+ if (nl80211_scan_filtered(drv, ie ? ie : beacon_ie,
ie ? ie_len : beacon_ie_len))
- return NL_SKIP;
+ return NULL;
r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
if (r == NULL)
- return NL_SKIP;
+ return NULL;
if (bss[NL80211_BSS_BSSID])
os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
ETH_ALEN);
@@ -695,40 +776,36 @@
}
}
- /*
- * cfg80211 maintains separate BSS table entries for APs if the same
- * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
- * not use frequency as a separate key in the BSS table, so filter out
- * duplicated entries. Prefer associated BSS entry in such a case in
- * order to get the correct frequency into the BSS table. Similarly,
- * prefer newer entries over older.
- */
- for (i = 0; i < res->num; i++) {
- const u8 *s1, *s2;
- if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
- continue;
-
- s1 = get_ie((u8 *) (res->res[i] + 1),
- res->res[i]->ie_len, WLAN_EID_SSID);
- s2 = get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
- if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
- os_memcmp(s1, s2, 2 + s1[1]) != 0)
- continue;
-
- /* Same BSSID,SSID was already included in scan results */
- wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
- "for " MACSTR, MAC2STR(r->bssid));
-
- if (((r->flags & WPA_SCAN_ASSOCIATED) &&
- !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
- r->age < res->res[i]->age) {
- os_free(res->res[i]);
- res->res[i] = r;
- } else
- os_free(r);
- return NL_SKIP;
+ if (bss[NL80211_BSS_PARENT_TSF] && bss[NL80211_BSS_PARENT_BSSID]) {
+ r->parent_tsf = nla_get_u64(bss[NL80211_BSS_PARENT_TSF]);
+ os_memcpy(r->tsf_bssid, nla_data(bss[NL80211_BSS_PARENT_BSSID]),
+ ETH_ALEN);
}
+ return r;
+}
+
+
+struct nl80211_bss_info_arg {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_scan_results *res;
+};
+
+static int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_bss_info_arg *_arg = arg;
+ struct wpa_scan_results *res = _arg->res;
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+
+ r = nl80211_parse_bss_info(_arg->drv, msg);
+ if (!r)
+ return NL_SKIP;
+
+ if (!res) {
+ os_free(r);
+ return NL_SKIP;
+ }
tmp = os_realloc_array(res->res, res->num + 1,
sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
@@ -755,36 +832,51 @@
}
+static void nl80211_check_bss_status(struct wpa_driver_nl80211_data *drv,
+ struct wpa_scan_res *r)
+{
+ if (!(r->flags & WPA_SCAN_ASSOCIATED))
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results indicate BSS status with "
+ MACSTR " as associated", MAC2STR(r->bssid));
+ if (is_sta_interface(drv->nlmode) && !drv->associated) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Local state (not associated) does not match with BSS state");
+ clear_state_mismatch(drv, r->bssid);
+ } else if (is_sta_interface(drv->nlmode) &&
+ os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Local state (associated with " MACSTR
+ ") does not match with BSS state",
+ MAC2STR(drv->bssid));
+ clear_state_mismatch(drv, r->bssid);
+ clear_state_mismatch(drv, drv->bssid);
+ }
+}
+
+
static void wpa_driver_nl80211_check_bss_status(
struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
{
size_t i;
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
+ for (i = 0; i < res->num; i++)
+ nl80211_check_bss_status(drv, res->res[i]);
+}
- if (r->flags & WPA_SCAN_ASSOCIATED) {
- wpa_printf(MSG_DEBUG, "nl80211: Scan results "
- "indicate BSS status with " MACSTR
- " as associated",
- MAC2STR(r->bssid));
- if (is_sta_interface(drv->nlmode) &&
- !drv->associated) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(not associated) does not match "
- "with BSS state");
- clear_state_mismatch(drv, r->bssid);
- } else if (is_sta_interface(drv->nlmode) &&
- os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
- 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(associated with " MACSTR ") does "
- "not match with BSS state",
- MAC2STR(drv->bssid));
- clear_state_mismatch(drv, r->bssid);
- clear_state_mismatch(drv, drv->bssid);
- }
- }
+
+static void nl80211_update_scan_res_noise(struct wpa_scan_res *res,
+ struct nl80211_noise_info *info)
+{
+ unsigned int i;
+
+ for (i = 0; res && i < info->count; i++) {
+ if ((int) info->freq[i] != res->freq ||
+ !(res->flags & WPA_SCAN_NOISE_INVALID))
+ continue;
+ res->noise = info->noise[i];
+ res->flags &= ~WPA_SCAN_NOISE_INVALID;
}
}
@@ -810,9 +902,17 @@
arg.res = res;
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
if (ret == 0) {
+ struct nl80211_noise_info info;
+
wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
"BSSes)", (unsigned long) res->num);
- nl80211_get_noise_for_scan_results(drv, res);
+ if (nl80211_get_noise_for_scan_results(drv, &info) == 0) {
+ size_t i;
+
+ for (i = 0; i < res->num; ++i)
+ nl80211_update_scan_res_noise(res->res[i],
+ &info);
+ }
return res;
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
@@ -840,45 +940,57 @@
}
-void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+struct nl80211_dump_scan_ctx {
+ struct wpa_driver_nl80211_data *drv;
+ int idx;
+};
+
+static int nl80211_dump_scan_handler(struct nl_msg *msg, void *arg)
{
- struct wpa_scan_results *res;
- size_t i;
+ struct nl80211_dump_scan_ctx *ctx = arg;
+ struct wpa_scan_res *r;
- res = nl80211_get_scan_results(drv);
- if (res == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
- wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
- (int) i, (int) res->num, MAC2STR(r->bssid),
- r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
- }
-
- wpa_scan_results_free(res);
+ r = nl80211_parse_bss_info(ctx->drv, msg);
+ if (!r)
+ return NL_SKIP;
+ wpa_printf(MSG_DEBUG, "nl80211: %d " MACSTR " %d%s",
+ ctx->idx, MAC2STR(r->bssid), r->freq,
+ r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+ ctx->idx++;
+ os_free(r);
+ return NL_SKIP;
}
-int wpa_driver_nl80211_abort_scan(void *priv)
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct nl80211_dump_scan_ctx ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+ ctx.drv = drv;
+ ctx.idx = 0;
+ msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
+ if (msg)
+ send_and_recv_msgs(drv, msg, nl80211_dump_scan_handler, &ctx);
+}
+
+
+int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie)
{
struct i802_bss *bss = priv;
+#ifdef CONFIG_DRIVER_NL80211_QCA
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret;
- struct nl_msg *msg;
- wpa_printf(MSG_DEBUG, "nl80211: Abort scan");
- msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ABORT_SCAN);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)",
- ret, strerror(-ret));
- }
-
- return ret;
+ /*
+ * If scan_cookie is zero, a normal scan through kernel (cfg80211)
+ * was triggered, hence abort the cfg80211 scan instead of the vendor
+ * scan.
+ */
+ if (drv->scan_vendor_cmd_avail && scan_cookie)
+ return nl80211_abort_vendor_scan(drv, scan_cookie);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ return nl80211_abort_scan(bss);
}
@@ -1015,7 +1127,7 @@
}
if (scan_flags &&
- nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, scan_flags))
goto fail;
if (params->p2p_probe) {
@@ -1043,6 +1155,14 @@
goto fail;
}
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: "
+ MACSTR, MAC2STR(params->bssid));
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SCAN_BSSID, ETH_ALEN,
+ params->bssid))
+ goto fail;
+ }
+
nla_nest_end(msg, attr);
ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie);
@@ -1056,6 +1176,8 @@
drv->vendor_scan_cookie = cookie;
drv->scan_state = SCAN_REQUESTED;
+ /* Pass the cookie to the caller to help distinguish the scans. */
+ params->scan_cookie = cookie;
wpa_printf(MSG_DEBUG,
"nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx",
@@ -1070,4 +1192,54 @@
return ret;
}
+
+/**
+ * nl80211_set_default_scan_ies - Set the scan default IEs to the driver
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @ies: Pointer to IEs buffer
+ * @ies_len: Length of IEs in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg = NULL;
+ struct nlattr *attr;
+ int ret = -1;
+
+ if (!drv->set_wifi_conf_vendor_cmd_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_SET_WIFI_CONFIGURATION))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (attr == NULL)
+ goto fail;
+
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan default IEs", ies, ies_len);
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES,
+ ies_len, ies))
+ goto fail;
+
+ nla_nest_end(msg, attr);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Set scan default IEs failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 43d4193..655128a 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -97,15 +97,31 @@
return 0;
}
-
+
static int wpa_driver_privsep_scan(void *priv,
struct wpa_driver_scan_params *params)
{
struct wpa_driver_privsep_data *drv = priv;
- const u8 *ssid = params->ssids[0].ssid;
- size_t ssid_len = params->ssids[0].ssid_len;
+ struct privsep_cmd_scan scan;
+ size_t i;
+
wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
- return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
+ os_memset(&scan, 0, sizeof(scan));
+ scan.num_ssids = params->num_ssids;
+ for (i = 0; i < params->num_ssids; i++) {
+ if (!params->ssids[i].ssid)
+ continue;
+ scan.ssid_lens[i] = params->ssids[i].ssid_len;
+ os_memcpy(scan.ssids[i], params->ssids[i].ssid,
+ scan.ssid_lens[i]);
+ }
+
+ for (i = 0; i < PRIVSEP_MAX_SCAN_FREQS &&
+ params->freqs && params->freqs[i]; i++)
+ scan.freqs[i] = params->freqs[i];
+ scan.num_freqs = i;
+
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, &scan, sizeof(scan),
NULL, NULL);
}
@@ -173,7 +189,11 @@
break;
os_memcpy(r, pos, len);
pos += len;
- if (sizeof(*r) + r->ie_len > (size_t) len) {
+ if (sizeof(*r) + r->ie_len + r->beacon_ie_len > (size_t) len) {
+ wpa_printf(MSG_ERROR,
+ "privsep: Invalid scan result len (%d + %d + %d > %d)",
+ (int) sizeof(*r), (int) r->ie_len,
+ (int) r->beacon_ie_len, len);
os_free(r);
break;
}
@@ -234,7 +254,7 @@
__func__, priv, params->freq, MAC2STR(params->bssid),
params->auth_alg, params->local_state_change, params->p2p);
- buflen = sizeof(*data) + params->ie_len + params->sae_data_len;
+ buflen = sizeof(*data) + params->ie_len + params->auth_data_len;
data = os_zalloc(buflen);
if (data == NULL)
return -1;
@@ -259,8 +279,8 @@
os_memcpy(pos, params->ie, params->ie_len);
pos += params->ie_len;
}
- if (params->sae_data_len)
- os_memcpy(pos, params->sae_data, params->sae_data_len);
+ if (params->auth_data_len)
+ os_memcpy(pos, params->auth_data, params->auth_data_len);
res = wpa_priv_cmd(drv, PRIVSEP_CMD_AUTHENTICATE, data, buflen,
NULL, NULL);
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index d3e0595..e8a5135 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - roboswitch driver interface
- * Copyright (c) 2008-2009 Jouke Witteveen
+ * Copyright (c) 2008-2012 Jouke Witteveen
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -401,7 +401,9 @@
os_free(drv);
return NULL;
}
- if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
+ /* BCM63xx devices provide 0 here */
+ if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR &&
+ if_mii(&drv->ifr)->phy_id != 0) {
wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
"RoboSwitch?)", __func__);
os_free(drv);
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 791cd5d..458d458 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1042,6 +1042,7 @@
wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0);
eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_wext_send_rfkill, drv, drv->ctx);
/*
* Clear possibly configured driver parameters in order to make it
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 15e82df..7e09dcf 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -12,13 +12,14 @@
#include "common.h"
#include "eloop.h"
#include "driver.h"
+#include "driver_wired_common.h"
#include <sys/ioctl.h>
+#undef IFNAMSIZ
#include <net/if.h>
#ifdef __linux__
#include <netpacket/packet.h>
#include <net/if_arp.h>
-#include <net/if.h>
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
#include <net/if_dl.h>
@@ -42,20 +43,12 @@
#pragma pack(pop)
#endif /* _MSC_VER */
-static const u8 pae_group_addr[ETH_ALEN] =
-{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
-
struct wpa_driver_wired_data {
- char ifname[IFNAMSIZ + 1];
- void *ctx;
+ struct driver_wired_common_data common;
- int sock; /* raw packet socket for driver access */
int dhcp_sock; /* socket for dhcp packets */
int use_pae_group_addr;
-
- int pf_sock;
- int membership, multi, iff_allmulti, iff_up;
};
@@ -83,34 +76,6 @@
};
-static int wired_multicast_membership(int sock, int ifindex,
- const u8 *addr, int add)
-{
-#ifdef __linux__
- struct packet_mreq mreq;
-
- if (sock < 0)
- return -1;
-
- os_memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- os_memcpy(mreq.mr_address, addr, ETH_ALEN);
-
- if (setsockopt(sock, SOL_PACKET,
- add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
- return -1;
- }
- return 0;
-#else /* __linux__ */
- return -1;
-#endif /* __linux__ */
-}
-
-
#ifdef __linux__
static void handle_data(void *ctx, unsigned char *buf, size_t len)
{
@@ -208,21 +173,22 @@
struct sockaddr_in addr2;
int n = 1;
- drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
- if (drv->sock < 0) {
+ drv->common.sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->common.sock < 0) {
wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
strerror(errno));
return -1;
}
- if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
+ if (eloop_register_read_sock(drv->common.sock, handle_read,
+ drv->common.ctx, NULL)) {
wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFINDEX, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
strerror(errno));
return -1;
@@ -234,13 +200,14 @@
wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
addr.sll_ifindex);
- if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (bind(drv->common.sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
/* filter multicast address */
- if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex,
+ if (wired_multicast_membership(drv->common.sock, ifr.ifr_ifindex,
pae_group_addr, 1) < 0) {
wpa_printf(MSG_ERROR, "wired: Failed to add multicast group "
"membership");
@@ -248,8 +215,8 @@
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
- if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ os_strlcpy(ifr.ifr_name, drv->common.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->common.sock, SIOCGIFHWADDR, &ifr) != 0) {
wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
strerror(errno));
return -1;
@@ -269,8 +236,8 @@
return -1;
}
- if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
- NULL)) {
+ if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp,
+ drv->common.ctx, NULL)) {
wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
@@ -294,7 +261,7 @@
}
os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->common.ifname, IFNAMSIZ);
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
(char *) &ifr, sizeof(ifr)) < 0) {
wpa_printf(MSG_ERROR,
@@ -343,7 +310,7 @@
pos = (u8 *) (hdr + 1);
os_memcpy(pos, data, data_len);
- res = send(drv->sock, (u8 *) hdr, len, 0);
+ res = send(drv->common.sock, (u8 *) hdr, len, 0);
os_free(hdr);
if (res < 0) {
@@ -368,8 +335,9 @@
return NULL;
}
- drv->ctx = hapd;
- os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
+ drv->common.ctx = hapd;
+ os_strlcpy(drv->common.ifname, params->ifname,
+ sizeof(drv->common.ifname));
drv->use_pae_group_addr = params->use_pae_group_addr;
if (wired_init_sockets(drv, params->own_addr)) {
@@ -385,9 +353,9 @@
{
struct wpa_driver_wired_data *drv = priv;
- if (drv->sock >= 0) {
- eloop_unregister_read_sock(drv->sock);
- close(drv->sock);
+ if (drv->common.sock >= 0) {
+ eloop_unregister_read_sock(drv->common.sock);
+ close(drv->common.sock);
}
if (drv->dhcp_sock >= 0) {
@@ -399,227 +367,18 @@
}
-static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
-{
- ssid[0] = 0;
- return 0;
-}
-
-
-static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
-{
- /* Report PAE group address as the "BSSID" for wired connection. */
- os_memcpy(bssid, pae_group_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->flags = WPA_DRIVER_FLAGS_WIRED;
- return 0;
-}
-
-
-static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *flags = ifr.ifr_flags & 0xffff;
- return 0;
-}
-
-
-static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
-{
- struct ifreq ifr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_flags = flags & 0xffff;
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
-static int wpa_driver_wired_get_ifstatus(const char *ifname, int *status)
-{
- struct ifmediareq ifmr;
- int s;
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifmr, 0, sizeof(ifmr));
- os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
- (IFM_ACTIVE | IFM_AVALID);
-
- return 0;
-}
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-
-
-static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
-{
- struct ifreq ifr;
- int s;
-
-#ifdef __sun__
- return -1;
-#endif /* __sun__ */
-
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-#ifdef __linux__
- ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
- os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
-#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- struct sockaddr_dl *dlp;
- dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
- dlp->sdl_len = sizeof(struct sockaddr_dl);
- dlp->sdl_family = AF_LINK;
- dlp->sdl_index = 0;
- dlp->sdl_nlen = 0;
- dlp->sdl_alen = ETH_ALEN;
- dlp->sdl_slen = 0;
- os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
-#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
- {
- struct sockaddr *sap;
- sap = (struct sockaddr *) &ifr.ifr_addr;
- sap->sa_len = sizeof(struct sockaddr);
- sap->sa_family = AF_UNSPEC;
- os_memcpy(sap->sa_data, addr, ETH_ALEN);
- }
-#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
-
- if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
- strerror(errno));
- close(s);
- return -1;
- }
- close(s);
- return 0;
-}
-
-
static void * wpa_driver_wired_init(void *ctx, const char *ifname)
{
struct wpa_driver_wired_data *drv;
- int flags;
drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->ctx = ctx;
-#ifdef __linux__
- drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
- if (drv->pf_sock < 0)
- wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
-#else /* __linux__ */
- drv->pf_sock = -1;
-#endif /* __linux__ */
-
- if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
- !(flags & IFF_UP) &&
- wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
- drv->iff_up = 1;
- }
-
- if (wired_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
- "packet socket", __func__);
- drv->membership = 1;
- } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
- wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
- "SIOCADDMULTI", __func__);
- drv->multi = 1;
- } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
- wpa_printf(MSG_INFO, "%s: Could not get interface "
- "flags", __func__);
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
os_free(drv);
return NULL;
- } else if (flags & IFF_ALLMULTI) {
- wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
- "for multicast", __func__);
- } else if (wpa_driver_wired_set_ifflags(ifname,
- flags | IFF_ALLMULTI) < 0) {
- wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
- __func__);
- os_free(drv);
- return NULL;
- } else {
- wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
- __func__);
- drv->iff_allmulti = 1;
}
-#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
- {
- int status;
- wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
- __func__);
- while (wpa_driver_wired_get_ifstatus(ifname, &status) == 0 &&
- status == 0)
- sleep(1);
- }
-#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
return drv;
}
@@ -628,41 +387,8 @@
static void wpa_driver_wired_deinit(void *priv)
{
struct wpa_driver_wired_data *drv = priv;
- int flags;
- if (drv->membership &&
- wired_multicast_membership(drv->pf_sock,
- if_nametoindex(drv->ifname),
- pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
- "group (PACKET)", __func__);
- }
-
- if (drv->multi &&
- wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
- "group (SIOCDELMULTI)", __func__);
- }
-
- if (drv->iff_allmulti &&
- (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
- wpa_driver_wired_set_ifflags(drv->ifname,
- flags & ~IFF_ALLMULTI) < 0)) {
- wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
- __func__);
- }
-
- if (drv->iff_up &&
- wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
- (flags & IFF_UP) &&
- wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
- __func__);
- }
-
- if (drv->pf_sock != -1)
- close(drv->pf_sock);
-
+ driver_wired_deinit_common(&drv->common);
os_free(drv);
}
@@ -673,9 +399,9 @@
.hapd_init = wired_driver_hapd_init,
.hapd_deinit = wired_driver_hapd_deinit,
.hapd_send_eapol = wired_send_eapol,
- .get_ssid = wpa_driver_wired_get_ssid,
- .get_bssid = wpa_driver_wired_get_bssid,
- .get_capa = wpa_driver_wired_get_capa,
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
.init = wpa_driver_wired_init,
.deinit = wpa_driver_wired_deinit,
};
diff --git a/src/drivers/driver_wired_common.c b/src/drivers/driver_wired_common.c
new file mode 100644
index 0000000..a860b1c
--- /dev/null
+++ b/src/drivers/driver_wired_common.c
@@ -0,0 +1,322 @@
+/*
+ * Common functions for Wired Ethernet driver interfaces
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#ifdef __linux__
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */
+#ifdef __sun__
+#include <sys/sockio.h>
+#endif /* __sun__ */
+
+
+static int driver_wired_get_ifflags(const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+static int driver_wired_set_ifflags(const char *ifname, int flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int driver_wired_multi(const char *ifname, const u8 *addr, int add)
+{
+ struct ifreq ifr;
+ int s;
+
+#ifdef __sun__
+ return -1;
+#endif /* __sun__ */
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+#ifdef __linux__
+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ {
+ struct sockaddr_dl *dlp;
+
+ dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETH_ALEN;
+ dlp->sdl_slen = 0;
+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+ {
+ struct sockaddr *sap;
+
+ sap = (struct sockaddr *) &ifr.ifr_addr;
+ sap->sa_len = sizeof(struct sockaddr);
+ sap->sa_family = AF_UNSPEC;
+ os_memcpy(sap->sa_data, addr, ETH_ALEN);
+ }
+#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
+
+ if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add)
+{
+#ifdef __linux__
+ struct packet_mreq mreq;
+
+ if (sock < 0)
+ return -1;
+
+ os_memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ os_memcpy(mreq.mr_address, addr, ETH_ALEN);
+
+ if (setsockopt(sock, SOL_PACKET,
+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+int driver_wired_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+int driver_wired_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_WIRED;
+ return 0;
+}
+
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+static int driver_wired_get_ifstatus(const char *ifname, int *status)
+{
+ struct ifmediareq ifmr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifmr, 0, sizeof(ifmr));
+ os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+ close(s);
+ *status = (ifmr.ifm_status & (IFM_ACTIVE | IFM_AVALID)) ==
+ (IFM_ACTIVE | IFM_AVALID);
+
+ return 0;
+}
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+
+
+int driver_wired_init_common(struct driver_wired_common_data *common,
+ const char *ifname, void *ctx)
+{
+ int flags;
+
+ os_strlcpy(common->ifname, ifname, sizeof(common->ifname));
+ common->ctx = ctx;
+
+#ifdef __linux__
+ common->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (common->pf_sock < 0)
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
+#else /* __linux__ */
+ common->pf_sock = -1;
+#endif /* __linux__ */
+
+ if (driver_wired_get_ifflags(ifname, &flags) == 0 &&
+ !(flags & IFF_UP) &&
+ driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0)
+ common->iff_up = 1;
+
+ if (wired_multicast_membership(common->pf_sock,
+ if_nametoindex(common->ifname),
+ pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Added multicast membership with packet socket",
+ __func__);
+ common->membership = 1;
+ } else if (driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Added multicast membership with SIOCADDMULTI",
+ __func__);
+ common->multi = 1;
+ } else if (driver_wired_get_ifflags(ifname, &flags) < 0) {
+ wpa_printf(MSG_INFO, "%s: Could not get interface flags",
+ __func__);
+ return -1;
+ } else if (flags & IFF_ALLMULTI) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Interface is already configured for multicast",
+ __func__);
+ } else if (driver_wired_set_ifflags(ifname,
+ flags | IFF_ALLMULTI) < 0) {
+ wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", __func__);
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", __func__);
+ common->iff_allmulti = 1;
+ }
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+ {
+ int status;
+
+ wpa_printf(MSG_DEBUG, "%s: waiting for link to become active",
+ __func__);
+ while (driver_wired_get_ifstatus(ifname, &status) == 0 &&
+ status == 0)
+ sleep(1);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */
+
+ return 0;
+}
+
+
+void driver_wired_deinit_common(struct driver_wired_common_data *common)
+{
+ int flags;
+
+ if (common->membership &&
+ wired_multicast_membership(common->pf_sock,
+ if_nametoindex(common->ifname),
+ pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to remove PAE multicast group (PACKET)",
+ __func__);
+ }
+
+ if (common->multi &&
+ driver_wired_multi(common->ifname, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Failed to remove PAE multicast group (SIOCDELMULTI)",
+ __func__);
+ }
+
+ if (common->iff_allmulti &&
+ (driver_wired_get_ifflags(common->ifname, &flags) < 0 ||
+ driver_wired_set_ifflags(common->ifname,
+ flags & ~IFF_ALLMULTI) < 0)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
+ __func__);
+ }
+
+ if (common->iff_up &&
+ driver_wired_get_ifflags(common->ifname, &flags) == 0 &&
+ (flags & IFF_UP) &&
+ driver_wired_set_ifflags(common->ifname, flags & ~IFF_UP) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
+ __func__);
+ }
+
+ if (common->pf_sock != -1)
+ close(common->pf_sock);
+}
diff --git a/src/drivers/driver_wired_common.h b/src/drivers/driver_wired_common.h
new file mode 100644
index 0000000..2bb0710
--- /dev/null
+++ b/src/drivers/driver_wired_common.h
@@ -0,0 +1,34 @@
+/*
+ * Common definitions for Wired Ethernet driver interfaces
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_WIRED_COMMON_H
+#define DRIVER_WIRED_COMMON_H
+
+struct driver_wired_common_data {
+ char ifname[IFNAMSIZ + 1];
+ void *ctx;
+
+ int sock; /* raw packet socket for driver access */
+ int pf_sock;
+ int membership, multi, iff_allmulti, iff_up;
+};
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+int wired_multicast_membership(int sock, int ifindex, const u8 *addr, int add);
+int driver_wired_get_ssid(void *priv, u8 *ssid);
+int driver_wired_get_bssid(void *priv, u8 *bssid);
+int driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa);
+
+int driver_wired_init_common(struct driver_wired_common_data *common,
+ const char *ifname, void *ctx);
+void driver_wired_deinit_common(struct driver_wired_common_data *common);
+
+#endif /* DRIVER_WIRED_COMMON_H */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index a98af9a..e95df6d 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -10,42 +10,6 @@
#include "utils/common.h"
#include "driver.h"
-#ifdef CONFIG_DRIVER_WEXT
-extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
-#endif /* CONFIG_DRIVER_WEXT */
-#ifdef CONFIG_DRIVER_NL80211
-extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
-#endif /* CONFIG_DRIVER_NL80211 */
-#ifdef CONFIG_DRIVER_HOSTAP
-extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
-#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_BSD
-extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
-#endif /* CONFIG_DRIVER_BSD */
-#ifdef CONFIG_DRIVER_OPENBSD
-extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
-#endif /* CONFIG_DRIVER_OPENBSD */
-#ifdef CONFIG_DRIVER_NDIS
-extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
-#endif /* CONFIG_DRIVER_NDIS */
-#ifdef CONFIG_DRIVER_WIRED
-extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
-#endif /* CONFIG_DRIVER_WIRED */
-#ifdef CONFIG_DRIVER_MACSEC_QCA
- /* driver_macsec_qca.c */
-extern struct wpa_driver_ops wpa_driver_macsec_qca_ops;
-#endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_ROBOSWITCH
-/* driver_roboswitch.c */
-extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
-#endif /* CONFIG_DRIVER_ROBOSWITCH */
-#ifdef CONFIG_DRIVER_ATHEROS
-extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
-#endif /* CONFIG_DRIVER_ATHEROS */
-#ifdef CONFIG_DRIVER_NONE
-extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
-#endif /* CONFIG_DRIVER_NONE */
-
const struct wpa_driver_ops *const wpa_drivers[] =
{
@@ -70,6 +34,9 @@
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_MACSEC_LINUX
+ &wpa_driver_macsec_linux_ops,
+#endif /* CONFIG_DRIVER_MACSEC_LINUX */
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index c1bfff1..1496b47 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -15,11 +15,24 @@
ifdef CONFIG_DRIVER_WIRED
DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
DRV_OBJS += ../src/drivers/driver_wired.o
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef CONFIG_DRIVER_MACSEC_LINUX
+DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
+DRV_OBJS += ../src/drivers/driver_macsec_linux.o
+NEED_DRV_WIRED_COMMON=1
+CONFIG_LIBNL3_ROUTE=y
endif
ifdef CONFIG_DRIVER_MACSEC_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
DRV_OBJS += ../src/drivers/driver_macsec_qca.o
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef NEED_DRV_WIRED_COMMON
+DRV_OBJS += ../src/drivers/driver_wired_common.o
endif
ifdef CONFIG_DRIVER_NL80211
@@ -29,7 +42,6 @@
DRV_OBJS += ../src/drivers/driver_nl80211_event.o
DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o
DRV_OBJS += ../src/drivers/driver_nl80211_scan.o
-DRV_OBJS += ../src/utils/radiotap.o
ifdef CONFIG_DRIVER_NL80211_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA
endif
@@ -38,6 +50,7 @@
NEED_NETLINK=y
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
+NEED_RADIOTAP=y
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
@@ -164,6 +177,10 @@
DRV_OBJS += ../src/drivers/rfkill.o
endif
+ifdef NEED_RADIOTAP
+DRV_OBJS += ../src/utils/radiotap.o
+endif
+
ifdef CONFIG_VLAN_NETLINK
ifdef CONFIG_FULL_DYNAMIC_VLAN
ifdef CONFIG_LIBNL32
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 0444e52..cd25133 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -15,6 +15,18 @@
ifdef CONFIG_DRIVER_WIRED
DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
DRV_OBJS += src/drivers/driver_wired.c
+NEED_DRV_WIRED_COMMON=1
+endif
+
+ifdef CONFIG_DRIVER_MACSEC_LINUX
+DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_LINUX
+DRV_OBJS += src/drivers/driver_macsec_linux.c
+NEED_DRV_WIRED_COMMON=1
+CONFIG_LIBNL3_ROUTE=y
+endif
+
+ifdef NEED_DRV_WIRED_COMMON
+DRV_OBJS += src/drivers/driver_wired_common.c
endif
ifdef CONFIG_DRIVER_NL80211
@@ -25,7 +37,6 @@
DRV_OBJS += src/drivers/driver_nl80211_event.c
DRV_OBJS += src/drivers/driver_nl80211_monitor.c
DRV_OBJS += src/drivers/driver_nl80211_scan.c
-DRV_OBJS += src/utils/radiotap.c
ifdef CONFIG_DRIVER_NL80211_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA
endif
@@ -34,6 +45,7 @@
NEED_NETLINK=y
NEED_LINUX_IOCTL=y
NEED_RFKILL=y
+NEED_RADIOTAP=y
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
@@ -149,6 +161,10 @@
DRV_OBJS += src/drivers/rfkill.c
endif
+ifdef NEED_RADIOTAP
+DRV_OBJS += src/utils/radiotap.c
+endif
+
ifdef CONFIG_DRIVER_CUSTOM
DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
endif
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 7758969..d6c62ee 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -48,6 +48,7 @@
#define NL80211_MULTICAST_GROUP_REG "regulatory"
#define NL80211_MULTICAST_GROUP_MLME "mlme"
#define NL80211_MULTICAST_GROUP_VENDOR "vendor"
+#define NL80211_MULTICAST_GROUP_NAN "nan"
#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
/**
@@ -322,7 +323,9 @@
* @NL80211_CMD_GET_SCAN: get scan results
* @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
* %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
- * probe requests at CCK rate or not.
+ * probe requests at CCK rate or not. %NL80211_ATTR_BSSID can be used to
+ * specify a BSSID to scan for; if not included, the wildcard BSSID will
+ * be used.
* @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
* NL80211_CMD_GET_SCAN and on the "scan" multicast group)
* @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
@@ -427,7 +430,11 @@
* @NL80211_CMD_ASSOCIATE: association request and notification; like
* NL80211_CMD_AUTHENTICATE but for Association and Reassociation
* (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
- * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
+ * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). The
+ * %NL80211_ATTR_PREV_BSSID attribute is used to specify whether the
+ * request is for the initial association to an ESS (that attribute not
+ * included) or for reassociation within the ESS (that attribute is
+ * included).
* @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
* NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
* MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
@@ -477,6 +484,9 @@
* set of BSSID,frequency parameters is used (i.e., either the enforcing
* %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict
* %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT).
+ * %NL80211_ATTR_PREV_BSSID can be used to request a reassociation within
+ * the ESS in case the device is already associated and an association with
+ * a different BSS is desired.
* Background scan period can optionally be
* specified in %NL80211_ATTR_BG_SCAN_PERIOD,
* if not specified default background scan configuration
@@ -484,7 +494,12 @@
* This attribute is ignored if driver does not support roam scan.
* It is also sent as an event, with the BSSID and response IEs when the
* connection is established or failed to be established. This can be
- * determined by the STATUS_CODE attribute.
+ * determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success,
+ * non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the
+ * event, the connection attempt failed due to not being able to initiate
+ * authentication/association or not receiving a response from the AP.
+ * Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
+ * well to remain backwards compatible.
* @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
* sent as an event when the card/driver roamed by itself.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
@@ -585,6 +600,20 @@
*
* @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
*
+ * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform
+ * multicast to unicast conversion. When enabled, all multicast packets
+ * with ethertype ARP, IPv4 or IPv6 (possibly within an 802.1Q header)
+ * will be sent out to each station once with the destination (multicast)
+ * MAC address replaced by the station's MAC address. Note that this may
+ * break certain expectations of the receiver, e.g. the ability to drop
+ * unicast IP packets encapsulated in multicast L2 frames, or the ability
+ * to not send destination unreachable messages in such cases.
+ * This can only be toggled per BSS. Configure this on an interface of
+ * type %NL80211_IFTYPE_AP. It applies to all its VLAN interfaces
+ * (%NL80211_IFTYPE_AP_VLAN), except for those in 4addr (WDS) mode.
+ * If %NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED is not present with this
+ * command, the feature is disabled.
+ *
* @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
* mesh config parameters may be given.
* @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
@@ -824,6 +853,47 @@
* not running. The driver indicates the status of the scan through
* cfg80211_scan_done().
*
+ * @NL80211_CMD_START_NAN: Start NAN operation, identified by its
+ * %NL80211_ATTR_WDEV interface. This interface must have been previously
+ * created with %NL80211_CMD_NEW_INTERFACE. After it has been started, the
+ * NAN interface will create or join a cluster. This command must have a
+ * valid %NL80211_ATTR_NAN_MASTER_PREF attribute and optional
+ * %NL80211_ATTR_NAN_DUAL attributes.
+ * After this command NAN functions can be added.
+ * @NL80211_CMD_STOP_NAN: Stop the NAN operation, identified by
+ * its %NL80211_ATTR_WDEV interface.
+ * @NL80211_CMD_ADD_NAN_FUNCTION: Add a NAN function. The function is defined
+ * with %NL80211_ATTR_NAN_FUNC nested attribute. When called, this
+ * operation returns the strictly positive and unique instance id
+ * (%NL80211_ATTR_NAN_FUNC_INST_ID) and a cookie (%NL80211_ATTR_COOKIE)
+ * of the function upon success.
+ * Since instance ID's can be re-used, this cookie is the right
+ * way to identify the function. This will avoid races when a termination
+ * event is handled by the user space after it has already added a new
+ * function that got the same instance id from the kernel as the one
+ * which just terminated.
+ * This cookie may be used in NAN events even before the command
+ * returns, so userspace shouldn't process NAN events until it processes
+ * the response to this command.
+ * Look at %NL80211_ATTR_SOCKET_OWNER as well.
+ * @NL80211_CMD_DEL_NAN_FUNCTION: Delete a NAN function by cookie.
+ * This command is also used as a notification sent when a NAN function is
+ * terminated. This will contain a %NL80211_ATTR_NAN_FUNC_INST_ID
+ * and %NL80211_ATTR_COOKIE attributes.
+ * @NL80211_CMD_CHANGE_NAN_CONFIG: Change current NAN configuration. NAN
+ * must be operational (%NL80211_CMD_START_NAN was executed).
+ * It must contain at least one of the following attributes:
+ * %NL80211_ATTR_NAN_MASTER_PREF, %NL80211_ATTR_NAN_DUAL.
+ * @NL80211_CMD_NAN_FUNC_MATCH: Notification sent when a match is reported.
+ * This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
+ * %NL80211_ATTR_COOKIE.
+ *
+ * @NL80211_CMD_UPDATE_CONNECT_PARAMS: Update one or more connect parameters
+ * for subsequent roaming cases if the driver or firmware uses internal
+ * BSS selection. This command can be issued only while connected and it
+ * does not result in a change for the current association. Currently,
+ * only the %NL80211_ATTR_IE data is used and updated with this command.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1012,6 +1082,17 @@
NL80211_CMD_ABORT_SCAN,
+ NL80211_CMD_START_NAN,
+ NL80211_CMD_STOP_NAN,
+ NL80211_CMD_ADD_NAN_FUNCTION,
+ NL80211_CMD_DEL_NAN_FUNCTION,
+ NL80211_CMD_CHANGE_NAN_CONFIG,
+ NL80211_CMD_NAN_MATCH,
+
+ NL80211_CMD_SET_MULTICAST_TO_UNICAST,
+
+ NL80211_CMD_UPDATE_CONNECT_PARAMS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1285,8 +1366,11 @@
* @NL80211_ATTR_RESP_IE: (Re)association response information elements as
* sent by peer, for ROAM and successful CONNECT events.
*
- * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
- * commands to specify using a reassociate frame
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used in ASSOCIATE and CONNECT
+ * commands to specify a request to reassociate within an ESS, i.e., to use
+ * Reassociate Request frame (with the value of this attribute in the
+ * Current AP address field) instead of Association Request frame which is
+ * used for the initial association to an ESS.
*
* @NL80211_ATTR_KEY: key information in a nested attribute with
* %NL80211_KEY_* sub-attributes
@@ -1326,7 +1410,13 @@
* enum nl80211_band value is used as the index (nla_type() of the nested
* data. If a band is not included, it will be configured to allow all
* rates based on negotiated supported rates information. This attribute
- * is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
+ * is used with %NL80211_CMD_SET_TX_BITRATE_MASK and with starting AP,
+ * and joining mesh networks (not IBSS yet). In the later case, it must
+ * specify just a single bitrate, which is to be used for the beacon.
+ * The driver must also specify support for this with the extended
+ * features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
+ * NL80211_EXT_FEATURE_BEACON_RATE_HT and
+ * NL80211_EXT_FEATURE_BEACON_RATE_VHT.
*
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
* at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
@@ -1572,8 +1662,16 @@
* the connection request from a station. nl80211_connect_failed_reason
* enum has different reasons of connection failure.
*
- * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
- * with the Authentication transaction sequence number field.
+ * @NL80211_ATTR_AUTH_DATA: Fields and elements in Authentication frames.
+ * This contains the authentication frame body (non-IE and IE data),
+ * excluding the Authentication algorithm number, i.e., starting at the
+ * Authentication transaction sequence number field. It is used with
+ * authentication algorithms that need special fields to be added into
+ * the frames (SAE and FILS). Currently, only the SAE cases use the
+ * initial two fields (Authentication transaction sequence number and
+ * Status code). However, those fields are included in the attribute data
+ * for all authentication algorithms to keep the attribute definition
+ * consistent.
*
* @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
* association request when used with NL80211_CMD_NEW_STATION)
@@ -1674,7 +1772,9 @@
*
* @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode
* Notification Element based on association request when used with
- * %NL80211_CMD_NEW_STATION; u8 attribute.
+ * %NL80211_CMD_NEW_STATION or %NL80211_CMD_SET_STATION (only when
+ * %NL80211_FEATURE_FULL_AP_CLIENT_STATE is supported, or with TDLS);
+ * u8 attribute.
*
* @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
* %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
@@ -1716,6 +1816,14 @@
* regulatory indoor configuration would be owned by the netlink socket
* that configured the indoor setting, and the indoor operation would be
* cleared when the socket is closed.
+ * If set during NAN interface creation, the interface will be destroyed
+ * if the socket is closed just like any other interface. Moreover, only
+ * the netlink socket that created the interface will be allowed to add
+ * and remove functions. NAN notifications will be sent in unicast to that
+ * socket. Without this attribute, any socket can add functions and the
+ * notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
+ * If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
+ * station will deauthenticate when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1727,6 +1835,8 @@
* underlying device supports these minimal RRM features:
* %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
* %NL80211_FEATURE_QUIET,
+ * Or, if global RRM is supported, see:
+ * %NL80211_EXT_FEATURE_RRM
* If this flag is used, driver must add the Power Capabilities IE to the
* association request. In addition, it must also set the RRM capability
* flag in the association request's Capability Info field.
@@ -1793,6 +1903,104 @@
* in a PBSS. Specified in %NL80211_CMD_CONNECT to request
* connecting to a PCP, and in %NL80211_CMD_START_AP to start
* a PCP instead of AP. Relevant for DMG networks only.
+ * @NL80211_ATTR_BSS_SELECT: nested attribute for driver supporting the
+ * BSS selection feature. When used with %NL80211_CMD_GET_WIPHY it contains
+ * attributes according &enum nl80211_bss_select_attr to indicate what
+ * BSS selection behaviours are supported. When used with %NL80211_CMD_CONNECT
+ * it contains the behaviour-specific attribute containing the parameters for
+ * BSS selection to be done by driver and/or firmware.
+ *
+ * @NL80211_ATTR_STA_SUPPORT_P2P_PS: whether P2P PS mechanism supported
+ * or not. u8, one of the values of &enum nl80211_sta_p2p_ps_status
+ *
+ * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
+ *
+ * @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes:
+ * %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA,
+ * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
+ * interface type.
+ *
+ * @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO
+ * groupID for monitor mode.
+ * The first 8 bytes are a mask that defines the membership in each
+ * group (there are 64 groups, group 0 and 63 are reserved),
+ * each bit represents a group and set to 1 for being a member in
+ * that group and 0 for not being a member.
+ * The remaining 16 bytes define the position in each group: 2 bits for
+ * each group.
+ * (smaller group numbers represented on most significant bits and bigger
+ * group numbers on least significant bits.)
+ * This attribute is used only if all interfaces are in monitor mode.
+ * Set this attribute in order to monitor packets using the given MU-MIMO
+ * groupID data.
+ * to turn off that feature set all the bits of the groupID to zero.
+ * @NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR: mac address for the sniffer to follow
+ * when using MU-MIMO air sniffer.
+ * to turn that feature off set an invalid mac address
+ * (e.g. FF:FF:FF:FF:FF:FF)
+ *
+ * @NL80211_ATTR_SCAN_START_TIME_TSF: The time at which the scan was actually
+ * started (u64). The time is the TSF of the BSS the interface that
+ * requested the scan is connected to (if available, otherwise this
+ * attribute must not be included).
+ * @NL80211_ATTR_SCAN_START_TIME_TSF_BSSID: The BSS according to which
+ * %NL80211_ATTR_SCAN_START_TIME_TSF is set.
+ * @NL80211_ATTR_MEASUREMENT_DURATION: measurement duration in TUs (u16). If
+ * %NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY is not set, this is the
+ * maximum measurement duration allowed. This attribute is used with
+ * measurement requests. It can also be used with %NL80211_CMD_TRIGGER_SCAN
+ * if the scan is used for beacon report radio measurement.
+ * @NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY: flag attribute that indicates
+ * that the duration specified with %NL80211_ATTR_MEASUREMENT_DURATION is
+ * mandatory. If this flag is not set, the duration is the maximum duration
+ * and the actual measurement duration may be shorter.
+ *
+ * @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
+ * used to pull the stored data for mesh peer in power save state.
+ *
+ * @NL80211_ATTR_NAN_MASTER_PREF: the master preference to be used by
+ * %NL80211_CMD_START_NAN and optionally with
+ * %NL80211_CMD_CHANGE_NAN_CONFIG. Its type is u8 and it can't be 0.
+ * Also, values 1 and 255 are reserved for certification purposes and
+ * should not be used during a normal device operation.
+ * @NL80211_ATTR_NAN_DUAL: NAN dual band operation config (see
+ * &enum nl80211_nan_dual_band_conf). This attribute is used with
+ * %NL80211_CMD_START_NAN and optionally with
+ * %NL80211_CMD_CHANGE_NAN_CONFIG.
+ * @NL80211_ATTR_NAN_FUNC: a function that can be added to NAN. See
+ * &enum nl80211_nan_func_attributes for description of this nested
+ * attribute.
+ * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
+ * See &enum nl80211_nan_match_attributes.
+ * @NL80211_ATTR_FILS_KEK: KEK for FILS (Re)Association Request/Response frame
+ * protection.
+ * @NL80211_ATTR_FILS_NONCES: Nonces (part of AAD) for FILS (Re)Association
+ * Request/Response frame protection. This attribute contains the 16 octet
+ * STA Nonce followed by 16 octets of AP Nonce.
+ *
+ * @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Indicates whether or not multicast
+ * packets should be send out as unicast to all stations (flag attribute).
+ *
+ * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also
+ * used in various commands/events for specifying the BSSID.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which
+ * other BSSs has to be better or slightly worse than the current
+ * connected BSS so that they get reported to user space.
+ * This will give an opportunity to userspace to consider connecting to
+ * other matching BSSs which have better or slightly worse RSSI than
+ * the current connected BSS by using an offloaded operation to avoid
+ * unnecessary wakeups.
+ *
+ * @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
+ * better BSSs. The attribute value is a packed structure
+ * value as specified by &struct nl80211_bss_select_rssi_adjust.
+ *
+ * @NL80211_ATTR_TIMEOUT_REASON: The reason for which an operation timed out.
+ * u32 attribute with an &enum nl80211_timeout_reason value. This is used,
+ * e.g., with %NL80211_CMD_CONNECT event.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2052,7 +2260,7 @@
NL80211_ATTR_CONN_FAILED_REASON,
- NL80211_ATTR_SAE_DATA,
+ NL80211_ATTR_AUTH_DATA,
NL80211_ATTR_VHT_CAPABILITY,
@@ -2170,6 +2378,41 @@
NL80211_ATTR_PBSS,
+ NL80211_ATTR_BSS_SELECT,
+
+ NL80211_ATTR_STA_SUPPORT_P2P_PS,
+
+ NL80211_ATTR_PAD,
+
+ NL80211_ATTR_IFTYPE_EXT_CAPA,
+
+ NL80211_ATTR_MU_MIMO_GROUP_DATA,
+ NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR,
+
+ NL80211_ATTR_SCAN_START_TIME_TSF,
+ NL80211_ATTR_SCAN_START_TIME_TSF_BSSID,
+ NL80211_ATTR_MEASUREMENT_DURATION,
+ NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY,
+
+ NL80211_ATTR_MESH_PEER_AID,
+
+ NL80211_ATTR_NAN_MASTER_PREF,
+ NL80211_ATTR_NAN_DUAL,
+ NL80211_ATTR_NAN_FUNC,
+ NL80211_ATTR_NAN_MATCH,
+
+ NL80211_ATTR_FILS_KEK,
+ NL80211_ATTR_FILS_NONCES,
+
+ NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
+
+ NL80211_ATTR_BSSID,
+
+ NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+ NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+
+ NL80211_ATTR_TIMEOUT_REASON,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2181,6 +2424,7 @@
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
+#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -2248,6 +2492,7 @@
* commands to create and destroy one
* @NL80211_IF_TYPE_OCB: Outside Context of a BSS
* This mode corresponds to the MIB variable dot11OCBActivated=true
+ * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev)
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
@@ -2268,6 +2513,7 @@
NL80211_IFTYPE_P2P_GO,
NL80211_IFTYPE_P2P_DEVICE,
NL80211_IFTYPE_OCB,
+ NL80211_IFTYPE_NAN,
/* keep last */
NUM_NL80211_IFTYPES,
@@ -2313,6 +2559,20 @@
NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
};
+/**
+ * enum nl80211_sta_p2p_ps_status - station support of P2P PS
+ *
+ * @NL80211_P2P_PS_UNSUPPORTED: station doesn't support P2P PS mechanism
+ * @@NL80211_P2P_PS_SUPPORTED: station supports P2P PS mechanism
+ * @NUM_NL80211_P2P_PS_STATUS: number of values
+ */
+enum nl80211_sta_p2p_ps_status {
+ NL80211_P2P_PS_UNSUPPORTED = 0,
+ NL80211_P2P_PS_SUPPORTED,
+
+ NUM_NL80211_P2P_PS_STATUS,
+};
+
#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER
/**
@@ -2470,6 +2730,9 @@
* TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
* each one of those is again nested with &enum nl80211_tid_stats
* attributes carrying the actual values.
+ * @NL80211_STA_INFO_RX_DURATION: aggregate PPDU duration for all frames
+ * received from the station (u64, usec)
+ * @NL80211_STA_INFO_PAD: attribute used for padding for 64-bit alignment
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2506,6 +2769,8 @@
NL80211_STA_INFO_BEACON_RX,
NL80211_STA_INFO_BEACON_SIGNAL_AVG,
NL80211_STA_INFO_TID_STATS,
+ NL80211_STA_INFO_RX_DURATION,
+ NL80211_STA_INFO_PAD,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -2522,6 +2787,7 @@
* transmitted MSDUs (not counting the first attempt; u64)
* @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
* MSDUs (u64)
+ * @NL80211_TID_STATS_PAD: attribute used for padding for 64-bit alignment
* @NUM_NL80211_TID_STATS: number of attributes here
* @NL80211_TID_STATS_MAX: highest numbered attribute here
*/
@@ -2531,6 +2797,7 @@
NL80211_TID_STATS_TX_MSDU,
NL80211_TID_STATS_TX_MSDU_RETRIES,
NL80211_TID_STATS_TX_MSDU_FAILED,
+ NL80211_TID_STATS_PAD,
/* keep last */
NUM_NL80211_TID_STATS,
@@ -2838,6 +3105,13 @@
* how this API was implemented in the past. Also, due to the same problem,
* the only way to create a matchset with only an RSSI filter (with this
* attribute) is if there's only a single matchset with the RSSI attribute.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether
+ * %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or
+ * relative to current bss's RSSI.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for
+ * BSS-es in the specified band is to be adjusted before doing
+ * RSSI-based BSS selection. The attribute value is a packed structure
+ * value as specified by &struct nl80211_bss_select_rssi_adjust.
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -2847,6 +3121,8 @@
NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -2967,6 +3243,7 @@
* transmitting data (on channel or globally)
* @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
* (on this channel or globally)
+ * @NL80211_SURVEY_INFO_PAD: attribute used for padding for 64-bit alignment
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -2982,6 +3259,7 @@
NL80211_SURVEY_INFO_TIME_RX,
NL80211_SURVEY_INFO_TIME_TX,
NL80211_SURVEY_INFO_TIME_SCAN,
+ NL80211_SURVEY_INFO_PAD,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
@@ -3407,6 +3685,13 @@
* @NL80211_BSS_LAST_SEEN_BOOTTIME: CLOCK_BOOTTIME timestamp when this entry
* was last updated by a received frame. The value is expected to be
* accurate to about 10ms. (u64, nanoseconds)
+ * @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
+ * @NL80211_BSS_PARENT_TSF: the time at the start of reception of the first
+ * octet of the timestamp field of the last beacon/probe received for
+ * this BSS. The time is the TSF of the BSS specified by
+ * @NL80211_BSS_PARENT_BSSID. (u64).
+ * @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
+ * is set.
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -3427,6 +3712,9 @@
NL80211_BSS_BEACON_TSF,
NL80211_BSS_PRESP_DATA,
NL80211_BSS_LAST_SEEN_BOOTTIME,
+ NL80211_BSS_PAD,
+ NL80211_BSS_PARENT_TSF,
+ NL80211_BSS_PARENT_BSSID,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -3459,6 +3747,9 @@
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
* @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
+ * @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key
+ * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS
+ * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key
* @__NL80211_AUTHTYPE_NUM: internal
* @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
* @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -3471,6 +3762,9 @@
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
NL80211_AUTHTYPE_SAE,
+ NL80211_AUTHTYPE_FILS_SK,
+ NL80211_AUTHTYPE_FILS_SK_PFS,
+ NL80211_AUTHTYPE_FILS_PK,
/* keep last */
__NL80211_AUTHTYPE_NUM,
@@ -3612,11 +3906,15 @@
* @NL80211_BAND_2GHZ: 2.4 GHz ISM band
* @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz)
+ * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
+ * since newer kernel versions may support more bands
*/
enum nl80211_band {
NL80211_BAND_2GHZ,
NL80211_BAND_5GHZ,
NL80211_BAND_60GHZ,
+
+ NUM_NL80211_BANDS,
};
/**
@@ -4075,6 +4373,9 @@
* of supported channel widths for radar detection.
* @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
* of supported regulatory regions for radar detection.
+ * @NL80211_IFACE_COMB_BI_MIN_GCD: u32 attribute specifying the minimum GCD of
+ * different beacon intervals supported by all the interface combinations
+ * in this group (if not present, all beacon intervals be identical).
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@@ -4082,8 +4383,8 @@
* limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
* => allows an AP and a STA that must match BIs
*
- * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
- * => allows 8 of AP/GO
+ * numbers = [ #{AP, P2P-GO} <= 8 ], BI min gcd, channels = 1, max = 8,
+ * => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
* => allows two STAs on different channels
@@ -4109,6 +4410,7 @@
NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
+ NL80211_IFACE_COMB_BI_MIN_GCD,
/* keep last */
NUM_NL80211_IFACE_COMB,
@@ -4402,12 +4704,60 @@
/**
* enum nl80211_ext_feature_index - bit index of extended features.
* @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
+ * @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can
+ * can request to use RRM (see %NL80211_ATTR_USE_RRM) with
+ * %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
+ * the ASSOC_REQ_USE_RRM flag in the association request even if
+ * NL80211_FEATURE_QUIET is not advertized.
+ * @NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER: This device supports MU-MIMO air
+ * sniffer which means that it can be configured to hear packets from
+ * certain groups which can be configured by the
+ * %NL80211_ATTR_MU_MIMO_GROUP_DATA attribute,
+ * or can be configured to follow a station by configuring the
+ * %NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR attribute.
+ * @NL80211_EXT_FEATURE_SCAN_START_TIME: This driver includes the actual
+ * time the scan started in scan results event. The time is the TSF of
+ * the BSS that the interface that requested the scan is connected to
+ * (if available).
+ * @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the
+ * time the last beacon/probe was received. The time is the TSF of the
+ * BSS that the interface that requested the scan is connected to
+ * (if available).
+ * @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of
+ * channel dwell time.
+ * @NL80211_EXT_FEATURE_BEACON_RATE_LEGACY: Driver supports beacon rate
+ * configuration (AP/mesh), supporting a legacy (non HT/VHT) rate.
+ * @NL80211_EXT_FEATURE_BEACON_RATE_HT: Driver supports beacon rate
+ * configuration (AP/mesh) with HT rates.
+ * @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate
+ * configuration (AP/mesh) with VHT rates.
+ * @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup
+ * with user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA: This driver supports randomized TA
+ * in @NL80211_CMD_FRAME while not associated.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports
+ * randomized TA in @NL80211_CMD_FRAME while associated.
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
+ * for reporting BSSs with better RSSI than the current connected BSS
+ * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_VHT_IBSS,
+ NL80211_EXT_FEATURE_RRM,
+ NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER,
+ NL80211_EXT_FEATURE_SCAN_START_TIME,
+ NL80211_EXT_FEATURE_BSS_PARENT_TSF,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
+ NL80211_EXT_FEATURE_BEACON_RATE_HT,
+ NL80211_EXT_FEATURE_BEACON_RATE_VHT,
+ NL80211_EXT_FEATURE_FILS_STA,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
+ NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -4447,6 +4797,21 @@
};
/**
+ * enum nl80211_timeout_reason - timeout reasons
+ *
+ * @NL80211_TIMEOUT_UNSPECIFIED: Timeout reason unspecified.
+ * @NL80211_TIMEOUT_SCAN: Scan (AP discovery) timed out.
+ * @NL80211_TIMEOUT_AUTH: Authentication timed out.
+ * @NL80211_TIMEOUT_ASSOC: Association timed out.
+ */
+enum nl80211_timeout_reason {
+ NL80211_TIMEOUT_UNSPECIFIED,
+ NL80211_TIMEOUT_SCAN,
+ NL80211_TIMEOUT_AUTH,
+ NL80211_TIMEOUT_ASSOC,
+};
+
+/**
* enum nl80211_scan_flags - scan request control flags
*
* Scan request control flags are used to control the handling
@@ -4657,4 +5022,231 @@
__NL80211_SCHED_SCAN_PLAN_AFTER_LAST - 1
};
+/**
+ * struct nl80211_bss_select_rssi_adjust - RSSI adjustment parameters.
+ *
+ * @band: band of BSS that must match for RSSI value adjustment. The value
+ * of this field is according to &enum nl80211_band.
+ * @delta: value used to adjust the RSSI value of matching BSS in dB.
+ */
+struct nl80211_bss_select_rssi_adjust {
+ __u8 band;
+ __s8 delta;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_bss_select_attr - attributes for bss selection.
+ *
+ * @__NL80211_BSS_SELECT_ATTR_INVALID: reserved.
+ * @NL80211_BSS_SELECT_ATTR_RSSI: Flag indicating only RSSI-based BSS selection
+ * is requested.
+ * @NL80211_BSS_SELECT_ATTR_BAND_PREF: attribute indicating BSS
+ * selection should be done such that the specified band is preferred.
+ * When there are multiple BSS-es in the preferred band, the driver
+ * shall use RSSI-based BSS selection as a second step. The value of
+ * this attribute is according to &enum nl80211_band (u32).
+ * @NL80211_BSS_SELECT_ATTR_RSSI_ADJUST: When present the RSSI level for
+ * BSS-es in the specified band is to be adjusted before doing
+ * RSSI-based BSS selection. The attribute value is a packed structure
+ * value as specified by &struct nl80211_bss_select_rssi_adjust.
+ * @NL80211_BSS_SELECT_ATTR_MAX: highest bss select attribute number.
+ * @__NL80211_BSS_SELECT_ATTR_AFTER_LAST: internal use.
+ *
+ * One and only one of these attributes are found within %NL80211_ATTR_BSS_SELECT
+ * for %NL80211_CMD_CONNECT. It specifies the required BSS selection behaviour
+ * which the driver shall use.
+ */
+enum nl80211_bss_select_attr {
+ __NL80211_BSS_SELECT_ATTR_INVALID,
+ NL80211_BSS_SELECT_ATTR_RSSI,
+ NL80211_BSS_SELECT_ATTR_BAND_PREF,
+ NL80211_BSS_SELECT_ATTR_RSSI_ADJUST,
+
+ /* keep last */
+ __NL80211_BSS_SELECT_ATTR_AFTER_LAST,
+ NL80211_BSS_SELECT_ATTR_MAX = __NL80211_BSS_SELECT_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_nan_dual_band_conf - NAN dual band configuration
+ *
+ * Defines the NAN dual band mode of operation
+ *
+ * @NL80211_NAN_BAND_DEFAULT: device default mode
+ * @NL80211_NAN_BAND_2GHZ: 2.4GHz mode
+ * @NL80211_NAN_BAND_5GHZ: 5GHz mode
+ */
+enum nl80211_nan_dual_band_conf {
+ NL80211_NAN_BAND_DEFAULT = 1 << 0,
+ NL80211_NAN_BAND_2GHZ = 1 << 1,
+ NL80211_NAN_BAND_5GHZ = 1 << 2,
+};
+
+/**
+ * enum nl80211_nan_function_type - NAN function type
+ *
+ * Defines the function type of a NAN function
+ *
+ * @NL80211_NAN_FUNC_PUBLISH: function is publish
+ * @NL80211_NAN_FUNC_SUBSCRIBE: function is subscribe
+ * @NL80211_NAN_FUNC_FOLLOW_UP: function is follow-up
+ */
+enum nl80211_nan_function_type {
+ NL80211_NAN_FUNC_PUBLISH,
+ NL80211_NAN_FUNC_SUBSCRIBE,
+ NL80211_NAN_FUNC_FOLLOW_UP,
+
+ /* keep last */
+ __NL80211_NAN_FUNC_TYPE_AFTER_LAST,
+ NL80211_NAN_FUNC_MAX_TYPE = __NL80211_NAN_FUNC_TYPE_AFTER_LAST - 1,
+};
+
+/**
+ * enum nl80211_nan_publish_type - NAN publish tx type
+ *
+ * Defines how to send publish Service Discovery Frames
+ *
+ * @NL80211_NAN_SOLICITED_PUBLISH: publish function is solicited
+ * @NL80211_NAN_UNSOLICITED_PUBLISH: publish function is unsolicited
+ */
+enum nl80211_nan_publish_type {
+ NL80211_NAN_SOLICITED_PUBLISH = 1 << 0,
+ NL80211_NAN_UNSOLICITED_PUBLISH = 1 << 1,
+};
+
+/**
+ * enum nl80211_nan_func_term_reason - NAN functions termination reason
+ *
+ * Defines termination reasons of a NAN function
+ *
+ * @NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST: requested by user
+ * @NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED: timeout
+ * @NL80211_NAN_FUNC_TERM_REASON_ERROR: errored
+ */
+enum nl80211_nan_func_term_reason {
+ NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST,
+ NL80211_NAN_FUNC_TERM_REASON_TTL_EXPIRED,
+ NL80211_NAN_FUNC_TERM_REASON_ERROR,
+};
+
+#define NL80211_NAN_FUNC_SERVICE_ID_LEN 6
+#define NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN 0xff
+#define NL80211_NAN_FUNC_SRF_MAX_LEN 0xff
+
+/**
+ * enum nl80211_nan_func_attributes - NAN function attributes
+ * @__NL80211_NAN_FUNC_INVALID: invalid
+ * @NL80211_NAN_FUNC_TYPE: &enum nl80211_nan_function_type (u8).
+ * @NL80211_NAN_FUNC_SERVICE_ID: 6 bytes of the service ID hash as
+ * specified in NAN spec. This is a binary attribute.
+ * @NL80211_NAN_FUNC_PUBLISH_TYPE: relevant if the function's type is
+ * publish. Defines the transmission type for the publish Service Discovery
+ * Frame, see &enum nl80211_nan_publish_type. Its type is u8.
+ * @NL80211_NAN_FUNC_PUBLISH_BCAST: relevant if the function is a solicited
+ * publish. Should the solicited publish Service Discovery Frame be sent to
+ * the NAN Broadcast address. This is a flag.
+ * @NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE: relevant if the function's type is
+ * subscribe. Is the subscribe active. This is a flag.
+ * @NL80211_NAN_FUNC_FOLLOW_UP_ID: relevant if the function's type is follow up.
+ * The instance ID for the follow up Service Discovery Frame. This is u8.
+ * @NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID: relevant if the function's type
+ * is follow up. This is a u8.
+ * The requestor instance ID for the follow up Service Discovery Frame.
+ * @NL80211_NAN_FUNC_FOLLOW_UP_DEST: the MAC address of the recipient of the
+ * follow up Service Discovery Frame. This is a binary attribute.
+ * @NL80211_NAN_FUNC_CLOSE_RANGE: is this function limited for devices in a
+ * close range. The range itself (RSSI) is defined by the device.
+ * This is a flag.
+ * @NL80211_NAN_FUNC_TTL: strictly positive number of DWs this function should
+ * stay active. If not present infinite TTL is assumed. This is a u32.
+ * @NL80211_NAN_FUNC_SERVICE_INFO: array of bytes describing the service
+ * specific info. This is a binary attribute.
+ * @NL80211_NAN_FUNC_SRF: Service Receive Filter. This is a nested attribute.
+ * See &enum nl80211_nan_srf_attributes.
+ * @NL80211_NAN_FUNC_RX_MATCH_FILTER: Receive Matching filter. This is a nested
+ * attribute. It is a list of binary values.
+ * @NL80211_NAN_FUNC_TX_MATCH_FILTER: Transmit Matching filter. This is a
+ * nested attribute. It is a list of binary values.
+ * @NL80211_NAN_FUNC_INSTANCE_ID: The instance ID of the function.
+ * Its type is u8 and it cannot be 0.
+ * @NL80211_NAN_FUNC_TERM_REASON: NAN function termination reason.
+ * See &enum nl80211_nan_func_term_reason.
+ *
+ * @NUM_NL80211_NAN_FUNC_ATTR: internal
+ * @NL80211_NAN_FUNC_ATTR_MAX: highest NAN function attribute
+ */
+enum nl80211_nan_func_attributes {
+ __NL80211_NAN_FUNC_INVALID,
+ NL80211_NAN_FUNC_TYPE,
+ NL80211_NAN_FUNC_SERVICE_ID,
+ NL80211_NAN_FUNC_PUBLISH_TYPE,
+ NL80211_NAN_FUNC_PUBLISH_BCAST,
+ NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE,
+ NL80211_NAN_FUNC_FOLLOW_UP_ID,
+ NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID,
+ NL80211_NAN_FUNC_FOLLOW_UP_DEST,
+ NL80211_NAN_FUNC_CLOSE_RANGE,
+ NL80211_NAN_FUNC_TTL,
+ NL80211_NAN_FUNC_SERVICE_INFO,
+ NL80211_NAN_FUNC_SRF,
+ NL80211_NAN_FUNC_RX_MATCH_FILTER,
+ NL80211_NAN_FUNC_TX_MATCH_FILTER,
+ NL80211_NAN_FUNC_INSTANCE_ID,
+ NL80211_NAN_FUNC_TERM_REASON,
+
+ /* keep last */
+ NUM_NL80211_NAN_FUNC_ATTR,
+ NL80211_NAN_FUNC_ATTR_MAX = NUM_NL80211_NAN_FUNC_ATTR - 1
+};
+
+/**
+ * enum nl80211_nan_srf_attributes - NAN Service Response filter attributes
+ * @__NL80211_NAN_SRF_INVALID: invalid
+ * @NL80211_NAN_SRF_INCLUDE: present if the include bit of the SRF set.
+ * This is a flag.
+ * @NL80211_NAN_SRF_BF: Bloom Filter. Present if and only if
+ * &NL80211_NAN_SRF_MAC_ADDRS isn't present. This attribute is binary.
+ * @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Mandatory if
+ * &NL80211_NAN_SRF_BF is present. This is a u8.
+ * @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Present if
+ * and only if &NL80211_NAN_SRF_BF isn't present. This is a nested
+ * attribute. Each nested attribute is a MAC address.
+ * @NUM_NL80211_NAN_SRF_ATTR: internal
+ * @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute
+ */
+enum nl80211_nan_srf_attributes {
+ __NL80211_NAN_SRF_INVALID,
+ NL80211_NAN_SRF_INCLUDE,
+ NL80211_NAN_SRF_BF,
+ NL80211_NAN_SRF_BF_IDX,
+ NL80211_NAN_SRF_MAC_ADDRS,
+
+ /* keep last */
+ NUM_NL80211_NAN_SRF_ATTR,
+ NL80211_NAN_SRF_ATTR_MAX = NUM_NL80211_NAN_SRF_ATTR - 1,
+};
+
+/**
+ * enum nl80211_nan_match_attributes - NAN match attributes
+ * @__NL80211_NAN_MATCH_INVALID: invalid
+ * @NL80211_NAN_MATCH_FUNC_LOCAL: the local function that had the
+ * match. This is a nested attribute.
+ * See &enum nl80211_nan_func_attributes.
+ * @NL80211_NAN_MATCH_FUNC_PEER: the peer function
+ * that caused the match. This is a nested attribute.
+ * See &enum nl80211_nan_func_attributes.
+ *
+ * @NUM_NL80211_NAN_MATCH_ATTR: internal
+ * @NL80211_NAN_MATCH_ATTR_MAX: highest NAN match attribute
+ */
+enum nl80211_nan_match_attributes {
+ __NL80211_NAN_MATCH_INVALID,
+ NL80211_NAN_MATCH_FUNC_LOCAL,
+ NL80211_NAN_MATCH_FUNC_PEER,
+
+ /* keep last */
+ NUM_NL80211_NAN_MATCH_ATTR,
+ NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index e8587fd..57990d2 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -79,7 +79,7 @@
/*
* RFC 4851, Section 5.1:
- * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
+ * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
* server_random + client_random, 48)
*/
os_memcpy(seed, server_random, TLS_RANDOM_LEN);
@@ -93,8 +93,7 @@
}
-u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
- const char *label, size_t len)
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, size_t len)
{
u8 *out;
@@ -102,7 +101,7 @@
if (out == NULL)
return NULL;
- if (tls_connection_prf(ssl_ctx, conn, label, 1, 1, out, len)) {
+ if (tls_connection_get_eap_fast_key(ssl_ctx, conn, out, len)) {
os_free(out);
return NULL;
}
diff --git a/src/eap_common/eap_fast_common.h b/src/eap_common/eap_fast_common.h
index 6756dd2..724204c 100644
--- a/src/eap_common/eap_fast_common.h
+++ b/src/eap_common/eap_fast_common.h
@@ -98,7 +98,7 @@
void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
const u8 *client_random, u8 *master_secret);
u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
- const char *label, size_t len);
+ size_t len);
int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 9110ca5..bc90c7a 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -489,7 +489,7 @@
u8 *emsk = NULL;
size_t emsk_len = 0;
u8 EMSKname[EAP_EMSK_NAME_LEN];
- u8 len[2];
+ u8 len[2], ctx[3];
char *realm;
size_t realm_len, nai_buf_len;
struct eap_erp_key *erp = NULL;
@@ -526,7 +526,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
- WPA_PUT_BE16(len, 8);
+ WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
if (hmac_sha256_kdf(sm->eapSessionId, sm->eapSessionIdLen, "EMSK",
len, sizeof(len),
EMSKname, EAP_EMSK_NAME_LEN) < 0) {
@@ -550,9 +550,11 @@
erp->rRK_len = emsk_len;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+ ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+ WPA_PUT_BE16(&ctx[1], erp->rRK_len);
if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
- "EAP Re-authentication Integrity Key@ietf.org",
- len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ "Re-authentication Integrity Key@ietf.org",
+ ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
goto fail;
}
@@ -571,8 +573,7 @@
#ifdef CONFIG_ERP
-static int eap_peer_erp_reauth_start(struct eap_sm *sm,
- const struct eap_hdr *hdr, size_t len)
+struct wpabuf * eap_peer_build_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
{
char *realm;
struct eap_erp_key *erp;
@@ -581,16 +582,16 @@
realm = eap_home_realm(sm);
if (!realm)
- return -1;
+ return NULL;
erp = eap_erp_get_key(sm, realm);
os_free(realm);
realm = NULL;
if (!erp)
- return -1;
+ return NULL;
if (erp->next_seq >= 65536)
- return -1; /* SEQ has range of 0..65535 */
+ return NULL; /* SEQ has range of 0..65535 */
/* TODO: check rRK lifetime expiration */
@@ -599,9 +600,9 @@
msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
- EAP_CODE_INITIATE, hdr->identifier);
+ EAP_CODE_INITIATE, eap_id);
if (msg == NULL)
- return -1;
+ return NULL;
wpabuf_put_u8(msg, 0x20); /* Flags: R=0 B=0 L=1 */
wpabuf_put_be16(msg, erp->next_seq);
@@ -615,13 +616,28 @@
if (hmac_sha256(erp->rIK, erp->rIK_len,
wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
wpabuf_free(msg);
- return -1;
+ return NULL;
}
wpabuf_put_data(msg, hash, 16);
- wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
sm->erp_seq = erp->next_seq;
erp->next_seq++;
+
+ wpa_hexdump_buf(MSG_DEBUG, "ERP: EAP-Initiate/Re-auth", msg);
+
+ return msg;
+}
+
+
+static int eap_peer_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
+{
+ struct wpabuf *msg;
+
+ msg = eap_peer_build_erp_reauth_start(sm, eap_id);
+ if (!msg)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
wpabuf_free(sm->eapRespData);
sm->eapRespData = msg;
sm->reauthInit = TRUE;
@@ -1566,7 +1582,7 @@
/* TODO: Derivation of domain specific keys for local ER */
}
- if (eap_peer_erp_reauth_start(sm, hdr, len) == 0)
+ if (eap_peer_erp_reauth_start(sm, hdr->identifier) == 0)
return;
invalid:
@@ -1577,8 +1593,7 @@
}
-static void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr,
- size_t len)
+void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr, size_t len)
{
#ifdef CONFIG_ERP
const u8 *pos = (const u8 *) (hdr + 1);
@@ -2231,6 +2246,7 @@
config->pending_req_passphrase++;
break;
case WPA_CTRL_REQ_SIM:
+ config->pending_req_sim++;
txt = msg;
break;
case WPA_CTRL_REQ_EXT_CERT_CHECK:
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 1a645af..932584f 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -252,6 +252,14 @@
* @ctx: eapol_ctx from eap_peer_sm_init() call
*/
void (*eap_proxy_cb)(void *ctx);
+
+ /**
+ * eap_proxy_notify_sim_status - Notification of SIM status change
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @sim_state: One of enum value from sim_state
+ */
+ void (*eap_proxy_notify_sim_status)(void *ctx,
+ enum eap_proxy_sim_state sim_state);
#endif /* CONFIG_EAP_PROXY */
/**
@@ -348,6 +356,8 @@
void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
int eap_peer_was_failure_expected(struct eap_sm *sm);
void eap_peer_erp_free_keys(struct eap_sm *sm);
+struct wpabuf * eap_peer_build_erp_reauth_start(struct eap_sm *sm, u8 eap_id);
+void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr, size_t len);
#endif /* IEEE8021X_EAPOL */
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 0bac62d..4188817 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -48,6 +48,7 @@
struct wpabuf *id_msgs;
int prev_id;
int result_ind, use_result_ind;
+ int use_pseudonym;
u8 eap_method;
u8 *network_name;
size_t network_name_len;
@@ -101,7 +102,8 @@
data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
- if (config && config->anonymous_identity) {
+ data->use_pseudonym = !sm->init_phase2;
+ if (config && config->anonymous_identity && data->use_pseudonym) {
data->pseudonym = os_malloc(config->anonymous_identity_len);
if (data->pseudonym) {
os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -350,7 +352,8 @@
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
- eap_set_anon_id(sm, NULL, 0);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
@@ -405,7 +408,9 @@
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
- eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, data->pseudonym,
+ data->pseudonym_len);
}
if (attr->next_reauth_id) {
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 39ddcff..16521c3 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -181,13 +181,13 @@
* subject_match - Constraint for server certificate subject
*
* This substring is matched against the subject of the authentication
- * server certificate. If this string is set, the server sertificate is
+ * server certificate. If this string is set, the server certificate is
* only accepted if it contains this string in the subject. The subject
* string is in following format:
*
* /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
*
- * Note: Since this is a substring match, this cannot be used securily
+ * Note: Since this is a substring match, this cannot be used securely
* to do a suffix match against a possible domain name in the CN entry.
* For such a use case, domain_suffix_match should be used instead.
*/
@@ -198,7 +198,7 @@
*
* Semicolon separated string of entries to be matched against the
* alternative subject name of the authentication server certificate.
- * If this string is set, the server sertificate is only accepted if it
+ * If this string is set, the server certificate is only accepted if it
* contains one of the entries in an alternative subject name
* extension.
*
@@ -628,6 +628,15 @@
int pending_req_passphrase;
/**
+ * pending_req_sim - Pending SIM request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_sim;
+
+ /**
* pending_req_otp - Whether there is a pending OTP request
*
* This field should not be set in configuration step. It is only used
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index f03cd4a..e4b0c10 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -275,7 +275,7 @@
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -303,7 +303,6 @@
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
- "key expansion",
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -485,7 +484,8 @@
if (*resp == NULL && config &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp || config->pending_req_new_password)) {
+ config->pending_req_otp || config->pending_req_new_password ||
+ config->pending_req_sim)) {
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
} else if (*resp == NULL)
@@ -710,9 +710,10 @@
if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
return -1;
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
- sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck));
+ if (sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck)) < 0)
+ return -1;
data->simck_idx++;
os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
@@ -1677,6 +1678,10 @@
static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ 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);
diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c
index 5f0b7fb..a7012d2 100644
--- a/src/eap_peer/eap_pax.c
+++ b/src/eap_peer/eap_pax.c
@@ -278,8 +278,15 @@
pos, EAP_PAX_MAC_LEN);
if (eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
- (u8 *) data->cid, data->cid_len, NULL, 0, mac) < 0 ||
- os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) {
+ (u8 *) data->cid, data->cid_len, NULL, 0, mac) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PAX: Could not derive MAC_CK(B, CID)");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+
+ if (os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
"received");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 45ba381..2ff6076 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -726,7 +726,8 @@
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp || config->pending_req_new_password)) {
+ config->pending_req_otp || config->pending_req_new_password ||
+ config->pending_req_sim)) {
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
}
@@ -1082,7 +1083,7 @@
eap_peer_tls_derive_key(sm, &data->ssl, label,
EAP_TLS_KEY_LEN);
if (data->key_data) {
- wpa_hexdump_key(MSG_DEBUG,
+ wpa_hexdump_key(MSG_DEBUG,
"EAP-PEAP: Derived key",
data->key_data,
EAP_TLS_KEY_LEN);
@@ -1163,6 +1164,10 @@
static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
+
+ 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);
data->pending_phase2_req = NULL;
wpabuf_free(data->pending_resp);
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
index 23cdbe6..7205fad 100644
--- a/src/eap_peer/eap_proxy.h
+++ b/src/eap_peer/eap_proxy.h
@@ -20,7 +20,7 @@
};
struct eap_proxy_sm *
-eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
void *msg_ctx);
void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy);
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
index d84f012..08009ca 100644
--- a/src/eap_peer/eap_proxy_dummy.c
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -12,7 +12,7 @@
#include "eap_proxy.h"
struct eap_proxy_sm *
-eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
void *msg_ctx)
{
return NULL;
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index d2bc981..662347b 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -345,7 +345,7 @@
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC);
wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF);
wpabuf_put_data(data->outbuf, id->token, sizeof(id->token));
- wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE);
+ wpabuf_put_u8(data->outbuf, id->prep);
wpabuf_put_data(data->outbuf, data->id_peer, data->id_peer_len);
eap_pwd_state(data, PWD_Commit_Req);
diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c
index 80f4667..330febb 100644
--- a/src/eap_peer/eap_sake.c
+++ b/src/eap_peer/eap_sake.c
@@ -309,11 +309,20 @@
return NULL;
}
- eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
- data->serverid, data->serverid_len,
- data->peerid, data->peerid_len, 0,
- wpabuf_head(reqData), wpabuf_len(reqData),
- attr.mic_s, mic_s);
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 0,
+ wpabuf_head(reqData), wpabuf_len(reqData),
+ attr.mic_s, mic_s)) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ eap_sake_state(data, FAILURE);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = FALSE;
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Auth-Reject");
+ return eap_sake_build_msg(data, id, 0,
+ EAP_SAKE_SUBTYPE_AUTH_REJECT);
+ }
if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
eap_sake_state(data, FAILURE);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index b97c95d..95ecdf7 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -46,6 +46,7 @@
CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
int result_ind, use_result_ind;
+ int use_pseudonym;
};
@@ -115,7 +116,8 @@
NULL;
}
- if (config && config->anonymous_identity) {
+ data->use_pseudonym = !sm->init_phase2;
+ if (config && config->anonymous_identity && data->use_pseudonym) {
data->pseudonym = os_malloc(config->anonymous_identity_len);
if (data->pseudonym) {
os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -372,7 +374,8 @@
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
- eap_set_anon_id(sm, NULL, 0);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
@@ -427,7 +430,9 @@
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
- eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, data->pseudonym,
+ data->pseudonym_len);
}
if (attr->next_reauth_id) {
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 406c162..0dcb9c1 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -328,8 +328,8 @@
if (out == NULL)
return NULL;
- if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
- out, len)) {
+ if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out,
+ len)) {
os_free(out);
return NULL;
}
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 92f94dc..3354b2d 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -458,7 +458,7 @@
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp)) {
+ config->pending_req_otp || config->pending_req_sim)) {
return 0;
}
@@ -1280,7 +1280,8 @@
} else if (config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp ||
- config->pending_req_new_password) {
+ config->pending_req_new_password ||
+ config->pending_req_sim) {
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_dup(in_decrypted);
}
@@ -1317,7 +1318,8 @@
(config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp ||
- config->pending_req_new_password)) {
+ config->pending_req_new_password ||
+ config->pending_req_sim)) {
/*
* Use empty buffer to force implicit request
* processing when EAP request is re-processed after
@@ -1537,7 +1539,7 @@
}
-static void eap_ttls_check_auth_status(struct eap_sm *sm,
+static void eap_ttls_check_auth_status(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret)
{
@@ -1648,6 +1650,10 @@
static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
+
+ 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);
data->pending_phase2_req = NULL;
wpabuf_free(data->pending_resp);
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index 9965513..0c5caa7 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -104,7 +104,7 @@
/* TNCC functions that IMCs can call */
-TNC_Result TNC_TNCC_ReportMessageTypes(
+static TNC_Result TNC_TNCC_ReportMessageTypes(
TNC_IMCID imcID,
TNC_MessageTypeList supportedTypes,
TNC_UInt32 typeCount)
@@ -138,7 +138,7 @@
}
-TNC_Result TNC_TNCC_SendMessage(
+static TNC_Result TNC_TNCC_SendMessage(
TNC_IMCID imcID,
TNC_ConnectionID connectionID,
TNC_BufferReference message,
@@ -183,7 +183,7 @@
}
-TNC_Result TNC_TNCC_RequestHandshakeRetry(
+static TNC_Result TNC_TNCC_RequestHandshakeRetry(
TNC_IMCID imcID,
TNC_ConnectionID connectionID,
TNC_RetryReason reason)
@@ -203,8 +203,8 @@
}
-TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
- const char *message)
+static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
+ const char *message)
{
wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
"severity==%lu message='%s')",
@@ -213,8 +213,9 @@
}
-TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
- const char *message)
+static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
+ TNC_ConnectionID connectionID,
+ const char *message)
{
wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
"connectionID==%lu message='%s')",
@@ -223,7 +224,7 @@
}
-TNC_Result TNC_TNCC_BindFunction(
+static TNC_Result TNC_TNCC_BindFunction(
TNC_IMCID imcID,
char *functionName,
void **pOutfunctionPointer)
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 69eaab8..93eab62 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -153,5 +153,6 @@
void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source,
const u8 *username, size_t username_len,
const u8 *challenge, const u8 *response);
+void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len);
#endif /* EAP_H */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 84ecafc..1b571cf 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -415,7 +415,7 @@
u8 *emsk = NULL;
size_t emsk_len = 0;
u8 EMSKname[EAP_EMSK_NAME_LEN];
- u8 len[2];
+ u8 len[2], ctx[3];
const char *domain;
size_t domain_len, nai_buf_len;
struct eap_server_erp_key *erp = NULL;
@@ -452,7 +452,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
- WPA_PUT_BE16(len, 8);
+ WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
"EMSK", len, sizeof(len),
EMSKname, EAP_EMSK_NAME_LEN) < 0) {
@@ -476,9 +476,11 @@
erp->rRK_len = emsk_len;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+ ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+ WPA_PUT_BE16(&ctx[1], erp->rRK_len);
if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
- "EAP Re-authentication Integrity Key@ietf.org",
- len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ "Re-authentication Integrity Key@ietf.org",
+ ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
goto fail;
}
@@ -1968,6 +1970,44 @@
}
+void eap_erp_update_identity(struct eap_sm *sm, const u8 *eap, size_t len)
+{
+#ifdef CONFIG_ERP
+ const struct eap_hdr *hdr;
+ const u8 *pos, *end;
+ struct erp_tlvs parse;
+
+ if (len < sizeof(*hdr) + 1)
+ return;
+ hdr = (const struct eap_hdr *) eap;
+ end = eap + len;
+ pos = (const u8 *) (hdr + 1);
+ if (hdr->code != EAP_CODE_INITIATE || *pos != EAP_ERP_TYPE_REAUTH)
+ return;
+ pos++;
+ if (pos + 3 > end)
+ return;
+
+ /* Skip Flags and SEQ */
+ pos += 3;
+
+ if (erp_parse_tlvs(pos, end, &parse, 1) < 0 || !parse.keyname)
+ return;
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP: Update identity based on EAP-Initiate/Re-auth keyName-NAI",
+ parse.keyname, parse.keyname_len);
+ os_free(sm->identity);
+ sm->identity = os_malloc(parse.keyname_len);
+ if (sm->identity) {
+ os_memcpy(sm->identity, parse.keyname, parse.keyname_len);
+ sm->identity_len = parse.keyname_len;
+ } else {
+ sm->identity_len = 0;
+ }
+#endif /* CONFIG_ERP */
+}
+
+
/**
* eap_get_interface - Get pointer to EAP-EAPOL interface data
* @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 6993159..f6d7e32 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -278,7 +278,7 @@
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -305,7 +305,6 @@
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
- "key expansion",
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -562,7 +561,7 @@
return -1;
}
data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
-
+
if (data->anon_provisioning) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
eap_fast_derive_key_provisioning(sm, data);
@@ -790,7 +789,7 @@
/* A-ID (inside PAC-Info) */
eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
-
+
/* Note: headers may be misaligned after A-ID */
if (sm->identity) {
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 64bf708..c60539f 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -602,7 +602,9 @@
if ((data->group_num != be_to_host16(id->group_num)) ||
(id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) ||
(os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) ||
- (id->prf != EAP_PWD_DEFAULT_PRF)) {
+ (id->prf != EAP_PWD_DEFAULT_PRF) ||
+ id->prep !=
+ data->password_hash ? EAP_PWD_PREP_MS : EAP_PWD_PREP_NONE) {
wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters");
eap_pwd_state(data, FAILURE);
return;
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 05677b7..6909695 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -115,8 +115,8 @@
if (out == NULL)
return NULL;
- if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0,
- out, len)) {
+ if (tls_connection_export_key(sm->ssl_ctx, data->conn, label, out,
+ len)) {
os_free(out);
return NULL;
}
diff --git a/src/eap_server/tncs.c b/src/eap_server/tncs.c
index dc6f689..cfcbd3e 100644
--- a/src/eap_server/tncs.c
+++ b/src/eap_server/tncs.c
@@ -140,7 +140,7 @@
/* TNCS functions that IMVs can call */
-TNC_Result TNC_TNCS_ReportMessageTypes(
+static TNC_Result TNC_TNCS_ReportMessageTypes(
TNC_IMVID imvID,
TNC_MessageTypeList supportedTypes,
TNC_UInt32 typeCount)
@@ -173,7 +173,7 @@
}
-TNC_Result TNC_TNCS_SendMessage(
+static TNC_Result TNC_TNCS_SendMessage(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_BufferReference message,
@@ -222,7 +222,7 @@
}
-TNC_Result TNC_TNCS_RequestHandshakeRetry(
+static TNC_Result TNC_TNCS_RequestHandshakeRetry(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_RetryReason reason)
@@ -233,7 +233,7 @@
}
-TNC_Result TNC_TNCS_ProvideRecommendation(
+static TNC_Result TNC_TNCS_ProvideRecommendation(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_IMV_Action_Recommendation recommendation,
@@ -260,7 +260,7 @@
}
-TNC_Result TNC_TNCS_GetAttribute(
+static TNC_Result TNC_TNCS_GetAttribute(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_AttributeID attribureID,
@@ -274,7 +274,7 @@
}
-TNC_Result TNC_TNCS_SetAttribute(
+static TNC_Result TNC_TNCS_SetAttribute(
TNC_IMVID imvID,
TNC_ConnectionID connectionID,
TNC_AttributeID attribureID,
@@ -287,7 +287,7 @@
}
-TNC_Result TNC_TNCS_BindFunction(
+static TNC_Result TNC_TNCS_BindFunction(
TNC_IMVID imvID,
char *functionName,
void **pOutFunctionPointer)
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 65460fc..e727005 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -95,7 +95,7 @@
SUPP_BE_RECEIVE = 4,
SUPP_BE_RESPONSE = 5,
SUPP_BE_FAIL = 6,
- SUPP_BE_TIMEOUT = 7,
+ SUPP_BE_TIMEOUT = 7,
SUPP_BE_SUCCESS = 8
} SUPP_BE_state; /* dot1xSuppBackendPaeState */
/* Variables */
@@ -250,6 +250,8 @@
if (sm->eapTriggerStart)
send_start = 1;
+ if (sm->ctx->preauth)
+ send_start = 1;
sm->eapTriggerStart = FALSE;
if (send_start) {
@@ -1999,6 +2001,7 @@
#ifdef CONFIG_EAP_PROXY
+
static void eapol_sm_eap_proxy_cb(void *ctx)
{
struct eapol_sm *sm = ctx;
@@ -2006,6 +2009,18 @@
if (sm->ctx->eap_proxy_cb)
sm->ctx->eap_proxy_cb(sm->ctx->ctx);
}
+
+
+static void
+eapol_sm_eap_proxy_notify_sim_status(void *ctx,
+ enum eap_proxy_sim_state sim_state)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->eap_proxy_notify_sim_status)
+ sm->ctx->eap_proxy_notify_sim_status(sm->ctx->ctx, sim_state);
+}
+
#endif /* CONFIG_EAP_PROXY */
@@ -2034,6 +2049,7 @@
eapol_sm_notify_status,
#ifdef CONFIG_EAP_PROXY
eapol_sm_eap_proxy_cb,
+ eapol_sm_eap_proxy_notify_sim_status,
#endif /* CONFIG_EAP_PROXY */
eapol_sm_set_anon_id
};
@@ -2141,16 +2157,14 @@
}
+#ifdef CONFIG_EAP_PROXY
int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
{
-#ifdef CONFIG_EAP_PROXY
if (sm->eap_proxy == NULL)
return -1;
return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
-#else /* CONFIG_EAP_PROXY */
- return -1;
-#endif /* CONFIG_EAP_PROXY */
}
+#endif /* CONFIG_EAP_PROXY */
void eapol_sm_erp_flush(struct eapol_sm *sm)
@@ -2158,3 +2172,26 @@
if (sm)
eap_peer_erp_free_keys(sm->eap);
}
+
+
+struct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm)
+{
+#ifdef CONFIG_ERP
+ if (!sm)
+ return NULL;
+ return eap_peer_build_erp_reauth_start(sm->eap, 0);
+#else /* CONFIG_ERP */
+ return NULL;
+#endif /* CONFIG_ERP */
+}
+
+
+void eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf,
+ size_t len)
+{
+#ifdef CONFIG_ERP
+ if (!sm)
+ return;
+ eap_peer_finish(sm->eap, (const struct eap_hdr *) buf, len);
+#endif /* CONFIG_ERP */
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 1309ff7..cb06e9a 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -277,6 +277,14 @@
* @ctx: eapol_ctx from eap_peer_sm_init() call
*/
void (*eap_proxy_cb)(void *ctx);
+
+ /**
+ * eap_proxy_notify_sim_status - Notification of SIM status change
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @status: One of enum value from sim_state
+ */
+ void (*eap_proxy_notify_sim_status)(void *ctx,
+ enum eap_proxy_sim_state sim_state);
#endif /* CONFIG_EAP_PROXY */
/**
@@ -328,6 +336,9 @@
struct ext_password_data *ext);
int eapol_sm_failed(struct eapol_sm *sm);
void eapol_sm_erp_flush(struct eapol_sm *sm);
+struct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm);
+void eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf,
+ size_t len);
int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
@@ -438,6 +449,15 @@
static inline void eapol_sm_erp_flush(struct eapol_sm *sm)
{
}
+static inline struct wpabuf *
+eapol_sm_build_erp_reauth_start(struct eapol_sm *sm)
+{
+ return NULL;
+}
+static inline void eapol_sm_process_erp_finish(struct eapol_sm *sm,
+ const u8 *buf, size_t len)
+{
+}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SUPP_SM_H */
diff --git a/src/fst/fst.c b/src/fst/fst.c
index 40430e2..32cd941 100644
--- a/src/fst/fst.c
+++ b/src/fst/fst.c
@@ -15,6 +15,7 @@
#include "fst/fst_defs.h"
#include "fst/fst_ctrl_iface.h"
+static int fst_global_initialized = 0;
struct dl_list fst_global_ctrls_list;
@@ -106,6 +107,7 @@
dl_list_init(&fst_global_groups_list);
dl_list_init(&fst_global_ctrls_list);
fst_session_global_init();
+ fst_global_initialized = 1;
return 0;
}
@@ -115,6 +117,9 @@
struct fst_group *group;
struct fst_ctrl_handle *h;
+ if (!fst_global_initialized)
+ return;
+
fst_session_global_deinit();
while ((group = fst_first_group()) != NULL)
fst_group_delete(group);
@@ -122,6 +127,7 @@
struct fst_ctrl_handle,
global_ctrls_lentry)))
fst_global_del_ctrl(h);
+ fst_global_initialized = 0;
}
diff --git a/src/fst/fst_defs.h b/src/fst/fst_defs.h
index 8ddcc61..5859f6f 100644
--- a/src/fst/fst_defs.h
+++ b/src/fst/fst_defs.h
@@ -34,7 +34,7 @@
struct session_transition_ie {
u8 element_id;
u8 length;
- u32 fsts_id;
+ le32 fsts_id;
u8 session_control;
u8 new_band_id;
u8 new_band_setup;
@@ -47,7 +47,7 @@
struct fst_setup_req {
u8 action;
u8 dialog_token;
- u32 llt;
+ le32 llt;
struct session_transition_ie stie;
/* Multi-band (optional) */
/* Wakeup Schedule (optional) */
@@ -70,18 +70,18 @@
struct fst_ack_req {
u8 action;
u8 dialog_token;
- u32 fsts_id;
+ le32 fsts_id;
} STRUCT_PACKED;
struct fst_ack_res {
u8 action;
u8 dialog_token;
- u32 fsts_id;
+ le32 fsts_id;
} STRUCT_PACKED;
struct fst_tear_down {
u8 action;
- u32 fsts_id;
+ le32 fsts_id;
} STRUCT_PACKED;
#endif /* IEEE_80211_FST_DEFS_H */
diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c
index d6157b1..a4ae016 100644
--- a/src/fst/fst_group.c
+++ b/src/fst/fst_group.c
@@ -29,7 +29,7 @@
const struct multi_band_ie *mbie =
(const struct multi_band_ie *) p;
WPA_ASSERT(mbie->eid == WLAN_EID_MULTI_BAND);
- WPA_ASSERT(2 + mbie->len >= sizeof(*mbie));
+ WPA_ASSERT(2U + mbie->len >= sizeof(*mbie));
fst_printf(MSG_WARNING,
"%s: %s: mb_ctrl=%u band_id=%u op_class=%u chan=%u bssid="
@@ -196,44 +196,35 @@
}
-static struct fst_iface *
-fst_group_get_new_iface_by_mbie_and_band_id(struct fst_group *g,
- const u8 *mb_ies_buff,
- size_t mb_ies_size,
- u8 band_id,
- u8 *iface_peer_addr)
+static const u8 * fst_mbie_get_peer_addr_for_band(const struct wpabuf *mbies,
+ u8 band_id)
{
- while (mb_ies_size >= 2) {
+ const u8 *p = wpabuf_head(mbies);
+ size_t s = wpabuf_len(mbies);
+
+ while (s >= 2) {
const struct multi_band_ie *mbie =
- (const struct multi_band_ie *) mb_ies_buff;
+ (const struct multi_band_ie *) p;
- if (mbie->eid != WLAN_EID_MULTI_BAND ||
- (size_t) 2 + mbie->len < sizeof(*mbie))
- break;
-
- if (mbie->band_id == band_id) {
- struct fst_iface *iface;
-
- foreach_fst_group_iface(g, iface) {
- const u8 *peer_addr =
- fst_mbie_get_peer_addr(mbie);
-
- if (peer_addr &&
- fst_iface_is_connected(iface, peer_addr,
- FALSE) &&
- band_id == fst_iface_get_band_id(iface)) {
- os_memcpy(iface_peer_addr, peer_addr,
- ETH_ALEN);
- return iface;
- }
- }
- break;
+ if (mbie->eid != WLAN_EID_MULTI_BAND) {
+ fst_printf(MSG_INFO, "unexpected eid %d", mbie->eid);
+ return NULL;
}
- mb_ies_buff += 2 + mbie->len;
- mb_ies_size -= 2 + mbie->len;
+ if (mbie->len < sizeof(*mbie) - 2 || mbie->len > s - 2) {
+ fst_printf(MSG_INFO, "invalid mbie len %d",
+ mbie->len);
+ return NULL;
+ }
+
+ if (mbie->band_id == band_id)
+ return fst_mbie_get_peer_addr(mbie);
+
+ p += 2 + mbie->len;
+ s -= 2 + mbie->len;
}
+ fst_printf(MSG_INFO, "mbie doesn't contain band %d", band_id);
return NULL;
}
@@ -270,78 +261,172 @@
}
-static Boolean
-fst_group_does_iface_appear_in_other_mbies(struct fst_group *g,
- struct fst_iface *iface,
- struct fst_iface *other,
- u8 *peer_addr)
+/**
+ * fst_group_get_peer_other_connection_1 - Find peer's "other" connection
+ * (iface, MAC tuple) by using peer's MB IE on iface.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ * "other" iface)
+ *
+ * This function parses peer's MB IE on iface. It looks for peer's MAC address
+ * on band_id (tmp_peer_addr). Next all interfaces are iterated to find an
+ * interface which correlates with band_id. If such interface is found, peer
+ * database is iterated to see if tmp_peer_addr is connected over it.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_1(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr)
{
- struct fst_get_peer_ctx *ctx;
- const u8 *addr;
- const u8 *iface_addr;
- enum mb_band_id iface_band_id;
+ const struct wpabuf *mbies;
+ struct fst_iface *other_iface;
+ const u8 *tmp_peer_addr;
- WPA_ASSERT(g == fst_iface_get_group(iface));
- WPA_ASSERT(g == fst_iface_get_group(other));
+ /* Get peer's MB IEs on iface */
+ mbies = fst_iface_get_peer_mb_ie(iface, peer_addr);
+ if (!mbies)
+ return NULL;
- iface_addr = fst_iface_get_addr(iface);
- iface_band_id = fst_iface_get_band_id(iface);
+ /* Get peer's MAC address on the "other" interface */
+ tmp_peer_addr = fst_mbie_get_peer_addr_for_band(mbies, band_id);
+ if (!tmp_peer_addr) {
+ fst_printf(MSG_INFO,
+ "couldn't extract other peer addr from mbies");
+ return NULL;
+ }
- addr = fst_iface_get_peer_first(other, &ctx, TRUE);
- for (; addr; addr = fst_iface_get_peer_next(other, &ctx, TRUE)) {
- const struct wpabuf *mbies;
- u8 other_iface_peer_addr[ETH_ALEN];
- struct fst_iface *other_new_iface;
+ fst_printf(MSG_DEBUG, "found other peer addr from mbies: " MACSTR,
+ MAC2STR(tmp_peer_addr));
- mbies = fst_iface_get_peer_mb_ie(other, addr);
- if (!mbies)
+ foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+ if (other_iface == iface ||
+ band_id != fst_iface_get_band_id(other_iface))
continue;
-
- other_new_iface = fst_group_get_new_iface_by_mbie_and_band_id(
- g, wpabuf_head(mbies), wpabuf_len(mbies),
- iface_band_id, other_iface_peer_addr);
- if (other_new_iface == iface &&
- os_memcmp(iface_addr, other_iface_peer_addr,
- ETH_ALEN) != 0) {
- os_memcpy(peer_addr, addr, ETH_ALEN);
- return TRUE;
+ if (fst_iface_is_connected(other_iface, tmp_peer_addr, FALSE)) {
+ os_memcpy(other_peer_addr, tmp_peer_addr, ETH_ALEN);
+ return other_iface;
}
}
- return FALSE;
-}
-
-
-struct fst_iface *
-fst_group_find_new_iface_by_stie(struct fst_group *g,
- struct fst_iface *iface,
- const u8 *peer_addr,
- const struct session_transition_ie *stie,
- u8 *iface_peer_addr)
-{
- struct fst_iface *i;
-
- foreach_fst_group_iface(g, i) {
- if (i == iface ||
- stie->new_band_id != fst_iface_get_band_id(i))
- continue;
- if (fst_group_does_iface_appear_in_other_mbies(g, iface, i,
- iface_peer_addr))
- return i;
- break;
- }
return NULL;
}
-struct fst_iface *
-fst_group_get_new_iface_by_stie_and_mbie(
- struct fst_group *g, const u8 *mb_ies_buff, size_t mb_ies_size,
- const struct session_transition_ie *stie, u8 *iface_peer_addr)
+/**
+ * fst_group_get_peer_other_connection_2 - Find peer's "other" connection
+ * (iface, MAC tuple) by using MB IEs of other peers.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ * "other" iface)
+ *
+ * This function iterates all connection (other_iface, cur_peer_addr tuples).
+ * For each connection, MB IE (of cur_peer_addr on other_iface) is parsed and
+ * MAC address on iface's band_id is extracted (this_peer_addr).
+ * this_peer_addr is then compared to peer_addr. A match indicates we have
+ * found the "other" connection.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_2(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr)
{
- return fst_group_get_new_iface_by_mbie_and_band_id(
- g, mb_ies_buff, mb_ies_size, stie->new_band_id,
- iface_peer_addr);
+ u8 this_band_id = fst_iface_get_band_id(iface);
+ const u8 *cur_peer_addr, *this_peer_addr;
+ struct fst_get_peer_ctx *ctx;
+ struct fst_iface *other_iface;
+ const struct wpabuf *cur_mbie;
+
+ foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+ if (other_iface == iface ||
+ band_id != fst_iface_get_band_id(other_iface))
+ continue;
+ cur_peer_addr = fst_iface_get_peer_first(other_iface, &ctx,
+ TRUE);
+ for (; cur_peer_addr;
+ cur_peer_addr = fst_iface_get_peer_next(other_iface, &ctx,
+ TRUE)) {
+ cur_mbie = fst_iface_get_peer_mb_ie(other_iface,
+ cur_peer_addr);
+ if (!cur_mbie)
+ continue;
+ this_peer_addr = fst_mbie_get_peer_addr_for_band(
+ cur_mbie, this_band_id);
+ if (!this_peer_addr)
+ continue;
+ if (os_memcmp(this_peer_addr, peer_addr, ETH_ALEN) ==
+ 0) {
+ os_memcpy(other_peer_addr, cur_peer_addr,
+ ETH_ALEN);
+ return other_iface;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * fst_group_get_peer_other_connection - Find peer's "other" connection (iface,
+ * MAC tuple).
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ * "other" iface)
+ *
+ * This function is called upon receiving FST Setup Request from some peer who
+ * has peer_addr on iface. It searches for another connection of the same peer
+ * on different interface which correlates with band_id. MB IEs received from
+ * peer (on the two different interfaces) are used to identify same peer.
+ */
+struct fst_iface *
+fst_group_get_peer_other_connection(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr)
+{
+ struct fst_iface *other_iface;
+
+ fst_printf(MSG_DEBUG, "%s: %s:" MACSTR ", %d", __func__,
+ fst_iface_get_name(iface), MAC2STR(peer_addr), band_id);
+
+ /*
+ * Two search methods are used:
+ * 1. Use peer's MB IE on iface to extract peer's MAC address on
+ * "other" connection. Then check if such "other" connection exists.
+ * 2. Iterate peer database, examine each MB IE to see if it points to
+ * (iface, peer_addr) tuple
+ */
+
+ other_iface = fst_group_get_peer_other_connection_1(iface, peer_addr,
+ band_id,
+ other_peer_addr);
+ if (other_iface) {
+ fst_printf(MSG_DEBUG, "found by method #1. %s:" MACSTR,
+ fst_iface_get_name(other_iface),
+ MAC2STR(other_peer_addr));
+ return other_iface;
+ }
+
+ other_iface = fst_group_get_peer_other_connection_2(iface, peer_addr,
+ band_id,
+ other_peer_addr);
+ if (other_iface) {
+ fst_printf(MSG_DEBUG, "found by method #2. %s:" MACSTR,
+ fst_iface_get_name(other_iface),
+ MAC2STR(other_peer_addr));
+ return other_iface;
+ }
+
+ fst_printf(MSG_INFO, "%s: other connection not found", __func__);
+ return NULL;
}
diff --git a/src/fst/fst_group.h b/src/fst/fst_group.h
index 3a87c0b..00aee9c 100644
--- a/src/fst/fst_group.h
+++ b/src/fst/fst_group.h
@@ -48,15 +48,9 @@
struct fst_iface * fst_group_get_iface_by_name(struct fst_group *g,
const char *ifname);
struct fst_iface *
-fst_group_find_new_iface_by_stie(struct fst_group *g,
- struct fst_iface *iface,
- const u8 *peer_addr,
- const struct session_transition_ie *stie,
- u8 *iface_peer_addr);
-struct fst_iface *
-fst_group_get_new_iface_by_stie_and_mbie(
- struct fst_group *g, const u8 *mb_ies_buff, size_t mb_ies_size,
- const struct session_transition_ie *stie, u8 *iface_peer_addr);
+fst_group_get_peer_other_connection(struct fst_iface *iface,
+ const u8 *peer_addr, u8 band_id,
+ u8 *other_peer_addr);
u8 fst_group_assign_dialog_token(struct fst_group *g);
u32 fst_group_assign_fsts_id(struct fst_group *g);
diff --git a/src/fst/fst_iface.h b/src/fst/fst_iface.h
index 0eb2732..cbaa7d8 100644
--- a/src/fst/fst_iface.h
+++ b/src/fst/fst_iface.h
@@ -106,7 +106,7 @@
const u8 *addr,
const u8 *buf, size_t size)
{
- return i->iface_obj.update_mb_ie(i->iface_obj.ctx, addr, buf, size);
+ i->iface_obj.update_mb_ie(i->iface_obj.ctx, addr, buf, size);
}
static inline const u8 * fst_iface_get_peer_first(struct fst_iface *i,
diff --git a/src/fst/fst_session.c b/src/fst/fst_session.c
index 449e304..a02a93e 100644
--- a/src/fst/fst_session.c
+++ b/src/fst/fst_session.c
@@ -44,7 +44,7 @@
#define FST_LLT_MS_DEFAULT 50
#define FST_ACTION_MAX_SUPPORTED FST_ACTION_ON_CHANNEL_TUNNEL
-const char * const fst_action_names[] = {
+static const char * const fst_action_names[] = {
[FST_ACTION_SETUP_REQUEST] = "Setup Request",
[FST_ACTION_SETUP_RESPONSE] = "Setup Response",
[FST_ACTION_TEAR_DOWN] = "Tear Down",
@@ -364,7 +364,6 @@
struct fst_iface *new_iface = NULL;
struct fst_group *g;
u8 new_iface_peer_addr[ETH_ALEN];
- const struct wpabuf *peer_mbies;
size_t plen;
if (frame_len < IEEE80211_HDRLEN + 1 + sizeof(*req)) {
@@ -400,36 +399,18 @@
MAC2STR(mgmt->sa));
}
- peer_mbies = fst_iface_get_peer_mb_ie(iface, mgmt->sa);
- if (peer_mbies) {
- new_iface = fst_group_get_new_iface_by_stie_and_mbie(
- g, wpabuf_head(peer_mbies), wpabuf_len(peer_mbies),
- &req->stie, new_iface_peer_addr);
- if (new_iface)
- fst_printf_iface(iface, MSG_INFO,
- "FST Request: new iface (%s:" MACSTR
- ") found by MB IEs",
- fst_iface_get_name(new_iface),
- MAC2STR(new_iface_peer_addr));
- }
-
- if (!new_iface) {
- new_iface = fst_group_find_new_iface_by_stie(
- g, iface, mgmt->sa, &req->stie,
- new_iface_peer_addr);
- if (new_iface)
- fst_printf_iface(iface, MSG_INFO,
- "FST Request: new iface (%s:" MACSTR
- ") found by others",
- fst_iface_get_name(new_iface),
- MAC2STR(new_iface_peer_addr));
- }
-
+ new_iface = fst_group_get_peer_other_connection(iface, mgmt->sa,
+ req->stie.new_band_id,
+ new_iface_peer_addr);
if (!new_iface) {
fst_printf_iface(iface, MSG_WARNING,
"FST Request dropped: new iface not found");
return;
}
+ fst_printf_iface(iface, MSG_INFO,
+ "FST Request: new iface (%s:" MACSTR ") found",
+ fst_iface_get_name(new_iface),
+ MAC2STR(new_iface_peer_addr));
s = fst_find_session_in_progress(mgmt->sa, g);
if (s) {
@@ -775,8 +756,6 @@
struct fst_session *s;
u32 id;
- WPA_ASSERT(!is_zero_ether_addr(own_addr));
-
id = fst_find_free_session_id();
if (id == FST_INVALID_SESSION_ID) {
fst_printf(MSG_ERROR, "Cannot assign new session ID");
@@ -994,7 +973,7 @@
res.stie.length = sizeof(res.stie) - 2;
if (status_code == WLAN_STATUS_SUCCESS) {
- res.stie.fsts_id = s->data.fsts_id;
+ res.stie.fsts_id = host_to_le32(s->data.fsts_id);
res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
fst_iface_get_channel_info(s->data.new_iface, &hw_mode,
@@ -1468,7 +1447,7 @@
res.stie.length = sizeof(res.stie) - 2;
if (res.status_code == WLAN_STATUS_SUCCESS) {
- res.stie.fsts_id = fsts_id;
+ res.stie.fsts_id = host_to_le32(fsts_id);
res.stie.session_control = SESSION_CONTROL(SESSION_TYPE_BSS, 0);
fst_iface_get_channel_info(s.data.new_iface, &hw_mode,
@@ -1517,7 +1496,7 @@
os_memset(&req, 0, sizeof(req));
req.action = FST_ACTION_ACK_REQUEST;
req.dialog_token = g->dialog_token;
- req.fsts_id = fsts_id;
+ req.fsts_id = host_to_le32(fsts_id);
return fst_session_send_action(&s, FALSE, &req, sizeof(req), NULL);
}
@@ -1545,7 +1524,7 @@
os_memset(&res, 0, sizeof(res));
res.action = FST_ACTION_ACK_RESPONSE;
res.dialog_token = g->dialog_token;
- res.fsts_id = fsts_id;
+ res.fsts_id = host_to_le32(fsts_id);
return fst_session_send_action(&s, FALSE, &res, sizeof(res), NULL);
}
@@ -1572,7 +1551,7 @@
os_memset(&td, 0, sizeof(td));
td.action = FST_ACTION_TEAR_DOWN;
- td.fsts_id = fsts_id;
+ td.fsts_id = host_to_le32(fsts_id);
return fst_session_send_action(&s, TRUE, &td, sizeof(td), NULL);
}
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
index e26ca20..ce86802 100644
--- a/src/l2_packet/l2_packet_privsep.c
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -51,7 +51,7 @@
return 0;
}
-
+
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
{
os_memcpy(addr, l2->own_addr, ETH_ALEN);
@@ -258,7 +258,7 @@
unlink(l2->own_socket_path);
os_free(l2->own_socket_path);
}
-
+
os_free(l2);
}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 6942c85..14d6279 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -711,6 +711,7 @@
struct p2p_message msg;
const u8 *p2p_dev_addr;
int wfd_changed;
+ int dev_name_changed;
int i;
struct os_reltime time_now;
@@ -788,11 +789,11 @@
dev->oper_ssid_len = msg.ssid[1];
}
- if (msg.adv_service_instance && msg.adv_service_instance_len) {
- wpabuf_free(dev->info.p2ps_instance);
+ wpabuf_free(dev->info.p2ps_instance);
+ dev->info.p2ps_instance = NULL;
+ if (msg.adv_service_instance && msg.adv_service_instance_len)
dev->info.p2ps_instance = wpabuf_alloc_copy(
msg.adv_service_instance, msg.adv_service_instance_len);
- }
if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
*msg.ds_params >= 1 && *msg.ds_params <= 14) {
@@ -821,6 +822,9 @@
}
dev->info.level = level;
+ dev_name_changed = os_strncmp(dev->info.device_name, msg.device_name,
+ WPS_DEV_NAME_MAX_LEN) != 0;
+
p2p_copy_wps_info(p2p, dev, 0, &msg);
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
@@ -839,9 +843,12 @@
wfd_changed = p2p_compare_wfd_info(dev, &msg);
- if (msg.wfd_subelems) {
+ if (wfd_changed) {
wpabuf_free(dev->info.wfd_subelems);
- dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ if (msg.wfd_subelems)
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ else
+ dev->info.wfd_subelems = NULL;
}
if (scan_res) {
@@ -855,6 +862,7 @@
p2p_update_peer_vendor_elems(dev, ies, ies_len);
if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
+ !dev_name_changed &&
(!msg.adv_service_instance ||
(dev->flags & P2P_DEV_P2PS_REPORTED)))
return 0;
@@ -1833,6 +1841,7 @@
p2p_clear_timeout(p2p);
p2p->ssid_set = 0;
peer->go_neg_req_sent = 0;
+ peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
peer->wps_method = WPS_NOT_READY;
peer->oob_pw_id = 0;
wpabuf_free(peer->go_neg_conf);
@@ -2234,6 +2243,58 @@
return buf;
}
+static int p2p_build_probe_resp_buf(struct p2p_data *p2p, struct wpabuf *buf,
+ struct wpabuf *ies,
+ const u8 *addr, int rx_freq)
+{
+ struct ieee80211_mgmt *resp;
+ u8 channel, op_class;
+
+ resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable));
+
+ resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_PROBE_RESP << 4));
+ os_memcpy(resp->da, addr, ETH_ALEN);
+ os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
+ resp->u.probe_resp.beacon_int = host_to_le16(100);
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ resp->u.probe_resp.capab_info =
+ host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
+ WLAN_CAPABILITY_PRIVACY |
+ WLAN_CAPABILITY_SHORT_SLOT_TIME);
+
+ wpabuf_put_u8(buf, WLAN_EID_SSID);
+ wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
+ wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
+
+ wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
+ wpabuf_put_u8(buf, 8);
+ wpabuf_put_u8(buf, (60 / 5) | 0x80);
+ wpabuf_put_u8(buf, 90 / 5);
+ wpabuf_put_u8(buf, (120 / 5) | 0x80);
+ wpabuf_put_u8(buf, 180 / 5);
+ wpabuf_put_u8(buf, (240 / 5) | 0x80);
+ wpabuf_put_u8(buf, 360 / 5);
+ wpabuf_put_u8(buf, 480 / 5);
+ wpabuf_put_u8(buf, 540 / 5);
+
+ if (!rx_freq) {
+ channel = p2p->cfg->channel;
+ } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ p2p_err(p2p, "Failed to convert freq to channel");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, channel);
+
+ wpabuf_put_buf(buf, ies);
+
+ return 0;
+}
static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
{
@@ -2267,10 +2328,8 @@
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
- struct ieee80211_mgmt *resp;
struct p2p_message msg;
struct wpabuf *ies;
- u8 channel, op_class;
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
@@ -2414,49 +2473,12 @@
return P2P_PREQ_NOT_PROCESSED;
}
- resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
- u.probe_resp.variable));
-
- resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
- (WLAN_FC_STYPE_PROBE_RESP << 4));
- os_memcpy(resp->da, addr, ETH_ALEN);
- os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
- os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
- resp->u.probe_resp.beacon_int = host_to_le16(100);
- /* hardware or low-level driver will setup seq_ctrl and timestamp */
- resp->u.probe_resp.capab_info =
- host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
- WLAN_CAPABILITY_PRIVACY |
- WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- wpabuf_put_u8(buf, WLAN_EID_SSID);
- wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
- wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
-
- wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
- wpabuf_put_u8(buf, 8);
- wpabuf_put_u8(buf, (60 / 5) | 0x80);
- wpabuf_put_u8(buf, 90 / 5);
- wpabuf_put_u8(buf, (120 / 5) | 0x80);
- wpabuf_put_u8(buf, 180 / 5);
- wpabuf_put_u8(buf, (240 / 5) | 0x80);
- wpabuf_put_u8(buf, 360 / 5);
- wpabuf_put_u8(buf, 480 / 5);
- wpabuf_put_u8(buf, 540 / 5);
-
- if (!rx_freq) {
- channel = p2p->cfg->channel;
- } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ if (p2p_build_probe_resp_buf(p2p, buf, ies, addr, rx_freq)) {
wpabuf_free(ies);
wpabuf_free(buf);
return P2P_PREQ_NOT_PROCESSED;
}
- wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
- wpabuf_put_u8(buf, 1);
- wpabuf_put_u8(buf, channel);
-
- wpabuf_put_buf(buf, ies);
wpabuf_free(ies);
p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
@@ -2470,12 +2492,18 @@
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq)
+ unsigned int rx_freq, int p2p_lo_started)
{
enum p2p_probe_req_status res;
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
+ if (p2p_lo_started) {
+ p2p_dbg(p2p,
+ "Probe Response is offloaded, do not reply Probe Request");
+ return P2P_PREQ_PROCESSED;
+ }
+
res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
return res;
@@ -2803,6 +2831,7 @@
}
p2p->p2ps_adv_list = NULL;
+ p2ps_prov_free(p2p);
p2p_dbg(p2p, "All ASP advertisements flushed");
}
@@ -2980,7 +3009,6 @@
os_free(p2p->groups);
p2ps_prov_free(p2p);
wpabuf_free(p2p->sd_resp);
- os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
p2p_service_flush_asp(p2p);
@@ -3004,6 +3032,10 @@
os_free(p2p->after_scan_tx);
p2p->after_scan_tx = NULL;
p2p->ssid_set = 0;
+ p2ps_prov_free(p2p);
+ p2p_reset_pending_pd(p2p);
+ p2p->override_pref_op_class = 0;
+ p2p->override_pref_channel = 0;
}
@@ -3782,6 +3814,8 @@
break;
case P2P_PENDING_INVITATION_RESPONSE:
p2p_invitation_resp_cb(p2p, success);
+ if (p2p->inv_status != P2P_SC_SUCCESS)
+ p2p_check_after_scan_tx_continuation(p2p);
break;
case P2P_PENDING_DEV_DISC_REQUEST:
p2p_dev_disc_req_cb(p2p, success);
@@ -5488,3 +5522,42 @@
i, p2p->pref_freq_list[i]);
}
}
+
+
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan)
+{
+ p2p->override_pref_op_class = op_class;
+ p2p->override_pref_channel = chan;
+}
+
+
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq)
+{
+ struct wpabuf *ies, *buf;
+ u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ int ret;
+
+ ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
+ if (!ies) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: Failed to build Probe Response IEs");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(200 + wpabuf_len(ies));
+ if (!buf) {
+ wpabuf_free(ies);
+ return NULL;
+ }
+
+ ret = p2p_build_probe_resp_buf(p2p, buf, ies, addr, freq);
+ wpabuf_free(ies);
+ if (ret) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 0feafd3..70d3a90 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1555,12 +1555,13 @@
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
* @rx_freq: Probe Request frame RX frequency
+ * @p2p_lo_started: Whether P2P Listen Offload is started
* Returns: value indicating the type and status of the probe request
*/
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
const u8 *bssid, const u8 *ie, size_t ie_len,
- unsigned int rx_freq);
+ unsigned int rx_freq, int p2p_lo_started);
/**
* p2p_rx_action - Report received Action frame
@@ -2133,6 +2134,16 @@
const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
/**
+ * p2p_group_get_client_interface_addr - Get P2P Interface Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @dev_addr: P2P Device Address of the client
+ * Returns: P2P Interface Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+ const u8 *dev_addr);
+
+/**
* p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
* @group: P2P group context from p2p_group_init()
* @addr: P2P Interface Address of the client
@@ -2274,7 +2285,7 @@
* discovery (p2p_find). A random number of 100 TU units is picked for each
* Listen state iteration from [min_disc_int,max_disc_int] range.
*
- * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * max_disc_tu can be used to further limit the discoverable duration. However,
* it should be noted that use of this parameter is not recommended since it
* would not be compliant with the P2P specification.
*/
@@ -2362,6 +2373,8 @@
void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
const unsigned int *pref_freq_list,
unsigned int size);
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan);
/**
* p2p_group_get_common_freqs - Get the group common frequencies
@@ -2373,4 +2386,7 @@
int p2p_group_get_common_freqs(struct p2p_group *group, int *common_freqs,
unsigned int *num);
+struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
+ unsigned int freq);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 793d28b..2882c6a 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -202,11 +202,11 @@
if (peer && peer->wps_method != WPS_NOT_READY) {
if (peer->wps_method == WPS_PBC)
methods |= WPS_CONFIG_PUSHBUTTON;
- else if (peer->wps_method == WPS_PIN_DISPLAY ||
- peer->wps_method == WPS_PIN_KEYPAD) {
- methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+ else if (peer->wps_method == WPS_P2PS)
methods |= WPS_CONFIG_P2PS;
- }
+ else if (peer->wps_method == WPS_PIN_DISPLAY ||
+ peer->wps_method == WPS_PIN_KEYPAD)
+ methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
} else if (p2p->cfg->config_methods) {
methods |= p2p->cfg->config_methods &
(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 9f0b3f3..65ab4b8 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -315,7 +315,12 @@
group_capab);
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
- if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
+ if (p2p->override_pref_op_class) {
+ p2p_dbg(p2p, "Override operating channel preference");
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->override_pref_op_class,
+ p2p->override_pref_channel);
+ } else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
@@ -562,26 +567,11 @@
* also supported by the peer device.
*/
for (i = 0; i < size && !found; i++) {
- /*
- * Make sure that the common frequency is:
- * 1. Supported by peer
- * 2. Allowed for P2P use.
- */
+ /* Make sure that the common frequency is supported by peer. */
oper_freq = freq_list[i];
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz", oper_freq);
- continue;
- }
- if (!p2p_channels_includes(&p2p->cfg->channels,
- op_class, op_channel) &&
- (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
- op_class, op_channel))) {
- p2p_dbg(p2p,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen due to earlier check */
for (j = 0; j < msg->channel_list_len; j++) {
if (op_channel != msg->channel_list[j])
@@ -602,8 +592,7 @@
oper_freq);
} else {
p2p_dbg(p2p,
- "None of our preferred channels are supported by peer!. Use: %d MHz for oper_channel",
- dev->oper_freq);
+ "None of our preferred channels are supported by peer!");
}
}
@@ -629,29 +618,9 @@
msg->pref_freq_list[2 * j + 1]);
if (freq_list[i] != oper_freq)
continue;
-
- /*
- * Make sure that the found frequency is:
- * 1. Supported
- * 2. Allowed for P2P use.
- */
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz",
- oper_freq);
- continue;
- }
-
- if (!p2p_channels_includes(&p2p->cfg->channels,
- op_class, op_channel) &&
- (go ||
- !p2p_channels_includes(&p2p->cfg->cli_channels,
- op_class, op_channel))) {
- p2p_dbg(p2p,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen */
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -666,9 +635,7 @@
"Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel",
oper_freq);
} else {
- p2p_dbg(p2p,
- "No common preferred channels found! Use: %d MHz for oper_channel",
- dev->oper_freq);
+ p2p_dbg(p2p, "No common preferred channels found!");
}
}
@@ -679,6 +646,8 @@
unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
unsigned int i;
u8 op_class, op_channel;
+ char txt[100], *pos, *end;
+ int res;
/*
* Use the preferred channel list from the driver only if there is no
@@ -694,6 +663,39 @@
if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
freq_list))
return;
+ /* Filter out frequencies that are not acceptable for P2P use */
+ i = 0;
+ while (i < size) {
+ if (p2p_freq_to_channel(freq_list[i], &op_class,
+ &op_channel) < 0 ||
+ (!p2p_channels_includes(&p2p->cfg->channels,
+ op_class, op_channel) &&
+ (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
+ op_class, op_channel)))) {
+ p2p_dbg(p2p,
+ "Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
+ freq_list[i], go);
+ if (size - i - 1 > 0)
+ os_memmove(&freq_list[i], &freq_list[i + 1], size - i - 1);
+ size--;
+ continue;
+ }
+
+ /* Preferred frequency is acceptable for P2P use */
+ i++;
+ }
+
+ pos = txt;
+ end = pos + sizeof(txt);
+ for (i = 0; i < size; i++) {
+ res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
+ p2p_dbg(p2p, "Local driver frequency preference (size=%u):%s",
+ size, txt);
/*
* Check if peer's preference of operating channel is in
@@ -703,20 +705,14 @@
if (freq_list[i] == (unsigned int) dev->oper_freq)
break;
}
- if (i != size) {
+ if (i != size &&
+ p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
/* Peer operating channel preference matches our preference */
- if (p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) <
- 0) {
- p2p_dbg(p2p,
- "Peer operating channel preference is unsupported frequency %u MHz",
- freq_list[i]);
- } else {
- p2p->op_reg_class = op_class;
- p2p->op_channel = op_channel;
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- return;
- }
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ os_memcpy(&p2p->channels, &p2p->cfg->channels,
+ sizeof(struct p2p_channels));
+ return;
}
p2p_dbg(p2p,
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index eac73ef..051b4e3 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -850,6 +850,20 @@
}
+const u8 * p2p_group_get_client_interface_addr(struct p2p_group *group,
+ const u8 *dev_addr)
+{
+ struct p2p_group_member *m;
+
+ if (!group)
+ return NULL;
+ m = p2p_group_get_client(group, dev_addr);
+ if (m)
+ return m->addr;
+ return NULL;
+}
+
+
static struct p2p_group_member * p2p_group_get_client_iface(
struct p2p_group *group, const u8 *interface_addr)
{
@@ -1098,7 +1112,7 @@
struct p2p_device *dev;
dev = p2p_get_device(group->p2p, m->dev_addr);
- if (!dev)
+ if (!dev || dev->channels.reg_classes == 0)
continue;
p2p_channels_intersect(&intersect, &dev->channels, &res);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 47524d4..ce69932 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -553,6 +553,10 @@
unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
unsigned int num_pref_freq;
+
+ /* Override option for preferred operating channel in GO Negotiation */
+ u8 override_pref_op_class;
+ u8 override_pref_channel;
};
/**
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 93a0535..3994ec0 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -1163,6 +1163,9 @@
msg.group_id, msg.group_id_len);
}
+ if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
+ p2ps_prov_free(p2p);
+
if (reject == P2P_SC_SUCCESS) {
switch (config_methods) {
case WPS_CONFIG_DISPLAY:
@@ -1581,7 +1584,7 @@
report_config_methods);
if (p2p->state == P2P_PD_DURING_FIND) {
- p2p_clear_timeout(p2p);
+ p2p_stop_listen_for_freq(p2p, 0);
p2p_continue_find(p2p);
}
}
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index a8bc5ba..d2fb4b5 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -426,6 +426,7 @@
{
struct wpabuf *resp;
size_t max_len;
+ unsigned int wait_time = 200;
/*
* In the 60 GHz, we have a smaller maximum frame length for management
@@ -460,6 +461,7 @@
1, p2p->srv_update_indic, NULL);
} else {
p2p_dbg(p2p, "SD response fits in initial response");
+ wait_time = 0; /* no more SD frames in the sequence */
resp = p2p_build_sd_response(dialog_token,
WLAN_STATUS_SUCCESS, 0,
p2p->srv_update_indic, resp_tlvs);
@@ -470,7 +472,7 @@
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
+ wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
p2p_dbg(p2p, "Failed to send Action frame");
wpabuf_free(resp);
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index cf43c59..360fcd3 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -20,7 +20,7 @@
#define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
#define STATE_MACHINE_DEBUG_PREFIX "CP"
-static u8 default_cs_id[] = CS_ID_GCM_AES_128;
+static u64 default_cs_id = CS_ID_GCM_AES_128;
/* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
@@ -45,7 +45,7 @@
Boolean elected_self;
u8 *authorization_data1;
enum confidentiality_offset cipher_offset;
- u8 *cipher_suite;
+ u64 cipher_suite;
Boolean new_sak; /* clear by CP */
struct ieee802_1x_mka_ki distributed_ki;
u8 distributed_an;
@@ -71,7 +71,7 @@
Boolean replay_protect;
u32 replay_window;
- u8 *current_cipher_suite;
+ u64 current_cipher_suite;
enum confidentiality_offset confidentiality_offset;
Boolean controlled_port_enabled;
@@ -97,8 +97,7 @@
static int changed_cipher(struct ieee802_1x_cp_sm *sm)
{
return sm->confidentiality_offset != sm->cipher_offset ||
- os_memcmp(sm->current_cipher_suite, sm->cipher_suite,
- CS_ID_LEN) != 0;
+ sm->current_cipher_suite != sm->cipher_suite;
}
@@ -160,6 +159,7 @@
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -178,6 +178,7 @@
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -185,21 +186,17 @@
SM_STATE(CP, SECURED)
{
- struct ieee802_1x_cp_conf conf;
-
SM_ENTRY(CP, SECURED);
sm->chgd_server = FALSE;
- ieee802_1x_kay_cp_conf(sm->kay, &conf);
- sm->protect_frames = conf.protect;
- sm->replay_protect = conf.replay_protect;
- sm->validate_frames = conf.validate;
+ sm->protect_frames = sm->kay->macsec_protect;
+ sm->replay_protect = sm->kay->macsec_replay_protect;
+ sm->validate_frames = sm->kay->macsec_validate;
- /* NOTE: now no other than default cipher suiter(AES-GCM-128) */
- os_memcpy(sm->current_cipher_suite, sm->cipher_suite, CS_ID_LEN);
- secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite,
- CS_ID_LEN);
+ /* NOTE: now no other than default cipher suite (AES-GCM-128) */
+ sm->current_cipher_suite = sm->cipher_suite;
+ secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
sm->confidentiality_offset = sm->cipher_offset;
@@ -208,6 +205,7 @@
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
}
@@ -428,9 +426,7 @@
/**
* ieee802_1x_cp_sm_init -
*/
-struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(
- struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pcp_conf)
+struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
{
struct ieee802_1x_cp_sm *sm;
@@ -446,10 +442,10 @@
sm->chgd_server = FALSE;
- sm->protect_frames = pcp_conf->protect;
- sm->validate_frames = pcp_conf->validate;
- sm->replay_protect = pcp_conf->replay_protect;
- sm->replay_window = pcp_conf->replay_window;
+ sm->protect_frames = kay->macsec_protect;
+ sm->validate_frames = kay->macsec_validate;
+ sm->replay_protect = kay->macsec_replay_protect;
+ sm->replay_window = kay->macsec_replay_window;
sm->controlled_port_enabled = FALSE;
@@ -460,17 +456,8 @@
sm->orx = FALSE;
sm->otx = FALSE;
- sm->cipher_suite = os_zalloc(CS_ID_LEN);
- sm->current_cipher_suite = os_zalloc(CS_ID_LEN);
- if (!sm->cipher_suite || !sm->current_cipher_suite) {
- wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
- os_free(sm->cipher_suite);
- os_free(sm->current_cipher_suite);
- os_free(sm);
- return NULL;
- }
- os_memcpy(sm->current_cipher_suite, default_cs_id, CS_ID_LEN);
- os_memcpy(sm->cipher_suite, default_cs_id, CS_ID_LEN);
+ sm->current_cipher_suite = default_cs_id;
+ sm->cipher_suite = default_cs_id;
sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
sm->confidentiality_offset = sm->cipher_offset;
sm->transmit_delay = MKA_LIFE_TIME;
@@ -482,6 +469,7 @@
wpa_printf(MSG_DEBUG, "CP: state machine created");
secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
+ secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
@@ -530,8 +518,6 @@
eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
os_free(sm->lki);
os_free(sm->oki);
- os_free(sm->cipher_suite);
- os_free(sm->current_cipher_suite);
os_free(sm->authorization_data);
os_free(sm);
}
@@ -618,10 +604,10 @@
/**
* ieee802_1x_cp_set_ciphersuite -
*/
-void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid)
+void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs)
{
struct ieee802_1x_cp_sm *sm = cp_ctx;
- os_memcpy(sm->cipher_suite, pid, CS_ID_LEN);
+ sm->cipher_suite = cs;
}
diff --git a/src/pae/ieee802_1x_cp.h b/src/pae/ieee802_1x_cp.h
index 773c930..695629e 100644
--- a/src/pae/ieee802_1x_cp.h
+++ b/src/pae/ieee802_1x_cp.h
@@ -16,17 +16,7 @@
struct ieee802_1x_kay;
struct ieee802_1x_mka_ki;
-struct ieee802_1x_cp_conf {
- Boolean protect;
- Boolean replay_protect;
- enum validate_frames validate;
- u32 replay_window;
-};
-
-
-struct ieee802_1x_cp_sm *
-ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pcp_conf);
+struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay);
void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm);
void ieee802_1x_cp_sm_step(void *cp_ctx);
void ieee802_1x_cp_connect_pending(void *cp_ctx);
@@ -36,7 +26,7 @@
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, void *pid);
+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);
void ieee802_1x_cp_set_distributedki(void *cp_ctx,
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index ef74430..3f9e53d 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -29,6 +29,8 @@
#define PENDING_PN_EXHAUSTION 0xC0000000
+#define MKA_ALIGN_LENGTH(len) (((len) + 0x3) & ~0x3)
+
/* IEEE Std 802.1X-2010, Table 9-1 - MKA Algorithm Agility */
#define MKA_ALGO_AGILITY_2009 { 0x00, 0x80, 0xC2, 0x01 }
static u8 mka_algo_agility[4] = MKA_ALGO_AGILITY_2009;
@@ -37,12 +39,11 @@
static struct macsec_ciphersuite cipher_suite_tbl[] = {
/* GCM-AES-128 */
{
- CS_ID_GCM_AES_128,
- CS_NAME_GCM_AES_128,
- MACSEC_CAP_INTEG_AND_CONF_0_30_50,
- 16,
-
- 0 /* index */
+ .id = CS_ID_GCM_AES_128,
+ .name = CS_NAME_GCM_AES_128,
+ .capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50,
+ .sak_len = DEFAULT_SA_KEY_LEN,
+ .index = 0,
},
};
#define CS_TABLE_SIZE (ARRAY_SIZE(cipher_suite_tbl))
@@ -50,16 +51,21 @@
static struct mka_alg mka_alg_tbl[] = {
{
- MKA_ALGO_AGILITY_2009,
- /* 128-bit CAK, KEK, ICK, ICV */
- 16, 16, 16, 16,
- ieee802_1x_cak_128bits_aes_cmac,
- ieee802_1x_ckn_128bits_aes_cmac,
- ieee802_1x_kek_128bits_aes_cmac,
- ieee802_1x_ick_128bits_aes_cmac,
- ieee802_1x_icv_128bits_aes_cmac,
+ .parameter = MKA_ALGO_AGILITY_2009,
- 1, /* index */
+ /* 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,
},
};
#define MKA_ALG_TABLE_SIZE (ARRAY_SIZE(mka_alg_tbl))
@@ -73,16 +79,6 @@
}
-struct mka_param_body_handler {
- int (*body_tx)(struct ieee802_1x_mka_participant *participant,
- struct wpabuf *buf);
- int (*body_rx)(struct ieee802_1x_mka_participant *participant,
- const u8 *mka_msg, size_t msg_len);
- int (*body_length)(struct ieee802_1x_mka_participant *participant);
- Boolean (*body_present)(struct ieee802_1x_mka_participant *participant);
-};
-
-
static void set_mka_param_body_len(void *body, unsigned int len)
{
struct ieee802_1x_mka_hdr *hdr = body;
@@ -98,7 +94,7 @@
}
-static int get_mka_param_body_type(const void *body)
+static u8 get_mka_param_body_type(const void *body)
{
const struct ieee802_1x_mka_hdr *hdr = body;
return hdr->type;
@@ -122,8 +118,8 @@
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_capbility);
- wpa_printf(MSG_DEBUG, "\tBody Length...: %d", (int) body_len);
+ 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",
@@ -148,7 +144,7 @@
size_t body_len;
size_t i;
u8 *mi;
- u32 mn;
+ be32 mn;
if (body == NULL)
return;
@@ -156,10 +152,10 @@
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...: %d", (int) body_len);
+ 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...: %d", (int) body_len);
+ wpa_printf(MSG_DEBUG, "\tBody Length...: %zu", body_len);
}
for (i = 0; i < body_len; i += MI_LEN + sizeof(mn)) {
@@ -187,7 +183,7 @@
wpa_printf(MSG_INFO, "\tDistributed AN........: %d", body->dan);
wpa_printf(MSG_INFO, "\tConfidentiality Offset: %d",
body->confid_offset);
- wpa_printf(MSG_INFO, "\tBody Length...........: %d", (int) body_len);
+ wpa_printf(MSG_INFO, "\tBody Length...........: %zu", body_len);
if (!body_len)
return;
@@ -280,7 +276,7 @@
return participant;
}
- wpa_printf(MSG_DEBUG, "KaY: principal participant is not founded");
+ wpa_printf(MSG_DEBUG, "KaY: principal participant is not found");
return NULL;
}
@@ -300,52 +296,12 @@
/**
- * ieee802_1x_kay_is_in_potential_peer
- */
-static Boolean
-ieee802_1x_kay_is_in_potential_peer(
- struct ieee802_1x_mka_participant *participant, const u8 *mi)
-{
- return get_peer_mi(&participant->potential_peers, mi) != NULL;
-}
-
-
-/**
- * ieee802_1x_kay_is_in_live_peer
- */
-static Boolean
-ieee802_1x_kay_is_in_live_peer(
- struct ieee802_1x_mka_participant *participant, const u8 *mi)
-{
- return get_peer_mi(&participant->live_peers, mi) != NULL;
-}
-
-
-/**
- * ieee802_1x_kay_is_in_peer
- */
-static Boolean
-ieee802_1x_kay_is_in_peer(struct ieee802_1x_mka_participant *participant,
- const u8 *mi)
-{
- return ieee802_1x_kay_is_in_live_peer(participant, mi) ||
- ieee802_1x_kay_is_in_potential_peer(participant, mi);
-}
-
-
-/**
- * ieee802_1x_kay_get_peer
+ * ieee802_1x_kay_get_potential_peer
*/
static struct ieee802_1x_kay_peer *
-ieee802_1x_kay_get_peer(struct ieee802_1x_mka_participant *participant,
- const u8 *mi)
+ieee802_1x_kay_get_potential_peer(
+ struct ieee802_1x_mka_participant *participant, const u8 *mi)
{
- struct ieee802_1x_kay_peer *peer;
-
- peer = get_peer_mi(&participant->live_peers, mi);
- if (peer)
- return peer;
-
return get_peer_mi(&participant->potential_peers, mi);
}
@@ -362,22 +318,82 @@
/**
+ * ieee802_1x_kay_is_in_potential_peer
+ */
+static Boolean
+ieee802_1x_kay_is_in_potential_peer(
+ struct ieee802_1x_mka_participant *participant, const u8 *mi)
+{
+ return ieee802_1x_kay_get_potential_peer(participant, mi) != NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_is_in_live_peer
+ */
+static Boolean
+ieee802_1x_kay_is_in_live_peer(
+ struct ieee802_1x_mka_participant *participant, const u8 *mi)
+{
+ return ieee802_1x_kay_get_live_peer(participant, mi) != NULL;
+}
+
+
+/**
+ * ieee802_1x_kay_get_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_get_peer(struct ieee802_1x_mka_participant *participant,
+ const u8 *mi)
+{
+ struct ieee802_1x_kay_peer *peer;
+
+ peer = ieee802_1x_kay_get_live_peer(participant, mi);
+ if (peer)
+ return peer;
+
+ return ieee802_1x_kay_get_potential_peer(participant, mi);
+}
+
+
+/**
* ieee802_1x_kay_get_cipher_suite
*/
static struct macsec_ciphersuite *
ieee802_1x_kay_get_cipher_suite(struct ieee802_1x_mka_participant *participant,
- u8 *cs_id)
+ const u8 *cs_id)
{
unsigned int i;
+ u64 cs;
+ be64 _cs;
+
+ os_memcpy(&_cs, cs_id, CS_ID_LEN);
+ cs = be_to_host64(_cs);
for (i = 0; i < CS_TABLE_SIZE; i++) {
- if (os_memcmp(cipher_suite_tbl[i].id, cs_id, CS_ID_LEN) == 0)
- break;
+ if (cipher_suite_tbl[i].id == cs)
+ return &cipher_suite_tbl[i];
}
- if (i >= CS_TABLE_SIZE)
- return NULL;
- return &cipher_suite_tbl[i];
+ return NULL;
+}
+
+
+u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci)
+{
+ struct ieee802_1x_mka_sci tmp;
+
+ os_memcpy(tmp.addr, sci->addr, ETH_ALEN);
+ tmp.port = sci->port;
+
+ return *((u64 *) &tmp);
+}
+
+
+static Boolean sci_equal(const struct ieee802_1x_mka_sci *a,
+ const struct ieee802_1x_mka_sci *b)
+{
+ return os_memcmp(a, b, sizeof(struct ieee802_1x_mka_sci)) == 0;
}
@@ -392,13 +408,13 @@
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
- if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
+ if (sci_equal(&peer->sci, sci))
return peer;
}
dl_list_for_each(peer, &participant->potential_peers,
struct ieee802_1x_kay_peer, list) {
- if (os_memcmp(&peer->sci, sci, sizeof(peer->sci)) == 0)
+ if (sci_equal(&peer->sci, sci))
return peer;
}
@@ -406,6 +422,8 @@
}
+static void ieee802_1x_kay_use_data_key(struct data_key *pkey);
+
/**
* ieee802_1x_kay_init_receive_sa -
*/
@@ -424,6 +442,7 @@
return NULL;
}
+ ieee802_1x_kay_use_data_key(key);
psa->pkey = key;
psa->lowest_pn = lowest_pn;
psa->next_pn = lowest_pn;
@@ -435,22 +454,25 @@
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create receive SA(AN: %d lowest_pn: %u of SC(channel: %d)",
- (int) an, lowest_pn, psc->channel);
+ "KaY: Create receive SA(AN: %hhu lowest_pn: %u of SC",
+ an, lowest_pn);
return psa;
}
+static void ieee802_1x_kay_deinit_data_key(struct data_key *pkey);
+
/**
* ieee802_1x_kay_deinit_receive_sa -
*/
static void ieee802_1x_kay_deinit_receive_sa(struct receive_sa *psa)
{
+ ieee802_1x_kay_deinit_data_key(psa->pkey);
psa->pkey = NULL;
wpa_printf(MSG_DEBUG,
- "KaY: Delete receive SA(an: %d) of SC(channel: %d)",
- psa->an, psa->sc->channel);
+ "KaY: Delete receive SA(an: %hhu) of SC",
+ psa->an);
dl_list_del(&psa->list);
os_free(psa);
}
@@ -460,8 +482,7 @@
* ieee802_1x_kay_init_receive_sc -
*/
static struct receive_sc *
-ieee802_1x_kay_init_receive_sc(const struct ieee802_1x_mka_sci *psci,
- int channel)
+ieee802_1x_kay_init_receive_sc(const struct ieee802_1x_mka_sci *psci)
{
struct receive_sc *psc;
@@ -475,19 +496,27 @@
}
os_memcpy(&psc->sci, psci, sizeof(psc->sci));
- psc->channel = channel;
os_get_time(&psc->created_time);
psc->receiving = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create receive SC(channel: %d)", channel);
+ wpa_printf(MSG_DEBUG, "KaY: Create receive SC");
wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)psci, sizeof(*psci));
return psc;
}
+static void ieee802_1x_delete_receive_sa(struct ieee802_1x_kay *kay,
+ struct receive_sa *sa)
+{
+ secy_disable_receive_sa(kay, sa);
+ secy_delete_receive_sa(kay, sa);
+ ieee802_1x_kay_deinit_receive_sa(sa);
+}
+
+
/**
* ieee802_1x_kay_deinit_receive_sc -
**/
@@ -497,31 +526,32 @@
{
struct receive_sa *psa, *pre_sa;
- wpa_printf(MSG_DEBUG, "KaY: Delete receive SC(channel: %d)",
- psc->channel);
+ wpa_printf(MSG_DEBUG, "KaY: Delete receive SC");
dl_list_for_each_safe(psa, pre_sa, &psc->sa_list, struct receive_sa,
- list) {
- secy_disable_receive_sa(participant->kay, psa);
- ieee802_1x_kay_deinit_receive_sa(psa);
- }
+ list)
+ ieee802_1x_delete_receive_sa(participant->kay, psa);
+
dl_list_del(&psc->list);
os_free(psc);
}
-/**
- * ieee802_1x_kay_create_live_peer
- */
+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);
+}
+
+
static struct ieee802_1x_kay_peer *
-ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
- u8 *mi, u32 mn)
+ieee802_1x_kay_create_peer(const u8 *mi, u32 mn)
{
struct ieee802_1x_kay_peer *peer;
- struct receive_sc *rxsc;
- u32 sc_ch = 0;
peer = os_zalloc(sizeof(*peer));
- if (peer == NULL) {
+ if (!peer) {
wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
return NULL;
}
@@ -530,24 +560,40 @@
peer->mn = mn;
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
peer->sak_used = FALSE;
- os_memcpy(&peer->sci, &participant->current_peer_sci,
- sizeof(peer->sci));
- dl_list_add(&participant->live_peers, &peer->list);
- secy_get_available_receive_sc(participant->kay, &sc_ch);
+ return peer;
+}
- rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
- if (!rxsc)
+
+/**
+ * ieee802_1x_kay_create_live_peer
+ */
+static struct ieee802_1x_kay_peer *
+ieee802_1x_kay_create_live_peer(struct ieee802_1x_mka_participant *participant,
+ const u8 *mi, u32 mn)
+{
+ struct ieee802_1x_kay_peer *peer;
+ struct receive_sc *rxsc;
+
+ peer = ieee802_1x_kay_create_peer(mi, mn);
+ if (!peer)
return NULL;
+ os_memcpy(&peer->sci, &participant->current_peer_sci,
+ sizeof(peer->sci));
+
+ rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci);
+ if (!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");
- 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);
+ ieee802_1x_kay_dump_peer(peer);
return peer;
}
@@ -562,24 +608,14 @@
{
struct ieee802_1x_kay_peer *peer;
- peer = os_zalloc(sizeof(*peer));
- if (peer == NULL) {
- wpa_printf(MSG_ERROR, "KaY-%s: out of memory", __func__);
+ peer = ieee802_1x_kay_create_peer(mi, mn);
+ if (!peer)
return NULL;
- }
-
- os_memcpy(peer->mi, mi, MI_LEN);
- peer->mn = mn;
- peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
- peer->sak_used = FALSE;
dl_list_add(&participant->potential_peers, &peer->list);
wpa_printf(MSG_DEBUG, "KaY: potential peer created");
- 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);
+ ieee802_1x_kay_dump_peer(peer);
return peer;
}
@@ -594,13 +630,12 @@
{
struct ieee802_1x_kay_peer *peer;
struct receive_sc *rxsc;
- u32 sc_ch = 0;
- dl_list_for_each(peer, &participant->potential_peers,
- struct ieee802_1x_kay_peer, list) {
- if (os_memcmp(peer->mi, mi, MI_LEN) == 0)
- break;
- }
+ peer = ieee802_1x_kay_get_potential_peer(participant, mi);
+
+ rxsc = ieee802_1x_kay_init_receive_sc(&participant->current_peer_sci);
+ if (!rxsc)
+ return NULL;
os_memcpy(&peer->sci, &participant->current_peer_sci,
sizeof(peer->sci));
@@ -608,20 +643,11 @@
peer->expire = time(NULL) + MKA_LIFE_TIME / 1000;
wpa_printf(MSG_DEBUG, "KaY: move potential peer to live 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);
+ ieee802_1x_kay_dump_peer(peer);
dl_list_del(&peer->list);
dl_list_add_tail(&participant->live_peers, &peer->list);
- secy_get_available_receive_sc(participant->kay, &sc_ch);
-
- rxsc = ieee802_1x_kay_init_receive_sc(&peer->sci, sc_ch);
- if (!rxsc)
- return NULL;
-
dl_list_add(&participant->rxsc_list, &rxsc->list);
secy_create_receive_sc(participant->kay, rxsc);
@@ -651,7 +677,7 @@
length = sizeof(struct ieee802_1x_mka_basic_body);
length += participant->ckn.len;
- return (length + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(length);
}
@@ -677,17 +703,17 @@
body->key_server = participant->can_be_key_server;
body->macsec_desired = kay->macsec_desired;
- body->macsec_capbility = kay->macsec_capable;
+ body->macsec_capability = kay->macsec_capable;
set_mka_param_body_len(body, length - MKA_HDR_LEN);
os_memcpy(body->actor_sci.addr, kay->actor_sci.addr,
sizeof(kay->actor_sci.addr));
- body->actor_sci.port = host_to_be16(kay->actor_sci.port);
+ body->actor_sci.port = kay->actor_sci.port;
os_memcpy(body->actor_mi, participant->mi, sizeof(body->actor_mi));
participant->mn = participant->mn + 1;
body->actor_mn = host_to_be32(participant->mn);
- os_memcpy(body->algo_agility, participant->kay->algo_agility,
+ os_memcpy(body->algo_agility, kay->algo_agility,
sizeof(body->algo_agility));
os_memcpy(body->ckn, participant->ckn.name, participant->ckn.len);
@@ -698,6 +724,17 @@
}
+static Boolean
+reset_participant_mi(struct ieee802_1x_mka_participant *participant)
+{
+ if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ return FALSE;
+ participant->mn = 0;
+
+ return TRUE;
+}
+
+
/**
* ieee802_1x_mka_decode_basic_body -
*/
@@ -729,16 +766,15 @@
/* If the peer's MI is my MI, I will choose new MI */
if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
- if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ if (!reset_participant_mi(participant))
return NULL;
- participant->mn = 0;
}
os_memcpy(participant->current_peer_id.mi, body->actor_mi, MI_LEN);
- participant->current_peer_id.mn = be_to_host32(body->actor_mn);
+ participant->current_peer_id.mn = body->actor_mn;
os_memcpy(participant->current_peer_sci.addr, body->actor_sci.addr,
sizeof(participant->current_peer_sci.addr));
- participant->current_peer_sci.port = be_to_host16(body->actor_sci.port);
+ participant->current_peer_sci.port = body->actor_sci.port;
/* handler peer */
peer = ieee802_1x_kay_get_peer(participant, body->actor_mi);
@@ -763,14 +799,14 @@
return NULL;
peer->macsec_desired = body->macsec_desired;
- peer->macsec_capbility = body->macsec_capbility;
+ peer->macsec_capability = body->macsec_capability;
peer->is_key_server = (Boolean) body->key_server;
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_capbility = body->macsec_capbility;
+ peer->macsec_capability = body->macsec_capability;
peer->is_key_server = (Boolean) body->key_server;
peer->key_server_priority = body->priority;
} else {
@@ -807,7 +843,7 @@
struct ieee802_1x_kay_peer, list)
len += sizeof(struct ieee802_1x_mka_peer_id);
- return (len + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(len);
}
@@ -836,7 +872,6 @@
sizeof(struct ieee802_1x_mka_peer_id));
os_memcpy(body_peer->mi, peer->mi, MI_LEN);
body_peer->mn = host_to_be32(peer->mn);
- body_peer++;
}
ieee802_1x_mka_dump_peer_body(body);
@@ -868,7 +903,7 @@
struct ieee802_1x_kay_peer, list)
len += sizeof(struct ieee802_1x_mka_peer_id);
- return (len + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(len);
}
@@ -897,7 +932,6 @@
sizeof(struct ieee802_1x_mka_peer_id));
os_memcpy(body_peer->mi, peer->mi, MI_LEN);
body_peer->mn = host_to_be32(peer->mn);
- body_peer++;
}
ieee802_1x_mka_dump_peer_body(body);
@@ -912,62 +946,54 @@
ieee802_1x_mka_i_in_peerlist(struct ieee802_1x_mka_participant *participant,
const u8 *mka_msg, size_t msg_len)
{
- Boolean included = FALSE;
struct ieee802_1x_mka_hdr *hdr;
size_t body_len;
size_t left_len;
- int body_type;
- u32 peer_mn;
- const u8 *peer_mi;
+ u8 body_type;
const u8 *pos;
size_t i;
- pos = mka_msg;
- left_len = msg_len;
- while (left_len > (MKA_HDR_LEN + DEFAULT_ICV_LEN)) {
+ 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) {
hdr = (struct ieee802_1x_mka_hdr *) pos;
body_len = get_mka_param_body_len(hdr);
body_type = get_mka_param_body_type(hdr);
if (body_type != MKA_LIVE_PEER_LIST &&
body_type != MKA_POTENTIAL_PEER_LIST)
- goto SKIP_PEER;
+ continue;
ieee802_1x_mka_dump_peer_body(
(struct ieee802_1x_mka_peer_body *)pos);
if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
- (int) left_len, (int) MKA_HDR_LEN,
- (int) body_len, DEFAULT_ICV_LEN);
- goto SKIP_PEER;
+ "KaY: MKA Peer Packet Body Length (%zu bytes) is less than the Parameter Set Header Length (%zu bytes) + the Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+ left_len, MKA_HDR_LEN,
+ body_len, DEFAULT_ICV_LEN);
+ continue;
}
if ((body_len % 16) != 0) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Peer Packet Body Length (%d bytes) should multiple of 16 octets",
- (int) body_len);
- goto SKIP_PEER;
+ "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+ body_len);
+ continue;
}
- for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
- peer_mi = MKA_HDR_LEN + pos + i;
- os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
- peer_mn = be_to_host32(peer_mn);
- if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0 &&
- peer_mn == participant->mn) {
- included = TRUE;
- break;
- }
+ for (i = 0; i < body_len;
+ i += sizeof(struct ieee802_1x_mka_peer_id)) {
+ const struct ieee802_1x_mka_peer_id *peer_mi;
+
+ 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;
}
-
- if (included)
- return TRUE;
-
-SKIP_PEER:
- left_len -= body_len + MKA_HDR_LEN;
- pos += body_len + MKA_HDR_LEN;
}
return FALSE;
@@ -984,8 +1010,6 @@
const struct ieee802_1x_mka_hdr *hdr;
struct ieee802_1x_kay_peer *peer;
size_t body_len;
- u32 peer_mn;
- const u8 *peer_mi;
size_t i;
Boolean is_included;
@@ -994,36 +1018,40 @@
hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
body_len = get_mka_param_body_len(hdr);
+ if (body_len % 16 != 0) {
+ wpa_printf(MSG_ERROR,
+ "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+ body_len);
+ return -1;
+ }
- for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
- peer_mi = MKA_HDR_LEN + peer_msg + i;
- os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
- peer_mn = be_to_host32(peer_mn);
+ for (i = 0; i < body_len; i += sizeof(struct ieee802_1x_mka_peer_id)) {
+ const struct ieee802_1x_mka_peer_id *peer_mi;
+ u32 peer_mn;
+
+ peer_mi = (const struct ieee802_1x_mka_peer_id *)
+ (peer_msg + MKA_HDR_LEN + i);
+ peer_mn = be_to_host32(peer_mi->mn);
/* it is myself */
if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
/* My message id is used by other participant */
- if (peer_mn > participant->mn) {
- if (os_get_random(participant->mi,
- sizeof(participant->mi)) < 0)
- wpa_printf(MSG_DEBUG,
- "KaY: Could not update mi");
- participant->mn = 0;
- }
+ if (peer_mn > participant->mn &&
+ !reset_participant_mi(participant))
+ wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
continue;
}
+
if (!is_included)
continue;
- peer = ieee802_1x_kay_get_peer(participant, peer_mi);
- if (NULL != peer) {
+ 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, peer_mn)) {
- return -1;
- }
+ } else if (!ieee802_1x_kay_create_potential_peer(
+ participant, peer_mi->mi, peer_mn)) {
+ return -1;
}
}
@@ -1039,30 +1067,33 @@
struct ieee802_1x_mka_participant *participant,
const u8 *peer_msg, size_t msg_len)
{
- struct ieee802_1x_mka_hdr *hdr;
+ const struct ieee802_1x_mka_hdr *hdr;
size_t body_len;
- u32 peer_mn;
- const u8 *peer_mi;
size_t i;
- hdr = (struct ieee802_1x_mka_hdr *) peer_msg;
+ hdr = (const struct ieee802_1x_mka_hdr *) peer_msg;
body_len = get_mka_param_body_len(hdr);
+ if (body_len % 16 != 0) {
+ wpa_printf(MSG_ERROR,
+ "KaY: MKA Peer Packet Body Length (%zu bytes) should be a multiple of 16 octets",
+ body_len);
+ return -1;
+ }
- for (i = 0; i < body_len; i += MI_LEN + sizeof(peer_mn)) {
- peer_mi = MKA_HDR_LEN + peer_msg + i;
- os_memcpy(&peer_mn, peer_mi + MI_LEN, sizeof(peer_mn));
- peer_mn = be_to_host32(peer_mn);
+ for (i = 0; i < body_len; i += sizeof(struct ieee802_1x_mka_peer_id)) {
+ const struct ieee802_1x_mka_peer_id *peer_mi;
+ u32 peer_mn;
+
+ peer_mi = (struct ieee802_1x_mka_peer_id *)
+ (peer_msg + MKA_HDR_LEN + i);
+ peer_mn = be_to_host32(peer_mi->mn);
/* it is myself */
if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
/* My message id is used by other participant */
- if (peer_mn > participant->mn) {
- if (os_get_random(participant->mi,
- sizeof(participant->mi)) < 0)
- wpa_printf(MSG_DEBUG,
- "KaY: Could not update mi");
- participant->mn = 0;
- }
+ if (peer_mn > participant->mn &&
+ !reset_participant_mi(participant))
+ wpa_printf(MSG_DEBUG, "KaY: Could not update mi");
continue;
}
}
@@ -1078,10 +1109,7 @@
ieee802_1x_mka_sak_use_body_present(
struct ieee802_1x_mka_participant *participant)
{
- if (participant->to_use_sak)
- return TRUE;
- else
- return FALSE;
+ return participant->to_use_sak;
}
@@ -1096,12 +1124,8 @@
if (participant->kay->macsec_desired && participant->advised_desired)
length = sizeof(struct ieee802_1x_mka_sak_use_body);
- else
- length = MKA_HDR_LEN;
- length = (length + 0x3) & ~0x3;
-
- return length;
+ return MKA_ALIGN_LENGTH(length);
}
@@ -1146,11 +1170,12 @@
struct wpabuf *buf)
{
struct ieee802_1x_mka_sak_use_body *body;
+ struct ieee802_1x_kay *kay = participant->kay;
unsigned int length;
u32 pn = 1;
length = ieee802_1x_mka_get_sak_use_length(participant);
- body = wpabuf_put(buf, sizeof(struct ieee802_1x_mka_sak_use_body));
+ body = wpabuf_put(buf, length);
body->type = MKA_SAK_USE;
set_mka_param_body_len(body, length - MKA_HDR_LEN);
@@ -1166,9 +1191,9 @@
}
/* data protect, lowest accept packet number */
- body->delay_protect = participant->kay->macsec_replay_protect;
+ body->delay_protect = kay->macsec_replay_protect;
pn = ieee802_1x_mka_get_lpn(participant, &participant->lki);
- if (pn > participant->kay->pn_exhaustion) {
+ if (pn > kay->pn_exhaustion) {
wpa_printf(MSG_WARNING, "KaY: My LPN exhaustion");
if (participant->is_key_server)
participant->new_sak = TRUE;
@@ -1179,20 +1204,12 @@
body->olpn = host_to_be32(pn);
/* plain tx, plain rx */
- if (participant->kay->macsec_protect)
- body->ptx = FALSE;
- else
- body->ptx = TRUE;
-
- if (participant->kay->macsec_validate == Strict)
- body->prx = FALSE;
- else
- body->prx = TRUE;
+ body->ptx = !kay->macsec_protect;
+ body->prx = kay->macsec_validate != Strict;
/* latest key: rx, tx, key server member identifier key number */
body->lan = participant->lan;
- os_memcpy(body->lsrv_mi, participant->lki.mi,
- sizeof(body->lsrv_mi));
+ os_memcpy(body->lsrv_mi, participant->lki.mi, sizeof(body->lsrv_mi));
body->lkn = host_to_be32(participant->lki.kn);
body->lrx = participant->lrx;
body->ltx = participant->ltx;
@@ -1213,16 +1230,11 @@
/* set CP's variable */
if (body->ltx) {
- if (!participant->kay->tx_enable)
- participant->kay->tx_enable = TRUE;
-
- if (!participant->kay->port_enable)
- participant->kay->port_enable = TRUE;
+ kay->tx_enable = TRUE;
+ kay->port_enable = TRUE;
}
- if (body->lrx) {
- if (!participant->kay->rx_enable)
- participant->kay->rx_enable = TRUE;
- }
+ if (body->lrx)
+ kay->rx_enable = TRUE;
ieee802_1x_mka_dump_sak_use_body(body);
return 0;
@@ -1246,7 +1258,8 @@
struct ieee802_1x_mka_ki ki;
u32 lpn;
Boolean all_receiving;
- Boolean founded;
+ Boolean found;
+ struct ieee802_1x_kay *kay = participant->kay;
if (!participant->principal) {
wpa_printf(MSG_WARNING, "KaY: Participant is not principal");
@@ -1266,8 +1279,8 @@
if ((body_len != 0) && (body_len < 40)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 40, or more octets",
- (int) body_len);
+ "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 0, 40, or more octets",
+ body_len);
return -1;
}
@@ -1288,30 +1301,29 @@
/* check latest key is valid */
if (body->ltx || body->lrx) {
- founded = FALSE;
+ found = FALSE;
os_memcpy(ki.mi, body->lsrv_mi, sizeof(ki.mi));
- ki.kn = ntohl(body->lkn);
+ ki.kn = be_to_host32(body->lkn);
dl_list_for_each(sa_key, &participant->sak_list,
struct data_key, list) {
if (is_ki_equal(&sa_key->key_identifier, &ki)) {
- founded = TRUE;
+ found = TRUE;
break;
}
}
- if (!founded) {
+ if (!found) {
wpa_printf(MSG_WARNING, "KaY: Latest key is invalid");
return -1;
}
if (os_memcmp(participant->lki.mi, body->lsrv_mi,
sizeof(participant->lki.mi)) == 0 &&
- ntohl(body->lkn) == participant->lki.kn &&
+ be_to_host32(body->lkn) == participant->lki.kn &&
body->lan == participant->lan) {
peer->sak_used = TRUE;
}
if (body->ltx && peer->is_key_server) {
- ieee802_1x_cp_set_servertransmitting(
- participant->kay->cp, TRUE);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ ieee802_1x_cp_set_servertransmitting(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
}
}
@@ -1319,7 +1331,7 @@
if (body->otx || body->orx) {
if (os_memcmp(participant->oki.mi, body->osrv_mi,
sizeof(participant->oki.mi)) != 0 ||
- ntohl(body->okn) != participant->oki.kn ||
+ be_to_host32(body->okn) != participant->oki.kn ||
body->oan != participant->oan) {
wpa_printf(MSG_WARNING, "KaY: Old key is invalid");
return -1;
@@ -1327,7 +1339,8 @@
}
/* TODO: how to set the MACsec hardware when delay_protect is true */
- if (body->delay_protect && (!ntohl(body->llpn) || !ntohl(body->olpn))) {
+ 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");
return -1;
@@ -1344,28 +1357,28 @@
}
if (all_receiving) {
participant->to_dist_sak = FALSE;
- ieee802_1x_cp_set_allreceiving(participant->kay->cp, TRUE);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ ieee802_1x_cp_set_allreceiving(kay->cp, TRUE);
+ ieee802_1x_cp_sm_step(kay->cp);
}
/* if i'm key server, and detects peer member pn exhaustion, rekey.*/
- lpn = ntohl(body->llpn);
- if (lpn > participant->kay->pn_exhaustion) {
+ lpn = be_to_host32(body->llpn);
+ if (lpn > kay->pn_exhaustion) {
if (participant->is_key_server) {
participant->new_sak = TRUE;
wpa_printf(MSG_WARNING, "KaY: Peer LPN exhaustion");
}
}
- founded = FALSE;
+ found = FALSE;
dl_list_for_each(txsa, &participant->txsc->sa_list,
struct transmit_sa, list) {
if (sa_key != NULL && txsa->pkey == sa_key) {
- founded = TRUE;
+ found = TRUE;
break;
}
}
- if (!founded) {
+ if (!found) {
wpa_printf(MSG_WARNING, "KaY: Can't find txsa");
return -1;
}
@@ -1373,9 +1386,9 @@
/* 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(participant->kay, txsa);
+ secy_get_transmit_next_pn(kay, txsa);
if (lpn > txsa->next_pn) {
- secy_set_transmit_next_pn(participant->kay, txsa);
+ secy_set_transmit_next_pn(kay, txsa);
wpa_printf(MSG_INFO, "KaY: update lpn =0x%x", lpn);
}
@@ -1390,10 +1403,7 @@
ieee802_1x_mka_dist_sak_body_present(
struct ieee802_1x_mka_participant *participant)
{
- if (!participant->to_dist_sak || !participant->new_key)
- return FALSE;
-
- return TRUE;
+ return participant->to_dist_sak && participant->new_key;
}
@@ -1404,21 +1414,18 @@
ieee802_1x_mka_get_dist_sak_length(
struct ieee802_1x_mka_participant *participant)
{
- int length;
- int cs_index = participant->kay->macsec_csindex;
+ int length = MKA_HDR_LEN;
+ unsigned int cs_index = participant->kay->macsec_csindex;
- if (participant->advised_desired) {
+ if (participant->advised_desired && cs_index < CS_TABLE_SIZE) {
length = sizeof(struct ieee802_1x_mka_dist_sak_body);
if (cs_index != DEFAULT_CS_INDEX)
length += CS_ID_LEN;
length += cipher_suite_tbl[cs_index].sak_len + 8;
- } else {
- length = MKA_HDR_LEN;
}
- length = (length + 0x3) & ~0x3;
- return length;
+ return MKA_ALIGN_LENGTH(length);
}
@@ -1433,7 +1440,7 @@
struct ieee802_1x_mka_dist_sak_body *body;
struct data_key *sak;
unsigned int length;
- int cs_index;
+ unsigned int cs_index;
int sak_pos;
length = ieee802_1x_mka_get_dist_sak_length(participant);
@@ -1452,8 +1459,13 @@
body->kn = host_to_be32(sak->key_identifier.kn);
cs_index = participant->kay->macsec_csindex;
sak_pos = 0;
+ if (cs_index >= CS_TABLE_SIZE)
+ return -1;
if (cs_index != DEFAULT_CS_INDEX) {
- os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN);
+ be64 cs;
+
+ cs = host_to_be64(cipher_suite_tbl[cs_index].id);
+ os_memcpy(body->sak, &cs, CS_ID_LEN);
sak_pos = CS_ID_LEN;
}
if (aes_wrap(participant->kek.key, 16,
@@ -1472,39 +1484,13 @@
/**
* ieee802_1x_kay_init_data_key -
*/
-static struct data_key *
-ieee802_1x_kay_init_data_key(const struct key_conf *conf)
+static void ieee802_1x_kay_init_data_key(struct data_key *pkey)
{
- struct data_key *pkey;
-
- if (!conf)
- return NULL;
-
- pkey = os_zalloc(sizeof(*pkey));
- if (pkey == NULL) {
- wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
- return NULL;
- }
-
- pkey->key = os_zalloc(conf->key_len);
- if (pkey->key == NULL) {
- wpa_printf(MSG_ERROR, "%s: out of memory", __func__);
- os_free(pkey);
- return NULL;
- }
-
- os_memcpy(pkey->key, conf->key, conf->key_len);
- os_memcpy(&pkey->key_identifier, &conf->ki,
- sizeof(pkey->key_identifier));
- pkey->confidentiality_offset = conf->offset;
- pkey->an = conf->an;
- pkey->transmits = conf->tx;
- pkey->receives = conf->rx;
+ pkey->transmits = TRUE;
+ pkey->receives = TRUE;
os_get_time(&pkey->created_time);
pkey->user = 1;
-
- return pkey;
}
@@ -1521,19 +1507,18 @@
struct ieee802_1x_kay_peer *peer;
struct macsec_ciphersuite *cs;
size_t body_len;
- struct key_conf *conf;
struct data_key *sa_key = NULL;
- struct ieee802_1x_mka_ki sak_ki;
int sak_len;
u8 *wrap_sak;
u8 *unwrap_sak;
+ struct ieee802_1x_kay *kay = participant->kay;
hdr = (struct ieee802_1x_mka_hdr *) mka_msg;
body_len = get_mka_param_body_len(hdr);
if ((body_len != 0) && (body_len != 28) && (body_len < 36)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 0, 28, 36, or more octets",
- (int) body_len);
+ "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 0, 28, 36, or more octets",
+ body_len);
return -1;
}
@@ -1547,8 +1532,8 @@
"KaY: I can't accept the distributed SAK as myself is key server ");
return -1;
}
- if (!participant->kay->macsec_desired ||
- participant->kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
+ if (!kay->macsec_desired ||
+ kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
wpa_printf(MSG_ERROR,
"KaY: I am not MACsec-desired or without MACsec capable");
return -1;
@@ -1561,28 +1546,29 @@
"KaY: The key server is not in my live peers list");
return -1;
}
- if (os_memcmp(&participant->kay->key_server_sci,
- &peer->sci, sizeof(struct ieee802_1x_mka_sci)) != 0) {
+ if (!sci_equal(&kay->key_server_sci, &peer->sci)) {
wpa_printf(MSG_ERROR, "KaY: The key server is not elected");
return -1;
}
+
if (body_len == 0) {
- participant->kay->authenticated = TRUE;
- participant->kay->secured = FALSE;
- participant->kay->failed = FALSE;
+ kay->authenticated = TRUE;
+ kay->secured = FALSE;
+ kay->failed = FALSE;
participant->advised_desired = FALSE;
- ieee802_1x_cp_connect_authenticated(participant->kay->cp);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ 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");
- participant->to_use_sak = TRUE;
+ participant->to_use_sak = FALSE;
return 0;
}
+
participant->advised_desired = TRUE;
- participant->kay->authenticated = FALSE;
- participant->kay->secured = TRUE;
- participant->kay->failed = FALSE;
- ieee802_1x_cp_connect_secure(participant->kay->cp);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ kay->authenticated = FALSE;
+ kay->secured = TRUE;
+ kay->failed = FALSE;
+ ieee802_1x_cp_connect_secure(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
body = (struct ieee802_1x_mka_dist_sak_body *)mka_msg;
ieee802_1x_mka_dump_dist_sak_body(body);
@@ -1595,10 +1581,12 @@
return 0;
}
}
+
if (body_len == 28) {
sak_len = DEFAULT_SA_KEY_LEN;
wrap_sak = body->sak;
- participant->kay->macsec_csindex = DEFAULT_CS_INDEX;
+ kay->macsec_csindex = DEFAULT_CS_INDEX;
+ cs = &cipher_suite_tbl[kay->macsec_csindex];
} else {
cs = ieee802_1x_kay_get_cipher_suite(participant, body->sak);
if (!cs) {
@@ -1608,7 +1596,7 @@
}
sak_len = cs->sak_len;
wrap_sak = body->sak + CS_ID_LEN;
- participant->kay->macsec_csindex = cs->index;
+ kay->macsec_csindex = cs->index;
}
unwrap_sak = os_zalloc(sak_len);
@@ -1624,62 +1612,38 @@
}
wpa_hexdump(MSG_DEBUG, "\tAES Key Unwrap of SAK:", unwrap_sak, sak_len);
- conf = os_zalloc(sizeof(*conf));
- if (!conf) {
- wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
- os_free(unwrap_sak);
- return -1;
- }
- conf->key_len = sak_len;
-
- conf->key = os_zalloc(conf->key_len);
- if (!conf->key) {
- wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
- os_free(unwrap_sak);
- os_free(conf);
- return -1;
- }
-
- os_memcpy(conf->key, unwrap_sak, conf->key_len);
-
- os_memcpy(&sak_ki.mi, &participant->current_peer_id.mi,
- sizeof(sak_ki.mi));
- sak_ki.kn = be_to_host32(body->kn);
-
- os_memcpy(conf->ki.mi, sak_ki.mi, MI_LEN);
- conf->ki.kn = sak_ki.kn;
- conf->an = body->dan;
- conf->offset = body->confid_offset;
- conf->rx = TRUE;
- conf->tx = TRUE;
-
- sa_key = ieee802_1x_kay_init_data_key(conf);
+ sa_key = os_zalloc(sizeof(*sa_key));
if (!sa_key) {
os_free(unwrap_sak);
- os_free(conf->key);
- os_free(conf);
return -1;
}
+ os_memcpy(&sa_key->key_identifier.mi, &participant->current_peer_id.mi,
+ MI_LEN);
+ sa_key->key_identifier.kn = be_to_host32(body->kn);
+
+ sa_key->key = unwrap_sak;
+ sa_key->key_len = sak_len;
+
+ sa_key->confidentiality_offset = body->confid_offset;
+ sa_key->an = body->dan;
+ ieee802_1x_kay_init_data_key(sa_key);
+
+ ieee802_1x_kay_use_data_key(sa_key);
dl_list_add(&participant->sak_list, &sa_key->list);
- ieee802_1x_cp_set_ciphersuite(
- participant->kay->cp,
- cipher_suite_tbl[participant->kay->macsec_csindex].id);
- ieee802_1x_cp_sm_step(participant->kay->cp);
- ieee802_1x_cp_set_offset(participant->kay->cp, body->confid_offset);
- ieee802_1x_cp_sm_step(participant->kay->cp);
- ieee802_1x_cp_set_distributedki(participant->kay->cp, &sak_ki);
- ieee802_1x_cp_set_distributedan(participant->kay->cp, body->dan);
- ieee802_1x_cp_signal_newsak(participant->kay->cp);
- ieee802_1x_cp_sm_step(participant->kay->cp);
+ ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
+ ieee802_1x_cp_sm_step(kay->cp);
+ ieee802_1x_cp_set_offset(kay->cp, body->confid_offset);
+ ieee802_1x_cp_sm_step(kay->cp);
+ ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
+ ieee802_1x_cp_set_distributedan(kay->cp, body->dan);
+ ieee802_1x_cp_signal_newsak(kay->cp);
+ ieee802_1x_cp_sm_step(kay->cp);
+ kay->rcvd_keys++;
participant->to_use_sak = TRUE;
- os_free(unwrap_sak);
- os_free(conf->key);
- os_free(conf);
-
return 0;
}
@@ -1705,7 +1669,7 @@
length = sizeof(struct ieee802_1x_mka_icv_body);
length += mka_alg_tbl[participant->kay->mka_algindex].icv_len;
- return (length + 0x3) & ~0x3;
+ return MKA_ALIGN_LENGTH(length);
}
@@ -1733,12 +1697,9 @@
return -1;
}
- if (length != DEFAULT_ICV_LEN) {
- os_memcpy(wpabuf_put(buf, length - MKA_HDR_LEN), cmac,
- length - MKA_HDR_LEN);
- } else {
- os_memcpy(wpabuf_put(buf, length), cmac, length);
- }
+ if (length != DEFAULT_ICV_LEN)
+ length -= MKA_HDR_LEN;
+ os_memcpy(wpabuf_put(buf, length), cmac, length);
return 0;
}
@@ -1754,7 +1715,7 @@
struct ieee802_1x_mka_icv_body *body;
size_t body_len;
size_t left_len;
- int body_type;
+ u8 body_type;
const u8 *pos;
pos = mka_msg;
@@ -1801,8 +1762,8 @@
body_len = get_mka_param_body_len(hdr);
if (body_len < 28) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 28 or more octets",
- (int) body_len);
+ "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 28 or more octets",
+ body_len);
return -1;
}
@@ -1825,8 +1786,8 @@
body_len = get_mka_param_body_len(hdr);
if (body_len < 5) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Use SAK Packet Body Length (%d bytes) should be 5 or more octets",
- (int) body_len);
+ "KaY: MKA Use SAK Packet Body Length (%zu bytes) should be 5 or more octets",
+ body_len);
return -1;
}
@@ -1845,85 +1806,105 @@
}
-static struct mka_param_body_handler mak_body_handler[] = {
+struct mka_param_body_handler {
+ int (*body_tx)(struct ieee802_1x_mka_participant *participant,
+ struct wpabuf *buf);
+ int (*body_rx)(struct ieee802_1x_mka_participant *participant,
+ const u8 *mka_msg, size_t msg_len);
+ int (*body_length)(struct ieee802_1x_mka_participant *participant);
+ Boolean (*body_present)(struct ieee802_1x_mka_participant *participant);
+};
+
+
+static struct mka_param_body_handler mka_body_handler[] = {
/* basic parameter set */
{
- ieee802_1x_mka_encode_basic_body,
- NULL,
- ieee802_1x_mka_basic_body_length,
- ieee802_1x_mka_basic_body_present
+ .body_tx = ieee802_1x_mka_encode_basic_body,
+ .body_rx = NULL,
+ .body_length = ieee802_1x_mka_basic_body_length,
+ .body_present = ieee802_1x_mka_basic_body_present
},
/* live peer list parameter set */
{
- ieee802_1x_mka_encode_live_peer_body,
- ieee802_1x_mka_decode_live_peer_body,
- ieee802_1x_mka_get_live_peer_length,
- ieee802_1x_mka_live_peer_body_present
+ .body_tx = ieee802_1x_mka_encode_live_peer_body,
+ .body_rx = ieee802_1x_mka_decode_live_peer_body,
+ .body_length = ieee802_1x_mka_get_live_peer_length,
+ .body_present = ieee802_1x_mka_live_peer_body_present
},
/* potential peer list parameter set */
{
- ieee802_1x_mka_encode_potential_peer_body,
- ieee802_1x_mka_decode_potential_peer_body,
- ieee802_1x_mka_get_potential_peer_length,
- ieee802_1x_mka_potential_peer_body_present
+ .body_tx = ieee802_1x_mka_encode_potential_peer_body,
+ .body_rx = ieee802_1x_mka_decode_potential_peer_body,
+ .body_length = ieee802_1x_mka_get_potential_peer_length,
+ .body_present = ieee802_1x_mka_potential_peer_body_present
},
/* sak use parameter set */
{
- ieee802_1x_mka_encode_sak_use_body,
- ieee802_1x_mka_decode_sak_use_body,
- ieee802_1x_mka_get_sak_use_length,
- ieee802_1x_mka_sak_use_body_present
+ .body_tx = ieee802_1x_mka_encode_sak_use_body,
+ .body_rx = ieee802_1x_mka_decode_sak_use_body,
+ .body_length = ieee802_1x_mka_get_sak_use_length,
+ .body_present = ieee802_1x_mka_sak_use_body_present
},
/* distribute sak parameter set */
{
- ieee802_1x_mka_encode_dist_sak_body,
- ieee802_1x_mka_decode_dist_sak_body,
- ieee802_1x_mka_get_dist_sak_length,
- ieee802_1x_mka_dist_sak_body_present
+ .body_tx = ieee802_1x_mka_encode_dist_sak_body,
+ .body_rx = ieee802_1x_mka_decode_dist_sak_body,
+ .body_length = ieee802_1x_mka_get_dist_sak_length,
+ .body_present = ieee802_1x_mka_dist_sak_body_present
},
/* distribute cak parameter set */
{
- NULL,
- ieee802_1x_mka_decode_dist_cak_body,
- NULL,
- NULL
+ .body_tx = NULL,
+ .body_rx = ieee802_1x_mka_decode_dist_cak_body,
+ .body_length = NULL,
+ .body_present = NULL
},
/* kmd parameter set */
{
- NULL,
- ieee802_1x_mka_decode_kmd_body,
- NULL,
- NULL
+ .body_tx = NULL,
+ .body_rx = ieee802_1x_mka_decode_kmd_body,
+ .body_length = NULL,
+ .body_present = NULL
},
/* announce parameter set */
{
- NULL,
- ieee802_1x_mka_decode_announce_body,
- NULL,
- NULL
+ .body_tx = NULL,
+ .body_rx = ieee802_1x_mka_decode_announce_body,
+ .body_length = NULL,
+ .body_present = NULL
},
/* icv parameter set */
{
- ieee802_1x_mka_encode_icv_body,
- NULL,
- ieee802_1x_mka_get_icv_length,
- ieee802_1x_mka_icv_body_present
+ .body_tx = ieee802_1x_mka_encode_icv_body,
+ .body_rx = NULL,
+ .body_length = ieee802_1x_mka_get_icv_length,
+ .body_present = ieee802_1x_mka_icv_body_present
},
};
/**
- * ieee802_1x_kay_deinit_data_key -
+ * ieee802_1x_kay_use_data_key - Take reference on a key
*/
-void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
+static void ieee802_1x_kay_use_data_key(struct data_key *pkey)
+{
+ pkey->user++;
+}
+
+
+/**
+ * ieee802_1x_kay_deinit_data_key - Release reference on a key and
+ * free if there are no remaining users
+ */
+static void ieee802_1x_kay_deinit_data_key(struct data_key *pkey)
{
if (!pkey)
return;
@@ -1932,7 +1913,6 @@
if (pkey->user > 1)
return;
- dl_list_del(&pkey->list);
os_free(pkey->key);
os_free(pkey);
}
@@ -1945,11 +1925,13 @@
ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant)
{
struct data_key *sa_key = NULL;
- struct key_conf *conf;
struct ieee802_1x_kay_peer *peer;
struct ieee802_1x_kay *kay = participant->kay;
int ctx_len, ctx_offset;
u8 *context;
+ unsigned int key_len;
+ u8 *key;
+ struct macsec_ciphersuite *cs;
/* check condition for generating a fresh SAK:
* must have one live peer
@@ -1976,40 +1958,29 @@
return -1;
}
- conf = os_zalloc(sizeof(*conf));
- if (!conf) {
- wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
- return -1;
- }
- conf->key_len = cipher_suite_tbl[kay->macsec_csindex].sak_len;
-
- conf->key = os_zalloc(conf->key_len);
- if (!conf->key) {
- os_free(conf);
+ cs = &cipher_suite_tbl[kay->macsec_csindex];
+ key_len = cs->sak_len;
+ key = os_zalloc(key_len);
+ if (!key) {
wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
return -1;
}
- ctx_len = conf->key_len + sizeof(kay->dist_kn);
+ ctx_len = key_len + sizeof(kay->dist_kn);
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list)
ctx_len += sizeof(peer->mi);
ctx_len += sizeof(participant->mi);
context = os_zalloc(ctx_len);
- if (!context) {
- os_free(conf->key);
- os_free(conf);
- return -1;
- }
+ if (!context)
+ goto fail;
+
ctx_offset = 0;
- if (os_get_random(context + ctx_offset, conf->key_len) < 0) {
- os_free(context);
- os_free(conf->key);
- os_free(conf);
- return -1;
- }
- ctx_offset += conf->key_len;
+ if (os_get_random(context + ctx_offset, key_len) < 0)
+ goto fail;
+
+ ctx_offset += key_len;
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
os_memcpy(context + ctx_offset, peer->mi, sizeof(peer->mi));
@@ -2020,46 +1991,46 @@
ctx_offset += sizeof(participant->mi);
os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn));
- if (conf->key_len == 16) {
+ if (key_len == 16) {
ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, conf->key);
- } else if (conf->key_len == 32) {
+ context, ctx_len, key);
+ } else if (key_len == 32) {
ieee802_1x_sak_128bits_aes_cmac(participant->cak.key,
- context, ctx_len, conf->key);
+ context, ctx_len, key);
} else {
wpa_printf(MSG_ERROR, "KaY: SAK Length not support");
- os_free(conf->key);
- os_free(conf);
- os_free(context);
- return -1;
+ goto fail;
}
- wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK",
- conf->key, conf->key_len);
+ wpa_hexdump(MSG_DEBUG, "KaY: generated new SAK", key, key_len);
+ os_free(context);
+ context = NULL;
- os_memcpy(conf->ki.mi, participant->mi, MI_LEN);
- conf->ki.kn = participant->kay->dist_kn;
- conf->an = participant->kay->dist_an;
- conf->offset = kay->macsec_confidentiality;
- conf->rx = TRUE;
- conf->tx = TRUE;
-
- sa_key = ieee802_1x_kay_init_data_key(conf);
+ sa_key = os_zalloc(sizeof(*sa_key));
if (!sa_key) {
- os_free(conf->key);
- os_free(conf);
- os_free(context);
- return -1;
+ wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__);
+ goto fail;
}
+
+ sa_key->key = key;
+ sa_key->key_len = key_len;
+ os_memcpy(sa_key->key_identifier.mi, participant->mi, MI_LEN);
+ sa_key->key_identifier.kn = kay->dist_kn;
+
+ sa_key->confidentiality_offset = kay->macsec_confidentiality;
+ sa_key->an = kay->dist_an;
+ ieee802_1x_kay_init_data_key(sa_key);
+
participant->new_key = sa_key;
+ ieee802_1x_kay_use_data_key(sa_key);
dl_list_add(&participant->sak_list, &sa_key->list);
- ieee802_1x_cp_set_ciphersuite(participant->kay->cp,
- cipher_suite_tbl[kay->macsec_csindex].id);
+
+ ieee802_1x_cp_set_ciphersuite(kay->cp, cs->id);
ieee802_1x_cp_sm_step(kay->cp);
- ieee802_1x_cp_set_offset(kay->cp, conf->offset);
+ ieee802_1x_cp_set_offset(kay->cp, kay->macsec_confidentiality);
ieee802_1x_cp_sm_step(kay->cp);
- ieee802_1x_cp_set_distributedki(kay->cp, &conf->ki);
- ieee802_1x_cp_set_distributedan(kay->cp, conf->an);
+ ieee802_1x_cp_set_distributedki(kay->cp, &sa_key->key_identifier);
+ ieee802_1x_cp_set_distributedan(kay->cp, sa_key->an);
ieee802_1x_cp_signal_newsak(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
@@ -2067,17 +2038,31 @@
struct ieee802_1x_kay_peer, list)
peer->sak_used = FALSE;
- participant->kay->dist_kn++;
- participant->kay->dist_an++;
- if (participant->kay->dist_an > 3)
- participant->kay->dist_an = 0;
+ kay->dist_kn++;
+ kay->dist_an++;
+ if (kay->dist_an > 3)
+ kay->dist_an = 0;
- participant->kay->dist_time = time(NULL);
+ kay->dist_time = time(NULL);
- os_free(conf->key);
- os_free(conf);
- os_free(context);
return 0;
+
+fail:
+ os_free(key);
+ os_free(context);
+ return -1;
+}
+
+
+static int compare_priorities(const struct ieee802_1x_kay_peer *peer,
+ const struct ieee802_1x_kay_peer *other)
+{
+ if (peer->key_server_priority < other->key_server_priority)
+ return -1;
+ if (other->key_server_priority < peer->key_server_priority)
+ return 1;
+
+ return os_memcmp(peer->sci.addr, other->sci.addr, ETH_ALEN);
}
@@ -2092,7 +2077,6 @@
struct ieee802_1x_kay_peer *key_server = NULL;
struct ieee802_1x_kay *kay = participant->kay;
Boolean i_is_key_server;
- int i;
if (participant->is_obliged_key_server) {
participant->new_sak = TRUE;
@@ -2112,47 +2096,26 @@
continue;
}
- if (peer->key_server_priority <
- key_server->key_server_priority) {
+ if (compare_priorities(peer, key_server) < 0)
key_server = peer;
- } else if (peer->key_server_priority ==
- key_server->key_server_priority) {
- for (i = 0; i < 6; i++) {
- if (peer->sci.addr[i] <
- key_server->sci.addr[i])
- key_server = peer;
- }
- }
}
/* elect the key server between me and the above elected peer */
i_is_key_server = FALSE;
if (key_server && participant->can_be_key_server) {
- if (kay->actor_priority
- < key_server->key_server_priority) {
- i_is_key_server = TRUE;
- } else if (kay->actor_priority
- == key_server->key_server_priority) {
- for (i = 0; i < 6; i++) {
- if (kay->actor_sci.addr[i]
- < key_server->sci.addr[i]) {
- i_is_key_server = TRUE;
- }
- }
- }
- }
+ struct ieee802_1x_kay_peer tmp;
- if (!key_server && !i_is_key_server) {
- participant->principal = FALSE;
- participant->is_key_server = FALSE;
- participant->is_elected = FALSE;
- return 0;
+ tmp.key_server_priority = kay->actor_priority;
+ os_memcpy(&tmp.sci, &kay->actor_sci, sizeof(tmp.sci));
+ if (compare_priorities(&tmp, key_server) < 0)
+ i_is_key_server = TRUE;
+ } else if (participant->can_be_key_server) {
+ i_is_key_server = TRUE;
}
if (i_is_key_server) {
ieee802_1x_cp_set_electedself(kay->cp, TRUE);
- if (os_memcmp(&kay->key_server_sci, &kay->actor_sci,
- sizeof(kay->key_server_sci))) {
+ if (!sci_equal(&kay->key_server_sci, &kay->actor_sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
}
@@ -2167,12 +2130,9 @@
os_memcpy(&kay->key_server_sci, &kay->actor_sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = kay->actor_priority;
- }
-
- if (key_server) {
+ } else if (key_server) {
ieee802_1x_cp_set_electedself(kay->cp, FALSE);
- if (os_memcmp(&kay->key_server_sci, &key_server->sci,
- sizeof(kay->key_server_sci))) {
+ if (!sci_equal(&kay->key_server_sci, &key_server->sci)) {
ieee802_1x_cp_signal_chgdserver(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
}
@@ -2184,6 +2144,10 @@
os_memcpy(&kay->key_server_sci, &key_server->sci,
sizeof(kay->key_server_sci));
kay->key_server_priority = key_server->key_server_priority;
+ } else {
+ participant->principal = FALSE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = FALSE;
}
return 0;
@@ -2226,11 +2190,11 @@
if (!peer->macsec_desired)
continue;
- if (peer->macsec_capbility == MACSEC_CAP_NOT_IMPLEMENTED)
+ if (peer->macsec_capability == MACSEC_CAP_NOT_IMPLEMENTED)
continue;
- less_capability = (less_capability < peer->macsec_capbility) ?
- less_capability : peer->macsec_capbility;
+ less_capability = (less_capability < peer->macsec_capability) ?
+ less_capability : peer->macsec_capability;
has_peer = TRUE;
}
@@ -2291,10 +2255,10 @@
eapol_hdr->type = IEEE802_1X_TYPE_EAPOL_MKA;
eapol_hdr->length = host_to_be16(pbuf->size - pbuf->used);
- for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
- if (mak_body_handler[i].body_present &&
- mak_body_handler[i].body_present(participant)) {
- if (mak_body_handler[i].body_tx(participant, pbuf))
+ for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
+ if (mka_body_handler[i].body_present &&
+ mka_body_handler[i].body_present(participant)) {
+ if (mka_body_handler[i].body_tx(participant, pbuf))
return -1;
}
}
@@ -2316,10 +2280,10 @@
wpa_printf(MSG_DEBUG, "KaY: to enpacket and send the MKPDU");
length += sizeof(struct ieee802_1x_hdr) + sizeof(struct ieee8023_hdr);
- for (i = 0; i < ARRAY_SIZE(mak_body_handler); i++) {
- if (mak_body_handler[i].body_present &&
- mak_body_handler[i].body_present(participant))
- length += mak_body_handler[i].body_length(participant);
+ for (i = 0; i < ARRAY_SIZE(mka_body_handler); i++) {
+ if (mka_body_handler[i].body_present &&
+ mka_body_handler[i].body_present(participant))
+ length += mka_body_handler[i].body_length(participant);
}
buf = wpabuf_alloc(length);
@@ -2344,6 +2308,16 @@
static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa);
+
+static void ieee802_1x_delete_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *sa)
+{
+ secy_disable_transmit_sa(kay, sa);
+ secy_delete_transmit_sa(kay, sa);
+ ieee802_1x_kay_deinit_transmit_sa(sa);
+}
+
+
/**
* ieee802_1x_participant_timer -
*/
@@ -2360,27 +2334,16 @@
participant = (struct ieee802_1x_mka_participant *)eloop_ctx;
kay = participant->kay;
if (participant->cak_life) {
- if (now > participant->cak_life) {
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = TRUE;
- ieee802_1x_kay_delete_mka(kay, &participant->ckn);
- return;
- }
+ if (now > participant->cak_life)
+ goto delete_mka;
}
/* should delete MKA instance if there are not live peers
* when the MKA life elapsed since its creating */
if (participant->mka_life) {
if (dl_list_empty(&participant->live_peers)) {
- if (now > participant->mka_life) {
- kay->authenticated = FALSE;
- kay->secured = FALSE;
- kay->failed = TRUE;
- ieee802_1x_kay_delete_mka(kay,
- &participant->ckn);
- return;
- }
+ if (now > participant->mka_life)
+ goto delete_mka;
} else {
participant->mka_life = 0;
}
@@ -2397,11 +2360,10 @@
dl_list_for_each_safe(rxsc, pre_rxsc,
&participant->rxsc_list,
struct receive_sc, list) {
- if (os_memcmp(&rxsc->sci, &peer->sci,
- sizeof(rxsc->sci)) == 0) {
- secy_delete_receive_sc(kay, rxsc);
+ if (sci_equal(&rxsc->sci, &peer->sci)) {
ieee802_1x_kay_deinit_receive_sc(
participant, rxsc);
+ secy_delete_receive_sc(kay, rxsc);
}
}
dl_list_del(&peer->list);
@@ -2416,6 +2378,12 @@
participant->advised_capability =
MACSEC_CAP_NOT_IMPLEMENTED;
participant->to_use_sak = FALSE;
+ participant->ltx = FALSE;
+ participant->lrx = FALSE;
+ participant->otx = FALSE;
+ participant->orx = FALSE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = FALSE;
kay->authenticated = TRUE;
kay->secured = FALSE;
kay->failed = FALSE;
@@ -2430,8 +2398,7 @@
dl_list_for_each_safe(txsa, pre_txsa,
&participant->txsc->sa_list,
struct transmit_sa, list) {
- secy_disable_transmit_sa(kay, txsa);
- ieee802_1x_kay_deinit_transmit_sa(txsa);
+ ieee802_1x_delete_transmit_sa(kay, txsa);
}
ieee802_1x_cp_connect_authenticated(kay->cp);
@@ -2461,7 +2428,8 @@
participant->new_sak = FALSE;
}
- if (participant->retry_count < MAX_RETRY_CNT) {
+ if (participant->retry_count < MAX_RETRY_CNT ||
+ participant->mode == PSK) {
ieee802_1x_participant_send_mkpdu(participant);
participant->retry_count++;
}
@@ -2469,6 +2437,14 @@
eloop_register_timeout(MKA_HELLO_TIME / 1000, 0,
ieee802_1x_participant_timer,
participant, NULL);
+
+ return;
+
+delete_mka:
+ kay->authenticated = FALSE;
+ kay->secured = FALSE;
+ kay->failed = TRUE;
+ ieee802_1x_kay_delete_mka(kay, &participant->ckn);
}
@@ -2497,6 +2473,7 @@
psa->confidentiality = FALSE;
psa->an = an;
+ ieee802_1x_kay_use_data_key(key);
psa->pkey = key;
psa->next_pn = next_PN;
psa->sc = psc;
@@ -2506,8 +2483,8 @@
dl_list_add(&psc->sa_list, &psa->list);
wpa_printf(MSG_DEBUG,
- "KaY: Create transmit SA(an: %d, next_PN: %u) of SC(channel: %d)",
- (int) an, next_PN, psc->channel);
+ "KaY: Create transmit SA(an: %hhu, next_PN: %u) of SC",
+ an, next_PN);
return psa;
}
@@ -2518,10 +2495,11 @@
*/
static void ieee802_1x_kay_deinit_transmit_sa(struct transmit_sa *psa)
{
+ ieee802_1x_kay_deinit_data_key(psa->pkey);
psa->pkey = NULL;
wpa_printf(MSG_DEBUG,
- "KaY: Delete transmit SA(an: %d) of SC(channel: %d)",
- psa->an, psa->sc->channel);
+ "KaY: Delete transmit SA(an: %hhu) of SC",
+ psa->an);
dl_list_del(&psa->list);
os_free(psa);
}
@@ -2531,8 +2509,7 @@
* init_transmit_sc -
*/
static struct transmit_sc *
-ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci,
- int channel)
+ieee802_1x_kay_init_transmit_sc(const struct ieee802_1x_mka_sci *sci)
{
struct transmit_sc *psc;
@@ -2542,7 +2519,6 @@
return NULL;
}
os_memcpy(&psc->sci, sci, sizeof(psc->sci));
- psc->channel = channel;
os_get_time(&psc->created_time);
psc->transmitting = FALSE;
@@ -2550,7 +2526,7 @@
psc->enciphering_sa = FALSE;
dl_list_init(&psc->sa_list);
- wpa_printf(MSG_DEBUG, "KaY: Create transmit SC(channel: %d)", channel);
+ wpa_printf(MSG_DEBUG, "KaY: Create transmit SC");
wpa_hexdump(MSG_DEBUG, "SCI: ", (u8 *)sci , sizeof(*sci));
return psc;
@@ -2566,13 +2542,9 @@
{
struct transmit_sa *psa, *tmp;
- wpa_printf(MSG_DEBUG, "KaY: Delete transmit SC(channel: %d)",
- psc->channel);
- dl_list_for_each_safe(psa, tmp, &psc->sa_list, struct transmit_sa,
- list) {
- secy_disable_transmit_sa(participant->kay, psa);
- ieee802_1x_kay_deinit_transmit_sa(psa);
- }
+ wpa_printf(MSG_DEBUG, "KaY: Delete transmit SC");
+ dl_list_for_each_safe(psa, tmp, &psc->sa_list, struct transmit_sa, list)
+ ieee802_1x_delete_transmit_sa(participant->kay, psa);
os_free(psc);
}
@@ -2650,6 +2622,32 @@
}
+static struct transmit_sa * lookup_txsa_by_an(struct transmit_sc *txsc, u8 an)
+{
+ struct transmit_sa *txsa;
+
+ dl_list_for_each(txsa, &txsc->sa_list, struct transmit_sa, list) {
+ if (txsa->an == an)
+ return txsa;
+ }
+
+ return NULL;
+}
+
+
+static struct receive_sa * lookup_rxsa_by_an(struct receive_sc *rxsc, u8 an)
+{
+ struct receive_sa *rxsa;
+
+ dl_list_for_each(rxsa, &rxsc->sa_list, struct receive_sa, list) {
+ if (rxsa->an == an)
+ return rxsa;
+ }
+
+ return NULL;
+}
+
+
/**
* ieee802_1x_kay_create_sas -
*/
@@ -2684,6 +2682,9 @@
}
dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
+ while ((rxsa = lookup_rxsa_by_an(rxsc, latest_sak->an)) != NULL)
+ ieee802_1x_delete_receive_sa(kay, rxsa);
+
rxsa = ieee802_1x_kay_init_receive_sa(rxsc, latest_sak->an, 1,
latest_sak);
if (!rxsa)
@@ -2692,6 +2693,10 @@
secy_create_receive_sa(kay, rxsa);
}
+ while ((txsa = lookup_txsa_by_an(principal->txsc, latest_sak->an)) !=
+ NULL)
+ ieee802_1x_delete_transmit_sa(kay, txsa);
+
txsa = ieee802_1x_kay_init_transmit_sa(principal->txsc, latest_sak->an,
1, latest_sak);
if (!txsa)
@@ -2725,20 +2730,16 @@
/* remove the transmit sa */
dl_list_for_each_safe(txsa, pre_txsa, &principal->txsc->sa_list,
struct transmit_sa, list) {
- if (is_ki_equal(&txsa->pkey->key_identifier, ki)) {
- secy_disable_transmit_sa(kay, txsa);
- ieee802_1x_kay_deinit_transmit_sa(txsa);
- }
+ if (is_ki_equal(&txsa->pkey->key_identifier, ki))
+ ieee802_1x_delete_transmit_sa(kay, txsa);
}
/* remove the receive sa */
dl_list_for_each(rxsc, &principal->rxsc_list, struct receive_sc, list) {
dl_list_for_each_safe(rxsa, pre_rxsa, &rxsc->sa_list,
struct receive_sa, list) {
- if (is_ki_equal(&rxsa->pkey->key_identifier, ki)) {
- secy_disable_receive_sa(kay, rxsa);
- ieee802_1x_kay_deinit_receive_sa(rxsa);
- }
+ if (is_ki_equal(&rxsa->pkey->key_identifier, ki))
+ ieee802_1x_delete_receive_sa(kay, rxsa);
}
}
@@ -2746,6 +2747,7 @@
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)) {
+ dl_list_del(&sa_key->list);
ieee802_1x_kay_deinit_data_key(sa_key);
break;
}
@@ -2827,7 +2829,7 @@
if (!principal)
return -1;
- if (principal->retry_count < MAX_RETRY_CNT) {
+ if (principal->retry_count < MAX_RETRY_CNT || principal->mode == PSK) {
ieee802_1x_participant_send_mkpdu(principal);
principal->retry_count++;
}
@@ -2837,38 +2839,6 @@
/**
- * ieee802_1x_kay_cp_conf -
- */
-int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pconf)
-{
- pconf->protect = kay->macsec_protect;
- pconf->replay_protect = kay->macsec_replay_protect;
- pconf->validate = kay->macsec_validate;
-
- return 0;
-}
-
-
-/**
- * ieee802_1x_kay_alloc_cp_sm -
- */
-static struct ieee802_1x_cp_sm *
-ieee802_1x_kay_alloc_cp_sm(struct ieee802_1x_kay *kay)
-{
- struct ieee802_1x_cp_conf conf;
-
- os_memset(&conf, 0, sizeof(conf));
- conf.protect = kay->macsec_protect;
- conf.replay_protect = kay->macsec_replay_protect;
- conf.validate = kay->macsec_validate;
- conf.replay_window = kay->macsec_replay_window;
-
- return ieee802_1x_cp_sm_init(kay, &conf);
-}
-
-
-/**
* ieee802_1x_kay_mkpdu_sanity_check -
* sanity check specified in clause 11.11.2 of IEEE802.1X-2010
*/
@@ -2896,13 +2866,13 @@
return -1;
}
- /* MKPDU should not less than 32 octets */
+ /* MKPDU should 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");
return -1;
}
- /* MKPDU should multiple 4 octets */
+ /* MKPDU should be a multiple of 4 octets */
if ((mka_msg_len % 4) != 0) {
wpa_printf(MSG_MSGDUMP,
"KaY: MKPDU is not multiple of 4 octets");
@@ -2915,9 +2885,9 @@
/* EAPOL-MKA body should comprise basic parameter set and ICV */
if (mka_msg_len < MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN) {
wpa_printf(MSG_ERROR,
- "KaY: Received EAPOL-MKA Packet Body Length (%d bytes) is less than the Basic Parameter Set Header Length (%d bytes) + the Basic Parameter Set Body Length (%d bytes) + %d bytes of ICV",
- (int) mka_msg_len, (int) MKA_HDR_LEN,
- (int) body_len, DEFAULT_ICV_LEN);
+ "KaY: Received EAPOL-MKA Packet Body Length (%zu bytes) is less than the Basic Parameter Set Header Length (%zu bytes) + the Basic Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+ mka_msg_len, MKA_HDR_LEN,
+ body_len, DEFAULT_ICV_LEN);
return -1;
}
@@ -2948,21 +2918,19 @@
wpa_printf(MSG_ERROR, "KaY: omac1_aes_128 failed");
return -1;
}
+
msg_icv = ieee802_1x_mka_decode_icv_body(participant, (u8 *) mka_hdr,
mka_msg_len);
-
- if (msg_icv) {
- if (os_memcmp_const(msg_icv, icv,
- mka_alg_tbl[kay->mka_algindex].icv_len) !=
- 0) {
- wpa_printf(MSG_ERROR,
- "KaY: Computed ICV is not equal to Received ICV");
- return -1;
- }
- } else {
+ if (!msg_icv) {
wpa_printf(MSG_ERROR, "KaY: No ICV");
return -1;
}
+ if (os_memcmp_const(msg_icv, icv,
+ mka_alg_tbl[kay->mka_algindex].icv_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "KaY: Computed ICV is not equal to Received ICV");
+ return -1;
+ }
return 0;
}
@@ -2978,10 +2946,9 @@
struct ieee802_1x_mka_hdr *hdr;
size_t body_len;
size_t left_len;
- int body_type;
+ u8 body_type;
int i;
const u8 *pos;
- Boolean my_included;
Boolean handled[256];
if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
@@ -3002,28 +2969,27 @@
left_len -= body_len + MKA_HDR_LEN;
/* check i am in the peer's peer list */
- my_included = ieee802_1x_mka_i_in_peerlist(participant, pos, left_len);
- if (my_included) {
+ if (ieee802_1x_mka_i_in_peerlist(participant, pos, left_len) &&
+ !ieee802_1x_kay_is_in_live_peer(participant,
+ participant->current_peer_id.mi)) {
/* accept the peer as live peer */
- if (!ieee802_1x_kay_is_in_peer(
- participant,
- participant->current_peer_id.mi)) {
- if (!ieee802_1x_kay_create_live_peer(
- participant,
- participant->current_peer_id.mi,
- participant->current_peer_id.mn))
- return -1;
- ieee802_1x_kay_elect_key_server(participant);
- ieee802_1x_kay_decide_macsec_use(participant);
- }
if (ieee802_1x_kay_is_in_potential_peer(
participant, participant->current_peer_id.mi)) {
- ieee802_1x_kay_move_live_peer(
- participant, participant->current_peer_id.mi,
- participant->current_peer_id.mn);
- ieee802_1x_kay_elect_key_server(participant);
- ieee802_1x_kay_decide_macsec_use(participant);
+ if (!ieee802_1x_kay_move_live_peer(
+ participant,
+ participant->current_peer_id.mi,
+ be_to_host32(participant->
+ current_peer_id.mn)))
+ return -1;
+ } else if (!ieee802_1x_kay_create_live_peer(
+ participant, participant->current_peer_id.mi,
+ be_to_host32(participant->
+ current_peer_id.mn))) {
+ return -1;
}
+
+ ieee802_1x_kay_elect_key_server(participant);
+ ieee802_1x_kay_decide_macsec_use(participant);
}
/*
@@ -3034,7 +3000,9 @@
handled[i] = FALSE;
handled[0] = TRUE;
- while (left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN) {
+ for (; left_len > MKA_HDR_LEN + DEFAULT_ICV_LEN;
+ 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_type = get_mka_param_body_type(hdr);
@@ -3044,28 +3012,25 @@
if (left_len < (MKA_HDR_LEN + body_len + DEFAULT_ICV_LEN)) {
wpa_printf(MSG_ERROR,
- "KaY: MKA Peer Packet Body Length (%d bytes) is less than the Parameter Set Header Length (%d bytes) + the Parameter Set Body Length (%d bytes) + %d bytes of ICV",
- (int) left_len, (int) MKA_HDR_LEN,
- (int) body_len, DEFAULT_ICV_LEN);
- goto next_para_set;
+ "KaY: MKA Peer Packet Body Length (%zu bytes) is less than the Parameter Set Header Length (%zu bytes) + the Parameter Set Body Length (%zu bytes) + %d bytes of ICV",
+ left_len, MKA_HDR_LEN,
+ body_len, DEFAULT_ICV_LEN);
+ continue;
}
if (handled[body_type])
- goto next_para_set;
+ continue;
handled[body_type] = TRUE;
- if (mak_body_handler[body_type].body_rx) {
- mak_body_handler[body_type].body_rx
+ 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);
} else {
wpa_printf(MSG_ERROR,
- "The type %d not supported in this MKA version %d",
+ "The type %d is not supported in this MKA version %d",
body_type, MKA_VERSION_ID);
}
-
-next_para_set:
- pos += body_len + MKA_HDR_LEN;
- left_len -= body_len + MKA_HDR_LEN;
}
kay->active = TRUE;
@@ -3094,10 +3059,10 @@
eth_hdr = (struct ieee8023_hdr *) buf;
eapol_hdr = (struct ieee802_1x_hdr *) (eth_hdr + 1);
if (len != sizeof(*eth_hdr) + sizeof(*eapol_hdr) +
- ntohs(eapol_hdr->length)) {
+ be_to_host16(eapol_hdr->length)) {
wpa_printf(MSG_MSGDUMP, "KAY: EAPOL MPDU is invalid: (%lu-%lu)",
(unsigned long) len,
- (unsigned long) ntohs(eapol_hdr->length));
+ (unsigned long) be_to_host16(eapol_hdr->length));
return;
}
@@ -3106,7 +3071,7 @@
eapol_hdr->version);
return;
}
- if (ntohs(eth_hdr->ethertype) != ETH_P_PAE ||
+ if (be_to_host16(eth_hdr->ethertype) != ETH_P_PAE ||
eapol_hdr->type != IEEE802_1X_TYPE_EAPOL_MKA)
return;
@@ -3125,7 +3090,7 @@
*/
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- const char *ifname, const u8 *addr)
+ u16 port, u8 priority, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3147,8 +3112,8 @@
os_strlcpy(kay->if_name, ifname, IFNAMSIZ);
os_memcpy(kay->actor_sci.addr, addr, ETH_ALEN);
- kay->actor_sci.port = 0x0001;
- kay->actor_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+ kay->actor_sci.port = host_to_be16(port ? port : 0x0001);
+ kay->actor_priority = priority;
/* While actor acts as a key server, shall distribute sakey */
kay->dist_kn = 1;
@@ -3165,7 +3130,14 @@
dl_list_init(&kay->participant_list);
- if (policy == DO_NOT_SECURE) {
+ if (policy != DO_NOT_SECURE &&
+ secy_get_capability(kay, &kay->macsec_capable) < 0) {
+ os_free(kay);
+ return NULL;
+ }
+
+ if (policy == DO_NOT_SECURE ||
+ kay->macsec_capable == MACSEC_CAP_NOT_IMPLEMENTED) {
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
kay->macsec_desired = FALSE;
kay->macsec_protect = FALSE;
@@ -3174,25 +3146,27 @@
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
} else {
- kay->macsec_capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
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;
- kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
+ if (kay->macsec_capable >= MACSEC_CAP_INTEG_AND_CONF)
+ kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
+ else
+ kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
}
wpa_printf(MSG_DEBUG, "KaY: state machine created");
/* Initialize the SecY must be prio to CP, as CP will control SecY */
secy_init_macsec(kay);
- secy_get_available_transmit_sc(kay, &kay->sc_ch);
wpa_printf(MSG_DEBUG, "KaY: secy init macsec done");
/* init CP */
- kay->cp = ieee802_1x_kay_alloc_cp_sm(kay);
+ kay->cp = ieee802_1x_cp_sm_init(kay);
if (kay->cp == NULL) {
ieee802_1x_kay_deinit(kay);
return NULL;
@@ -3314,7 +3288,7 @@
default:
participant->is_obliged_key_server = FALSE;
participant->can_be_key_server = TRUE;
- participant->is_key_server = FALSE;
+ participant->is_key_server = TRUE;
participant->is_elected = FALSE;
break;
}
@@ -3335,9 +3309,8 @@
participant->retry_count = 0;
participant->kay = kay;
- if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ if (!reset_participant_mi(participant))
goto fail;
- participant->mn = 0;
participant->lrx = FALSE;
participant->ltx = FALSE;
@@ -3349,8 +3322,7 @@
dl_list_init(&participant->sak_list);
participant->new_key = NULL;
dl_list_init(&participant->rxsc_list);
- participant->txsc = ieee802_1x_kay_init_transmit_sc(&kay->actor_sci,
- kay->sc_ch);
+ participant->txsc = ieee802_1x_kay_init_transmit_sc(&kay->actor_sci);
secy_cp_control_protect_frames(kay, kay->macsec_protect);
secy_cp_control_replay(kay, kay->macsec_replay_protect,
kay->macsec_replay_window);
@@ -3387,8 +3359,17 @@
usecs = os_random() % (MKA_HELLO_TIME * 1000);
eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
participant, NULL);
- participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
- usecs / 1000000;
+
+ /* Disable MKA lifetime for PSK mode.
+ * The peer(s) can take a long time to come up, because we
+ * create a "standby" MKA, and we need it to remain live until
+ * some peer appears.
+ */
+ if (mode != PSK) {
+ participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
+ usecs / 1000000;
+ }
+ participant->mode = mode;
return participant;
@@ -3422,6 +3403,7 @@
return;
}
+ eloop_cancel_timeout(ieee802_1x_participant_timer, participant, NULL);
dl_list_del(&participant->list);
/* remove live peer */
@@ -3445,17 +3427,16 @@
sak = dl_list_entry(participant->sak_list.next,
struct data_key, list);
dl_list_del(&sak->list);
- os_free(sak->key);
- os_free(sak);
+ ieee802_1x_kay_deinit_data_key(sak);
}
while (!dl_list_empty(&participant->rxsc_list)) {
rxsc = dl_list_entry(participant->rxsc_list.next,
struct receive_sc, list);
- secy_delete_receive_sc(kay, rxsc);
ieee802_1x_kay_deinit_receive_sc(participant, rxsc);
+ secy_delete_receive_sc(kay, rxsc);
}
- secy_delete_transmit_sc(kay, participant->txsc);
ieee802_1x_kay_deinit_transmit_sc(participant, participant->txsc);
+ secy_delete_transmit_sc(kay, participant->txsc);
os_memset(&participant->cak, 0, sizeof(participant->cak));
os_memset(&participant->kek, 0, sizeof(participant->kek));
@@ -3510,14 +3491,16 @@
* ieee802_1x_kay_change_cipher_suite -
*/
int
-ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay, int cs_index)
+ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
+ unsigned int cs_index)
{
struct ieee802_1x_mka_participant *participant;
+ enum macsec_cap secy_cap;
if (!kay)
return -1;
- if ((unsigned int) cs_index >= CS_TABLE_SIZE) {
+ if (cs_index >= CS_TABLE_SIZE) {
wpa_printf(MSG_ERROR,
"KaY: Configured cipher suite index is out of range");
return -1;
@@ -3531,6 +3514,12 @@
kay->macsec_csindex = cs_index;
kay->macsec_capable = cipher_suite_tbl[kay->macsec_csindex].capable;
+ if (secy_get_capability(kay, &secy_cap) < 0)
+ return -3;
+
+ if (kay->macsec_capable > secy_cap)
+ kay->macsec_capable = secy_cap;
+
participant = ieee802_1x_kay_get_principal_participant(kay);
if (participant) {
wpa_printf(MSG_INFO, "KaY: Cipher Suite changed");
@@ -3539,3 +3528,51 @@
return 0;
}
+
+
+#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()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @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
+ * 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;
+
+ if (!kay)
+ return 0;
+
+ len = os_snprintf(buf, buflen,
+ "PAE KaY status=%s\n"
+ "Authenticated=%s\n"
+ "Secured=%s\n"
+ "Failed=%s\n"
+ "Actor Priority=%u\n"
+ "Key Server Priority=%u\n"
+ "Is Key Server=%s\n"
+ "Number of Keys Distributed=%u\n"
+ "Number of Keys Received=%u\n",
+ kay->active ? "Active" : "Not-Active",
+ kay->authenticated ? "Yes" : "No",
+ kay->secured ? "Yes" : "No",
+ kay->failed ? "Yes" : "No",
+ kay->actor_priority,
+ kay->key_server_priority,
+ kay->is_key_server ? "Yes" : "No",
+ kay->dist_kn - 1,
+ kay->rcvd_keys);
+ if (os_snprintf_error(buflen, len))
+ return 0;
+
+ return len;
+}
+#endif /* CONFIG_CTRL_IFACE */
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 064417e..8f394fd 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -14,9 +14,8 @@
#include "common/ieee802_1x_defs.h"
struct macsec_init_params;
-struct ieee802_1x_cp_conf;
-#define MI_LEN 12
+#define MI_LEN 12 /* 96-bit Member Identifier */
#define MAX_KEY_LEN 32 /* 32 bytes, 256 bits */
#define MAX_CKN_LEN 32 /* 32 bytes, 256 bits */
@@ -25,6 +24,12 @@
#define MKA_LIFE_TIME 6000
#define MKA_SAK_RETIRE_TIME 3000
+/**
+ * struct ieee802_1x_mka_ki - Key Identifier (KI)
+ * @mi: Key Server's Member Identifier
+ * @kn: Key Number, assigned by the Key Server
+ * IEEE 802.1X-2010 9.8 SAK generation, distribution, and selection
+ */
struct ieee802_1x_mka_ki {
u8 mi[MI_LEN];
u32 kn;
@@ -32,7 +37,7 @@
struct ieee802_1x_mka_sci {
u8 addr[ETH_ALEN];
- u16 port;
+ be16 port;
};
struct mka_key {
@@ -48,8 +53,84 @@
enum mka_created_mode {
PSK,
EAP_EXCHANGE,
- DISTRIBUTED,
- CACHED,
+};
+
+struct data_key {
+ u8 *key;
+ int key_len;
+ struct ieee802_1x_mka_ki key_identifier;
+ enum confidentiality_offset confidentiality_offset;
+ u8 an;
+ Boolean transmits;
+ Boolean receives;
+ struct os_time created_time;
+ u32 next_pn;
+
+ /* not defined data */
+ Boolean rx_latest;
+ Boolean tx_latest;
+
+ int user;
+
+ struct dl_list list;
+};
+
+/* TransmitSC in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct transmit_sc {
+ struct ieee802_1x_mka_sci sci; /* const SCI sci */
+ Boolean transmitting; /* bool transmitting (read only) */
+
+ struct os_time created_time; /* Time createdTime */
+
+ u8 encoding_sa; /* AN encodingSA (read only) */
+ u8 enciphering_sa; /* AN encipheringSA (read only) */
+
+ /* not defined data */
+ struct dl_list list;
+ struct dl_list sa_list;
+};
+
+/* TransmitSA in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct transmit_sa {
+ Boolean in_use; /* bool inUse (read only) */
+ u32 next_pn; /* PN nextPN (read only) */
+ struct os_time created_time; /* Time createdTime */
+
+ Boolean enable_transmit; /* bool EnableTransmit */
+
+ u8 an;
+ Boolean confidentiality;
+ struct data_key *pkey;
+
+ struct transmit_sc *sc;
+ struct dl_list list; /* list entry in struct transmit_sc::sa_list */
+};
+
+/* ReceiveSC in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct receive_sc {
+ struct ieee802_1x_mka_sci sci; /* const SCI sci */
+ Boolean receiving; /* bool receiving (read only) */
+
+ struct os_time created_time; /* Time createdTime */
+
+ struct dl_list list;
+ struct dl_list sa_list;
+};
+
+/* ReceiveSA in IEEE Std 802.1AE-2006, Figure 10-6 */
+struct receive_sa {
+ Boolean enable_receive; /* bool enableReceive */
+ Boolean in_use; /* bool inUse (read only) */
+
+ u32 next_pn; /* PN nextPN (read only) */
+ u32 lowest_pn; /* PN lowestPN (read only) */
+ u8 an;
+ struct os_time created_time;
+
+ struct data_key *pkey;
+ struct receive_sc *sc; /* list entry in struct receive_sc::sa_list */
+
+ struct dl_list list;
};
struct ieee802_1x_kay_ctx {
@@ -59,34 +140,30 @@
/* abstract wpa driver interface */
int (*macsec_init)(void *ctx, struct macsec_init_params *params);
int (*macsec_deinit)(void *ctx);
+ int (*macsec_get_capability)(void *priv, enum macsec_cap *cap);
int (*enable_protect_frames)(void *ctx, Boolean enabled);
+ int (*enable_encrypt)(void *ctx, Boolean enabled);
int (*set_replay_protect)(void *ctx, Boolean enabled, u32 window);
- int (*set_current_cipher_suite)(void *ctx, const u8 *cs, size_t cs_len);
+ int (*set_current_cipher_suite)(void *ctx, u64 cs);
int (*enable_controlled_port)(void *ctx, Boolean enabled);
- int (*get_receive_lowest_pn)(void *ctx, u32 channel, u8 an,
- u32 *lowest_pn);
- int (*get_transmit_next_pn)(void *ctx, u32 channel, u8 an,
- u32 *next_pn);
- int (*set_transmit_next_pn)(void *ctx, u32 channel, u8 an, u32 next_pn);
- int (*get_available_receive_sc)(void *ctx, u32 *channel);
- int (*create_receive_sc)(void *ctx, u32 channel,
- struct ieee802_1x_mka_sci *sci,
+ 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 (*create_receive_sc)(void *ctx, struct receive_sc *sc,
enum validate_frames vf,
enum confidentiality_offset co);
- int (*delete_receive_sc)(void *ctx, u32 channel);
- int (*create_receive_sa)(void *ctx, u32 channel, u8 an, u32 lowest_pn,
- const u8 *sak);
- int (*enable_receive_sa)(void *ctx, u32 channel, u8 an);
- int (*disable_receive_sa)(void *ctx, u32 channel, u8 an);
- int (*get_available_transmit_sc)(void *ctx, u32 *channel);
- int (*create_transmit_sc)(void *ctx, u32 channel,
- const struct ieee802_1x_mka_sci *sci,
+ int (*delete_receive_sc)(void *ctx, struct receive_sc *sc);
+ int (*create_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*delete_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*enable_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*disable_receive_sa)(void *ctx, struct receive_sa *sa);
+ int (*create_transmit_sc)(void *ctx, struct transmit_sc *sc,
enum confidentiality_offset co);
- int (*delete_transmit_sc)(void *ctx, u32 channel);
- int (*create_transmit_sa)(void *ctx, u32 channel, u8 an, u32 next_pn,
- Boolean confidentiality, const u8 *sak);
- int (*enable_transmit_sa)(void *ctx, u32 channel, u8 an);
- int (*disable_transmit_sa)(void *ctx, u32 channel, u8 an);
+ int (*delete_transmit_sc)(void *ctx, struct transmit_sc *sc);
+ int (*create_transmit_sa)(void *ctx, struct transmit_sa *sa);
+ int (*delete_transmit_sa)(void *ctx, struct transmit_sa *sa);
+ int (*enable_transmit_sa)(void *ctx, struct transmit_sa *sa);
+ int (*disable_transmit_sa)(void *ctx, struct transmit_sa *sa);
};
struct ieee802_1x_kay {
@@ -105,6 +182,7 @@
enum macsec_cap macsec_capable;
Boolean macsec_desired;
Boolean macsec_protect;
+ Boolean macsec_encrypt;
Boolean macsec_replay_protect;
u32 macsec_replay_window;
enum validate_frames macsec_validate;
@@ -126,16 +204,16 @@
Boolean is_obliged_key_server;
char if_name[IFNAMSIZ];
- int macsec_csindex; /* MACsec cipher suite table index */
+ unsigned int macsec_csindex; /* MACsec cipher suite table index */
int mka_algindex; /* MKA alg table index */
u32 dist_kn;
+ u32 rcvd_keys;
u8 dist_an;
time_t dist_time;
u8 mka_version;
u8 algo_agility[4];
- u32 sc_ch;
u32 pn_exhaustion;
Boolean port_enable;
@@ -154,9 +232,11 @@
};
+u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci);
+
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
- const char *ifname, const u8 *addr);
+ u16 port, u8 priority, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
@@ -171,7 +251,7 @@
Boolean status);
int ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay);
int ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
- int cs_index);
+ unsigned int cs_index);
int ieee802_1x_kay_set_latest_sa_attr(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki, u8 lan,
@@ -188,7 +268,7 @@
int ieee802_1x_kay_enable_rx_sas(struct ieee802_1x_kay *kay,
struct ieee802_1x_mka_ki *lki);
int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay);
-int ieee802_1x_kay_cp_conf(struct ieee802_1x_kay *kay,
- struct ieee802_1x_cp_conf *pconf);
+int ieee802_1x_kay_get_status(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 bdad3a5..bc522d8 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -38,7 +38,7 @@
struct ieee802_1x_mka_peer_id {
u8 mi[MI_LEN];
- u32 mn;
+ be32 mn;
};
struct ieee802_1x_kay_peer {
@@ -49,105 +49,13 @@
Boolean is_key_server;
u8 key_server_priority;
Boolean macsec_desired;
- enum macsec_cap macsec_capbility;
+ enum macsec_cap macsec_capability;
Boolean sak_used;
struct dl_list list;
};
-struct key_conf {
- u8 *key;
- struct ieee802_1x_mka_ki ki;
- enum confidentiality_offset offset;
- u8 an;
- Boolean tx;
- Boolean rx;
- int key_len; /* unit: byte */
-};
-
-struct data_key {
- u8 *key;
- int key_len;
- struct ieee802_1x_mka_ki key_identifier;
- enum confidentiality_offset confidentiality_offset;
- u8 an;
- Boolean transmits;
- Boolean receives;
- struct os_time created_time;
- u32 next_pn;
-
- /* not defined data */
- Boolean rx_latest;
- Boolean tx_latest;
-
- int user; /* FIXME: to indicate if it can be delete safely */
-
- struct dl_list list;
-};
-
-/* TransmitSC in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct transmit_sc {
- struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean transmitting; /* bool transmitting (read only) */
-
- struct os_time created_time; /* Time createdTime */
-
- u8 encoding_sa; /* AN encodingSA (read only) */
- u8 enciphering_sa; /* AN encipheringSA (read only) */
-
- /* not defined data */
- unsigned int channel;
-
- struct dl_list list;
- struct dl_list sa_list;
-};
-
-/* TransmitSA in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct transmit_sa {
- Boolean in_use; /* bool inUse (read only) */
- u32 next_pn; /* PN nextPN (read only) */
- struct os_time created_time; /* Time createdTime */
-
- Boolean enable_transmit; /* bool EnableTransmit */
-
- u8 an;
- Boolean confidentiality;
- struct data_key *pkey;
-
- struct transmit_sc *sc;
- struct dl_list list; /* list entry in struct transmit_sc::sa_list */
-};
-
-/* ReceiveSC in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct receive_sc {
- struct ieee802_1x_mka_sci sci; /* const SCI sci */
- Boolean receiving; /* bool receiving (read only) */
-
- struct os_time created_time; /* Time createdTime */
-
- unsigned int channel;
-
- struct dl_list list;
- struct dl_list sa_list;
-};
-
-/* ReceiveSA in IEEE Std 802.1AE-2006, Figure 10-6 */
-struct receive_sa {
- Boolean enable_receive; /* bool enableReceive */
- Boolean in_use; /* bool inUse (read only) */
-
- u32 next_pn; /* PN nextPN (read only) */
- u32 lowest_pn; /* PN lowestPN (read only) */
- u8 an;
- struct os_time created_time;
-
- struct data_key *pkey;
- struct receive_sc *sc; /* list entry in struct receive_sc::sa_list */
-
- struct dl_list list;
-};
-
struct macsec_ciphersuite {
- u8 id[CS_ID_LEN];
+ u64 id;
char name[32];
enum macsec_cap capable;
int sak_len; /* unit: byte */
@@ -185,6 +93,7 @@
Boolean active;
Boolean participant;
Boolean retain;
+ enum mka_created_mode mode;
enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
@@ -241,153 +150,213 @@
struct ieee802_1x_mka_hdr {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
- u32 reserve:8;
+ u8 reserve;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#else
#error "Please fix <bits/endian.h>"
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
};
#define MKA_HDR_LEN sizeof(struct ieee802_1x_mka_hdr)
+/**
+ * struct ieee802_1x_mka_basic_body - Basic Parameter Set (Figure 11-8)
+ * @version: MKA Version Identifier
+ * @priority: Key Server Priority
+ * @length: Parameter set body length
+ * @macsec_capability: MACsec capability, as defined in ieee802_1x_defs.h
+ * @macsec_desired: the participant wants MACsec to be used to protect frames
+ * (9.6.1)
+ * @key_server: the participant has not decided that another participant is or
+ * will be the key server (9.5.1)
+ * @length1: Parameter set body length (cont)
+ * @actor_mi: Actor's Member Identifier
+ * @actor_mn: Actor's Message Number
+ * @algo_agility: Algorithm Agility parameter
+ * @ckn: CAK Name
+ */
struct ieee802_1x_mka_basic_body {
/* octet 1 */
- u32 version:8;
+ u8 version;
/* octet 2 */
- u32 priority:8;
+ u8 priority;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 macsec_capbility:2;
- u32 macsec_desired:1;
- u32 key_server:1;
+ u8 length:4;
+ u8 macsec_capability:2;
+ u8 macsec_desired:1;
+ u8 key_server:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 key_server:1;
- u32 macsec_desired:1;
- u32 macsec_capbility:2;
- u32 length:4;
+ u8 key_server:1;
+ u8 macsec_desired:1;
+ u8 macsec_capability:2;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
struct ieee802_1x_mka_sci actor_sci;
u8 actor_mi[MI_LEN];
- u32 actor_mn;
+ be32 actor_mn;
u8 algo_agility[4];
/* followed by CAK Name*/
u8 ckn[0];
};
+/**
+ * struct ieee802_1x_mka_peer_body - Live Peer List and Potential Peer List
+ * parameter sets (Figure 11-9)
+ * @type: Parameter set type (1 or 2)
+ * @length: Parameter set body length
+ * @length1: Parameter set body length (cont)
+ * @peer: array of (MI, MN) pairs
+ */
struct ieee802_1x_mka_peer_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
- u32 reserve:8;
+ u8 reserve;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
u8 peer[0];
/* followed by Peers */
};
+/**
+ * struct ieee802_1x_mka_sak_use_body - MACsec SAK Use parameter set (Figure
+ * 11-10)
+ * @type: MKA message type
+ * @lan: latest key AN
+ * @ltx: latest key TX
+ * @lrx: latest key RX
+ * @oan: old key AN
+ * @otx: old key TX
+ * @orx: old key RX
+ * @ptx: plain TX, ie protectFrames is False
+ * @prx: plain RX, ie validateFrames is not Strict
+ * @delay_protect: True if LPNs are being reported sufficiently frequently to
+ * allow the recipient to provide data delay protection. If False, the LPN
+ * can be reported as zero.
+ * @lsrv_mi: latest key server MI
+ * @lkn: latest key number (together with MI, form the KI)
+ * @llpn: latest lowest acceptable PN (LPN)
+ * @osrv_mi: old key server MI
+ * @okn: old key number (together with MI, form the KI)
+ * @olpn: old lowest acceptable PN (LPN)
+ */
struct ieee802_1x_mka_sak_use_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 orx:1;
- u32 otx:1;
- u32 oan:2;
- u32 lrx:1;
- u32 ltx:1;
- u32 lan:2;
+ u8 orx:1;
+ u8 otx:1;
+ u8 oan:2;
+ u8 lrx:1;
+ u8 ltx:1;
+ u8 lan:2;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 lan:2;
- u32 ltx:1;
- u32 lrx:1;
- u32 oan:2;
- u32 otx:1;
- u32 orx:1;
+ u8 lan:2;
+ u8 ltx:1;
+ u8 lrx:1;
+ u8 oan:2;
+ u8 otx:1;
+ u8 orx:1;
#endif
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 delay_protect:1;
- u32 reserve:1;
- u32 prx:1;
- u32 ptx:1;
+ u8 length:4;
+ u8 delay_protect:1;
+ u8 reserve:1;
+ u8 prx:1;
+ u8 ptx:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 ptx:1;
- u32 prx:1;
- u32 reserve:1;
- u32 delay_protect:1;
- u32 length:4;
+ u8 ptx:1;
+ u8 prx:1;
+ u8 reserve:1;
+ u8 delay_protect:1;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
/* octet 5 - 16 */
u8 lsrv_mi[MI_LEN];
/* octet 17 - 20 */
- u32 lkn;
+ be32 lkn;
/* octet 21 - 24 */
- u32 llpn;
+ be32 llpn;
/* octet 25 - 36 */
u8 osrv_mi[MI_LEN];
/* octet 37 - 40 */
- u32 okn;
+ be32 okn;
/* octet 41 - 44 */
- u32 olpn;
+ be32 olpn;
};
-
+/**
+ * struct ieee802_1x_mka_dist_sak_body - Distributed SAK parameter set
+ * (GCM-AES-128, Figure 11-11)
+ * @type: Parameter set type (4)
+ * @length: Parameter set body length
+ * @length1: Parameter set body length (cont)
+ * Total parameter body length values:
+ * - 0 for plain text
+ * - 28 for GCM-AES-128
+ * - 36 or more for other cipher suites
+ * @confid_offset: confidentiality offset, as defined in ieee802_1x_defs.h
+ * @dan: distributed AN (0 for plain text)
+ * @kn: Key Number
+ * @sak: AES Key Wrap of SAK (see 9.8)
+ */
struct ieee802_1x_mka_dist_sak_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 reserve:4;
- u32 confid_offset:2;
- u32 dan:2;
+ u8 reserve:4;
+ u8 confid_offset:2;
+ u8 dan:2;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 dan:2;
- u32 confid_offset:2;
- u32 reserve:4;
+ u8 dan:2;
+ u8 confid_offset:2;
+ u8 reserve:4;
#endif
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
/* octet 5 - 8 */
- u32 kn;
+ be32 kn;
/* for GCM-AES-128: octet 9-32: SAK
* for other cipher suite: octet 9-16: cipher suite id, octet 17-: SAK
@@ -395,22 +364,57 @@
u8 sak[0];
};
+/**
+ * struct ieee802_1x_mka_dist_cak_body - Distributed CAK parameter set (Figure
+ * 11-13)
+ * @type: Parameter set type (5)
+ * @length: Parameter set body length
+ * @length1: Parameter set body length (cont)
+ * Total parameter body length values:
+ * - 0 for plain text
+ * - 28 for GCM-AES-128
+ * - 36 or more for other cipher suites
+ * @cak: AES Key Wrap of CAK (see 9.8)
+ * @ckn: CAK Name
+ */
+struct ieee802_1x_mka_dist_cak_body {
+ /* octet 1 */
+ u8 type;
+ /* octet 2 */
+ u8 reserve;
+ /* octet 3 */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u8 length:4;
+ u8 reserve1:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u8 reserve1:4;
+ u8 length:4;
+#endif
+ /* octet 4 */
+ u8 length1;
+
+ /* octet 5 - 28 */
+ u8 cak[24];
+
+ /* followed by CAK Name, 29- */
+ u8 ckn[0];
+};
struct ieee802_1x_mka_icv_body {
/* octet 1 */
- u32 type:8;
+ u8 type;
/* octet 2 */
- u32 reserve:8;
+ u8 reserve;
/* octet 3 */
#if __BYTE_ORDER == __LITTLE_ENDIAN
- u32 length:4;
- u32 reserve1:4;
+ u8 length:4;
+ u8 reserve1:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
- u32 reserve1:4;
- u32 length:4;
+ u8 reserve1:4;
+ u8 length:4;
#endif
/* octet 4 */
- u32 length1:8;
+ u8 length1;
/* octet 5 - */
u8 icv[0];
diff --git a/src/pae/ieee802_1x_secy_ops.c b/src/pae/ieee802_1x_secy_ops.c
index fbe05dc..ab5339b 100644
--- a/src/pae/ieee802_1x_secy_ops.c
+++ b/src/pae/ieee802_1x_secy_ops.c
@@ -45,6 +45,26 @@
}
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->enable_encrypt) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy enable_encrypt operation not supported");
+ return -1;
+ }
+
+ return ops->enable_encrypt(ops->ctx, enabled);
+}
+
+
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean enabled, u32 win)
{
struct ieee802_1x_kay_ctx *ops;
@@ -65,8 +85,7 @@
}
-int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
- const u8 *cs, size_t cs_len)
+int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs)
{
struct ieee802_1x_kay_ctx *ops;
@@ -82,7 +101,7 @@
return -1;
}
- return ops->set_current_cipher_suite(ops->ctx, cs, cs_len);
+ return ops->set_current_cipher_suite(ops->ctx, cs);
}
@@ -114,6 +133,26 @@
}
+int secy_get_capability(struct ieee802_1x_kay *kay, enum macsec_cap *cap)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->macsec_get_capability) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy macsec_get_capability operation not supported");
+ return -1;
+ }
+
+ return ops->macsec_get_capability(ops->ctx, cap);
+}
+
+
int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
struct receive_sa *rxsa)
{
@@ -131,10 +170,7 @@
return -1;
}
- return ops->get_receive_lowest_pn(ops->ctx,
- rxsa->sc->channel,
- rxsa->an,
- &rxsa->lowest_pn);
+ return ops->get_receive_lowest_pn(ops->ctx, rxsa);
}
@@ -155,10 +191,7 @@
return -1;
}
- return ops->get_transmit_next_pn(ops->ctx,
- txsa->sc->channel,
- txsa->an,
- &txsa->next_pn);
+ return ops->get_transmit_next_pn(ops->ctx, txsa);
}
@@ -179,30 +212,7 @@
return -1;
}
- return ops->set_transmit_next_pn(ops->ctx,
- txsa->sc->channel,
- txsa->an,
- txsa->next_pn);
-}
-
-
-int secy_get_available_receive_sc(struct ieee802_1x_kay *kay, u32 *channel)
-{
- struct ieee802_1x_kay_ctx *ops;
-
- if (!kay) {
- wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
- return -1;
- }
-
- ops = kay->ctx;
- if (!ops || !ops->get_available_receive_sc) {
- wpa_printf(MSG_ERROR,
- "KaY: secy get_available_receive_sc operation not supported");
- return -1;
- }
-
- return ops->get_available_receive_sc(ops->ctx, channel);
+ return ops->set_transmit_next_pn(ops->ctx, txsa);
}
@@ -222,8 +232,7 @@
return -1;
}
- return ops->create_receive_sc(ops->ctx, rxsc->channel, &rxsc->sci,
- kay->vf, kay->co);
+ return ops->create_receive_sc(ops->ctx, rxsc, kay->vf, kay->co);
}
@@ -243,7 +252,7 @@
return -1;
}
- return ops->delete_receive_sc(ops->ctx, rxsc->channel);
+ return ops->delete_receive_sc(ops->ctx, rxsc);
}
@@ -263,8 +272,27 @@
return -1;
}
- return ops->create_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an,
- rxsa->lowest_pn, rxsa->pkey->key);
+ return ops->create_receive_sa(ops->ctx, rxsa);
+}
+
+
+int secy_delete_receive_sa(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->delete_receive_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy delete_receive_sa operation not supported");
+ return -1;
+ }
+
+ return ops->delete_receive_sa(ops->ctx, rxsa);
}
@@ -286,7 +314,7 @@
rxsa->enable_receive = TRUE;
- return ops->enable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
+ return ops->enable_receive_sa(ops->ctx, rxsa);
}
@@ -308,27 +336,7 @@
rxsa->enable_receive = FALSE;
- return ops->disable_receive_sa(ops->ctx, rxsa->sc->channel, rxsa->an);
-}
-
-
-int secy_get_available_transmit_sc(struct ieee802_1x_kay *kay, u32 *channel)
-{
- struct ieee802_1x_kay_ctx *ops;
-
- if (!kay) {
- wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
- return -1;
- }
-
- ops = kay->ctx;
- if (!ops || !ops->get_available_transmit_sc) {
- wpa_printf(MSG_ERROR,
- "KaY: secy get_available_transmit_sc operation not supported");
- return -1;
- }
-
- return ops->get_available_transmit_sc(ops->ctx, channel);
+ return ops->disable_receive_sa(ops->ctx, rxsa);
}
@@ -349,8 +357,7 @@
return -1;
}
- return ops->create_transmit_sc(ops->ctx, txsc->channel, &txsc->sci,
- kay->co);
+ return ops->create_transmit_sc(ops->ctx, txsc, kay->co);
}
@@ -371,7 +378,7 @@
return -1;
}
- return ops->delete_transmit_sc(ops->ctx, txsc->channel);
+ return ops->delete_transmit_sc(ops->ctx, txsc);
}
@@ -392,9 +399,28 @@
return -1;
}
- return ops->create_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an,
- txsa->next_pn, txsa->confidentiality,
- txsa->pkey->key);
+ return ops->create_transmit_sa(ops->ctx, txsa);
+}
+
+
+int secy_delete_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *txsa)
+{
+ struct ieee802_1x_kay_ctx *ops;
+
+ if (!kay || !txsa) {
+ wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__);
+ return -1;
+ }
+
+ ops = kay->ctx;
+ if (!ops || !ops->delete_transmit_sa) {
+ wpa_printf(MSG_ERROR,
+ "KaY: secy delete_transmit_sa operation not supported");
+ return -1;
+ }
+
+ return ops->delete_transmit_sa(ops->ctx, txsa);
}
@@ -417,7 +443,7 @@
txsa->enable_transmit = TRUE;
- return ops->enable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
+ return ops->enable_transmit_sa(ops->ctx, txsa);
}
@@ -440,7 +466,7 @@
txsa->enable_transmit = FALSE;
- return ops->disable_transmit_sa(ops->ctx, txsa->sc->channel, txsa->an);
+ return ops->disable_transmit_sa(ops->ctx, txsa);
}
diff --git a/src/pae/ieee802_1x_secy_ops.h b/src/pae/ieee802_1x_secy_ops.h
index 295b823..9fb29c3 100644
--- a/src/pae/ieee802_1x_secy_ops.h
+++ b/src/pae/ieee802_1x_secy_ops.h
@@ -13,10 +13,6 @@
#include "common/ieee802_1x_defs.h"
struct ieee802_1x_kay_conf;
-struct receive_sa;
-struct transmit_sa;
-struct receive_sc;
-struct transmit_sc;
int secy_init_macsec(struct ieee802_1x_kay *kay);
int secy_deinit_macsec(struct ieee802_1x_kay *kay);
@@ -25,35 +21,37 @@
int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay,
enum validate_frames vf);
int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, Boolean flag);
+int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, Boolean enabled);
int secy_cp_control_replay(struct ieee802_1x_kay *kay, Boolean flag, u32 win);
-int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay,
- const u8 *cs, size_t cs_len);
+int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs);
int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay,
enum confidentiality_offset co);
int secy_cp_control_enable_port(struct ieee802_1x_kay *kay, Boolean flag);
/****** KaY -> SecY *******/
+int secy_get_capability(struct ieee802_1x_kay *kay, enum macsec_cap *cap);
int secy_get_receive_lowest_pn(struct ieee802_1x_kay *kay,
struct receive_sa *rxsa);
int secy_get_transmit_next_pn(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
int secy_set_transmit_next_pn(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
-int secy_get_available_receive_sc(struct ieee802_1x_kay *kay, u32 *channel);
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);
+int secy_delete_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
int secy_enable_receive_sa(struct ieee802_1x_kay *kay, struct receive_sa *rxsa);
int secy_disable_receive_sa(struct ieee802_1x_kay *kay,
struct receive_sa *rxsa);
-int secy_get_available_transmit_sc(struct ieee802_1x_kay *kay, u32 *channel);
int secy_create_transmit_sc(struct ieee802_1x_kay *kay,
struct transmit_sc *txsc);
int secy_delete_transmit_sc(struct ieee802_1x_kay *kay,
struct transmit_sc *txsc);
int secy_create_transmit_sa(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
+int secy_delete_transmit_sa(struct ieee802_1x_kay *kay,
+ struct transmit_sa *txsa);
int secy_enable_transmit_sa(struct ieee802_1x_kay *kay,
struct transmit_sa *txsa);
int secy_disable_transmit_sa(struct ieee802_1x_kay *kay,
diff --git a/src/radius/radius.c b/src/radius/radius.c
index da978db..9ddc19b 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -210,7 +210,7 @@
{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
+ { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
RADIUS_ATTR_INT32 },
@@ -538,7 +538,8 @@
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
- size_t secret_len)
+ size_t secret_len,
+ int require_message_authenticator)
{
const u8 *addr[4];
size_t len[4];
@@ -577,7 +578,11 @@
}
if (attr == NULL) {
- /* Message-Authenticator is MAY; not required */
+ if (require_message_authenticator) {
+ wpa_printf(MSG_WARNING,
+ "Missing Message-Authenticator attribute in RADIUS message");
+ return 1;
+ }
return 0;
}
@@ -818,8 +823,9 @@
os_memcpy(msg->hdr->authenticator, req_auth,
sizeof(msg->hdr->authenticator));
}
- hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), auth);
+ if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), auth) < 0)
+ return 1;
os_memcpy(attr + 1, orig, MD5_MAC_LEN);
if (req_auth) {
os_memcpy(msg->hdr->authenticator, orig_authenticator,
@@ -862,8 +868,8 @@
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
- md5_vector(4, addr, len, hash);
- if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ if (md5_vector(4, addr, len, hash) < 0 ||
+ os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "Response Authenticator invalid!");
return 1;
}
@@ -1017,7 +1023,10 @@
addr[1] = pos - MD5_MAC_LEN;
elen[1] = MD5_MAC_LEN;
}
- md5_vector(first ? 3 : 2, addr, elen, hash);
+ if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) {
+ os_free(plain);
+ return NULL;
+ }
first = 0;
for (i = 0; i < MD5_MAC_LEN; i++)
@@ -1199,8 +1208,10 @@
vhdr = (struct radius_attr_vendor *) pos;
vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
pos = (u8 *) (vhdr + 1);
- if (os_get_random((u8 *) &salt, sizeof(salt)) < 0)
+ if (os_get_random((u8 *) &salt, sizeof(salt)) < 0) {
+ os_free(buf);
return 0;
+ }
salt |= 0x8000;
WPA_PUT_BE16(pos, salt);
pos += 2;
diff --git a/src/radius/radius.h b/src/radius/radius.h
index cba2b91..cd510d2 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -242,7 +242,8 @@
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
- size_t secret_len);
+ size_t secret_len,
+ int require_message_authenticator);
struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
const u8 *data, size_t data_len);
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index a4edd5f..06c804d 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1636,11 +1636,16 @@
int radius_client_get_mib(struct radius_client_data *radius, char *buf,
size_t buflen)
{
- struct hostapd_radius_servers *conf = radius->conf;
+ struct hostapd_radius_servers *conf;
int i;
struct hostapd_radius_server *serv;
int count = 0;
+ if (!radius)
+ return 0;
+
+ conf = radius->conf;
+
if (conf->auth_servers) {
for (i = 0; i < conf->num_auth_servers; i++) {
serv = &conf->auth_servers[i];
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index b7d991b..8a3d7e0 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -23,6 +23,7 @@
struct hostapd_ip_addr client_addr;
unsigned int time_window;
int require_event_timestamp;
+ int require_message_authenticator;
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);
@@ -234,9 +235,11 @@
radius_msg_dump(msg);
if (radius_msg_verify_das_req(msg, das->shared_secret,
- das->shared_secret_len)) {
- wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
- "from %s:%d - drop", abuf, from_port);
+ das->shared_secret_len,
+ das->require_message_authenticator)) {
+ wpa_printf(MSG_DEBUG,
+ "DAS: Invalid authenticator or Message-Authenticator in packet from %s:%d - drop",
+ abuf, from_port);
goto fail;
}
@@ -362,6 +365,8 @@
das->time_window = conf->time_window;
das->require_event_timestamp = conf->require_event_timestamp;
+ das->require_message_authenticator =
+ conf->require_message_authenticator;
das->ctx = conf->ctx;
das->disconnect = conf->disconnect;
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index ce731d4..9863fdc 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -44,6 +44,7 @@
const struct hostapd_ip_addr *client_addr;
unsigned int time_window;
int require_event_timestamp;
+ int require_message_authenticator;
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 744283c..e8bef45 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -26,9 +26,14 @@
#define RADIUS_SESSION_TIMEOUT 60
/**
+ * RADIUS_SESSION_MAINTAIN - Completed session expiration timeout in seconds
+ */
+#define RADIUS_SESSION_MAINTAIN 5
+
+/**
* RADIUS_MAX_SESSION - Maximum number of active sessions
*/
-#define RADIUS_MAX_SESSION 100
+#define RADIUS_MAX_SESSION 1000
/**
* RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
@@ -1057,7 +1062,7 @@
"message");
return -1;
}
-
+
eap = radius_msg_get_eap(msg);
if (eap == NULL && sess->macacl) {
reply = radius_server_macacl(data, client, sess, msg);
@@ -1172,7 +1177,7 @@
sess->sess_id);
eloop_cancel_timeout(radius_server_session_remove_timeout,
data, sess);
- eloop_register_timeout(10, 0,
+ eloop_register_timeout(RADIUS_SESSION_MAINTAIN, 0,
radius_server_session_remove_timeout,
data, sess);
}
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index 79764d9..ce338f8 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -65,10 +65,9 @@
{
size_t rlen;
struct wpa_eapol_key *err;
- struct wpa_eapol_key_192 *err192;
struct rsn_error_kde error;
- u8 *rbuf, *pos;
- size_t kde_len;
+ u8 *rbuf, *pos, *mic;
+ size_t kde_len, mic_len = 16;
u16 key_info;
kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
@@ -76,11 +75,11 @@
kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*err) + kde_len, &rlen,
- (void *) &err);
+ NULL, sizeof(*err) + mic_len + 2 + kde_len,
+ &rlen, (void *) &err);
if (rbuf == NULL)
return -1;
- err192 = (struct wpa_eapol_key_192 *) err;
+ mic = (u8 *) (err + 1);
err->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -92,8 +91,8 @@
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
- pos = (u8 *) (err + 1);
+ WPA_PUT_BE16(mic + mic_len, (u16) kde_len);
+ pos = mic + mic_len + 2;
if (peer) {
/* Peer MAC Address KDE */
@@ -114,8 +113,8 @@
"(mui %d error_type %d)", mui, error_type);
}
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
- ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
+ wpa_eapol_key_send(sm, &sm->ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen,
+ mic);
return 0;
}
@@ -128,9 +127,8 @@
{
size_t rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
- u8 *rbuf, *pos;
- size_t kde_len;
+ u8 *rbuf, *pos, *mic;
+ size_t kde_len, mic_len = 16;
u16 key_info;
/* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
@@ -139,11 +137,10 @@
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*reply) + kde_len, &rlen,
- (void *) &reply);
+ NULL, sizeof(*reply) + mic_len + 2 + kde_len,
+ &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -155,8 +152,9 @@
os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
- WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
- pos = (u8 *) (reply + 1);
+ mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(mic + mic_len, (u16) kde_len);
+ pos = mic + mic_len + 2;
/* Peer RSN IE */
pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
@@ -168,8 +166,8 @@
wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
- ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
+ wpa_eapol_key_send(sm, &sm->ptk, ver, src_addr, ETH_P_EAPOL, rbuf, rlen,
+ mic);
return 0;
}
@@ -177,7 +175,8 @@
static int wpa_supplicant_process_smk_m2(
struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key, size_t extra_len, int ver)
+ const struct wpa_eapol_key *key, const u8 *key_data,
+ size_t key_data_len, int ver)
{
struct wpa_peerkey *peerkey;
struct wpa_eapol_ie_parse kde;
@@ -194,8 +193,7 @@
return -1;
}
- if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
- 0) {
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
return -1;
}
@@ -324,18 +322,19 @@
{
size_t mlen;
struct wpa_eapol_key *msg;
- u8 *mbuf;
- size_t kde_len;
+ u8 *mbuf, *mic;
+ size_t kde_len, mic_len = 16;
u16 key_info, ver;
kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*msg) + kde_len, &mlen,
+ sizeof(*msg) + mic_len + 2 + kde_len, &mlen,
(void *) &msg);
if (mbuf == NULL)
return;
+ mic = (u8 *) (msg + 1);
msg->type = EAPOL_KEY_TYPE_RSN;
if (peerkey->cipher != WPA_CIPHER_TKIP)
@@ -355,8 +354,8 @@
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(msg->key_data_length, kde_len);
- wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
+ WPA_PUT_BE16(mic + mic_len, kde_len);
+ wpa_add_kde(mic + mic_len + 2, RSN_KEY_DATA_PMKID,
peerkey->smkid, PMKID_LEN);
if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
@@ -371,7 +370,7 @@
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
mbuf, mlen, NULL);
}
@@ -381,8 +380,8 @@
{
size_t mlen;
struct wpa_eapol_key *msg;
- u8 *mbuf, *pos;
- size_t kde_len;
+ u8 *mbuf, *pos, *mic;
+ size_t kde_len, mic_len = 16;
u16 key_info, ver;
be32 lifetime;
@@ -390,11 +389,12 @@
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*msg) + kde_len, &mlen,
+ sizeof(*msg) + mic_len + 2 + kde_len, &mlen,
(void *) &msg);
if (mbuf == NULL)
return;
+ mic = (u8 *) (msg + 1);
msg->type = EAPOL_KEY_TYPE_RSN;
if (peerkey->cipher != WPA_CIPHER_TKIP)
@@ -415,8 +415,8 @@
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(msg->key_data_length, kde_len);
- pos = (u8 *) (msg + 1);
+ WPA_PUT_BE16(mic + mic_len, kde_len);
+ pos = mic + mic_len + 2;
pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
lifetime = host_to_be32(peerkey->lifetime);
wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
@@ -426,9 +426,8 @@
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
- peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
- msg->key_mic);
+ wpa_eapol_key_send(sm, &peerkey->stk, ver, peerkey->addr, ETH_P_EAPOL,
+ mbuf, mlen, mic);
}
@@ -512,7 +511,8 @@
static int wpa_supplicant_process_smk_m45(
struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key, size_t extra_len, int ver)
+ const struct wpa_eapol_key *key, const u8 *key_data,
+ size_t key_data_len, int ver)
{
struct wpa_peerkey *peerkey;
struct wpa_eapol_ie_parse kde;
@@ -524,8 +524,7 @@
return -1;
}
- if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
- 0) {
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
return -1;
}
@@ -591,7 +590,7 @@
static int wpa_supplicant_process_smk_error(
struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key, size_t extra_len)
+ const u8 *key_data, size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
struct rsn_error_kde error;
@@ -606,8 +605,7 @@
return -1;
}
- if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
- 0) {
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
return -1;
}
@@ -717,7 +715,8 @@
if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
peerkey->pnonce, kde_buf, kde_buf_len,
- stk)) {
+ stk) < 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to send STK message 2/4");
os_free(kde_buf);
return;
}
@@ -845,6 +844,10 @@
"4-Way Handshake differs from 3 of STK 4-Way "
"Handshake - drop packet (src=" MACSTR ")",
MAC2STR(peerkey->addr));
+ wpa_hexdump(MSG_DEBUG, "RSN: INonce from message 1",
+ peerkey->inonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "RSN: INonce from message 3",
+ key->key_nonce, WPA_NONCE_LEN);
return;
}
@@ -852,8 +855,10 @@
if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
WPA_GET_BE16(key->key_info),
- &peerkey->stk))
+ &peerkey->stk) < 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to send STK message 4/4");
return;
+ }
_key = peerkey->stk.tk;
if (peerkey->cipher == WPA_CIPHER_TKIP) {
@@ -911,10 +916,10 @@
*/
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key_192 *key, u16 ver,
+ struct wpa_eapol_key *key, u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN], *mic_pos;
size_t mic_len = 16;
int ok = 0;
@@ -926,12 +931,13 @@
peerkey->stk_set = 1;
}
- os_memcpy(mic, key->key_mic, mic_len);
+ mic_pos = (u8 *) (key + 1);
+ os_memcpy(mic, mic_pos, mic_len);
if (peerkey->tstk_set) {
- os_memset(key->key_mic, 0, mic_len);
+ os_memset(mic_pos, 0, mic_len);
wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
- sm->key_mgmt, ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
+ sm->key_mgmt, ver, buf, len, mic_pos);
+ if (os_memcmp_const(mic, mic_pos, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"when using TSTK - ignoring TSTK");
} else {
@@ -945,10 +951,10 @@
}
if (!ok && peerkey->stk_set) {
- os_memset(key->key_mic, 0, mic_len);
+ os_memset(mic_pos, 0, mic_len);
wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
- sm->key_mgmt, ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
+ sm->key_mgmt, ver, buf, len, mic_pos);
+ if (os_memcmp_const(mic, mic_pos, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"- dropping packet");
return -1;
@@ -980,10 +986,10 @@
*/
int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
{
- size_t rlen, kde_len;
+ size_t rlen, kde_len, mic_len;
struct wpa_eapol_key *req;
int key_info, ver;
- u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
+ u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos, *mic;
u16 count;
struct rsn_ie_hdr *hdr;
struct wpa_peerkey *peerkey;
@@ -999,6 +1005,7 @@
return -1;
}
+ mic_len = wpa_mic_len(sm->key_mgmt);
if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
@@ -1047,7 +1054,7 @@
kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*req) + kde_len, &rlen,
+ sizeof(*req) + mic_len + 2 + kde_len, &rlen,
(void *) &req);
if (rbuf == NULL) {
wpa_supplicant_peerkey_free(sm, peerkey);
@@ -1074,8 +1081,10 @@
wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
req->key_nonce, WPA_NONCE_LEN);
- WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
- pos = (u8 *) (req + 1);
+ mic = pos = (u8 *) (req + 1);
+ pos += mic_len;
+ WPA_PUT_BE16(pos, (u16) kde_len);
+ pos += 2;
/* Initiator RSN IE */
pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
@@ -1084,8 +1093,8 @@
wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
MACSTR ")", MAC2STR(peer));
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
- ETH_P_EAPOL, rbuf, rlen, req->key_mic);
+ wpa_eapol_key_send(sm, &sm->ptk, ver, bssid, ETH_P_EAPOL, rbuf, rlen,
+ mic);
peerkey->next = sm->peerkey;
sm->peerkey = peerkey;
@@ -1135,20 +1144,22 @@
void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
- struct wpa_eapol_key *key, size_t extra_len,
+ struct wpa_eapol_key *key, const u8 *key_data,
+ size_t key_data_len,
u16 key_info, u16 ver)
{
if (key_info & WPA_KEY_INFO_ERROR) {
/* SMK Error */
- wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
+ wpa_supplicant_process_smk_error(sm, src_addr, key_data,
+ key_data_len);
} else if (key_info & WPA_KEY_INFO_ACK) {
/* SMK M2 */
- wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
- ver);
+ wpa_supplicant_process_smk_m2(sm, src_addr, key, key_data,
+ key_data_len, ver);
} else {
/* SMK M4 or M5 */
- wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
- ver);
+ wpa_supplicant_process_smk_m45(sm, src_addr, key, key_data,
+ key_data_len, ver);
}
}
diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
index 6ccd948..02e12e9 100644
--- a/src/rsn_supp/peerkey.h
+++ b/src/rsn_supp/peerkey.h
@@ -38,14 +38,14 @@
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key_192 *key, u16 ver,
+ struct wpa_eapol_key *key, u16 ver,
const u8 *buf, size_t len);
void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
struct wpa_eapol_key *key, u16 key_info, u16 ver,
const u8 *key_data, size_t key_data_len);
void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
- struct wpa_eapol_key *key, size_t extra_len,
- u16 key_info, u16 ver);
+ struct wpa_eapol_key *key, const u8 *key_data,
+ size_t key_data_len, u16 key_info, u16 ver);
void peerkey_deinit(struct wpa_sm *sm);
#else /* CONFIG_PEERKEY */
@@ -68,8 +68,8 @@
static inline void
peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
- struct wpa_eapol_key *key, size_t extra_len,
- u16 key_info, u16 ver)
+ struct wpa_eapol_key *key, const u8 *key_data,
+ size_t key_data_len, u16 key_info, u16 ver)
{
}
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 3d8d122..f723bb0 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -43,7 +43,8 @@
struct rsn_pmksa_cache_entry *entry,
enum pmksa_free_reason reason)
{
- wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+ wpa_sm_remove_pmkid(pmksa->sm, entry->network_ctx, entry->aa,
+ entry->pmkid);
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx, reason);
_pmksa_cache_free_entry(entry);
@@ -128,7 +129,7 @@
const u8 *pmkid, const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
- struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+ struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
if (pmk_len > PMK_LEN_MAX)
@@ -159,14 +160,25 @@
os_memcpy(entry->aa, aa, ETH_ALEN);
entry->network_ctx = network_ctx;
+ return pmksa_cache_add_entry(pmksa, entry);
+}
+
+
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ struct rsn_pmksa_cache_entry *pos, *prev;
+
/* Replace an old entry for the same Authenticator (if found) with the
* new entry */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
- if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
- if (pos->pmk_len == pmk_len &&
- os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
+ if (os_memcmp(entry->aa, pos->aa, ETH_ALEN) == 0) {
+ if (pos->pmk_len == entry->pmk_len &&
+ os_memcmp_const(pos->pmk, entry->pmk,
+ entry->pmk_len) == 0 &&
os_memcmp_const(pos->pmkid, entry->pmkid,
PMKID_LEN) == 0) {
wpa_printf(MSG_DEBUG, "WPA: reusing previous "
@@ -192,8 +204,8 @@
"the current AP and any PMKSA cache entry "
"that was based on the old PMK");
if (!pos->opportunistic)
- pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
- pos->pmk_len);
+ pmksa_cache_flush(pmksa, entry->network_ctx,
+ pos->pmk, pos->pmk_len);
pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
break;
}
@@ -244,8 +256,9 @@
}
pmksa->pmksa_count++;
wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
- " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
- wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+ " network_ctx=%p", MAC2STR(entry->aa), entry->network_ctx);
+ wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa,
+ entry->pmkid);
return entry;
}
@@ -513,6 +526,12 @@
}
+struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa->pmksa;
+}
+
+
/**
* pmksa_cache_init - Initialize PMKSA cache
* @free_cb: Callback function to be called when a PMKSA cache entry is freed
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index daede6d..adc251a 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -55,10 +55,14 @@
const u8 *aa, const u8 *pmkid,
const void *network_ctx);
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *pmkid, const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
@@ -104,6 +108,19 @@
}
static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
+{
+ return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *pmkid, const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 4c9a4fb..e83d073 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -342,7 +342,7 @@
/* Some drivers (e.g., NDIS) expect to get notified about the
* PMKIDs again, so report the existing data now. */
if (p) {
- wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
+ wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid);
}
dl_list_del(&candidate->list);
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 9eb9738..c2ed952 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1220,9 +1220,10 @@
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_DIFF_BSSID) {
+ struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
+
wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in "
"Link Identifier");
- struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos;
wpa_tdls_linkid(sm, peer, l);
l->bssid[5] ^= 0x01;
pos += sizeof(*l);
@@ -2912,14 +2913,14 @@
static int wpa_tdls_prohibited(struct ieee802_11_elems *elems)
{
/* bit 38 - TDLS Prohibited */
- return !!(elems->ext_capab[2 + 4] & 0x40);
+ return !!(elems->ext_capab[4] & 0x40);
}
static int wpa_tdls_chan_switch_prohibited(struct ieee802_11_elems *elems)
{
/* bit 39 - TDLS Channel Switch Prohibited */
- return !!(elems->ext_capab[2 + 4] & 0x80);
+ return !!(elems->ext_capab[4] & 0x80);
}
@@ -2932,7 +2933,7 @@
if (ies == NULL ||
ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed ||
- elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ elems.ext_capab == NULL || elems.ext_capab_len < 5)
return;
sm->tdls_prohibited = wpa_tdls_prohibited(&elems);
@@ -2951,7 +2952,7 @@
if (ies == NULL ||
ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed ||
- elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ elems.ext_capab == NULL || elems.ext_capab_len < 5)
return;
if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) {
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 441c856..8153f79 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -10,10 +10,14 @@
#include "includes.h"
#include "common.h"
+#include "crypto/aes.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
+#include "crypto/aes_siv.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "wpa.h"
#include "eloop.h"
@@ -30,8 +34,7 @@
/**
* wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
* @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @kck: Key Confirmation Key (KCK, part of PTK)
- * @kck_len: KCK length in octets
+ * @ptk: PTK for Key Confirmation/Encryption Key
* @ver: Version field from Key Info
* @dest: Destination address for the frame
* @proto: Ethertype (usually ETH_P_EAPOL)
@@ -40,7 +43,7 @@
* @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
* Returns: >= 0 on success, < 0 on failure
*/
-int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
+int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic)
{
@@ -64,16 +67,89 @@
MAC2STR(dest));
}
}
- if (key_mic &&
- wpa_eapol_key_mic(kck, kck_len, sm->key_mgmt, ver, msg, msg_len,
- key_mic)) {
- wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
- "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
- ver, sm->key_mgmt);
+
+ if (mic_len) {
+ if (key_mic && (!ptk || !ptk->kck_len))
+ goto out;
+
+ if (key_mic &&
+ wpa_eapol_key_mic(ptk->kck, ptk->kck_len, sm->key_mgmt, ver,
+ msg, msg_len, key_mic)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+ "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+ ver, sm->key_mgmt);
+ goto out;
+ }
+ if (ptk)
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK",
+ ptk->kck, ptk->kck_len);
+ wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC",
+ key_mic, mic_len);
+ } else {
+#ifdef CONFIG_FILS
+ /* AEAD cipher - Key MIC field not used */
+ struct ieee802_1x_hdr *s_hdr, *hdr;
+ struct wpa_eapol_key *s_key, *key;
+ u8 *buf, *s_key_data, *key_data;
+ size_t buf_len = msg_len + AES_BLOCK_SIZE;
+ size_t key_data_len;
+ u16 eapol_len;
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ if (!ptk || !ptk->kek_len)
+ goto out;
+
+ key_data_len = msg_len - sizeof(struct ieee802_1x_hdr) -
+ sizeof(struct wpa_eapol_key) - 2;
+
+ buf = os_malloc(buf_len);
+ if (!buf)
+ goto out;
+
+ os_memcpy(buf, msg, msg_len);
+ hdr = (struct ieee802_1x_hdr *) buf;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ key_data = ((u8 *) (key + 1)) + 2;
+
+ /* Update EAPOL header to include AES-SIV overhead */
+ eapol_len = be_to_host16(hdr->length);
+ eapol_len += AES_BLOCK_SIZE;
+ hdr->length = host_to_be16(eapol_len);
+
+ /* Update Key Data Length field to include AES-SIV overhead */
+ WPA_PUT_BE16((u8 *) (key + 1), AES_BLOCK_SIZE + key_data_len);
+
+ s_hdr = (struct ieee802_1x_hdr *) msg;
+ s_key = (struct wpa_eapol_key *) (s_hdr + 1);
+ s_key_data = ((u8 *) (s_key + 1)) + 2;
+
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Plaintext Key Data",
+ s_key_data, key_data_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = buf;
+ aad_len[0] = key_data - buf;
+ if (aes_siv_encrypt(ptk->kek, ptk->kek_len,
+ s_key_data, key_data_len,
+ 1, aad, aad_len, key_data) < 0) {
+ os_free(buf);
+ goto out;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "WPA: Encrypted Key Data from SIV",
+ key_data, AES_BLOCK_SIZE + key_data_len);
+
+ os_free(msg);
+ msg = buf;
+ msg_len = buf_len;
+#else /* CONFIG_FILS */
goto out;
+#endif /* CONFIG_FILS */
}
- wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
- wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
+
wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
ret = wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
eapol_sm_notify_tx_eapol_key(sm->eapol);
@@ -97,9 +173,8 @@
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
int key_info, ver;
- u8 bssid[ETH_ALEN], *rbuf, *key_mic;
+ u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->key_mgmt))
@@ -119,19 +194,20 @@
}
mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return;
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
if (sm->ptk_set)
- key_info |= WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+ key_info |= WPA_KEY_INFO_SECURE;
+ if (sm->ptk_set && mic_len)
+ key_info |= WPA_KEY_INFO_MIC;
if (error)
key_info |= WPA_KEY_INFO_ERROR;
if (pairwise)
@@ -142,21 +218,19 @@
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
- if (mic_len == 24)
- WPA_PUT_BE16(reply192->key_data_length, 0);
- else
- WPA_PUT_BE16(reply->key_data_length, 0);
+ mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(mic + mic_len, 0);
if (!(key_info & WPA_KEY_INFO_MIC))
key_mic = NULL;
else
- key_mic = reply192->key_mic; /* same offset in reply */
+ key_mic = mic;
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Sending EAPOL-Key Request (error=%d "
"pairwise=%d ptk_set=%d len=%lu)",
error, pairwise, sm->ptk_set, (unsigned long) rlen);
- wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
- ETH_P_EAPOL, rbuf, rlen, key_mic);
+ wpa_eapol_key_send(sm, &sm->ptk, ver, bssid, ETH_P_EAPOL, rbuf, rlen,
+ key_mic);
}
@@ -214,7 +288,7 @@
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
int res, pmk_len;
- if (sm->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (wpa_key_mgmt_sha384(sm->key_mgmt))
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
@@ -341,9 +415,9 @@
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *key_mic;
u8 *rsn_ie_buf = NULL;
+ u16 key_info;
if (wpa_ie == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - "
@@ -384,7 +458,7 @@
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
NULL, hdrlen + wpa_ie_len,
&rlen, (void *) &reply);
@@ -392,13 +466,16 @@
os_free(rsn_ie_buf);
return -1;
}
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
- WPA_PUT_BE16(reply->key_info,
- ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
+ key_info = ver | WPA_KEY_INFO_KEY_TYPE;
+ if (mic_len)
+ key_info |= WPA_KEY_INFO_MIC;
+ else
+ key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+ WPA_PUT_BE16(reply->key_info, key_info);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
@@ -408,21 +485,16 @@
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- key_mic = reply192->key_mic; /* same offset for reply and reply192 */
- if (mic_len == 24) {
- WPA_PUT_BE16(reply192->key_data_length, wpa_ie_len);
- os_memcpy(reply192 + 1, wpa_ie, wpa_ie_len);
- } else {
- WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
- os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
- }
+ key_mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len); /* Key Data Length */
+ os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */
os_free(rsn_ie_buf);
os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst,
- ETH_P_EAPOL, rbuf, rlen, key_mic);
+ return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen,
+ key_mic);
}
@@ -1203,22 +1275,24 @@
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *key_mic;
mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_SECURE;
- key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
+ key_info |= ver | WPA_KEY_INFO_KEY_TYPE;
+ if (mic_len)
+ key_info |= WPA_KEY_INFO_MIC;
+ else
+ key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
WPA_PUT_BE16(reply->key_info, key_info);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
@@ -1227,15 +1301,12 @@
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- key_mic = reply192->key_mic; /* same offset for reply and reply192 */
- if (mic_len == 24)
- WPA_PUT_BE16(reply192->key_data_length, 0);
- else
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(key_mic + mic_len, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- return wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst,
- ETH_P_EAPOL, rbuf, rlen, key_mic);
+ return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen,
+ key_mic);
}
@@ -1378,7 +1449,8 @@
int maxkeylen;
struct wpa_eapol_ie_parse ie;
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
+ wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data",
+ keydata, keydatalen);
if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
return -1;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
@@ -1512,22 +1584,22 @@
{
size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *key_mic;
mic_len = wpa_mic_len(sm->key_mgmt);
- hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
+ hdrlen = sizeof(*reply) + mic_len + 2;
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
- reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
- key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+ key_info |= ver | WPA_KEY_INFO_SECURE;
+ if (mic_len)
+ key_info |= WPA_KEY_INFO_MIC;
WPA_PUT_BE16(reply->key_info, key_info);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
@@ -1536,15 +1608,12 @@
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- key_mic = reply192->key_mic; /* same offset for reply and reply192 */
- if (mic_len == 24)
- WPA_PUT_BE16(reply192->key_data_length, 0);
- else
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = (u8 *) (reply + 1);
+ WPA_PUT_BE16(key_mic + mic_len, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- return wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver,
- sm->bssid, ETH_P_EAPOL, rbuf, rlen, key_mic);
+ return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
}
@@ -1620,7 +1689,7 @@
static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_eapol_key_192 *key,
+ struct wpa_eapol_key *key,
u16 ver,
const u8 *buf, size_t len)
{
@@ -1628,12 +1697,12 @@
int ok = 0;
size_t mic_len = wpa_mic_len(sm->key_mgmt);
- os_memcpy(mic, key->key_mic, mic_len);
+ os_memcpy(mic, key + 1, mic_len);
if (sm->tptk_set) {
- os_memset(key->key_mic, 0, mic_len);
+ os_memset(key + 1, 0, mic_len);
wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len, sm->key_mgmt,
- ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
+ ver, buf, len, (u8 *) (key + 1));
+ if (os_memcmp_const(mic, key + 1, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
@@ -1647,10 +1716,10 @@
}
if (!ok && sm->ptk_set) {
- os_memset(key->key_mic, 0, mic_len);
+ os_memset(key + 1, 0, mic_len);
wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len, sm->key_mgmt,
- ver, buf, len, key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
+ ver, buf, len, (u8 *) (key + 1));
+ if (os_memcmp_const(mic, key + 1, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
@@ -1675,7 +1744,8 @@
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key *key,
+ size_t mic_len, u16 ver,
u8 *key_data, size_t *key_data_len)
{
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
@@ -1734,7 +1804,7 @@
}
os_memcpy(key_data, buf, *key_data_len);
bin_clear_free(buf, *key_data_len);
- WPA_PUT_BE16(key->key_data_length, *key_data_len);
+ WPA_PUT_BE16(((u8 *) (key + 1)) + mic_len, *key_data_len);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported key_info type %d", ver);
@@ -1797,6 +1867,76 @@
}
+#ifdef CONFIG_FILS
+static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len,
+ size_t *key_data_len)
+{
+ struct wpa_ptk *ptk;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ u8 *pos, *tmp;
+ const u8 *aad[1];
+ size_t aad_len[1];
+
+ if (*key_data_len < AES_BLOCK_SIZE) {
+ wpa_printf(MSG_INFO, "No room for AES-SIV data in the frame");
+ return -1;
+ }
+
+ if (sm->tptk_set)
+ ptk = &sm->tptk;
+ else if (sm->ptk_set)
+ ptk = &sm->ptk;
+ else
+ return -1;
+
+ hdr = (struct ieee802_1x_hdr *) buf;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ pos = (u8 *) (key + 1);
+ pos += 2; /* Pointing at the Encrypted Key Data field */
+
+ tmp = os_malloc(*key_data_len);
+ if (!tmp)
+ return -1;
+
+ /* AES-SIV AAD from EAPOL protocol version field (inclusive) to
+ * to Key Data (exclusive). */
+ aad[0] = buf;
+ aad_len[0] = pos - buf;
+ if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, *key_data_len,
+ 1, aad, aad_len, tmp) < 0) {
+ wpa_printf(MSG_INFO, "Invalid AES-SIV data in the frame");
+ bin_clear_free(tmp, *key_data_len);
+ return -1;
+ }
+
+ /* AEAD decryption and validation completed successfully */
+ (*key_data_len) -= AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Decrypted Key Data",
+ tmp, *key_data_len);
+
+ /* Replace Key Data field with the decrypted version */
+ os_memcpy(pos, tmp, *key_data_len);
+ pos -= 2; /* Key Data Length field */
+ WPA_PUT_BE16(pos, *key_data_len);
+ bin_clear_free(tmp, *key_data_len);
+
+ if (sm->tptk_set) {
+ sm->tptk_set = 0;
+ sm->ptk_set = 1;
+ os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+ }
+
+ os_memcpy(sm->rx_replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ sm->rx_replay_counter_set = 1;
+
+ return 0;
+}
+#endif /* CONFIG_FILS */
+
+
/**
* wpa_sm_rx_eapol - Process received WPA EAPOL frames
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -1819,12 +1959,11 @@
size_t plen, data_len, key_data_len;
const struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- struct wpa_eapol_key_192 *key192;
u16 key_info, ver;
u8 *tmp = NULL;
int ret = -1;
struct wpa_peerkey *peerkey = NULL;
- u8 *key_data;
+ u8 *mic, *key_data;
size_t mic_len, keyhdrlen;
#ifdef CONFIG_IEEE80211R
@@ -1832,7 +1971,7 @@
#endif /* CONFIG_IEEE80211R */
mic_len = wpa_mic_len(sm->key_mgmt);
- keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+ keyhdrlen = sizeof(*key) + mic_len + 2;
if (len < sizeof(*hdr) + keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -1884,12 +2023,8 @@
goto out;
os_memcpy(tmp, buf, data_len);
key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
- key192 = (struct wpa_eapol_key_192 *)
- (tmp + sizeof(struct ieee802_1x_hdr));
- if (mic_len == 24)
- key_data = (u8 *) (key192 + 1);
- else
- key_data = (u8 *) (key + 1);
+ mic = (u8 *) (key + 1);
+ key_data = mic + mic_len + 2;
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1900,11 +2035,8 @@
goto out;
}
- if (mic_len == 24)
- key_data_len = WPA_GET_BE16(key192->key_data_length);
- else
- key_data_len = WPA_GET_BE16(key->key_data_length);
- wpa_eapol_key_dump(sm, key, key_data_len, key192->key_mic, mic_len);
+ key_data_len = WPA_GET_BE16(mic + mic_len);
+ wpa_eapol_key_dump(sm, key, key_data_len, mic, mic_len);
if (key_data_len > plen - keyhdrlen) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
@@ -1923,6 +2055,7 @@
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_key_mgmt_fils(sm->key_mgmt) &&
sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
@@ -1938,7 +2071,8 @@
goto out;
}
- if (wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ if ((wpa_key_mgmt_suite_b(sm->key_mgmt) ||
+ wpa_key_mgmt_fils(sm->key_mgmt)) &&
ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
@@ -1960,6 +2094,7 @@
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
+ !wpa_key_mgmt_fils(sm->key_mgmt) &&
!wpa_key_mgmt_suite_b(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
@@ -1970,6 +2105,7 @@
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_key_mgmt_fils(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@@ -2060,19 +2196,27 @@
}
if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
- wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
+ wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
goto out;
#ifdef CONFIG_PEERKEY
if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
- peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
+ peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp,
data_len))
goto out;
#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_FILS
+ if (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ if (wpa_supp_aead_decrypt(sm, tmp, data_len, &key_data_len))
+ goto out;
+ }
+#endif /* CONFIG_FILS */
+
if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
- (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
+ (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && mic_len) {
+ if (wpa_supplicant_decrypt_key_data(sm, key, mic_len,
+ ver, key_data,
&key_data_len))
goto out;
}
@@ -2088,7 +2232,8 @@
/* PeerKey 4-Way Handshake */
peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
key_data, key_data_len);
- } else if (key_info & WPA_KEY_INFO_MIC) {
+ } else if (key_info & (WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ENCR_KEY_DATA)) {
/* 3/4 4-Way Handshake */
wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
key_data_len);
@@ -2100,17 +2245,18 @@
}
} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
/* PeerKey SMK Handshake */
- peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
- ver);
+ peerkey_rx_eapol_smk(sm, src_addr, key, key_data, key_data_len,
+ key_info, ver);
} else {
- if (key_info & WPA_KEY_INFO_MIC) {
+ if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
+ (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) {
/* 1/2 Group Key Handshake */
wpa_supplicant_process_1_of_2(sm, src_addr, key,
key_data, key_data_len,
ver);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: EAPOL-Key (Group) without Mic bit - "
+ "WPA: EAPOL-Key (Group) without Mic/Encr bit - "
"dropped");
}
}
@@ -2392,6 +2538,16 @@
clear_keys = 0;
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_FILS
+ if (sm->fils_completed) {
+ /*
+ * Clear portValid to kick EAPOL state machine to re-enter
+ * AUTHENTICATED state to get the EAPOL port Authorized.
+ */
+ wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
+ clear_keys = 0;
+ }
+#endif /* CONFIG_FILS */
if (clear_keys) {
/*
@@ -2440,9 +2596,13 @@
#ifdef CONFIG_TDLS
wpa_tdls_disassoc(sm);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_FILS
+ sm->fils_completed = 0;
+#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
sm->ft_reassoc_completed = 0;
#endif /* CONFIG_IEEE80211R */
+
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
@@ -2790,6 +2950,10 @@
os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
sm->assoc_wpa_ie_len = *wpa_ie_len;
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Leave previously set WPA IE default",
+ sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
}
return 0;
@@ -2933,6 +3097,20 @@
}
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm)
+{
+ return pmksa_cache_head(sm->pmksa);
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm,
+ struct rsn_pmksa_cache_entry * entry)
+{
+ return pmksa_cache_add_entry(sm->pmksa, entry);
+}
+
+
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
@@ -3106,3 +3284,570 @@
sm->test_assoc_ie = buf;
}
#endif /* CONFIG_TESTING_OPTIONS */
+
+
+#ifdef CONFIG_FILS
+
+struct wpabuf * fils_build_auth(struct wpa_sm *sm)
+{
+ struct wpabuf *buf = NULL;
+ struct wpabuf *erp_msg;
+
+ erp_msg = eapol_sm_build_erp_reauth_start(sm->eapol);
+ if (!erp_msg && !sm->cur_pmksa) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Neither ERP EAP-Initiate/Re-auth nor PMKSA cache entry is available - skip FILS");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "FILS: Try to use FILS (erp=%d pmksa_cache=%d)",
+ erp_msg != NULL, sm->cur_pmksa != NULL);
+
+ sm->fils_completed = 0;
+
+ if (!sm->assoc_wpa_ie) {
+ wpa_printf(MSG_INFO, "FILS: No own RSN IE set for FILS");
+ goto fail;
+ }
+
+ if (random_get_bytes(sm->fils_nonce, FILS_NONCE_LEN) < 0 ||
+ random_get_bytes(sm->fils_session, FILS_SESSION_LEN) < 0)
+ goto fail;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Generated FILS Nonce",
+ sm->fils_nonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: Generated FILS Session",
+ sm->fils_session, FILS_SESSION_LEN);
+
+ buf = wpabuf_alloc(1000 + sm->assoc_wpa_ie_len);
+ if (!buf)
+ goto fail;
+
+ /* Fields following the Authentication algorithm number field */
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 1);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* TODO: Finite Cyclic Group when using PK or PFS */
+ /* TODO: Element when using PK or PFS */
+
+ /* RSNE */
+ wpa_hexdump(MSG_DEBUG, "FILS: RSNE in FILS Authentication frame",
+ sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
+ wpabuf_put_data(buf, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len);
+
+ /* TODO: MDE when using FILS for FT initial association */
+ /* TODO: FTE when using FILS for FT initial association */
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, sm->fils_nonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
+
+ /* FILS Wrapped Data */
+ sm->fils_erp_pmkid_set = 0;
+ if (erp_msg) {
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
+ wpabuf_put_buf(buf, erp_msg);
+ /* Calculate pending PMKID here so that we do not need to
+ * maintain a copy of the EAP-Initiate/Reauth message. */
+ if (fils_pmkid_erp(sm->key_mgmt, wpabuf_head(erp_msg),
+ wpabuf_len(erp_msg),
+ sm->fils_erp_pmkid) == 0)
+ sm->fils_erp_pmkid_set = 1;
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG, "RSN: FILS fields for Authentication frame",
+ buf);
+
+fail:
+ wpabuf_free(erp_msg);
+ return buf;
+}
+
+
+int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len)
+{
+ const u8 *pos, *end;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsn;
+ int pmkid_match = 0;
+ u8 ick[FILS_ICK_MAX_LEN];
+ size_t ick_len;
+ int res;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
+ data, len);
+ pos = data;
+ end = data + len;
+
+ /* TODO: Finite Cyclic Group when using PK or PFS */
+ /* TODO: Element when using PK or PFS */
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
+ if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "FILS: Could not parse elements");
+ return -1;
+ }
+
+ /* RSNE */
+ wpa_hexdump(MSG_DEBUG, "FILS: RSN element", elems.rsn_ie,
+ elems.rsn_ie_len);
+ if (!elems.rsn_ie ||
+ wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: No RSN element");
+ return -1;
+ }
+
+ if (!elems.fils_nonce) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
+ return -1;
+ }
+ os_memcpy(sm->fils_anonce, elems.fils_nonce, FILS_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce", sm->fils_anonce, FILS_NONCE_LEN);
+
+ /* TODO: MDE when using FILS+FT */
+ /* TODO: FTE when using FILS+FT */
+
+ /* PMKID List */
+ if (rsn.pmkid && rsn.num_pmkid > 0) {
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID List",
+ rsn.pmkid, rsn.num_pmkid * PMKID_LEN);
+
+ if (rsn.num_pmkid != 1) {
+ wpa_printf(MSG_DEBUG, "FILS: Invalid PMKID selection");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", rsn.pmkid, PMKID_LEN);
+ if (os_memcmp(sm->cur_pmksa->pmkid, rsn.pmkid, PMKID_LEN) != 0)
+ {
+ wpa_printf(MSG_DEBUG, "FILS: PMKID mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected PMKID",
+ sm->cur_pmksa->pmkid, PMKID_LEN);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "FILS: Matching PMKID - continue using PMKSA caching");
+ pmkid_match = 1;
+ }
+ if (!pmkid_match && sm->cur_pmksa) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No PMKID match - cannot use cached PMKSA entry");
+ sm->cur_pmksa = NULL;
+ }
+
+ /* FILS Session */
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ if (os_memcmp(sm->fils_session, elems.fils_session, FILS_SESSION_LEN)
+ != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+ sm->fils_session, FILS_SESSION_LEN);
+ return -1;
+ }
+
+ /* FILS Wrapped Data */
+ if (!sm->cur_pmksa && elems.fils_wrapped_data) {
+ u8 rmsk[ERP_MAX_KEY_LEN];
+ size_t rmsk_len;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
+ elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data,
+ elems.fils_wrapped_data_len);
+ if (eapol_sm_failed(sm->eapol))
+ return -1;
+
+ rmsk_len = ERP_MAX_KEY_LEN;
+ res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
+ if (res == PMK_LEN) {
+ rmsk_len = PMK_LEN;
+ res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
+ }
+ if (res)
+ return -1;
+
+ res = fils_rmsk_to_pmk(sm->key_mgmt, rmsk, rmsk_len,
+ sm->fils_nonce, sm->fils_anonce, NULL, 0,
+ sm->pmk, &sm->pmk_len);
+ os_memset(rmsk, 0, sizeof(rmsk));
+ if (res)
+ return -1;
+
+ if (!sm->fils_erp_pmkid_set) {
+ wpa_printf(MSG_DEBUG, "FILS: PMKID not available");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "FILS: PMKID", sm->fils_erp_pmkid,
+ PMKID_LEN);
+ wpa_printf(MSG_DEBUG, "FILS: ERP processing succeeded - add PMKSA cache entry for the result");
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sm->fils_erp_pmkid, NULL, 0,
+ sm->bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ }
+
+ if (!sm->cur_pmksa) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No remaining options to continue FILS authentication");
+ return -1;
+ }
+
+ if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid,
+ sm->fils_nonce, sm->fils_anonce, &sm->ptk,
+ ick, &ick_len, sm->key_mgmt, sm->pairwise_cipher) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK");
+ return -1;
+ }
+ sm->ptk_set = 1;
+ sm->tptk_set = 0;
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+
+ res = fils_key_auth_sk(ick, ick_len, sm->fils_nonce,
+ sm->fils_anonce, sm->own_addr, sm->bssid,
+ NULL, 0, NULL, 0, /* TODO: SK+PFS */
+ sm->key_mgmt, sm->fils_key_auth_sta,
+ sm->fils_key_auth_ap,
+ &sm->fils_key_auth_len);
+ os_memset(ick, 0, sizeof(ick));
+ return res;
+}
+
+
+struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
+ size_t *kek_len, const u8 **snonce,
+ const u8 **anonce,
+ const struct wpabuf **hlp,
+ unsigned int num_hlp)
+{
+ struct wpabuf *buf;
+ size_t len;
+ unsigned int i;
+
+ len = 1000;
+ for (i = 0; hlp && i < num_hlp; i++)
+ len += 10 + wpabuf_len(hlp[i]);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return NULL;
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
+
+ /* Everything after FILS Session element gets encrypted in the driver
+ * with KEK. The buffer returned from here is the plaintext version. */
+
+ /* TODO: FILS Public Key */
+
+ /* FILS Key Confirm */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ wpabuf_put_u8(buf, 1 + sm->fils_key_auth_len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
+ wpabuf_put_data(buf, sm->fils_key_auth_sta, sm->fils_key_auth_len);
+
+ /* FILS HLP Container */
+ for (i = 0; hlp && i < num_hlp; i++) {
+ const u8 *pos = wpabuf_head(hlp[i]);
+ size_t left = wpabuf_len(hlp[i]);
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
+ if (left <= 254)
+ len = 1 + left;
+ else
+ len = 255;
+ wpabuf_put_u8(buf, len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_HLP_CONTAINER);
+ /* Destination MAC Address, Source MAC Address, HLP Packet.
+ * HLP Packet is in MSDU format (i.e., included the LLC/SNAP
+ * header when LPD is used). */
+ wpabuf_put_data(buf, pos, len - 1);
+ pos += len - 1;
+ left -= len - 1;
+ while (left) {
+ wpabuf_put_u8(buf, WLAN_EID_FRAGMENT);
+ len = left > 255 ? 255 : left;
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_data(buf, pos, len);
+ pos += len;
+ left -= len;
+ }
+ }
+
+ /* TODO: FILS IP Address Assignment */
+
+ wpa_hexdump_buf(MSG_DEBUG, "FILS: Association Request plaintext", buf);
+
+ *kek = sm->ptk.kek;
+ *kek_len = sm->ptk.kek_len;
+ wpa_hexdump_key(MSG_DEBUG, "FILS: KEK for AEAD", *kek, *kek_len);
+ *snonce = sm->fils_nonce;
+ wpa_hexdump(MSG_DEBUG, "FILS: SNonce for AEAD AAD",
+ *snonce, FILS_NONCE_LEN);
+ *anonce = sm->fils_anonce;
+ wpa_hexdump(MSG_DEBUG, "FILS: ANonce for AEAD AAD",
+ *anonce, FILS_NONCE_LEN);
+
+ return buf;
+}
+
+
+static void fils_process_hlp_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
+{
+ const u8 *pos, *end;
+
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP response", resp, len);
+ if (len < 2 * ETH_ALEN)
+ return;
+ pos = resp + 2 * ETH_ALEN;
+ end = resp + len;
+ if (end - pos >= 6 &&
+ os_memcmp(pos, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+ pos += 6; /* Remove SNAP/LLC header */
+ wpa_sm_fils_hlp_rx(sm, resp, resp + ETH_ALEN, pos, end - pos);
+}
+
+
+static void fils_process_hlp_container(struct wpa_sm *sm, const u8 *pos,
+ size_t len)
+{
+ const u8 *end = pos + len;
+ u8 *tmp, *tmp_pos;
+
+ /* Check if there are any FILS HLP Container elements */
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ return;
+ if (pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + 2 * ETH_ALEN &&
+ pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ pos += 2 + pos[1];
+ }
+ if (end - pos < 2)
+ return; /* No FILS HLP Container elements */
+
+ tmp = os_malloc(end - pos);
+ if (!tmp)
+ return;
+
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos ||
+ pos[0] != WLAN_EID_EXTENSION ||
+ pos[1] < 1 + 2 * ETH_ALEN ||
+ pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ tmp_pos = tmp;
+ os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
+ tmp_pos += pos[1] - 1;
+ pos += 2 + pos[1];
+
+ /* Add possible fragments */
+ while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
+ 2 + pos[1] <= end - pos) {
+ os_memcpy(tmp_pos, pos + 2, pos[1]);
+ tmp_pos += pos[1];
+ pos += 2 + pos[1];
+ }
+
+ fils_process_hlp_resp(sm, tmp, tmp_pos - tmp);
+ }
+
+ os_free(tmp);
+}
+
+
+int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ const u8 *end, *ie_start;
+ struct ieee802_11_elems elems;
+ int keylen, rsclen;
+ enum wpa_alg alg;
+ struct wpa_gtk_data gd;
+ int maxkeylen;
+ struct wpa_eapol_ie_parse kde;
+
+ if (!sm || !sm->ptk_set) {
+ wpa_printf(MSG_DEBUG, "FILS: No KEK available");
+ return -1;
+ }
+
+ if (!wpa_key_mgmt_fils(sm->key_mgmt)) {
+ wpa_printf(MSG_DEBUG, "FILS: Not a FILS AKM");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "FILS: (Re)Association Response frame",
+ resp, len);
+
+ mgmt = (const struct ieee80211_mgmt *) resp;
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_resp))
+ return -1;
+
+ end = resp + len;
+ /* Same offset for Association Response and Reassociation Response */
+ ie_start = mgmt->u.assoc_resp.variable;
+
+ if (ieee802_11_parse_elems(ie_start, end - ie_start, &elems, 1) ==
+ ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to parse decrypted elements");
+ goto fail;
+ }
+
+ if (!elems.fils_session) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Session element");
+ return -1;
+ }
+ if (os_memcmp(elems.fils_session, sm->fils_session,
+ FILS_SESSION_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: FILS Session mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
+ elems.fils_session, FILS_SESSION_LEN);
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+ sm->fils_session, FILS_SESSION_LEN);
+ }
+
+ /* TODO: FILS Public Key */
+
+ if (!elems.fils_key_confirm) {
+ wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
+ goto fail;
+ }
+ if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unexpected Key-Auth length %d (expected %d)",
+ elems.fils_key_confirm_len,
+ (int) sm->fils_key_auth_len);
+ goto fail;
+ }
+ if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_ap,
+ sm->fils_key_auth_len) != 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
+ wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
+ elems.fils_key_confirm,
+ elems.fils_key_confirm_len);
+ wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
+ sm->fils_key_auth_ap, sm->fils_key_auth_len);
+ goto fail;
+ }
+
+ /* Key Delivery */
+ if (!elems.key_delivery) {
+ wpa_printf(MSG_DEBUG, "FILS: No Key Delivery element");
+ goto fail;
+ }
+
+ /* Parse GTK and set the key to the driver */
+ os_memset(&gd, 0, sizeof(gd));
+ if (wpa_supplicant_parse_ies(elems.key_delivery + WPA_KEY_RSC_LEN,
+ elems.key_delivery_len - WPA_KEY_RSC_LEN,
+ &kde) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to parse KDEs");
+ goto fail;
+ }
+ if (!kde.gtk) {
+ wpa_printf(MSG_DEBUG, "FILS: No GTK KDE");
+ goto fail;
+ }
+ maxkeylen = gd.gtk_len = kde.gtk_len - 2;
+ if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gd.gtk_len, maxkeylen,
+ &gd.key_rsc_len, &gd.alg))
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "FILS: Received GTK", kde.gtk, kde.gtk_len);
+ gd.keyidx = kde.gtk[0] & 0x3;
+ gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+ !!(kde.gtk[0] & BIT(2)));
+ if (kde.gtk_len - 2 > sizeof(gd.gtk)) {
+ wpa_printf(MSG_DEBUG, "FILS: Too long GTK in GTK KDE (len=%lu)",
+ (unsigned long) kde.gtk_len - 2);
+ goto fail;
+ }
+ os_memcpy(gd.gtk, kde.gtk + 2, kde.gtk_len - 2);
+
+ wpa_printf(MSG_DEBUG, "FILS: Set GTK to driver");
+ if (wpa_supplicant_install_gtk(sm, &gd, elems.key_delivery, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to set GTK");
+ goto fail;
+ }
+
+ if (ieee80211w_set_keys(sm, &kde) < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to set IGTK");
+ goto fail;
+ }
+
+ alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+ keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+ rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
+ sm->ptk.tk, keylen);
+ if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
+ sm->ptk.tk, keylen) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
+ MACSTR ")",
+ alg, keylen, MAC2STR(sm->bssid));
+ goto fail;
+ }
+
+ /* TODO: TK could be cleared after auth frame exchange now that driver
+ * takes care of association frame encryption/decryption. */
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+ sm->ptk.installed = 1;
+
+ /* FILS HLP Container */
+ fils_process_hlp_container(sm, ie_start, end - ie_start);
+
+ /* TODO: FILS IP Address Assignment */
+
+ wpa_printf(MSG_DEBUG, "FILS: Auth+Assoc completed successfully");
+ sm->fils_completed = 1;
+
+ return 0;
+fail:
+ return -1;
+}
+
+#endif /* CONFIG_FILS */
+
+
+int wpa_fils_is_completed(struct wpa_sm *sm)
+{
+#ifdef CONFIG_FILS
+ return sm && sm->fils_completed;
+#else /* CONFIG_FILS */
+ return 0;
+#endif /* CONFIG_FILS */
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index c89799a..bde8c78 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -25,7 +25,7 @@
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
- void (*deauthenticate)(void * ctx, int reason_code);
+ void (*deauthenticate)(void * ctx, int reason_code);
int (*set_key)(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
@@ -38,8 +38,10 @@
void (*cancel_auth_timeout)(void *ctx);
u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len,
size_t *msg_len, void **data_pos);
- int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
- int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+ int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
+ const u8 *pmkid);
+ int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid,
+ const u8 *pmkid);
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
const struct wpa_config_blob * (*get_config_blob)(void *ctx,
const char *name);
@@ -77,6 +79,8 @@
const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
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);
};
@@ -147,6 +151,10 @@
const u8 *buf, size_t len);
int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm);
+struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm,
+ struct rsn_pmksa_cache_entry * entry);
void wpa_sm_drop_sa(struct wpa_sm *sm);
int wpa_sm_has_ptk(struct wpa_sm *sm);
@@ -418,8 +426,22 @@
u8 oper_class,
struct hostapd_freq_params *freq_params);
int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
+#ifdef CONFIG_TDLS_TESTING
+extern unsigned int tdls_testing;
+#endif /* CONFIG_TDLS_TESTING */
+
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
+struct wpabuf * fils_build_auth(struct wpa_sm *sm);
+int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len);
+struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
+ size_t *kek_len, const u8 **snonce,
+ const u8 **anonce,
+ const struct wpabuf **hlp,
+ unsigned int num_hlp);
+int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len);
+int wpa_fils_is_completed(struct wpa_sm *sm);
+
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 56f88dc..b061638 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -144,6 +144,18 @@
#ifdef CONFIG_TESTING_OPTIONS
struct wpabuf *test_assoc_ie;
#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_FILS
+ u8 fils_nonce[FILS_NONCE_LEN];
+ u8 fils_session[FILS_SESSION_LEN];
+ u8 fils_anonce[FILS_NONCE_LEN];
+ u8 fils_key_auth_ap[FILS_MAX_KEY_AUTH_LEN];
+ u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
+ size_t fils_key_auth_len;
+ unsigned int fils_completed:1;
+ unsigned int fils_erp_pmkid_set:1;
+ u8 fils_erp_pmkid[PMKID_LEN];
+#endif /* CONFIG_FILS */
};
@@ -215,18 +227,18 @@
msg_len, data_pos);
}
-static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid,
- const u8 *pmkid)
+static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid)
{
WPA_ASSERT(sm->ctx->add_pmkid);
- return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid);
+ return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid);
}
-static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
- const u8 *pmkid)
+static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx,
+ const u8 *bssid, const u8 *pmkid)
{
WPA_ASSERT(sm->ctx->remove_pmkid);
- return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
+ return sm->ctx->remove_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid);
}
static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
@@ -359,7 +371,16 @@
return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
}
-int wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
+static inline void wpa_sm_fils_hlp_rx(struct wpa_sm *sm,
+ const u8 *dst, const u8 *src,
+ const u8 *pkt, size_t pkt_len)
+{
+ if (sm->ctx->fils_hlp_rx)
+ sm->ctx->fils_hlp_rx(sm->ctx->ctx, dst, src, pkt, pkt_len);
+}
+
+
+int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic);
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index c44844e..3be3087 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -180,6 +180,18 @@
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
+#ifdef CONFIG_FILS
+ } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
+ } else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
+#ifdef CONFIG_IEEE80211R
+ } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
+ } else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 8bc824f..4f7a148 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -116,7 +116,7 @@
#define MP_PREC 32 /* default digits of precision */
#else
#define MP_PREC 8 /* default digits of precision */
- #endif
+ #endif
#endif
/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
@@ -274,8 +274,8 @@
*tmpc++ &= MP_MASK;
}
- /* now copy higher words if any, that is in A+B
- * if A or B has more digits add those in
+ /* now copy higher words if any, that is in A+B
+ * if A or B has more digits add those in
*/
if (min != max) {
for (; i < max; i++) {
@@ -499,29 +499,29 @@
#ifdef BN_MP_TOOM_MUL_C
if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
res = mp_toom_mul(a, b, c);
- } else
+ } else
#endif
#ifdef BN_MP_KARATSUBA_MUL_C
/* use Karatsuba? */
if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
res = mp_karatsuba_mul (a, b, c);
- } else
+ } else
#endif
{
/* can we use the fast multiplier?
*
- * The fast multiplier can be used if the output will
- * have less than MP_WARRAY digits and the number of
+ * The fast multiplier can be used if the output will
+ * have less than MP_WARRAY digits and the number of
* digits won't affect carry propagation
*/
#ifdef BN_FAST_S_MP_MUL_DIGS_C
int digs = a->used + b->used + 1;
if ((digs < MP_WARRAY) &&
- MIN(a->used, b->used) <=
+ MIN(a->used, b->used) <=
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
res = fast_s_mp_mul_digs (a, b, c, digs);
- } else
+ } else
#endif
#ifdef BN_S_MP_MUL_DIGS_C
res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
@@ -629,7 +629,7 @@
err = mp_exptmod(&tmpG, &tmpX, P, Y);
mp_clear_multi(&tmpG, &tmpX, NULL);
return err;
-#else
+#else
#error mp_exptmod would always fail
/* no invmod */
return MP_VAL;
@@ -658,7 +658,7 @@
dr = mp_reduce_is_2k(P) << 1;
}
#endif
-
+
/* if the modulus is odd or dr != 0 use the montgomery method */
#ifdef BN_MP_EXPTMOD_FAST_C
if (mp_isodd (P) == 1 || dr != 0) {
@@ -693,7 +693,7 @@
return MP_GT;
}
}
-
+
/* compare digits */
if (a->sign == MP_NEG) {
/* if negative compare opposite direction */
@@ -779,7 +779,7 @@
}
/* init temps */
- if ((res = mp_init_multi(&x, &y, &u, &v,
+ if ((res = mp_init_multi(&x, &y, &u, &v,
&A, &B, &C, &D, NULL)) != MP_OKAY) {
return res;
}
@@ -906,14 +906,14 @@
goto LBL_ERR;
}
}
-
+
/* too big */
while (mp_cmp_mag(&C, b) != MP_LT) {
if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
goto LBL_ERR;
}
}
-
+
/* C is now the inverse */
mp_exch (&C, c);
res = MP_OKAY;
@@ -933,7 +933,7 @@
if (a->used > b->used) {
return MP_GT;
}
-
+
if (a->used < b->used) {
return MP_LT;
}
@@ -1199,8 +1199,8 @@
/* top [offset into digits] */
top = a->dp + b;
- /* this is implemented as a sliding window where
- * the window is b-digits long and digits from
+ /* this is implemented as a sliding window where
+ * the window is b-digits long and digits from
* the top of the window are copied to the bottom
*
* e.g.
@@ -1218,13 +1218,13 @@
*bottom++ = 0;
}
}
-
+
/* remove excess digits */
a->used -= b;
}
-/* swap the elements of two integers, for cases where you can't simply swap the
+/* swap the elements of two integers, for cases where you can't simply swap the
* mp_int pointers around
*/
static void mp_exch (mp_int * a, mp_int * b)
@@ -1237,7 +1237,7 @@
}
-/* trim unused digits
+/* trim unused digits
*
* This is used to ensure that leading zero digits are
* trimed and the leading "used" digit will be non-zero
@@ -1298,7 +1298,7 @@
#ifdef BN_MP_ABS_C
-/* b = |a|
+/* b = |a|
*
* Simple function copies the input and fixes the sign to positive
*/
@@ -1434,7 +1434,7 @@
/* set the carry to the carry bits of the current word */
r = rr;
}
-
+
/* set final carry */
if (r != 0) {
c->dp[(c->used)++] = r;
@@ -1446,7 +1446,7 @@
#ifdef BN_MP_INIT_MULTI_C
-static int mp_init_multi(mp_int *mp, ...)
+static int mp_init_multi(mp_int *mp, ...)
{
mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
int n = 0; /* Number of ok inits */
@@ -1460,11 +1460,11 @@
succeeded in init-ing, then return error.
*/
va_list clean_args;
-
+
/* end the current list */
va_end(args);
-
- /* now start cleaning up */
+
+ /* now start cleaning up */
cur_arg = mp;
va_start(clean_args, mp);
while (n--) {
@@ -1484,7 +1484,7 @@
#ifdef BN_MP_CLEAR_MULTI_C
-static void mp_clear_multi(mp_int *mp, ...)
+static void mp_clear_multi(mp_int *mp, ...)
{
mp_int* next_mp = mp;
va_list args;
@@ -1558,7 +1558,7 @@
/* get number of digits and add that */
r = (a->used - 1) * DIGIT_BIT;
-
+
/* take the last digit and count the bits in it */
q = a->dp[a->used - 1];
while (q > ((mp_digit) 0)) {
@@ -1628,7 +1628,7 @@
}
return res;
}
-
+
/* init our temps */
if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL)) != MP_OKAY) {
return res;
@@ -1638,7 +1638,7 @@
mp_set(&tq, 1);
n = mp_count_bits(a) - mp_count_bits(b);
if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
- ((res = mp_abs(b, &tb)) != MP_OKAY) ||
+ ((res = mp_abs(b, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
goto LBL_ERR;
@@ -1675,17 +1675,17 @@
#else
-/* integer signed division.
+/* integer signed division.
* c*b + d == a [e.g. a/b, c=quotient, d=remainder]
* HAC pp.598 Algorithm 14.20
*
- * Note that the description in HAC is horribly
- * incomplete. For example, it doesn't consider
- * the case where digits are removed from 'x' in
- * the inner loop. It also doesn't consider the
+ * Note that the description in HAC is horribly
+ * incomplete. For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop. It also doesn't consider the
* case that y has fewer than three digits, etc..
*
- * The overall algorithm is as described as
+ * The overall algorithm is as described as
* 14.20 from HAC but fixed to treat these cases.
*/
static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
@@ -1775,7 +1775,7 @@
continue;
}
- /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
* otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
if (x.dp[i] == y.dp[t]) {
q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
@@ -1789,10 +1789,10 @@
q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
}
- /* while (q{i-t-1} * (yt * b + y{t-1})) >
- xi * b**2 + xi-1 * b + xi-2
-
- do q{i-t-1} -= 1;
+ /* while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
*/
q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
do {
@@ -1843,10 +1843,10 @@
}
}
- /* now q is the quotient and x is the remainder
- * [which we have to normalize]
+ /* now q is the quotient and x is the remainder
+ * [which we have to normalize]
*/
-
+
/* get sign before writing to c */
x.sign = x.used == 0 ? MP_ZPOS : a->sign;
@@ -1914,7 +1914,7 @@
/* init M array */
/* init first cell */
if ((err = mp_init(&M[1])) != MP_OKAY) {
- return err;
+ return err;
}
/* now init the second half of the array */
@@ -1932,7 +1932,7 @@
if ((err = mp_init (&mu)) != MP_OKAY) {
goto LBL_M;
}
-
+
if (redmode == 0) {
if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
goto LBL_MU;
@@ -1943,22 +1943,22 @@
goto LBL_MU;
}
redux = mp_reduce_2k_l;
- }
+ }
/* create M table
*
- * The M table contains powers of the base,
+ * The M table contains powers of the base,
* e.g. M[x] = G**x mod P
*
- * The first half of the table is not
+ * The first half of the table is not
* computed though accept for M[0] and M[1]
*/
if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
goto LBL_MU;
}
- /* compute the value at M[1<<(winsize-1)] by squaring
- * M[1] (winsize-1) times
+ /* compute the value at M[1<<(winsize-1)] by squaring
+ * M[1] (winsize-1) times
*/
if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_MU;
@@ -1966,7 +1966,7 @@
for (x = 0; x < (winsize - 1); x++) {
/* square it */
- if ((err = mp_sqr (&M[1 << (winsize - 1)],
+ if ((err = mp_sqr (&M[1 << (winsize - 1)],
&M[1 << (winsize - 1)])) != MP_OKAY) {
goto LBL_MU;
}
@@ -2117,18 +2117,18 @@
if (a->used >= TOOM_SQR_CUTOFF) {
res = mp_toom_sqr(a, b);
/* Karatsuba? */
- } else
+ } else
#endif
#ifdef BN_MP_KARATSUBA_SQR_C
if (a->used >= KARATSUBA_SQR_CUTOFF) {
res = mp_karatsuba_sqr (a, b);
- } else
+ } else
#endif
{
#ifdef BN_FAST_S_MP_SQR_C
/* can we use the fast comba multiplier? */
- if ((a->used * 2 + 1) < MP_WARRAY &&
- a->used <
+ if ((a->used * 2 + 1) < MP_WARRAY &&
+ a->used <
(1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
res = fast_s_mp_sqr (a, b);
} else
@@ -2145,7 +2145,7 @@
}
-/* reduces a modulo n where n is of the form 2**p - d
+/* reduces a modulo n where n is of the form 2**p - d
This differs from reduce_2k since "d" can be larger
than a single digit.
*/
@@ -2153,33 +2153,33 @@
{
mp_int q;
int p, res;
-
+
if ((res = mp_init(&q)) != MP_OKAY) {
return res;
}
-
- p = mp_count_bits(n);
+
+ p = mp_count_bits(n);
top:
/* q = a/2**p, a = a mod 2**p */
if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
goto ERR;
}
-
+
/* q = q * d */
- if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
+ if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
goto ERR;
}
-
+
/* a = a + q */
if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
goto ERR;
}
-
+
if (mp_cmp_mag(a, n) != MP_LT) {
s_mp_sub(a, n, a);
goto top;
}
-
+
ERR:
mp_clear(&q);
return res;
@@ -2191,26 +2191,26 @@
{
int res;
mp_int tmp;
-
+
if ((res = mp_init(&tmp)) != MP_OKAY) {
return res;
}
-
+
if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
goto ERR;
}
-
+
if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
goto ERR;
}
-
+
ERR:
mp_clear(&tmp);
return res;
}
-/* computes a = 2**b
+/* computes a = 2**b
*
* Simple algorithm which zeroes the int, grows it then just sets one bit
* as required.
@@ -2243,7 +2243,7 @@
static int mp_reduce_setup (mp_int * a, mp_int * b)
{
int res;
-
+
if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
return res;
}
@@ -2251,7 +2251,7 @@
}
-/* reduces x mod m, assumes 0 < x < m**2, mu is
+/* reduces x mod m, assumes 0 < x < m**2, mu is
* precomputed via mp_reduce_setup.
* From HAC pp.604 Algorithm 14.42
*/
@@ -2266,7 +2266,7 @@
}
/* q1 = x / b**(k-1) */
- mp_rshd (&q, um - 1);
+ mp_rshd (&q, um - 1);
/* according to HAC this optimization is ok */
if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
@@ -2282,8 +2282,8 @@
if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
-#else
- {
+#else
+ {
#error mp_reduce would always fail
res = MP_VAL;
goto CLEANUP;
@@ -2292,7 +2292,7 @@
}
/* q3 = q2 / b**(k+1) */
- mp_rshd (&q, um + 1);
+ mp_rshd (&q, um + 1);
/* x = x mod b**(k+1), quick (no division) */
if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
@@ -2326,7 +2326,7 @@
goto CLEANUP;
}
}
-
+
CLEANUP:
mp_clear (&q);
@@ -2335,7 +2335,7 @@
/* multiplies |a| * |b| and only computes up to digs digits of result
- * HAC pp. 595, Algorithm 14.12 Modified so you can control how
+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how
* many digits of output are created.
*/
static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
@@ -2349,7 +2349,7 @@
#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* can we use the fast multiplier? */
if (((digs) < MP_WARRAY) &&
- MIN (a->used, b->used) <
+ MIN (a->used, b->used) <
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_digs (a, b, c, digs);
}
@@ -2372,10 +2372,10 @@
/* setup some aliases */
/* copy of the digit from a used within the nested loop */
tmpx = a->dp[ix];
-
+
/* an alias for the destination shifted ix places */
tmpt = t.dp + ix;
-
+
/* an alias for the digits of b */
tmpy = b->dp;
@@ -2409,15 +2409,15 @@
#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* Fast (comba) multiplier
*
- * This is the fast column-array [comba] multiplier. It is
- * designed to compute the columns of the product first
- * then handle the carries afterwards. This has the effect
+ * This is the fast column-array [comba] multiplier. It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards. This has the effect
* of making the nested loops that compute the columns very
* simple and schedulable on super-scalar processors.
*
- * This has been modified to produce a variable number of
- * digits of output so if say only a half-product is required
- * you don't have to compute the upper half (a feature
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
* required for fast Barrett reduction).
*
* Based on Algorithm 14.12 on pp.595 of HAC.
@@ -2441,7 +2441,7 @@
/* clear the carry */
_W = 0;
- for (ix = 0; ix < pa; ix++) {
+ for (ix = 0; ix < pa; ix++) {
int tx, ty;
int iy;
mp_digit *tmpx, *tmpy;
@@ -2454,7 +2454,7 @@
tmpx = a->dp + tx;
tmpy = b->dp + ty;
- /* this is the number of times the loop will iterrate, essentially
+ /* this is the number of times the loop will iterrate, essentially
while (tx++ < a->used && ty-- >= 0) { ... }
*/
iy = MIN(a->used-tx, ty+1);
@@ -2501,8 +2501,8 @@
int x;
/* pad size so there are always extra digits */
- size += (MP_PREC * 2) - (size % MP_PREC);
-
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
/* alloc mem */
a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
if (a->dp == NULL) {
@@ -2556,7 +2556,7 @@
/* alias for where to store the results */
tmpt = t.dp + (2*ix + 1);
-
+
for (iy = ix + 1; iy < pa; iy++) {
/* first calculate the product */
r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
@@ -2863,24 +2863,24 @@
/* alias for source */
tmpa = a->dp;
-
+
/* alias for dest */
tmpb = b->dp;
/* carry */
r = 0;
for (x = 0; x < a->used; x++) {
-
- /* get what will be the *next* carry bit from the
- * MSB of the current digit
+
+ /* get what will be the *next* carry bit from the
+ * MSB of the current digit
*/
rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
-
+
/* now shift up this digit, add in the carry [from the previous] */
*tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
-
- /* copy the carry that would be from the source
- * digit into the next iteration
+
+ /* copy the carry that would be from the source
+ * digit into the next iteration
*/
r = rr;
}
@@ -2892,8 +2892,8 @@
++(b->used);
}
- /* now zero any excess digits on the destination
- * that we didn't write to
+ /* now zero any excess digits on the destination
+ * that we didn't write to
*/
tmpb = b->dp + b->used;
for (x = b->used; x < oldused; x++) {
@@ -3011,7 +3011,7 @@
/* determine and setup reduction code */
if (redmode == 0) {
-#ifdef BN_MP_MONTGOMERY_SETUP_C
+#ifdef BN_MP_MONTGOMERY_SETUP_C
/* now setup montgomery */
if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
goto LBL_M;
@@ -3026,7 +3026,7 @@
if (((P->used * 2 + 1) < MP_WARRAY) &&
P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
redux = fast_mp_montgomery_reduce;
- } else
+ } else
#endif
{
#ifdef BN_MP_MONTGOMERY_REDUCE_C
@@ -3077,7 +3077,7 @@
if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
goto LBL_RES;
}
-#else
+#else
err = MP_VAL;
goto LBL_RES;
#endif
@@ -3245,10 +3245,10 @@
#ifdef BN_FAST_S_MP_SQR_C
/* the jist of squaring...
- * you do like mult except the offset of the tmpx [one that
- * starts closer to zero] can't equal the offset of tmpy.
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
* So basically you set up iy like before then you min it with
- * (ty-tx) so that it never happens. You double all those
+ * (ty-tx) so that it never happens. You double all those
* you add in the inner loop
After that loop you do the squares and add them in.
@@ -3270,7 +3270,7 @@
/* number of output digits to produce */
W1 = 0;
- for (ix = 0; ix < pa; ix++) {
+ for (ix = 0; ix < pa; ix++) {
int tx, ty, iy;
mp_word _W;
mp_digit *tmpy;
@@ -3291,7 +3291,7 @@
*/
iy = MIN(a->used-tx, ty+1);
- /* now for squaring tx can never equal ty
+ /* now for squaring tx can never equal ty
* we halve the distance since they approach at a rate of 2x
* and we have to round because odd cases need to be executed
*/
diff --git a/src/tls/rsa.c b/src/tls/rsa.c
index 0b7b530..3525eb9 100644
--- a/src/tls/rsa.c
+++ b/src/tls/rsa.c
@@ -80,7 +80,7 @@
* PKCS #1, 7.1:
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
- * publicExponent INTEGER -- e
+ * publicExponent INTEGER -- e
* }
*/
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 9bc0d21..76e1974 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -264,7 +264,7 @@
* @in_data: Pointer to plaintext data to be encrypted
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length
+ * @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 6b28417..e178915 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -21,7 +21,7 @@
* RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
* Add support for commonly used cipher suites; don't bother with exportable
* suites.
- */
+ */
static const struct tls_cipher_suite tls_cipher_suites[] = {
{ TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
@@ -482,21 +482,21 @@
os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
"\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
{
- wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-256");
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-256");
decrypted = buf + 19;
buflen -= 19;
} else if (buflen >= 19 + 48 &&
os_memcmp(buf, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01"
"\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19) == 0)
{
- wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-384");
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-384");
decrypted = buf + 19;
buflen -= 19;
} else if (buflen >= 19 + 64 &&
os_memcmp(buf, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01"
"\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19) == 0)
{
- wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = SHA-512");
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-512");
decrypted = buf + 19;
buflen -= 19;
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index ba47337..5406969 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -216,7 +216,7 @@
* @in_data: Pointer to plaintext data to be encrypted
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (encrypted TLS data)
- * @out_len: Maximum out_data length
+ * @out_len: Maximum out_data length
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 75f222c..0d6ee67 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -2039,7 +2039,7 @@
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
cert->issuer_trusted = 0;
- x509_name_string(&cert->subject, buf, sizeof(buf));
+ x509_name_string(&cert->subject, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
if (chain_trusted)
@@ -2063,11 +2063,11 @@
wpa_printf(MSG_DEBUG, "X509: Certificate "
"chain issuer name mismatch");
x509_name_string(&cert->issuer, buf,
- sizeof(buf));
+ sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
buf);
x509_name_string(&cert->next->subject, buf,
- sizeof(buf));
+ sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: next cert "
"subject: %s", buf);
*reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 8aad813..52efc53 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -17,6 +17,7 @@
base64.o \
bitfield.o \
common.o \
+ crc32.o \
ip_addr.o \
radiotap.o \
trace.o \
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index 59ba4d1..062e6fe 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -52,7 +52,7 @@
eloop_terminate();
return;
}
- wpabuf_put_str(resp, "User input completed");
+ wpabuf_put_str(resp, "HTTP/1.1\r\n\r\nUser input completed");
if (done) {
eloop_cancel_timeout(browser_timeout, NULL, NULL);
diff --git a/src/utils/common.c b/src/utils/common.c
index 9c7d0d4..1eb3370 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -697,6 +697,29 @@
}
+int has_ctrl_char(const u8 *data, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (data[i] < 32 || data[i] == 127)
+ return 1;
+ }
+ return 0;
+}
+
+
+int has_newline(const char *str)
+{
+ while (*str) {
+ if (*str == '\n' || *str == '\r')
+ return 1;
+ str++;
+ }
+ return 0;
+}
+
+
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len)
@@ -978,7 +1001,7 @@
* @delim: a string of delimiters
* @last: a pointer to a character following the returned token
* It has to be set to NULL for the first call and passed for any
- * futher call.
+ * further call.
* Returns: a pointer to token position in str or NULL
*
* This function is similar to str_token, but it can be used with both
@@ -1123,3 +1146,78 @@
{
return c > 0 && c < 32;
}
+
+
+/**
+ * ssid_parse - Parse a string that contains SSID in hex or text format
+ * @buf: Input NULL terminated string that contains the SSID
+ * @ssid: Output SSID
+ * Returns: 0 on success, -1 otherwise
+ *
+ * The SSID has to be enclosed in double quotes for the text format or space
+ * or NULL terminated string of hex digits for the hex format. buf can include
+ * additional arguments after the SSID.
+ */
+int ssid_parse(const char *buf, struct wpa_ssid_value *ssid)
+{
+ char *tmp, *res, *end;
+ size_t len;
+
+ ssid->ssid_len = 0;
+
+ tmp = os_strdup(buf);
+ if (!tmp)
+ return -1;
+
+ if (*tmp != '"') {
+ end = os_strchr(tmp, ' ');
+ if (end)
+ *end = '\0';
+ } else {
+ end = os_strchr(tmp + 1, '"');
+ if (!end) {
+ os_free(tmp);
+ return -1;
+ }
+
+ end[1] = '\0';
+ }
+
+ res = wpa_config_parse_string(tmp, &len);
+ if (res && len <= SSID_MAX_LEN) {
+ ssid->ssid_len = len;
+ os_memcpy(ssid->ssid, res, len);
+ }
+
+ os_free(tmp);
+ os_free(res);
+
+ return ssid->ssid_len ? 0 : -1;
+}
+
+
+int str_starts(const char *str, const char *start)
+{
+ return os_strncmp(str, start, os_strlen(start)) == 0;
+}
+
+
+/**
+ * rssi_to_rcpi - Convert RSSI to RCPI
+ * @rssi: RSSI to convert
+ * Returns: RCPI corresponding to the given RSSI value, or 255 if not available.
+ *
+ * It's possible to estimate RCPI based on RSSI in dBm. This calculation will
+ * not reflect the correct value for high rates, but it's good enough for Action
+ * frames which are transmitted with up to 24 Mbps rates.
+ */
+u8 rssi_to_rcpi(int rssi)
+{
+ if (!rssi)
+ return 255; /* not available */
+ if (rssi < -110)
+ return 0;
+ if (rssi > 0)
+ return 220;
+ return (rssi + 110) * 2;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 6f0de69..8842864 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -419,6 +419,7 @@
*/
#ifdef __CHECKER__
#define __force __attribute__((force))
+#undef __bitwise
#define __bitwise __attribute__((bitwise))
#else
#define __force
@@ -448,6 +449,13 @@
#endif /* __GNUC__ */
#endif /* __must_check */
+#define SSID_MAX_LEN 32
+
+struct wpa_ssid_value {
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len;
+};
+
int hwaddr_aton(const char *txt, u8 *addr);
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
int hwaddr_compact_aton(const char *txt, u8 *addr);
@@ -464,6 +472,7 @@
size_t len);
int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+int ssid_parse(const char *buf, struct wpa_ssid_value *ssid);
#ifdef CONFIG_NATIVE_WINDOWS
void wpa_unicode2ascii_inplace(TCHAR *str);
@@ -480,6 +489,8 @@
char * wpa_config_parse_string(const char *value, size_t *len);
int is_hex(const u8 *data, size_t len);
+int has_ctrl_char(const u8 *data, size_t len);
+int has_newline(const char *str);
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len);
@@ -539,6 +550,9 @@
char *outp, size_t out_size);
int is_ctrl_char(char c);
+int str_starts(const char *str, const char *start);
+
+u8 rssi_to_rcpi(int rssi);
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/crc32.h b/src/utils/crc32.h
new file mode 100644
index 0000000..dc31399
--- /dev/null
+++ b/src/utils/crc32.h
@@ -0,0 +1,14 @@
+/*
+ * 32-bit CRC for FCS calculation
+ * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CRC32_H
+#define CRC32_H
+
+u32 crc32(const u8 *frame, size_t frame_len);
+
+#endif /* CRC32_H */
diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c
index 13173cb..2ffd1a2 100644
--- a/src/utils/edit_simple.c
+++ b/src/utils/edit_simple.c
@@ -47,6 +47,12 @@
return;
}
+ if (c == '\b') {
+ if (cmdbuf_pos > 0)
+ cmdbuf_pos--;
+ return;
+ }
+
if (c >= 32 && c <= 255) {
if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) {
cmdbuf[cmdbuf_pos++] = c;
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 97af16f..04ee6d1 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -45,16 +45,16 @@
/**
* eloop_event_handler - eloop generic event callback type
* @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
*/
-typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_event_handler)(void *eloop_ctx, void *user_ctx);
/**
* eloop_timeout_handler - eloop timeout event callback type
* @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
*/
-typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_timeout_handler)(void *eloop_ctx, void *user_ctx);
/**
* eloop_signal_handler - eloop signal event callback type
diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c
index 0613119..5615bd7 100644
--- a/src/utils/ext_password.c
+++ b/src/utils/ext_password.c
@@ -16,10 +16,6 @@
#include "ext_password_i.h"
-#ifdef CONFIG_EXT_PASSWORD_TEST
-extern struct ext_password_backend ext_password_test;
-#endif /* CONFIG_EXT_PASSWORD_TEST */
-
static const struct ext_password_backend *backends[] = {
#ifdef CONFIG_EXT_PASSWORD_TEST
&ext_password_test,
diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h
index 043e731..948eaf5 100644
--- a/src/utils/ext_password_i.h
+++ b/src/utils/ext_password_i.h
@@ -20,4 +20,10 @@
struct wpabuf * ext_password_alloc(size_t len);
+/* Available ext_password backends */
+
+#ifdef CONFIG_EXT_PASSWORD_TEST
+extern const struct ext_password_backend ext_password_test;
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+
#endif /* EXT_PASSWORD_I_H */
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index d594398..a06aae8 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -857,10 +857,8 @@
os_memset(hcert, 0, sizeof(*hcert));
*names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
- if (*names) {
+ if (*names)
add_alt_names(ctx, hcert, *names);
- sk_GENERAL_NAME_pop_free(*names, GENERAL_NAME_free);
- }
add_logotype_ext(ctx, hcert, cert);
}
diff --git a/src/utils/module_tests.h b/src/utils/module_tests.h
new file mode 100644
index 0000000..3bfe4ad
--- /dev/null
+++ b/src/utils/module_tests.h
@@ -0,0 +1,20 @@
+/*
+ * Module tests
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MODULE_TESTS_H
+#define MODULE_TESTS_H
+
+int wpas_module_tests(void);
+int hapd_module_tests(void);
+
+int utils_module_tests(void);
+int wps_module_tests(void);
+int common_module_tests(void);
+int crypto_module_tests(void);
+
+#endif /* MODULE_TESTS_H */
diff --git a/src/utils/os.h b/src/utils/os.h
index 9e496fb..e8f0b79 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -657,6 +657,10 @@
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
#define TEST_FAIL() testing_test_fail()
int testing_test_fail(void);
+extern char wpa_trace_fail_func[256];
+extern unsigned int wpa_trace_fail_after;
+extern char wpa_trace_test_fail_func[256];
+extern unsigned int wpa_trace_test_fail_after;
#else
#define TEST_FAIL() 0
#endif
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 0118d98..26fd172 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -80,6 +80,9 @@
struct timespec ts;
int res;
+ if (TEST_FAIL())
+ return -1;
+
while (1) {
res = clock_gettime(clock_id, &ts);
if (res == 0) {
@@ -435,11 +438,7 @@
int os_file_exists(const char *fname)
{
- FILE *f = fopen(fname, "rb");
- if (f == NULL)
- return 0;
- fclose(f);
- return 1;
+ return access(fname, F_OK) == 0;
}
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index 2f1157b..383ed3d 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -11,7 +11,11 @@
*/
#include "includes.h"
+#ifdef __APPLE__
+#include <PCSC/winscard.h>
+#else
#include <winscard.h>
+#endif
#include "common.h"
#include "pcsc_funcs.h"
@@ -110,7 +114,11 @@
struct scard_data {
SCARDCONTEXT ctx;
SCARDHANDLE card;
+#ifdef __APPLE__
+ uint32_t protocol;
+#else
DWORD protocol;
+#endif
sim_types sim_type;
int pin1_required;
};
@@ -504,7 +512,12 @@
struct scard_data * scard_init(const char *reader)
{
long ret;
- unsigned long len, pos;
+#ifdef __APPLE__
+ uint32_t len;
+#else
+ unsigned long len;
+#endif
+ unsigned long pos;
struct scard_data *scard;
#ifdef CONFIG_NATIVE_WINDOWS
TCHAR *readers = NULL;
@@ -605,7 +618,7 @@
readers = NULL;
wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
- (unsigned int) scard->card, scard->protocol,
+ (unsigned int) scard->card, (unsigned long) scard->protocol,
scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
ret = SCardBeginTransaction(scard->card);
@@ -764,7 +777,11 @@
unsigned char *_recv, size_t *recv_len)
{
long ret;
+#ifdef __APPLE__
+ uint32_t rlen;
+#else
unsigned long rlen;
+#endif
wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
_send, send_len);
diff --git a/src/utils/platform.h b/src/utils/platform.h
index 46cfe78..813987e 100644
--- a/src/utils/platform.h
+++ b/src/utils/platform.h
@@ -15,7 +15,7 @@
\
__ptr->__val; \
})
-#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *)(p)))
-#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *)(p)))
+#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((le16 *)(p)))
+#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((le32 *)(p)))
#endif /* PLATFORM_H */
diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c
index c9a5023..71996eb 100644
--- a/src/utils/radiotap.c
+++ b/src/utils/radiotap.c
@@ -13,8 +13,8 @@
*
* See COPYING for more details.
*/
-#include "radiotap_iter.h"
#include "platform.h"
+#include "radiotap_iter.h"
/* function prototypes and related defs are in radiotap_iter.h */
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
index 0572e7c..460af23 100644
--- a/src/utils/radiotap.h
+++ b/src/utils/radiotap.h
@@ -65,12 +65,12 @@
* new fields does not count.
*/
uint8_t it_pad;
- uint16_t it_len; /* length of the whole
+ le16 it_len; /* length of the whole
* header in bytes, including
* it_version, it_pad,
* it_len, and data fields.
*/
- uint32_t it_present; /* A bitmap telling which
+ le32 it_present; /* A bitmap telling which
* fields are present. Set bit 31
* (0x80000000) to extend the
* bitmap by another 32 bits.
diff --git a/src/utils/radiotap_iter.h b/src/utils/radiotap_iter.h
index b768c85..6ea07e3 100644
--- a/src/utils/radiotap_iter.h
+++ b/src/utils/radiotap_iter.h
@@ -67,7 +67,7 @@
const struct ieee80211_radiotap_namespace *current_namespace;
unsigned char *_arg, *_next_ns_data;
- uint32_t *_next_bitmap;
+ le32 *_next_bitmap;
unsigned char *this_arg;
#ifdef RADIOTAP_SUPPORT_OVERRIDES
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index 41511b9..abdb79c 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -16,6 +16,7 @@
#include "utils/base64.h"
#include "utils/ip_addr.h"
#include "utils/eloop.h"
+#include "utils/module_tests.h"
struct printf_test_data {
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index f7acf6b..62758d8 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -13,7 +13,7 @@
#ifdef CONFIG_DEBUG_SYSLOG
#include <syslog.h>
-static int wpa_debug_syslog = 0;
+int wpa_debug_syslog = 0;
#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 17d8f96..1fe0b7d 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -14,6 +14,9 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
+#ifdef CONFIG_DEBUG_SYSLOG
+extern int wpa_debug_syslog;
+#endif /* CONFIG_DEBUG_SYSLOG */
/* Debugging function - conditional printf and hex dump. Driver wrappers can
* use these for debugging purposes. */
diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c
index 11e7323..77ee472 100644
--- a/src/utils/wpabuf.c
+++ b/src/utils/wpabuf.c
@@ -244,15 +244,13 @@
if (a)
len += wpabuf_len(a);
- if (b)
- len += wpabuf_len(b);
+ len += wpabuf_len(b);
n = wpabuf_alloc(len);
if (n) {
if (a)
wpabuf_put_buf(n, a);
- if (b)
- wpabuf_put_buf(n, b);
+ wpabuf_put_buf(n, b);
}
wpabuf_free(a);
@@ -310,3 +308,33 @@
wpabuf_overflow(buf, res);
buf->used += res;
}
+
+
+/**
+ * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf
+ * @buf: Buffer with null terminated string (hexdump) of binary data
+ * Returns: wpabuf or %NULL on failure
+ *
+ * The string len must be a multiple of two and contain only hexadecimal digits.
+ */
+struct wpabuf * wpabuf_parse_bin(const char *buf)
+{
+ size_t len;
+ struct wpabuf *ret;
+
+ len = os_strlen(buf);
+ if (len & 0x01)
+ return NULL;
+ len /= 2;
+
+ ret = wpabuf_alloc(len);
+ if (ret == NULL)
+ return NULL;
+
+ if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+ wpabuf_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h
index 9cd8a07..01da41b 100644
--- a/src/utils/wpabuf.h
+++ b/src/utils/wpabuf.h
@@ -37,6 +37,7 @@
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
+struct wpabuf * wpabuf_parse_bin(const char *buf);
/**
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 7c6dcb2..fade6b6 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -174,7 +174,7 @@
} else if (data->registrar)
wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
- wpabuf_free(data->dh_privkey);
+ wpabuf_clear_free(data->dh_privkey);
wpabuf_free(data->dh_pubkey_e);
wpabuf_free(data->dh_pubkey_r);
wpabuf_free(data->last_msg);
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 748620f..770f5e9 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -20,10 +20,10 @@
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
{
- struct wpabuf *pubkey;
+ struct wpabuf *pubkey = NULL;
wpa_printf(MSG_DEBUG, "WPS: * Public Key");
- wpabuf_free(wps->dh_privkey);
+ wpabuf_clear_free(wps->dh_privkey);
wps->dh_privkey = NULL;
if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
wps->wps->dh_ctx) {
@@ -413,7 +413,8 @@
dev_pw_id);
addr[0] = wpabuf_head(pubkey);
hash_len = wpabuf_len(pubkey);
- sha256_vector(1, addr, &hash_len, pubkey_hash);
+ if (sha256_vector(1, addr, &hash_len, pubkey_hash) < 0)
+ return -1;
#ifdef CONFIG_WPS_TESTING
if (wps_corrupt_pkhash) {
wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index eadb22f..e8c4579 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
@@ -229,6 +229,16 @@
cred->key_len--;
#endif /* CONFIG_WPS_STRICT */
}
+
+
+ if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
+ (cred->key_len < 8 || has_ctrl_char(cred->key, cred->key_len))) {
+ wpa_printf(MSG_INFO, "WPS: Reject credential with invalid WPA/WPA2-Personal passphrase");
+ wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
+ cred->key, cred->key_len);
+ return -1;
+ }
+
return 0;
}
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index c6a1cfd..2e34721 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -90,7 +90,7 @@
}
/* Own DH private key is not needed anymore */
- wpabuf_free(wps->dh_privkey);
+ wpabuf_clear_free(wps->dh_privkey);
wps->dh_privkey = NULL;
wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
@@ -100,7 +100,7 @@
len[0] = wpabuf_len(dh_shared);
sha256_vector(1, addr, len, dhkey);
wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
- wpabuf_free(dh_shared);
+ wpabuf_clear_free(dh_shared);
/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
addr[0] = wps->nonce_e;
@@ -129,23 +129,26 @@
}
-void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
- size_t dev_passwd_len)
+int wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+ size_t dev_passwd_len)
{
u8 hash[SHA256_MAC_LEN];
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
- (dev_passwd_len + 1) / 2, hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
+ (dev_passwd_len + 1) / 2, hash) < 0)
+ return -1;
os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
- dev_passwd + (dev_passwd_len + 1) / 2,
- dev_passwd_len / 2, hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
+ dev_passwd + (dev_passwd_len + 1) / 2,
+ dev_passwd_len / 2, hash) < 0)
+ return -1;
os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
dev_passwd, dev_passwd_len);
wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
+ return 0;
}
@@ -173,7 +176,7 @@
wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
wpabuf_len(decrypted))) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
return NULL;
}
@@ -184,14 +187,14 @@
pad = *pos;
if (pad > wpabuf_len(decrypted)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
return NULL;
}
for (i = 0; i < pad; i++) {
if (*pos-- != pad) {
wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
"string");
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
return NULL;
}
}
@@ -373,7 +376,7 @@
wps_build_mac_addr(plain, wps->dev.mac_addr) ||
wps_build_wfa_ext(plain, 0, NULL, 0)) {
os_free(data.new_psk);
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
@@ -421,7 +424,7 @@
wps_build_wfa_ext(data, 0, NULL, 0)) {
wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
"token");
- wpabuf_free(data);
+ wpabuf_clear_free(data);
return NULL;
}
@@ -658,7 +661,7 @@
wpabuf_free(*pubkey);
*pubkey = pub;
- wpabuf_free(*privkey);
+ wpabuf_clear_free(*privkey);
*privkey = priv;
return 0;
@@ -689,7 +692,7 @@
}
*id = 0x10 + val % 0xfff0;
- wpabuf_free(*dev_pw);
+ wpabuf_clear_free(*dev_pw);
*dev_pw = pw;
return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 9321b72..4175077 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -173,7 +173,8 @@
wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
return NULL;
}
- wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+ if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
+ return NULL;
if (wps->wps->ap && random_pool_ready() != 1) {
wpa_printf(MSG_INFO,
@@ -224,11 +225,11 @@
wps_build_encr_settings(wps, msg, plain) ||
wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->state = RECV_M6;
return msg;
@@ -394,11 +395,11 @@
wps_build_encr_settings(wps, msg, plain) ||
wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
if (wps->wps->ap && wps->wps->registrar) {
/*
@@ -1007,11 +1008,11 @@
eattr.key_wrap_auth) ||
wps_process_creds(wps, eattr.cred, eattr.cred_len,
eattr.num_cred, attr->version2 != NULL)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = WPS_MSG_DONE;
return WPS_CONTINUE;
@@ -1112,7 +1113,7 @@
}
if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -1122,11 +1123,11 @@
if (wps_parse_msg(decrypted, &eattr) < 0 ||
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_r_snonce1(wps, eattr.r_snonce1)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_M5;
return WPS_CONTINUE;
@@ -1165,7 +1166,7 @@
}
if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -1175,11 +1176,11 @@
if (wps_parse_msg(decrypted, &eattr) < 0 ||
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_r_snonce2(wps, eattr.r_snonce2)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
if (wps->wps->ap)
wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_AP_PIN_SUCCESS,
@@ -1236,7 +1237,7 @@
if (wps_validate_m8_encr(decrypted, wps->wps->ap,
attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -1249,11 +1250,11 @@
eattr.num_cred, attr->version2 != NULL) ||
wps_process_ap_settings_e(wps, &eattr, decrypted,
attr->version2 != NULL)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = WPS_MSG_DONE;
return WPS_CONTINUE;
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index f7154f8..fe0c60b 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -132,8 +132,8 @@
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
const char *label, u8 *res, size_t res_len);
int wps_derive_keys(struct wps_data *wps);
-void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
- size_t dev_passwd_len);
+int wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+ size_t dev_passwd_len);
struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
size_t encr_len);
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
diff --git a/src/wps/wps_module_tests.c b/src/wps/wps_module_tests.c
index 3506307..23bed4b 100644
--- a/src/wps/wps_module_tests.c
+++ b/src/wps/wps_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "wps_attr_parse.h"
struct wps_attr_parse_test {
@@ -17,7 +18,7 @@
int extra;
};
-const struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
+static const struct wps_attr_parse_test wps_attr_parse_test_cases[] = {
/* Empty message */
{ "", 0, 0 },
/* Truncated attribute header */
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 25e88d5..fac8bd8 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -703,7 +703,7 @@
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
wps_registrar_flush(reg);
- wpabuf_free(reg->extra_cred);
+ wpabuf_clear_free(reg->extra_cred);
os_free(reg);
}
@@ -1577,13 +1577,13 @@
if (wbuf == NULL)
return -1;
if (wps_build_credential(wbuf, cred)) {
- wpabuf_free(wbuf);
+ wpabuf_clear_free(wbuf);
return -1;
}
wpabuf_put_be16(msg, ATTR_CRED);
wpabuf_put_be16(msg, wpabuf_len(wbuf));
wpabuf_put_buf(msg, wbuf);
- wpabuf_free(wbuf);
+ wpabuf_clear_free(wbuf);
return 0;
}
@@ -1751,14 +1751,14 @@
return -1;
if (wps_build_credential(cred, &wps->cred)) {
- wpabuf_free(cred);
+ wpabuf_clear_free(cred);
return -1;
}
wpabuf_put_be16(msg, ATTR_CRED);
wpabuf_put_be16(msg, wpabuf_len(cred));
wpabuf_put_buf(msg, cred);
- wpabuf_free(cred);
+ wpabuf_clear_free(cred);
skip_cred_build:
if (wps->wps->registrar->extra_cred) {
@@ -1796,7 +1796,7 @@
}
if (wps_build_ap_settings(wps, plain)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
@@ -1804,7 +1804,7 @@
wpabuf_put_be16(msg, ATTR_CRED);
wpabuf_put_be16(msg, wpabuf_len(plain));
wpabuf_put_buf(msg, plain);
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return msg;
}
@@ -1864,10 +1864,10 @@
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain)) {
wpabuf_free(msg);
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
config_in_m2 = 1;
}
#endif /* CONFIG_WPS_NFC */
@@ -1928,7 +1928,8 @@
wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
- wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+ if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
+ return NULL;
plain = wpabuf_alloc(200);
if (plain == NULL)
@@ -1949,11 +1950,11 @@
wps_build_encr_settings(wps, msg, plain) ||
wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->state = RECV_M5;
return msg;
@@ -1984,11 +1985,11 @@
wps_build_encr_settings(wps, msg, plain) ||
wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wpabuf_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->wps_pin_revealed = 1;
wps->state = RECV_M7;
@@ -2021,11 +2022,11 @@
wps_build_encr_settings(wps, msg, plain) ||
wps_build_wfa_ext(msg, 0, NULL, 0) ||
wps_build_authenticator(wps, msg)) {
- wpabuf_free(plain);
- wpabuf_free(msg);
+ wpabuf_clear_free(plain);
+ wpabuf_clear_free(msg);
return NULL;
}
- wpabuf_free(plain);
+ wpabuf_clear_free(plain);
wps->state = RECV_DONE;
return msg;
@@ -2785,7 +2786,7 @@
}
if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -2795,11 +2796,11 @@
if (wps_parse_msg(decrypted, &eattr) < 0 ||
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_e_snonce1(wps, eattr.e_snonce1)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_M6;
return WPS_CONTINUE;
@@ -2937,7 +2938,7 @@
if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er,
attr->version2 != NULL) < 0) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
@@ -2948,12 +2949,12 @@
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_e_snonce2(wps, eattr.e_snonce2) ||
wps_process_ap_settings_r(wps, &eattr)) {
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- wpabuf_free(decrypted);
+ wpabuf_clear_free(decrypted);
wps->state = SEND_M8;
return WPS_CONTINUE;
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 968fc03..a685ce4 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -100,12 +100,6 @@
}
-static int str_starts(const char *str, const char *start)
-{
- return os_strncmp(str, start, os_strlen(start)) == 0;
-}
-
-
/***************************************************************************
* Advertisements.
* These are multicast to the world to tell them we are here.
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 09399cd..96d5cd0 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -25,6 +25,9 @@
# Disable unused parameter warnings
L_CFLAGS += -Wno-unused-parameter
+# Disable redefined macro warnings
+L_CFLAGS += -Wno-macro-redefined
+
# Set Android extended P2P functionality
L_CFLAGS += -DANDROID_P2P
@@ -49,6 +52,12 @@
L_CFLAGS += -mabi=aapcs-linux
endif
+# C++ flags for hidl interface
+L_CPPFLAGS := -Wall -Werror
+# TODO: Remove these allowed warnings later.
+L_CPPFLAGS += -Wno-unused-variable -Wno-unused-parameter
+L_CPPFLAGS += -Wno-unused-private-field
+
INCLUDES = $(LOCAL_PATH)
INCLUDES += $(LOCAL_PATH)/src
INCLUDES += $(LOCAL_PATH)/src/common
@@ -86,7 +95,10 @@
OBJS += src/utils/common.c
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
+OBJS += src/utils/bitfield.c
OBJS += wmm_ac.c
+OBJS += op_classes.c
+OBJS += rrm.c
OBJS_p = wpa_passphrase.c
OBJS_p += src/utils/common.c
OBJS_p += src/utils/wpa_debug.c
@@ -94,6 +106,7 @@
OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
OBJS_c += src/utils/wpa_debug.c
OBJS_c += src/utils/common.c
+OBJS_c += src/common/cli.c
OBJS_d =
OBJS_priv =
@@ -203,6 +216,10 @@
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_IEEE80211R_AP
+CONFIG_IEEE80211R=y
+endif
+
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R
OBJS += src/rsn_supp/wpa_ft.c
@@ -231,6 +248,12 @@
NEED_DH_GROUPS=y
endif
+ifdef CONFIG_FILS
+L_CFLAGS += -DCONFIG_FILS
+NEED_SHA384=y
+NEED_AES_SIV=y
+endif
+
ifdef CONFIG_WNM
L_CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.c
@@ -251,6 +274,10 @@
L_CFLAGS += -DCONFIG_PEERKEY
endif
+ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+L_CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL
+endif
+
ifndef CONFIG_NO_WPA
OBJS += src/rsn_supp/wpa.c
OBJS += src/rsn_supp/preauth.c
@@ -287,7 +314,6 @@
OBJS += src/p2p/p2p_dev_disc.c
OBJS += src/p2p/p2p_group.c
OBJS += src/ap/p2p_hostapd.c
-OBJS += src/utils/bitfield.c
L_CFLAGS += -DCONFIG_P2P
NEED_GAS=y
NEED_OFFCHANNEL=y
@@ -797,11 +823,16 @@
OBJS += src/ap/beacon.c
OBJS += src/ap/bss_load.c
OBJS += src/ap/eap_user_db.c
+OBJS += src/ap/neighbor_db.c
+OBJS += src/ap/rrm.c
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
ifdef CONFIG_IEEE80211AC
OBJS += src/ap/ieee802_11_vht.c
endif
+ifdef CONFIG_IEEE80211AX
+OBJS += src/ap/ieee802_11_he.c
+endif
endif
ifdef CONFIG_WNM
OBJS += src/ap/wnm_ap.c
@@ -809,6 +840,9 @@
ifdef CONFIG_MBO
OBJS += src/ap/mbo_ap.c
endif
+ifdef CONFIG_FILS
+OBJS += src/ap/fils_hlp.c
+endif
ifdef CONFIG_CTRL_IFACE
OBJS += src/ap/ctrl_iface_ap.c
endif
@@ -823,11 +857,9 @@
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211AX
+L_CFLAGS += -DCONFIG_IEEE80211AX
endif
-
-ifdef CONFIG_MBO
-OBJS += mbo.c
-L_CFLAGS += -DCONFIG_MBO
endif
ifdef NEED_AP_MLME
@@ -851,13 +883,19 @@
endif
endif
+ifdef CONFIG_MBO
+OBJS += mbo.c
+L_CFLAGS += -DCONFIG_MBO
+endif
+
ifdef NEED_RSN_AUTHENTICATOR
L_CFLAGS += -DCONFIG_NO_RADIUS
NEED_AES_WRAP=y
OBJS += src/ap/wpa_auth.c
OBJS += src/ap/wpa_auth_ie.c
OBJS += src/ap/pmksa_cache_auth.c
-ifdef CONFIG_IEEE80211R
+ifdef CONFIG_IEEE80211R_AP
+L_CFLAGS += -DCONFIG_IEEE80211R_AP
OBJS += src/ap/wpa_auth_ft.c
endif
ifdef CONFIG_PEERKEY
@@ -1257,6 +1295,9 @@
endif
ifdef NEED_SHA384
L_CFLAGS += -DCONFIG_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/sha384.c
+endif
OBJS += src/crypto/sha384-prf.c
endif
@@ -1347,14 +1388,9 @@
OBJS += $(DBUS_OBJS)
L_CFLAGS += $(DBUS_CFLAGS)
-ifdef CONFIG_CTRL_IFACE_BINDER
-BINDER=y
-L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER
-OBJS += binder/binder.cpp binder/binder_manager.cpp
-OBJS += binder/supplicant.cpp binder/iface.cpp
-OBJS += binder/fi/w1/wpa_supplicant/ISupplicant.aidl
-OBJS += binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
-OBJS += binder/fi/w1/wpa_supplicant/IIface.aidl
+ifdef CONFIG_CTRL_IFACE_HIDL
+WPA_SUPPLICANT_USE_HIDL=y
+L_CFLAGS += -DCONFIG_HIDL -DCONFIG_CTRL_IFACE_HIDL
endif
ifdef CONFIG_READLINE
@@ -1550,6 +1586,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := wpa_cli
+LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_TAGS := debug
LOCAL_SHARED_LIBRARIES := libc libcutils liblog
LOCAL_CFLAGS := $(L_CFLAGS)
@@ -1560,6 +1597,8 @@
########################
include $(CLEAR_VARS)
LOCAL_MODULE := wpa_supplicant
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
ifdef CONFIG_DRIVER_CUSTOM
LOCAL_STATIC_LIBRARIES := libCustomWifi
endif
@@ -1572,14 +1611,12 @@
LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY)
endif
ifeq ($(CONFIG_TLS), openssl)
-LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
+LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore-wifi-hidl
endif
# With BoringSSL we need libkeystore-engine in order to provide access to
# keystore keys.
-ifneq (,$(wildcard external/boringssl/flavor.mk))
-LOCAL_SHARED_LIBRARIES += libkeystore-engine
-endif
+LOCAL_SHARED_LIBRARIES += libkeystore-engine-wifi-hidl
ifdef CONFIG_DRIVER_NL80211
ifneq ($(wildcard external/libnl),)
@@ -1594,9 +1631,10 @@
ifeq ($(DBUS), y)
LOCAL_SHARED_LIBRARIES += libdbus
endif
-ifeq ($(BINDER), y)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder frameworks/native/aidl/binder
-LOCAL_SHARED_LIBRARIES += libutils libbinder
+ifeq ($(WPA_SUPPLICANT_USE_HIDL), y)
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.0
+LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils
+LOCAL_STATIC_LIBRARIES += libwpa_hidl
endif
include $(BUILD_EXECUTABLE)
@@ -1628,11 +1666,39 @@
include $(CLEAR_VARS)
LOCAL_MODULE = libwpa_client
+LOCAL_PROPRIETARY_MODULE := true
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils liblog
-LOCAL_COPY_HEADERS_TO := libwpa_client
-LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
-LOCAL_COPY_HEADERS += src/common/qca-vendor.h
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/wpa_client_include $(LOCAL_PATH)/wpa_client_include/libwpa_client
include $(BUILD_SHARED_LIBRARY)
+
+ifeq ($(WPA_SUPPLICANT_USE_HIDL), y)
+### Hidl service library ###
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := libwpa_hidl
+LOCAL_CPPFLAGS := $(L_CPPFLAGS)
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+HIDL_INTERFACE_VERSION = 1.0
+LOCAL_SRC_FILES := \
+ hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
+ hidl/$(HIDL_INTERFACE_VERSION)/hidl_manager.cpp \
+ hidl/$(HIDL_INTERFACE_VERSION)/iface_config_utils.cpp \
+ hidl/$(HIDL_INTERFACE_VERSION)/p2p_iface.cpp \
+ hidl/$(HIDL_INTERFACE_VERSION)/p2p_network.cpp \
+ hidl/$(HIDL_INTERFACE_VERSION)/sta_iface.cpp \
+ hidl/$(HIDL_INTERFACE_VERSION)/sta_network.cpp \
+ hidl/$(HIDL_INTERFACE_VERSION)/supplicant.cpp
+LOCAL_SHARED_LIBRARIES := \
+ android.hardware.wifi.supplicant@$(HIDL_INTERFACE_VERSION) \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ libutils
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/hidl/$(HIDL_INTERFACE_VERSION)
+include $(BUILD_STATIC_LIBRARY)
+endif # WPA_SUPPLICANT_USE_HIDL == y
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index facd90e..f28055f 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,149 @@
ChangeLog for wpa_supplicant
+2016-10-02 - v2.6
+ * fixed WNM Sleep Mode processing when PMF is not enabled
+ [http://w1.fi/security/2015-6/] (CVE-2015-5310)
+ * fixed EAP-pwd last fragment validation
+ [http://w1.fi/security/2015-7/] (CVE-2015-5315)
+ * fixed EAP-pwd unexpected Confirm message processing
+ [http://w1.fi/security/2015-8/] (CVE-2015-5316)
+ * fixed WPS configuration update vulnerability with malformed passphrase
+ [http://w1.fi/security/2016-1/] (CVE-2016-4476)
+ * fixed configuration update vulnerability with malformed parameters set
+ over the local control interface
+ [http://w1.fi/security/2016-1/] (CVE-2016-4477)
+ * fixed TK configuration to the driver in EAPOL-Key 3/4 retry case
+ * extended channel switch support for P2P GO
+ * started to throttle control interface event message bursts to avoid
+ issues with monitor sockets running out of buffer space
+ * mesh mode fixes/improvements
+ - generate proper AID for peer
+ - enable WMM by default
+ - add VHT support
+ - fix PMKID derivation
+ - improve robustness on various exchanges
+ - fix peer link counting in reconnect case
+ - improve mesh joining behavior
+ - allow DTIM period to be configured
+ - allow HT to be disabled (disable_ht=1)
+ - add MESH_PEER_ADD and MESH_PEER_REMOVE commands
+ - add support for PMKSA caching
+ - add minimal support for SAE group negotiation
+ - allow pairwise/group cipher to be configured in the network profile
+ - use ieee80211w profile parameter to enable/disable PMF and derive
+ a separate TX IGTK if PMF is enabled instead of using MGTK
+ incorrectly
+ - fix AEK and MTK derivation
+ - remove GTKdata and IGTKdata from Mesh Peering Confirm/Close
+ - note: these changes are not fully backwards compatible for secure
+ (RSN) mesh network
+ * fixed PMKID derivation with SAE
+ * added support for requesting and fetching arbitrary ANQP-elements
+ without internal support in wpa_supplicant for the specific element
+ (anqp[265]=<hexdump> in "BSS <BSSID>" command output)
+ * P2P
+ - filter control characters in group client device names to be
+ consistent with other P2P peer cases
+ - support VHT 80+80 MHz and 160 MHz
+ - indicate group completion in P2P Client role after data association
+ instead of already after the WPS provisioning step
+ - improve group-join operation to use SSID, if known, to filter BSS
+ entries
+ - added optional ssid=<hexdump> argument to P2P_CONNECT for join case
+ - added P2P_GROUP_MEMBER command to fetch client interface address
+ * P2PS
+ - fix follow-on PD Response behavior
+ - fix PD Response generation for unknown peer
+ - fix persistent group reporting
+ - add channel policy to PD Request
+ - add group SSID to the P2PS-PROV-DONE event
+ - allow "P2P_CONNECT <addr> p2ps" to be used without specifying the
+ default PIN
+ * BoringSSL
+ - support for OCSP stapling
+ - support building of h20-osu-client
+ * D-Bus
+ - add ExpectDisconnect()
+ - add global config parameters as properties
+ - add SaveConfig()
+ - add VendorElemAdd(), VendorElemGet(), VendorElemRem()
+ * fixed Suite B 192-bit AKM to use proper PMK length
+ (note: this makes old releases incompatible with the fixed behavior)
+ * improved PMF behavior for cases where the AP and STA has different
+ configuration by not trying to connect in some corner cases where the
+ connection cannot succeed
+ * added option to reopen debug log (e.g., to rotate the file) upon
+ receipt of SIGHUP signal
+ * EAP-pwd: added support for Brainpool Elliptic Curves
+ (with OpenSSL 1.0.2 and newer)
+ * fixed EAPOL reauthentication after FT protocol run
+ * fixed FTIE generation for 4-way handshake after FT protocol run
+ * extended INTERFACE_ADD command to allow certain type (sta/ap)
+ interface to be created
+ * fixed and improved various FST operations
+ * added 80+80 MHz and 160 MHz VHT support for IBSS/mesh
+ * fixed SIGNAL_POLL in IBSS and mesh cases
+ * added an option to abort an ongoing scan (used to speed up connection
+ and can also be done with the new ABORT_SCAN command)
+ * TLS client
+ - do not verify CA certificates when ca_cert is not specified
+ - support validating server certificate hash
+ - support SHA384 and SHA512 hashes
+ - add signature_algorithms extension into ClientHello
+ - support TLS v1.2 signature algorithm with SHA384 and SHA512
+ - support server certificate probing
+ - allow specific TLS versions to be disabled with phase2 parameter
+ - support extKeyUsage
+ - support PKCS #5 v2.0 PBES2
+ - support PKCS #5 with PKCS #12 style key decryption
+ - minimal support for PKCS #12
+ - support OCSP stapling (including ocsp_multi)
+ * OpenSSL
+ - support OpenSSL 1.1 API changes
+ - drop support for OpenSSL 0.9.8
+ - drop support for OpenSSL 1.0.0
+ * added support for multiple schedule scan plans (sched_scan_plans)
+ * added support for external server certificate chain validation
+ (tls_ext_cert_check=1 in the network profile phase1 parameter)
+ * made phase2 parser more strict about correct use of auth=<val> and
+ autheap=<val> values
+ * improved GAS offchannel operations with comeback request
+ * added SIGNAL_MONITOR command to request signal strength monitoring
+ events
+ * added command for retrieving HS 2.0 icons with in-memory storage
+ (REQ_HS20_ICON, GET_HS20_ICON, DEL_HS20_ICON commands and
+ RX-HS20-ICON event)
+ * enabled ACS support for AP mode operations with wpa_supplicant
+ * EAP-PEAP: fixed interoperability issue with Windows 2012r2 server
+ ("Invalid Compound_MAC in cryptobinding TLV")
+ * EAP-TTLS: fixed success after fragmented final Phase 2 message
+ * VHT: added interoperability workaround for 80+80 and 160 MHz channels
+ * WNM: workaround for broken AP operating class behavior
+ * added kqueue(2) support for eloop (CONFIG_ELOOP_KQUEUE)
+ * nl80211:
+ - add support for full station state operations
+ - do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled
+ - add NL80211_ATTR_PREV_BSSID with Connect command
+ - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
+ unencrypted EAPOL frames
+ * added initial MBO support; number of extensions to WNM BSS Transition
+ Management
+ * added support for PBSS/PCP and P2P on 60 GHz
+ * Interworking: add credential realm to EAP-TLS identity
+ * fixed EAPOL-Key Request Secure bit to be 1 if PTK is set
+ * HS 2.0: add support for configuring frame filters
+ * added POLL_STA command to check connectivity in AP mode
+ * added initial functionality for location related operations
+ * started to ignore pmf=1/2 parameter for non-RSN networks
+ * added wps_disabled=1 network profile parameter to allow AP mode to
+ be started without enabling WPS
+ * wpa_cli: added action script support for AP-ENABLED and AP-DISABLED
+ events
+ * improved Public Action frame addressing
+ - add gas_address3 configuration parameter to control Address 3
+ behavior
+ * number of small fixes
+
2015-09-27 - v2.5
* fixed P2P validation of SSID element length before copying it
[http://w1.fi/security/2015-1/] (CVE-2015-1863)
diff --git a/wpa_supplicant/CleanSpec.mk b/wpa_supplicant/CleanSpec.mk
new file mode 100644
index 0000000..26b4fd9
--- /dev/null
+++ b/wpa_supplicant/CleanSpec.mk
@@ -0,0 +1,54 @@
+# -*- mode: makefile -*-
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(OUT_DIR)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+#
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/obj/SHARED_LIBRARIES/libdvm*)
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/wpa_supplicant*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/wpa_cli*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libwpa_client*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libwpa_client*)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 550d44b..7bcb7e4 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -103,6 +103,9 @@
OBJS += ../src/utils/common.o
OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/bitfield.o
+OBJS += op_classes.o
+OBJS += rrm.o
OBJS_p = wpa_passphrase.o
OBJS_p += ../src/utils/common.o
OBJS_p += ../src/utils/wpa_debug.o
@@ -110,6 +113,7 @@
OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
OBJS_c += ../src/utils/wpa_debug.o
OBJS_c += ../src/utils/common.o
+OBJS_c += ../src/common/cli.o
OBJS += wmm_ac.o
ifndef CONFIG_OS
@@ -242,6 +246,10 @@
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_IEEE80211R_AP
+CONFIG_IEEE80211R=y
+endif
+
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R
OBJS += ../src/rsn_supp/wpa_ft.o
@@ -270,6 +278,12 @@
NEED_DH_GROUPS=y
endif
+ifdef CONFIG_FILS
+CFLAGS += -DCONFIG_FILS
+NEED_SHA384=y
+NEED_AES_SIV=y
+endif
+
ifdef CONFIG_WNM
CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.o
@@ -290,6 +304,10 @@
CFLAGS += -DCONFIG_PEERKEY
endif
+ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL
+endif
+
ifndef CONFIG_NO_WPA
OBJS += ../src/rsn_supp/wpa.o
OBJS += ../src/rsn_supp/preauth.o
@@ -334,7 +352,6 @@
OBJS += ../src/p2p/p2p_dev_disc.o
OBJS += ../src/p2p/p2p_group.o
OBJS += ../src/ap/p2p_hostapd.o
-OBJS += ../src/utils/bitfield.o
CFLAGS += -DCONFIG_P2P
NEED_GAS=y
NEED_OFFCHANNEL=y
@@ -844,11 +861,16 @@
OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/bss_load.o
OBJS += ../src/ap/eap_user_db.o
+OBJS += ../src/ap/neighbor_db.o
+OBJS += ../src/ap/rrm.o
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
ifdef CONFIG_IEEE80211AC
OBJS += ../src/ap/ieee802_11_vht.o
endif
+ifdef CONFIG_IEEE80211AX
+OBJS += ../src/ap/ieee802_11_he.o
+endif
endif
ifdef CONFIG_WNM
OBJS += ../src/ap/wnm_ap.o
@@ -856,6 +878,9 @@
ifdef CONFIG_MBO
OBJS += ../src/ap/mbo_ap.o
endif
+ifdef CONFIG_FILS
+OBJS += ../src/ap/fils_hlp.o
+endif
ifdef CONFIG_CTRL_IFACE
OBJS += ../src/ap/ctrl_iface_ap.o
endif
@@ -870,11 +895,9 @@
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211AX
+CFLAGS += -DCONFIG_IEEE80211AX
endif
-
-ifdef CONFIG_MBO
-OBJS += mbo.o
-CFLAGS += -DCONFIG_MBO
endif
ifdef NEED_AP_MLME
@@ -898,13 +921,19 @@
endif
endif
+ifdef CONFIG_MBO
+OBJS += mbo.o
+CFLAGS += -DCONFIG_MBO
+endif
+
ifdef NEED_RSN_AUTHENTICATOR
CFLAGS += -DCONFIG_NO_RADIUS
NEED_AES_WRAP=y
OBJS += ../src/ap/wpa_auth.o
OBJS += ../src/ap/wpa_auth_ie.o
OBJS += ../src/ap/pmksa_cache_auth.o
-ifdef CONFIG_IEEE80211R
+ifdef CONFIG_IEEE80211R_AP
+CFLAGS += -DCONFIG_IEEE80211R_AP
OBJS += ../src/ap/wpa_auth_ft.o
endif
ifdef CONFIG_PEERKEY
@@ -928,9 +957,13 @@
#dynamic symbol loading that is now used in pcsc_funcs.c
#LIBS += -lwinscard
else
+ifdef CONFIG_OSX
+LIBS += -framework PCSC
+else
LIBS += -lpcsclite -lpthread
endif
endif
+endif
ifdef CONFIG_SIM_SIMULATOR
CFLAGS += -DCONFIG_SIM_SIMULATOR
@@ -1303,6 +1336,9 @@
OBJS += $(SHA256OBJS)
endif
ifdef NEED_SHA384
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/sha384.o
+endif
CFLAGS += -DCONFIG_SHA384
OBJS += ../src/crypto/sha384-prf.o
endif
@@ -1382,6 +1418,7 @@
DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1)
endif
DBUS_CFLAGS += $(DBUS_INCLUDE)
+DBUS_INTERFACE=fi.epitest.hostap.WPASupplicant
endif
ifdef CONFIG_CTRL_IFACE_DBUS_NEW
@@ -1407,6 +1444,7 @@
DBUS_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO
endif
DBUS_CFLAGS += $(DBUS_INCLUDE)
+DBUS_INTERFACE=fi.w1.wpa_supplicant1
endif
ifdef DBUS
@@ -1573,9 +1611,6 @@
ifdef CONFIG_WPS
OBJS += ../src/wps/wps_module_tests.o
endif
-ifndef CONFIG_P2P
-OBJS += ../src/utils/bitfield.o
-endif
endif
OBJS += ../src/drivers/driver_common.o
@@ -1769,11 +1804,13 @@
endif
%.service: %.service.in
- $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
+ -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
@$(E) " sed" $<
%@.service: %.service.arg.in
- $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' \
+ -e 's|\@DBUS_INTERFACE\@|$(DBUS_INTERFACE)|g' $< >$@
@$(E) " sed" $<
wpa_supplicant.exe: wpa_supplicant
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 11ab01a..730714b 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
WPA Supplicant
==============
-Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
@@ -83,7 +83,7 @@
authentication)
(following methods are supported, but since they do not generate keying
material, they cannot be used with WPA or IEEE 802.1X WEP keying)
- * EAP-MD5-Challenge
+ * EAP-MD5-Challenge
* EAP-MSCHAPv2
* EAP-GTC
* EAP-OTP
@@ -965,6 +965,17 @@
also possible to run multiple wpa_priv processes at the same time, if
desired.
+It should be noted that the interface used between wpa_supplicant and
+wpa_priv does not include all the capabilities of the wpa_supplicant
+driver interface and at times, this interface lacks update especially
+for recent addition. Consequently, use of wpa_priv does come with the
+price of somewhat reduced available functionality. The next section
+describing how wpa_supplicant can be used with reduced privileges
+without having to handle the complexity of separate wpa_priv. While that
+approve does not provide separation for network admin capabilities, it
+does allow other root privileges to be dropped without the drawbacks of
+the wpa_priv process.
+
Linux capabilities instead of privileged process
------------------------------------------------
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 0a8bf98..1679347 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -1,9 +1,9 @@
# Example wpa_supplicant build time configuration
#
# This file lists the configuration options that are used when building the
-# hostapd binary. All lines starting with # are ignored. Configuration option
-# lines must be commented out complete, if they are not to be included, i.e.,
-# just setting VARIABLE=n is not disabling that variable.
+# wpa_supplicant binary. All lines starting with # are ignored. Configuration
+# option lines must be commented out complete, if they are not to be included,
+# i.e., just setting VARIABLE=n is not disabling that variable.
#
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
# be modified from here. In most cases, these lines should use += in order not
@@ -91,11 +91,10 @@
CONFIG_EAP_TTLS=y
# EAP-FAST
-# Note: Default OpenSSL package does not include support for all the
-# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
-# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
-# to add the needed functions.
-CONFIG_EAP_FAST=y
+# Note: If OpenSSL is used as the TLS library, OpenSSL 1.0 or newer is needed
+# for EAP-FAST support. Older OpenSSL releases would need to be patched, e.g.,
+# with openssl-0.9.8x-tls-extensions.patch, to add the needed functions.
+#CONFIG_EAP_FAST=y
# EAP-GTC
CONFIG_EAP_GTC=y
@@ -152,6 +151,9 @@
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
+# EAP-EKE
+#CONFIG_EAP_EKE=y
+
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
@@ -176,8 +178,10 @@
# Select control interface backend for external programs, e.g, wpa_cli:
# unix = UNIX domain sockets (default for Linux/*BSD)
# udp = UDP sockets using localhost (127.0.0.1)
+# udp6 = UDP IPv6 sockets using localhost (::1)
# named_pipe = Windows Named Pipe (default for Windows)
# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose)
# y = use default (backwards compatibility)
# If this option is commented out, control interface is not included in the
# build.
@@ -254,6 +258,9 @@
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
+# Should we use kqueue instead of select? Select is used by default.
+#CONFIG_ELOOP_KQUEUE=y
+
# Select layer 2 packet implementation
# linux = Linux packet socket (default)
# pcap = libpcap/libdnet/WinPcap
@@ -263,6 +270,12 @@
# none = Empty template
CONFIG_L2_PACKET=linux
+# Disable Linux packet socket workaround applicable for station interface
+# in a bridge for EAPOL frames. This should be uncommented only if the kernel
+# is known to not have the regression issue in packet socket behavior with
+# bridge interfaces (commit 'bridge: respect RFC2863 operational state')').
+#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y
+
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
@@ -324,9 +337,9 @@
# Add introspection support for new DBus control interface
#CONFIG_CTRL_IFACE_DBUS_INTRO=y
-# Add support for Binder control interface
+# Add support for Hidl control interface
# Only applicable for Android platforms.
-#CONFIG_CTRL_IFACE_BINDER=y
+CONFIG_CTRL_IFACE_HIDL=y
# Add support for loading EAP methods dynamically as shared libraries.
# When this option is enabled, each EAP method can be either included
@@ -349,9 +362,13 @@
# amount of memory/flash.
#CONFIG_DYNAMIC_EAP_METHODS=y
-# IEEE Std 802.11r-2008 (Fast BSS Transition)
+# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
CONFIG_IEEE80211R=y
+# IEEE Std 802.11r-2008 (Fast BSS Transition) for AP mode (implies
+# CONFIG_IEEE80211R).
+#CONFIG_IEEE80211R_AP=y
+
# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
#CONFIG_DEBUG_FILE=y
@@ -429,6 +446,10 @@
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
CONFIG_IEEE80211N=y
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
CONFIG_WNM=y
@@ -442,6 +463,9 @@
# Hotspot 2.0
CONFIG_HS20=y
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
+
# Disable roaming in wpa_supplicant
CONFIG_NO_ROAMING=y
@@ -489,4 +513,32 @@
# Support Multi Band Operation
#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
+# This is needed to be able to use mode=1 network profile with proto=RSN and
+# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None).
+#CONFIG_IBSS_RSN=y
+
+# External PMKSA cache control
+# This can be used to enable control interface commands that allow the current
+# PMKSA cache entries to be fetched and new entries to be added.
+#CONFIG_PMKSA_CACHE_EXTERNAL=y
+
+# Mesh Networking (IEEE 802.11s)
+#CONFIG_MESH=y
+
+# Background scanning modules
+# These can be used to request wpa_supplicant to perform background scanning
+# operations for roaming within an ESS (same SSID). See the bgscan parameter in
+# the wpa_supplicant.conf file for more details.
+# Periodic background scans based on signal strength
+#CONFIG_BGSCAN_SIMPLE=y
+# Learn channels used by the network and try to avoid bgscans on other
+# channels (experimental)
+#CONFIG_BGSCAN_LEARN=y
+
include $(wildcard $(LOCAL_PATH)/android_config_*.inc)
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index b133d03..1721d6a 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -168,6 +168,7 @@
if (mode->vht_capab && ssid->vht) {
conf->ieee80211ac = 1;
+ conf->vht_capab |= mode->vht_capab;
wpas_conf_ap_vht(wpa_s, conf, mode);
}
}
@@ -214,6 +215,13 @@
if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
return -1;
+ if (ssid->pbss > 1) {
+ wpa_printf(MSG_ERROR, "Invalid pbss value(%d) for AP mode",
+ ssid->pbss);
+ return -1;
+ }
+ bss->pbss = ssid->pbss;
+
#ifdef CONFIG_ACS
if (ssid->acs) {
/* Setting channel to 0 in order to enable ACS */
@@ -227,6 +235,7 @@
conf->ieee80211d = 1;
conf->country[0] = wpa_s->conf->country[0];
conf->country[1] = wpa_s->conf->country[1];
+ conf->country[2] = ' ';
}
#ifdef CONFIG_P2P
@@ -287,7 +296,10 @@
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
bss->wpa = ssid->proto;
- bss->wpa_key_mgmt = ssid->key_mgmt;
+ if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ else
+ bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
if (ssid->psk_set) {
bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
@@ -296,6 +308,7 @@
return -1;
os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
bss->ssid.wpa_psk->group = 1;
+ bss->ssid.wpa_psk_set = 1;
} else if (ssid->passphrase) {
bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
@@ -409,6 +422,8 @@
!(bss->wpa & 2)))
goto no_wps; /* WPS2 does not allow WPA/TKIP-only
* configuration */
+ if (ssid->wps_disabled)
+ goto no_wps;
bss->eap_server = 1;
if (!ssid->ignore_broadcast_ssid)
@@ -437,6 +452,8 @@
os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
bss->pbc_in_m1 = wpa_s->conf->pbc_in_m1;
+ if (ssid->eap.fragment_size != DEFAULT_FRAGMENT_SIZE)
+ bss->fragment_size = ssid->eap.fragment_size;
no_wps:
#endif /* CONFIG_WPS */
@@ -453,7 +470,8 @@
wpabuf_dup(wpa_s->conf->ap_vendor_elements);
}
- bss->pbss = ssid->pbss;
+ bss->ftm_responder = wpa_s->conf->ftm_responder;
+ bss->ftm_initiator = wpa_s->conf->ftm_initiator;
return 0;
}
@@ -649,12 +667,17 @@
if (ieee80211_is_dfs(params.freq.freq))
params.freq.freq = 0; /* set channel after CAC */
+ if (params.p2p)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_GO);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_AP_BSS);
+
if (wpa_drv_associate(wpa_s, ¶ms) < 0) {
wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
return -1;
}
- wpa_s->ap_iface = hapd_iface = os_zalloc(sizeof(*wpa_s->ap_iface));
+ wpa_s->ap_iface = hapd_iface = hostapd_alloc_iface();
if (hapd_iface == NULL)
return -1;
hapd_iface->owner = wpa_s;
@@ -1363,7 +1386,6 @@
hapd = wpa_s->ap_iface->bss[0];
return hostapd_ctrl_iface_stop_ap(hapd);
}
-#endif /* CONFIG_CTRL_IFACE */
int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
@@ -1418,6 +1440,44 @@
}
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr,
+ char *buf, size_t len)
+{
+ return hostapd_ctrl_iface_pmksa_list_mesh(wpa_s->ifmsh->bss[0], addr,
+ &buf[0], len);
+}
+
+
+int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct external_pmksa_cache *entry;
+ void *pmksa_cache;
+
+ pmksa_cache = hostapd_ctrl_iface_pmksa_create_entry(wpa_s->own_addr,
+ cmd);
+ if (!pmksa_cache)
+ return -1;
+
+ entry = os_zalloc(sizeof(struct external_pmksa_cache));
+ if (!entry)
+ return -1;
+
+ entry->pmksa_cache = pmksa_cache;
+
+ dl_list_add(&wpa_s->mesh_external_pmksa_cache, &entry->list);
+
+ return 0;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+#endif /* CONFIG_CTRL_IFACE */
+
+
#ifdef NEED_AP_MLME
void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
struct dfs_event *radar)
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 5a59ddc..3fa656f 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -85,6 +85,9 @@
int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
size_t len);
void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
+int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr,
+ char *buf, size_t len);
+int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd);
void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
struct dfs_event *radar);
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
index d12eb21..5056a93 100644
--- a/wpa_supplicant/autoscan.c
+++ b/wpa_supplicant/autoscan.c
@@ -16,13 +16,6 @@
#include "scan.h"
#include "autoscan.h"
-#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
-extern const struct autoscan_ops autoscan_exponential_ops;
-#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
-
-#ifdef CONFIG_AUTOSCAN_PERIODIC
-extern const struct autoscan_ops autoscan_periodic_ops;
-#endif /* CONFIG_AUTOSCAN_PERIODIC */
static const struct autoscan_ops * autoscan_modules[] = {
#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
@@ -54,11 +47,16 @@
struct sched_scan_plan *scan_plans;
/* Give preference to scheduled scan plans if supported/configured */
- if (wpa_s->sched_scan_plans)
+ if (wpa_s->sched_scan_plans) {
+ wpa_printf(MSG_DEBUG,
+ "autoscan: sched_scan_plans set - use it instead");
return 0;
+ }
- if (wpa_s->autoscan && wpa_s->autoscan_priv)
+ if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+ wpa_printf(MSG_DEBUG, "autoscan: Already initialized");
return 0;
+ }
if (name == NULL)
return 0;
diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h
index e2a7652..560684f 100644
--- a/wpa_supplicant/autoscan.h
+++ b/wpa_supplicant/autoscan.h
@@ -27,6 +27,16 @@
int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
+/* Available autoscan modules */
+
+#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
+extern const struct autoscan_ops autoscan_exponential_ops;
+#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
+
+#ifdef CONFIG_AUTOSCAN_PERIODIC
+extern const struct autoscan_ops autoscan_periodic_ops;
+#endif /* CONFIG_AUTOSCAN_PERIODIC */
+
#else /* CONFIG_AUTOSCAN */
static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
index f74cdbf..1ea6401 100644
--- a/wpa_supplicant/bgscan.c
+++ b/wpa_supplicant/bgscan.c
@@ -13,12 +13,6 @@
#include "config_ssid.h"
#include "bgscan.h"
-#ifdef CONFIG_BGSCAN_SIMPLE
-extern const struct bgscan_ops bgscan_simple_ops;
-#endif /* CONFIG_BGSCAN_SIMPLE */
-#ifdef CONFIG_BGSCAN_LEARN
-extern const struct bgscan_ops bgscan_learn_ops;
-#endif /* CONFIG_BGSCAN_LEARN */
static const struct bgscan_ops * bgscan_modules[] = {
#ifdef CONFIG_BGSCAN_SIMPLE
@@ -40,8 +34,6 @@
const struct bgscan_ops *ops = NULL;
bgscan_deinit(wpa_s);
- if (name == NULL)
- return -1;
params = os_strchr(name, ':');
if (params == NULL) {
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
index 9131e4e..3df1550 100644
--- a/wpa_supplicant/bgscan.h
+++ b/wpa_supplicant/bgscan.h
@@ -39,6 +39,15 @@
int current_signal, int current_noise,
int current_txrate);
+/* Available bgscan modules */
+
+#ifdef CONFIG_BGSCAN_SIMPLE
+extern const struct bgscan_ops bgscan_simple_ops;
+#endif /* CONFIG_BGSCAN_SIMPLE */
+#ifdef CONFIG_BGSCAN_LEARN
+extern const struct bgscan_ops bgscan_learn_ops;
+#endif /* CONFIG_BGSCAN_LEARN */
+
#else /* CONFIG_BGSCAN */
static inline int bgscan_init(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index a320cc4..cb732f7 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -320,9 +320,6 @@
{
const char *pos;
- if (params == NULL)
- return 0;
-
data->short_interval = atoi(params);
pos = os_strchr(params, ':');
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index a467cc5..41a26df 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -56,12 +56,7 @@
} else {
if (data->scan_interval == data->short_interval) {
data->short_scan_count++;
- /*
- * Spend at most the duration of a long scan interval
- * scanning at the short scan interval. After that,
- * revert to the long scan interval.
- */
- if (data->short_scan_count > data->max_short_scans) {
+ if (data->short_scan_count >= data->max_short_scans) {
data->scan_interval = data->long_interval;
wpa_printf(MSG_DEBUG, "bgscan simple: Backing "
"off to long scan interval");
@@ -85,9 +80,6 @@
{
const char *pos;
- if (params == NULL)
- return 0;
-
data->short_interval = atoi(params);
pos = os_strchr(params, ':');
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
deleted file mode 100644
index 28f7a2b..0000000
--- a/wpa_supplicant/binder/binder.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-
-#include "binder_manager.h"
-
-extern "C" {
-#include "utils/includes.h"
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "binder.h"
-#include "binder_i.h"
-}
-
-void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct wpa_global *global = (wpa_global *) eloop_ctx;
- struct wpas_binder_priv *priv = (wpas_binder_priv *) sock_ctx;
-
- wpa_printf(MSG_DEBUG, "Processing binder events on FD %d",
- priv->binder_fd);
- android::IPCThreadState::self()->handlePolledCommands();
-}
-
-
-struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global)
-{
- struct wpas_binder_priv *priv;
- wpa_supplicant_binder::BinderManager *binder_manager;
-
- priv = (wpas_binder_priv *) os_zalloc(sizeof(*priv));
- if (!priv)
- return NULL;
- priv->global = global;
-
- android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
- android::IPCThreadState::self()->disableBackgroundScheduling(true);
- android::IPCThreadState::self()->setupPolling(&priv->binder_fd);
- wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd);
- if (priv->binder_fd < 0)
- goto err;
- /* Look for read events from the binder socket in the eloop. */
- if (eloop_register_read_sock(priv->binder_fd, wpas_binder_sock_handler,
- global, priv) < 0)
- goto err;
-
- binder_manager = wpa_supplicant_binder::BinderManager::getInstance();
- if (!binder_manager)
- goto err;
- binder_manager->registerBinderService(global);
- /* We may not need to store this binder manager reference in the
- * global data strucure because we've made it a singleton class. */
- priv->binder_manager = (void *) binder_manager;
-
- return priv;
-
-err:
- wpas_binder_deinit(priv);
- return NULL;
-}
-
-
-void wpas_binder_deinit(struct wpas_binder_priv *priv)
-{
- if (!priv)
- return;
-
- wpa_supplicant_binder::BinderManager::destroyInstance();
- eloop_unregister_read_sock(priv->binder_fd);
- android::IPCThreadState::shutdown();
-}
-
-
-int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s->global->binder)
- return 1;
-
- wpa_supplicant_binder::BinderManager *binder_manager =
- wpa_supplicant_binder::BinderManager::getInstance();
- if (!binder_manager)
- return 1;
-
- return binder_manager->registerInterface(wpa_s);
-}
-
-
-int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s->global->binder)
- return 1;
-
- wpa_supplicant_binder::BinderManager *binder_manager =
- wpa_supplicant_binder::BinderManager::getInstance();
- if (!binder_manager)
- return 1;
-
- return binder_manager->unregisterInterface(wpa_s);
-}
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
deleted file mode 100644
index a165074..0000000
--- a/wpa_supplicant/binder/binder.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef BINDER_H
-#define BINDER_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif /* _cplusplus */
-
-/**
- * This is the binder RPC interface entry point to the wpa_supplicant core.
- * This initializes the binder driver & BinderManager instance and then forwards
- * all the notifcations from the supplicant core to the BinderManager.
- */
-struct wpas_binder_priv;
-struct wpa_global;
-
-struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global);
-void wpas_binder_deinit(struct wpas_binder_priv *priv);
-
-#ifdef CONFIG_CTRL_IFACE_BINDER
-int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
-int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
-#else /* CONFIG_CTRL_IFACE_BINDER */
-static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
-{
- return 0;
-}
-#endif /* CONFIG_CTRL_IFACE_BINDER */
-
-#ifdef _cplusplus
-}
-#endif /* _cplusplus */
-
-#endif /* BINDER_H */
diff --git a/wpa_supplicant/binder/binder_i.h b/wpa_supplicant/binder/binder_i.h
deleted file mode 100644
index e8087b6..0000000
--- a/wpa_supplicant/binder/binder_i.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef BINDER_I_H
-#define BINDER_I_H
-
-#ifdef _cplusplus
-extern "C" {
-#endif // _cplusplus
-
-struct wpas_binder_priv {
- int binder_fd;
- struct wpa_global *global;
- void *binder_manager;
-};
-
-#ifdef _cplusplus
-}
-#endif /* _cplusplus */
-
-#endif /* BINDER_I_H */
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
deleted file mode 100644
index 728f4b7..0000000
--- a/wpa_supplicant/binder/binder_manager.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include <binder/IServiceManager.h>
-
-#include "binder_manager.h"
-
-extern "C" {
-#include "utils/includes.h"
-#include "utils/common.h"
-}
-
-namespace wpa_supplicant_binder {
-
-const char BinderManager::kBinderServiceName[] = "fi.w1.wpa_supplicant";
-BinderManager *BinderManager::instance_ = NULL;
-
-
-BinderManager * BinderManager::getInstance()
-{
- if (!instance_)
- instance_ = new BinderManager();
- return instance_;
-}
-
-
-void BinderManager::destroyInstance()
-{
- if (instance_)
- delete instance_;
- instance_ = NULL;
-}
-
-
-int BinderManager::registerBinderService(struct wpa_global *global)
-{
- /* Create the main binder service object and register with
- * system service manager. */
- supplicant_object_ = new Supplicant(global);
- android::String16 service_name(kBinderServiceName);
- android::defaultServiceManager()->addService(
- service_name,
- android::IInterface::asBinder(supplicant_object_));
- return 0;
-}
-
-
-int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s)
- return 1;
-
- /* Using the corresponding wpa_supplicant pointer as key to our
- * object map. */
- const void *iface_key = wpa_s;
-
- /* Return failure if we already have an object for that iface_key. */
- if (iface_object_map_.find(iface_key) != iface_object_map_.end())
- return 1;
-
- iface_object_map_[iface_key] = new Iface(wpa_s);
- if (!iface_object_map_[iface_key].get())
- return 1;
-
- wpa_s->binder_object_key = iface_key;
-
- return 0;
-}
-
-
-int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
-{
- if (!wpa_s || !wpa_s->binder_object_key)
- return 1;
-
- const void *iface_key = wpa_s;
- if (iface_object_map_.find(iface_key) == iface_object_map_.end())
- return 1;
-
- /* Delete the corresponding iface object from our map. */
- iface_object_map_.erase(iface_key);
- wpa_s->binder_object_key = NULL;
- return 0;
-}
-
-
-int BinderManager::getIfaceBinderObjectByKey(
- const void *iface_object_key,
- android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
-{
- if (!iface_object_key || !iface_object)
- return 1;
-
- if (iface_object_map_.find(iface_object_key) == iface_object_map_.end())
- return 1;
-
- *iface_object = iface_object_map_[iface_object_key];
- return 0;
-}
-
-} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
deleted file mode 100644
index 687e740..0000000
--- a/wpa_supplicant/binder/binder_manager.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef BINDER_MANAGER_H
-#define BINDER_MANAGER_H
-
-#include <map>
-#include <string>
-
-#include "supplicant.h"
-#include "iface.h"
-
-struct wpa_global;
-struct wpa_supplicant;
-
-namespace wpa_supplicant_binder {
-
-/**
- * BinderManager is responsible for managing the lifetime of all
- * binder objects created by wpa_supplicant. This is a singleton
- * class which is created by the supplicant core and can be used
- * to get references to the binder objects.
- */
-class BinderManager {
-public:
- static const char kBinderServiceName[];
-
- static BinderManager * getInstance();
- static void destroyInstance();
- int registerBinderService(struct wpa_global *global);
- int registerInterface(struct wpa_supplicant *wpa_s);
- int unregisterInterface(struct wpa_supplicant *wpa_s);
- int getIfaceBinderObjectByKey(
- const void *iface_object_key,
- android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
-
-private:
- BinderManager() = default;
- ~BinderManager() = default;
-
- /* Singleton instance of this class. */
- static BinderManager *instance_;
- /* The main binder service object. */
- android::sp<Supplicant> supplicant_object_;
- /* Map of all the interface specific binder objects controlled by
- * wpa_supplicant. This map is keyed in by the corresponding
- * wpa_supplicant structure pointer. */
- std::map<const void *, android::sp<Iface>> iface_object_map_;
-};
-
-} /* namespace wpa_supplicant_binder */
-
-#endif /* BINDER_MANAGER_H */
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
deleted file mode 100644
index ea11d42..0000000
--- a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-package fi.w1.wpa_supplicant;
-
-/**
- * Interface exposed by wpa_supplicant for each network interface it controls.
- */
-interface IIface {
-}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
deleted file mode 100644
index 1cbee20..0000000
--- a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * WPA Supplicant - binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-package fi.w1.wpa_supplicant;
-
-import android.os.PersistableBundle;
-import fi.w1.wpa_supplicant.IIface;
-
-/**
- * Interface exposed by the wpa_supplicant binder service registered
- * with the service manager with name: fi.w1.wpa_supplicant.
- */
-interface ISupplicant {
- /* Error values returned by the service to RPC method calls. */
- const int ERROR_INVALID_ARGS = 1;
- const int ERROR_UNKNOWN = 2;
- const int ERROR_IFACE_EXISTS = 3;
- const int ERROR_IFACE_UNKNOWN = 4;
-
- /**
- * Registers a wireless interface in wpa_supplicant.
- *
- * @param args A dictionary with arguments used to add the interface to
- * wpa_supplicant.
- * The dictionary may contain the following entries:
- * Ifname(String) Name of the network interface to control, e.g.,
- * wlan0.
- * BridgeIfname(String) Name of the bridge interface to control, e.g.,
- * br0.
- * Driver(String) Driver name which the interface uses, e.g., nl80211.
- * ConfigFile(String) Configuration file path.
- *
- * @return Binder object representing the interface.
- */
- IIface CreateInterface(in PersistableBundle args);
-
- /**
- * Deregisters a wireless interface from wpa_supplicant.
- *
- * @param ifname Name of the network interface, e.g., wlan0
- */
- void RemoveInterface(in @utf8InCpp String ifname);
-
- /**
- * Gets a binder object for the interface corresponding to ifname
- * which wpa_supplicant already controls.
- *
- * @param ifname Name of the network interface, e.g., wlan0
- *
- * @return Binder object representing the interface.
- */
- IIface GetInterface(in @utf8InCpp String ifname);
-}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
deleted file mode 100644
index d624d91..0000000
--- a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-package fi.w1.wpa_supplicant;
-
-import android.os.PersistableBundle;
-
-/**
- * Callback Interface exposed by the wpa_supplicant service. Clients need
- * to host an instance of this binder object and pass a reference of the object
- * to wpa_supplicant via the registerCallbacksObject method.
- */
-interface ISupplicantCallbacks {
-}
diff --git a/wpa_supplicant/binder/iface.cpp b/wpa_supplicant/binder/iface.cpp
deleted file mode 100644
index af2548d..0000000
--- a/wpa_supplicant/binder/iface.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "iface.h"
-
-namespace wpa_supplicant_binder {
-
-Iface::Iface(struct wpa_supplicant *wpa_s)
- : wpa_s_(wpa_s)
-{
-}
-
-} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/iface.h b/wpa_supplicant/binder/iface.h
deleted file mode 100644
index acc8e55..0000000
--- a/wpa_supplicant/binder/iface.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef IFACE_H
-#define IFACE_H
-
-#include "fi/w1/wpa_supplicant/BnIface.h"
-
-extern "C" {
-#include "utils/includes.h"
-#include "utils/common.h"
-#include "../wpa_supplicant_i.h"
-}
-
-namespace wpa_supplicant_binder {
-
-/**
- * Implementation of Iface binder object. Each unique binder
- * object is used for control operations on a specific interface
- * controlled by wpa_supplicant.
- */
-class Iface : public fi::w1::wpa_supplicant::BnIface
-{
-public:
- Iface(struct wpa_supplicant *wpa_s);
- virtual ~Iface() = default;
-
-private:
- /* Raw pointer to the structure maintained by the core for this
- * interface. */
- struct wpa_supplicant *wpa_s_;
-};
-
-} /* namespace wpa_supplicant_binder */
-
-#endif /* IFACE_H */
diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp
deleted file mode 100644
index 6844e5a..0000000
--- a/wpa_supplicant/binder/supplicant.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "binder_manager.h"
-#include "supplicant.h"
-
-namespace wpa_supplicant_binder {
-
-Supplicant::Supplicant(struct wpa_global *global)
- : wpa_global_(global)
-{
-}
-
-
-android::binder::Status Supplicant::CreateInterface(
- const android::os::PersistableBundle ¶ms,
- android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
-{
- android::String16 driver, ifname, confname, bridge_ifname;
-
- /* Check if required Ifname argument is missing */
- if (!params.getString(android::String16("Ifname"), &ifname))
- return android::binder::Status::fromServiceSpecificError(
- ERROR_INVALID_ARGS,
- android::String8("Ifname missing in params."));
- /* Retrieve the remaining params from the dictionary */
- params.getString(android::String16("Driver"), &driver);
- params.getString(android::String16("ConfigFile"), &confname);
- params.getString(android::String16("BridgeIfname"), &bridge_ifname);
-
- /*
- * Try to get the wpa_supplicant record for this iface, return
- * an error if we already control it.
- */
- if (wpa_supplicant_get_iface(wpa_global_,
- android::String8(ifname).string()) != NULL)
- return android::binder::Status::fromServiceSpecificError(
- ERROR_IFACE_EXISTS,
- android::String8("wpa_supplicant already controls this interface."));
-
- android::binder::Status status;
- struct wpa_supplicant *wpa_s = NULL;
- struct wpa_interface iface;
-
- os_memset(&iface, 0, sizeof(iface));
- iface.driver = os_strdup(android::String8(driver).string());
- iface.ifname = os_strdup(android::String8(ifname).string());
- iface.confname = os_strdup(android::String8(confname).string());
- iface.bridge_ifname = os_strdup(
- android::String8(bridge_ifname).string());
- /* Otherwise, have wpa_supplicant attach to it. */
- wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
- /* The supplicant core creates a corresponding binder object via
- * BinderManager when |wpa_supplicant_add_iface| is called. */
- if (!wpa_s || !wpa_s->binder_object_key) {
- status = android::binder::Status::fromServiceSpecificError(
- ERROR_UNKNOWN,
- android::String8("wpa_supplicant couldn't grab this interface."));
- } else {
- BinderManager *binder_manager = BinderManager::getInstance();
-
- if (!binder_manager ||
- binder_manager->getIfaceBinderObjectByKey(
- wpa_s->binder_object_key, aidl_return))
- status = android::binder::Status::fromServiceSpecificError(
- ERROR_UNKNOWN,
- android::String8("wpa_supplicant encountered a binder error."));
- else
- status = android::binder::Status::ok();
- }
- os_free((void *) iface.driver);
- os_free((void *) iface.ifname);
- os_free((void *) iface.confname);
- os_free((void *) iface.bridge_ifname);
- return status;
-}
-
-
-android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
-{
- struct wpa_supplicant *wpa_s;
-
- wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
- if (!wpa_s || !wpa_s->binder_object_key)
- return android::binder::Status::fromServiceSpecificError(
- ERROR_IFACE_UNKNOWN,
- android::String8("wpa_supplicant does not control this interface."));
- if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
- return android::binder::Status::fromServiceSpecificError(
- ERROR_UNKNOWN,
- android::String8("wpa_supplicant couldn't remove this interface."));
- return android::binder::Status::ok();
-}
-
-
-android::binder::Status Supplicant::GetInterface(
- const std::string &ifname,
- android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
-{
- struct wpa_supplicant *wpa_s;
-
- wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
- if (!wpa_s || !wpa_s->binder_object_key)
- return android::binder::Status::fromServiceSpecificError(
- ERROR_IFACE_UNKNOWN,
- android::String8("wpa_supplicant does not control this interface."));
-
- BinderManager *binder_manager = BinderManager::getInstance();
- if (!binder_manager ||
- binder_manager->getIfaceBinderObjectByKey(wpa_s->binder_object_key,
- aidl_return))
- return android::binder::Status::fromServiceSpecificError(
- ERROR_UNKNOWN,
- android::String8("wpa_supplicant encountered a binder error."));
-
- return android::binder::Status::ok();
-}
-
-} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h
deleted file mode 100644
index b96f4e6..0000000
--- a/wpa_supplicant/binder/supplicant.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * binder interface for wpa_supplicant daemon
- * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef SUPPLICANT_H
-#define SUPPLICANT_H
-
-#include "fi/w1/wpa_supplicant/BnSupplicant.h"
-#include "fi/w1/wpa_supplicant/IIface.h"
-#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
-
-extern "C" {
-#include "utils/includes.h"
-#include "utils/common.h"
-#include "../wpa_supplicant_i.h"
-}
-
-namespace wpa_supplicant_binder {
-
-/**
- * Implementation of the supplicant binder object. This binder
- * object is used core for global control operations on
- * wpa_supplicant.
- */
-class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant
-{
-public:
- Supplicant(struct wpa_global *global);
- virtual ~Supplicant() = default;
-
- android::binder::Status CreateInterface(
- const android::os::PersistableBundle ¶ms,
- android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
- override;
- android::binder::Status RemoveInterface(
- const std::string &ifname) override;
- android::binder::Status GetInterface(
- const std::string &ifname,
- android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
- override;
-
-private:
- /* Raw pointer to the global structure maintained by the core. */
- struct wpa_global *wpa_global_;
- /* All the callback objects registered by the clients. */
- std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>>
- callbacks_;
-};
-
-} /* namespace wpa_supplicant_binder */
-
-#endif /* SUPPLICANT_H */
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index a83ca10..914bd5d 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
+#include "eap_peer/eap.h"
#include "wpa_supplicant_i.h"
#include "config.h"
#include "notify.h"
@@ -92,6 +93,7 @@
ANQP_DUP(nai_realm);
ANQP_DUP(anqp_3gpp);
ANQP_DUP(domain_name);
+ ANQP_DUP(fils_realm_info);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
ANQP_DUP(hs20_capability_list);
@@ -167,6 +169,7 @@
wpabuf_free(anqp->nai_realm);
wpabuf_free(anqp->anqp_3gpp);
wpabuf_free(anqp->domain_name);
+ wpabuf_free(anqp->fils_realm_info);
while ((elem = dl_list_first(&anqp->anqp_elems,
struct wpa_bss_anqp_elem, list))) {
@@ -213,8 +216,8 @@
}
-static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- const char *reason)
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason)
{
if (wpa_s->last_scan_res) {
unsigned int i;
@@ -266,9 +269,9 @@
}
-static void calculate_update_time(const struct os_reltime *fetch_time,
- unsigned int age_ms,
- struct os_reltime *update_time)
+void calculate_update_time(const struct os_reltime *fetch_time,
+ unsigned int age_ms,
+ struct os_reltime *update_time)
{
os_time_t usec;
@@ -303,6 +306,47 @@
}
+static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+ struct wpa_ssid *ssid;
+ struct wpabuf *wps_ie;
+ int pbc = 0, ret;
+
+ wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ if (!wps_ie)
+ return 0;
+
+ if (wps_is_selected_pbc_registrar(wps_ie)) {
+ pbc = 1;
+ } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
+ wpabuf_free(wps_ie);
+ return 0;
+ }
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+ continue;
+ if (ssid->ssid_len &&
+ (ssid->ssid_len != bss->ssid_len ||
+ os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
+ continue;
+
+ if (pbc)
+ ret = eap_is_wps_pbc_enrollee(&ssid->eap);
+ else
+ ret = eap_is_wps_pin_enrollee(&ssid->eap);
+ wpabuf_free(wps_ie);
+ return ret;
+ }
+ wpabuf_free(wps_ie);
+#endif /* CONFIG_WPS */
+
+ return 0;
+}
+
+
static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_ssid *ssid;
@@ -341,7 +385,8 @@
struct wpa_bss *bss;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- if (!wpa_bss_known(wpa_s, bss)) {
+ if (!wpa_bss_known(wpa_s, bss) &&
+ !wpa_bss_is_wps_candidate(wpa_s, bss)) {
wpa_bss_remove(wpa_s, bss, __func__);
return 0;
}
@@ -552,6 +597,42 @@
{
u32 changes;
+ if (bss->last_update_idx == wpa_s->bss_update_idx) {
+ struct os_reltime update_time;
+
+ /*
+ * Some drivers (e.g., cfg80211) include multiple BSS entries
+ * for the same BSS if that BSS's channel changes. The BSS list
+ * implementation in wpa_supplicant does not do that and we need
+ * to filter out the obsolete results here to make sure only the
+ * most current BSS information remains in the table.
+ */
+ wpa_printf(MSG_DEBUG, "BSS: " MACSTR
+ " has multiple entries in the scan results - select the most current one",
+ MAC2STR(bss->bssid));
+ calculate_update_time(fetch_time, res->age, &update_time);
+ wpa_printf(MSG_DEBUG,
+ "Previous last_update: %u.%06u (freq %d%s)",
+ (unsigned int) bss->last_update.sec,
+ (unsigned int) bss->last_update.usec,
+ bss->freq,
+ (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
+ wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
+ (unsigned int) update_time.sec,
+ (unsigned int) update_time.usec,
+ res->freq,
+ (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
+ if ((bss->flags & WPA_BSS_ASSOCIATED) ||
+ (!(res->flags & WPA_SCAN_ASSOCIATED) &&
+ !os_reltime_before(&bss->last_update, &update_time))) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore this BSS entry since the previous update looks more current");
+ return bss;
+ }
+ wpa_printf(MSG_DEBUG,
+ "Accept this BSS entry since it looks more current than the previous update");
+ }
+
changes = wpa_bss_compare_res(bss, res);
if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index f7f72f3..84505fa 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -40,6 +40,7 @@
struct wpabuf *nai_realm;
struct wpabuf *anqp_3gpp;
struct wpabuf *domain_name;
+ struct wpabuf *fils_realm_info;
struct dl_list anqp_elems; /* list of struct wpa_bss_anqp_elem */
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
@@ -113,6 +114,8 @@
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res,
struct os_reltime *fetch_time);
+void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ const char *reason);
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s);
@@ -165,4 +168,8 @@
bss->level = new_level;
}
+void calculate_update_time(const struct os_reltime *fetch_time,
+ unsigned int age_ms,
+ struct os_reltime *update_time);
+
#endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 4376676..58ecf19 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "utils/uuid.h"
#include "utils/ip_addr.h"
+#include "common/ieee802_1x_defs.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -478,6 +479,12 @@
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
(u8 *) value, len);
+ if (has_ctrl_char((u8 *) value, len)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid passphrase character",
+ line);
+ return -1;
+ }
if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
os_memcmp(ssid->passphrase, value, len) == 0) {
/* No change to the previously configured value */
@@ -713,6 +720,18 @@
else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ else if (os_strcmp(start, "FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA256;
+ else if (os_strcmp(start, "FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FILS_SHA384;
+#ifdef CONFIG_IEEE80211R
+ else if (os_strcmp(start, "FT-FILS-SHA256") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA256;
+ else if (os_strcmp(start, "FT-FILS-SHA384") == 0)
+ val |= WPA_KEY_MGMT_FT_FILS_SHA384;
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -1810,6 +1829,69 @@
#endif /* CONFIG_MESH */
+#ifdef CONFIG_MACSEC
+
+static int wpa_config_parse_mka_cak(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ if (hexstr2bin(value, ssid->mka_cak, MACSEC_CAK_LEN) ||
+ value[MACSEC_CAK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CAK '%s'.",
+ line, value);
+ return -1;
+ }
+
+ ssid->mka_psk_set |= MKA_PSK_SET_CAK;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CAK", ssid->mka_cak, MACSEC_CAK_LEN);
+ return 0;
+}
+
+
+static int wpa_config_parse_mka_ckn(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ if (hexstr2bin(value, ssid->mka_ckn, MACSEC_CKN_LEN) ||
+ value[MACSEC_CKN_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MKA-CKN '%s'.",
+ line, value);
+ return -1;
+ }
+
+ ssid->mka_psk_set |= MKA_PSK_SET_CKN;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "MKA-CKN", ssid->mka_ckn, MACSEC_CKN_LEN);
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mka_cak(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+ return NULL;
+
+ return wpa_config_write_string_hex(ssid->mka_cak, MACSEC_CAK_LEN);
+}
+
+
+static char * wpa_config_write_mka_ckn(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+ return NULL;
+ return wpa_config_write_string_hex(ssid->mka_ckn, MACSEC_CKN_LEN);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MACSEC */
+
+
/* Helper macros for network block parser */
#ifdef OFFSET
@@ -1999,6 +2081,7 @@
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
+ { INT(group_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P
@@ -2043,12 +2126,18 @@
{ INT(beacon_int) },
#ifdef CONFIG_MACSEC
{ INT_RANGE(macsec_policy, 0, 1) },
+ { INT_RANGE(macsec_integ_only, 0, 1) },
+ { INT_RANGE(macsec_port, 1, 65534) },
+ { INT_RANGE(mka_priority, 0, 255) },
+ { FUNC_KEY(mka_cak) },
+ { FUNC_KEY(mka_ckn) },
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
{ INT(update_identifier) },
#endif /* CONFIG_HS20 */
{ INT_RANGE(mac_addr, 0, 2) },
- { INT_RANGE(pbss, 0, 1) },
+ { INT_RANGE(pbss, 0, 2) },
+ { INT_RANGE(wps_disabled, 0, 1) },
};
#undef OFFSET
@@ -2530,6 +2619,9 @@
#ifdef CONFIG_IEEE80211W
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_MACSEC
+ ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
+#endif /* CONFIG_MACSEC */
ssid->mac_addr = -1;
}
@@ -2662,9 +2754,8 @@
return props;
err:
- value = *props;
- while (value)
- os_free(value++);
+ for (i = 0; props[i]; i++)
+ os_free(props[i]);
os_free(props);
return NULL;
#endif /* NO_CONFIG_WRITE */
@@ -2695,14 +2786,15 @@
const struct parse_data *field = &ssid_fields[i];
if (os_strcmp(var, field->name) == 0) {
char *ret = field->writer(field, ssid);
- if (ret != NULL && (os_strchr(ret, '\r') != NULL ||
- os_strchr(ret, '\n') != NULL)) {
+
+ if (ret && has_newline(ret)) {
wpa_printf(MSG_ERROR,
- "Found newline in value for %s; "
- "not returning it", var);
+ "Found newline in value for %s; not returning it",
+ var);
os_free(ret);
ret = NULL;
}
+
return ret;
}
}
@@ -2889,6 +2981,8 @@
if (os_strcmp(var, "password") == 0 &&
os_strncmp(value, "ext:", 4) == 0) {
+ if (has_newline(value))
+ return -1;
str_clear_free(cred->password);
cred->password = os_strdup(value);
cred->ext_password = 1;
@@ -2939,9 +3033,14 @@
}
val = wpa_config_parse_string(value, &len);
- if (val == NULL) {
+ if (val == NULL ||
+ (os_strcmp(var, "excluded_ssid") != 0 &&
+ os_strcmp(var, "roaming_consortium") != 0 &&
+ os_strcmp(var, "required_roaming_consortium") != 0 &&
+ has_newline(val))) {
wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
"value '%s'.", line, var, value);
+ os_free(val);
return -1;
}
@@ -3649,6 +3748,7 @@
config->ctrl_interface = os_strdup(ctrl_interface);
if (driver_param)
config->driver_param = os_strdup(driver_param);
+ config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
return config;
}
@@ -3750,6 +3850,12 @@
return -1;
}
+ if (has_newline(pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
+ line, data->name);
+ return -1;
+ }
+
tmp = os_strdup(pos);
if (tmp == NULL)
return -1;
@@ -3788,22 +3894,12 @@
struct wpa_config *config, int line,
const char *pos)
{
- size_t len;
struct wpabuf **dst, *tmp;
- len = os_strlen(pos);
- if (len & 0x01)
+ tmp = wpabuf_parse_bin(pos);
+ if (!tmp)
return -1;
- tmp = wpabuf_alloc(len / 2);
- if (tmp == NULL)
- return -1;
-
- if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
- wpabuf_free(tmp);
- return -1;
- }
-
dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
wpabuf_free(*dst);
*dst = tmp;
@@ -4350,6 +4446,7 @@
{ INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
{ INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
#endif /* CONFIG_FST */
+ { INT_RANGE(cert_in_cb, 0, 1), 0 },
{ INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
{ STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
#ifdef CONFIG_MBO
@@ -4357,6 +4454,11 @@
{ INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
#endif /*CONFIG_MBO */
+ { INT(gas_address3), 0 },
+ { INT_RANGE(ftm_responder, 0, 1), 0 },
+ { INT_RANGE(ftm_initiator, 0, 1), 0 },
+ { INT(gas_rand_addr_lifetime), 0 },
+ { INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 9a13f5f..2f2bb01 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1039,7 +1039,8 @@
*
* By default, PMF is disabled unless enabled by the per-network
* ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
- * this default behavior.
+ * this default behavior for RSN network (this is not applicable for
+ * non-RSN cases).
*/
enum mfp_options pmf;
@@ -1291,6 +1292,57 @@
*/
enum mbo_cellular_capa mbo_cell_capa;
#endif /* CONFIG_MBO */
+
+ /**
+ * gas_address3 - GAS Address3 field behavior
+ *
+ * Values:
+ * 0 - P2P specification (Address3 = AP BSSID)
+ * 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+ * sent to not-associated AP; if associated, AP BSSID)
+ */
+ int gas_address3;
+
+ /**
+ * ftm_responder - Publish FTM (fine timing measurement)
+ * responder functionality
+ *
+ * Values:
+ * 0 - do not publish FTM responder functionality (Default)
+ * 1 - publish FTM responder functionality in
+ * bit 70 of Extended Capabilities element
+ * Note, actual FTM responder operation is managed outside
+ * wpa_supplicant.
+ */
+ int ftm_responder;
+
+ /**
+ * ftm_initiator - Publish FTM (fine timing measurement)
+ * initiator functionality
+ *
+ * Values:
+ * 0 - do not publish FTM initiator functionality (Default)
+ * 1 - publish FTM initiator functionality in
+ * bit 71 of Extended Capabilities element
+ * Note, actual FTM initiator operation is managed outside
+ * wpa_supplicant.
+ */
+ int ftm_initiator;
+
+ /**
+ * gas_rand_addr_lifetime - Lifetime of random MAC address for ANQP in
+ * seconds
+ */
+ unsigned int gas_rand_addr_lifetime;
+
+ /**
+ * gas_rand_mac_addr - GAS MAC address policy
+ *
+ * 0 = use permanent MAC address
+ * 1 = use random MAC address
+ * 2 = like 1, but maintain OUI (with local admin bit set)
+ */
+ int gas_rand_mac_addr;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 38061f1..84a1ee9 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -19,6 +19,7 @@
#include "config.h"
#include "base64.h"
#include "uuid.h"
+#include "common/ieee802_1x_defs.h"
#include "p2p/p2p.h"
#include "eap_peer/eap_methods.h"
#include "eap_peer/eap.h"
@@ -136,6 +137,9 @@
wpa_config_update_psk(ssid);
}
+ if (ssid->disabled == 2)
+ ssid->p2p_persistent_group = 1;
+
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
@@ -662,6 +666,40 @@
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MACSEC
+
+static void write_mka_cak(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CAK))
+ return;
+
+ value = wpa_config_get(ssid, "mka_cak");
+ if (!value)
+ return;
+ fprintf(f, "\tmka_cak=%s\n", value);
+ os_free(value);
+}
+
+
+static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!(ssid->mka_psk_set & MKA_PSK_SET_CKN))
+ return;
+
+ value = wpa_config_get(ssid, "mka_ckn");
+ if (!value)
+ return;
+ fprintf(f, "\tmka_ckn=%s\n", value);
+ os_free(value);
+}
+
+#endif /* CONFIG_MACSEC */
+
+
static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
{
int i;
@@ -756,6 +794,7 @@
INT(mixed_cell);
INT(max_oper_chwidth);
INT(pbss);
+ INT(wps_disabled);
#ifdef CONFIG_IEEE80211W
write_int(f, "ieee80211w", ssid->ieee80211w,
MGMT_FRAME_PROTECTION_DEFAULT);
@@ -771,6 +810,11 @@
INT(beacon_int);
#ifdef CONFIG_MACSEC
INT(macsec_policy);
+ write_mka_cak(f, ssid);
+ write_mka_ckn(f, ssid);
+ INT(macsec_integ_only);
+ INT(macsec_port);
+ INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
INT(update_identifier);
@@ -784,6 +828,7 @@
INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
#endif /* CONFIG_MESH */
INT(wpa_ptk_rekey);
+ INT(group_rekey);
INT(ignore_broadcast_ssid);
#ifdef CONFIG_HT_OVERRIDES
INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
@@ -1074,6 +1119,17 @@
}
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
+ {
+ int i;
+ char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
+
+ for (i = 0; i < config->num_sec_device_types; i++) {
+ buf = wps_dev_type_bin2str(config->sec_device_type[i],
+ _buf, sizeof(_buf));
+ if (buf)
+ fprintf(f, "sec_device_type=%s\n", buf);
+ }
+ }
if (config->p2p_listen_reg_class)
fprintf(f, "p2p_listen_reg_class=%d\n",
config->p2p_listen_reg_class);
@@ -1173,6 +1229,8 @@
config->bss_expiration_scan_count);
if (config->filter_ssids)
fprintf(f, "filter_ssids=%d\n", config->filter_ssids);
+ if (config->filter_rssi)
+ fprintf(f, "filter_rssi=%d\n", config->filter_rssi);
if (config->max_num_sta != DEFAULT_MAX_NUM_STA)
fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
if (config->disassoc_low_ack)
@@ -1224,7 +1282,7 @@
if (config->sae_groups) {
int i;
fprintf(f, "sae_groups=");
- for (i = 0; config->sae_groups[i] >= 0; i++) {
+ for (i = 0; config->sae_groups[i] > 0; i++) {
fprintf(f, "%s%d", i > 0 ? " " : "",
config->sae_groups[i]);
}
@@ -1276,6 +1334,9 @@
if (config->bgscan)
fprintf(f, "bgscan=\"%s\"\n", config->bgscan);
+ if (config->autoscan)
+ fprintf(f, "autoscan=%s\n", config->autoscan);
+
if (config->p2p_search_delay != DEFAULT_P2P_SEARCH_DELAY)
fprintf(f, "p2p_search_delay=%u\n",
config->p2p_search_delay);
@@ -1335,6 +1396,30 @@
fprintf(f, "mbo_cell_capa=%u\n", config->mbo_cell_capa);
#endif /* CONFIG_MBO */
+ if (config->gas_address3)
+ fprintf(f, "gas_address3=%d\n", config->gas_address3);
+
+ if (config->ftm_responder)
+ fprintf(f, "ftm_responder=%d\n", config->ftm_responder);
+ if (config->ftm_initiator)
+ fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator);
+
+ if (config->osu_dir)
+ fprintf(f, "osu_dir=%s\n", config->osu_dir);
+
+ if (config->fst_group_id)
+ fprintf(f, "fst_group_id=%s\n", config->fst_group_id);
+ if (config->fst_priority)
+ fprintf(f, "fst_priority=%d\n", config->fst_priority);
+ if (config->fst_llt)
+ fprintf(f, "fst_llt=%d\n", config->fst_llt);
+
+ if (config->gas_rand_addr_lifetime != DEFAULT_RAND_ADDR_LIFETIME)
+ fprintf(f, "gas_rand_addr_lifetime=%u\n",
+ config->gas_rand_addr_lifetime);
+ if (config->gas_rand_mac_addr)
+ fprintf(f, "gas_rand_mac_addr=%d\n", config->gas_rand_mac_addr);
+
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index eb7b87b..69ace37 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -361,10 +361,14 @@
/**
* pbss - Whether to use PBSS. Relevant to DMG networks only.
+ * 0 = do not use PBSS
+ * 1 = use PBSS
+ * 2 = don't care (not allowed in AP mode)
* Used together with mode configuration. When mode is AP, it
* means to start a PCP instead of a regular AP. When mode is INFRA it
- * means connect to a PCP instead of AP. P2P_GO and P2P_GROUP_FORMATION
- * modes must use PBSS in DMG network.
+ * means connect to a PCP instead of AP. In this mode you can also
+ * specify 2 (don't care) meaning connect to either AP or PCP.
+ * P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in DMG network.
*/
int pbss;
@@ -483,6 +487,14 @@
int wpa_ptk_rekey;
/**
+ * group_rekey - Group rekeying time in seconds
+ *
+ * This value, if non-zero, is used as the dot11RSNAConfigGroupRekeyTime
+ * parameter when operating in Authenticator role in IBSS.
+ */
+ int group_rekey;
+
+ /**
* scan_freq - Array of frequencies to scan or %NULL for all
*
* This is an optional zero-terminated array of frequencies in
@@ -716,6 +728,54 @@
* determine whether to use a secure session or not.
*/
int macsec_policy;
+
+ /**
+ * macsec_integ_only - Determines how MACsec are transmitted
+ *
+ * This setting applies only when MACsec is in use, i.e.,
+ * - macsec_policy is enabled
+ * - the key server has decided to enable MACsec
+ *
+ * 0: Encrypt traffic (default)
+ * 1: Integrity only
+ */
+ int macsec_integ_only;
+
+ /**
+ * macsec_port - MACsec port (in SCI)
+ *
+ * Port component of the SCI.
+ *
+ * Range: 1-65534 (default: 1)
+ */
+ int macsec_port;
+
+ /**
+ * mka_priority - Priority of MKA Actor
+ *
+ * Range: 0-255 (default: 255)
+ */
+ int mka_priority;
+
+ /**
+ * mka_ckn - MKA pre-shared CKN
+ */
+#define MACSEC_CKN_LEN 32
+ u8 mka_ckn[MACSEC_CKN_LEN];
+
+ /**
+ * mka_cak - MKA pre-shared CAK
+ */
+#define MACSEC_CAK_LEN 16
+ u8 mka_cak[MACSEC_CAK_LEN];
+
+#define MKA_PSK_SET_CKN BIT(0)
+#define MKA_PSK_SET_CAK BIT(1)
+#define MKA_PSK_SET (MKA_PSK_SET_CKN | MKA_PSK_SET_CAK)
+ /**
+ * mka_psk_set - Whether mka_ckn and mka_cak are set
+ */
+ u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
@@ -744,6 +804,14 @@
* this MBSS will trigger a peering attempt.
*/
int no_auto_peer;
+
+ /**
+ * wps_disabled - WPS disabled in AP mode
+ *
+ * 0 = WPS enabled and configured (default)
+ * 1 = WPS disabled
+ */
+ int wps_disabled;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 199f04f..82ba3b0 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -933,6 +933,7 @@
#ifdef CONFIG_HS20
INT(update_identifier);
#endif /* CONFIG_HS20 */
+ INT(group_rekey);
#undef STR
#undef INT
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8574437..761d917 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
+#include "utils/module_tests.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -311,6 +312,102 @@
}
+static int wpas_ctrl_iface_set_lci(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct wpabuf *lci;
+
+ if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
+ return 0;
+ }
+
+ lci = wpabuf_parse_bin(cmd);
+ if (!lci)
+ return -1;
+
+ if (os_get_reltime(&wpa_s->lci_time)) {
+ wpabuf_free(lci);
+ return -1;
+ }
+
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = lci;
+
+ return 0;
+}
+
+
+static int
+wpas_ctrl_set_relative_rssi(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ int relative_rssi;
+
+ if (os_strcmp(cmd, "disable") == 0) {
+ wpa_s->srp.relative_rssi_set = 0;
+ return 0;
+ }
+
+ relative_rssi = atoi(cmd);
+ if (relative_rssi < 0 || relative_rssi > 100)
+ return -1;
+ wpa_s->srp.relative_rssi = relative_rssi;
+ wpa_s->srp.relative_rssi_set = 1;
+ return 0;
+}
+
+
+static int wpas_ctrl_set_relative_band_adjust(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ char *pos;
+ int adjust_rssi;
+
+ /* <band>:adjust_value */
+ pos = os_strchr(cmd, ':');
+ if (!pos)
+ return -1;
+ pos++;
+ adjust_rssi = atoi(pos);
+ if (adjust_rssi < -100 || adjust_rssi > 100)
+ return -1;
+
+ if (os_strncmp(cmd, "2G", 2) == 0)
+ wpa_s->srp.relative_adjust_band = WPA_SETBAND_2G;
+ else if (os_strncmp(cmd, "5G", 2) == 0)
+ wpa_s->srp.relative_adjust_band = WPA_SETBAND_5G;
+ else
+ return -1;
+
+ wpa_s->srp.relative_adjust_rssi = adjust_rssi;
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct wpabuf *ric_ies;
+
+ if (*cmd == '\0' || os_strcmp(cmd, "\"\"") == 0) {
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = NULL;
+ return 0;
+ }
+
+ ric_ies = wpabuf_parse_bin(cmd);
+ if (!ric_ies)
+ return -1;
+
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = ric_ies;
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -337,16 +434,29 @@
-1, -1, -1, atoi(value));
} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
- atoi(value)))
+ atoi(value))) {
ret = -1;
+ } else {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
- atoi(value)))
+ atoi(value))) {
ret = -1;
+ } else {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
- if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
+ if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
+ atoi(value))) {
ret = -1;
+ } else {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
wpa_s->wps_fragment_size = atoi(value);
#ifdef CONFIG_WPS_TESTING
@@ -393,7 +503,6 @@
#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
- extern unsigned int tdls_testing;
tdls_testing = strtol(value, NULL, 0);
wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
#endif /* CONFIG_TDLS_TESTING */
@@ -484,6 +593,18 @@
wpa_s->test_failure = atoi(value);
} else if (os_strcasecmp(cmd, "p2p_go_csa_on_inv") == 0) {
wpa_s->p2p_go_csa_on_inv = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_auth_resp") == 0) {
+ wpa_s->ignore_auth_resp = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ignore_assoc_disallow") == 0) {
+ wpa_s->ignore_assoc_disallow = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "reject_btm_req_reason") == 0) {
+ wpa_s->reject_btm_req_reason = atoi(value);
+ } else if (os_strcasecmp(cmd, "get_pref_freq_list_override") == 0) {
+ os_free(wpa_s->get_pref_freq_list_override);
+ if (!value[0])
+ wpa_s->get_pref_freq_list_override = NULL;
+ else
+ wpa_s->get_pref_freq_list_override = os_strdup(value);
#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
@@ -494,9 +615,23 @@
#ifdef CONFIG_MBO
} else if (os_strcasecmp(cmd, "non_pref_chan") == 0) {
ret = wpas_mbo_update_non_pref_chan(wpa_s, value);
+ if (ret == 0) {
+ value[-1] = '=';
+ wpa_config_process_global(wpa_s->conf, cmd, -1);
+ }
} else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) {
wpas_mbo_update_cell_capa(wpa_s, atoi(value));
#endif /* CONFIG_MBO */
+ } else if (os_strcasecmp(cmd, "lci") == 0) {
+ ret = wpas_ctrl_iface_set_lci(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) {
+ ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value));
+ } else if (os_strcasecmp(cmd, "relative_rssi") == 0) {
+ ret = wpas_ctrl_set_relative_rssi(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "relative_band_adjust") == 0) {
+ ret = wpas_ctrl_set_relative_band_adjust(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "ric_ies") == 0) {
+ ret = wpas_ctrl_iface_set_ric_ies(wpa_s, value);
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -1857,6 +1992,10 @@
"mode=P2P GO - group "
"formation\n");
break;
+ case WPAS_MODE_MESH:
+ ret = os_snprintf(pos, end - pos,
+ "mode=mesh\n");
+ break;
default:
ret = 0;
break;
@@ -1875,6 +2014,7 @@
#endif /* CONFIG_AP */
pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
}
+#ifdef CONFIG_SME
#ifdef CONFIG_SAE
if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
#ifdef CONFIG_AP
@@ -1888,6 +2028,7 @@
pos += ret;
}
#endif /* CONFIG_SAE */
+#endif /* CONFIG_SME */
ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
wpa_supplicant_state_txt(wpa_s->wpa_state));
if (os_snprintf_error(end - pos, ret))
@@ -2009,6 +2150,12 @@
pos += res;
}
+#ifdef CONFIG_MACSEC
+ res = ieee802_1x_kay_get_status(wpa_s->kay, pos, end - pos);
+ if (res > 0)
+ pos += res;
+#endif /* CONFIG_MACSEC */
+
sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
if (sess_id) {
char *start = pos;
@@ -2398,6 +2545,39 @@
}
#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_FILS
+ if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sFILS-SHA256",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFILS-SHA384",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA256",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ ret = os_snprintf(pos, end - pos, "%sFT-FILS-SHA384",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_FILS */
+
if (data.key_mgmt & WPA_KEY_MGMT_OSEN) {
ret = os_snprintf(pos, end - pos, "%sOSEN",
pos == start ? "" : "+");
@@ -2569,6 +2749,14 @@
pos += ret;
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_FILS
+ if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
+ ret = os_snprintf(pos, end - pos, "[FILS]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ 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]");
@@ -2890,15 +3078,10 @@
wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL)
return -1;
- wpas_notify_network_added(wpa_s, ssid);
-
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
-
ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
if (os_snprintf_error(buflen, ret))
return -1;
@@ -2911,7 +3094,7 @@
{
int id;
struct wpa_ssid *ssid;
- int was_disabled;
+ int result;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
@@ -2947,54 +3130,17 @@
id = atoi(cmd);
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid)
- wpas_notify_network_removed(wpa_s, ssid);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
"id=%d", id);
return -1;
}
-
- if (wpa_s->last_ssid == ssid)
- wpa_s->last_ssid = NULL;
-
- if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- /*
- * Invalidate the EAP session cache if the current or
- * previously used network is removed.
- */
- eapol_sm_invalidate_cached_session(wpa_s->eapol);
- }
-
- if (ssid == wpa_s->current_ssid) {
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-
- if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
- wpa_s->own_disconnect_req = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- }
-
- was_disabled = ssid->disabled;
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
"network id=%d", id);
return -1;
}
-
- if (!was_disabled && wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
- "network from filters");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-
return 0;
}
@@ -4009,6 +4155,16 @@
}
#endif /* CONFIG_ACS */
+#ifdef CONFIG_FILS
+ if (os_strcmp(field, "fils") == 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) {
+ res = os_snprintf(buf, buflen, "FILS");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_FILS */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -4051,13 +4207,85 @@
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_FILS
+static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end)
+{
+ char *start = pos;
+ const u8 *ie, *ie_end;
+ u16 info, realms;
+ int ret;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+ if (!ie)
+ return 0;
+ ie_end = ie + 2 + ie[1];
+ ie += 2;
+ if (ie_end - ie < 2)
+ return -1;
+
+ info = WPA_GET_LE16(ie);
+ ie += 2;
+ ret = os_snprintf(pos, end - pos, "fils_info=%04x\n", info);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ if (info & BIT(7)) {
+ /* Cache Identifier Included */
+ if (ie_end - ie < 2)
+ return -1;
+ ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n",
+ ie[0], ie[1]);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += 2;
+ }
+
+ if (info & BIT(8)) {
+ /* HESSID Included */
+ if (ie_end - ie < ETH_ALEN)
+ return -1;
+ ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n",
+ MAC2STR(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += ETH_ALEN;
+ }
+
+ realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3;
+ if (realms) {
+ if (ie_end - ie < realms * 2)
+ return -1;
+ ret = os_snprintf(pos, end - pos, "fils_realms=");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, end - pos, ie, realms * 2);
+ if (ret <= 0)
+ return 0;
+ pos += ret;
+ ie += realms * 2;
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ return pos - start;
+}
+#endif /* CONFIG_FILS */
+
+
static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
unsigned long mask, char *buf, size_t buflen)
{
size_t i;
int ret;
char *pos, *end;
- const u8 *ie, *ie2, *osen_ie;
+ const u8 *ie, *ie2, *osen_ie, *mesh;
pos = buf;
end = buf + buflen;
@@ -4166,13 +4394,16 @@
return 0;
pos += ret;
+ mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
+
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
if (ie)
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
2 + ie[1]);
ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
if (ie2)
- pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
+ pos = wpa_supplicant_ie_txt(pos, end,
+ mesh ? "RSN" : "WPA2", ie2,
2 + ie2[1]);
osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
if (osen_ie)
@@ -4186,6 +4417,14 @@
return 0;
pos += ret;
}
+
+ if (mesh) {
+ ret = os_snprintf(pos, end - pos, "[MESH]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
if (bss_is_dmg(bss)) {
const char *s;
ret = os_snprintf(pos, end - pos, "[DMG]");
@@ -4239,6 +4478,14 @@
pos += ret;
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_FILS
+ if (wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION)) {
+ ret = os_snprintf(pos, end - pos, "[FILS]");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
ret = os_snprintf(pos, end - pos, "\n");
if (os_snprintf_error(end - pos, ret))
@@ -4269,9 +4516,10 @@
if (mask & WPA_BSS_MASK_P2P_SCAN) {
ie = (const u8 *) (bss + 1);
ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
+ if (ret >= end - pos)
return 0;
- pos += ret;
+ if (ret > 0)
+ pos += ret;
}
#endif /* CONFIG_P2P */
@@ -4322,6 +4570,8 @@
pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
pos = anqp_add_hex(pos, end, "anqp_domain_name",
anqp->domain_name);
+ pos = anqp_add_hex(pos, end, "anqp_fils_realm_info",
+ anqp->fils_realm_info);
#ifdef CONFIG_HS20
pos = anqp_add_hex(pos, end, "hs20_capability_list",
anqp->hs20_capability_list);
@@ -4352,9 +4602,10 @@
if (mask & WPA_BSS_MASK_MESH_SCAN) {
ie = (const u8 *) (bss + 1);
ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
- if (ret < 0 || ret >= end - pos)
+ if (ret >= end - pos)
return 0;
- pos += ret;
+ if (ret > 0)
+ pos += ret;
}
#endif /* CONFIG_MESH */
@@ -4382,6 +4633,44 @@
}
#endif /* CONFIG_FST */
+ if (mask & WPA_BSS_MASK_UPDATE_IDX) {
+ ret = os_snprintf(pos, end - pos, "update_idx=%u\n",
+ bss->last_update_idx);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ if ((mask & WPA_BSS_MASK_BEACON_IE) && bss->beacon_ie_len) {
+ ret = os_snprintf(pos, end - pos, "beacon_ie=");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ ie = (const u8 *) (bss + 1);
+ ie += bss->ie_len;
+ for (i = 0; i < bss->beacon_ie_len; i++) {
+ ret = os_snprintf(pos, end - pos, "%02x", *ie++);
+ 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))
+ return 0;
+ pos += ret;
+ }
+
+#ifdef CONFIG_FILS
+ if (mask & WPA_BSS_MASK_FILS_INDICATION) {
+ ret = print_fils_indication(bss, pos, end);
+ if (ret < 0)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_FILS */
+
if (mask & WPA_BSS_MASK_DELIM) {
ret = os_snprintf(pos, end - pos, "====\n");
if (os_snprintf_error(end - pos, ret))
@@ -4472,6 +4761,8 @@
bss = dl_list_entry(next, struct wpa_bss,
list_id);
}
+ } else if (os_strncmp(cmd, "CURRENT", 7) == 0) {
+ bss = wpa_s->current_bss;
#ifdef CONFIG_P2P
} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
if (hwaddr_aton(cmd + 13, bssid) == 0)
@@ -5069,6 +5360,8 @@
wps_method = WPS_PIN_DISPLAY;
} else if (os_strncmp(pos, "pbc", 3) == 0) {
wps_method = WPS_PBC;
+ } else if (os_strstr(pos, "p2ps") != NULL) {
+ wps_method = WPS_P2PS;
} else {
pin = pos;
pos = os_strchr(pin, ' ');
@@ -5077,8 +5370,6 @@
*pos++ = '\0';
if (os_strncmp(pos, "display", 7) == 0)
wps_method = WPS_PIN_DISPLAY;
- else if (os_strncmp(pos, "p2ps", 4) == 0)
- wps_method = WPS_P2PS;
}
if (!wps_pin_str_valid(pin)) {
os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
@@ -5805,10 +6096,47 @@
}
+static int p2p_ctrl_group_member(struct wpa_supplicant *wpa_s, const char *cmd,
+ char *buf, size_t buflen)
+{
+ u8 dev_addr[ETH_ALEN];
+ struct wpa_ssid *ssid;
+ int res;
+ const u8 *iaddr;
+
+ ssid = wpa_s->current_ssid;
+ if (!wpa_s->global->p2p || !ssid || ssid->mode != WPAS_MODE_P2P_GO ||
+ hwaddr_aton(cmd, dev_addr))
+ return -1;
+
+ iaddr = p2p_group_get_client_interface_addr(wpa_s->p2p_group, dev_addr);
+ if (!iaddr)
+ return -1;
+ res = os_snprintf(buf, buflen, MACSTR, MAC2STR(iaddr));
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+}
+
+
+static int wpas_find_p2p_dev_addr_bss(struct wpa_global *global,
+ const u8 *p2p_dev_addr)
+{
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (wpa_bss_get_p2p_dev_addr(wpa_s, p2p_dev_addr))
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
- u8 addr[ETH_ALEN], *addr_ptr;
+ u8 addr[ETH_ALEN], *addr_ptr, group_capab;
int next, res;
const struct p2p_peer_info *info;
char *pos, *end;
@@ -5837,6 +6165,16 @@
info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
if (info == NULL)
return -1;
+ group_capab = info->group_capab;
+
+ if (group_capab &&
+ !wpas_find_p2p_dev_addr_bss(wpa_s->global, info->p2p_device_addr)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Could not find any BSS with p2p_dev_addr "
+ MACSTR ", hence override group_capab from 0x%x to 0",
+ MAC2STR(info->p2p_device_addr), group_capab);
+ group_capab = 0;
+ }
pos = buf;
end = buf + buflen;
@@ -5862,7 +6200,7 @@
info->serial_number,
info->config_methods,
info->dev_capab,
- info->group_capab,
+ group_capab,
info->level);
if (os_snprintf_error(end - pos, res))
return pos - buf;
@@ -6143,6 +6481,20 @@
return 0;
}
+ if (os_strcmp(cmd, "override_pref_op_chan") == 0) {
+ int op_class, chan;
+
+ op_class = atoi(param);
+ param = os_strchr(param, ':');
+ if (!param)
+ return -1;
+ param++;
+ chan = atoi(param);
+ p2p_set_override_pref_op_chan(wpa_s->global->p2p, op_class,
+ chan);
+ return 0;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
@@ -6229,6 +6581,21 @@
return 0;
}
+
+static int p2p_ctrl_iface_p2p_lo_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int freq = 0, period = 0, interval = 0, count = 0;
+
+ if (sscanf(cmd, "%d %d %d %d", &freq, &period, &interval, &count) != 4)
+ {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid P2P LO Start parameter: '%s'", cmd);
+ return -1;
+ }
+
+ return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
+}
+
#endif /* CONFIG_P2P */
@@ -6346,6 +6713,7 @@
u16 id[MAX_ANQP_INFO_ID];
size_t num_id = 0;
u32 subtypes = 0;
+ int get_cell_pref = 0;
used = hwaddr_aton2(dst, dst_addr);
if (used < 0)
@@ -6363,6 +6731,15 @@
#else /* CONFIG_HS20 */
return -1;
#endif /* CONFIG_HS20 */
+ } else if (os_strncmp(pos, "mbo:", 4) == 0) {
+#ifdef CONFIG_MBO
+ int num = atoi(pos + 4);
+ if (num != MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
+ return -1;
+ get_cell_pref = 1;
+#else /* CONFIG_MBO */
+ return -1;
+#endif /* CONFIG_MBO */
} else {
id[num_id] = atoi(pos);
if (id[num_id])
@@ -6377,7 +6754,8 @@
if (num_id == 0)
return -1;
- return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes);
+ return anqp_send_req(wpa_s, dst_addr, id, num_id, subtypes,
+ get_cell_pref);
}
@@ -6714,6 +7092,9 @@
autoscan_init(wpa_s, 1);
else if (state == WPA_SCANNING)
wpa_supplicant_reinit_autoscan(wpa_s);
+ else
+ wpa_printf(MSG_DEBUG, "No autoscan update in state %s",
+ wpa_supplicant_state_txt(state));
return 0;
}
@@ -6882,6 +7263,46 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type if_type,
+ unsigned int *num,
+ unsigned int *freq_list)
+{
+ char *pos = wpa_s->get_pref_freq_list_override;
+ char *end;
+ unsigned int count = 0;
+
+ /* Override string format:
+ * <if_type1>:<freq1>,<freq2>,... <if_type2>:... */
+
+ while (pos) {
+ if (atoi(pos) == (int) if_type)
+ break;
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+ if (!pos)
+ return -1;
+ pos = os_strchr(pos, ':');
+ if (!pos)
+ return -1;
+ pos++;
+ end = os_strchr(pos, ' ');
+ while (pos && (!end || pos < end) && count < *num) {
+ freq_list[count++] = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos)
+ pos++;
+ }
+
+ *num = count;
+ return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static int wpas_ctrl_iface_get_pref_freq_list(
struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
{
@@ -6929,6 +7350,34 @@
}
+static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ int ret, i;
+ char *pos, *end;
+
+ ret = os_snprintf(buf, buflen, "%016llX:\n",
+ (long long unsigned) wpa_s->drv_flags);
+ if (os_snprintf_error(buflen, ret))
+ return -1;
+
+ pos = buf + ret;
+ end = buf + buflen;
+
+ for (i = 0; i < 64; i++) {
+ if (wpa_s->drv_flags & (1LLU << i)) {
+ ret = os_snprintf(pos, end - pos, "%s\n",
+ driver_flag_to_string(1LLU << i));
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -7040,7 +7489,8 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
- wpas_abort_ongoing_scan(wpa_s);
+ if (wpas_abort_ongoing_scan(wpa_s) == 0)
+ wpa_s->ignore_post_flush_scan_res = 1;
if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
/*
@@ -7083,7 +7533,6 @@
#ifdef CONFIG_TDLS
#ifdef CONFIG_TDLS_TESTING
- extern unsigned int tdls_testing;
tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
@@ -7141,7 +7590,12 @@
wpa_s->extra_roc_dur = 0;
wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
wpa_s->p2p_go_csa_on_inv = 0;
+ wpa_s->ignore_auth_resp = 0;
+ wpa_s->ignore_assoc_disallow = 0;
+ wpa_s->reject_btm_req_reason = 0;
wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
+ os_free(wpa_s->get_pref_freq_list_override);
+ wpa_s->get_pref_freq_list_override = NULL;
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->disconnected = 0;
@@ -7160,6 +7614,13 @@
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
wpa_s->wnmsleep_used = 0;
+
+#ifdef CONFIG_SME
+ wpa_s->sme.last_unprot_disconnect.sec = 0;
+#endif /* CONFIG_SME */
+
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = NULL;
}
@@ -7216,6 +7677,13 @@
eloop_cancel_timeout(wpas_ctrl_radio_work_timeout,
work, NULL);
+ /*
+ * work->type points to a buffer in ework, so need to replace
+ * that here with a fixed string to avoid use of freed memory
+ * in debug prints.
+ */
+ work->type = "freed-ext-work";
+ work->ctx = NULL;
os_free(ework);
return;
}
@@ -7665,6 +8133,194 @@
}
+static int wpas_ctrl_iface_mgmt_rx_process(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *pos, *param;
+ size_t len;
+ u8 *buf;
+ int freq = 0, datarate = 0, ssi_signal = 0;
+ union wpa_event_data event;
+
+ if (!wpa_s->ext_mgmt_frame_handling)
+ return -1;
+
+ /* freq=<MHz> datarate=<val> ssi_signal=<val> frame=<frame hexdump> */
+
+ wpa_printf(MSG_DEBUG, "External MGMT RX process: %s", cmd);
+
+ pos = cmd;
+ param = os_strstr(pos, "freq=");
+ if (param) {
+ param += 5;
+ freq = atoi(param);
+ }
+
+ param = os_strstr(pos, " datarate=");
+ if (param) {
+ param += 10;
+ datarate = atoi(param);
+ }
+
+ param = os_strstr(pos, " ssi_signal=");
+ if (param) {
+ param += 12;
+ ssi_signal = atoi(param);
+ }
+
+ param = os_strstr(pos, " frame=");
+ if (param == NULL)
+ return -1;
+ param += 7;
+
+ len = os_strlen(param);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(param, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.freq = freq;
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.datarate = datarate;
+ wpa_s->ext_mgmt_frame_handling = 0;
+ wpa_supplicant_event(wpa_s, EVENT_RX_MGMT, &event);
+ wpa_s->ext_mgmt_frame_handling = 1;
+
+ os_free(buf);
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_driver_scan_res(struct wpa_supplicant *wpa_s,
+ char *param)
+{
+ struct wpa_scan_res *res;
+ struct os_reltime now;
+ char *pos, *end;
+ int ret = -1;
+
+ if (!param)
+ return -1;
+
+ if (os_strcmp(param, "START") == 0) {
+ wpa_bss_update_start(wpa_s);
+ return 0;
+ }
+
+ if (os_strcmp(param, "END") == 0) {
+ wpa_bss_update_end(wpa_s, NULL, 1);
+ return 0;
+ }
+
+ if (os_strncmp(param, "BSS ", 4) != 0)
+ return -1;
+ param += 3;
+
+ res = os_zalloc(sizeof(*res) + os_strlen(param) / 2);
+ if (!res)
+ return -1;
+
+ pos = os_strstr(param, " flags=");
+ if (pos)
+ res->flags = strtol(pos + 7, NULL, 16);
+
+ pos = os_strstr(param, " bssid=");
+ if (pos && hwaddr_aton(pos + 7, res->bssid))
+ goto fail;
+
+ pos = os_strstr(param, " freq=");
+ if (pos)
+ res->freq = atoi(pos + 6);
+
+ pos = os_strstr(param, " beacon_int=");
+ if (pos)
+ res->beacon_int = atoi(pos + 12);
+
+ pos = os_strstr(param, " caps=");
+ if (pos)
+ res->caps = strtol(pos + 6, NULL, 16);
+
+ pos = os_strstr(param, " qual=");
+ if (pos)
+ res->qual = atoi(pos + 6);
+
+ pos = os_strstr(param, " noise=");
+ if (pos)
+ res->noise = atoi(pos + 7);
+
+ pos = os_strstr(param, " level=");
+ if (pos)
+ res->level = atoi(pos + 7);
+
+ pos = os_strstr(param, " tsf=");
+ if (pos)
+ res->tsf = strtoll(pos + 5, NULL, 16);
+
+ pos = os_strstr(param, " age=");
+ if (pos)
+ res->age = atoi(pos + 5);
+
+ pos = os_strstr(param, " est_throughput=");
+ if (pos)
+ res->est_throughput = atoi(pos + 16);
+
+ pos = os_strstr(param, " snr=");
+ if (pos)
+ res->snr = atoi(pos + 5);
+
+ pos = os_strstr(param, " parent_tsf=");
+ if (pos)
+ res->parent_tsf = strtoll(pos + 7, NULL, 16);
+
+ pos = os_strstr(param, " tsf_bssid=");
+ if (pos && hwaddr_aton(pos + 11, res->tsf_bssid))
+ goto fail;
+
+ pos = os_strstr(param, " ie=");
+ if (pos) {
+ pos += 4;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+ res->ie_len = (end - pos) / 2;
+ if (hexstr2bin(pos, (u8 *) (res + 1), res->ie_len))
+ goto fail;
+ }
+
+ pos = os_strstr(param, " beacon_ie=");
+ if (pos) {
+ pos += 11;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+ res->beacon_ie_len = (end - pos) / 2;
+ if (hexstr2bin(pos, ((u8 *) (res + 1)) + res->ie_len,
+ res->beacon_ie_len))
+ goto fail;
+ }
+
+ os_get_reltime(&now);
+ wpa_bss_update_scan_res(wpa_s, res, &now);
+ ret = 0;
+fail:
+ os_free(res);
+
+ return ret;
+}
+
+
static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *param;
@@ -7695,6 +8351,8 @@
wpa_supplicant_event(wpa_s, ev, &event);
os_free(event.freq_range.range);
return 0;
+ } else if (os_strcmp(cmd, "SCAN_RES") == 0) {
+ return wpas_ctrl_iface_driver_scan_res(wpa_s, param);
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "Testing - unknown driver event: %s",
cmd);
@@ -7764,7 +8422,8 @@
#define HWSIM_PACKETLEN 1500
#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
-void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
const struct ether_header *eth;
@@ -7940,8 +8599,6 @@
static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
char *pos;
wpa_trace_fail_after = atoi(cmd);
@@ -7964,9 +8621,6 @@
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_fail_func[256];
- extern unsigned int wpa_trace_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
wpa_trace_fail_func);
#else /* WPA_TRACE_BFD */
@@ -7978,8 +8632,6 @@
static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
char *pos;
wpa_trace_test_fail_after = atoi(cmd);
@@ -8002,9 +8654,6 @@
char *buf, size_t buflen)
{
#ifdef WPA_TRACE_BFD
- extern char wpa_trace_test_fail_func[256];
- extern unsigned int wpa_trace_test_fail_after;
-
return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
wpa_trace_test_fail_func);
#else /* WPA_TRACE_BFD */
@@ -8207,34 +8856,140 @@
static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
{
struct wpa_supplicant *wpa_s = ctx;
+ size_t len;
+ const u8 *data;
- if (neighbor_rep) {
- wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
- "length=%u",
- (unsigned int) wpabuf_len(neighbor_rep));
- wpabuf_free(neighbor_rep);
- } else {
+ /*
+ * Neighbor Report element (IEEE P802.11-REVmc/D5.0)
+ * BSSID[6]
+ * BSSID Information[4]
+ * Operating Class[1]
+ * Channel Number[1]
+ * PHY Type[1]
+ * Optional Subelements[variable]
+ */
+#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
+
+ if (!neighbor_rep || wpabuf_len(neighbor_rep) == 0) {
wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+ goto out;
}
+
+ data = wpabuf_head_u8(neighbor_rep);
+ len = wpabuf_len(neighbor_rep);
+
+ while (len >= 2 + NR_IE_MIN_LEN) {
+ const u8 *nr;
+ char lci[256 * 2 + 1];
+ char civic[256 * 2 + 1];
+ u8 nr_len = data[1];
+ const u8 *pos = data, *end;
+
+ if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
+ nr_len < NR_IE_MIN_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%u",
+ data[0], nr_len);
+ goto out;
+ }
+
+ if (2U + nr_len > len) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
+ data[0], len, nr_len);
+ goto out;
+ }
+ pos += 2;
+ end = pos + nr_len;
+
+ nr = pos;
+ pos += NR_IE_MIN_LEN;
+
+ lci[0] = '\0';
+ civic[0] = '\0';
+ while (end - pos > 2) {
+ u8 s_id, s_len;
+
+ s_id = *pos++;
+ s_len = *pos++;
+ if (s_len > end - pos)
+ goto out;
+ if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
+ /* Measurement Token[1] */
+ /* Measurement Report Mode[1] */
+ /* Measurement Type[1] */
+ /* Measurement Report[variable] */
+ switch (pos[2]) {
+ case MEASURE_TYPE_LCI:
+ if (lci[0])
+ break;
+ wpa_snprintf_hex(lci, sizeof(lci),
+ pos, s_len);
+ break;
+ case MEASURE_TYPE_LOCATION_CIVIC:
+ if (civic[0])
+ break;
+ wpa_snprintf_hex(civic, sizeof(civic),
+ pos, s_len);
+ break;
+ }
+ }
+
+ pos += s_len;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+ "bssid=" MACSTR
+ " info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
+ MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
+ nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
+ nr[ETH_ALEN + 6],
+ lci[0] ? " lci=" : "", lci,
+ civic[0] ? " civic=" : "", civic);
+
+ data = end;
+ len -= 2 + nr_len;
+ }
+
+out:
+ wpabuf_free(neighbor_rep);
}
-static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
- char *cmd)
+static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s,
+ char *cmd)
{
- struct wpa_ssid ssid;
- struct wpa_ssid *ssid_p = NULL;
- int ret = 0;
+ struct wpa_ssid_value ssid, *ssid_p = NULL;
+ int ret, lci = 0, civic = 0;
+ char *ssid_s;
- if (os_strncmp(cmd, " ssid=", 6) == 0) {
- ssid.ssid_len = os_strlen(cmd + 6);
- if (ssid.ssid_len > SSID_MAX_LEN)
+ ssid_s = os_strstr(cmd, "ssid=");
+ if (ssid_s) {
+ if (ssid_parse(ssid_s + 5, &ssid)) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: Send Neighbor Report: bad SSID");
return -1;
- ssid.ssid = (u8 *) (cmd + 6);
+ }
+
ssid_p = &ssid;
+
+ /*
+ * Move cmd after the SSID text that may include "lci" or
+ * "civic".
+ */
+ cmd = os_strchr(ssid_s + 6, ssid_s[5] == '"' ? '"' : ' ');
+ if (cmd)
+ cmd++;
+
}
- ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+ if (cmd && os_strstr(cmd, "lci"))
+ lci = 1;
+
+ if (cmd && os_strstr(cmd, "civic"))
+ civic = 1;
+
+ ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p, lci, civic,
wpas_ctrl_neighbor_rep_cb,
wpa_s);
@@ -8319,10 +9074,7 @@
}
} else if (wpa_s->sched_scanning &&
(type & MAC_ADDR_RAND_SCHED_SCAN)) {
- /* simulate timeout to restart the sched scan */
- wpa_s->sched_scan_timed_out = 1;
- wpa_s->prev_sched_ssid = NULL;
- wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpas_scan_restart_sched_scan(wpa_s);
}
return 0;
}
@@ -8348,12 +9100,8 @@
wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
addr, mask);
- if (wpa_s->sched_scanning && !wpa_s->pno) {
- /* simulate timeout to restart the sched scan */
- wpa_s->sched_scan_timed_out = 1;
- wpa_s->prev_sched_ssid = NULL;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- }
+ if (wpa_s->sched_scanning && !wpa_s->pno)
+ wpas_scan_restart_sched_scan(wpa_s);
}
if (type & MAC_ADDR_RAND_PNO) {
@@ -8392,6 +9140,222 @@
}
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+
+static int wpas_ctrl_iface_pmksa_get(struct wpa_supplicant *wpa_s,
+ const char *cmd, char *buf, size_t buflen)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ struct wpa_ssid *ssid;
+ char *pos, *pos2, *end;
+ int ret;
+ struct os_reltime now;
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid)
+ return -1;
+
+ pos = buf;
+ end = buf + buflen;
+
+ os_get_reltime(&now);
+
+ /*
+ * Entry format:
+ * <BSSID> <PMKID> <PMK> <reauth_time in seconds>
+ * <expiration in seconds> <akmp> <opportunistic>
+ */
+
+ for (entry = wpa_sm_pmksa_cache_head(wpa_s->wpa); entry;
+ entry = entry->next) {
+ if (entry->network_ctx != ssid)
+ continue;
+
+ pos2 = pos;
+ ret = os_snprintf(pos2, end - pos2, MACSTR " ",
+ MAC2STR(entry->aa));
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmkid,
+ PMKID_LEN);
+
+ ret = os_snprintf(pos2, end - pos2, " ");
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ pos2 += wpa_snprintf_hex(pos2, end - pos2, entry->pmk,
+ entry->pmk_len);
+
+ ret = os_snprintf(pos2, end - pos2, " %d %d %d %d",
+ (int) (entry->reauth_time - now.sec),
+ (int) (entry->expiration - now.sec),
+ entry->akmp,
+ entry->opportunistic);
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ ret = os_snprintf(pos2, end - pos2, "\n");
+ if (os_snprintf_error(end - pos2, ret))
+ break;
+ pos2 += ret;
+
+ pos = pos2;
+ }
+
+ return pos - buf;
+}
+
+
+static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ struct wpa_ssid *ssid;
+ char *pos, *pos2;
+ int ret = -1;
+ struct os_reltime now;
+ int reauth_time = 0, expiration = 0;
+
+ /*
+ * Entry format:
+ * <network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds>
+ * <expiration in seconds> <akmp> <opportunistic>
+ */
+
+ ssid = wpa_config_get_network(wpa_s->conf, atoi(cmd));
+ if (!ssid)
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return -1;
+ pos++;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ return -1;
+
+ if (hwaddr_aton(pos, entry->aa))
+ goto fail;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ if (hexstr2bin(pos, entry->pmkid, PMKID_LEN) < 0)
+ goto fail;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ pos2 = os_strchr(pos, ' ');
+ if (!pos2)
+ goto fail;
+ entry->pmk_len = (pos2 - pos) / 2;
+ if (entry->pmk_len < PMK_LEN || entry->pmk_len > PMK_LEN_MAX ||
+ hexstr2bin(pos, entry->pmk, entry->pmk_len) < 0)
+ goto fail;
+
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+
+ if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration,
+ &entry->akmp, &entry->opportunistic) != 4)
+ goto fail;
+ os_get_reltime(&now);
+ entry->expiration = now.sec + expiration;
+ entry->reauth_time = now.sec + reauth_time;
+
+ entry->network_ctx = ssid;
+
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+ entry = NULL;
+ ret = 0;
+fail:
+ os_free(entry);
+ return ret;
+}
+
+
+#ifdef CONFIG_MESH
+
+static int wpas_ctrl_iface_mesh_pmksa_get(struct wpa_supplicant *wpa_s,
+ const char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 spa[ETH_ALEN];
+
+ if (!wpa_s->ifmsh)
+ return -1;
+
+ if (os_strcasecmp(cmd, "any") == 0)
+ return wpas_ap_pmksa_cache_list_mesh(wpa_s, NULL, buf, buflen);
+
+ if (hwaddr_aton(cmd, spa))
+ return -1;
+
+ return wpas_ap_pmksa_cache_list_mesh(wpa_s, spa, buf, buflen);
+}
+
+
+static int wpas_ctrl_iface_mesh_pmksa_add(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ /*
+ * We do not check mesh interface existance because PMKSA should be
+ * stored before wpa_s->ifmsh creation to suppress commit message
+ * creation.
+ */
+ return wpas_ap_pmksa_cache_add_external(wpa_s, cmd);
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
+#ifdef CONFIG_FILS
+static int wpas_ctrl_iface_fils_hlp_req_add(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct fils_hlp_req *req;
+ const char *pos;
+
+ /* format: <dst> <packet starting from ethertype> */
+
+ req = os_zalloc(sizeof(*req));
+ if (!req)
+ return -1;
+
+ if (hwaddr_aton(cmd, req->dst))
+ goto fail;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ goto fail;
+ pos++;
+ req->pkt = wpabuf_parse_bin(pos);
+ if (!req->pkt)
+ goto fail;
+
+ dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
+ return 0;
+fail:
+ wpabuf_free(req->pkt);
+ os_free(req);
+ return -1;
+}
+#endif /* CONFIG_FILS */
+
+
static int wpas_ctrl_cmd_debug_level(const char *cmd)
{
if (os_strcmp(cmd, "PING") == 0 ||
@@ -8466,6 +9430,22 @@
reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
wpas_ctrl_iface_pmksa_flush(wpa_s);
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ } else if (os_strncmp(buf, "PMKSA_GET ", 10) == 0) {
+ reply_len = wpas_ctrl_iface_pmksa_get(wpa_s, buf + 10,
+ reply, reply_size);
+ } else if (os_strncmp(buf, "PMKSA_ADD ", 10) == 0) {
+ if (wpas_ctrl_iface_pmksa_add(wpa_s, buf + 10) < 0)
+ reply_len = -1;
+#ifdef CONFIG_MESH
+ } else if (os_strncmp(buf, "MESH_PMKSA_GET ", 15) == 0) {
+ reply_len = wpas_ctrl_iface_mesh_pmksa_get(wpa_s, buf + 15,
+ reply, reply_size);
+ } else if (os_strncmp(buf, "MESH_PMKSA_ADD ", 15) == 0) {
+ if (wpas_ctrl_iface_mesh_pmksa_add(wpa_s, buf + 15) < 0)
+ reply_len = -1;
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
} else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
@@ -8673,6 +9653,9 @@
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_GROUP_MEMBER ", 17) == 0) {
+ reply_len = p2p_ctrl_group_member(wpa_s, buf + 17, reply,
+ reply_size);
} else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
reply_len = -1;
@@ -8738,6 +9721,12 @@
} else if (os_strncmp(buf, "P2P_REMOVE_CLIENT ", 18) == 0) {
if (p2p_ctrl_remove_client(wpa_s, buf + 18) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_LO_START ", 13) == 0) {
+ if (p2p_ctrl_iface_p2p_lo_start(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
+ if (wpas_p2p_lo_stop(wpa_s))
+ reply_len = -1;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -8802,7 +9791,10 @@
if (del_hs20_icon(wpa_s, buf + 14) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "FETCH_OSU") == 0) {
- if (hs20_fetch_osu(wpa_s) < 0)
+ if (hs20_fetch_osu(wpa_s, 0) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FETCH_OSU no-scan") == 0) {
+ if (hs20_fetch_osu(wpa_s, 1) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "CANCEL_FETCH_OSU") == 0) {
hs20_cancel_fetch_osu(wpa_s);
@@ -8841,16 +9833,7 @@
reply_len = wpa_supplicant_ctrl_iface_list_networks(
wpa_s, NULL, reply, reply_size);
} else if (os_strcmp(buf, "DISCONNECT") == 0) {
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
- wpa_s->reassociate = 0;
- wpa_s->disconnected = 1;
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_cancel_scan(wpa_s);
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+ wpas_request_disconnection(wpa_s);
} else if (os_strcmp(buf, "SCAN") == 0) {
wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len);
} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
@@ -9013,6 +9996,9 @@
if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_AUTOSCAN */
+ } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) {
+ reply_len = wpas_ctrl_iface_driver_flags(wpa_s, reply,
+ reply_size);
#ifdef ANDROID
} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
@@ -9043,6 +10029,9 @@
reply_len = -1;
} else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) {
wpas_ctrl_iface_mgmt_tx_done(wpa_s);
+ } else if (os_strncmp(buf, "MGMT_RX_PROCESS ", 16) == 0) {
+ if (wpas_ctrl_iface_mgmt_rx_process(wpa_s, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
reply_len = -1;
@@ -9085,7 +10074,7 @@
if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
reply_len = -1;
} else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
- if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
+ if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20))
reply_len = -1;
} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
wpas_ctrl_iface_erp_flush(wpa_s);
@@ -9095,6 +10084,13 @@
} else if (os_strncmp(buf, "GET_PREF_FREQ_LIST ", 19) == 0) {
reply_len = wpas_ctrl_iface_get_pref_freq_list(
wpa_s, buf + 19, reply, reply_size);
+#ifdef CONFIG_FILS
+ } else if (os_strncmp(buf, "FILS_HLP_REQ_ADD ", 17) == 0) {
+ if (wpas_ctrl_iface_fils_hlp_req_add(wpa_s, buf + 17))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "FILS_HLP_REQ_FLUSH") == 0) {
+ wpas_flush_fils_hlp_req(wpa_s);
+#endif /* CONFIG_FILS */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -9404,6 +10400,9 @@
"P2P_CANCEL",
"P2P_PRESENCE_REQ",
"P2P_EXT_LISTEN",
+#ifdef CONFIG_AP
+ "STA-FIRST",
+#endif /* CONFIG_AP */
NULL
};
static const char * prefix[] = {
@@ -9417,6 +10416,7 @@
"P2P_LISTEN ",
"P2P_GROUP_REMOVE ",
"P2P_GROUP_ADD ",
+ "P2P_GROUP_MEMBER ",
"P2P_PROV_DISC ",
"P2P_SERV_DISC_REQ ",
"P2P_SERV_DISC_CANCEL_REQ ",
@@ -9440,6 +10440,10 @@
"NFC_REPORT_HANDOVER ",
"P2P_ASP_PROVISION ",
"P2P_ASP_PROVISION_RESP ",
+#ifdef CONFIG_AP
+ "STA ",
+ "STA-NEXT ",
+#endif /* CONFIG_AP */
NULL
};
int found = 0;
@@ -9788,7 +10792,6 @@
reply_size);
#ifdef CONFIG_MODULE_TESTS
} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
- int wpas_module_tests(void);
if (wpas_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index d894f6a..0c355f7 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1254,14 +1254,14 @@
* irrespective of the role (client/GO) of the current device
*
* @wpa_s: %wpa_supplicant network interface data
- * @ssid: SSID object
* @client: this device is P2P client
- * @network_id: network id of the group started, use instead of ssid->id
- * to account for persistent groups
+ * @persistent: 0 - non persistent group, 1 - persistent group
+ * @ip: When group role is client, it contains local IP address, netmask, and
+ * GO's IP address, if assigned; otherwise, NULL
*/
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id)
+ int client, int persistent,
+ const u8 *ip)
{
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
@@ -1300,8 +1300,16 @@
wpa_s->dbus_new_path) ||
!wpa_dbus_dict_append_string(&dict_iter, "role",
client ? "client" : "GO") ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) ||
!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
wpa_s->dbus_groupobj_path) ||
+ (ip &&
+ (!wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddr",
+ (char *) ip, 4) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+ (char *) ip + 4, 4) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+ (char *) ip + 8, 4))) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
} else {
@@ -1979,6 +1987,11 @@
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;
@@ -3130,6 +3143,13 @@
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,
@@ -3160,6 +3180,11 @@
NULL,
NULL
},
+ { "ConfigFile", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
+ wpas_dbus_getter_config_file,
+ NULL,
+ NULL
+ },
{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
wpas_dbus_getter_current_bss,
NULL,
@@ -3221,6 +3246,42 @@
wpas_dbus_setter_config_methods,
NULL
},
+ {
+ "DeviceName", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_name,
+ wpas_dbus_setter_wps_device_name,
+ NULL
+ },
+ {
+ "Manufacturer", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_manufacturer,
+ wpas_dbus_setter_wps_manufacturer,
+ NULL
+ },
+ {
+ "ModelName", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_model_name,
+ wpas_dbus_setter_wps_device_model_name,
+ NULL
+ },
+ {
+ "ModelNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_model_number,
+ wpas_dbus_setter_wps_device_model_number,
+ NULL
+ },
+ {
+ "SerialNumber", WPAS_DBUS_NEW_IFACE_WPS, "s",
+ wpas_dbus_getter_wps_device_serial_number,
+ wpas_dbus_setter_wps_device_serial_number,
+ NULL
+ },
+ {
+ "DeviceType", WPAS_DBUS_NEW_IFACE_WPS, "ay",
+ wpas_dbus_getter_wps_device_device_type,
+ wpas_dbus_setter_wps_device_device_type,
+ NULL
+ },
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ "P2PDeviceConfig", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
@@ -3354,6 +3415,13 @@
END_ARGS
}
},
+ { "DeviceFoundProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "properties", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
{ "DeviceLost", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
{ "path", "o", ARG_OUT },
@@ -3802,12 +3870,13 @@
* In case of peer objects, it would be emitted by either
* the "interface object" or by "peer objects"
* @sig_name: signal name - DeviceFound
+ * @properties: Whether to add a second argument with object properties
*
- * Notify listeners about event related with newly found p2p peer device
+ * Notify listeners about event related with p2p peer device
*/
static void wpas_dbus_signal_peer(struct wpa_supplicant *wpa_s,
const u8 *dev_addr, const char *interface,
- const char *sig_name)
+ const char *sig_name, int properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
@@ -3835,7 +3904,10 @@
dbus_message_iter_init_append(msg, &iter);
path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
+ &path) ||
+ (properties && !wpa_dbus_get_object_properties(
+ iface, peer_obj_path, WPAS_DBUS_NEW_IFACE_P2P_PEER,
+ &iter)))
wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
else
dbus_connection_send(iface->con, msg, NULL);
@@ -3856,7 +3928,11 @@
{
wpas_dbus_signal_peer(wpa_s, dev_addr,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "DeviceFound");
+ "DeviceFound", FALSE);
+
+ wpas_dbus_signal_peer(wpa_s, dev_addr,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "DeviceFoundProperties", TRUE);
}
/**
@@ -3871,7 +3947,7 @@
{
wpas_dbus_signal_peer(wpa_s, dev_addr,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "DeviceLost");
+ "DeviceLost", FALSE);
}
/**
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 3ac66db..bd0e074 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -22,6 +22,7 @@
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,
@@ -190,8 +191,8 @@
const u8 *src, u16 dev_passwd_id,
u8 go_intent);
void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id);
+ int client, int persistent,
+ const u8 *ip);
void wpas_dbus_signal_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
@@ -401,8 +402,8 @@
static inline void
wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- int client, int network_id)
+ int client, int persistent,
+ const u8 *ip)
{
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index da90ea1..e6f356b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -517,6 +517,27 @@
/**
+ * wpas_dbus_string_property_getter - Get string type property
+ * @iter: Message iter to use when appending arguments
+ * @val: Pointer to place holding property value, can be %NULL
+ * @error: On failure an error describing the failure
+ * Returns: TRUE if the request was successful, FALSE if it failed
+ *
+ * Generic getter for string type properties. %NULL is converted to an empty
+ * string.
+ */
+dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
+ const void *val,
+ DBusError *error)
+{
+ if (!val)
+ val = "";
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+ &val, error);
+}
+
+
+/**
* wpas_dbus_handler_create_interface - Request registration of a network iface
* @message: Pointer to incoming dbus message
* @global: %wpa_supplicant global data structure
@@ -970,6 +991,9 @@
#ifdef CONFIG_INTERWORKING
capabilities[num_items++] = "interworking";
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_IEEE80211W
+ capabilities[num_items++] = "pmf";
+#endif /* CONFIG_IEEE80211W */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -1475,10 +1499,7 @@
struct wpa_supplicant *wpa_s)
{
if (wpa_s->current_ssid != NULL) {
- wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
+ wpas_request_disconnection(wpa_s);
return NULL;
}
@@ -1507,7 +1528,7 @@
dbus_message_iter_init(message, &iter);
if (wpa_s->dbus_new_path)
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL) {
wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
__func__);
@@ -1516,9 +1537,6 @@
"wpa_supplicant could not add a network on this interface.");
goto err;
}
- wpas_notify_network_added(wpa_s, ssid);
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
@@ -1665,8 +1683,7 @@
const char *op;
char *iface, *net_id;
int id;
- struct wpa_ssid *ssid;
- int was_disabled;
+ int result;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
@@ -1689,27 +1706,12 @@
goto out;
}
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
reply = wpas_dbus_error_network_unknown(message);
goto out;
}
-
- was_disabled = ssid->disabled;
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
- else if (!was_disabled && wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG,
- "Stop ongoing sched_scan to remove network from filters");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
wpa_printf(MSG_ERROR,
"%s[dbus]: error occurred when removing network %d",
__func__, id);
@@ -2490,6 +2492,28 @@
goto nomem;
}
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "GroupMgmt",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "aes-128-cmac")) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_128) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "bip-gmac-128")) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_GMAC_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "bip-gmac-256")) ||
+ (res == 0 && (capa.enc & WPA_DRIVER_CAPA_ENC_BIP_CMAC_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "bip-cmac-256")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto nomem;
+
/***** key management */
if (res < 0) {
const char *args[] = {
@@ -2639,8 +2663,9 @@
&iter_array) ||
!wpa_dbus_dict_string_array_add_element(
&iter_array, "infrastructure") ||
- !wpa_dbus_dict_string_array_add_element(
- &iter_array, "ad-hoc") ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_IBSS) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ad-hoc")) ||
(res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
!wpa_dbus_dict_string_array_add_element(
&iter_array, "ap")) ||
@@ -2787,6 +2812,61 @@
}
+#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)
@@ -3107,10 +3187,8 @@
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *ifname = wpa_s->ifname;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &ifname, error);
+ return wpas_dbus_string_property_getter(iter, wpa_s->ifname, error);
}
@@ -3128,7 +3206,6 @@
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *driver;
if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
@@ -3138,9 +3215,8 @@
return FALSE;
}
- driver = wpa_s->driver->name;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &driver, error);
+ return wpas_dbus_string_property_getter(iter, wpa_s->driver->name,
+ error);
}
@@ -3227,9 +3303,11 @@
"EAP-%s", eap_mode);
auth_mode = eap_mode_buf;
- } else {
+ } else if (wpa_s->current_ssid) {
auth_mode = wpa_key_mgmt_txt(wpa_s->key_mgmt,
wpa_s->current_ssid->proto);
+ } else {
+ auth_mode = "UNKNOWN";
}
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -3251,10 +3329,28 @@
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *bridge_ifname = wpa_s->bridge_ifname;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &bridge_ifname, error);
+ return wpas_dbus_string_property_getter(iter, wpa_s->bridge_ifname,
+ error);
+}
+
+
+/**
+ * wpas_dbus_getter_config_file - Get interface configuration file path
+ * @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 "ConfigFile" property.
+ */
+dbus_bool_t wpas_dbus_getter_config_file(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->confname, error);
}
@@ -3394,14 +3490,10 @@
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *pkcs11_engine_path;
- if (wpa_s->conf->pkcs11_engine_path == NULL)
- pkcs11_engine_path = "";
- else
- pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &pkcs11_engine_path, error);
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->pkcs11_engine_path,
+ error);
}
@@ -3419,14 +3511,10 @@
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- const char *pkcs11_module_path;
- if (wpa_s->conf->pkcs11_module_path == NULL)
- pkcs11_module_path = "";
- else
- pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &pkcs11_module_path, error);
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->pkcs11_module_path,
+ error);
}
@@ -3678,6 +3766,7 @@
struct bss_handler_args *args = user_data;
struct wpa_bss *res;
const char *mode;
+ const u8 *mesh;
res = get_bss_helper(args, error, __func__);
if (!res)
@@ -3691,9 +3780,15 @@
case IEEE80211_CAP_DMG_AP:
mode = "infrastructure";
break;
+ default:
+ mode = "";
+ break;
}
} else {
- if (res->caps & IEEE80211_CAP_IBSS)
+ mesh = wpa_bss_get_ie(res, WLAN_EID_MESH_ID);
+ if (mesh)
+ mode = "mesh";
+ else if (res->caps & IEEE80211_CAP_IBSS)
mode = "ad-hoc";
else
mode = "infrastructure";
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index cd299c0..3b8f096 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -43,6 +43,10 @@
size_t array_len,
DBusError *error);
+dbus_bool_t wpas_dbus_string_property_getter(DBusMessageIter *iter,
+ const void *val,
+ DBusError *error);
+
DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
struct wpa_global *global);
@@ -134,6 +138,8 @@
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);
@@ -150,6 +156,7 @@
DECLARE_ACCESSOR(wpas_dbus_getter_ifname);
DECLARE_ACCESSOR(wpas_dbus_getter_driver);
DECLARE_ACCESSOR(wpas_dbus_getter_bridge_ifname);
+DECLARE_ACCESSOR(wpas_dbus_getter_config_file);
DECLARE_ACCESSOR(wpas_dbus_getter_current_bss);
DECLARE_ACCESSOR(wpas_dbus_getter_current_network);
DECLARE_ACCESSOR(wpas_dbus_getter_current_auth_mode);
@@ -185,6 +192,18 @@
DECLARE_ACCESSOR(wpas_dbus_setter_process_credentials);
DECLARE_ACCESSOR(wpas_dbus_getter_config_methods);
DECLARE_ACCESSOR(wpas_dbus_setter_config_methods);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_name);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_manufacturer);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_name);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_name);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_model_number);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_model_number);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_serial_number);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_serial_number);
+DECLARE_ACCESSOR(wpas_dbus_getter_wps_device_device_type);
+DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_device_type);
DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 73b9e20..a04783d 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -28,6 +28,18 @@
#include "../p2p_supplicant.h"
#include "../wifi_display.h"
+
+static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
+{
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE ||
+ entry.array_len != 4)
+ return 0;
+
+ return 1;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -78,6 +90,7 @@
int num_req_dev_types = 0;
unsigned int i;
u8 *req_dev_types = NULL;
+ unsigned int freq = 0;
dbus_message_iter_init(message, &iter);
entry.key = NULL;
@@ -122,6 +135,10 @@
type = P2P_FIND_PROGRESSIVE;
else
goto error_clear;
+ } else if (os_strcmp(entry.key, "freq") == 0 &&
+ (entry.type == DBUS_TYPE_INT32 ||
+ entry.type == DBUS_TYPE_UINT32)) {
+ freq = entry.uint32_value;
} else
goto error_clear;
wpa_dbus_dict_entry_clear(&entry);
@@ -130,7 +147,7 @@
wpa_s = wpa_s->global->p2p_init_wpa_s;
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL, 0, 0, NULL, 0);
+ NULL, 0, 0, NULL, freq);
os_free(req_dev_types);
return reply;
@@ -867,6 +884,35 @@
goto err_no_mem;
}
+ /* GO IP address */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_go) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrGo",
+ (char *) wpa_s->conf->ip_addr_go,
+ 4))
+ goto err_no_mem;
+
+ /* IP address mask */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_mask) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrMask",
+ (char *) wpa_s->conf->ip_addr_mask,
+ 4))
+ goto err_no_mem;
+
+ /* IP address start */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_start) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrStart",
+ (char *)
+ wpa_s->conf->ip_addr_start,
+ 4))
+ goto err_no_mem;
+
+ /* IP address end */
+ if (WPA_GET_BE32(wpa_s->conf->ip_addr_end) &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "IpAddrEnd",
+ (char *) wpa_s->conf->ip_addr_end,
+ 4))
+ goto err_no_mem;
+
/* Vendor Extensions */
for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
if (wpa_s->conf->wps_vendor_ext[i] == NULL)
@@ -1051,6 +1097,26 @@
wpa_s->conf->p2p_intra_bss = entry.bool_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_INTRA_BSS;
+ } else if (os_strcmp(entry.key, "IpAddrGo") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_go,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrMask") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_mask,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrStart") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_start,
+ entry.bytearray_value, 4);
+ } else if (os_strcmp(entry.key, "IpAddrEnd") == 0) {
+ if (!wpas_dbus_validate_dbus_ipaddr(entry))
+ goto error;
+ os_memcpy(wpa_s->conf->ip_addr_end,
+ entry.bytearray_value, 4);
} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
entry.type == DBUS_TYPE_UINT32)
wpa_s->conf->p2p_group_idle = entry.uint32_value;
@@ -2286,19 +2352,12 @@
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- char *p_pass;
struct wpa_ssid *ssid = wpa_s->current_ssid;
if (ssid == NULL)
return FALSE;
- p_pass = ssid->passphrase;
- if (!p_pass)
- p_pass = "";
-
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &p_pass, error);
-
+ return wpas_dbus_string_property_getter(iter, ssid->passphrase, error);
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index 1d5dd1c..f762b3f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -325,7 +325,7 @@
* @wpa_s: %wpa_supplicant data structure
* Returns: NULL on success or DBus error on failure
*
- * Handler for "Cancel" method call. Returns NULL if WPS cancel successfull
+ * Handler for "Cancel" method call. Returns NULL if WPS cancel successful
* or DBus error on WPS cancel failure
*/
DBusMessage * wpas_dbus_handler_wps_cancel(DBusMessage *message,
@@ -412,12 +412,10 @@
DBusMessageIter *iter, DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- char *methods = wpa_s->conf->config_methods;
- if (methods == NULL)
- methods = "";
- return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
- &methods, error);
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->config_methods,
+ error);
}
@@ -454,3 +452,349 @@
return TRUE;
}
+
+
+/**
+ * wpas_dbus_getter_wps_device_name - Get current WPS device name
+ * @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 "DeviceName" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->device_name,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_name - Set current WPS device name
+ * @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 for "DeviceName" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *devname;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_DEV_NAME_MAX_LEN)
+ return FALSE;
+
+ devname = os_strdup(methods);
+ if (!devname)
+ return FALSE;
+
+ os_free(wpa_s->conf->device_name);
+ wpa_s->conf->device_name = devname;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_NAME;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_manufacturer - Get current manufacturer name
+ * @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 "Manufacturer" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_manufacturer(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->manufacturer,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_manufacturer - Set current manufacturer name
+ * @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 for "Manufacturer" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_manufacturer(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *manufacturer;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_MANUFACTURER_MAX_LEN)
+ return FALSE;
+
+ manufacturer = os_strdup(methods);
+ if (!manufacturer)
+ return FALSE;
+
+ os_free(wpa_s->conf->manufacturer);
+ wpa_s->conf->manufacturer = manufacturer;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_model_name - Get current device model name
+ * @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 "ModelName" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_model_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_name,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_model_name - Set current device model name
+ * @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 for "ModelName" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_model_name(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *model_name;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_MODEL_NAME_MAX_LEN)
+ return FALSE;
+
+ model_name = os_strdup(methods);
+ if (!model_name)
+ return FALSE;
+ os_free(wpa_s->conf->model_name);
+ wpa_s->conf->model_name = model_name;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_model_number - Get current device model number
+ * @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 "ModelNumber" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_model_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter, wpa_s->conf->model_number,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_model_number - Set current device model number
+ * @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 for "ModelNumber" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_model_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *model_number;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_MODEL_NUMBER_MAX_LEN)
+ return FALSE;
+
+ model_number = os_strdup(methods);
+ if (!model_number)
+ return FALSE;
+
+ os_free(wpa_s->conf->model_number);
+ wpa_s->conf->model_number = model_number;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_serial_number - Get current device serial number
+ * @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 "SerialNumber" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_serial_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_string_property_getter(iter,
+ wpa_s->conf->serial_number,
+ error);
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_serial_number - Set current device serial number
+ * @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 for "SerialNumber" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_serial_number(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ char *methods, *serial_number;
+
+ if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+ &methods))
+ return FALSE;
+
+ if (os_strlen(methods) > WPS_SERIAL_NUMBER_MAX_LEN)
+ return FALSE;
+
+ serial_number = os_strdup(methods);
+ if (!serial_number)
+ return FALSE;
+ os_free(wpa_s->conf->serial_number);
+ wpa_s->conf->serial_number = serial_number;
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_WPS_STRING;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_getter_wps_device_device_type - Get current device type
+ * @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 "DeviceType" property.
+ */
+dbus_bool_t wpas_dbus_getter_wps_device_device_type(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ (char *)
+ wpa_s->conf->device_type,
+ WPS_DEV_TYPE_LEN, error)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: error constructing reply", __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * wpas_dbus_setter_wps_device_device_type - Set current device type
+ * @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 for "DeviceType" property.
+ */
+dbus_bool_t wpas_dbus_setter_wps_device_device_type(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ u8 *dev_type;
+ int dev_len;
+ DBusMessageIter variant, array_iter;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ dbus_message_iter_recurse(iter, &variant);
+ if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ dbus_message_iter_recurse(&variant, &array_iter);
+ dbus_message_iter_get_fixed_array(&array_iter, &dev_type, &dev_len);
+
+ if (dev_len != WPS_DEV_TYPE_LEN)
+ return FALSE;
+
+ os_memcpy(wpa_s->conf->device_type, dev_type, WPS_DEV_TYPE_LEN);
+ wpa_s->conf->changed_parameters |= CFG_CHANGED_DEVICE_TYPE;
+ wpa_supplicant_update_config(wpa_s);
+
+ return TRUE;
+}
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e8f62ef..e540832 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -717,16 +717,13 @@
char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
if (wpa_s->dbus_path)
- ssid = wpa_config_add_network(wpa_s->conf);
+ ssid = wpa_supplicant_add_network(wpa_s);
if (ssid == NULL) {
reply = dbus_message_new_error(
message, WPAS_ERROR_ADD_NETWORK_ERROR,
"wpa_supplicant could not add a network on this interface.");
goto out;
}
- wpas_notify_network_added(wpa_s, ssid);
- ssid->disabled = 1;
- wpa_config_set_network_defaults(ssid);
/* Construct the object path for this network. */
os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -758,7 +755,7 @@
const char *op;
char *iface = NULL, *net_id = NULL;
int id;
- struct wpa_ssid *ssid;
+ int result;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_OBJECT_PATH, &op,
@@ -781,19 +778,12 @@
}
id = strtoul(net_id, NULL, 10);
- ssid = wpa_config_get_network(wpa_s->conf, id);
- if (ssid == NULL) {
+ result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
reply = wpas_dbus_new_invalid_network_error(message);
goto out;
}
-
- wpas_notify_network_removed(wpa_s, ssid);
-
- if (ssid == wpa_s->current_ssid)
- wpa_supplicant_deauthenticate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
-
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (result == -2) {
reply = dbus_message_new_error(
message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
"error removing the specified on this interface.");
@@ -1069,8 +1059,7 @@
DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpa_s->disconnected = 1;
- wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpas_request_disconnection(wpa_s);
return wpas_dbus_new_success_reply(message);
}
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 1d05198..1e37e27 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -1,9 +1,9 @@
# Example wpa_supplicant build time configuration
#
# This file lists the configuration options that are used when building the
-# hostapd binary. All lines starting with # are ignored. Configuration option
-# lines must be commented out complete, if they are not to be included, i.e.,
-# just setting VARIABLE=n is not disabling that variable.
+# wpa_supplicant binary. All lines starting with # are ignored. Configuration
+# option lines must be commented out complete, if they are not to be included,
+# i.e., just setting VARIABLE=n is not disabling that variable.
#
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
# be modified from here. In most cases, these lines should use += in order not
@@ -370,9 +370,13 @@
# amount of memory/flash.
#CONFIG_DYNAMIC_EAP_METHODS=y
-# IEEE Std 802.11r-2008 (Fast BSS Transition)
+# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode
#CONFIG_IEEE80211R=y
+# IEEE Std 802.11r-2008 (Fast BSS Transition) for AP mode (implies
+# CONFIG_IEEE80211R).
+#CONFIG_IEEE80211R_AP=y
+
# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
#CONFIG_DEBUG_FILE=y
@@ -548,3 +552,31 @@
# Support Multi Band Operation
#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
+# This is needed to be able to use mode=1 network profile with proto=RSN and
+# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None).
+#CONFIG_IBSS_RSN=y
+
+# External PMKSA cache control
+# This can be used to enable control interface commands that allow the current
+# PMKSA cache entries to be fetched and new entries to be added.
+#CONFIG_PMKSA_CACHE_EXTERNAL=y
+
+# Mesh Networking (IEEE 802.11s)
+#CONFIG_MESH=y
+
+# Background scanning modules
+# These can be used to request wpa_supplicant to perform background scanning
+# operations for roaming within an ESS (same SSID). See the bgscan parameter in
+# the wpa_supplicant.conf file for more details.
+# Periodic background scans based on signal strength
+#CONFIG_BGSCAN_SIMPLE=y
+# Learn channels used by the network and try to avoid bgscans on other
+# channels (experimental)
+#CONFIG_BGSCAN_LEARN=y
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index 3f22413..25cfd06 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-2016,
+ <para>wpa_supplicant is copyright (c) 2003-2017,
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 13c9f45..fa94ae4 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-2016,
+ <para>wpa_supplicant is copyright (c) 2003-2017,
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 15400f0..be3045a 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-2016,
+ <para>wpa_supplicant is copyright (c) 2003-2017,
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 352d3d2..cee9ed6 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-2016,
+ <para>wpa_supplicant is copyright (c) 2003-2017,
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 faf1f27..6667a07 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -18,7 +18,7 @@
</refsynopsisdiv>
<refsect1>
- <title>Overview</title>
+ <title>Overview</title>
<para><command>wpa_passphrase</command> pre-computes PSK entries for
network configuration blocks of a
@@ -62,7 +62,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2016,
+ <para>wpa_supplicant is copyright (c) 2003-2017,
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 403c9b2..3796b93 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-2016,
+ <para>wpa_supplicant is copyright (c) 2003-2017,
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 c8c1ac4..80b3878 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -377,13 +377,6 @@
</varlistentry>
<varlistentry>
- <term>-t</term>
- <listitem>
- <para>Include timestamp in debug messages.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term>-h</term>
<listitem>
<para>Help. Show a usage message.</para>
@@ -572,7 +565,7 @@
using ap_scan=0 option in configuration file.</para>
</listitem>
</varlistentry>
-
+
<varlistentry>
<term>Wired Ethernet drivers</term>
<listitem>
@@ -597,7 +590,7 @@
</varlistentry>
</variablelist>
-
+
<para>wpa_supplicant was designed to be portable for different
drivers and operating systems. Hopefully, support for more wlan
cards and OSes will be added in the future. See developer.txt for
@@ -736,7 +729,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2016,
+ <para>wpa_supplicant is copyright (c) 2003-2017,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 699fd4f..0af63c9 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -158,6 +158,15 @@
return -1;
}
+static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (wpa_s->driver->get_seqnum)
+ return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv,
+ addr, idx, seq);
+ return -1;
+}
+
static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s,
const u8 *addr, int reason_code)
{
@@ -706,6 +715,14 @@
return wpa_s->driver->macsec_deinit(wpa_s->drv_priv);
}
+static inline int wpa_drv_macsec_get_capability(struct wpa_supplicant *wpa_s,
+ enum macsec_cap *cap)
+{
+ if (!wpa_s->driver->macsec_get_capability)
+ return -1;
+ return wpa_s->driver->macsec_get_capability(wpa_s->drv_priv, cap);
+}
+
static inline int wpa_drv_enable_protect_frames(struct wpa_supplicant *wpa_s,
Boolean enabled)
{
@@ -714,6 +731,14 @@
return wpa_s->driver->enable_protect_frames(wpa_s->drv_priv, enabled);
}
+static inline int wpa_drv_enable_encrypt(struct wpa_supplicant *wpa_s,
+ Boolean enabled)
+{
+ if (!wpa_s->driver->enable_encrypt)
+ return -1;
+ return wpa_s->driver->enable_encrypt(wpa_s->drv_priv, enabled);
+}
+
static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s,
Boolean enabled, u32 window)
{
@@ -724,12 +749,11 @@
}
static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s,
- const u8 *cs, size_t cs_len)
+ u64 cs)
{
if (!wpa_s->driver->set_current_cipher_suite)
return -1;
- return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs,
- cs_len);
+ return wpa_s->driver->set_current_cipher_suite(wpa_s->drv_priv, cs);
}
static inline int wpa_drv_enable_controlled_port(struct wpa_supplicant *wpa_s,
@@ -741,145 +765,127 @@
}
static inline int wpa_drv_get_receive_lowest_pn(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 *lowest_pn)
+ struct receive_sa *sa)
{
if (!wpa_s->driver->get_receive_lowest_pn)
return -1;
- return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, channel,
- an, lowest_pn);
+ return wpa_s->driver->get_receive_lowest_pn(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_get_transmit_next_pn(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 *next_pn)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->get_transmit_next_pn)
return -1;
- return wpa_s->driver->get_transmit_next_pn(wpa_s->drv_priv, channel,
- an, next_pn);
+ return wpa_s->driver->get_transmit_next_pn(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_set_transmit_next_pn(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 next_pn)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->set_transmit_next_pn)
return -1;
- return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, channel,
- an, next_pn);
-}
-
-static inline int wpa_drv_get_available_receive_sc(struct wpa_supplicant *wpa_s,
- u32 *channel)
-{
- if (!wpa_s->driver->get_available_receive_sc)
- return -1;
- return wpa_s->driver->get_available_receive_sc(wpa_s->drv_priv,
- channel);
+ return wpa_s->driver->set_transmit_next_pn(wpa_s->drv_priv, sa);
}
static inline int
-wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+wpa_drv_create_receive_sc(struct wpa_supplicant *wpa_s, struct receive_sc *sc,
unsigned int conf_offset, int validation)
{
if (!wpa_s->driver->create_receive_sc)
return -1;
- return wpa_s->driver->create_receive_sc(wpa_s->drv_priv, channel,
- sci_addr, sci_port, conf_offset,
- validation);
+ return wpa_s->driver->create_receive_sc(wpa_s->drv_priv, sc,
+ conf_offset, validation);
}
static inline int wpa_drv_delete_receive_sc(struct wpa_supplicant *wpa_s,
- u32 channel)
+ struct receive_sc *sc)
{
if (!wpa_s->driver->delete_receive_sc)
return -1;
- return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, channel);
+ return wpa_s->driver->delete_receive_sc(wpa_s->drv_priv, sc);
}
static inline int wpa_drv_create_receive_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak)
+ struct receive_sa *sa)
{
if (!wpa_s->driver->create_receive_sa)
return -1;
- return wpa_s->driver->create_receive_sa(wpa_s->drv_priv, channel, an,
- lowest_pn, sak);
+ return wpa_s->driver->create_receive_sa(wpa_s->drv_priv, sa);
+}
+
+static inline int wpa_drv_delete_receive_sa(struct wpa_supplicant *wpa_s,
+ struct receive_sa *sa)
+{
+ if (!wpa_s->driver->delete_receive_sa)
+ return -1;
+ return wpa_s->driver->delete_receive_sa(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_enable_receive_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+ struct receive_sa *sa)
{
if (!wpa_s->driver->enable_receive_sa)
return -1;
- return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->enable_receive_sa(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_disable_receive_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+ struct receive_sa *sa)
{
if (!wpa_s->driver->disable_receive_sa)
return -1;
- return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->disable_receive_sa(wpa_s->drv_priv, sa);
}
static inline int
-wpa_drv_get_available_transmit_sc(struct wpa_supplicant *wpa_s, u32 *channel)
-{
- if (!wpa_s->driver->get_available_transmit_sc)
- return -1;
- return wpa_s->driver->get_available_transmit_sc(wpa_s->drv_priv,
- channel);
-}
-
-static inline int
-wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, u32 channel,
- const u8 *sci_addr, u16 sci_port,
+wpa_drv_create_transmit_sc(struct wpa_supplicant *wpa_s, struct transmit_sc *sc,
unsigned int conf_offset)
{
if (!wpa_s->driver->create_transmit_sc)
return -1;
- return wpa_s->driver->create_transmit_sc(wpa_s->drv_priv, channel,
- sci_addr, sci_port,
+ return wpa_s->driver->create_transmit_sc(wpa_s->drv_priv, sc,
conf_offset);
}
static inline int wpa_drv_delete_transmit_sc(struct wpa_supplicant *wpa_s,
- u32 channel)
+ struct transmit_sc *sc)
{
if (!wpa_s->driver->delete_transmit_sc)
return -1;
- return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, channel);
+ return wpa_s->driver->delete_transmit_sc(wpa_s->drv_priv, sc);
}
static inline int wpa_drv_create_transmit_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an,
- u32 next_pn,
- Boolean confidentiality,
- const u8 *sak)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->create_transmit_sa)
return -1;
- return wpa_s->driver->create_transmit_sa(wpa_s->drv_priv, channel, an,
- next_pn, confidentiality, sak);
+ return wpa_s->driver->create_transmit_sa(wpa_s->drv_priv, sa);
+}
+
+static inline int wpa_drv_delete_transmit_sa(struct wpa_supplicant *wpa_s,
+ struct transmit_sa *sa)
+{
+ if (!wpa_s->driver->delete_transmit_sa)
+ return -1;
+ return wpa_s->driver->delete_transmit_sa(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_enable_transmit_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->enable_transmit_sa)
return -1;
- return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->enable_transmit_sa(wpa_s->drv_priv, sa);
}
static inline int wpa_drv_disable_transmit_sa(struct wpa_supplicant *wpa_s,
- u32 channel, u8 an)
+ struct transmit_sa *sa)
{
if (!wpa_s->driver->disable_transmit_sa)
return -1;
- return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, channel, an);
+ return wpa_s->driver->disable_transmit_sa(wpa_s->drv_priv, sa);
}
#endif /* CONFIG_MACSEC */
@@ -896,6 +902,11 @@
unsigned int *num,
unsigned int *freq_list)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->get_pref_freq_list_override)
+ return wpas_ctrl_iface_get_pref_freq_list_override(
+ wpa_s, if_type, num, freq_list);
+#endif /* CONFIG_TESTING_OPTIONS */
if (!wpa_s->driver->get_pref_freq_list)
return -1;
return wpa_s->driver->get_pref_freq_list(wpa_s->drv_priv, if_type,
@@ -910,11 +921,72 @@
return wpa_s->driver->set_prob_oper_freq(wpa_s->drv_priv, freq);
}
-static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s)
+static inline int wpa_drv_abort_scan(struct wpa_supplicant *wpa_s,
+ u64 scan_cookie)
{
if (!wpa_s->driver->abort_scan)
return -1;
- return wpa_s->driver->abort_scan(wpa_s->drv_priv);
+ return wpa_s->driver->abort_scan(wpa_s->drv_priv, scan_cookie);
+}
+
+static inline int wpa_drv_configure_frame_filters(struct wpa_supplicant *wpa_s,
+ u32 filters)
+{
+ if (!wpa_s->driver->configure_data_frame_filters)
+ return -1;
+ return wpa_s->driver->configure_data_frame_filters(wpa_s->drv_priv,
+ filters);
+}
+
+static inline int wpa_drv_get_ext_capa(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type type)
+{
+ if (!wpa_s->driver->get_ext_capab)
+ return -1;
+ return wpa_s->driver->get_ext_capab(wpa_s->drv_priv, type,
+ &wpa_s->extended_capa,
+ &wpa_s->extended_capa_mask,
+ &wpa_s->extended_capa_len);
+}
+
+static inline int wpa_drv_p2p_lo_start(struct wpa_supplicant *wpa_s,
+ unsigned int channel,
+ unsigned int period,
+ unsigned int interval,
+ unsigned int count,
+ const u8 *device_types,
+ size_t dev_types_len,
+ const u8 *ies, size_t ies_len)
+{
+ if (!wpa_s->driver->p2p_lo_start)
+ return -1;
+ return wpa_s->driver->p2p_lo_start(wpa_s->drv_priv, channel, period,
+ interval, count, device_types,
+ dev_types_len, ies, ies_len);
+}
+
+static inline int wpa_drv_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->p2p_lo_stop)
+ return -1;
+ return wpa_s->driver->p2p_lo_stop(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t len)
+{
+ if (!wpa_s->driver->set_default_scan_ies)
+ return -1;
+ return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len);
+}
+
+static inline int wpa_drv_set_tdls_mode(struct wpa_supplicant *wpa_s,
+ int tdls_external_control)
+{
+ if (!wpa_s->driver->set_tdls_mode)
+ return -1;
+ return wpa_s->driver->set_tdls_mode(wpa_s->drv_priv,
+ tdls_external_control);
}
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 1b3d8a9..bc3c90e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -281,6 +281,11 @@
wpa_supplicant_ap_deinit(wpa_s);
#endif /* CONFIG_AP */
+#ifdef CONFIG_HS20
+ /* Clear possibly configured frame filters */
+ wpa_drv_configure_frame_filters(wpa_s, 0);
+#endif /* CONFIG_HS20 */
+
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
return;
@@ -498,7 +503,7 @@
static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_bss *bss)
+ struct wpa_bss *bss, int debug_print)
{
struct wpa_ie_data ie;
int proto_match = 0;
@@ -521,40 +526,46 @@
proto_match++;
if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - parse "
- "failed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - parse failed");
break;
}
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
- "in RSN IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on TSN in RSN IE");
return 1;
}
if (!(ie.proto & ssid->proto)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - proto "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - proto mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - PTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - PTK cipher mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - GTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - GTK cipher mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - key mgmt "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - key mgmt mismatch");
break;
}
@@ -562,16 +573,18 @@
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
- "frame protection");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection");
break;
}
#endif /* CONFIG_IEEE80211W */
if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
wpas_get_ssid_pmf(wpa_s, ssid) ==
NO_MGMT_FRAME_PROTECTION) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled but AP requires it");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled but AP requires it");
break;
}
#ifdef CONFIG_MBO
@@ -579,87 +592,114 @@
wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) &&
wpas_get_ssid_pmf(wpa_s, ssid) !=
NO_MGMT_FRAME_PROTECTION) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip RSN IE - no mgmt frame protection enabled on MBO AP");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSN IE - no mgmt frame protection enabled on MBO AP");
break;
}
#endif /* CONFIG_MBO */
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on RSN IE");
return 1;
}
+#ifdef CONFIG_IEEE80211W
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MFP Required but network not MFP Capable");
+ return 0;
+ }
+#endif /* CONFIG_IEEE80211W */
+
wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
proto_match++;
if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - parse "
- "failed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - parse failed");
break;
}
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
{
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
- "in WPA IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on TSN in WPA IE");
return 1;
}
if (!(ie.proto & ssid->proto)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - proto "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - proto mismatch");
break;
}
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - PTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - PTK cipher mismatch");
break;
}
if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - GTK "
- "cipher mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - GTK cipher mismatch");
break;
}
if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - key mgmt "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip WPA IE - key mgmt mismatch");
break;
}
- wpa_dbg(wpa_s, MSG_DEBUG, " selected based on WPA IE");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " selected based on WPA IE");
return 1;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
!rsn_ie) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " allow for non-WPA IEEE 802.1X");
return 1;
}
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no WPA/RSN proto match");
return 0;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) &&
wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow in OSEN");
return 1;
}
if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
return 1;
}
- wpa_dbg(wpa_s, MSG_DEBUG, " reject due to mismatch with "
- "WPA/WPA2");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " reject due to mismatch with WPA/WPA2");
return 0;
}
@@ -679,7 +719,8 @@
}
-static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int debug_print)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
@@ -736,9 +777,9 @@
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
if (!ht_supported(mode)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support "
- "HT PHY");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support HT PHY");
return 0;
}
continue;
@@ -748,9 +789,9 @@
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) {
if (!vht_supported(mode)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support "
- "VHT PHY");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support VHT PHY");
return 0;
}
continue;
@@ -770,10 +811,11 @@
* order to join a BSS all required rates
* have to be supported by the hardware.
*/
- wpa_dbg(wpa_s, MSG_DEBUG,
- " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
- r / 10, r % 10,
- bss->freq, mode->mode, mode->num_rates);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support required rate %d.%d Mbps (freq=%d mode==%d num_rates=%d)",
+ r / 10, r % 10,
+ bss->freq, mode->mode, mode->num_rates);
return 0;
}
}
@@ -829,7 +871,7 @@
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
- int only_first_ssid)
+ int only_first_ssid, int debug_print)
{
u8 wpa_ie_len, rsn_ie_len;
int wpa;
@@ -850,15 +892,20 @@
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
- wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
- "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
- i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
- wpa_ie_len, rsn_ie_len, bss->caps, bss->level, bss->freq,
- wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "",
- (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
- wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) ?
- " p2p" : "",
- osen ? " osen=1" : "");
+ if (debug_print) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR
+ " ssid='%s' wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d freq=%d %s%s%s",
+ i, MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len),
+ wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
+ bss->freq,
+ wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ?
+ " wps" : "",
+ (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
+ wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE))
+ ? " p2p" : "",
+ osen ? " osen=1" : "");
+ }
e = wpa_blacklist_get(wpa_s, bss->bssid);
if (e) {
@@ -875,24 +922,30 @@
limit = 0;
}
if (e->count > limit) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
- "(count=%d limit=%d)", e->count, limit);
+ if (debug_print) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (count=%d limit=%d)",
+ e->count, limit);
+ }
return NULL;
}
}
if (bss->ssid_len == 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
return NULL;
}
if (disallowed_bssid(wpa_s, bss->bssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
return NULL;
}
if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
return NULL;
}
@@ -903,21 +956,25 @@
int res;
if (wpas_network_disabled(wpa_s, ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
continue;
}
res = wpas_temp_disabled(wpa_s, ssid);
if (res > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled "
- "temporarily for %d second(s)", res);
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - disabled temporarily for %d second(s)",
+ res);
continue;
}
#ifdef CONFIG_WPS
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
- "(WPS)");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - blacklisted (WPS)");
continue;
}
@@ -943,13 +1000,17 @@
if (check_ssid &&
(bss->ssid_len != ssid->ssid_len ||
os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SSID mismatch");
continue;
}
if (ssid->bssid_set &&
os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID mismatch");
continue;
}
@@ -957,8 +1018,9 @@
if (ssid->num_bssid_blacklist &&
addr_in_list(bss->bssid, ssid->bssid_blacklist,
ssid->num_bssid_blacklist)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID blacklisted");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID blacklisted");
continue;
}
@@ -966,69 +1028,106 @@
if (ssid->num_bssid_whitelist &&
!addr_in_list(bss->bssid, ssid->bssid_whitelist,
ssid->num_bssid_whitelist)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - BSSID not in whitelist");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in whitelist");
continue;
}
- if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
+ if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss,
+ debug_print))
continue;
if (!osen && !wpa &&
!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-WPA network "
- "not allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-WPA network not allowed");
continue;
}
if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
has_wep_key(ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - ignore WPA/WPA2 AP for WEP network block");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - ignore WPA/WPA2 AP for WEP network block");
continue;
}
if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-OSEN network "
- "not allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - non-OSEN network not allowed");
continue;
}
if (!wpa_supplicant_match_privacy(bss, ssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy "
- "mismatch");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - privacy mismatch");
continue;
}
- if (!bss_is_ess(bss) && !bss_is_pbss(bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - neither ESS nor PBSS network");
+ if (ssid->mode != IEEE80211_MODE_MESH && !bss_is_ess(bss) &&
+ !bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - not ESS, PBSS, or MBSS");
continue;
}
- if (ssid->pbss != bss_is_pbss(bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - PBSS mismatch (ssid %d bss %d)",
- ssid->pbss, bss_is_pbss(bss));
+ if (ssid->pbss != 2 && ssid->pbss != bss_is_pbss(bss)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - PBSS mismatch (ssid %d bss %d)",
+ ssid->pbss, bss_is_pbss(bss));
continue;
}
if (!freq_allowed(ssid->freq_list, bss->freq)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not "
- "allowed");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed");
continue;
}
- if (!rate_match(wpa_s, bss)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do "
- "not match");
+#ifdef CONFIG_MESH
+ if (ssid->mode == IEEE80211_MODE_MESH && ssid->frequency > 0 &&
+ ssid->frequency != bss->freq) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - frequency not allowed (mesh)");
continue;
}
+#endif /* CONFIG_MESH */
+
+ if (!rate_match(wpa_s, bss, debug_print)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - rate sets do not match");
+ continue;
+ }
+
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
+ WPA_KEY_MGMT_WPA_NONE))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - IBSS RSN not supported in the build");
+ continue;
+ }
+#endif /* !CONFIG_IBSS_RSN */
#ifdef CONFIG_P2P
if (ssid->p2p_group &&
!wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
!wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P IE seen");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P IE seen");
continue;
}
@@ -1038,20 +1137,26 @@
ie = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
if (ie == NULL) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no P2P element");
continue;
}
p2p_ie = wpa_bss_get_vendor_ie_multi(
bss, P2P_IE_VENDOR_TYPE);
if (p2p_ie == NULL) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - could not fetch P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - could not fetch P2P element");
continue;
}
if (p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr) < 0
|| os_memcmp(dev_addr, ssid->go_p2p_dev_addr,
ETH_ALEN) != 0) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - no matching GO P2P Device Address in P2P element");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - no matching GO P2P Device Address in P2P element");
wpabuf_free(p2p_ie);
continue;
}
@@ -1071,27 +1176,37 @@
os_reltime_sub(&wpa_s->scan_min_time,
&bss->last_update, &diff);
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - scan result not recent enough (%u.%06u seconds too old)",
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - scan result not recent enough (%u.%06u seconds too old)",
(unsigned int) diff.sec,
(unsigned int) diff.usec);
continue;
}
#ifdef CONFIG_MBO
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_assoc_disallow)
+ goto skip_assoc_disallow;
+#endif /* CONFIG_TESTING_OPTIONS */
assoc_disallow = wpas_mbo_get_bss_attr(
bss, MBO_ATTR_ID_ASSOC_DISALLOW);
if (assoc_disallow && assoc_disallow[1] >= 1) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO association disallowed (reason %u)",
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO association disallowed (reason %u)",
assoc_disallow[2]);
continue;
}
if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - MBO retry delay has not passed yet");
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - MBO retry delay has not passed yet");
continue;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ skip_assoc_disallow:
+#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_MBO */
/* Matching configuration found */
@@ -1111,6 +1226,25 @@
{
unsigned int i;
+ if (wpa_s->current_ssid) {
+ struct wpa_ssid *ssid;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Scan results matching the currently selected network");
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+ ssid = wpa_scan_res_match(wpa_s, i, bss, group,
+ only_first_ssid, 0);
+ if (ssid != wpa_s->current_ssid)
+ continue;
+ wpa_dbg(wpa_s, MSG_DEBUG, "%u: " MACSTR
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ i, MAC2STR(bss->bssid), bss->freq, bss->level,
+ bss->snr, bss->est_throughput);
+ }
+ }
+
if (only_first_ssid)
wpa_dbg(wpa_s, MSG_DEBUG, "Try to find BSS matching pre-selected network id=%d",
group->id);
@@ -1121,7 +1255,7 @@
for (i = 0; i < wpa_s->last_scan_res_used; i++) {
struct wpa_bss *bss = wpa_s->last_scan_res[i];
*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group,
- only_first_ssid);
+ only_first_ssid, 1);
if (!*selected_ssid)
continue;
wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
@@ -1302,6 +1436,17 @@
{
if (wpas_network_disabled(wpa_s, ssid))
continue;
+#ifndef CONFIG_IBSS_RSN
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
+ WPA_KEY_MGMT_WPA_NONE))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "IBSS RSN not supported in the build - cannot use the profile for SSID '%s'",
+ wpa_ssid_txt(ssid->ssid,
+ ssid->ssid_len));
+ continue;
+ }
+#endif /* !CONFIG_IBSS_RSN */
if (ssid->mode == IEEE80211_MODE_IBSS ||
ssid->mode == IEEE80211_MODE_AP ||
ssid->mode == IEEE80211_MODE_MESH)
@@ -1345,8 +1490,9 @@
{
struct wpa_bss *current_bss = NULL;
#ifndef CONFIG_NO_ROAMING
- int min_diff;
+ int min_diff, diff;
int to_5ghz;
+ int cur_est, sel_est;
#endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate)
@@ -1380,12 +1526,13 @@
#ifndef CONFIG_NO_ROAMING
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
- " level=%d snr=%d est_throughput=%u",
- MAC2STR(current_bss->bssid), current_bss->level,
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ MAC2STR(current_bss->bssid),
+ current_bss->freq, current_bss->level,
current_bss->snr, current_bss->est_throughput);
wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR
- " level=%d snr=%d est_throughput=%u",
- MAC2STR(selected->bssid), selected->level,
+ " freq=%d level=%d snr=%d est_throughput=%u",
+ MAC2STR(selected->bssid), selected->freq, selected->level,
selected->snr, selected->est_throughput);
if (wpa_s->current_ssid->bssid_set &&
@@ -1411,6 +1558,14 @@
return 0;
}
+ if (current_bss->est_throughput > selected->est_throughput + 5000) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - Current BSS has better estimated throughput");
+ return 0;
+ }
+
+ cur_est = current_bss->est_throughput;
+ sel_est = selected->est_throughput;
min_diff = 2;
if (current_bss->level < 0) {
if (current_bss->level < -85)
@@ -1423,20 +1578,42 @@
min_diff = 4;
else
min_diff = 5;
+ if (cur_est > sel_est * 1.5)
+ min_diff += 10;
+ else if (cur_est > sel_est * 1.2)
+ min_diff += 5;
+ else if (cur_est > sel_est * 1.1)
+ min_diff += 2;
+ else if (cur_est > sel_est)
+ min_diff++;
}
if (to_5ghz) {
+ int reduce = 2;
+
/* Make it easier to move to 5 GHz band */
- if (min_diff > 2)
- min_diff -= 2;
+ if (sel_est > cur_est * 1.5)
+ reduce = 5;
+ else if (sel_est > cur_est * 1.2)
+ reduce = 4;
+ else if (sel_est > cur_est * 1.1)
+ reduce = 3;
+
+ if (min_diff > reduce)
+ min_diff -= reduce;
else
min_diff = 0;
}
- if (abs(current_bss->level - selected->level) < min_diff) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
- "in signal level");
+ diff = abs(current_bss->level - selected->level);
+ if (diff < min_diff) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Skip roam - too small difference in signal level (%d < %d)",
+ diff, min_diff);
return 0;
}
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Allow reassociation due to difference in signal level (%d >= %d)",
+ diff, min_diff);
return 1;
#else /* CONFIG_NO_ROAMING */
return 0;
@@ -1444,11 +1621,18 @@
}
-/* Return != 0 if no scan results could be fetched or if scan results should not
- * be shared with other virtual interfaces. */
+/*
+ * Return a negative value if no scan results could be fetched or if scan
+ * results should not be shared with other virtual interfaces.
+ * Return 0 if scan results were fetched and may be shared with other
+ * interfaces.
+ * Return 1 if scan results may be shared with other virtual interfaces but may
+ * not trigger any operations.
+ * Return 2 if the interface was removed and cannot be used.
+ */
static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
union wpa_event_data *data,
- int own_request)
+ int own_request, int update_only)
{
struct wpa_scan_results *scan_res = NULL;
int ret = 0;
@@ -1498,6 +1682,11 @@
}
#endif /* CONFIG_NO_RANDOM_POOL */
+ if (update_only) {
+ ret = 1;
+ goto scan_work_done;
+ }
+
if (own_request && wpa_s->scan_res_handler &&
!(data && data->scan_info.external_scan)) {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
@@ -1506,7 +1695,7 @@
scan_res_handler = wpa_s->scan_res_handler;
wpa_s->scan_res_handler = NULL;
scan_res_handler(wpa_s, scan_res);
- ret = -2;
+ ret = 1;
goto scan_work_done;
}
@@ -1547,6 +1736,10 @@
if (sme_proc_obss_scan(wpa_s) > 0)
goto scan_work_done;
+ if (own_request &&
+ wpas_beacon_rep_scan_process(wpa_s, scan_res, &data->scan_info) > 0)
+ goto scan_work_done;
+
if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
goto scan_work_done;
@@ -1611,6 +1804,14 @@
selected = wpa_supplicant_pick_network(wpa_s, &ssid);
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Avoiding join because we already joined a mesh group");
+ return 0;
+ }
+#endif /* CONFIG_MESH */
+
if (selected) {
int skip;
skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
@@ -1634,18 +1835,12 @@
if (new_scan)
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
/*
- * Do not notify other virtual radios of scan results since we do not
- * want them to start other associations at the same time.
+ * Do not allow other virtual radios to trigger operations based
+ * on these scan results since we do not want them to start
+ * other associations at the same time.
*/
return 1;
} else {
-#ifdef CONFIG_MESH
- if (wpa_s->ifmsh) {
- wpa_msg(wpa_s, MSG_INFO,
- "Avoiding join because we already joined a mesh group");
- return 0;
- }
-#endif /* CONFIG_MESH */
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -1726,7 +1921,7 @@
struct wpa_supplicant *ifs;
int res;
- res = _wpa_supplicant_event_scan_results(wpa_s, data, 1);
+ res = _wpa_supplicant_event_scan_results(wpa_s, data, 1, 0);
if (res == 2) {
/*
* Interface may have been removed, so must not dereference
@@ -1734,7 +1929,8 @@
*/
return 1;
}
- if (res != 0) {
+
+ if (res < 0) {
/*
* If no scan results could be fetched, then no need to
* notify those interfaces that did not actually request
@@ -1754,7 +1950,10 @@
if (ifs != wpa_s) {
wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
"sibling", ifs->ifname);
- _wpa_supplicant_event_scan_results(ifs, data, 0);
+ res = _wpa_supplicant_event_scan_results(ifs, data, 0,
+ res > 0);
+ if (res < 0)
+ return 0;
}
}
@@ -1771,6 +1970,8 @@
#else /* CONFIG_NO_SCAN_PROCESSING */
struct os_reltime now;
+ wpa_s->ignore_post_flush_scan_res = 0;
+
if (wpa_s->last_scan_res_used == 0)
return -1;
@@ -2010,6 +2211,19 @@
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+#ifdef CONFIG_FILS
+#ifdef CONFIG_SME
+ if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS &&
+ (!data->assoc_info.resp_frame ||
+ fils_process_assoc_resp(wpa_s->wpa,
+ data->assoc_info.resp_frame,
+ data->assoc_info.resp_frame_len) < 0)) {
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED);
+ return -1;
+ }
+#endif /* CONFIG_SME */
+#endif /* CONFIG_FILS */
+
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
@@ -2210,7 +2424,7 @@
union wpa_event_data *data)
{
u8 bssid[ETH_ALEN];
- int ft_completed;
+ int ft_completed, already_authorized;
int new_bss = 0;
#ifdef CONFIG_AP
@@ -2231,6 +2445,13 @@
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
return;
+ /*
+ * FILS authentication can share the same mechanism to mark the
+ * connection fully authenticated, so set ft_completed also based on
+ * FILS result.
+ */
+ if (!ft_completed)
+ ft_completed = wpa_fils_is_completed(wpa_s->wpa);
if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
@@ -2259,12 +2480,8 @@
}
}
-#ifdef ANDROID
- if (wpa_s->conf->ap_scan == 1) {
-#else
if (wpa_s->conf->ap_scan == 1 &&
wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
-#endif
if (wpa_supplicant_assoc_update_ie(wpa_s) < 0 && new_bss)
wpa_msg(wpa_s, MSG_WARNING,
"WPA/RSN IEs not updated");
@@ -2290,6 +2507,8 @@
if (wpa_s->l2)
l2_packet_notify_auth_start(wpa_s->l2);
+ already_authorized = data && data->assoc_info.authorized;
+
/*
* Set portEnabled first to FALSE in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
@@ -2298,11 +2517,12 @@
* AUTHENTICATED without ever giving chance to EAP state machine to
* reset the state.
*/
- if (!ft_completed) {
+ if (!ft_completed && !already_authorized) {
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
}
- if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed)
+ if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed ||
+ already_authorized)
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
/* 802.1X::portControl = Auto */
eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -2365,7 +2585,7 @@
struct os_reltime now, age;
os_get_reltime(&now);
os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
- if (age.sec == 0 && age.usec < 100000 &&
+ if (age.sec == 0 && age.usec < 200000 &&
os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
@@ -2394,7 +2614,7 @@
wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
wpa_s->ibss_rsn == NULL) {
- wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+ wpa_s->ibss_rsn = ibss_rsn_init(wpa_s, wpa_s->current_ssid);
if (!wpa_s->ibss_rsn) {
wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
wpa_supplicant_deauthenticate(
@@ -2488,6 +2708,7 @@
struct wpa_bss *fast_reconnect = NULL;
struct wpa_ssid *fast_reconnect_ssid = NULL;
struct wpa_ssid *last_ssid;
+ struct wpa_bss *curr = NULL;
authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -2503,6 +2724,19 @@
return;
}
+ if (!wpa_s->disconnected && wpa_s->wpa_state >= WPA_AUTHENTICATING &&
+ reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY &&
+ locally_generated)
+ /*
+ * Remove the inactive AP (which is probably out of range) from
+ * the BSS list after marking disassociation. In particular
+ * mac80211-based drivers use the
+ * WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY reason code in
+ * locally generated disconnection events for cases where the
+ * AP does not reply anymore.
+ */
+ curr = wpa_s->current_bss;
+
if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect");
@@ -2564,6 +2798,9 @@
last_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s);
+ if (curr)
+ wpa_bss_remove(wpa_s, curr, "Connection to AP lost");
+
if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
wpa_s->current_ssid = last_ssid;
@@ -3165,7 +3402,16 @@
{
struct wpa_supplicant *ifs;
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+ /*
+ * To allow backwards compatibility with higher level layers that
+ * assumed the REGDOM_CHANGE event is sent over the initially added
+ * interface. Find the highest parent of this interface and use it to
+ * send the event.
+ */
+ 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 : "");
@@ -3180,14 +3426,16 @@
free_hw_features(ifs);
ifs->hw.modes = wpa_drv_get_hw_feature_data(
ifs, &ifs->hw.num_modes, &ifs->hw.flags);
- }
- /* Restart sched_scan with updated channel list */
- if (wpa_s->sched_scanning) {
- wpa_dbg(wpa_s, MSG_DEBUG,
- "Channel list changed restart sched scan.");
- wpa_supplicant_cancel_sched_scan(wpa_s);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ /* Restart PNO/sched_scan with updated channel list */
+ if (ifs->pno) {
+ wpas_stop_pno(ifs);
+ wpas_start_pno(ifs);
+ } else if (ifs->sched_scanning && !ifs->pno_sched_pending) {
+ wpa_dbg(ifs, MSG_DEBUG,
+ "Channel list changed - restart sched_scan");
+ wpas_scan_restart_sched_scan(ifs);
+ }
}
wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DRIVER);
@@ -3278,6 +3526,14 @@
#endif /* CONFIG_INTERWORKING */
if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) {
+ wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa,
+ payload + 1,
+ plen - 1);
+ return;
+ }
+
+ if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
return;
@@ -3362,6 +3618,7 @@
union wpa_event_data *data)
{
struct wpa_supplicant *wpa_s = ctx;
+ char buf[100];
int resched;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
@@ -3405,6 +3662,13 @@
sme_event_auth(wpa_s, data);
break;
case EVENT_ASSOC:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO,
+ "EVENT_ASSOC - ignore_auth_resp active!");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_supplicant_event_assoc(wpa_s, data);
if (data && data->assoc_info.authorized)
wpa_supplicant_event_assoc_auth(wpa_s, data);
@@ -3419,6 +3683,13 @@
data ? &data->disassoc_info : NULL);
break;
case EVENT_DEAUTH:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO,
+ "EVENT_DEAUTH - ignore_auth_resp active!");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpas_event_deauth(wpa_s,
data ? &data->deauth_info : NULL);
break;
@@ -3516,16 +3787,26 @@
break;
#endif /* CONFIG_IBSS_RSN */
case EVENT_ASSOC_REJECT:
+ if (data->assoc_reject.timeout_reason)
+ os_snprintf(buf, sizeof(buf), "=%s",
+ data->assoc_reject.timeout_reason);
+ else
+ buf[0] = '\0';
if (data->assoc_reject.bssid)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "bssid=" MACSTR " status_code=%u",
+ "bssid=" MACSTR " status_code=%u%s%s",
MAC2STR(data->assoc_reject.bssid),
- data->assoc_reject.status_code);
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "",
+ buf);
else
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
- "status_code=%u",
- data->assoc_reject.status_code);
+ "status_code=%u%s%s",
+ data->assoc_reject.status_code,
+ data->assoc_reject.timed_out ? " timeout" : "",
+ buf);
wpa_s->assoc_status_code = data->assoc_reject.status_code;
+ wpa_s->assoc_timed_out = data->assoc_reject.timed_out;
wpas_notify_assoc_status_code(wpa_s);
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_reject(wpa_s, data);
@@ -3582,17 +3863,20 @@
#endif /* CONFIG_AP */
#ifdef CONFIG_OFFCHANNEL
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
- MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
+ MACSTR, MAC2STR(wpa_s->p2pdev->pending_action_dst));
/*
* Catch TX status events for Action frames we sent via group
- * interface in GO mode.
+ * interface in GO mode, or via standalone AP interface.
+ * Note, wpa_s->p2pdev will be the same as wpa_s->parent,
+ * except when the primary interface is used as a GO interface
+ * (for drivers which do not have group interface concurrency)
*/
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
- os_memcmp(wpa_s->parent->pending_action_dst,
+ os_memcmp(wpa_s->p2pdev->pending_action_dst,
data->tx_status.dst, ETH_ALEN) == 0) {
offchannel_send_action_tx_status(
- wpa_s->parent, data->tx_status.dst,
+ wpa_s->p2pdev, data->tx_status.dst,
data->tx_status.data,
data->tx_status.data_len,
data->tx_status.ack ?
@@ -3638,6 +3922,15 @@
if (!data || !wpa_s->current_ssid)
break;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CHANNEL_SWITCH
+ "freq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d",
+ data->ch_switch.freq,
+ data->ch_switch.ht_enabled,
+ data->ch_switch.ch_offset,
+ channel_width_to_string(data->ch_switch.ch_width),
+ data->ch_switch.cf1,
+ data->ch_switch.cf2);
+
wpa_s->assoc_freq = data->ch_switch.freq;
wpa_s->current_ssid->frequency = data->ch_switch.freq;
@@ -3905,6 +4198,7 @@
wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
}
wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_bss_flush(wpa_s);
radio_remove_works(wpa_s, NULL, 0);
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
@@ -3971,6 +4265,20 @@
break;
/*
+ * If the driver stopped scanning without being requested to,
+ * request a new scan to continue scanning for networks.
+ */
+ if (!wpa_s->sched_scan_stop_req &&
+ wpa_s->wpa_state == WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Restart scanning after unexpected sched_scan stop event");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ break;
+ }
+
+ wpa_s->sched_scan_stop_req = 0;
+
+ /*
* Start a new sched scan to continue searching for more SSIDs
* either if timed out or PNO schedule scan is pending.
*/
@@ -4020,12 +4328,28 @@
#endif /* CONFIG_AP */
break;
case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_AP
#ifdef CONFIG_ACS
if (!wpa_s->ap_iface)
break;
hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
&data->acs_selected_channels);
#endif /* CONFIG_ACS */
+#endif /* CONFIG_AP */
+ break;
+ case EVENT_P2P_LO_STOP:
+#ifdef CONFIG_P2P
+ wpa_s->p2p_lo_started = 0;
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_LISTEN_OFFLOAD_STOP
+ P2P_LISTEN_OFFLOAD_STOP_REASON "reason=%d",
+ data->p2p_lo_stop.reason_code);
+#endif /* CONFIG_P2P */
+ break;
+ case EVENT_BEACON_LOSS:
+ if (!wpa_s->current_bss || !wpa_s->current_ssid)
+ break;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_BEACON_LOSS);
+ bgscan_notify_beacon_loss(wpa_s);
break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 4f0d0e6..db481a5 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -17,6 +17,7 @@
#include "common/wpa_ctrl.h"
#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
+#include "config.h"
#include "driver_i.h"
#include "offchannel.h"
#include "gas_query.h"
@@ -52,6 +53,7 @@
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code);
void *ctx;
+ u8 sa[ETH_ALEN];
};
/**
@@ -62,6 +64,9 @@
struct dl_list pending; /* struct gas_query_pending */
struct gas_query_pending *current;
struct wpa_radio_work *work;
+ struct os_reltime last_mac_addr_rand;
+ int last_rand_sa_type;
+ u8 rand_addr[ETH_ALEN];
};
@@ -116,8 +121,6 @@
return "PEER_ERROR";
case GAS_QUERY_INTERNAL_ERROR:
return "INTERNAL_ERROR";
- case GAS_QUERY_CANCELLED:
- return "CANCELLED";
case GAS_QUERY_DELETED_AT_DEINIT:
return "DELETED_AT_DEINIT";
}
@@ -273,10 +276,15 @@
struct wpabuf *req, unsigned int wait_time)
{
int res, prot = pmf_in_use(gas->wpa_s, query->addr);
+ const u8 *bssid;
+ const u8 wildcard_bssid[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
- "freq=%d prot=%d", MAC2STR(query->addr),
- (unsigned int) wpabuf_len(req), query->freq, prot);
+ "freq=%d prot=%d using src addr " MACSTR,
+ MAC2STR(query->addr), (unsigned int) wpabuf_len(req),
+ query->freq, prot, MAC2STR(query->sa));
if (prot) {
u8 *categ = wpabuf_mhead_u8(req);
*categ = WLAN_ACTION_PROTECTED_DUAL;
@@ -285,10 +293,19 @@
if (gas->wpa_s->max_remain_on_chan &&
wait_time > gas->wpa_s->max_remain_on_chan)
wait_time = gas->wpa_s->max_remain_on_chan;
+ if (!gas->wpa_s->conf->gas_address3 ||
+ (gas->wpa_s->current_ssid &&
+ gas->wpa_s->wpa_state >= WPA_ASSOCIATED &&
+ os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))
+ bssid = query->addr;
+ else
+ bssid = wildcard_bssid;
+
res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
- gas->wpa_s->own_addr, query->addr,
- wpabuf_head(req), wpabuf_len(req),
- wait_time, gas_query_tx_status, 0);
+ query->sa, bssid, wpabuf_head(req),
+ wpabuf_len(req), wait_time,
+ gas_query_tx_status, 0);
+
if (res == 0)
query->offchannel_tx_started = 1;
return res;
@@ -397,6 +414,7 @@
}
if (comeback_delay) {
+ eloop_cancel_timeout(gas_query_timeout, gas, query);
query->wait_comeback = 1;
gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
return;
@@ -500,6 +518,14 @@
if (gas == NULL || len < 4)
return -1;
+ pos = data;
+ action = *pos++;
+ dialog_token = *pos++;
+
+ if (action != WLAN_PA_GAS_INITIAL_RESP &&
+ action != WLAN_PA_GAS_COMEBACK_RESP)
+ return -1; /* Not a GAS response */
+
prot = categ == WLAN_ACTION_PROTECTED_DUAL;
pmf = pmf_in_use(gas->wpa_s, sa);
if (prot && !pmf) {
@@ -511,14 +537,6 @@
return 0;
}
- pos = data;
- action = *pos++;
- dialog_token = *pos++;
-
- if (action != WLAN_PA_GAS_INITIAL_RESP &&
- action != WLAN_PA_GAS_COMEBACK_RESP)
- return -1; /* Not a GAS response */
-
query = gas_query_get_pending(gas, sa, dialog_token);
if (query == NULL) {
wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
@@ -684,7 +702,7 @@
GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
MACSTR, MAC2STR(query->addr));
- gas_query_free(query, 1);
+ gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
return;
}
gas->current = query;
@@ -714,6 +732,58 @@
}
+static int gas_query_set_sa(struct gas_query *gas,
+ struct gas_query_pending *query)
+{
+ struct wpa_supplicant *wpa_s = gas->wpa_s;
+ struct os_reltime now;
+
+ if (!wpa_s->conf->gas_rand_mac_addr ||
+ !(wpa_s->current_bss ?
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED) :
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA))) {
+ /* Use own MAC address as the transmitter address */
+ os_memcpy(query->sa, wpa_s->own_addr, ETH_ALEN);
+ return 0;
+ }
+
+ os_get_reltime(&now);
+
+ if (wpa_s->conf->gas_rand_mac_addr == gas->last_rand_sa_type &&
+ gas->last_mac_addr_rand.sec != 0 &&
+ !os_reltime_expired(&now, &gas->last_mac_addr_rand,
+ wpa_s->conf->gas_rand_addr_lifetime)) {
+ wpa_printf(MSG_DEBUG,
+ "GAS: Use the previously selected random transmitter address "
+ MACSTR, MAC2STR(gas->rand_addr));
+ os_memcpy(query->sa, gas->rand_addr, ETH_ALEN);
+ return 0;
+ }
+
+ if (wpa_s->conf->gas_rand_mac_addr == 1 &&
+ random_mac_addr(gas->rand_addr) < 0) {
+ wpa_printf(MSG_ERROR, "GAS: Failed to get random address");
+ return -1;
+ }
+
+ if (wpa_s->conf->gas_rand_mac_addr == 2 &&
+ random_mac_addr_keep_oui(gas->rand_addr) < 0) {
+ wpa_printf(MSG_ERROR,
+ "GAS: Failed to get random address with same OUI");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "GAS: Use a new random transmitter address "
+ MACSTR, MAC2STR(gas->rand_addr));
+ os_memcpy(query->sa, gas->rand_addr, ETH_ALEN);
+ os_get_reltime(&gas->last_mac_addr_rand);
+ gas->last_rand_sa_type = wpa_s->conf->gas_rand_mac_addr;
+
+ return 0;
+}
+
+
/**
* gas_query_req - Request a GAS query
* @gas: GAS query data from gas_query_init()
@@ -748,6 +818,10 @@
return -1;
query->gas = gas;
+ if (gas_query_set_sa(gas, query)) {
+ os_free(query);
+ return -1;
+ }
os_memcpy(query->addr, dst, ETH_ALEN);
query->dialog_token = dialog_token;
query->freq = freq;
@@ -764,26 +838,10 @@
if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb,
query) < 0) {
+ query->req = NULL; /* caller will free this in error case */
gas_query_free(query, 1);
return -1;
}
return dialog_token;
}
-
-
-/**
- * gas_query_cancel - Cancel a pending GAS query
- * @gas: GAS query data from gas_query_init()
- * @dst: Destination MAC address for the query
- * @dialog_token: Dialog token from gas_query_req()
- */
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
-{
- struct gas_query_pending *query;
-
- query = gas_query_get_pending(gas, dst, dialog_token);
- if (query)
- gas_query_done(gas, query, GAS_QUERY_CANCELLED);
-
-}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index ad13490..ef82097 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -29,7 +29,6 @@
GAS_QUERY_TIMEOUT,
GAS_QUERY_PEER_ERROR,
GAS_QUERY_INTERNAL_ERROR,
- GAS_QUERY_CANCELLED,
GAS_QUERY_DELETED_AT_DEINIT
};
@@ -40,7 +39,6 @@
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code),
void *ctx);
-void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token);
#else /* CONFIG_GAS */
diff --git a/wpa_supplicant/hidl/.clang-format b/wpa_supplicant/hidl/.clang-format
new file mode 100644
index 0000000..42fadb5
--- /dev/null
+++ b/wpa_supplicant/hidl/.clang-format
@@ -0,0 +1,9 @@
+BasedOnStyle: Google
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Mozilla
+AllowShortIfStatementsOnASingleLine: false
+IndentCaseLabels: false
+AccessModifierOffset: -8
+AlignAfterOpenBracket: AlwaysBreak
+SortIncludes: false
diff --git a/wpa_supplicant/hidl/1.0/hidl.cpp b/wpa_supplicant/hidl/1.0/hidl.cpp
new file mode 100644
index 0000000..e5f5303
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/hidl.cpp
@@ -0,0 +1,623 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <hwbinder/IPCThreadState.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include "hidl_manager.h"
+
+extern "C" {
+#include "hidl.h"
+#include "hidl_i.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
+}
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::IPCThreadState;
+using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager;
+
+void wpas_hidl_sock_handler(
+ int /* sock */, void * /* eloop_ctx */, void * /* sock_ctx */)
+{
+ IPCThreadState::self()->handlePolledCommands();
+}
+
+struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global)
+{
+ struct wpas_hidl_priv *priv;
+ HidlManager *hidl_manager;
+
+ priv = (wpas_hidl_priv *)os_zalloc(sizeof(*priv));
+ if (!priv)
+ return NULL;
+ priv->global = global;
+
+ wpa_printf(MSG_DEBUG, "Initing hidl control");
+
+ configureRpcThreadpool(1, true /* callerWillJoin */);
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+ IPCThreadState::self()->setupPolling(&priv->hidl_fd);
+ if (priv->hidl_fd < 0)
+ goto err;
+
+ wpa_printf(MSG_INFO, "Processing hidl events on FD %d", priv->hidl_fd);
+ // Look for read events from the hidl socket in the eloop.
+ if (eloop_register_read_sock(
+ priv->hidl_fd, wpas_hidl_sock_handler, global, priv) < 0)
+ goto err;
+
+ hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ goto err;
+ hidl_manager->registerHidlService(global);
+ // We may not need to store this hidl manager reference in the
+ // global data strucure because we've made it a singleton class.
+ priv->hidl_manager = (void *)hidl_manager;
+
+ return priv;
+err:
+ wpas_hidl_deinit(priv);
+ return NULL;
+}
+
+void wpas_hidl_deinit(struct wpas_hidl_priv *priv)
+{
+ if (!priv)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Deiniting hidl control");
+
+ HidlManager::destroyInstance();
+ eloop_unregister_read_sock(priv->hidl_fd);
+ IPCThreadState::shutdown();
+ os_free(priv);
+}
+
+int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s || !wpa_s->global->hidl)
+ return 1;
+
+ wpa_printf(
+ MSG_DEBUG, "Registering interface to hidl control: %s",
+ wpa_s->ifname);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return 1;
+
+ return hidl_manager->registerInterface(wpa_s);
+}
+
+int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s || !wpa_s->global->hidl)
+ return 1;
+
+ wpa_printf(
+ MSG_DEBUG, "Deregistering interface from hidl control: %s",
+ wpa_s->ifname);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return 1;
+
+ return hidl_manager->unregisterInterface(wpa_s);
+}
+
+int wpas_hidl_register_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !ssid)
+ return 1;
+
+ wpa_printf(
+ MSG_DEBUG, "Registering network to hidl control: %d", ssid->id);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return 1;
+
+ return hidl_manager->registerNetwork(wpa_s, ssid);
+}
+
+int wpas_hidl_unregister_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !ssid)
+ return 1;
+
+ wpa_printf(
+ MSG_DEBUG, "Deregistering network from hidl control: %d", ssid->id);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return 1;
+
+ return hidl_manager->unregisterNetwork(wpa_s, ssid);
+}
+
+int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s || !wpa_s->global->hidl)
+ return 1;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying state change event to hidl control: %d",
+ wpa_s->wpa_state);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return 1;
+
+ return hidl_manager->notifyStateChange(wpa_s);
+}
+
+int wpas_hidl_notify_network_request(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !ssid)
+ return 1;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying network request to hidl control: %d",
+ ssid->id);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return 1;
+
+ return hidl_manager->notifyNetworkRequest(
+ wpa_s, ssid, rtype, default_txt);
+}
+
+void wpas_hidl_notify_anqp_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+ const struct wpa_bss_anqp *anqp)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !bssid || !result || !anqp)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying ANQP query done to hidl control: " MACSTR "result: %s",
+ MAC2STR(bssid), result);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyAnqpQueryDone(wpa_s, bssid, result, anqp);
+}
+
+void wpas_hidl_notify_hs20_icon_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
+ const u8 *image, u32 image_length)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !bssid || !file_name || !image)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying HS20 icon query done to hidl control: " MACSTR
+ "file_name: %s",
+ MAC2STR(bssid), file_name);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyHs20IconQueryDone(
+ wpa_s, bssid, file_name, image, image_length);
+}
+
+void wpas_hidl_notify_hs20_rx_subscription_remediation(
+ struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !url)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying HS20 subscription remediation rx to hidl control: %s",
+ url);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyHs20RxSubscriptionRemediation(
+ wpa_s, url, osu_method);
+}
+
+void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
+ struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
+{
+ if (!wpa_s || !wpa_s->global->hidl || !url)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying HS20 deauth imminent notice rx to hidl control: %s",
+ url);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyHs20RxDeauthImminentNotice(
+ wpa_s, code, reauth_delay, url);
+}
+
+void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying disconnect reason to hidl control: %d",
+ wpa_s->disconnect_reason);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyDisconnectReason(wpa_s);
+}
+
+void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying assoc reject to hidl control: %d",
+ wpa_s->assoc_status_code);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyAssocReject(wpa_s);
+}
+
+void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying auth timeout to hidl control");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyAuthTimeout(wpa_s);
+}
+
+void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying bssid changed to hidl control");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyBssidChanged(wpa_s);
+}
+
+void wpas_hidl_notify_wps_event_fail(
+ struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
+ uint16_t error_indication)
+{
+ if (!wpa_s || !peer_macaddr)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying Wps event fail to hidl control: %d, %d",
+ config_error, error_indication);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyWpsEventFail(
+ wpa_s, peer_macaddr, config_error, error_indication);
+}
+
+void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying Wps event success to hidl control");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyWpsEventSuccess(wpa_s);
+}
+
+void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying Wps event PBC overlap to hidl control");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyWpsEventPbcOverlap(wpa_s);
+}
+
+void wpas_hidl_notify_p2p_device_found(
+ struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+ u8 peer_wfd_device_info_len)
+{
+ if (!wpa_s || !addr || !info)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying P2P device found to hidl control " MACSTR,
+ MAC2STR(info->p2p_device_addr));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pDeviceFound(
+ wpa_s, addr, info, peer_wfd_device_info, peer_wfd_device_info_len);
+}
+
+void wpas_hidl_notify_p2p_device_lost(
+ struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{
+ if (!wpa_s || !p2p_device_addr)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying P2P device lost to hidl control " MACSTR,
+ MAC2STR(p2p_device_addr));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pDeviceLost(wpa_s, p2p_device_addr);
+}
+
+void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying P2P find stop to hidl control");
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pFindStopped(wpa_s);
+}
+
+void wpas_hidl_notify_p2p_go_neg_req(
+ struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+ u8 go_intent)
+{
+ if (!wpa_s || !src_addr)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P GO negotiation request to hidl control " MACSTR,
+ MAC2STR(src_addr));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pGoNegReq(
+ wpa_s, src_addr, dev_passwd_id, go_intent);
+}
+
+void wpas_hidl_notify_p2p_go_neg_completed(
+ struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{
+ if (!wpa_s || !res)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P GO negotiation completed to hidl control: %d",
+ res->status);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pGoNegCompleted(wpa_s, res);
+}
+
+void wpas_hidl_notify_p2p_group_formation_failure(
+ struct wpa_supplicant *wpa_s, const char *reason)
+{
+ if (!wpa_s || !reason)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P Group formation failure to hidl control: %s",
+ reason);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pGroupFormationFailure(wpa_s, reason);
+}
+
+void wpas_hidl_notify_p2p_group_started(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+ int client)
+{
+ if (!wpa_s || !ssid)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying P2P Group start to hidl control: %d",
+ ssid->id);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pGroupStarted(wpa_s, ssid, persistent, client);
+}
+
+void wpas_hidl_notify_p2p_group_removed(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
+{
+ if (!wpa_s || !ssid || !role)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying P2P Group removed to hidl control: %d",
+ ssid->id);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pGroupRemoved(wpa_s, ssid, role);
+}
+
+void wpas_hidl_notify_p2p_invitation_received(
+ struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+ const u8 *bssid, int id, int op_freq)
+{
+ if (!wpa_s || !sa || !go_dev_addr || !bssid)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P invitation received to hidl control: %d " MACSTR, id,
+ MAC2STR(bssid));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pInvitationReceived(
+ wpa_s, sa, go_dev_addr, bssid, id, op_freq);
+}
+
+void wpas_hidl_notify_p2p_invitation_result(
+ struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{
+ if (!wpa_s || !bssid)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P invitation result to hidl control: " MACSTR,
+ MAC2STR(bssid));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pInvitationResult(wpa_s, status, bssid);
+}
+
+void wpas_hidl_notify_p2p_provision_discovery(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status, u16 config_methods,
+ unsigned int generated_pin)
+{
+ if (!wpa_s || !dev_addr)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P provision discovery to hidl control " MACSTR,
+ MAC2STR(dev_addr));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pProvisionDiscovery(
+ wpa_s, dev_addr, request, status, config_methods, generated_pin);
+}
+
+void wpas_hidl_notify_p2p_sd_response(
+ struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+ if (!wpa_s || !sa || !tlvs)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P service discovery response to hidl control " MACSTR,
+ MAC2STR(sa));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyP2pSdResponse(
+ wpa_s, sa, update_indic, tlvs, tlvs_len);
+}
+
+void wpas_hidl_notify_ap_sta_authorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+ if (!wpa_s || !sta)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P AP STA authorized to hidl control " MACSTR,
+ MAC2STR(sta));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyApStaAuthorized(wpa_s, sta, p2p_dev_addr);
+}
+
+void wpas_hidl_notify_ap_sta_deauthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+ if (!wpa_s || !sta)
+ return;
+
+ wpa_printf(
+ MSG_DEBUG,
+ "Notifying P2P AP STA deauthorized to hidl control " MACSTR,
+ MAC2STR(sta));
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager)
+ return;
+
+ hidl_manager->notifyApStaDeauthorized(wpa_s, sta, p2p_dev_addr);
+}
diff --git a/wpa_supplicant/hidl/1.0/hidl.h b/wpa_supplicant/hidl/1.0/hidl.h
new file mode 100644
index 0000000..96631f2
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/hidl.h
@@ -0,0 +1,221 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_HIDL_H
+#define WPA_SUPPLICANT_HIDL_HIDL_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif // _cplusplus
+
+/**
+ * This is the hidl RPC interface entry point to the wpa_supplicant core.
+ * This initializes the hidl driver & HidlManager instance and then forwards
+ * all the notifcations from the supplicant core to the HidlManager.
+ */
+struct wpas_hidl_priv;
+struct wpa_global;
+
+struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global);
+void wpas_hidl_deinit(struct wpas_hidl_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_HIDL
+int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s);
+int wpas_hidl_register_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_hidl_unregister_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s);
+int wpas_hidl_notify_network_request(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype, const char *default_txt);
+void wpas_hidl_notify_anqp_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+ const struct wpa_bss_anqp *anqp);
+void wpas_hidl_notify_hs20_icon_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
+ const u8 *image, u32 image_length);
+void wpas_hidl_notify_hs20_rx_subscription_remediation(
+ struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
+void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
+ struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url);
+void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_wps_event_fail(
+ struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
+ uint16_t error_indication);
+void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_p2p_device_found(
+ struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+ u8 peer_wfd_device_info_len);
+void wpas_hidl_notify_p2p_device_lost(
+ struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
+void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
+void wpas_hidl_notify_p2p_go_neg_req(
+ struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+ u8 go_intent);
+void wpas_hidl_notify_p2p_go_neg_completed(
+ struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
+void wpas_hidl_notify_p2p_group_formation_failure(
+ struct wpa_supplicant *wpa_s, const char *reason);
+void wpas_hidl_notify_p2p_group_started(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+ int client);
+void wpas_hidl_notify_p2p_group_removed(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid,
+ const char *role);
+void wpas_hidl_notify_p2p_invitation_received(
+ struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+ const u8 *bssid, int id, int op_freq);
+void wpas_hidl_notify_p2p_invitation_result(
+ struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
+void wpas_hidl_notify_p2p_provision_discovery(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status, u16 config_methods,
+ unsigned int generated_pin);
+void wpas_hidl_notify_p2p_sd_response(
+ struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len);
+void wpas_hidl_notify_ap_sta_authorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
+void wpas_hidl_notify_ap_sta_deauthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr);
+#else // CONFIG_CTRL_IFACE_HIDL
+static inline int wpas_hidl_register_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_hidl_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_hidl_register_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ return 0;
+}
+static inline int wpas_hidl_unregister_network(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ return 0;
+}
+static inline int wpas_hidl_notify_state_changed(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+static inline int wpas_hidl_notify_network_request(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+ return 0;
+}
+static void wpas_hidl_notify_anqp_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+ const struct wpa_bss_anqp *anqp)
+{
+}
+static void wpas_hidl_notify_hs20_icon_query_done(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
+ const u8 *image, u32 image_length)
+{
+}
+static void wpas_hidl_notify_hs20_rx_subscription_remediation(
+ struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
+{
+}
+static void wpas_hidl_notify_hs20_rx_deauth_imminent_notice(
+ struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
+{
+}
+static void wpas_hidl_notify_disconnect_reason(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_assoc_reject(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_auth_timeout(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_fail(
+ struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
+ uint16_t error_indication)
+{
+}
+static void wpas_hidl_notify_bssid_changed(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_success(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_wps_event_pbc_overlap(struct wpa_supplicant *wpa_s)
+{
+}
+static void wpas_hidl_notify_p2p_device_found(
+ struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+ u8 peer_wfd_device_info_len);
+{
+}
+static void wpas_hidl_notify_p2p_device_lost(
+ struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{
+}
+static void wpas_hidl_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s) {}
+static void wpas_hidl_notify_p2p_go_neg_req(
+ struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+ u8 go_intent)
+{
+}
+static void wpas_hidl_notify_p2p_go_neg_completed(
+ struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{
+}
+static void wpas_hidl_notify_p2p_group_formation_failure(
+ struct wpa_supplicant *wpa_s, const char *reason)
+{
+}
+static void wpas_hidl_notify_p2p_group_started(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, int persistent,
+ int client)
+{
+}
+static void wpas_hidl_notify_p2p_group_removed(
+ struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, const char *role)
+{
+}
+static void wpas_hidl_notify_p2p_invitation_received(
+ struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+ const u8 *bssid, int id, int op_freq)
+{
+}
+static void wpas_hidl_notify_p2p_invitation_result(
+ struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{
+}
+static void wpas_hidl_notify_p2p_provision_discovery(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status, u16 config_methods,
+ unsigned int generated_pin)
+{
+}
+static void wpas_hidl_notify_p2p_sd_response(
+ struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+}
+static void wpas_hidl_notify_ap_sta_authorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+}
+static void wpas_hidl_notify_ap_sta_deauthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+}
+#endif // CONFIG_CTRL_IFACE_HIDL
+
+#ifdef _cplusplus
+}
+#endif // _cplusplus
+
+#endif // WPA_SUPPLICANT_HIDL_HIDL_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_constants.h b/wpa_supplicant/hidl/1.0/hidl_constants.h
new file mode 100644
index 0000000..988a590
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/hidl_constants.h
@@ -0,0 +1,21 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H
+#define WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H
+
+namespace wpa_supplicant_hidl {
+namespace hidl_constants {
+
+extern const char kServiceName[];
+
+} /* namespace hidl_constants */
+} /* namespace wpa_supplicant_hidl */
+
+#endif /* WPA_SUPPLICANT_HIDL_HIDL_CONSTANTS_H */
diff --git a/wpa_supplicant/hidl/1.0/hidl_i.h b/wpa_supplicant/hidl/1.0/hidl_i.h
new file mode 100644
index 0000000..c7a0142
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/hidl_i.h
@@ -0,0 +1,28 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HIDL_I_H
+#define HIDL_I_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif // _cplusplus
+
+struct wpas_hidl_priv
+{
+ int hidl_fd;
+ struct wpa_global *global;
+ void *hidl_manager;
+};
+
+#ifdef _cplusplus
+}
+#endif // _cplusplus
+
+#endif // HIDL_I_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_manager.cpp b/wpa_supplicant/hidl/1.0/hidl_manager.cpp
new file mode 100644
index 0000000..72b53a4
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/hidl_manager.cpp
@@ -0,0 +1,1773 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <algorithm>
+#include <regex>
+
+#include "hidl_manager.h"
+#include "misc_utils.h"
+
+extern "C" {
+#include "src/eap_common/eap_sim_common.h"
+}
+
+namespace {
+using android::hardware::hidl_array;
+
+constexpr uint8_t kWfdDeviceInfoLen = 6;
+// GSM-AUTH:<RAND1>:<RAND2>[:<RAND3>]
+constexpr char kGsmAuthRegex2[] = "GSM-AUTH:([0-9a-f]+):([0-9a-f]+)";
+constexpr char kGsmAuthRegex3[] =
+ "GSM-AUTH:([0-9a-f]+):([0-9a-f]+):([0-9a-f]+)";
+// UMTS-AUTH:<RAND>:<AUTN>
+constexpr char kUmtsAuthRegex[] = "UMTS-AUTH:([0-9a-f]+):([0-9a-f]+)";
+constexpr size_t kGsmRandLenBytes = GSM_RAND_LEN;
+constexpr size_t kUmtsRandLenBytes = EAP_AKA_RAND_LEN;
+constexpr size_t kUmtsAutnLenBytes = EAP_AKA_AUTN_LEN;
+constexpr u8 kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
+/**
+ * Check if the provided |wpa_supplicant| structure represents a P2P iface or
+ * not.
+ */
+constexpr bool isP2pIface(const struct wpa_supplicant *wpa_s)
+{
+ return (wpa_s->global->p2p_init_wpa_s == wpa_s);
+}
+
+/**
+ * Creates a unique key for the network using the provided |ifname| and
+ * |network_id| to be used in the internal map of |ISupplicantNetwork| objects.
+ * This is of the form |ifname|_|network_id|. For ex: "wlan0_1".
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ */
+const std::string getNetworkObjectMapKey(
+ const std::string &ifname, int network_id)
+{
+ return ifname + "_" + std::to_string(network_id);
+}
+
+/**
+ * Add callback to the corresponding list after linking to death on the
+ * corresponding hidl object reference.
+ */
+template <class CallbackType>
+int registerForDeathAndAddCallbackHidlObjectToList(
+ const android::sp<CallbackType> &callback,
+ const std::function<void(const android::sp<CallbackType> &)>
+ &on_hidl_died_fctor,
+ std::vector<android::sp<CallbackType>> &callback_list)
+{
+#if 0 // TODO(b/31632518): HIDL object death notifications.
+ auto death_notifier = new CallbackObjectDeathNotifier<CallbackType>(
+ callback, on_hidl_died_fctor);
+ // Use the |callback.get()| as cookie so that we don't need to
+ // store a reference to this |CallbackObjectDeathNotifier| instance
+ // to use in |unlinkToDeath| later.
+ // NOTE: This may cause an immediate callback if the object is already
+ // dead, so add it to the list before we register for callback!
+ if (android::hardware::IInterface::asBinder(callback)->linkToDeath(
+ death_notifier, callback.get()) != android::OK) {
+ wpa_printf(
+ MSG_ERROR,
+ "Error registering for death notification for "
+ "supplicant callback object");
+ callback_list.erase(
+ std::remove(
+ callback_list.begin(), callback_list.end(), callback),
+ callback_list.end());
+ return 1;
+ }
+#endif // TODO(b/31632518): HIDL object death notifications.
+ callback_list.push_back(callback);
+ return 0;
+}
+
+template <class ObjectType>
+int addHidlObjectToMap(
+ const std::string &key, const android::sp<ObjectType> object,
+ std::map<const std::string, android::sp<ObjectType>> &object_map)
+{
+ // Return failure if we already have an object for that |key|.
+ if (object_map.find(key) != object_map.end())
+ return 1;
+ object_map[key] = object;
+ if (!object_map[key].get())
+ return 1;
+ return 0;
+}
+
+template <class ObjectType>
+int removeHidlObjectFromMap(
+ const std::string &key,
+ std::map<const std::string, android::sp<ObjectType>> &object_map)
+{
+ // Return failure if we dont have an object for that |key|.
+ const auto &object_iter = object_map.find(key);
+ if (object_iter == object_map.end())
+ return 1;
+ object_iter->second->invalidate();
+ object_map.erase(object_iter);
+ return 0;
+}
+
+template <class CallbackType>
+int addIfaceCallbackHidlObjectToMap(
+ const std::string &ifname, const android::sp<CallbackType> &callback,
+ const std::function<void(const android::sp<CallbackType> &)>
+ &on_hidl_died_fctor,
+ std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ if (ifname.empty())
+ return 1;
+
+ auto iface_callback_map_iter = callbacks_map.find(ifname);
+ if (iface_callback_map_iter == callbacks_map.end())
+ return 1;
+ auto &iface_callback_list = iface_callback_map_iter->second;
+
+ // Register for death notification before we add it to our list.
+ return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
+ callback, on_hidl_died_fctor, iface_callback_list);
+}
+
+template <class CallbackType>
+int addNetworkCallbackHidlObjectToMap(
+ const std::string &ifname, int network_id,
+ const android::sp<CallbackType> &callback,
+ const std::function<void(const android::sp<CallbackType> &)>
+ &on_hidl_died_fctor,
+ std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ if (ifname.empty() || network_id < 0)
+ return 1;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+ auto network_callback_map_iter = callbacks_map.find(network_key);
+ if (network_callback_map_iter == callbacks_map.end())
+ return 1;
+ auto &network_callback_list = network_callback_map_iter->second;
+
+ // Register for death notification before we add it to our list.
+ return registerForDeathAndAddCallbackHidlObjectToList<CallbackType>(
+ callback, on_hidl_died_fctor, network_callback_list);
+}
+
+template <class CallbackType>
+int removeAllIfaceCallbackHidlObjectsFromMap(
+ const std::string &ifname,
+ std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ auto iface_callback_map_iter = callbacks_map.find(ifname);
+ if (iface_callback_map_iter == callbacks_map.end())
+ return 1;
+#if 0 // TODO(b/31632518): HIDL object death notifications.
+ const auto &iface_callback_list = iface_callback_map_iter->second;
+ for (const auto &callback : iface_callback_list) {
+ if (android::hardware::IInterface::asBinder(callback)
+ ->unlinkToDeath(nullptr, callback.get()) !=
+ android::OK) {
+ wpa_printf(
+ MSG_ERROR,
+ "Error deregistering for death notification for "
+ "iface callback object");
+ }
+ }
+#endif // TODO(b/31632518): HIDL object death notifications.
+ callbacks_map.erase(iface_callback_map_iter);
+ return 0;
+}
+
+template <class CallbackType>
+int removeAllNetworkCallbackHidlObjectsFromMap(
+ const std::string &network_key,
+ std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ auto network_callback_map_iter = callbacks_map.find(network_key);
+ if (network_callback_map_iter == callbacks_map.end())
+ return 1;
+#if 0 // TODO(b/31632518): HIDL object death notifications.
+ const auto &network_callback_list = network_callback_map_iter->second;
+ for (const auto &callback : network_callback_list) {
+ if (android::hardware::IInterface::asBinder(callback)
+ ->unlinkToDeath(nullptr, callback.get()) !=
+ android::OK) {
+ wpa_printf(
+ MSG_ERROR,
+ "Error deregistering for death "
+ "notification for "
+ "network callback object");
+ }
+ }
+#endif // TODO(b/31632518): HIDL object death notifications.
+ callbacks_map.erase(network_callback_map_iter);
+ return 0;
+}
+
+template <class CallbackType>
+void removeIfaceCallbackHidlObjectFromMap(
+ const std::string &ifname, const android::sp<CallbackType> &callback,
+ std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ if (ifname.empty())
+ return;
+
+ auto iface_callback_map_iter = callbacks_map.find(ifname);
+ if (iface_callback_map_iter == callbacks_map.end())
+ return;
+
+ auto &iface_callback_list = iface_callback_map_iter->second;
+ iface_callback_list.erase(
+ std::remove(
+ iface_callback_list.begin(), iface_callback_list.end(),
+ callback),
+ iface_callback_list.end());
+}
+
+template <class CallbackType>
+void removeNetworkCallbackHidlObjectFromMap(
+ const std::string &ifname, int network_id,
+ const android::sp<CallbackType> &callback,
+ std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ if (ifname.empty() || network_id < 0)
+ return;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+
+ auto network_callback_map_iter = callbacks_map.find(network_key);
+ if (network_callback_map_iter == callbacks_map.end())
+ return;
+
+ auto &network_callback_list = network_callback_map_iter->second;
+ network_callback_list.erase(
+ std::remove(
+ network_callback_list.begin(), network_callback_list.end(),
+ callback),
+ network_callback_list.end());
+}
+
+template <class CallbackType>
+void callWithEachIfaceCallback(
+ const std::string &ifname,
+ const std::function<
+ android::hardware::Return<void>(android::sp<CallbackType>)> &method,
+ const std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ if (ifname.empty())
+ return;
+
+ auto iface_callback_map_iter = callbacks_map.find(ifname);
+ if (iface_callback_map_iter == callbacks_map.end())
+ return;
+ const auto &iface_callback_list = iface_callback_map_iter->second;
+ for (const auto &callback : iface_callback_list) {
+ if (!method(callback).isOk()) {
+ wpa_printf(
+ MSG_ERROR, "Failed to invoke HIDL iface callback");
+ }
+ }
+}
+
+template <class CallbackType>
+void callWithEachNetworkCallback(
+ const std::string &ifname, int network_id,
+ const std::function<
+ android::hardware::Return<void>(android::sp<CallbackType>)> &method,
+ const std::map<const std::string, std::vector<android::sp<CallbackType>>>
+ &callbacks_map)
+{
+ if (ifname.empty() || network_id < 0)
+ return;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+ auto network_callback_map_iter = callbacks_map.find(network_key);
+ if (network_callback_map_iter == callbacks_map.end())
+ return;
+ const auto &network_callback_list = network_callback_map_iter->second;
+ for (const auto &callback : network_callback_list) {
+ if (!method(callback).isOk()) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to invoke HIDL network callback");
+ }
+ }
+}
+
+int parseGsmAuthNetworkRequest(
+ const std::string ¶ms_str,
+ std::vector<hidl_array<uint8_t, kGsmRandLenBytes>> *out_rands)
+{
+ std::smatch matches;
+ std::regex params_gsm_regex2(kGsmAuthRegex2);
+ std::regex params_gsm_regex3(kGsmAuthRegex3);
+ if (!std::regex_match(params_str, matches, params_gsm_regex3) &&
+ !std::regex_match(params_str, matches, params_gsm_regex2)) {
+ return 1;
+ }
+ for (uint32_t i = 1; i < matches.size(); i++) {
+ hidl_array<uint8_t, kGsmRandLenBytes> rand;
+ const auto &match = matches[i];
+ WPA_ASSERT(match.size() >= 2 * rand.size());
+ if (hexstr2bin(match.str().c_str(), rand.data(), rand.size())) {
+ wpa_printf(
+ MSG_ERROR, "Failed to parse GSM auth params");
+ return 1;
+ }
+ out_rands->push_back(rand);
+ }
+ return 0;
+}
+
+int parseUmtsAuthNetworkRequest(
+ const std::string ¶ms_str,
+ hidl_array<uint8_t, kUmtsRandLenBytes> *out_rand,
+ hidl_array<uint8_t, kUmtsAutnLenBytes> *out_autn)
+{
+ std::smatch matches;
+ std::regex params_umts_regex(kUmtsAuthRegex);
+ if (!std::regex_match(params_str, matches, params_umts_regex)) {
+ return 1;
+ }
+ WPA_ASSERT(matches[1].size() >= 2 * out_rand->size());
+ if (hexstr2bin(
+ matches[1].str().c_str(), out_rand->data(), out_rand->size())) {
+ wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
+ return 1;
+ }
+ WPA_ASSERT(matches[2].size() >= 2 * out_autn->size());
+ if (hexstr2bin(
+ matches[2].str().c_str(), out_autn->data(), out_autn->size())) {
+ wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params");
+ return 1;
+ }
+ return 0;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+
+HidlManager *HidlManager::instance_ = NULL;
+
+HidlManager *HidlManager::getInstance()
+{
+ if (!instance_)
+ instance_ = new HidlManager();
+ return instance_;
+}
+
+void HidlManager::destroyInstance()
+{
+ if (instance_)
+ delete instance_;
+ instance_ = NULL;
+}
+
+int HidlManager::registerHidlService(struct wpa_global *global)
+{
+ // Create the main hidl service object and register it.
+ supplicant_object_ = new Supplicant(global);
+ if (supplicant_object_->registerAsService() != android::NO_ERROR) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Register an interface to hidl manager.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::registerInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return 1;
+
+ if (isP2pIface(wpa_s)) {
+ if (addHidlObjectToMap<P2pIface>(
+ wpa_s->ifname,
+ new P2pIface(wpa_s->global, wpa_s->ifname),
+ p2p_iface_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to register P2P interface with HIDL "
+ "control: %s",
+ wpa_s->ifname);
+ return 1;
+ }
+ p2p_iface_callbacks_map_[wpa_s->ifname] =
+ std::vector<android::sp<ISupplicantP2pIfaceCallback>>();
+ } else {
+ if (addHidlObjectToMap<StaIface>(
+ wpa_s->ifname,
+ new StaIface(wpa_s->global, wpa_s->ifname),
+ sta_iface_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to register STA interface with HIDL "
+ "control: %s",
+ wpa_s->ifname);
+ return 1;
+ }
+ sta_iface_callbacks_map_[wpa_s->ifname] =
+ std::vector<android::sp<ISupplicantStaIfaceCallback>>();
+ }
+
+ // Invoke the |onInterfaceCreated| method on all registered callbacks.
+ callWithEachSupplicantCallback(std::bind(
+ &ISupplicantCallback::onInterfaceCreated, std::placeholders::_1,
+ wpa_s->ifname));
+ return 0;
+}
+
+/**
+ * Unregister an interface from hidl manager.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::unregisterInterface(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return 1;
+
+ if (isP2pIface(wpa_s)) {
+ if (removeHidlObjectFromMap(
+ wpa_s->ifname, p2p_iface_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to unregister P2P interface with HIDL "
+ "control: %s",
+ wpa_s->ifname);
+ return 1;
+ }
+ if (removeAllIfaceCallbackHidlObjectsFromMap(
+ wpa_s->ifname, p2p_iface_callbacks_map_)) {
+ return 1;
+ }
+ } else {
+ if (removeHidlObjectFromMap(
+ wpa_s->ifname, sta_iface_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to unregister STA interface with HIDL "
+ "control: %s",
+ wpa_s->ifname);
+ return 1;
+ }
+ if (removeAllIfaceCallbackHidlObjectsFromMap(
+ wpa_s->ifname, sta_iface_callbacks_map_)) {
+ return 1;
+ }
+ }
+
+ // Invoke the |onInterfaceRemoved| method on all registered callbacks.
+ callWithEachSupplicantCallback(std::bind(
+ &ISupplicantCallback::onInterfaceRemoved, std::placeholders::_1,
+ wpa_s->ifname));
+ return 0;
+}
+
+/**
+ * Register a network to hidl manager.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is added.
+ * @param ssid |wpa_ssid| struct corresponding to the network being added.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::registerNetwork(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ if (!wpa_s || !ssid)
+ return 1;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
+
+ if (isP2pIface(wpa_s)) {
+ if (addHidlObjectToMap<P2pNetwork>(
+ network_key,
+ new P2pNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
+ p2p_network_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to register P2P network with HIDL "
+ "control: %d",
+ ssid->id);
+ return 1;
+ }
+ p2p_network_callbacks_map_[network_key] =
+ std::vector<android::sp<ISupplicantP2pNetworkCallback>>();
+ // Invoke the |onNetworkAdded| method on all registered
+ // callbacks.
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onNetworkAdded,
+ std::placeholders::_1, ssid->id));
+ } else {
+ if (addHidlObjectToMap<StaNetwork>(
+ network_key,
+ new StaNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
+ sta_network_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to register STA network with HIDL "
+ "control: %d",
+ ssid->id);
+ return 1;
+ }
+ sta_network_callbacks_map_[network_key] =
+ std::vector<android::sp<ISupplicantStaNetworkCallback>>();
+ // Invoke the |onNetworkAdded| method on all registered
+ // callbacks.
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onNetworkAdded,
+ std::placeholders::_1, ssid->id));
+ }
+ return 0;
+}
+
+/**
+ * Unregister a network from hidl manager.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is added.
+ * @param ssid |wpa_ssid| struct corresponding to the network being added.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::unregisterNetwork(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ if (!wpa_s || !ssid)
+ return 1;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
+
+ if (isP2pIface(wpa_s)) {
+ if (removeHidlObjectFromMap(
+ network_key, p2p_network_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to unregister P2P network with HIDL "
+ "control: %d",
+ ssid->id);
+ return 1;
+ }
+ if (removeAllNetworkCallbackHidlObjectsFromMap(
+ network_key, p2p_network_callbacks_map_))
+ return 1;
+
+ // Invoke the |onNetworkRemoved| method on all registered
+ // callbacks.
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onNetworkRemoved,
+ std::placeholders::_1, ssid->id));
+ } else {
+ if (removeHidlObjectFromMap(
+ network_key, sta_network_object_map_)) {
+ wpa_printf(
+ MSG_ERROR,
+ "Failed to unregister STA network with HIDL "
+ "control: %d",
+ ssid->id);
+ return 1;
+ }
+ if (removeAllNetworkCallbackHidlObjectsFromMap(
+ network_key, sta_network_callbacks_map_))
+ return 1;
+
+ // Invoke the |onNetworkRemoved| method on all registered
+ // callbacks.
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onNetworkRemoved,
+ std::placeholders::_1, ssid->id));
+ }
+ return 0;
+}
+
+/**
+ * Notify all listeners about any state changes on a particular interface.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the state change event occured.
+ */
+int HidlManager::notifyStateChange(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return 1;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return 1;
+
+ // Invoke the |onStateChanged| method on all registered callbacks.
+ uint32_t hidl_network_id = UINT32_MAX;
+ std::vector<uint8_t> hidl_ssid;
+ if (wpa_s->current_ssid) {
+ hidl_network_id = wpa_s->current_ssid->id;
+ hidl_ssid.assign(
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
+ }
+ uint8_t *bssid;
+ // wpa_supplicant sets the |pending_bssid| field when it starts a
+ // connection. Only after association state does it update the |bssid|
+ // field. So, in the HIDL callback send the appropriate bssid.
+ if (wpa_s->wpa_state <= WPA_ASSOCIATED) {
+ bssid = wpa_s->pending_bssid;
+ } else {
+ bssid = wpa_s->bssid;
+ }
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname, std::bind(
+ &ISupplicantStaIfaceCallback::onStateChanged,
+ std::placeholders::_1,
+ static_cast<ISupplicantStaIfaceCallback::State>(
+ wpa_s->wpa_state),
+ bssid, hidl_network_id, hidl_ssid));
+ return 0;
+}
+
+/**
+ * Notify all listeners about a request on a particular network.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is present.
+ * @param ssid |wpa_ssid| struct corresponding to the network.
+ * @param type type of request.
+ * @param param addition params associated with the request.
+ */
+int HidlManager::notifyNetworkRequest(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
+ const char *param)
+{
+ if (!wpa_s || !ssid)
+ return 1;
+
+ const std::string network_key =
+ getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
+ if (sta_network_object_map_.find(network_key) ==
+ sta_network_object_map_.end())
+ return 1;
+
+ if (type == WPA_CTRL_REQ_EAP_IDENTITY) {
+ callWithEachStaNetworkCallback(
+ wpa_s->ifname, ssid->id,
+ std::bind(
+ &ISupplicantStaNetworkCallback::
+ onNetworkEapIdentityRequest,
+ std::placeholders::_1));
+ return 0;
+ }
+ if (type == WPA_CTRL_REQ_SIM) {
+ std::vector<hidl_array<uint8_t, 16>> gsm_rands;
+ hidl_array<uint8_t, 16> umts_rand;
+ hidl_array<uint8_t, 16> umts_autn;
+ if (!parseGsmAuthNetworkRequest(param, &gsm_rands)) {
+ ISupplicantStaNetworkCallback::
+ NetworkRequestEapSimGsmAuthParams hidl_params;
+ hidl_params.rands = gsm_rands;
+ callWithEachStaNetworkCallback(
+ wpa_s->ifname, ssid->id,
+ std::bind(
+ &ISupplicantStaNetworkCallback::
+ onNetworkEapSimGsmAuthRequest,
+ std::placeholders::_1, hidl_params));
+ return 0;
+ }
+ if (!parseUmtsAuthNetworkRequest(
+ param, &umts_rand, &umts_autn)) {
+ ISupplicantStaNetworkCallback::
+ NetworkRequestEapSimUmtsAuthParams hidl_params;
+ hidl_params.rand = umts_rand;
+ hidl_params.autn = umts_autn;
+ callWithEachStaNetworkCallback(
+ wpa_s->ifname, ssid->id,
+ std::bind(
+ &ISupplicantStaNetworkCallback::
+ onNetworkEapSimUmtsAuthRequest,
+ std::placeholders::_1, hidl_params));
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**
+ * Notify all listeners about the end of an ANQP query.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ * @param bssid BSSID of the access point.
+ * @param result Result of the operation ("SUCCESS" or "FAILURE").
+ * @param anqp |wpa_bss_anqp| ANQP data fetched.
+ */
+void HidlManager::notifyAnqpQueryDone(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+ const struct wpa_bss_anqp *anqp)
+{
+ if (!wpa_s || !bssid || !result || !anqp)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ ISupplicantStaIfaceCallback::AnqpData hidl_anqp_data;
+ ISupplicantStaIfaceCallback::Hs20AnqpData hidl_hs20_anqp_data;
+ if (std::string(result) == "SUCCESS") {
+ hidl_anqp_data.venueName =
+ misc_utils::convertWpaBufToVector(anqp->venue_name);
+ hidl_anqp_data.roamingConsortium =
+ misc_utils::convertWpaBufToVector(anqp->roaming_consortium);
+ hidl_anqp_data.ipAddrTypeAvailability =
+ misc_utils::convertWpaBufToVector(
+ anqp->ip_addr_type_availability);
+ hidl_anqp_data.naiRealm =
+ misc_utils::convertWpaBufToVector(anqp->nai_realm);
+ hidl_anqp_data.anqp3gppCellularNetwork =
+ misc_utils::convertWpaBufToVector(anqp->anqp_3gpp);
+ hidl_anqp_data.domainName =
+ misc_utils::convertWpaBufToVector(anqp->domain_name);
+
+ hidl_hs20_anqp_data.operatorFriendlyName =
+ misc_utils::convertWpaBufToVector(
+ anqp->hs20_operator_friendly_name);
+ hidl_hs20_anqp_data.wanMetrics =
+ misc_utils::convertWpaBufToVector(anqp->hs20_wan_metrics);
+ hidl_hs20_anqp_data.connectionCapability =
+ misc_utils::convertWpaBufToVector(
+ anqp->hs20_connection_capability);
+ hidl_hs20_anqp_data.osuProvidersList =
+ misc_utils::convertWpaBufToVector(
+ anqp->hs20_osu_providers_list);
+ }
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname, std::bind(
+ &ISupplicantStaIfaceCallback::onAnqpQueryDone,
+ std::placeholders::_1, bssid, hidl_anqp_data,
+ hidl_hs20_anqp_data));
+}
+
+/**
+ * Notify all listeners about the end of an HS20 icon query.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ * @param bssid BSSID of the access point.
+ * @param file_name Name of the icon file.
+ * @param image Raw bytes of the icon file.
+ * @param image_length Size of the the icon file.
+ */
+void HidlManager::notifyHs20IconQueryDone(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name,
+ const u8 *image, u32 image_length)
+{
+ if (!wpa_s || !bssid || !file_name || !image)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onHs20IconQueryDone,
+ std::placeholders::_1, bssid, file_name,
+ std::vector<uint8_t>(image, image + image_length)));
+}
+
+/**
+ * Notify all listeners about the reception of HS20 subscription
+ * remediation notification from the server.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ * @param url URL of the server.
+ * @param osu_method OSU method (OMA_DM or SOAP_XML_SPP).
+ */
+void HidlManager::notifyHs20RxSubscriptionRemediation(
+ struct wpa_supplicant *wpa_s, const char *url, u8 osu_method)
+{
+ if (!wpa_s || !url)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ ISupplicantStaIfaceCallback::OsuMethod hidl_osu_method = {};
+ if (osu_method & 0x1) {
+ hidl_osu_method =
+ ISupplicantStaIfaceCallback::OsuMethod::OMA_DM;
+ } else if (osu_method & 0x2) {
+ hidl_osu_method =
+ ISupplicantStaIfaceCallback::OsuMethod::SOAP_XML_SPP;
+ }
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onHs20SubscriptionRemediation,
+ std::placeholders::_1, wpa_s->bssid, hidl_osu_method, url));
+}
+
+/**
+ * Notify all listeners about the reception of HS20 immient deauth
+ * notification from the server.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface.
+ * @param code Deauth reason code sent from server.
+ * @param reauth_delay Reauthentication delay in seconds sent from server.
+ * @param url URL of the server.
+ */
+void HidlManager::notifyHs20RxDeauthImminentNotice(
+ struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url)
+{
+ if (!wpa_s || !url)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onHs20DeauthImminentNotice,
+ std::placeholders::_1, wpa_s->bssid, code, reauth_delay, url));
+}
+
+/**
+ * Notify all listeners about the reason code for disconnection from the
+ * currently connected network.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is present.
+ */
+void HidlManager::notifyDisconnectReason(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ const u8 *bssid = wpa_s->bssid;
+ if (is_zero_ether_addr(bssid)) {
+ bssid = wpa_s->pending_bssid;
+ }
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onDisconnected,
+ std::placeholders::_1, bssid, wpa_s->disconnect_reason < 0,
+ static_cast<ISupplicantStaIfaceCallback::ReasonCode>(
+ wpa_s->disconnect_reason)));
+}
+
+/**
+ * Notify all listeners about association reject from the access point to which
+ * we are attempting to connect.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is present.
+ */
+void HidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ const u8 *bssid = wpa_s->bssid;
+ if (is_zero_ether_addr(bssid)) {
+ bssid = wpa_s->pending_bssid;
+ }
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onAssociationRejected,
+ std::placeholders::_1, bssid,
+ static_cast<ISupplicantStaIfaceCallback::StatusCode>(
+ wpa_s->assoc_status_code),
+ wpa_s->assoc_timed_out == 1));
+}
+
+void HidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ const std::string ifname(wpa_s->ifname);
+ if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+ return;
+
+ const u8 *bssid = wpa_s->bssid;
+ if (is_zero_ether_addr(bssid)) {
+ bssid = wpa_s->pending_bssid;
+ }
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onAuthenticationTimeout,
+ std::placeholders::_1, bssid));
+}
+
+void HidlManager::notifyBssidChanged(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ const std::string ifname(wpa_s->ifname);
+ if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end())
+ return;
+
+ // wpa_supplicant does not explicitly give us the reason for bssid
+ // change, but we figure that out from what is set out of |wpa_s->bssid|
+ // & |wpa_s->pending_bssid|.
+ const u8 *bssid;
+ ISupplicantStaIfaceCallback::BssidChangeReason reason;
+ if (is_zero_ether_addr(wpa_s->bssid) &&
+ !is_zero_ether_addr(wpa_s->pending_bssid)) {
+ bssid = wpa_s->pending_bssid;
+ reason =
+ ISupplicantStaIfaceCallback::BssidChangeReason::ASSOC_START;
+ } else if (
+ !is_zero_ether_addr(wpa_s->bssid) &&
+ is_zero_ether_addr(wpa_s->pending_bssid)) {
+ bssid = wpa_s->bssid;
+ reason = ISupplicantStaIfaceCallback::BssidChangeReason::
+ ASSOC_COMPLETE;
+ } else if (
+ is_zero_ether_addr(wpa_s->bssid) &&
+ is_zero_ether_addr(wpa_s->pending_bssid)) {
+ bssid = wpa_s->pending_bssid;
+ reason =
+ ISupplicantStaIfaceCallback::BssidChangeReason::DISASSOC;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown bssid change reason");
+ return;
+ }
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname, std::bind(
+ &ISupplicantStaIfaceCallback::onBssidChanged,
+ std::placeholders::_1, reason, bssid));
+}
+
+void HidlManager::notifyWpsEventFail(
+ struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error,
+ uint16_t error_indication)
+{
+ if (!wpa_s || !peer_macaddr)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onWpsEventFail,
+ std::placeholders::_1, peer_macaddr,
+ static_cast<ISupplicantStaIfaceCallback::WpsConfigError>(
+ config_error),
+ static_cast<ISupplicantStaIfaceCallback::WpsErrorIndication>(
+ error_indication)));
+}
+
+void HidlManager::notifyWpsEventSuccess(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname, std::bind(
+ &ISupplicantStaIfaceCallback::onWpsEventSuccess,
+ std::placeholders::_1));
+}
+
+void HidlManager::notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onWpsEventPbcOverlap,
+ std::placeholders::_1));
+}
+
+void HidlManager::notifyP2pDeviceFound(
+ struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+ u8 peer_wfd_device_info_len)
+{
+ if (!wpa_s || !addr || !info)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ std::array<uint8_t, kWfdDeviceInfoLen> hidl_peer_wfd_device_info{};
+ if (peer_wfd_device_info) {
+ if (peer_wfd_device_info_len != kWfdDeviceInfoLen) {
+ wpa_printf(
+ MSG_ERROR, "Unexpected WFD device info len: %d",
+ peer_wfd_device_info_len);
+ } else {
+ os_memcpy(
+ hidl_peer_wfd_device_info.data(),
+ peer_wfd_device_info, kWfdDeviceInfoLen);
+ }
+ }
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onDeviceFound,
+ std::placeholders::_1, addr, info->p2p_device_addr,
+ info->pri_dev_type, info->device_name, info->config_methods,
+ info->dev_capab, info->group_capab, hidl_peer_wfd_device_info));
+}
+
+void HidlManager::notifyP2pDeviceLost(
+ struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr)
+{
+ if (!wpa_s || !p2p_device_addr)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname, std::bind(
+ &ISupplicantP2pIfaceCallback::onDeviceLost,
+ std::placeholders::_1, p2p_device_addr));
+}
+
+void HidlManager::notifyP2pFindStopped(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname, std::bind(
+ &ISupplicantP2pIfaceCallback::onFindStopped,
+ std::placeholders::_1));
+}
+
+void HidlManager::notifyP2pGoNegReq(
+ struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+ u8 /* go_intent */)
+{
+ if (!wpa_s || !src_addr)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onGoNegotiationRequest,
+ std::placeholders::_1, src_addr,
+ static_cast<ISupplicantP2pIfaceCallback::WpsDevPasswordId>(
+ dev_passwd_id)));
+}
+
+void HidlManager::notifyP2pGoNegCompleted(
+ struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res)
+{
+ if (!wpa_s || !res)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onGoNegotiationCompleted,
+ std::placeholders::_1,
+ static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
+ res->status)));
+}
+
+void HidlManager::notifyP2pGroupFormationFailure(
+ struct wpa_supplicant *wpa_s, const char *reason)
+{
+ if (!wpa_s || !reason)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onGroupFormationFailure,
+ std::placeholders::_1, reason));
+}
+
+void HidlManager::notifyP2pGroupStarted(
+ struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid, int persistent, int client)
+{
+ if (!wpa_group_s || !wpa_group_s->parent || !ssid)
+ return;
+
+ // For group notifications, need to use the parent iface for callbacks.
+ struct wpa_supplicant *wpa_s = wpa_group_s->parent;
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ uint32_t hidl_freq = wpa_group_s->current_bss
+ ? wpa_group_s->current_bss->freq
+ : wpa_group_s->assoc_freq;
+ std::array<uint8_t, 32> hidl_psk;
+ if (ssid->psk_set) {
+ os_memcpy(hidl_psk.data(), ssid->psk, 32);
+ }
+ bool hidl_is_go = (client == 0 ? true : false);
+ bool hidl_is_persistent = (persistent == 1 ? true : false);
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onGroupStarted,
+ std::placeholders::_1, wpa_group_s->ifname, hidl_is_go,
+ std::vector<uint8_t>{ssid->ssid, ssid->ssid + ssid->ssid_len},
+ hidl_freq, hidl_psk, ssid->passphrase, wpa_group_s->go_dev_addr,
+ hidl_is_persistent));
+}
+
+void HidlManager::notifyP2pGroupRemoved(
+ struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+ const char *role)
+{
+ if (!wpa_group_s || !wpa_group_s->parent || !ssid || !role)
+ return;
+
+ // For group notifications, need to use the parent iface for callbacks.
+ struct wpa_supplicant *wpa_s = wpa_group_s->parent;
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ bool hidl_is_go = (std::string(role) == "GO");
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onGroupRemoved,
+ std::placeholders::_1, wpa_group_s->ifname, hidl_is_go));
+}
+
+void HidlManager::notifyP2pInvitationReceived(
+ struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+ const u8 *bssid, int id, int op_freq)
+{
+ if (!wpa_s || !sa || !go_dev_addr || !bssid)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ SupplicantNetworkId hidl_network_id;
+ if (id < 0) {
+ hidl_network_id = UINT32_MAX;
+ }
+ hidl_network_id = id;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onInvitationReceived,
+ std::placeholders::_1, sa, go_dev_addr, bssid, hidl_network_id,
+ op_freq));
+}
+
+void HidlManager::notifyP2pInvitationResult(
+ struct wpa_supplicant *wpa_s, int status, const u8 *bssid)
+{
+ if (!wpa_s || !bssid)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onInvitationResult,
+ std::placeholders::_1, bssid,
+ static_cast<ISupplicantP2pIfaceCallback::P2pStatusCode>(
+ status)));
+}
+
+void HidlManager::notifyP2pProvisionDiscovery(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status, u16 config_methods,
+ unsigned int generated_pin)
+{
+ if (!wpa_s || !dev_addr)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ std::string hidl_generated_pin;
+ if (generated_pin > 0) {
+ hidl_generated_pin =
+ misc_utils::convertWpsPinToString(generated_pin);
+ }
+ bool hidl_is_request = (request == 1 ? true : false);
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompleted,
+ std::placeholders::_1, dev_addr, hidl_is_request,
+ static_cast<ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode>(
+ status),
+ config_methods, hidl_generated_pin));
+}
+
+void HidlManager::notifyP2pSdResponse(
+ struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len)
+{
+ if (!wpa_s || !sa || !tlvs)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onServiceDiscoveryResponse,
+ std::placeholders::_1, sa, update_indic,
+ std::vector<uint8_t>{tlvs, tlvs + tlvs_len}));
+}
+
+void HidlManager::notifyApStaAuthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+ if (!wpa_s || !wpa_s->parent || !sta)
+ return;
+ if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+ callWithEachP2pIfaceCallback(
+ wpa_s->parent->ifname, std::bind(
+ &ISupplicantP2pIfaceCallback::onStaAuthorized,
+ std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
+}
+
+void HidlManager::notifyApStaDeauthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta, const u8 *p2p_dev_addr)
+{
+ if (!wpa_s || !wpa_s->parent || !sta)
+ return;
+ if (p2p_iface_object_map_.find(wpa_s->parent->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ callWithEachP2pIfaceCallback(
+ wpa_s->parent->ifname, std::bind(
+ &ISupplicantP2pIfaceCallback::onStaDeauthorized,
+ std::placeholders::_1, sta, p2p_dev_addr ? p2p_dev_addr : kZeroBssid));
+}
+
+void HidlManager::notifyExtRadioWorkStart(
+ struct wpa_supplicant *wpa_s, uint32_t id)
+{
+ if (!wpa_s)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onExtRadioWorkStart,
+ std::placeholders::_1, id));
+}
+
+void HidlManager::notifyExtRadioWorkTimeout(
+ struct wpa_supplicant *wpa_s, uint32_t id)
+{
+ if (!wpa_s)
+ return;
+
+ if (sta_iface_object_map_.find(wpa_s->ifname) ==
+ sta_iface_object_map_.end())
+ return;
+
+ callWithEachStaIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &ISupplicantStaIfaceCallback::onExtRadioWorkTimeout,
+ std::placeholders::_1, id));
+}
+
+/**
+ * Retrieve the |ISupplicantP2pIface| hidl object reference using the provided
+ * ifname.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param iface_object Hidl reference corresponding to the iface.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::getP2pIfaceHidlObjectByIfname(
+ const std::string &ifname, android::sp<ISupplicantP2pIface> *iface_object)
+{
+ if (ifname.empty() || !iface_object)
+ return 1;
+
+ auto iface_object_iter = p2p_iface_object_map_.find(ifname);
+ if (iface_object_iter == p2p_iface_object_map_.end())
+ return 1;
+
+ *iface_object = iface_object_iter->second;
+ return 0;
+}
+
+/**
+ * Retrieve the |ISupplicantStaIface| hidl object reference using the provided
+ * ifname.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param iface_object Hidl reference corresponding to the iface.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::getStaIfaceHidlObjectByIfname(
+ const std::string &ifname, android::sp<ISupplicantStaIface> *iface_object)
+{
+ if (ifname.empty() || !iface_object)
+ return 1;
+
+ auto iface_object_iter = sta_iface_object_map_.find(ifname);
+ if (iface_object_iter == sta_iface_object_map_.end())
+ return 1;
+
+ *iface_object = iface_object_iter->second;
+ return 0;
+}
+
+/**
+ * Retrieve the |ISupplicantP2pNetwork| hidl object reference using the provided
+ * ifname and network_id.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param network_object Hidl reference corresponding to the network.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::getP2pNetworkHidlObjectByIfnameAndNetworkId(
+ const std::string &ifname, int network_id,
+ android::sp<ISupplicantP2pNetwork> *network_object)
+{
+ if (ifname.empty() || network_id < 0 || !network_object)
+ return 1;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+
+ auto network_object_iter = p2p_network_object_map_.find(network_key);
+ if (network_object_iter == p2p_network_object_map_.end())
+ return 1;
+
+ *network_object = network_object_iter->second;
+ return 0;
+}
+
+/**
+ * Retrieve the |ISupplicantStaNetwork| hidl object reference using the provided
+ * ifname and network_id.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param network_object Hidl reference corresponding to the network.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::getStaNetworkHidlObjectByIfnameAndNetworkId(
+ const std::string &ifname, int network_id,
+ android::sp<ISupplicantStaNetwork> *network_object)
+{
+ if (ifname.empty() || network_id < 0 || !network_object)
+ return 1;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+
+ auto network_object_iter = sta_network_object_map_.find(network_key);
+ if (network_object_iter == sta_network_object_map_.end())
+ return 1;
+
+ *network_object = network_object_iter->second;
+ return 0;
+}
+
+/**
+ * Add a new |ISupplicantCallback| hidl object reference to our
+ * global callback list.
+ *
+ * @param callback Hidl reference of the |ISupplicantCallback| object.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::addSupplicantCallbackHidlObject(
+ const android::sp<ISupplicantCallback> &callback)
+{
+ // Register for death notification before we add it to our list.
+ auto on_hidl_died_fctor = std::bind(
+ &HidlManager::removeSupplicantCallbackHidlObject, this,
+ std::placeholders::_1);
+ return registerForDeathAndAddCallbackHidlObjectToList<
+ ISupplicantCallback>(
+ callback, on_hidl_died_fctor, supplicant_callbacks_);
+}
+
+/**
+ * Add a new iface callback hidl object reference to our
+ * interface callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param callback Hidl reference of the callback object.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::addP2pIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantP2pIfaceCallback> &callback)
+{
+ const std::function<void(
+ const android::sp<ISupplicantP2pIfaceCallback> &)>
+ on_hidl_died_fctor = std::bind(
+ &HidlManager::removeP2pIfaceCallbackHidlObject, this, ifname,
+ std::placeholders::_1);
+ return addIfaceCallbackHidlObjectToMap(
+ ifname, callback, on_hidl_died_fctor, p2p_iface_callbacks_map_);
+}
+
+/**
+ * Add a new iface callback hidl object reference to our
+ * interface callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param callback Hidl reference of the callback object.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::addStaIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantStaIfaceCallback> &callback)
+{
+ const std::function<void(
+ const android::sp<ISupplicantStaIfaceCallback> &)>
+ on_hidl_died_fctor = std::bind(
+ &HidlManager::removeStaIfaceCallbackHidlObject, this, ifname,
+ std::placeholders::_1);
+ return addIfaceCallbackHidlObjectToMap(
+ ifname, callback, on_hidl_died_fctor, sta_iface_callbacks_map_);
+}
+
+/**
+ * Add a new network callback hidl object reference to our network callback
+ * list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param callback Hidl reference of the callback object.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::addP2pNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantP2pNetworkCallback> &callback)
+{
+ const std::function<void(
+ const android::sp<ISupplicantP2pNetworkCallback> &)>
+ on_hidl_died_fctor = std::bind(
+ &HidlManager::removeP2pNetworkCallbackHidlObject, this, ifname,
+ network_id, std::placeholders::_1);
+ return addNetworkCallbackHidlObjectToMap(
+ ifname, network_id, callback, on_hidl_died_fctor,
+ p2p_network_callbacks_map_);
+}
+
+/**
+ * Add a new network callback hidl object reference to our network callback
+ * list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param callback Hidl reference of the callback object.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int HidlManager::addStaNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantStaNetworkCallback> &callback)
+{
+ const std::function<void(
+ const android::sp<ISupplicantStaNetworkCallback> &)>
+ on_hidl_died_fctor = std::bind(
+ &HidlManager::removeStaNetworkCallbackHidlObject, this, ifname,
+ network_id, std::placeholders::_1);
+ return addNetworkCallbackHidlObjectToMap(
+ ifname, network_id, callback, on_hidl_died_fctor,
+ sta_network_callbacks_map_);
+}
+
+/**
+ * Removes the provided |ISupplicantCallback| hidl object reference
+ * from our global callback list.
+ *
+ * @param callback Hidl reference of the |ISupplicantCallback| object.
+ */
+void HidlManager::removeSupplicantCallbackHidlObject(
+ const android::sp<ISupplicantCallback> &callback)
+{
+ supplicant_callbacks_.erase(
+ std::remove(
+ supplicant_callbacks_.begin(), supplicant_callbacks_.end(),
+ callback),
+ supplicant_callbacks_.end());
+}
+
+/**
+ * Removes the provided iface callback hidl object reference from
+ * our interface callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param callback Hidl reference of the callback object.
+ */
+void HidlManager::removeP2pIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantP2pIfaceCallback> &callback)
+{
+ return removeIfaceCallbackHidlObjectFromMap(
+ ifname, callback, p2p_iface_callbacks_map_);
+}
+
+/**
+ * Removes the provided iface callback hidl object reference from
+ * our interface callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param callback Hidl reference of the callback object.
+ */
+void HidlManager::removeStaIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantStaIfaceCallback> &callback)
+{
+ return removeIfaceCallbackHidlObjectFromMap(
+ ifname, callback, sta_iface_callbacks_map_);
+}
+
+/**
+ * Removes the provided network callback hidl object reference from
+ * our network callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param callback Hidl reference of the callback object.
+ */
+void HidlManager::removeP2pNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantP2pNetworkCallback> &callback)
+{
+ return removeNetworkCallbackHidlObjectFromMap(
+ ifname, network_id, callback, p2p_network_callbacks_map_);
+}
+
+/**
+ * Removes the provided network callback hidl object reference from
+ * our network callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param callback Hidl reference of the callback object.
+ */
+void HidlManager::removeStaNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantStaNetworkCallback> &callback)
+{
+ return removeNetworkCallbackHidlObjectFromMap(
+ ifname, network_id, callback, sta_network_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered |ISupplicantCallback| callback hidl objects.
+ *
+ * @param method Pointer to the required hidl method from
+ * |ISupplicantCallback|.
+ */
+void HidlManager::callWithEachSupplicantCallback(
+ const std::function<Return<void>(android::sp<ISupplicantCallback>)> &method)
+{
+ for (const auto &callback : supplicant_callbacks_) {
+ if (!method(callback).isOk()) {
+ wpa_printf(MSG_ERROR, "Failed to invoke HIDL callback");
+ }
+ }
+}
+
+/**
+ * Helper fucntion to invoke the provided callback method on all the
+ * registered iface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * |ISupplicantIfaceCallback|.
+ */
+void HidlManager::callWithEachP2pIfaceCallback(
+ const std::string &ifname,
+ const std::function<Return<void>(android::sp<ISupplicantP2pIfaceCallback>)>
+ &method)
+{
+ callWithEachIfaceCallback(ifname, method, p2p_iface_callbacks_map_);
+}
+
+/**
+ * Helper fucntion to invoke the provided callback method on all the
+ * registered iface callback hidl objects for the specified
+ * |ifname|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param method Pointer to the required hidl method from
+ * |ISupplicantIfaceCallback|.
+ */
+void HidlManager::callWithEachStaIfaceCallback(
+ const std::string &ifname,
+ const std::function<Return<void>(android::sp<ISupplicantStaIfaceCallback>)>
+ &method)
+{
+ callWithEachIfaceCallback(ifname, method, sta_iface_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered network callback hidl objects for the specified
+ * |ifname| & |network_id|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param method Pointer to the required hidl method from
+ * |ISupplicantP2pNetworkCallback| or |ISupplicantStaNetworkCallback| .
+ */
+void HidlManager::callWithEachP2pNetworkCallback(
+ const std::string &ifname, int network_id,
+ const std::function<
+ Return<void>(android::sp<ISupplicantP2pNetworkCallback>)> &method)
+{
+ callWithEachNetworkCallback(
+ ifname, network_id, method, p2p_network_callbacks_map_);
+}
+
+/**
+ * Helper function to invoke the provided callback method on all the
+ * registered network callback hidl objects for the specified
+ * |ifname| & |network_id|.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param method Pointer to the required hidl method from
+ * |ISupplicantP2pNetworkCallback| or |ISupplicantStaNetworkCallback| .
+ */
+void HidlManager::callWithEachStaNetworkCallback(
+ const std::string &ifname, int network_id,
+ const std::function<
+ Return<void>(android::sp<ISupplicantStaNetworkCallback>)> &method)
+{
+ callWithEachNetworkCallback(
+ ifname, network_id, method, sta_network_callbacks_map_);
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/hidl_manager.h b/wpa_supplicant/hidl/1.0/hidl_manager.h
new file mode 100644
index 0000000..9d9527c
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/hidl_manager.h
@@ -0,0 +1,678 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
+#define WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
+
+#include <map>
+#include <string>
+
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
+
+#include "p2p_iface.h"
+#include "p2p_network.h"
+#include "sta_iface.h"
+#include "sta_network.h"
+#include "supplicant.h"
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * HidlManager is responsible for managing the lifetime of all
+ * hidl objects created by wpa_supplicant. This is a singleton
+ * class which is created by the supplicant core and can be used
+ * to get references to the hidl objects.
+ */
+class HidlManager
+{
+public:
+ static HidlManager *getInstance();
+ static void destroyInstance();
+
+ // Methods called from wpa_supplicant core.
+ int registerHidlService(struct wpa_global *global);
+ int registerInterface(struct wpa_supplicant *wpa_s);
+ int unregisterInterface(struct wpa_supplicant *wpa_s);
+ int registerNetwork(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+ int unregisterNetwork(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+ int notifyStateChange(struct wpa_supplicant *wpa_s);
+ int notifyNetworkRequest(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
+ const char *param);
+ void notifyAnqpQueryDone(
+ struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result,
+ const struct wpa_bss_anqp *anqp);
+ void notifyHs20IconQueryDone(
+ struct wpa_supplicant *wpa_s, const u8 *bssid,
+ const char *file_name, const u8 *image, u32 image_length);
+ void notifyHs20RxSubscriptionRemediation(
+ struct wpa_supplicant *wpa_s, const char *url, u8 osu_method);
+ void notifyHs20RxDeauthImminentNotice(
+ struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay,
+ const char *url);
+ void notifyDisconnectReason(struct wpa_supplicant *wpa_s);
+ void notifyAssocReject(struct wpa_supplicant *wpa_s);
+ void notifyAuthTimeout(struct wpa_supplicant *wpa_s);
+ void notifyBssidChanged(struct wpa_supplicant *wpa_s);
+ void notifyWpsEventFail(
+ struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr,
+ uint16_t config_error, uint16_t error_indication);
+ void notifyWpsEventSuccess(struct wpa_supplicant *wpa_s);
+ void notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s);
+ void notifyP2pDeviceFound(
+ struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
+ u8 peer_wfd_device_info_len);
+ void notifyP2pDeviceLost(
+ struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr);
+ void notifyP2pFindStopped(struct wpa_supplicant *wpa_s);
+ void notifyP2pGoNegReq(
+ struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id,
+ u8 go_intent);
+ void notifyP2pGoNegCompleted(
+ struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res);
+ void notifyP2pGroupFormationFailure(
+ struct wpa_supplicant *wpa_s, const char *reason);
+ void notifyP2pGroupStarted(
+ struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+ int persistent, int client);
+ void notifyP2pGroupRemoved(
+ struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
+ const char *role);
+ void notifyP2pInvitationReceived(
+ struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr,
+ const u8 *bssid, int id, int op_freq);
+ void notifyP2pInvitationResult(
+ struct wpa_supplicant *wpa_s, int status, const u8 *bssid);
+ void notifyP2pProvisionDiscovery(
+ struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request,
+ enum p2p_prov_disc_status status, u16 config_methods,
+ unsigned int generated_pin);
+ void notifyP2pSdResponse(
+ struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
+ const u8 *tlvs, size_t tlvs_len);
+ void notifyApStaAuthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta,
+ const u8 *p2p_dev_addr);
+ void notifyApStaDeauthorized(
+ struct wpa_supplicant *wpa_s, const u8 *sta,
+ const u8 *p2p_dev_addr);
+
+ // Methods called from hidl objects.
+ void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
+ void notifyExtRadioWorkTimeout(
+ struct wpa_supplicant *wpa_s, uint32_t id);
+
+ int getP2pIfaceHidlObjectByIfname(
+ const std::string &ifname,
+ android::sp<ISupplicantP2pIface> *iface_object);
+ int getStaIfaceHidlObjectByIfname(
+ const std::string &ifname,
+ android::sp<ISupplicantStaIface> *iface_object);
+ int getP2pNetworkHidlObjectByIfnameAndNetworkId(
+ const std::string &ifname, int network_id,
+ android::sp<ISupplicantP2pNetwork> *network_object);
+ int getStaNetworkHidlObjectByIfnameAndNetworkId(
+ const std::string &ifname, int network_id,
+ android::sp<ISupplicantStaNetwork> *network_object);
+ int addSupplicantCallbackHidlObject(
+ const android::sp<ISupplicantCallback> &callback);
+ int addP2pIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantP2pIfaceCallback> &callback);
+ int addStaIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantStaIfaceCallback> &callback);
+ int addP2pNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantP2pNetworkCallback> &callback);
+ int addStaNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantStaNetworkCallback> &callback);
+
+private:
+ HidlManager() = default;
+ ~HidlManager() = default;
+ HidlManager(const HidlManager &) = default;
+ HidlManager &operator=(const HidlManager &) = default;
+
+ void removeSupplicantCallbackHidlObject(
+ const android::sp<ISupplicantCallback> &callback);
+ void removeP2pIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantP2pIfaceCallback> &callback);
+ void removeStaIfaceCallbackHidlObject(
+ const std::string &ifname,
+ const android::sp<ISupplicantStaIfaceCallback> &callback);
+ void removeP2pNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantP2pNetworkCallback> &callback);
+ void removeStaNetworkCallbackHidlObject(
+ const std::string &ifname, int network_id,
+ const android::sp<ISupplicantStaNetworkCallback> &callback);
+
+ void callWithEachSupplicantCallback(
+ const std::function<android::hardware::Return<void>(
+ android::sp<ISupplicantCallback>)> &method);
+ void callWithEachP2pIfaceCallback(
+ const std::string &ifname,
+ const std::function<android::hardware::Return<void>(
+ android::sp<ISupplicantP2pIfaceCallback>)> &method);
+ void callWithEachStaIfaceCallback(
+ const std::string &ifname,
+ const std::function<android::hardware::Return<void>(
+ android::sp<ISupplicantStaIfaceCallback>)> &method);
+ void callWithEachP2pNetworkCallback(
+ const std::string &ifname, int network_id,
+ const std::function<android::hardware::Return<void>(
+ android::sp<ISupplicantP2pNetworkCallback>)> &method);
+ void callWithEachStaNetworkCallback(
+ const std::string &ifname, int network_id,
+ const std::function<android::hardware::Return<void>(
+ android::sp<ISupplicantStaNetworkCallback>)> &method);
+
+ // Singleton instance of this class.
+ static HidlManager *instance_;
+ // The main hidl service object.
+ android::sp<Supplicant> supplicant_object_;
+ // Map of all the P2P interface specific hidl objects controlled by
+ // wpa_supplicant. This map is keyed in by the corresponding
+ // |ifname|.
+ std::map<const std::string, android::sp<P2pIface>>
+ p2p_iface_object_map_;
+ // Map of all the STA interface specific hidl objects controlled by
+ // wpa_supplicant. This map is keyed in by the corresponding
+ // |ifname|.
+ std::map<const std::string, android::sp<StaIface>>
+ sta_iface_object_map_;
+ // Map of all the P2P network specific hidl objects controlled by
+ // wpa_supplicant. This map is keyed in by the corresponding
+ // |ifname| & |network_id|.
+ std::map<const std::string, android::sp<P2pNetwork>>
+ p2p_network_object_map_;
+ // Map of all the STA network specific hidl objects controlled by
+ // wpa_supplicant. This map is keyed in by the corresponding
+ // |ifname| & |network_id|.
+ std::map<const std::string, android::sp<StaNetwork>>
+ sta_network_object_map_;
+
+ // Callback registered for the main hidl service object.
+ std::vector<android::sp<ISupplicantCallback>> supplicant_callbacks_;
+ // Map of all the callbacks registered for P2P interface specific
+ // hidl objects controlled by wpa_supplicant. This map is keyed in by
+ // the corresponding |ifname|.
+ std::map<
+ const std::string,
+ std::vector<android::sp<ISupplicantP2pIfaceCallback>>>
+ p2p_iface_callbacks_map_;
+ // Map of all the callbacks registered for STA interface specific
+ // hidl objects controlled by wpa_supplicant. This map is keyed in by
+ // the corresponding |ifname|.
+ std::map<
+ const std::string,
+ std::vector<android::sp<ISupplicantStaIfaceCallback>>>
+ sta_iface_callbacks_map_;
+ // Map of all the callbacks registered for P2P network specific
+ // hidl objects controlled by wpa_supplicant. This map is keyed in by
+ // the corresponding |ifname| & |network_id|.
+ std::map<
+ const std::string,
+ std::vector<android::sp<ISupplicantP2pNetworkCallback>>>
+ p2p_network_callbacks_map_;
+ // Map of all the callbacks registered for STA network specific
+ // hidl objects controlled by wpa_supplicant. This map is keyed in by
+ // the corresponding |ifname| & |network_id|.
+ std::map<
+ const std::string,
+ std::vector<android::sp<ISupplicantStaNetworkCallback>>>
+ sta_network_callbacks_map_;
+
+#if 0 // TODO(b/31632518): HIDL object death notifications.
+ /**
+ * Helper class used to deregister the callback object reference from
+ * our callback list on the death of the hidl object.
+ * This class stores a reference of the callback hidl object and a
+ * function to be called to indicate the death of the hidl object.
+ */
+ template <class CallbackType>
+ class CallbackObjectDeathNotifier
+ : public android::hardware::IBinder::DeathRecipient
+ {
+ public:
+ CallbackObjectDeathNotifier(
+ const android::sp<CallbackType> &callback,
+ const std::function<void(const android::sp<CallbackType> &)>
+ &on_hidl_died)
+ : callback_(callback), on_hidl_died_(on_hidl_died)
+ {
+ }
+ void binderDied(const android::wp<android::hardware::IBinder>
+ & /* who */) override
+ {
+ on_hidl_died_(callback_);
+ }
+
+ private:
+ // The callback hidl object reference.
+ const android::sp<CallbackType> callback_;
+ // Callback function to be called when the hidl dies.
+ const std::function<void(const android::sp<CallbackType> &)>
+ on_hidl_died_;
+ };
+#endif
+};
+
+// The hidl interface uses some values which are the same as internal ones to
+// avoid nasty runtime conversion functions. So, adding compile time asserts
+// to guard against any internal changes breaking the hidl interface.
+static_assert(
+ static_cast<uint32_t>(ISupplicant::DebugLevel::EXCESSIVE) == MSG_EXCESSIVE,
+ "Debug level value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicant::DebugLevel::ERROR) == MSG_ERROR,
+ "Debug level value mismatch");
+
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) ==
+ WPA_KEY_MGMT_NONE,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) ==
+ WPA_KEY_MGMT_PSK,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) ==
+ WPA_KEY_MGMT_IEEE8021X,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) ==
+ WPA_KEY_MGMT_IEEE8021X_NO_WPA,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) ==
+ WPA_KEY_MGMT_FT_IEEE8021X,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) ==
+ WPA_KEY_MGMT_FT_PSK,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN) ==
+ WPA_KEY_MGMT_OSEN,
+ "KeyMgmt value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) ==
+ WPA_PROTO_WPA,
+ "Proto value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) ==
+ WPA_PROTO_RSN,
+ "Proto value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN) ==
+ WPA_PROTO_OSEN,
+ "Proto value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) ==
+ WPA_AUTH_ALG_OPEN,
+ "AuthAlg value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) ==
+ WPA_AUTH_ALG_SHARED,
+ "AuthAlg value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP) ==
+ WPA_AUTH_ALG_LEAP,
+ "AuthAlg value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) ==
+ WPA_CIPHER_WEP40,
+ "GroupCipher value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) ==
+ WPA_CIPHER_WEP104,
+ "GroupCipher value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) ==
+ WPA_CIPHER_TKIP,
+ "GroupCipher value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) ==
+ WPA_CIPHER_CCMP,
+ "GroupCipher value mismatch");
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED) ==
+ WPA_CIPHER_GTK_NOT_USED,
+ "GroupCipher value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) ==
+ WPA_CIPHER_NONE,
+ "PairwiseCipher value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) ==
+ WPA_CIPHER_TKIP,
+ "PairwiseCipher value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP) ==
+ WPA_CIPHER_CCMP,
+ "PairwiseCipher value mismatch");
+
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::DISCONNECTED) ==
+ WPA_DISCONNECTED,
+ "State value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaIfaceCallback::State::COMPLETED) ==
+ WPA_COMPLETED,
+ "State value mismatch");
+
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::VENUE_NAME) ==
+ ANQP_VENUE_NAME,
+ "ANQP ID value mismatch");
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaIface::AnqpInfoId::ROAMING_CONSORTIUM) ==
+ ANQP_ROAMING_CONSORTIUM,
+ "ANQP ID value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::NAI_REALM) ==
+ ANQP_NAI_REALM,
+ "ANQP ID value mismatch");
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaIface::AnqpInfoId::IP_ADDR_TYPE_AVAILABILITY) ==
+ ANQP_IP_ADDR_TYPE_AVAILABILITY,
+ "ANQP ID value mismatch");
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaIface::AnqpInfoId::ANQP_3GPP_CELLULAR_NETWORK) ==
+ ANQP_3GPP_CELLULAR_NETWORK,
+ "ANQP ID value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaIface::AnqpInfoId::DOMAIN_NAME) ==
+ ANQP_DOMAIN_NAME,
+ "ANQP ID value mismatch");
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaIface::Hs20AnqpSubtypes::OPERATOR_FRIENDLY_NAME) ==
+ HS20_STYPE_OPERATOR_FRIENDLY_NAME,
+ "HS Subtype value mismatch");
+static_assert(
+ static_cast<uint32_t>(ISupplicantStaIface::Hs20AnqpSubtypes::WAN_METRICS) ==
+ HS20_STYPE_WAN_METRICS,
+ "HS Subtype value mismatch");
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaIface::Hs20AnqpSubtypes::CONNECTION_CAPABILITY) ==
+ HS20_STYPE_CONNECTION_CAPABILITY,
+ "HS Subtype value mismatch");
+static_assert(
+ static_cast<uint32_t>(
+ ISupplicantStaIface::Hs20AnqpSubtypes::OSU_PROVIDERS_LIST) ==
+ HS20_STYPE_OSU_PROVIDERS_LIST,
+ "HS Subtype value mismatch");
+
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantStaIfaceCallback::WpsConfigError::NO_ERROR) ==
+ WPS_CFG_NO_ERROR,
+ "Wps config error value mismatch");
+static_assert(
+ static_cast<uint16_t>(ISupplicantStaIfaceCallback::WpsConfigError::
+ PUBLIC_KEY_HASH_MISMATCH) ==
+ WPS_CFG_PUBLIC_KEY_HASH_MISMATCH,
+ "Wps config error value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantStaIfaceCallback::WpsErrorIndication::NO_ERROR) ==
+ WPS_EI_NO_ERROR,
+ "Wps error indication value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantStaIfaceCallback::WpsErrorIndication::AUTH_FAILURE) ==
+ WPS_EI_AUTH_FAILURE,
+ "Wps error indication value mismatch");
+
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::USBA) == WPS_CONFIG_USBA,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::ETHERNET) == WPS_CONFIG_ETHERNET,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::LABEL) == WPS_CONFIG_LABEL,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::DISPLAY) == WPS_CONFIG_DISPLAY,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::INT_NFC_TOKEN) ==
+ WPS_CONFIG_INT_NFC_TOKEN,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::EXT_NFC_TOKEN) ==
+ WPS_CONFIG_EXT_NFC_TOKEN,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::NFC_INTERFACE) ==
+ WPS_CONFIG_NFC_INTERFACE,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::PUSHBUTTON) ==
+ WPS_CONFIG_PUSHBUTTON,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::KEYPAD) == WPS_CONFIG_KEYPAD,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::VIRT_PUSHBUTTON) ==
+ WPS_CONFIG_VIRT_PUSHBUTTON,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::PHY_PUSHBUTTON) ==
+ WPS_CONFIG_PHY_PUSHBUTTON,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::P2PS) == WPS_CONFIG_P2PS,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::VIRT_DISPLAY) ==
+ WPS_CONFIG_VIRT_DISPLAY,
+ "Wps config value mismatch");
+static_assert(
+ static_cast<uint32_t>(WpsConfigMethods::PHY_DISPLAY) ==
+ WPS_CONFIG_PHY_DISPLAY,
+ "Wps config value mismatch");
+
+static_assert(
+ static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_OWNER) ==
+ P2P_GROUP_CAPAB_GROUP_OWNER,
+ "P2P capability value mismatch");
+static_assert(
+ static_cast<uint32_t>(P2pGroupCapabilityMask::PERSISTENT_GROUP) ==
+ P2P_GROUP_CAPAB_PERSISTENT_GROUP,
+ "P2P capability value mismatch");
+static_assert(
+ static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_LIMIT) ==
+ P2P_GROUP_CAPAB_GROUP_LIMIT,
+ "P2P capability value mismatch");
+static_assert(
+ static_cast<uint32_t>(P2pGroupCapabilityMask::INTRA_BSS_DIST) ==
+ P2P_GROUP_CAPAB_INTRA_BSS_DIST,
+ "P2P capability value mismatch");
+static_assert(
+ static_cast<uint32_t>(P2pGroupCapabilityMask::CROSS_CONN) ==
+ P2P_GROUP_CAPAB_CROSS_CONN,
+ "P2P capability value mismatch");
+static_assert(
+ static_cast<uint32_t>(P2pGroupCapabilityMask::PERSISTENT_RECONN) ==
+ P2P_GROUP_CAPAB_PERSISTENT_RECONN,
+ "P2P capability value mismatch");
+static_assert(
+ static_cast<uint32_t>(P2pGroupCapabilityMask::GROUP_FORMATION) ==
+ P2P_GROUP_CAPAB_GROUP_FORMATION,
+ "P2P capability value mismatch");
+
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId::DEFAULT) ==
+ DEV_PW_DEFAULT,
+ "Wps dev password id value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId::USER_SPECIFIED) ==
+ DEV_PW_USER_SPECIFIED,
+ "Wps dev password id value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId::MACHINE_SPECIFIED) ==
+ DEV_PW_MACHINE_SPECIFIED,
+ "Wps dev password id value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId::REKEY) == DEV_PW_REKEY,
+ "Wps dev password id value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId::PUSHBUTTON) ==
+ DEV_PW_PUSHBUTTON,
+ "Wps dev password id value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId::REGISTRAR_SPECIFIED) ==
+ DEV_PW_REGISTRAR_SPECIFIED,
+ "Wps dev password id value mismatch");
+static_assert(
+ static_cast<uint16_t>(ISupplicantP2pIfaceCallback::WpsDevPasswordId::
+ NFC_CONNECTION_HANDOVER) ==
+ DEV_PW_NFC_CONNECTION_HANDOVER,
+ "Wps dev password id value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::WpsDevPasswordId::P2PS_DEFAULT) ==
+ DEV_PW_P2PS_DEFAULT,
+ "Wps dev password id value mismatch");
+
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::SUCCESS) == P2P_SC_SUCCESS,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
+ FAIL_INFO_CURRENTLY_UNAVAILABLE) ==
+ P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_INCOMPATIBLE_PARAMS) ==
+ P2P_SC_FAIL_INCOMPATIBLE_PARAMS,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_LIMIT_REACHED) ==
+ P2P_SC_FAIL_LIMIT_REACHED,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_INVALID_PARAMS) ==
+ P2P_SC_FAIL_INVALID_PARAMS,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
+ FAIL_UNABLE_TO_ACCOMMODATE) ==
+ P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_PREV_PROTOCOL_ERROR) ==
+ P2P_SC_FAIL_PREV_PROTOCOL_ERROR,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_NO_COMMON_CHANNELS) ==
+ P2P_SC_FAIL_NO_COMMON_CHANNELS,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_UNKNOWN_GROUP) ==
+ P2P_SC_FAIL_UNKNOWN_GROUP,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_BOTH_GO_INTENT_15) ==
+ P2P_SC_FAIL_BOTH_GO_INTENT_15,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(ISupplicantP2pIfaceCallback::P2pStatusCode::
+ FAIL_INCOMPATIBLE_PROV_METHOD) ==
+ P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::FAIL_REJECTED_BY_USER) ==
+ P2P_SC_FAIL_REJECTED_BY_USER,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pStatusCode::SUCCESS_DEFERRED) ==
+ P2P_SC_SUCCESS_DEFERRED,
+ "P2P status code value mismatch");
+
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::SUCCESS) ==
+ P2P_PROV_DISC_SUCCESS,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::TIMEOUT) ==
+ P2P_PROV_DISC_TIMEOUT,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::REJECTED) ==
+ P2P_PROV_DISC_REJECTED,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::TIMEOUT_JOIN) ==
+ P2P_PROV_DISC_TIMEOUT_JOIN,
+ "P2P status code value mismatch");
+static_assert(
+ static_cast<uint16_t>(
+ ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode::INFO_UNAVAILABLE) ==
+ P2P_PROV_DISC_INFO_UNAVAILABLE,
+ "P2P status code value mismatch");
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
+#endif // WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H
diff --git a/wpa_supplicant/hidl/1.0/hidl_return_util.h b/wpa_supplicant/hidl/1.0/hidl_return_util.h
new file mode 100644
index 0000000..c077fc8
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/hidl_return_util.h
@@ -0,0 +1,101 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HIDL_RETURN_UTIL_H_
+#define HIDL_RETURN_UTIL_H_
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+namespace hidl_return_util {
+
+/**
+ * These utility functions are used to invoke a method on the provided
+ * HIDL interface object.
+ * These functions checks if the provided HIDL interface object is valid.
+ * a) if valid, Invokes the corresponding internal implementation function of
+ * the HIDL method. It then invokes the HIDL continuation callback with
+ * the status and any returned values.
+ * b) if invalid, invokes the HIDL continuation callback with the
+ * provided error status and default values.
+ */
+// Use for HIDL methods which return only an instance of SupplicantStatus.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCall(
+ ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatus&)>& hidl_cb, Args&&... args)
+{
+ if (obj->isValid()) {
+ hidl_cb((obj->*work)(std::forward<Args>(args)...));
+ } else {
+ hidl_cb({status_code_if_invalid, ""});
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return instance of SupplicantStatus and a single
+// return value.
+template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+Return<void> validateAndCall(
+ ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatus&, ReturnT)>& hidl_cb,
+ Args&&... args)
+{
+ if (obj->isValid()) {
+ const auto& ret_pair =
+ (obj->*work)(std::forward<Args>(args)...);
+ const SupplicantStatus& status = std::get<0>(ret_pair);
+ const auto& ret_value = std::get<1>(ret_pair);
+ hidl_cb(status, ret_value);
+ } else {
+ hidl_cb(
+ {status_code_if_invalid, ""},
+ typename std::remove_reference<ReturnT>::type());
+ }
+ return Void();
+}
+
+// Use for HIDL methods which return instance of SupplicantStatus and 2 return
+// values.
+template <
+ typename ObjT, typename WorkFuncT, typename ReturnT1, typename ReturnT2,
+ typename... Args>
+Return<void> validateAndCall(
+ ObjT* obj, SupplicantStatusCode status_code_if_invalid, WorkFuncT&& work,
+ const std::function<void(const SupplicantStatus&, ReturnT1, ReturnT2)>&
+ hidl_cb,
+ Args&&... args)
+{
+ if (obj->isValid()) {
+ const auto& ret_tuple =
+ (obj->*work)(std::forward<Args>(args)...);
+ const SupplicantStatus& status = std::get<0>(ret_tuple);
+ const auto& ret_value1 = std::get<1>(ret_tuple);
+ const auto& ret_value2 = std::get<2>(ret_tuple);
+ hidl_cb(status, ret_value1, ret_value2);
+ } else {
+ hidl_cb(
+ {status_code_if_invalid, ""},
+ typename std::remove_reference<ReturnT1>::type(),
+ typename std::remove_reference<ReturnT2>::type());
+ }
+ return Void();
+}
+
+} // namespace hidl_util
+} // namespace implementation
+} // namespace V1_0
+} // namespace supplicant
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // HIDL_RETURN_UTIL_H_
diff --git a/wpa_supplicant/hidl/1.0/iface_config_utils.cpp b/wpa_supplicant/hidl/1.0/iface_config_utils.cpp
new file mode 100644
index 0000000..7dc5a6c
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/iface_config_utils.cpp
@@ -0,0 +1,180 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Jouni Malinen
+ * <j@w1.fi>
+ * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Roshan Pius
+ * <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "hidl_manager.h"
+#include "hidl_return_util.h"
+#include "iface_config_utils.h"
+
+namespace {
+constexpr uint32_t kMaxWpsDeviceNameSize = WPS_DEV_NAME_MAX_LEN;
+constexpr uint32_t kMaxWpsManufacturerSize = WPS_MANUFACTURER_MAX_LEN;
+constexpr uint32_t kMaxWpsModelNameSize = WPS_MODEL_NAME_MAX_LEN;
+constexpr uint32_t kMaxWpsModelNumberSize = WPS_MODEL_NUMBER_MAX_LEN;
+constexpr uint32_t kMaxWpsSerialNumberSize = WPS_SERIAL_NUMBER_MAX_LEN;
+
+void processConfigUpdate(struct wpa_supplicant* wpa_s, uint32_t changed_param)
+{
+ wpa_s->conf->changed_parameters |= changed_param;
+ wpa_supplicant_update_config(wpa_s);
+}
+
+// Free any existing pointer stored in |dst| and store the provided string value
+// there.
+int freeAndSetStringConfigParam(
+ struct wpa_supplicant* wpa_s, const std::string& value, uint32_t max_size,
+ uint32_t changed_param, char** dst)
+{
+ if (value.size() > max_size) {
+ return -1;
+ }
+ WPA_ASSERT(dst);
+ os_free(static_cast<void*>(*dst));
+ *dst = os_strdup(value.c_str());
+ processConfigUpdate(wpa_s, changed_param);
+ return 0;
+}
+
+std::string convertWpsConfigMethodsMaskToString(uint16_t config_methods)
+{
+ using WpsConfigMethods =
+ android::hardware::wifi::supplicant::V1_0::WpsConfigMethods;
+ std::string config_methods_str;
+ for (const auto& flag_and_name :
+ {std::make_pair(WpsConfigMethods::USBA, "usba"),
+ {WpsConfigMethods::ETHERNET, "ethernet"},
+ {WpsConfigMethods::LABEL, "label"},
+ {WpsConfigMethods::DISPLAY, "display"},
+ {WpsConfigMethods::INT_NFC_TOKEN, "int_nfc_token"},
+ {WpsConfigMethods::EXT_NFC_TOKEN, "ext_nfc_token"},
+ {WpsConfigMethods::NFC_INTERFACE, "nfc_interface"},
+ {WpsConfigMethods::PUSHBUTTON, "push_button"},
+ {WpsConfigMethods::KEYPAD, "keypad"},
+ {WpsConfigMethods::VIRT_PUSHBUTTON, "virtual_push_button"},
+ {WpsConfigMethods::PHY_PUSHBUTTON, "physical_push_button"},
+ {WpsConfigMethods::P2PS, "p2ps"},
+ {WpsConfigMethods::VIRT_DISPLAY, "virtual_display"},
+ {WpsConfigMethods::PHY_DISPLAY, "physical_display"}}) {
+ const auto flag =
+ static_cast<std::underlying_type<WpsConfigMethods>::type>(
+ flag_and_name.first);
+ if ((config_methods & flag) == flag) {
+ config_methods_str += flag_and_name.second;
+ config_methods_str += " ";
+ }
+ }
+ return config_methods_str;
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+namespace iface_config_utils {
+SupplicantStatus setWpsDeviceName(
+ struct wpa_supplicant* wpa_s, const std::string& name)
+{
+ WPA_ASSERT(wpa_s);
+ if (freeAndSetStringConfigParam(
+ wpa_s, name, kMaxWpsDeviceNameSize, CFG_CHANGED_DEVICE_NAME,
+ &wpa_s->conf->device_name)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus setWpsDeviceType(
+ struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type)
+{
+ WPA_ASSERT(wpa_s);
+ WPA_ASSERT(type.size() == WPS_DEV_TYPE_LEN);
+ os_memcpy(wpa_s->conf->device_type, type.data(), WPS_DEV_TYPE_LEN);
+ processConfigUpdate(wpa_s, CFG_CHANGED_DEVICE_TYPE);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus setWpsManufacturer(
+ struct wpa_supplicant* wpa_s, const std::string& manufacturer)
+{
+ WPA_ASSERT(wpa_s);
+ if (freeAndSetStringConfigParam(
+ wpa_s, manufacturer, kMaxWpsManufacturerSize,
+ CFG_CHANGED_WPS_STRING, &wpa_s->conf->manufacturer)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus setWpsModelName(
+ struct wpa_supplicant* wpa_s, const std::string& model_name)
+{
+ WPA_ASSERT(wpa_s);
+ if (freeAndSetStringConfigParam(
+ wpa_s, model_name, kMaxWpsModelNameSize, CFG_CHANGED_WPS_STRING,
+ &wpa_s->conf->model_name)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus setWpsModelNumber(
+ struct wpa_supplicant* wpa_s, const std::string& model_number)
+{
+ WPA_ASSERT(wpa_s);
+ if (freeAndSetStringConfigParam(
+ wpa_s, model_number, kMaxWpsModelNumberSize,
+ CFG_CHANGED_WPS_STRING, &wpa_s->conf->model_number)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus setWpsSerialNumber(
+ struct wpa_supplicant* wpa_s, const std::string& serial_number)
+{
+ WPA_ASSERT(wpa_s);
+ if (freeAndSetStringConfigParam(
+ wpa_s, serial_number, kMaxWpsSerialNumberSize,
+ CFG_CHANGED_WPS_STRING, &wpa_s->conf->serial_number)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus setWpsConfigMethods(
+ struct wpa_supplicant* wpa_s, uint16_t config_methods)
+{
+ WPA_ASSERT(wpa_s);
+ if (freeAndSetStringConfigParam(
+ wpa_s, convertWpsConfigMethodsMaskToString(config_methods),
+ UINT32_MAX, CFG_CHANGED_CONFIG_METHODS,
+ &wpa_s->conf->config_methods)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus setExternalSim(
+ struct wpa_supplicant* wpa_s, bool useExternalSim)
+{
+ WPA_ASSERT(wpa_s);
+ wpa_s->conf->external_sim = useExternalSim ? 1 : 0;
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+} // namespace iface_config_utils
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/iface_config_utils.h b/wpa_supplicant/hidl/1.0/iface_config_utils.h
new file mode 100644
index 0000000..789cc38
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/iface_config_utils.h
@@ -0,0 +1,59 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Jouni Malinen
+ * <j@w1.fi>
+ * Copyright (struct wpa_supplicant* wpa_s, c) 2004-2016, Roshan Pius
+ * <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
+#define WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
+
+#include <android-base/macros.h>
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+}
+
+/**
+ * Utility functions to set various config parameters of an iface via HIDL
+ * methods.
+ */
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+namespace iface_config_utils {
+SupplicantStatus setWpsDeviceName(
+ struct wpa_supplicant* wpa_s, const std::string& name);
+SupplicantStatus setWpsDeviceType(
+ struct wpa_supplicant* wpa_s, const std::array<uint8_t, 8>& type);
+SupplicantStatus setWpsManufacturer(
+ struct wpa_supplicant* wpa_s, const std::string& manufacturer);
+SupplicantStatus setWpsModelName(
+ struct wpa_supplicant* wpa_s, const std::string& model_name);
+SupplicantStatus setWpsModelNumber(
+ struct wpa_supplicant* wpa_s, const std::string& model_number);
+SupplicantStatus setWpsSerialNumber(
+ struct wpa_supplicant* wpa_s, const std::string& serial_number);
+SupplicantStatus setWpsConfigMethods(
+ struct wpa_supplicant* wpa_s, uint16_t config_methods);
+SupplicantStatus setExternalSim(
+ struct wpa_supplicant* wpa_s, bool useExternalSim);
+} // namespace iface_config_utils
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
+
+#endif // WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H
diff --git a/wpa_supplicant/hidl/1.0/misc_utils.h b/wpa_supplicant/hidl/1.0/misc_utils.h
new file mode 100644
index 0000000..354ec32
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/misc_utils.h
@@ -0,0 +1,72 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MISC_UTILS_H_
+#define MISC_UTILS_H_
+
+extern "C" {
+#include "wpabuf.h"
+}
+
+namespace {
+constexpr size_t kWpsPinNumDigits = 8;
+// Custom deleter for wpabuf.
+void freeWpaBuf(wpabuf *ptr) { wpabuf_free(ptr); }
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+namespace misc_utils {
+using wpabuf_unique_ptr = std::unique_ptr<wpabuf, void (*)(wpabuf *)>;
+
+// Creates a unique_ptr for wpabuf ptr with a custom deleter.
+inline wpabuf_unique_ptr createWpaBufUniquePtr(struct wpabuf *raw_ptr)
+{
+ return {raw_ptr, freeWpaBuf};
+}
+
+// Creates a wpabuf ptr with a custom deleter copying the data from the provided
+// vector.
+inline wpabuf_unique_ptr convertVectorToWpaBuf(const std::vector<uint8_t> &data)
+{
+ return createWpaBufUniquePtr(
+ wpabuf_alloc_copy(data.data(), data.size()));
+}
+
+// Copies the provided wpabuf contents to a std::vector.
+inline std::vector<uint8_t> convertWpaBufToVector(const struct wpabuf *buf)
+{
+ if (buf) {
+ return std::vector<uint8_t>(
+ wpabuf_head_u8(buf), wpabuf_head_u8(buf) + wpabuf_len(buf));
+ } else {
+ return std::vector<uint8_t>();
+ }
+}
+
+// Returns a string holding the wps pin.
+inline std::string convertWpsPinToString(int pin)
+{
+ char pin_str[kWpsPinNumDigits + 1];
+ snprintf(pin_str, sizeof(pin_str), "%08d", pin);
+ return pin_str;
+}
+
+} // namespace misc_utils
+} // namespace implementation
+} // namespace V1_0
+} // namespace supplicant
+} // namespace wifi
+} // namespace hardware
+} // namespace android
+#endif // MISC_UTILS_H_
diff --git a/wpa_supplicant/hidl/1.0/p2p_iface.cpp b/wpa_supplicant/hidl/1.0/p2p_iface.cpp
new file mode 100644
index 0000000..ab4014d
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/p2p_iface.cpp
@@ -0,0 +1,1282 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ * Copyright (C) 2017 Sony Mobile Communications Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "hidl_manager.h"
+#include "hidl_return_util.h"
+#include "iface_config_utils.h"
+#include "misc_utils.h"
+#include "p2p_iface.h"
+
+extern "C" {
+#include "ap.h"
+#include "wps_supplicant.h"
+#include "wifi_display.h"
+}
+
+namespace {
+const char kConfigMethodStrPbc[] = "pbc";
+const char kConfigMethodStrDisplay[] = "display";
+const char kConfigMethodStrKeypad[] = "keypad";
+constexpr char kSetMiracastMode[] = "MIRACAST ";
+constexpr uint8_t kWfdDeviceInfoSubelemId = 0;
+constexpr char kWfdDeviceInfoSubelemLenHexStr[] = "0006";
+
+using android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
+uint8_t convertHidlMiracastModeToInternal(
+ ISupplicantP2pIface::MiracastMode mode)
+{
+ switch (mode) {
+ case ISupplicantP2pIface::MiracastMode::DISABLED:
+ return 0;
+ case ISupplicantP2pIface::MiracastMode::SOURCE:
+ return 1;
+ case ISupplicantP2pIface::MiracastMode::SINK:
+ return 2;
+ };
+ WPA_ASSERT(false);
+}
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+P2pIface::P2pIface(struct wpa_global* wpa_global, const char ifname[])
+ : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
+{
+}
+
+void P2pIface::invalidate() { is_valid_ = false; }
+bool P2pIface::isValid()
+{
+ return (is_valid_ && (retrieveIfacePtr() != nullptr));
+}
+Return<void> P2pIface::getName(getName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getNameInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::getType(getType_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getTypeInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::addNetwork(addNetwork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::addNetworkInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::removeNetwork(
+ SupplicantNetworkId id, removeNetwork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::removeNetworkInternal, _hidl_cb, id);
+}
+
+Return<void> P2pIface::getNetwork(
+ SupplicantNetworkId id, getNetwork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getNetworkInternal, _hidl_cb, id);
+}
+
+Return<void> P2pIface::listNetworks(listNetworks_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::listNetworksInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::registerCallback(
+ const sp<ISupplicantP2pIfaceCallback>& callback,
+ registerCallback_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::registerCallbackInternal, _hidl_cb, callback);
+}
+
+Return<void> P2pIface::getDeviceAddress(getDeviceAddress_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getDeviceAddressInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::setSsidPostfix(
+ const hidl_vec<uint8_t>& postfix, setSsidPostfix_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setSsidPostfixInternal, _hidl_cb, postfix);
+}
+
+Return<void> P2pIface::setGroupIdle(
+ const hidl_string& group_ifname, uint32_t timeout_in_sec,
+ setGroupIdle_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setGroupIdleInternal, _hidl_cb, group_ifname,
+ timeout_in_sec);
+}
+
+Return<void> P2pIface::setPowerSave(
+ const hidl_string& group_ifname, bool enable, setPowerSave_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setPowerSaveInternal, _hidl_cb, group_ifname, enable);
+}
+
+Return<void> P2pIface::find(uint32_t timeout_in_sec, find_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::findInternal, _hidl_cb, timeout_in_sec);
+}
+
+Return<void> P2pIface::stopFind(stopFind_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::stopFindInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::flush(flush_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::flushInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::connect(
+ const hidl_array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method,
+ const hidl_string& pre_selected_pin, bool join_existing_group,
+ bool persistent, uint32_t go_intent, connect_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::connectInternal, _hidl_cb, peer_address,
+ provision_method, pre_selected_pin, join_existing_group, persistent,
+ go_intent);
+}
+
+Return<void> P2pIface::cancelConnect(cancelConnect_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::cancelConnectInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::provisionDiscovery(
+ const hidl_array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method,
+ provisionDiscovery_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::provisionDiscoveryInternal, _hidl_cb, peer_address,
+ provision_method);
+}
+
+Return<void> P2pIface::addGroup(
+ bool persistent, SupplicantNetworkId persistent_network_id,
+ addGroup_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::addGroupInternal, _hidl_cb, persistent,
+ persistent_network_id);
+}
+
+Return<void> P2pIface::removeGroup(
+ const hidl_string& group_ifname, removeGroup_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::removeGroupInternal, _hidl_cb, group_ifname);
+}
+
+Return<void> P2pIface::reject(
+ const hidl_array<uint8_t, 6>& peer_address, reject_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::rejectInternal, _hidl_cb, peer_address);
+}
+
+Return<void> P2pIface::invite(
+ const hidl_string& group_ifname,
+ const hidl_array<uint8_t, 6>& go_device_address,
+ const hidl_array<uint8_t, 6>& peer_address, invite_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::inviteInternal, _hidl_cb, group_ifname,
+ go_device_address, peer_address);
+}
+
+Return<void> P2pIface::reinvoke(
+ SupplicantNetworkId persistent_network_id,
+ const hidl_array<uint8_t, 6>& peer_address, reinvoke_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::reinvokeInternal, _hidl_cb, persistent_network_id,
+ peer_address);
+}
+
+Return<void> P2pIface::configureExtListen(
+ uint32_t period_in_millis, uint32_t interval_in_millis,
+ configureExtListen_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::configureExtListenInternal, _hidl_cb, period_in_millis,
+ interval_in_millis);
+}
+
+Return<void> P2pIface::setListenChannel(
+ uint32_t channel, uint32_t operating_class, setListenChannel_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setListenChannelInternal, _hidl_cb, channel,
+ operating_class);
+}
+
+Return<void> P2pIface::setDisallowedFrequencies(
+ const hidl_vec<FreqRange>& ranges, setDisallowedFrequencies_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setDisallowedFrequenciesInternal, _hidl_cb, ranges);
+}
+
+Return<void> P2pIface::getSsid(
+ const hidl_array<uint8_t, 6>& peer_address, getSsid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getSsidInternal, _hidl_cb, peer_address);
+}
+
+Return<void> P2pIface::getGroupCapability(
+ const hidl_array<uint8_t, 6>& peer_address, getGroupCapability_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getGroupCapabilityInternal, _hidl_cb, peer_address);
+}
+
+Return<void> P2pIface::addBonjourService(
+ const hidl_vec<uint8_t>& query, const hidl_vec<uint8_t>& response,
+ addBonjourService_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::addBonjourServiceInternal, _hidl_cb, query, response);
+}
+
+Return<void> P2pIface::removeBonjourService(
+ const hidl_vec<uint8_t>& query, removeBonjourService_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::removeBonjourServiceInternal, _hidl_cb, query);
+}
+
+Return<void> P2pIface::addUpnpService(
+ uint32_t version, const hidl_string& service_name,
+ addUpnpService_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::addUpnpServiceInternal, _hidl_cb, version, service_name);
+}
+
+Return<void> P2pIface::removeUpnpService(
+ uint32_t version, const hidl_string& service_name,
+ removeUpnpService_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::removeUpnpServiceInternal, _hidl_cb, version,
+ service_name);
+}
+
+Return<void> P2pIface::flushServices(flushServices_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::flushServicesInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::requestServiceDiscovery(
+ const hidl_array<uint8_t, 6>& peer_address, const hidl_vec<uint8_t>& query,
+ requestServiceDiscovery_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::requestServiceDiscoveryInternal, _hidl_cb, peer_address,
+ query);
+}
+
+Return<void> P2pIface::cancelServiceDiscovery(
+ uint64_t identifier, cancelServiceDiscovery_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::cancelServiceDiscoveryInternal, _hidl_cb, identifier);
+}
+
+Return<void> P2pIface::setMiracastMode(
+ ISupplicantP2pIface::MiracastMode mode, setMiracastMode_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setMiracastModeInternal, _hidl_cb, mode);
+}
+
+Return<void> P2pIface::startWpsPbc(
+ const hidl_string& group_ifname, const hidl_array<uint8_t, 6>& bssid,
+ startWpsPbc_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::startWpsPbcInternal, _hidl_cb, group_ifname, bssid);
+}
+
+Return<void> P2pIface::startWpsPinKeypad(
+ const hidl_string& group_ifname, const hidl_string& pin,
+ startWpsPinKeypad_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::startWpsPinKeypadInternal, _hidl_cb, group_ifname, pin);
+}
+
+Return<void> P2pIface::startWpsPinDisplay(
+ const hidl_string& group_ifname, const hidl_array<uint8_t, 6>& bssid,
+ startWpsPinDisplay_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::startWpsPinDisplayInternal, _hidl_cb, group_ifname,
+ bssid);
+}
+
+Return<void> P2pIface::cancelWps(
+ const hidl_string& group_ifname, cancelWps_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::cancelWpsInternal, _hidl_cb, group_ifname);
+}
+
+Return<void> P2pIface::setWpsDeviceName(
+ const hidl_string& name, setWpsDeviceName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWpsDeviceNameInternal, _hidl_cb, name);
+}
+
+Return<void> P2pIface::setWpsDeviceType(
+ const hidl_array<uint8_t, 8>& type, setWpsDeviceType_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWpsDeviceTypeInternal, _hidl_cb, type);
+}
+
+Return<void> P2pIface::setWpsManufacturer(
+ const hidl_string& manufacturer, setWpsManufacturer_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWpsManufacturerInternal, _hidl_cb, manufacturer);
+}
+
+Return<void> P2pIface::setWpsModelName(
+ const hidl_string& model_name, setWpsModelName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWpsModelNameInternal, _hidl_cb, model_name);
+}
+
+Return<void> P2pIface::setWpsModelNumber(
+ const hidl_string& model_number, setWpsModelNumber_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWpsModelNumberInternal, _hidl_cb, model_number);
+}
+
+Return<void> P2pIface::setWpsSerialNumber(
+ const hidl_string& serial_number, setWpsSerialNumber_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWpsSerialNumberInternal, _hidl_cb, serial_number);
+}
+
+Return<void> P2pIface::setWpsConfigMethods(
+ uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWpsConfigMethodsInternal, _hidl_cb, config_methods);
+}
+
+Return<void> P2pIface::enableWfd(bool enable, enableWfd_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::enableWfdInternal, _hidl_cb, enable);
+}
+
+Return<void> P2pIface::setWfdDeviceInfo(
+ const hidl_array<uint8_t, 6>& info, setWfdDeviceInfo_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::setWfdDeviceInfoInternal, _hidl_cb, info);
+}
+
+Return<void> P2pIface::createNfcHandoverRequestMessage(
+ createNfcHandoverRequestMessage_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::createNfcHandoverRequestMessageInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::createNfcHandoverSelectMessage(
+ createNfcHandoverSelectMessage_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::createNfcHandoverSelectMessageInternal, _hidl_cb);
+}
+
+Return<void> P2pIface::reportNfcHandoverResponse(
+ const hidl_vec<uint8_t>& request, reportNfcHandoverResponse_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::reportNfcHandoverResponseInternal, _hidl_cb, request);
+}
+
+Return<void> P2pIface::reportNfcHandoverInitiation(
+ const hidl_vec<uint8_t>& select, reportNfcHandoverInitiation_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::reportNfcHandoverInitiationInternal, _hidl_cb, select);
+}
+
+Return<void> P2pIface::saveConfig(saveConfig_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::saveConfigInternal, _hidl_cb);
+}
+
+std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
+}
+
+std::pair<SupplicantStatus, IfaceType> P2pIface::getTypeInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::P2P};
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
+P2pIface::addNetworkInternal()
+{
+ android::sp<ISupplicantP2pNetwork> network;
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ struct wpa_ssid* ssid = wpa_supplicant_add_network(wpa_s);
+ if (!ssid) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
+ }
+ HidlManager* hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->getP2pNetworkHidlObjectByIfnameAndNetworkId(
+ wpa_s->ifname, ssid->id, &network)) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, network};
+}
+
+SupplicantStatus P2pIface::removeNetworkInternal(SupplicantNetworkId id)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
+ return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
+ }
+ if (result != 0) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
+P2pIface::getNetworkInternal(SupplicantNetworkId id)
+{
+ android::sp<ISupplicantP2pNetwork> network;
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ struct wpa_ssid* ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (!ssid) {
+ return {{SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""},
+ network};
+ }
+ HidlManager* hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->getP2pNetworkHidlObjectByIfnameAndNetworkId(
+ wpa_s->ifname, ssid->id, &network)) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, network};
+}
+
+std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
+P2pIface::listNetworksInternal()
+{
+ std::vector<SupplicantNetworkId> network_ids;
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ for (struct wpa_ssid* wpa_ssid = wpa_s->conf->ssid; wpa_ssid;
+ wpa_ssid = wpa_ssid->next) {
+ network_ids.emplace_back(wpa_ssid->id);
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, std::move(network_ids)};
+}
+
+SupplicantStatus P2pIface::registerCallbackInternal(
+ const sp<ISupplicantP2pIfaceCallback>& callback)
+{
+ HidlManager* hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->addP2pIfaceCallbackHidlObject(ifname_, callback)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+P2pIface::getDeviceAddressInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ std::array<uint8_t, 6> addr;
+ static_assert(ETH_ALEN == addr.size(), "Size mismatch");
+ os_memcpy(addr.data(), wpa_s->global->p2p_dev_addr, ETH_ALEN);
+ return {{SupplicantStatusCode::SUCCESS, ""}, addr};
+}
+
+SupplicantStatus P2pIface::setSsidPostfixInternal(
+ const std::vector<uint8_t>& postfix)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (p2p_set_ssid_postfix(
+ wpa_s->global->p2p, postfix.data(), postfix.size())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setGroupIdleInternal(
+ const std::string& group_ifname, uint32_t timeout_in_sec)
+{
+ struct wpa_supplicant* wpa_group_s =
+ retrieveGroupIfacePtr(group_ifname);
+ if (!wpa_group_s) {
+ return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+ wpa_group_s->conf->p2p_group_idle = timeout_in_sec;
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setPowerSaveInternal(
+ const std::string& group_ifname, bool enable)
+{
+ struct wpa_supplicant* wpa_group_s =
+ retrieveGroupIfacePtr(group_ifname);
+ if (!wpa_group_s) {
+ return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+ if (wpa_drv_set_p2p_powersave(wpa_group_s, enable, -1, -1)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::findInternal(uint32_t timeout_in_sec)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+ uint32_t search_delay = wpas_p2p_search_delay(wpa_s);
+ if (wpas_p2p_find(
+ wpa_s, timeout_in_sec, P2P_FIND_START_WITH_FULL, 0, nullptr,
+ nullptr, search_delay, 0, nullptr, 0)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::stopFindInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+ wpas_p2p_stop_find(wpa_s);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::flushInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ wpa_s->force_long_sd = 0;
+ wpas_p2p_stop_find(wpa_s);
+ wpa_s->parent->p2ps_method_config_any = 0;
+ if (wpa_s->global->p2p)
+ p2p_flush(wpa_s->global->p2p);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+// This method only implements support for subset (needed by Android framework)
+// of parameters that can be specified for connect.
+std::pair<SupplicantStatus, std::string> P2pIface::connectInternal(
+ const std::array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method,
+ const std::string& pre_selected_pin, bool join_existing_group,
+ bool persistent, uint32_t go_intent)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (go_intent > 15) {
+ return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}};
+ }
+ int go_intent_signed = join_existing_group ? -1 : go_intent;
+ p2p_wps_method wps_method = {};
+ switch (provision_method) {
+ case WpsProvisionMethod::PBC:
+ wps_method = WPS_PBC;
+ break;
+ case WpsProvisionMethod::DISPLAY:
+ wps_method = WPS_PIN_DISPLAY;
+ break;
+ case WpsProvisionMethod::KEYPAD:
+ wps_method = WPS_PIN_KEYPAD;
+ break;
+ }
+ const char* pin = pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
+ 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, false, false, VHT_CHANWIDTH_USE_HT, nullptr, 0);
+ if (new_pin < 0) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ std::string pin_ret;
+ if (provision_method == WpsProvisionMethod::DISPLAY &&
+ pre_selected_pin.empty()) {
+ pin_ret = misc_utils::convertWpsPinToString(new_pin);
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, pin_ret};
+}
+
+SupplicantStatus P2pIface::cancelConnectInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpas_p2p_cancel(wpa_s)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::provisionDiscoveryInternal(
+ const std::array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ p2ps_provision* prov_param;
+ const char* config_method_str = nullptr;
+ switch (provision_method) {
+ case WpsProvisionMethod::PBC:
+ config_method_str = kConfigMethodStrPbc;
+ break;
+ case WpsProvisionMethod::DISPLAY:
+ config_method_str = kConfigMethodStrDisplay;
+ break;
+ case WpsProvisionMethod::KEYPAD:
+ config_method_str = kConfigMethodStrKeypad;
+ break;
+ }
+ if (wpas_p2p_prov_disc(
+ wpa_s, peer_address.data(), config_method_str,
+ WPAS_P2P_PD_FOR_GO_NEG, nullptr)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::addGroupInternal(
+ bool persistent, SupplicantNetworkId persistent_network_id)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int vht = wpa_s->conf->p2p_go_vht;
+ int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ struct wpa_ssid* ssid =
+ wpa_config_get_network(wpa_s->conf, persistent_network_id);
+ if (ssid == NULL) {
+ if (wpas_p2p_group_add(
+ wpa_s, persistent, 0, 0, ht40, vht,
+ VHT_CHANWIDTH_USE_HT)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ } else {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+ } 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)) {
+ return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
+ ""};
+ } else {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+ }
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+SupplicantStatus P2pIface::removeGroupInternal(const std::string& group_ifname)
+{
+ struct wpa_supplicant* wpa_group_s =
+ retrieveGroupIfacePtr(group_ifname);
+ if (!wpa_group_s) {
+ return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+ if (wpas_p2p_group_remove(wpa_group_s, group_ifname.c_str())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::rejectInternal(
+ const std::array<uint8_t, 6>& peer_address)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+ if (wpas_p2p_reject(wpa_s, peer_address.data())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::inviteInternal(
+ const std::string& group_ifname,
+ const std::array<uint8_t, 6>& go_device_address,
+ const std::array<uint8_t, 6>& peer_address)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpas_p2p_invite_group(
+ wpa_s, group_ifname.c_str(), peer_address.data(),
+ go_device_address.data())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::reinvokeInternal(
+ SupplicantNetworkId persistent_network_id,
+ const std::array<uint8_t, 6>& peer_address)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ int vht = wpa_s->conf->p2p_go_vht;
+ int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ struct wpa_ssid* ssid =
+ wpa_config_get_network(wpa_s->conf, persistent_network_id);
+ if (ssid == NULL || ssid->disabled != 2) {
+ return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
+ }
+ if (wpas_p2p_invite(
+ wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
+ VHT_CHANWIDTH_USE_HT, 0)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::configureExtListenInternal(
+ uint32_t period_in_millis, uint32_t interval_in_millis)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpas_p2p_ext_listen(wpa_s, period_in_millis, interval_in_millis)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setListenChannelInternal(
+ uint32_t channel, uint32_t operating_class)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (p2p_set_listen_channel(
+ wpa_s->global->p2p, operating_class, channel, 1)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setDisallowedFrequenciesInternal(
+ const std::vector<FreqRange>& ranges)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ using DestT = struct wpa_freq_range_list::wpa_freq_range;
+ DestT* freq_ranges = nullptr;
+ // Empty ranges is used to enable all frequencies.
+ if (ranges.size() != 0) {
+ freq_ranges =
+ static_cast<DestT*>(os_malloc(sizeof(DestT) * ranges.size()));
+ if (!freq_ranges) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ uint32_t i = 0;
+ for (const auto& range : ranges) {
+ freq_ranges[i].min = range.min;
+ freq_ranges[i].max = range.max;
+ i++;
+ }
+ }
+
+ os_free(wpa_s->global->p2p_disallow_freq.range);
+ wpa_s->global->p2p_disallow_freq.range = freq_ranges;
+ wpa_s->global->p2p_disallow_freq.num = ranges.size();
+ wpas_p2p_update_channel_list(wpa_s, WPAS_P2P_CHANNEL_UPDATE_DISALLOW);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>> P2pIface::getSsidInternal(
+ const std::array<uint8_t, 6>& peer_address)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ const struct p2p_peer_info* info =
+ p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
+ if (!info) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ const struct p2p_device* dev =
+ reinterpret_cast<const struct p2p_device*>(
+ (reinterpret_cast<const uint8_t*>(info)) -
+ offsetof(struct p2p_device, info));
+ std::vector<uint8_t> ssid;
+ if (dev && dev->oper_ssid_len) {
+ ssid.assign(
+ dev->oper_ssid, dev->oper_ssid + dev->oper_ssid_len);
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, ssid};
+}
+
+std::pair<SupplicantStatus, uint32_t> P2pIface::getGroupCapabilityInternal(
+ const std::array<uint8_t, 6>& peer_address)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ const struct p2p_peer_info* info =
+ p2p_get_peer_info(wpa_s->global->p2p, peer_address.data(), 0);
+ if (!info) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, info->group_capab};
+}
+
+SupplicantStatus P2pIface::addBonjourServiceInternal(
+ const std::vector<uint8_t>& query, const std::vector<uint8_t>& response)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ auto query_buf = misc_utils::convertVectorToWpaBuf(query);
+ auto response_buf = misc_utils::convertVectorToWpaBuf(response);
+ if (!query_buf || !response_buf) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ if (wpas_p2p_service_add_bonjour(
+ wpa_s, query_buf.get(), response_buf.get())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ // If successful, the wpabuf is referenced internally and hence should
+ // not be freed.
+ query_buf.release();
+ response_buf.release();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::removeBonjourServiceInternal(
+ const std::vector<uint8_t>& query)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ auto query_buf = misc_utils::convertVectorToWpaBuf(query);
+ if (!query_buf) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ if (wpas_p2p_service_del_bonjour(wpa_s, query_buf.get())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::addUpnpServiceInternal(
+ uint32_t version, const std::string& service_name)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpas_p2p_service_add_upnp(wpa_s, version, service_name.c_str())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::removeUpnpServiceInternal(
+ uint32_t version, const std::string& service_name)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpas_p2p_service_del_upnp(wpa_s, version, service_name.c_str())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::flushServicesInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ wpas_p2p_service_flush(wpa_s);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, uint64_t> P2pIface::requestServiceDiscoveryInternal(
+ const std::array<uint8_t, 6>& peer_address,
+ const std::vector<uint8_t>& query)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ auto query_buf = misc_utils::convertVectorToWpaBuf(query);
+ if (!query_buf) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ const uint8_t* dst_addr = is_zero_ether_addr(peer_address.data())
+ ? nullptr
+ : peer_address.data();
+ uint64_t identifier =
+ wpas_p2p_sd_request(wpa_s, dst_addr, query_buf.get());
+ if (identifier == 0) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, identifier};
+}
+
+SupplicantStatus P2pIface::cancelServiceDiscoveryInternal(uint64_t identifier)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (wpas_p2p_sd_cancel_request(wpa_s, identifier)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setMiracastModeInternal(
+ ISupplicantP2pIface::MiracastMode mode)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ uint8_t mode_internal = convertHidlMiracastModeToInternal(mode);
+ const std::string cmd_str =
+ kSetMiracastMode + std::to_string(mode_internal);
+ std::vector<char> cmd(
+ cmd_str.c_str(), cmd_str.c_str() + cmd_str.size() + 1);
+ char driver_cmd_reply_buf[4096] = {};
+ if (wpa_drv_driver_cmd(
+ wpa_s, cmd.data(), driver_cmd_reply_buf,
+ sizeof(driver_cmd_reply_buf))) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::startWpsPbcInternal(
+ const std::string& group_ifname, const std::array<uint8_t, 6>& bssid)
+{
+ struct wpa_supplicant* wpa_group_s =
+ retrieveGroupIfacePtr(group_ifname);
+ if (!wpa_group_s) {
+ return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+ const uint8_t* bssid_addr =
+ is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
+#ifdef CONFIG_AP
+ if (wpa_group_s->ap_iface) {
+ if (wpa_supplicant_ap_wps_pbc(wpa_group_s, bssid_addr, NULL)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+#endif /* CONFIG_AP */
+ if (wpas_wps_start_pbc(wpa_group_s, bssid_addr, 0)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::startWpsPinKeypadInternal(
+ const std::string& group_ifname, const std::string& pin)
+{
+ struct wpa_supplicant* wpa_group_s =
+ retrieveGroupIfacePtr(group_ifname);
+ if (!wpa_group_s) {
+ return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+#ifdef CONFIG_AP
+ if (wpa_group_s->ap_iface) {
+ if (wpa_supplicant_ap_wps_pin(
+ wpa_group_s, nullptr, pin.c_str(), nullptr, 0, 0) < 0) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+#endif /* CONFIG_AP */
+ if (wpas_wps_start_pin(
+ wpa_group_s, nullptr, pin.c_str(), 0, DEV_PW_DEFAULT)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::string> P2pIface::startWpsPinDisplayInternal(
+ const std::string& group_ifname, const std::array<uint8_t, 6>& bssid)
+{
+ struct wpa_supplicant* wpa_group_s =
+ retrieveGroupIfacePtr(group_ifname);
+ if (!wpa_group_s) {
+ return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""}, ""};
+ }
+ const uint8_t* bssid_addr =
+ is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
+ int pin = wpas_wps_start_pin(
+ wpa_group_s, bssid_addr, nullptr, 0, DEV_PW_DEFAULT);
+ if (pin < 0) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, ""};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ misc_utils::convertWpsPinToString(pin)};
+}
+
+SupplicantStatus P2pIface::cancelWpsInternal(const std::string& group_ifname)
+{
+ struct wpa_supplicant* wpa_group_s =
+ retrieveGroupIfacePtr(group_ifname);
+ if (!wpa_group_s) {
+ return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
+ }
+ if (wpas_wps_cancel(wpa_group_s)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setWpsDeviceNameInternal(const std::string& name)
+{
+ return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
+}
+
+SupplicantStatus P2pIface::setWpsDeviceTypeInternal(
+ const std::array<uint8_t, 8>& type)
+{
+ return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
+}
+
+SupplicantStatus P2pIface::setWpsManufacturerInternal(
+ const std::string& manufacturer)
+{
+ return iface_config_utils::setWpsManufacturer(
+ retrieveIfacePtr(), manufacturer);
+}
+
+SupplicantStatus P2pIface::setWpsModelNameInternal(
+ const std::string& model_name)
+{
+ return iface_config_utils::setWpsModelName(
+ retrieveIfacePtr(), model_name);
+}
+
+SupplicantStatus P2pIface::setWpsModelNumberInternal(
+ const std::string& model_number)
+{
+ return iface_config_utils::setWpsModelNumber(
+ retrieveIfacePtr(), model_number);
+}
+
+SupplicantStatus P2pIface::setWpsSerialNumberInternal(
+ const std::string& serial_number)
+{
+ return iface_config_utils::setWpsSerialNumber(
+ retrieveIfacePtr(), serial_number);
+}
+
+SupplicantStatus P2pIface::setWpsConfigMethodsInternal(uint16_t config_methods)
+{
+ return iface_config_utils::setWpsConfigMethods(
+ retrieveIfacePtr(), config_methods);
+}
+
+SupplicantStatus P2pIface::enableWfdInternal(bool enable)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ wifi_display_enable(wpa_s->global, enable);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::setWfdDeviceInfoInternal(
+ const std::array<uint8_t, 6>& info)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ std::vector<char> wfd_device_info_hex(info.size() * 2 + 1);
+ wpa_snprintf_hex(
+ wfd_device_info_hex.data(), wfd_device_info_hex.size(), info.data(),
+ info.size());
+ // |wifi_display_subelem_set| expects the first 2 bytes
+ // to hold the lenght of the subelement. In this case it's
+ // fixed to 6, so prepend that.
+ std::string wfd_device_info_set_cmd_str =
+ std::to_string(kWfdDeviceInfoSubelemId) + " " +
+ kWfdDeviceInfoSubelemLenHexStr + wfd_device_info_hex.data();
+ std::vector<char> wfd_device_info_set_cmd(
+ wfd_device_info_set_cmd_str.c_str(),
+ wfd_device_info_set_cmd_str.c_str() +
+ wfd_device_info_set_cmd_str.size() + 1);
+ if (wifi_display_subelem_set(
+ wpa_s->global, wfd_device_info_set_cmd.data())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>>
+P2pIface::createNfcHandoverRequestMessageInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ auto buf = misc_utils::createWpaBufUniquePtr(
+ wpas_p2p_nfc_handover_req(wpa_s, 1));
+ if (!buf) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ misc_utils::convertWpaBufToVector(buf.get())};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>>
+P2pIface::createNfcHandoverSelectMessageInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ auto buf = misc_utils::createWpaBufUniquePtr(
+ wpas_p2p_nfc_handover_sel(wpa_s, 1, 0));
+ if (!buf) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ misc_utils::convertWpaBufToVector(buf.get())};
+}
+
+SupplicantStatus P2pIface::reportNfcHandoverResponseInternal(
+ const std::vector<uint8_t>& request)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ auto req = misc_utils::convertVectorToWpaBuf(request);
+ auto sel = misc_utils::convertVectorToWpaBuf(std::vector<uint8_t>{0});
+ if (!req || !sel) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+
+ if (wpas_p2p_nfc_report_handover(wpa_s, 0, req.get(), sel.get(), 0)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::reportNfcHandoverInitiationInternal(
+ const std::vector<uint8_t>& select)
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ auto req = misc_utils::convertVectorToWpaBuf(std::vector<uint8_t>{0});
+ auto sel = misc_utils::convertVectorToWpaBuf(select);
+ if (!req || !sel) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+
+ if (wpas_p2p_nfc_report_handover(wpa_s, 1, req.get(), sel.get(), 0)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus P2pIface::saveConfigInternal()
+{
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ if (!wpa_s->conf->update_config) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+/**
+ * Retrieve the underlying |wpa_supplicant| struct
+ * pointer for this iface.
+ * If the underlying iface is removed, then all RPC method calls on this object
+ * will return failure.
+ */
+wpa_supplicant* P2pIface::retrieveIfacePtr()
+{
+ return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
+}
+
+/**
+ * Retrieve the underlying |wpa_supplicant| struct
+ * pointer for this group iface.
+ */
+wpa_supplicant* P2pIface::retrieveGroupIfacePtr(const std::string& group_ifname)
+{
+ return wpa_supplicant_get_iface(wpa_global_, group_ifname.c_str());
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/p2p_iface.h b/wpa_supplicant/hidl/1.0/p2p_iface.h
new file mode 100644
index 0000000..4f4a79d
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/p2p_iface.h
@@ -0,0 +1,314 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_P2P_IFACE_H
+#define WPA_SUPPLICANT_HIDL_P2P_IFACE_H
+
+#include <array>
+#include <vector>
+
+#include <android-base/macros.h>
+
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "p2p/p2p.h"
+#include "p2p/p2p_i.h"
+#include "p2p_supplicant.h"
+#include "p2p_supplicant.h"
+#include "config.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Implementation of P2pIface hidl object. Each unique hidl
+ * object is used for control operations on a specific interface
+ * controlled by wpa_supplicant.
+ */
+class P2pIface
+ : public android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface
+{
+public:
+ P2pIface(struct wpa_global* wpa_global, const char ifname[]);
+ ~P2pIface() override = default;
+ // Refer to |StaIface::invalidate()|.
+ void invalidate();
+ bool isValid();
+
+ // Hidl methods exposed.
+ Return<void> getName(getName_cb _hidl_cb) override;
+ Return<void> getType(getType_cb _hidl_cb) override;
+ Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
+ Return<void> removeNetwork(
+ SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
+ Return<void> getNetwork(
+ SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
+ Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
+ Return<void> registerCallback(
+ const sp<ISupplicantP2pIfaceCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
+ Return<void> getDeviceAddress(getDeviceAddress_cb _hidl_cb) override;
+ Return<void> setSsidPostfix(
+ const hidl_vec<uint8_t>& postfix,
+ setSsidPostfix_cb _hidl_cb) override;
+ Return<void> setGroupIdle(
+ const hidl_string& group_ifname, uint32_t timeout_in_sec,
+ setGroupIdle_cb _hidl_cb) override;
+ Return<void> setPowerSave(
+ const hidl_string& group_ifname, bool enable,
+ setPowerSave_cb _hidl_cb) override;
+ Return<void> find(uint32_t timeout_in_sec, find_cb _hidl_cb) override;
+ Return<void> stopFind(stopFind_cb _hidl_cb) override;
+ Return<void> flush(flush_cb _hidl_cb) override;
+ Return<void> connect(
+ const hidl_array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method,
+ const hidl_string& pre_selected_pin, bool join_existing_group,
+ bool persistent, uint32_t go_intent, connect_cb _hidl_cb) override;
+ Return<void> cancelConnect(cancelConnect_cb _hidl_cb) override;
+ Return<void> provisionDiscovery(
+ const hidl_array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method,
+ provisionDiscovery_cb _hidl_cb) override;
+ Return<void> addGroup(
+ bool persistent, SupplicantNetworkId persistent_network_id,
+ addGroup_cb _hidl_cb) override;
+ Return<void> removeGroup(
+ const hidl_string& group_ifname, removeGroup_cb _hidl_cb) override;
+ Return<void> reject(
+ const hidl_array<uint8_t, 6>& peer_address,
+ reject_cb _hidl_cb) override;
+ Return<void> invite(
+ const hidl_string& group_ifname,
+ const hidl_array<uint8_t, 6>& go_device_address,
+ const hidl_array<uint8_t, 6>& peer_address,
+ invite_cb _hidl_cb) override;
+ Return<void> reinvoke(
+ SupplicantNetworkId persistent_network_id,
+ const hidl_array<uint8_t, 6>& peer_address,
+ reinvoke_cb _hidl_cb) override;
+ Return<void> configureExtListen(
+ uint32_t period_in_millis, uint32_t interval_in_millis,
+ configureExtListen_cb _hidl_cb) override;
+ Return<void> setListenChannel(
+ uint32_t channel, uint32_t operating_class,
+ setListenChannel_cb _hidl_cb) override;
+ Return<void> setDisallowedFrequencies(
+ const hidl_vec<FreqRange>& ranges,
+ setDisallowedFrequencies_cb _hidl_cb) override;
+ Return<void> getSsid(
+ const hidl_array<uint8_t, 6>& peer_address,
+ getSsid_cb _hidl_cb) override;
+ Return<void> getGroupCapability(
+ const hidl_array<uint8_t, 6>& peer_address,
+ getGroupCapability_cb _hidl_cb) override;
+ Return<void> addBonjourService(
+ const hidl_vec<uint8_t>& query, const hidl_vec<uint8_t>& response,
+ addBonjourService_cb _hidl_cb) override;
+ Return<void> removeBonjourService(
+ const hidl_vec<uint8_t>& query,
+ removeBonjourService_cb _hidl_cb) override;
+ Return<void> addUpnpService(
+ uint32_t version, const hidl_string& service_name,
+ addUpnpService_cb _hidl_cb) override;
+ Return<void> removeUpnpService(
+ uint32_t version, const hidl_string& service_name,
+ removeUpnpService_cb _hidl_cb) override;
+ Return<void> flushServices(flushServices_cb _hidl_cb) override;
+ Return<void> requestServiceDiscovery(
+ const hidl_array<uint8_t, 6>& peer_address,
+ const hidl_vec<uint8_t>& query,
+ requestServiceDiscovery_cb _hidl_cb) override;
+ Return<void> cancelServiceDiscovery(
+ uint64_t identifier, cancelServiceDiscovery_cb _hidl_cb) override;
+ Return<void> setMiracastMode(
+ ISupplicantP2pIface::MiracastMode mode,
+ setMiracastMode_cb _hidl_cb) override;
+ Return<void> startWpsPbc(
+ const hidl_string& groupIfName, const hidl_array<uint8_t, 6>& bssid,
+ startWpsPbc_cb _hidl_cb) override;
+ Return<void> startWpsPinKeypad(
+ const hidl_string& groupIfName, const hidl_string& pin,
+ startWpsPinKeypad_cb _hidl_cb) override;
+ Return<void> startWpsPinDisplay(
+ const hidl_string& groupIfName, const hidl_array<uint8_t, 6>& bssid,
+ startWpsPinDisplay_cb _hidl_cb) override;
+ Return<void> cancelWps(
+ const hidl_string& groupIfName, cancelWps_cb _hidl_cb) override;
+ Return<void> setWpsDeviceName(
+ const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
+ Return<void> setWpsDeviceType(
+ const hidl_array<uint8_t, 8>& type,
+ setWpsDeviceType_cb _hidl_cb) override;
+ Return<void> setWpsManufacturer(
+ const hidl_string& manufacturer,
+ setWpsManufacturer_cb _hidl_cb) override;
+ Return<void> setWpsModelName(
+ const hidl_string& model_name,
+ setWpsModelName_cb _hidl_cb) override;
+ Return<void> setWpsModelNumber(
+ const hidl_string& model_number,
+ setWpsModelNumber_cb _hidl_cb) override;
+ Return<void> setWpsSerialNumber(
+ const hidl_string& serial_number,
+ setWpsSerialNumber_cb _hidl_cb) override;
+ Return<void> setWpsConfigMethods(
+ uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb) override;
+ Return<void> enableWfd(bool enable, enableWfd_cb _hidl_cb) override;
+ Return<void> setWfdDeviceInfo(
+ const hidl_array<uint8_t, 6>& info,
+ setWfdDeviceInfo_cb _hidl_cb) override;
+ Return<void> createNfcHandoverRequestMessage(
+ createNfcHandoverRequestMessage_cb _hidl_cb) override;
+ Return<void> createNfcHandoverSelectMessage(
+ createNfcHandoverSelectMessage_cb _hidl_cb) override;
+ Return<void> reportNfcHandoverResponse(
+ const hidl_vec<uint8_t>& request,
+ reportNfcHandoverResponse_cb _hidl_cb) override;
+ Return<void> reportNfcHandoverInitiation(
+ const hidl_vec<uint8_t>& select,
+ reportNfcHandoverInitiation_cb _hidl_cb) override;
+ Return<void> saveConfig(saveConfig_cb _hidl_cb) override;
+
+private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<SupplicantStatus, std::string> getNameInternal();
+ std::pair<SupplicantStatus, IfaceType> getTypeInternal();
+ std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
+ addNetworkInternal();
+ SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
+ std::pair<SupplicantStatus, sp<ISupplicantP2pNetwork>>
+ getNetworkInternal(SupplicantNetworkId id);
+ std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
+ listNetworksInternal();
+ SupplicantStatus registerCallbackInternal(
+ const sp<ISupplicantP2pIfaceCallback>& callback);
+ std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+ getDeviceAddressInternal();
+ SupplicantStatus setSsidPostfixInternal(
+ const std::vector<uint8_t>& postfix);
+ SupplicantStatus setGroupIdleInternal(
+ const std::string& group_ifname, uint32_t timeout_in_sec);
+ SupplicantStatus setPowerSaveInternal(
+ const std::string& group_ifname, bool enable);
+ SupplicantStatus findInternal(uint32_t timeout_in_sec);
+ SupplicantStatus stopFindInternal();
+ SupplicantStatus flushInternal();
+ std::pair<SupplicantStatus, std::string> connectInternal(
+ const std::array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method,
+ const std::string& pre_selected_pin, bool join_existing_group,
+ bool persistent, uint32_t go_intent);
+ SupplicantStatus cancelConnectInternal();
+ SupplicantStatus provisionDiscoveryInternal(
+ const std::array<uint8_t, 6>& peer_address,
+ ISupplicantP2pIface::WpsProvisionMethod provision_method);
+ SupplicantStatus addGroupInternal(
+ bool persistent, SupplicantNetworkId persistent_network_id);
+ SupplicantStatus removeGroupInternal(const std::string& group_ifname);
+ SupplicantStatus rejectInternal(
+ const std::array<uint8_t, 6>& peer_address);
+ SupplicantStatus inviteInternal(
+ const std::string& group_ifname,
+ const std::array<uint8_t, 6>& go_device_address,
+ const std::array<uint8_t, 6>& peer_address);
+ SupplicantStatus reinvokeInternal(
+ SupplicantNetworkId persistent_network_id,
+ const std::array<uint8_t, 6>& peer_address);
+ SupplicantStatus configureExtListenInternal(
+ uint32_t period_in_millis, uint32_t interval_in_millis);
+ SupplicantStatus setListenChannelInternal(
+ uint32_t channel, uint32_t operating_class);
+ SupplicantStatus setDisallowedFrequenciesInternal(
+ const std::vector<FreqRange>& ranges);
+ std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal(
+ const std::array<uint8_t, 6>& peer_address);
+ std::pair<SupplicantStatus, uint32_t> getGroupCapabilityInternal(
+ const std::array<uint8_t, 6>& peer_address);
+ SupplicantStatus addBonjourServiceInternal(
+ const std::vector<uint8_t>& query,
+ const std::vector<uint8_t>& response);
+ SupplicantStatus removeBonjourServiceInternal(
+ const std::vector<uint8_t>& query);
+ SupplicantStatus addUpnpServiceInternal(
+ uint32_t version, const std::string& service_name);
+ SupplicantStatus removeUpnpServiceInternal(
+ uint32_t version, const std::string& service_name);
+ SupplicantStatus flushServicesInternal();
+ std::pair<SupplicantStatus, uint64_t> requestServiceDiscoveryInternal(
+ const std::array<uint8_t, 6>& peer_address,
+ const std::vector<uint8_t>& query);
+ SupplicantStatus cancelServiceDiscoveryInternal(uint64_t identifier);
+ SupplicantStatus setMiracastModeInternal(
+ ISupplicantP2pIface::MiracastMode mode);
+ SupplicantStatus startWpsPbcInternal(
+ const std::string& group_ifname,
+ const std::array<uint8_t, 6>& bssid);
+ SupplicantStatus startWpsPinKeypadInternal(
+ const std::string& group_ifname, const std::string& pin);
+ std::pair<SupplicantStatus, std::string> startWpsPinDisplayInternal(
+ const std::string& group_ifname,
+ const std::array<uint8_t, 6>& bssid);
+ SupplicantStatus cancelWpsInternal(const std::string& group_ifname);
+ SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
+ SupplicantStatus setWpsDeviceTypeInternal(
+ const std::array<uint8_t, 8>& type);
+ SupplicantStatus setWpsManufacturerInternal(
+ const std::string& manufacturer);
+ SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
+ SupplicantStatus setWpsModelNumberInternal(
+ const std::string& model_number);
+ SupplicantStatus setWpsSerialNumberInternal(
+ const std::string& serial_number);
+ SupplicantStatus setWpsConfigMethodsInternal(uint16_t config_methods);
+ SupplicantStatus enableWfdInternal(bool enable);
+ SupplicantStatus setWfdDeviceInfoInternal(
+ const std::array<uint8_t, 6>& info);
+ std::pair<SupplicantStatus, std::vector<uint8_t>>
+ createNfcHandoverRequestMessageInternal();
+ std::pair<SupplicantStatus, std::vector<uint8_t>>
+ createNfcHandoverSelectMessageInternal();
+ SupplicantStatus reportNfcHandoverResponseInternal(
+ const std::vector<uint8_t>& request);
+ SupplicantStatus reportNfcHandoverInitiationInternal(
+ const std::vector<uint8_t>& select);
+ SupplicantStatus saveConfigInternal();
+
+ struct wpa_supplicant* retrieveIfacePtr();
+ struct wpa_supplicant* retrieveGroupIfacePtr(
+ const std::string& group_ifname);
+
+ // Reference to the global wpa_struct. This is assumed to be valid for
+ // the lifetime of the process.
+ struct wpa_global* wpa_global_;
+ // Name of the iface this hidl object controls
+ const std::string ifname_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(P2pIface);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
+
+#endif // WPA_SUPPLICANT_HIDL_P2P_IFACE_H
diff --git a/wpa_supplicant/hidl/1.0/p2p_network.cpp b/wpa_supplicant/hidl/1.0/p2p_network.cpp
new file mode 100644
index 0000000..7daa453
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/p2p_network.cpp
@@ -0,0 +1,257 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "hidl_manager.h"
+#include "hidl_return_util.h"
+#include "p2p_network.h"
+
+extern "C" {
+#include "config_ssid.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+P2pNetwork::P2pNetwork(
+ struct wpa_global *wpa_global, const char ifname[], int network_id)
+ : wpa_global_(wpa_global),
+ ifname_(ifname),
+ network_id_(network_id),
+ is_valid_(true)
+{
+}
+
+void P2pNetwork::invalidate() { is_valid_ = false; }
+bool P2pNetwork::isValid()
+{
+ return (is_valid_ && (retrieveNetworkPtr() != nullptr));
+}
+
+Return<void> P2pNetwork::getId(getId_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::getIdInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::getInterfaceName(getInterfaceName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::getInterfaceNameInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::getType(getType_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::getTypeInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::registerCallback(
+ const sp<ISupplicantP2pNetworkCallback> &callback,
+ registerCallback_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::registerCallbackInternal, _hidl_cb, callback);
+}
+
+Return<void> P2pNetwork::getSsid(getSsid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::getSsidInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::getBssid(getBssid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::getBssidInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::isCurrent(isCurrent_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::isCurrentInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::isPersistent(isPersistent_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::isPersistentInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::isGo(isGo_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::isGoInternal, _hidl_cb);
+}
+
+Return<void> P2pNetwork::setClientList(
+ const hidl_vec<hidl_array<uint8_t, 6>> &clients, setClientList_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::setClientListInternal, _hidl_cb, clients);
+}
+
+Return<void> P2pNetwork::getClientList(getClientList_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &P2pNetwork::getClientListInternal, _hidl_cb);
+}
+
+std::pair<SupplicantStatus, uint32_t> P2pNetwork::getIdInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
+}
+
+std::pair<SupplicantStatus, std::string> P2pNetwork::getInterfaceNameInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
+}
+
+std::pair<SupplicantStatus, IfaceType> P2pNetwork::getTypeInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::P2P};
+}
+
+SupplicantStatus P2pNetwork::registerCallbackInternal(
+ const sp<ISupplicantP2pNetworkCallback> &callback)
+{
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->addP2pNetworkCallbackHidlObject(
+ ifname_, network_id_, callback)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>> P2pNetwork::getSsidInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ {wpa_ssid->ssid, wpa_ssid->ssid + wpa_ssid->ssid_len}};
+}
+
+std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+P2pNetwork::getBssidInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ std::array<uint8_t, 6> bssid{};
+ if (wpa_ssid->bssid_set) {
+ os_memcpy(bssid.data(), wpa_ssid->bssid, ETH_ALEN);
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, bssid};
+}
+
+std::pair<SupplicantStatus, bool> P2pNetwork::isCurrentInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ (wpa_s->current_ssid == wpa_ssid)};
+}
+
+std::pair<SupplicantStatus, bool> P2pNetwork::isPersistentInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""}, (wpa_ssid->disabled == 2)};
+}
+
+std::pair<SupplicantStatus, bool> P2pNetwork::isGoInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ (wpa_ssid->mode == wpa_ssid::wpas_mode::WPAS_MODE_P2P_GO)};
+}
+
+SupplicantStatus P2pNetwork::setClientListInternal(
+ const std::vector<hidl_array<uint8_t, 6>> &clients)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ os_free(wpa_ssid->p2p_client_list);
+ // Internal representation uses a generic MAC addr/mask storage format
+ // (even though the mask is always 0xFF'ed for p2p_client_list). So, the
+ // first 6 bytes holds the client MAC address and the next 6 bytes are
+ // OxFF'ed.
+ wpa_ssid->p2p_client_list =
+ (u8 *)os_malloc(ETH_ALEN * 2 * clients.size());
+ if (!wpa_ssid->p2p_client_list) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ u8 *list = wpa_ssid->p2p_client_list;
+ for (const auto &client : clients) {
+ os_memcpy(list, client.data(), ETH_ALEN);
+ list += ETH_ALEN;
+ os_memset(list, 0xFF, ETH_ALEN);
+ list += ETH_ALEN;
+ }
+ wpa_ssid->num_p2p_clients = clients.size();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::vector<hidl_array<uint8_t, 6>>>
+P2pNetwork::getClientListInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->p2p_client_list) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ std::vector<hidl_array<uint8_t, 6>> clients;
+ u8 *list = wpa_ssid->p2p_client_list;
+ for (size_t i = 0; i < wpa_ssid->num_p2p_clients; i++) {
+ clients.emplace_back(list);
+ list += 2 * ETH_ALEN;
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, clients};
+}
+
+/**
+ * Retrieve the underlying |wpa_ssid| struct pointer for
+ * this network.
+ * If the underlying network is removed or the interface
+ * this network belong to is removed, all RPC method calls
+ * on this object will return failure.
+ */
+struct wpa_ssid *P2pNetwork::retrieveNetworkPtr()
+{
+ wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (!wpa_s)
+ return nullptr;
+ return wpa_config_get_network(wpa_s->conf, network_id_);
+}
+
+/**
+ * Retrieve the underlying |wpa_supplicant| struct
+ * pointer for this network.
+ */
+struct wpa_supplicant *P2pNetwork::retrieveIfacePtr()
+{
+ return wpa_supplicant_get_iface(
+ (struct wpa_global *)wpa_global_, ifname_.c_str());
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/p2p_network.h b/wpa_supplicant/hidl/1.0/p2p_network.h
new file mode 100644
index 0000000..6164f43
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/p2p_network.h
@@ -0,0 +1,102 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
+#define WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
+
+#include <android-base/macros.h>
+
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetworkCallback.h>
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "wpa_supplicant_i.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Implementation of P2pNetwork hidl object. Each unique hidl
+ * object is used for control operations on a specific network
+ * controlled by wpa_supplicant.
+ */
+class P2pNetwork : public ISupplicantP2pNetwork
+{
+public:
+ P2pNetwork(
+ struct wpa_global* wpa_global, const char ifname[], int network_id);
+ ~P2pNetwork() override = default;
+ // Refer to |StaIface::invalidate()|.
+ void invalidate();
+ bool isValid();
+
+ // Hidl methods exposed.
+ Return<void> getId(getId_cb _hidl_cb) override;
+ Return<void> getInterfaceName(getInterfaceName_cb _hidl_cb) override;
+ Return<void> getType(getType_cb _hidl_cb) override;
+ Return<void> registerCallback(
+ const sp<ISupplicantP2pNetworkCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
+ Return<void> getSsid(getSsid_cb _hidl_cb) override;
+ Return<void> getBssid(getBssid_cb _hidl_cb) override;
+ Return<void> isCurrent(isCurrent_cb _hidl_cb) override;
+ Return<void> isPersistent(isPersistent_cb _hidl_cb) override;
+ Return<void> isGo(isGo_cb _hidl_cb) override;
+ Return<void> setClientList(
+ const hidl_vec<hidl_array<uint8_t, 6>>& clients,
+ setClientList_cb _hidl_cb) override;
+ Return<void> getClientList(getClientList_cb _hidl_cb) override;
+
+private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<SupplicantStatus, uint32_t> getIdInternal();
+ std::pair<SupplicantStatus, std::string> getInterfaceNameInternal();
+ std::pair<SupplicantStatus, IfaceType> getTypeInternal();
+ SupplicantStatus registerCallbackInternal(
+ const sp<ISupplicantP2pNetworkCallback>& callback);
+ std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
+ std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
+ std::pair<SupplicantStatus, bool> isCurrentInternal();
+ std::pair<SupplicantStatus, bool> isPersistentInternal();
+ std::pair<SupplicantStatus, bool> isGoInternal();
+ SupplicantStatus setClientListInternal(
+ const std::vector<hidl_array<uint8_t, 6>>& clients);
+ std::pair<SupplicantStatus, std::vector<hidl_array<uint8_t, 6>>>
+ getClientListInternal();
+
+ struct wpa_ssid* retrieveNetworkPtr();
+ struct wpa_supplicant* retrieveIfacePtr();
+
+ // Reference to the global wpa_struct. This is assumed to be valid
+ // for the lifetime of the process.
+ const struct wpa_global* wpa_global_;
+ // Name of the iface this network belongs to.
+ const std::string ifname_;
+ // Id of the network this hidl object controls.
+ const int network_id_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(P2pNetwork);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
+
+#endif // WPA_SUPPLICANT_HIDL_P2P_NETWORK_H
diff --git a/wpa_supplicant/hidl/1.0/sta_iface.cpp b/wpa_supplicant/hidl/1.0/sta_iface.cpp
new file mode 100644
index 0000000..8498e69
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/sta_iface.cpp
@@ -0,0 +1,1020 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "hidl_manager.h"
+#include "hidl_return_util.h"
+#include "iface_config_utils.h"
+#include "misc_utils.h"
+#include "sta_iface.h"
+
+extern "C" {
+#include "utils/eloop.h"
+#include "gas_query.h"
+#include "interworking.h"
+#include "hs20_supplicant.h"
+#include "wps_supplicant.h"
+}
+
+namespace {
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager;
+
+constexpr uint32_t kMaxAnqpElems = 100;
+constexpr char kGetMacAddress[] = "MACADDR";
+constexpr char kStartRxFilter[] = "RXFILTER-START";
+constexpr char kStopRxFilter[] = "RXFILTER-STOP";
+constexpr char kAddRxFilter[] = "RXFILTER-ADD";
+constexpr char kRemoveRxFilter[] = "RXFILTER-REMOVE";
+constexpr char kSetBtCoexistenceMode[] = "BTCOEXMODE";
+constexpr char kSetBtCoexistenceScanStart[] = "BTCOEXSCAN-START";
+constexpr char kSetBtCoexistenceScanStop[] = "BTCOEXSCAN-STOP";
+constexpr char kSetSupendModeEnabled[] = "SETSUSPENDMODE 1";
+constexpr char kSetSupendModeDisabled[] = "SETSUSPENDMODE 0";
+constexpr char kSetCountryCode[] = "COUNTRY";
+constexpr uint32_t kExtRadioWorkDefaultTimeoutInSec = static_cast<uint32_t>(
+ ISupplicantStaIface::ExtRadioWorkDefaults::TIMEOUT_IN_SECS);
+constexpr char kExtRadioWorkNamePrefix[] = "ext:";
+
+uint8_t convertHidlRxFilterTypeToInternal(
+ ISupplicantStaIface::RxFilterType type)
+{
+ switch (type) {
+ case ISupplicantStaIface::RxFilterType::V4_MULTICAST:
+ return 2;
+ case ISupplicantStaIface::RxFilterType::V6_MULTICAST:
+ return 3;
+ };
+ WPA_ASSERT(false);
+}
+
+uint8_t convertHidlBtCoexModeToInternal(
+ ISupplicantStaIface::BtCoexistenceMode mode)
+{
+ switch (mode) {
+ case ISupplicantStaIface::BtCoexistenceMode::ENABLED:
+ return 0;
+ case ISupplicantStaIface::BtCoexistenceMode::DISABLED:
+ return 1;
+ case ISupplicantStaIface::BtCoexistenceMode::SENSE:
+ return 2;
+ };
+ WPA_ASSERT(false);
+}
+
+SupplicantStatus doZeroArgDriverCommand(
+ struct wpa_supplicant *wpa_s, const char *cmd)
+{
+ std::vector<char> cmd_vec(cmd, cmd + strlen(cmd) + 1);
+ char driver_cmd_reply_buf[4096] = {};
+ if (wpa_drv_driver_cmd(
+ wpa_s, cmd_vec.data(), driver_cmd_reply_buf,
+ sizeof(driver_cmd_reply_buf))) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus doOneArgDriverCommand(
+ struct wpa_supplicant *wpa_s, const char *cmd, uint8_t arg)
+{
+ std::string cmd_str = std::string(cmd) + " " + std::to_string(arg);
+ return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
+}
+
+SupplicantStatus doOneArgDriverCommand(
+ struct wpa_supplicant *wpa_s, const char *cmd, const std::string &arg)
+{
+ std::string cmd_str = std::string(cmd) + " " + arg;
+ return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
+}
+
+void endExtRadioWork(struct wpa_radio_work *work)
+{
+ auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+ work->wpa_s->ext_work_in_progress = 0;
+ radio_work_done(work);
+ os_free(ework);
+}
+
+void extRadioWorkTimeoutCb(void *eloop_ctx, void *timeout_ctx)
+{
+ auto *work = static_cast<struct wpa_radio_work *>(eloop_ctx);
+ auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+ wpa_dbg(
+ work->wpa_s, MSG_DEBUG, "Timing out external radio work %u (%s)",
+ ework->id, work->type);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ WPA_ASSERT(hidl_manager);
+ hidl_manager->notifyExtRadioWorkTimeout(work->wpa_s, ework->id);
+
+ endExtRadioWork(work);
+}
+
+void startExtRadioWork(struct wpa_radio_work *work)
+{
+ auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+ work->wpa_s->ext_work_in_progress = 1;
+ if (!ework->timeout) {
+ ework->timeout = kExtRadioWorkDefaultTimeoutInSec;
+ }
+ eloop_register_timeout(
+ ework->timeout, 0, extRadioWorkTimeoutCb, work, nullptr);
+}
+
+void extRadioWorkStartCb(struct wpa_radio_work *work, int deinit)
+{
+ // deinit==1 is invoked during interface removal. Since the HIDL
+ // interface does not support interface addition/removal, we don't
+ // need to handle this scenario.
+ WPA_ASSERT(!deinit);
+
+ auto *ework = static_cast<struct wpa_external_work *>(work->ctx);
+ wpa_dbg(
+ work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
+ ework->id, ework->type);
+
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ WPA_ASSERT(hidl_manager);
+ hidl_manager->notifyExtRadioWorkStart(work->wpa_s, ework->id);
+
+ startExtRadioWork(work);
+}
+
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+StaIface::StaIface(struct wpa_global *wpa_global, const char ifname[])
+ : wpa_global_(wpa_global), ifname_(ifname), is_valid_(true)
+{
+}
+
+void StaIface::invalidate() { is_valid_ = false; }
+bool StaIface::isValid()
+{
+ return (is_valid_ && (retrieveIfacePtr() != nullptr));
+}
+
+Return<void> StaIface::getName(getName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::getNameInternal, _hidl_cb);
+}
+
+Return<void> StaIface::getType(getType_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::getTypeInternal, _hidl_cb);
+}
+
+Return<void> StaIface::addNetwork(addNetwork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::addNetworkInternal, _hidl_cb);
+}
+
+Return<void> StaIface::removeNetwork(
+ SupplicantNetworkId id, removeNetwork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::removeNetworkInternal, _hidl_cb, id);
+}
+
+Return<void> StaIface::getNetwork(
+ SupplicantNetworkId id, getNetwork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::getNetworkInternal, _hidl_cb, id);
+}
+
+Return<void> StaIface::listNetworks(listNetworks_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::listNetworksInternal, _hidl_cb);
+}
+
+Return<void> StaIface::registerCallback(
+ const sp<ISupplicantStaIfaceCallback> &callback,
+ registerCallback_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::registerCallbackInternal, _hidl_cb, callback);
+}
+
+Return<void> StaIface::reassociate(reassociate_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::reassociateInternal, _hidl_cb);
+}
+
+Return<void> StaIface::reconnect(reconnect_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::reconnectInternal, _hidl_cb);
+}
+
+Return<void> StaIface::disconnect(disconnect_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::disconnectInternal, _hidl_cb);
+}
+
+Return<void> StaIface::setPowerSave(bool enable, setPowerSave_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setPowerSaveInternal, _hidl_cb, enable);
+}
+
+Return<void> StaIface::initiateTdlsDiscover(
+ const hidl_array<uint8_t, 6> &mac_address, initiateTdlsDiscover_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::initiateTdlsDiscoverInternal, _hidl_cb, mac_address);
+}
+
+Return<void> StaIface::initiateTdlsSetup(
+ const hidl_array<uint8_t, 6> &mac_address, initiateTdlsSetup_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::initiateTdlsSetupInternal, _hidl_cb, mac_address);
+}
+
+Return<void> StaIface::initiateTdlsTeardown(
+ const hidl_array<uint8_t, 6> &mac_address, initiateTdlsTeardown_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::initiateTdlsTeardownInternal, _hidl_cb, mac_address);
+}
+Return<void> StaIface::initiateAnqpQuery(
+ const hidl_array<uint8_t, 6> &mac_address,
+ const hidl_vec<ISupplicantStaIface::AnqpInfoId> &info_elements,
+ const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes> &sub_types,
+ initiateAnqpQuery_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::initiateAnqpQueryInternal, _hidl_cb, mac_address,
+ info_elements, sub_types);
+}
+
+Return<void> StaIface::initiateHs20IconQuery(
+ const hidl_array<uint8_t, 6> &mac_address, const hidl_string &file_name,
+ initiateHs20IconQuery_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::initiateHs20IconQueryInternal, _hidl_cb, mac_address,
+ file_name);
+}
+
+Return<void> StaIface::getMacAddress(getMacAddress_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::getMacAddressInternal, _hidl_cb);
+}
+
+Return<void> StaIface::startRxFilter(startRxFilter_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::startRxFilterInternal, _hidl_cb);
+}
+
+Return<void> StaIface::stopRxFilter(stopRxFilter_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::stopRxFilterInternal, _hidl_cb);
+}
+
+Return<void> StaIface::addRxFilter(
+ ISupplicantStaIface::RxFilterType type, addRxFilter_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::addRxFilterInternal, _hidl_cb, type);
+}
+
+Return<void> StaIface::removeRxFilter(
+ ISupplicantStaIface::RxFilterType type, removeRxFilter_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::removeRxFilterInternal, _hidl_cb, type);
+}
+
+Return<void> StaIface::setBtCoexistenceMode(
+ ISupplicantStaIface::BtCoexistenceMode mode,
+ setBtCoexistenceMode_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setBtCoexistenceModeInternal, _hidl_cb, mode);
+}
+
+Return<void> StaIface::setBtCoexistenceScanModeEnabled(
+ bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setBtCoexistenceScanModeEnabledInternal, _hidl_cb,
+ enable);
+}
+
+Return<void> StaIface::setSuspendModeEnabled(
+ bool enable, setSuspendModeEnabled_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setSuspendModeEnabledInternal, _hidl_cb, enable);
+}
+
+Return<void> StaIface::setCountryCode(
+ const hidl_array<int8_t, 2> &code, setCountryCode_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setCountryCodeInternal, _hidl_cb, code);
+}
+
+Return<void> StaIface::startWpsRegistrar(
+ const hidl_array<uint8_t, 6> &bssid, const hidl_string &pin,
+ startWpsRegistrar_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::startWpsRegistrarInternal, _hidl_cb, bssid, pin);
+}
+
+Return<void> StaIface::startWpsPbc(
+ const hidl_array<uint8_t, 6> &bssid, startWpsPbc_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::startWpsPbcInternal, _hidl_cb, bssid);
+}
+
+Return<void> StaIface::startWpsPinKeypad(
+ const hidl_string &pin, startWpsPinKeypad_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::startWpsPinKeypadInternal, _hidl_cb, pin);
+}
+
+Return<void> StaIface::startWpsPinDisplay(
+ const hidl_array<uint8_t, 6> &bssid, startWpsPinDisplay_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::startWpsPinDisplayInternal, _hidl_cb, bssid);
+}
+
+Return<void> StaIface::cancelWps(cancelWps_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::cancelWpsInternal, _hidl_cb);
+}
+
+Return<void> StaIface::setWpsDeviceName(
+ const hidl_string &name, setWpsDeviceName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setWpsDeviceNameInternal, _hidl_cb, name);
+}
+
+Return<void> StaIface::setWpsDeviceType(
+ const hidl_array<uint8_t, 8> &type, setWpsDeviceType_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setWpsDeviceTypeInternal, _hidl_cb, type);
+}
+
+Return<void> StaIface::setWpsManufacturer(
+ const hidl_string &manufacturer, setWpsManufacturer_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setWpsManufacturerInternal, _hidl_cb, manufacturer);
+}
+
+Return<void> StaIface::setWpsModelName(
+ const hidl_string &model_name, setWpsModelName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setWpsModelNameInternal, _hidl_cb, model_name);
+}
+
+Return<void> StaIface::setWpsModelNumber(
+ const hidl_string &model_number, setWpsModelNumber_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setWpsModelNumberInternal, _hidl_cb, model_number);
+}
+
+Return<void> StaIface::setWpsSerialNumber(
+ const hidl_string &serial_number, setWpsSerialNumber_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setWpsSerialNumberInternal, _hidl_cb, serial_number);
+}
+
+Return<void> StaIface::setWpsConfigMethods(
+ uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setWpsConfigMethodsInternal, _hidl_cb, config_methods);
+}
+
+Return<void> StaIface::setExternalSim(
+ bool useExternalSim, setExternalSim_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::setExternalSimInternal, _hidl_cb, useExternalSim);
+}
+
+Return<void> StaIface::addExtRadioWork(
+ const hidl_string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec,
+ addExtRadioWork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::addExtRadioWorkInternal, _hidl_cb, name, freq_in_mhz,
+ timeout_in_sec);
+}
+
+Return<void> StaIface::removeExtRadioWork(
+ uint32_t id, removeExtRadioWork_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::removeExtRadioWorkInternal, _hidl_cb, id);
+}
+
+Return<void> StaIface::enableAutoReconnect(
+ bool enable, enableAutoReconnect_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &StaIface::enableAutoReconnectInternal, _hidl_cb, enable);
+}
+
+std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
+}
+
+std::pair<SupplicantStatus, IfaceType> StaIface::getTypeInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
+StaIface::addNetworkInternal()
+{
+ android::sp<ISupplicantStaNetwork> network;
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
+ if (!ssid) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
+ }
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
+ wpa_s->ifname, ssid->id, &network)) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, network};
+}
+
+SupplicantStatus StaIface::removeNetworkInternal(SupplicantNetworkId id)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ int result = wpa_supplicant_remove_network(wpa_s, id);
+ if (result == -1) {
+ return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
+ }
+ if (result != 0) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
+StaIface::getNetworkInternal(SupplicantNetworkId id)
+{
+ android::sp<ISupplicantStaNetwork> network;
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (!ssid) {
+ return {{SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""},
+ network};
+ }
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
+ wpa_s->ifname, ssid->id, &network)) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, network};
+}
+
+std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
+StaIface::listNetworksInternal()
+{
+ std::vector<SupplicantNetworkId> network_ids;
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ for (struct wpa_ssid *wpa_ssid = wpa_s->conf->ssid; wpa_ssid;
+ wpa_ssid = wpa_ssid->next) {
+ network_ids.emplace_back(wpa_ssid->id);
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, std::move(network_ids)};
+}
+
+SupplicantStatus StaIface::registerCallbackInternal(
+ const sp<ISupplicantStaIfaceCallback> &callback)
+{
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->addStaIfaceCallbackHidlObject(ifname_, callback)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::reassociateInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+ wpas_request_connection(wpa_s);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::reconnectInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+ if (!wpa_s->disconnected) {
+ return {SupplicantStatusCode::FAILURE_IFACE_NOT_DISCONNECTED,
+ ""};
+ }
+ wpas_request_connection(wpa_s);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::disconnectInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+ wpas_request_disconnection(wpa_s);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::setPowerSaveInternal(bool enable)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+ }
+ if (wpa_drv_set_p2p_powersave(wpa_s, enable, -1, -1)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::initiateTdlsDiscoverInternal(
+ const std::array<uint8_t, 6> &mac_address)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ int ret;
+ const u8 *peer = mac_address.data();
+ if (wpa_tdls_is_external_setup(wpa_s->wpa)) {
+ ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+ } else {
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+ }
+ if (ret) {
+ wpa_printf(MSG_INFO, "StaIface: TDLS discover failed: %d", ret);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::initiateTdlsSetupInternal(
+ const std::array<uint8_t, 6> &mac_address)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ int ret;
+ const u8 *peer = mac_address.data();
+ if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
+ !(wpa_s->conf->tdls_external_control)) {
+ wpa_tdls_remove(wpa_s->wpa, peer);
+ ret = wpa_tdls_start(wpa_s->wpa, peer);
+ } else {
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+ }
+ if (ret) {
+ wpa_printf(MSG_INFO, "StaIface: TDLS setup failed: %d", ret);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::initiateTdlsTeardownInternal(
+ const std::array<uint8_t, 6> &mac_address)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ int ret;
+ const u8 *peer = mac_address.data();
+ if (wpa_tdls_is_external_setup(wpa_s->wpa) &&
+ !(wpa_s->conf->tdls_external_control)) {
+ ret = wpa_tdls_teardown_link(
+ wpa_s->wpa, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ } else {
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+ }
+ if (ret) {
+ wpa_printf(MSG_INFO, "StaIface: TDLS teardown failed: %d", ret);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::initiateAnqpQueryInternal(
+ const std::array<uint8_t, 6> &mac_address,
+ const std::vector<ISupplicantStaIface::AnqpInfoId> &info_elements,
+ const std::vector<ISupplicantStaIface::Hs20AnqpSubtypes> &sub_types)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (info_elements.size() > kMaxAnqpElems) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ uint16_t info_elems_buf[kMaxAnqpElems];
+ uint32_t num_info_elems = 0;
+ for (const auto &info_element : info_elements) {
+ info_elems_buf[num_info_elems++] =
+ static_cast<std::underlying_type<
+ ISupplicantStaIface::AnqpInfoId>::type>(info_element);
+ }
+ uint32_t sub_types_bitmask = 0;
+ for (const auto &type : sub_types) {
+ sub_types_bitmask |= BIT(
+ static_cast<std::underlying_type<
+ ISupplicantStaIface::Hs20AnqpSubtypes>::type>(type));
+ }
+ if (anqp_send_req(
+ wpa_s, mac_address.data(), info_elems_buf, num_info_elems,
+ sub_types_bitmask, false)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::initiateHs20IconQueryInternal(
+ const std::array<uint8_t, 6> &mac_address, const std::string &file_name)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ wpa_s->fetch_osu_icon_in_progress = 0;
+ if (hs20_anqp_send_req(
+ wpa_s, mac_address.data(), BIT(HS20_STYPE_ICON_REQUEST),
+ reinterpret_cast<const uint8_t *>(file_name.c_str()),
+ file_name.size(), true)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+StaIface::getMacAddressInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ std::vector<char> cmd(
+ kGetMacAddress, kGetMacAddress + sizeof(kGetMacAddress));
+ char driver_cmd_reply_buf[4096] = {};
+ int ret = wpa_drv_driver_cmd(
+ wpa_s, cmd.data(), driver_cmd_reply_buf,
+ sizeof(driver_cmd_reply_buf));
+ // Reply is of the format: "Macaddr = XX:XX:XX:XX:XX:XX"
+ std::string reply_str = driver_cmd_reply_buf;
+ if (ret < 0 || reply_str.empty() ||
+ reply_str.find("=") == std::string::npos) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ // Remove all whitespace first and then split using the delimiter "=".
+ reply_str.erase(
+ remove_if(reply_str.begin(), reply_str.end(), isspace),
+ reply_str.end());
+ std::string mac_addr_str =
+ reply_str.substr(reply_str.find("=") + 1, reply_str.size());
+ std::array<uint8_t, 6> mac_addr;
+ if (hwaddr_aton(mac_addr_str.c_str(), mac_addr.data())) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, mac_addr};
+}
+
+SupplicantStatus StaIface::startRxFilterInternal()
+{
+ return doZeroArgDriverCommand(retrieveIfacePtr(), kStartRxFilter);
+}
+
+SupplicantStatus StaIface::stopRxFilterInternal()
+{
+ return doZeroArgDriverCommand(retrieveIfacePtr(), kStopRxFilter);
+}
+
+SupplicantStatus StaIface::addRxFilterInternal(
+ ISupplicantStaIface::RxFilterType type)
+{
+ return doOneArgDriverCommand(
+ retrieveIfacePtr(), kAddRxFilter,
+ convertHidlRxFilterTypeToInternal(type));
+}
+
+SupplicantStatus StaIface::removeRxFilterInternal(
+ ISupplicantStaIface::RxFilterType type)
+{
+ return doOneArgDriverCommand(
+ retrieveIfacePtr(), kRemoveRxFilter,
+ convertHidlRxFilterTypeToInternal(type));
+}
+
+SupplicantStatus StaIface::setBtCoexistenceModeInternal(
+ ISupplicantStaIface::BtCoexistenceMode mode)
+{
+ return doOneArgDriverCommand(
+ retrieveIfacePtr(), kSetBtCoexistenceMode,
+ convertHidlBtCoexModeToInternal(mode));
+}
+
+SupplicantStatus StaIface::setBtCoexistenceScanModeEnabledInternal(bool enable)
+{
+ const char *cmd;
+ if (enable) {
+ cmd = kSetBtCoexistenceScanStart;
+ } else {
+ cmd = kSetBtCoexistenceScanStop;
+ }
+ return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
+}
+
+SupplicantStatus StaIface::setSuspendModeEnabledInternal(bool enable)
+{
+ const char *cmd;
+ if (enable) {
+ cmd = kSetSupendModeEnabled;
+ } else {
+ cmd = kSetSupendModeDisabled;
+ }
+ return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
+}
+
+SupplicantStatus StaIface::setCountryCodeInternal(
+ const std::array<int8_t, 2> &code)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ SupplicantStatus status = doOneArgDriverCommand(
+ wpa_s, kSetCountryCode,
+ std::string(std::begin(code), std::end(code)));
+ if (status.code != SupplicantStatusCode::SUCCESS) {
+ return status;
+ }
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ if (p2p) {
+ char country[3];
+ country[0] = code[0];
+ country[1] = code[1];
+ country[2] = 0x04;
+ p2p_set_country(p2p, country);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::startWpsRegistrarInternal(
+ const std::array<uint8_t, 6> &bssid, const std::string &pin)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpas_wps_start_reg(wpa_s, bssid.data(), pin.c_str(), nullptr)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::startWpsPbcInternal(
+ const std::array<uint8_t, 6> &bssid)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ const uint8_t *bssid_addr =
+ is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
+ if (wpas_wps_start_pbc(wpa_s, bssid_addr, 0)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::startWpsPinKeypadInternal(const std::string &pin)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpas_wps_start_pin(
+ wpa_s, nullptr, pin.c_str(), 0, DEV_PW_DEFAULT)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::string> StaIface::startWpsPinDisplayInternal(
+ const std::array<uint8_t, 6> &bssid)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ const uint8_t *bssid_addr =
+ is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
+ int pin =
+ wpas_wps_start_pin(wpa_s, bssid_addr, nullptr, 0, DEV_PW_DEFAULT);
+ if (pin < 0) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, ""};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ misc_utils::convertWpsPinToString(pin)};
+}
+
+SupplicantStatus StaIface::cancelWpsInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpas_wps_cancel(wpa_s)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaIface::setWpsDeviceNameInternal(const std::string &name)
+{
+ return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
+}
+
+SupplicantStatus StaIface::setWpsDeviceTypeInternal(
+ const std::array<uint8_t, 8> &type)
+{
+ return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type);
+}
+
+SupplicantStatus StaIface::setWpsManufacturerInternal(
+ const std::string &manufacturer)
+{
+ return iface_config_utils::setWpsManufacturer(
+ retrieveIfacePtr(), manufacturer);
+}
+
+SupplicantStatus StaIface::setWpsModelNameInternal(
+ const std::string &model_name)
+{
+ return iface_config_utils::setWpsModelName(
+ retrieveIfacePtr(), model_name);
+}
+
+SupplicantStatus StaIface::setWpsModelNumberInternal(
+ const std::string &model_number)
+{
+ return iface_config_utils::setWpsModelNumber(
+ retrieveIfacePtr(), model_number);
+}
+
+SupplicantStatus StaIface::setWpsSerialNumberInternal(
+ const std::string &serial_number)
+{
+ return iface_config_utils::setWpsSerialNumber(
+ retrieveIfacePtr(), serial_number);
+}
+
+SupplicantStatus StaIface::setWpsConfigMethodsInternal(uint16_t config_methods)
+{
+ return iface_config_utils::setWpsConfigMethods(
+ retrieveIfacePtr(), config_methods);
+}
+
+SupplicantStatus StaIface::setExternalSimInternal(bool useExternalSim)
+{
+ return iface_config_utils::setExternalSim(
+ retrieveIfacePtr(), useExternalSim);
+}
+
+std::pair<SupplicantStatus, uint32_t> StaIface::addExtRadioWorkInternal(
+ const std::string &name, uint32_t freq_in_mhz, uint32_t timeout_in_sec)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ auto *ework = static_cast<struct wpa_external_work *>(
+ os_zalloc(sizeof(struct wpa_external_work)));
+ if (!ework) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
+ UINT32_MAX};
+ }
+
+ std::string radio_work_name = kExtRadioWorkNamePrefix + name;
+ os_strlcpy(ework->type, radio_work_name.c_str(), sizeof(ework->type));
+ ework->timeout = timeout_in_sec;
+ wpa_s->ext_work_id++;
+ if (wpa_s->ext_work_id == 0) {
+ wpa_s->ext_work_id++;
+ }
+ ework->id = wpa_s->ext_work_id;
+
+ if (radio_add_work(
+ wpa_s, freq_in_mhz, ework->type, 0, extRadioWorkStartCb,
+ ework)) {
+ os_free(ework);
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
+ UINT32_MAX};
+ }
+ return {SupplicantStatus{SupplicantStatusCode::SUCCESS, ""}, ework->id};
+}
+
+SupplicantStatus StaIface::removeExtRadioWorkInternal(uint32_t id)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_radio_work *work;
+ dl_list_for_each(work, &wpa_s->radio->work, struct wpa_radio_work, list)
+ {
+ if (os_strncmp(
+ work->type, kExtRadioWorkNamePrefix,
+ sizeof(kExtRadioWorkNamePrefix)) != 0)
+ continue;
+
+ auto *ework =
+ static_cast<struct wpa_external_work *>(work->ctx);
+ if (ework->id != id)
+ continue;
+
+ wpa_dbg(
+ wpa_s, MSG_DEBUG, "Completed external radio work %u (%s)",
+ ework->id, ework->type);
+ eloop_cancel_timeout(extRadioWorkTimeoutCb, work, NULL);
+ endExtRadioWork(work);
+
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+}
+
+SupplicantStatus StaIface::enableAutoReconnectInternal(bool enable)
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ wpa_s->auto_reconnect_disabled = enable ? 0 : 1;
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+/**
+ * Retrieve the underlying |wpa_supplicant| struct
+ * pointer for this iface.
+ * If the underlying iface is removed, then all RPC method calls on this object
+ * will return failure.
+ */
+wpa_supplicant *StaIface::retrieveIfacePtr()
+{
+ return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/sta_iface.h b/wpa_supplicant/hidl/1.0/sta_iface.h
new file mode 100644
index 0000000..6e62260
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/sta_iface.h
@@ -0,0 +1,249 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_STA_IFACE_H
+#define WPA_SUPPLICANT_HIDL_STA_IFACE_H
+
+#include <array>
+#include <vector>
+
+#include <android-base/macros.h>
+
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "driver_i.h"
+#include "wpa.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Implementation of StaIface hidl object. Each unique hidl
+ * object is used for control operations on a specific interface
+ * controlled by wpa_supplicant.
+ */
+class StaIface
+ : public android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface
+{
+public:
+ StaIface(struct wpa_global* wpa_global, const char ifname[]);
+ ~StaIface() override = default;
+ // HIDL does not provide a built-in mechanism to let the server
+ // invalidate a HIDL interface object after creation. If any client
+ // process holds onto a reference to the object in their context,
+ // any method calls on that reference will continue to be directed to
+ // the server.
+ // However Supplicant HAL needs to control the lifetime of these
+ // objects. So, add a public |invalidate| method to all |Iface| and
+ // |Network| objects.
+ // This will be used to mark an object invalid when the corresponding
+ // iface or network is removed.
+ // All HIDL method implementations should check if the object is still
+ // marked valid before processing them.
+ void invalidate();
+ bool isValid();
+
+ // Hidl methods exposed.
+ Return<void> getName(getName_cb _hidl_cb) override;
+ Return<void> getType(getType_cb _hidl_cb) override;
+ Return<void> addNetwork(addNetwork_cb _hidl_cb) override;
+ Return<void> removeNetwork(
+ SupplicantNetworkId id, removeNetwork_cb _hidl_cb) override;
+ Return<void> getNetwork(
+ SupplicantNetworkId id, getNetwork_cb _hidl_cb) override;
+ Return<void> listNetworks(listNetworks_cb _hidl_cb) override;
+ Return<void> registerCallback(
+ const sp<ISupplicantStaIfaceCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
+ Return<void> reassociate(reassociate_cb _hidl_cb) override;
+ Return<void> reconnect(reconnect_cb _hidl_cb) override;
+ Return<void> disconnect(disconnect_cb _hidl_cb) override;
+ Return<void> setPowerSave(
+ bool enable, setPowerSave_cb _hidl_cb) override;
+ Return<void> initiateTdlsDiscover(
+ const hidl_array<uint8_t, 6>& mac_address,
+ initiateTdlsDiscover_cb _hidl_cb) override;
+ Return<void> initiateTdlsSetup(
+ const hidl_array<uint8_t, 6>& mac_address,
+ initiateTdlsSetup_cb _hidl_cb) override;
+ Return<void> initiateTdlsTeardown(
+ const hidl_array<uint8_t, 6>& mac_address,
+ initiateTdlsTeardown_cb _hidl_cb) override;
+ Return<void> initiateAnqpQuery(
+ const hidl_array<uint8_t, 6>& mac_address,
+ const hidl_vec<ISupplicantStaIface::AnqpInfoId>& info_elements,
+ const hidl_vec<ISupplicantStaIface::Hs20AnqpSubtypes>& sub_types,
+ initiateAnqpQuery_cb _hidl_cb) override;
+ Return<void> initiateHs20IconQuery(
+ const hidl_array<uint8_t, 6>& mac_address,
+ const hidl_string& file_name,
+ initiateHs20IconQuery_cb _hidl_cb) override;
+ Return<void> getMacAddress(getMacAddress_cb _hidl_cb) override;
+ Return<void> startRxFilter(startRxFilter_cb _hidl_cb) override;
+ Return<void> stopRxFilter(stopRxFilter_cb _hidl_cb) override;
+ Return<void> addRxFilter(
+ ISupplicantStaIface::RxFilterType type,
+ addRxFilter_cb _hidl_cb) override;
+ Return<void> removeRxFilter(
+ ISupplicantStaIface::RxFilterType type,
+ removeRxFilter_cb _hidl_cb) override;
+ Return<void> setBtCoexistenceMode(
+ ISupplicantStaIface::BtCoexistenceMode mode,
+ setBtCoexistenceMode_cb _hidl_cb) override;
+ Return<void> setBtCoexistenceScanModeEnabled(
+ bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb) override;
+ Return<void> setSuspendModeEnabled(
+ bool enable, setSuspendModeEnabled_cb _hidl_cb) override;
+ Return<void> setCountryCode(
+ const hidl_array<int8_t, 2>& code,
+ setCountryCode_cb _hidl_cb) override;
+ Return<void> startWpsRegistrar(
+ const hidl_array<uint8_t, 6>& bssid, const hidl_string& pin,
+ startWpsRegistrar_cb _hidl_cb) override;
+ Return<void> startWpsPbc(
+ const hidl_array<uint8_t, 6>& bssid,
+ startWpsPbc_cb _hidl_cb) override;
+ Return<void> startWpsPinKeypad(
+ const hidl_string& pin, startWpsPinKeypad_cb _hidl_cb) override;
+ Return<void> startWpsPinDisplay(
+ const hidl_array<uint8_t, 6>& bssid,
+ startWpsPinDisplay_cb _hidl_cb) override;
+ Return<void> cancelWps(cancelWps_cb _hidl_cb) override;
+ Return<void> setWpsDeviceName(
+ const hidl_string& name, setWpsDeviceName_cb _hidl_cb) override;
+ Return<void> setWpsDeviceType(
+ const hidl_array<uint8_t, 8>& type,
+ setWpsDeviceType_cb _hidl_cb) override;
+ Return<void> setWpsManufacturer(
+ const hidl_string& manufacturer,
+ setWpsManufacturer_cb _hidl_cb) override;
+ Return<void> setWpsModelName(
+ const hidl_string& model_name,
+ setWpsModelName_cb _hidl_cb) override;
+ Return<void> setWpsModelNumber(
+ const hidl_string& model_number,
+ setWpsModelNumber_cb _hidl_cb) override;
+ Return<void> setWpsSerialNumber(
+ const hidl_string& serial_number,
+ setWpsSerialNumber_cb _hidl_cb) override;
+ Return<void> setWpsConfigMethods(
+ uint16_t config_methods, setWpsConfigMethods_cb _hidl_cb) override;
+ Return<void> setExternalSim(
+ bool useExternalSim, setExternalSim_cb _hidl_cb) override;
+ Return<void> addExtRadioWork(
+ const hidl_string& name, uint32_t freq_in_mhz,
+ uint32_t timeout_in_sec, addExtRadioWork_cb _hidl_cb) override;
+ Return<void> removeExtRadioWork(
+ uint32_t id, removeExtRadioWork_cb _hidl_cb) override;
+ Return<void> enableAutoReconnect(
+ bool enable, enableAutoReconnect_cb _hidl_cb) override;
+
+private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<SupplicantStatus, std::string> getNameInternal();
+ std::pair<SupplicantStatus, IfaceType> getTypeInternal();
+ std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
+ addNetworkInternal();
+ SupplicantStatus removeNetworkInternal(SupplicantNetworkId id);
+ std::pair<SupplicantStatus, sp<ISupplicantNetwork>> getNetworkInternal(
+ SupplicantNetworkId id);
+ std::pair<SupplicantStatus, std::vector<SupplicantNetworkId>>
+ listNetworksInternal();
+ SupplicantStatus registerCallbackInternal(
+ const sp<ISupplicantStaIfaceCallback>& callback);
+ SupplicantStatus reassociateInternal();
+ SupplicantStatus reconnectInternal();
+ SupplicantStatus disconnectInternal();
+ SupplicantStatus setPowerSaveInternal(bool enable);
+ SupplicantStatus initiateTdlsDiscoverInternal(
+ const std::array<uint8_t, 6>& mac_address);
+ SupplicantStatus initiateTdlsSetupInternal(
+ const std::array<uint8_t, 6>& mac_address);
+ SupplicantStatus initiateTdlsTeardownInternal(
+ const std::array<uint8_t, 6>& mac_address);
+ SupplicantStatus initiateAnqpQueryInternal(
+ const std::array<uint8_t, 6>& mac_address,
+ const std::vector<ISupplicantStaIface::AnqpInfoId>& info_elements,
+ const std::vector<ISupplicantStaIface::Hs20AnqpSubtypes>&
+ sub_types);
+ SupplicantStatus initiateHs20IconQueryInternal(
+ const std::array<uint8_t, 6>& mac_address,
+ const std::string& file_name);
+ std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+ getMacAddressInternal();
+ SupplicantStatus startRxFilterInternal();
+ SupplicantStatus stopRxFilterInternal();
+ SupplicantStatus addRxFilterInternal(
+ ISupplicantStaIface::RxFilterType type);
+ SupplicantStatus removeRxFilterInternal(
+ ISupplicantStaIface::RxFilterType type);
+ SupplicantStatus setBtCoexistenceModeInternal(
+ ISupplicantStaIface::BtCoexistenceMode mode);
+ SupplicantStatus setBtCoexistenceScanModeEnabledInternal(bool enable);
+ SupplicantStatus setSuspendModeEnabledInternal(bool enable);
+ SupplicantStatus setCountryCodeInternal(
+ const std::array<int8_t, 2>& code);
+ SupplicantStatus startWpsRegistrarInternal(
+ const std::array<uint8_t, 6>& bssid, const std::string& pin);
+ SupplicantStatus startWpsPbcInternal(
+ const std::array<uint8_t, 6>& bssid);
+ SupplicantStatus startWpsPinKeypadInternal(const std::string& pin);
+ std::pair<SupplicantStatus, std::string> startWpsPinDisplayInternal(
+ const std::array<uint8_t, 6>& bssid);
+ SupplicantStatus cancelWpsInternal();
+ SupplicantStatus setWpsDeviceNameInternal(const std::string& name);
+ SupplicantStatus setWpsDeviceTypeInternal(
+ const std::array<uint8_t, 8>& type);
+ SupplicantStatus setWpsManufacturerInternal(
+ const std::string& manufacturer);
+ SupplicantStatus setWpsModelNameInternal(const std::string& model_name);
+ SupplicantStatus setWpsModelNumberInternal(
+ const std::string& model_number);
+ SupplicantStatus setWpsSerialNumberInternal(
+ const std::string& serial_number);
+ SupplicantStatus setWpsConfigMethodsInternal(uint16_t config_methods);
+ SupplicantStatus setExternalSimInternal(bool useExternalSim);
+ std::pair<SupplicantStatus, uint32_t> addExtRadioWorkInternal(
+ const std::string& name, uint32_t freq_in_mhz,
+ uint32_t timeout_in_sec);
+ SupplicantStatus removeExtRadioWorkInternal(uint32_t id);
+ SupplicantStatus enableAutoReconnectInternal(bool enable);
+
+ struct wpa_supplicant* retrieveIfacePtr();
+
+ // Reference to the global wpa_struct. This is assumed to be valid for
+ // the lifetime of the process.
+ struct wpa_global* wpa_global_;
+ // Name of the iface this hidl object controls
+ const std::string ifname_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaIface);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
+
+#endif // WPA_SUPPLICANT_HIDL_STA_IFACE_H
diff --git a/wpa_supplicant/hidl/1.0/sta_network.cpp b/wpa_supplicant/hidl/1.0/sta_network.cpp
new file mode 100644
index 0000000..72185b3
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/sta_network.cpp
@@ -0,0 +1,1819 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "hidl_manager.h"
+#include "hidl_return_util.h"
+#include "misc_utils.h"
+#include "sta_network.h"
+
+extern "C" {
+#include "wps_supplicant.h"
+}
+
+namespace {
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+
+constexpr uint8_t kZeroBssid[6] = {0, 0, 0, 0, 0, 0};
+
+constexpr uint32_t kAllowedKeyMgmtMask =
+ (static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::NONE) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_EAP) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::FT_PSK) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::KeyMgmtMask::OSEN));
+constexpr uint32_t kAllowedProtoMask =
+ (static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::WPA) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::RSN) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::ProtoMask::OSEN));
+constexpr uint32_t kAllowedAuthAlgMask =
+ (static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::OPEN) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::SHARED) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::AuthAlgMask::LEAP));
+constexpr uint32_t kAllowedGroupCipherMask =
+ (static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP40) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::WEP104) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::TKIP) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::GroupCipherMask::CCMP) |
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::GroupCipherMask::GTK_NOT_USED));
+constexpr uint32_t kAllowedPairwisewCipherMask =
+ (static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::NONE) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::TKIP) |
+ static_cast<uint32_t>(ISupplicantStaNetwork::PairwiseCipherMask::CCMP));
+
+constexpr uint32_t kEapMethodMax =
+ static_cast<uint32_t>(ISupplicantStaNetwork::EapMethod::WFA_UNAUTH_TLS) + 1;
+constexpr char const *kEapMethodStrings[kEapMethodMax] = {
+ "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS"};
+constexpr uint32_t kEapPhase2MethodMax =
+ static_cast<uint32_t>(ISupplicantStaNetwork::EapPhase2Method::AKA_PRIME) +
+ 1;
+constexpr char const *kEapPhase2MethodStrings[kEapPhase2MethodMax] = {
+ "", "PAP", "MSCHAP", "MSCHAPV2", "GTC", "SIM", "AKA", "AKA'"};
+constexpr char kEapPhase2AuthPrefix[] = "auth=";
+constexpr char kEapPhase2AuthEapPrefix[] = "autheap=";
+constexpr char kNetworkEapSimGsmAuthResponse[] = "GSM-AUTH";
+constexpr char kNetworkEapSimUmtsAuthResponse[] = "UMTS-AUTH";
+constexpr char kNetworkEapSimUmtsAutsResponse[] = "UMTS-AUTS";
+constexpr char kNetworkEapSimGsmAuthFailure[] = "GSM-FAIL";
+constexpr char kNetworkEapSimUmtsAuthFailure[] = "UMTS-FAIL";
+} // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+StaNetwork::StaNetwork(
+ struct wpa_global *wpa_global, const char ifname[], int network_id)
+ : wpa_global_(wpa_global),
+ ifname_(ifname),
+ network_id_(network_id),
+ is_valid_(true)
+{
+}
+
+void StaNetwork::invalidate() { is_valid_ = false; }
+bool StaNetwork::isValid()
+{
+ return (is_valid_ && (retrieveNetworkPtr() != nullptr));
+}
+
+Return<void> StaNetwork::getId(getId_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getIdInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getInterfaceName(getInterfaceName_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getInterfaceNameInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getType(getType_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getTypeInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::registerCallback(
+ const sp<ISupplicantStaNetworkCallback> &callback,
+ registerCallback_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::registerCallbackInternal, _hidl_cb, callback);
+}
+
+Return<void> StaNetwork::setSsid(
+ const hidl_vec<uint8_t> &ssid, setSsid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setSsidInternal, _hidl_cb, ssid);
+}
+
+Return<void> StaNetwork::setBssid(
+ const hidl_array<uint8_t, 6> &bssid, setBssid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setBssidInternal, _hidl_cb, bssid);
+}
+
+Return<void> StaNetwork::setScanSsid(bool enable, setScanSsid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setScanSsidInternal, _hidl_cb, enable);
+}
+
+Return<void> StaNetwork::setKeyMgmt(
+ uint32_t key_mgmt_mask, setKeyMgmt_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setKeyMgmtInternal, _hidl_cb, key_mgmt_mask);
+}
+
+Return<void> StaNetwork::setProto(uint32_t proto_mask, setProto_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setProtoInternal, _hidl_cb, proto_mask);
+}
+
+Return<void> StaNetwork::setAuthAlg(
+ uint32_t auth_alg_mask,
+ std::function<void(const SupplicantStatus &status)> _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setAuthAlgInternal, _hidl_cb, auth_alg_mask);
+}
+
+Return<void> StaNetwork::setGroupCipher(
+ uint32_t group_cipher_mask, setGroupCipher_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setGroupCipherInternal, _hidl_cb, group_cipher_mask);
+}
+
+Return<void> StaNetwork::setPairwiseCipher(
+ uint32_t pairwise_cipher_mask, setPairwiseCipher_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setPairwiseCipherInternal, _hidl_cb,
+ pairwise_cipher_mask);
+}
+
+Return<void> StaNetwork::setPskPassphrase(
+ const hidl_string &psk, setPskPassphrase_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setPskPassphraseInternal, _hidl_cb, psk);
+}
+
+Return<void> StaNetwork::setPsk(
+ const hidl_array<uint8_t, 32> &psk, setPsk_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setPskInternal, _hidl_cb, psk);
+}
+
+Return<void> StaNetwork::setWepKey(
+ uint32_t key_idx, const hidl_vec<uint8_t> &wep_key, setWepKey_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setWepKeyInternal, _hidl_cb, key_idx, wep_key);
+}
+
+Return<void> StaNetwork::setWepTxKeyIdx(
+ uint32_t key_idx, setWepTxKeyIdx_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setWepTxKeyIdxInternal, _hidl_cb, key_idx);
+}
+
+Return<void> StaNetwork::setRequirePmf(bool enable, setRequirePmf_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setRequirePmfInternal, _hidl_cb, enable);
+}
+
+Return<void> StaNetwork::setEapMethod(
+ ISupplicantStaNetwork::EapMethod method, setEapMethod_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapMethodInternal, _hidl_cb, method);
+}
+
+Return<void> StaNetwork::setEapPhase2Method(
+ ISupplicantStaNetwork::EapPhase2Method method,
+ setEapPhase2Method_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapPhase2MethodInternal, _hidl_cb, method);
+}
+
+Return<void> StaNetwork::setEapIdentity(
+ const hidl_vec<uint8_t> &identity, setEapIdentity_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapIdentityInternal, _hidl_cb, identity);
+}
+
+Return<void> StaNetwork::setEapAnonymousIdentity(
+ const hidl_vec<uint8_t> &identity, setEapAnonymousIdentity_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapAnonymousIdentityInternal, _hidl_cb, identity);
+}
+
+Return<void> StaNetwork::setEapPassword(
+ const hidl_vec<uint8_t> &password, setEapPassword_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapPasswordInternal, _hidl_cb, password);
+}
+
+Return<void> StaNetwork::setEapCACert(
+ const hidl_string &path, setEapCACert_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapCACertInternal, _hidl_cb, path);
+}
+
+Return<void> StaNetwork::setEapCAPath(
+ const hidl_string &path, setEapCAPath_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapCAPathInternal, _hidl_cb, path);
+}
+
+Return<void> StaNetwork::setEapClientCert(
+ const hidl_string &path, setEapClientCert_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapClientCertInternal, _hidl_cb, path);
+}
+
+Return<void> StaNetwork::setEapPrivateKeyId(
+ const hidl_string &id, setEapPrivateKeyId_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapPrivateKeyIdInternal, _hidl_cb, id);
+}
+
+Return<void> StaNetwork::setEapSubjectMatch(
+ const hidl_string &match, setEapSubjectMatch_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapSubjectMatchInternal, _hidl_cb, match);
+}
+
+Return<void> StaNetwork::setEapAltSubjectMatch(
+ const hidl_string &match, setEapAltSubjectMatch_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapAltSubjectMatchInternal, _hidl_cb, match);
+}
+
+Return<void> StaNetwork::setEapEngine(bool enable, setEapEngine_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapEngineInternal, _hidl_cb, enable);
+}
+
+Return<void> StaNetwork::setEapEngineID(
+ const hidl_string &id, setEapEngineID_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapEngineIDInternal, _hidl_cb, id);
+}
+
+Return<void> StaNetwork::setEapDomainSuffixMatch(
+ const hidl_string &match, setEapDomainSuffixMatch_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setEapDomainSuffixMatchInternal, _hidl_cb, match);
+}
+
+Return<void> StaNetwork::setProactiveKeyCaching(
+ bool enable, setProactiveKeyCaching_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setProactiveKeyCachingInternal, _hidl_cb, enable);
+}
+
+Return<void> StaNetwork::setIdStr(
+ const hidl_string &id_str, setIdStr_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setIdStrInternal, _hidl_cb, id_str);
+}
+
+Return<void> StaNetwork::setUpdateIdentifier(
+ uint32_t id, setUpdateIdentifier_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::setUpdateIdentifierInternal, _hidl_cb, id);
+}
+
+Return<void> StaNetwork::getSsid(getSsid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getSsidInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getBssid(getBssid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getBssidInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getScanSsid(getScanSsid_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getScanSsidInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getKeyMgmt(getKeyMgmt_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getKeyMgmtInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getProto(getProto_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getProtoInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getAuthAlg(getAuthAlg_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getAuthAlgInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getGroupCipher(getGroupCipher_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getGroupCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getPairwiseCipher(getPairwiseCipher_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getPairwiseCipherInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getPskPassphrase(getPskPassphrase_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getPskPassphraseInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getPsk(getPsk_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getPskInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getWepKey(uint32_t key_idx, getWepKey_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getWepKeyInternal, _hidl_cb, key_idx);
+}
+
+Return<void> StaNetwork::getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getWepTxKeyIdxInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getRequirePmf(getRequirePmf_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getRequirePmfInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapMethod(getEapMethod_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapMethodInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapPhase2Method(getEapPhase2Method_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapPhase2MethodInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapIdentity(getEapIdentity_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapIdentityInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapAnonymousIdentity(
+ getEapAnonymousIdentity_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapAnonymousIdentityInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapPassword(getEapPassword_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapPasswordInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapCACert(getEapCACert_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapCACertInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapCAPath(getEapCAPath_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapCAPathInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapClientCert(getEapClientCert_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapClientCertInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapPrivateKeyId(getEapPrivateKeyId_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapPrivateKeyIdInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapSubjectMatch(getEapSubjectMatch_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapSubjectMatchInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapAltSubjectMatch(
+ getEapAltSubjectMatch_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapAltSubjectMatchInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapEngine(getEapEngine_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapEngineInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapEngineID(getEapEngineID_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapEngineIDInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getEapDomainSuffixMatch(
+ getEapDomainSuffixMatch_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getEapDomainSuffixMatchInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getIdStr(getIdStr_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getIdStrInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::getWpsNfcConfigurationToken(
+ getWpsNfcConfigurationToken_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::getWpsNfcConfigurationTokenInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::enable(bool no_connect, enable_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::enableInternal, _hidl_cb, no_connect);
+}
+
+Return<void> StaNetwork::disable(disable_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::disableInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::select(select_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::selectInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::sendNetworkEapSimGsmAuthResponse(
+ const hidl_vec<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
+ &vec_params,
+ sendNetworkEapSimGsmAuthResponse_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::sendNetworkEapSimGsmAuthResponseInternal, _hidl_cb,
+ vec_params);
+}
+
+Return<void> StaNetwork::sendNetworkEapSimGsmAuthFailure(
+ sendNetworkEapSimGsmAuthFailure_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::sendNetworkEapSimGsmAuthFailureInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::sendNetworkEapSimUmtsAuthResponse(
+ const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams ¶ms,
+ sendNetworkEapSimUmtsAuthResponse_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal, _hidl_cb,
+ params);
+}
+
+Return<void> StaNetwork::sendNetworkEapSimUmtsAutsResponse(
+ const hidl_array<uint8_t, 14> &auts,
+ sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal, _hidl_cb,
+ auts);
+}
+
+Return<void> StaNetwork::sendNetworkEapSimUmtsAuthFailure(
+ sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal, _hidl_cb);
+}
+
+Return<void> StaNetwork::sendNetworkEapIdentityResponse(
+ const hidl_vec<uint8_t> &identity,
+ sendNetworkEapIdentityResponse_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+ &StaNetwork::sendNetworkEapIdentityResponseInternal, _hidl_cb,
+ identity);
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getIdInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, network_id_};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getInterfaceNameInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
+}
+
+std::pair<SupplicantStatus, IfaceType> StaNetwork::getTypeInternal()
+{
+ return {{SupplicantStatusCode::SUCCESS, ""}, IfaceType::STA};
+}
+
+SupplicantStatus StaNetwork::registerCallbackInternal(
+ const sp<ISupplicantStaNetworkCallback> &callback)
+{
+ HidlManager *hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->addStaNetworkCallbackHidlObject(
+ ifname_, network_id_, callback)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setSsidInternal(const std::vector<uint8_t> &ssid)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (ssid.size() == 0 ||
+ ssid.size() >
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ SSID_MAX_LEN_IN_BYTES)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ if (setByteArrayFieldAndResetState(
+ ssid.data(), ssid.size(), &(wpa_ssid->ssid),
+ &(wpa_ssid->ssid_len), "ssid")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ if (wpa_ssid->passphrase) {
+ wpa_config_update_psk(wpa_ssid);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setBssidInternal(
+ const std::array<uint8_t, 6> &bssid)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ int prev_bssid_set = wpa_ssid->bssid_set;
+ u8 prev_bssid[ETH_ALEN];
+ os_memcpy(prev_bssid, wpa_ssid->bssid, ETH_ALEN);
+ // Zero'ed array is used to clear out the BSSID value.
+ if (os_memcmp(bssid.data(), kZeroBssid, ETH_ALEN) == 0) {
+ wpa_ssid->bssid_set = 0;
+ wpa_printf(MSG_MSGDUMP, "BSSID any");
+ } else {
+ os_memcpy(wpa_ssid->bssid, bssid.data(), ETH_ALEN);
+ wpa_ssid->bssid_set = 1;
+ wpa_hexdump(MSG_MSGDUMP, "BSSID", wpa_ssid->bssid, ETH_ALEN);
+ }
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if ((wpa_ssid->bssid_set != prev_bssid_set ||
+ os_memcmp(wpa_ssid->bssid, prev_bssid, ETH_ALEN) != 0)) {
+ wpas_notify_network_bssid_set_changed(wpa_s, wpa_ssid);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setScanSsidInternal(bool enable)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->scan_ssid = enable ? 1 : 0;
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setKeyMgmtInternal(uint32_t key_mgmt_mask)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (key_mgmt_mask & ~kAllowedKeyMgmtMask) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ wpa_ssid->key_mgmt = key_mgmt_mask;
+ wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", wpa_ssid->key_mgmt);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setProtoInternal(uint32_t proto_mask)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (proto_mask & ~kAllowedProtoMask) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ wpa_ssid->proto = proto_mask;
+ wpa_printf(MSG_MSGDUMP, "proto: 0x%x", wpa_ssid->proto);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setAuthAlgInternal(uint32_t auth_alg_mask)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (auth_alg_mask & ~kAllowedAuthAlgMask) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ wpa_ssid->auth_alg = auth_alg_mask;
+ wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", wpa_ssid->auth_alg);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setGroupCipherInternal(uint32_t group_cipher_mask)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (group_cipher_mask & ~kAllowedGroupCipherMask) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ wpa_ssid->group_cipher = group_cipher_mask;
+ wpa_printf(MSG_MSGDUMP, "group_cipher: 0x%x", wpa_ssid->group_cipher);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setPairwiseCipherInternal(
+ uint32_t pairwise_cipher_mask)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (pairwise_cipher_mask & ~kAllowedPairwisewCipherMask) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ wpa_ssid->pairwise_cipher = pairwise_cipher_mask;
+ wpa_printf(
+ MSG_MSGDUMP, "pairwise_cipher: 0x%x", wpa_ssid->pairwise_cipher);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setPskPassphraseInternal(const std::string &psk)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (isPskPassphraseValid(psk)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ if (wpa_ssid->passphrase &&
+ os_strlen(wpa_ssid->passphrase) == psk.size() &&
+ os_memcmp(wpa_ssid->passphrase, psk.c_str(), psk.size()) == 0) {
+ return {SupplicantStatusCode::SUCCESS, ""};
+ }
+ // Flag to indicate if raw psk is calculated or not using
+ // |wpa_config_update_psk|. Deferred if ssid not already set.
+ wpa_ssid->psk_set = 0;
+ if (setStringKeyFieldAndResetState(
+ psk.c_str(), &(wpa_ssid->passphrase), "psk passphrase")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ if (wpa_ssid->ssid_len) {
+ wpa_config_update_psk(wpa_ssid);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setPskInternal(const std::array<uint8_t, 32> &psk)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ WPA_ASSERT(psk.size() == sizeof(wpa_ssid->psk));
+ str_clear_free(wpa_ssid->passphrase);
+ wpa_ssid->passphrase = nullptr;
+ os_memcpy(wpa_ssid->psk, psk.data(), sizeof(wpa_ssid->psk));
+ wpa_ssid->psk_set = 1;
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setWepKeyInternal(
+ uint32_t key_idx, const std::vector<uint8_t> &wep_key)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (key_idx >=
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ if (wep_key.size() !=
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ WEP40_KEY_LEN_IN_BYTES) &&
+ wep_key.size() !=
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ WEP104_KEY_LEN_IN_BYTES)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ os_memcpy(wpa_ssid->wep_key[key_idx], wep_key.data(), wep_key.size());
+ wpa_ssid->wep_key_len[key_idx] = wep_key.size();
+ std::string msg_dump_title("wep_key" + std::to_string(key_idx));
+ wpa_hexdump_key(
+ MSG_MSGDUMP, msg_dump_title.c_str(), wpa_ssid->wep_key[key_idx],
+ wpa_ssid->wep_key_len[key_idx]);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setWepTxKeyIdxInternal(uint32_t key_idx)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (key_idx >=
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ wpa_ssid->wep_tx_keyidx = key_idx;
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setRequirePmfInternal(bool enable)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->ieee80211w =
+ enable ? MGMT_FRAME_PROTECTION_REQUIRED : NO_MGMT_FRAME_PROTECTION;
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapMethodInternal(
+ ISupplicantStaNetwork::EapMethod method)
+{
+ uint32_t eap_method_idx = static_cast<
+ std::underlying_type<ISupplicantStaNetwork::EapMethod>::type>(
+ method);
+ if (eap_method_idx >= kEapMethodMax) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ int retrieved_vendor, retrieved_method;
+ const char *method_str = kEapMethodStrings[eap_method_idx];
+ // This string lookup is needed to check if the device supports the
+ // corresponding EAP type.
+ retrieved_method = eap_peer_get_type(method_str, &retrieved_vendor);
+ if (retrieved_vendor == EAP_VENDOR_IETF &&
+ retrieved_method == EAP_TYPE_NONE) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ if (wpa_ssid->eap.eap_methods) {
+ os_free(wpa_ssid->eap.eap_methods);
+ }
+ // wpa_supplicant can support setting multiple eap methods for each
+ // network. But, this is not really used by Android. So, just adding
+ // support for setting one EAP method for each network. The additional
+ // |eap_method_type| member in the array is used to indicate the end
+ // of list.
+ wpa_ssid->eap.eap_methods =
+ (eap_method_type *)os_malloc(sizeof(eap_method_type) * 2);
+ if (!wpa_ssid->eap.eap_methods) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ wpa_ssid->eap.eap_methods[0].vendor = retrieved_vendor;
+ wpa_ssid->eap.eap_methods[0].method = retrieved_method;
+ wpa_ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
+ wpa_ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
+
+ wpa_ssid->leap = 0;
+ wpa_ssid->non_leap = 0;
+ if (retrieved_vendor == EAP_VENDOR_IETF &&
+ retrieved_method == EAP_TYPE_LEAP) {
+ wpa_ssid->leap++;
+ } else {
+ wpa_ssid->non_leap++;
+ }
+ wpa_hexdump(
+ MSG_MSGDUMP, "eap methods", (u8 *)wpa_ssid->eap.eap_methods,
+ sizeof(eap_method_type) * 2);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapPhase2MethodInternal(
+ ISupplicantStaNetwork::EapPhase2Method method)
+{
+ uint32_t eap_phase2_method_idx = static_cast<
+ std::underlying_type<ISupplicantStaNetwork::EapPhase2Method>::type>(
+ method);
+ if (eap_phase2_method_idx >= kEapPhase2MethodMax) {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ // EAP method needs to be set for us to construct the eap
+ // phase 2 method string.
+ SupplicantStatus status;
+ ISupplicantStaNetwork::EapMethod eap_method;
+ std::tie(status, eap_method) = getEapMethodInternal();
+ if (status.code != SupplicantStatusCode::SUCCESS) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN,
+ "EAP method not set"};
+ }
+ std::string eap_phase2_str;
+ if (method == ISupplicantStaNetwork::EapPhase2Method::NONE) {
+ eap_phase2_str = "";
+ } else if (
+ eap_method == ISupplicantStaNetwork::EapMethod::TTLS &&
+ method == ISupplicantStaNetwork::EapPhase2Method::GTC) {
+ eap_phase2_str = kEapPhase2AuthEapPrefix;
+ } else {
+ eap_phase2_str = kEapPhase2AuthPrefix;
+ }
+ eap_phase2_str += kEapPhase2MethodStrings[eap_phase2_method_idx];
+ if (setStringFieldAndResetState(
+ eap_phase2_str.c_str(), &(wpa_ssid->eap.phase2),
+ "eap phase2")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapIdentityInternal(
+ const std::vector<uint8_t> &identity)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setByteArrayFieldAndResetState(
+ identity.data(), identity.size(), &(wpa_ssid->eap.identity),
+ &(wpa_ssid->eap.identity_len), "eap identity")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapAnonymousIdentityInternal(
+ const std::vector<uint8_t> &identity)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setByteArrayFieldAndResetState(
+ identity.data(), identity.size(),
+ &(wpa_ssid->eap.anonymous_identity),
+ &(wpa_ssid->eap.anonymous_identity_len),
+ "eap anonymous_identity")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapPasswordInternal(
+ const std::vector<uint8_t> &password)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setByteArrayKeyFieldAndResetState(
+ password.data(), password.size(), &(wpa_ssid->eap.password),
+ &(wpa_ssid->eap.password_len), "eap password")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ wpa_ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ wpa_ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapCACertInternal(const std::string &path)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ path.c_str(), &(wpa_ssid->eap.ca_cert), "eap ca_cert")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapCAPathInternal(const std::string &path)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ path.c_str(), &(wpa_ssid->eap.ca_path), "eap ca_path")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapClientCertInternal(const std::string &path)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ path.c_str(), &(wpa_ssid->eap.client_cert),
+ "eap client_cert")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapPrivateKeyIdInternal(const std::string &id)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ id.c_str(), &(wpa_ssid->eap.key_id), "eap key_id")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapSubjectMatchInternal(
+ const std::string &match)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ match.c_str(), &(wpa_ssid->eap.subject_match),
+ "eap subject_match")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapAltSubjectMatchInternal(
+ const std::string &match)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ match.c_str(), &(wpa_ssid->eap.altsubject_match),
+ "eap altsubject_match")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapEngineInternal(bool enable)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->eap.engine = enable ? 1 : 0;
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapEngineIDInternal(const std::string &id)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ id.c_str(), &(wpa_ssid->eap.engine_id), "eap engine_id")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setEapDomainSuffixMatchInternal(
+ const std::string &match)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ match.c_str(), &(wpa_ssid->eap.domain_suffix_match),
+ "eap domain_suffix_match")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setProactiveKeyCachingInternal(bool enable)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->proactive_key_caching = enable ? 1 : 0;
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setIdStrInternal(const std::string &id_str)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (setStringFieldAndResetState(
+ id_str.c_str(), &(wpa_ssid->id_str), "id_str")) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::setUpdateIdentifierInternal(uint32_t id)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ wpa_ssid->update_identifier = id;
+ wpa_printf(
+ MSG_MSGDUMP, "update_identifier: %d", wpa_ssid->update_identifier);
+ resetInternalStateAfterParamsUpdate();
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getSsidInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ std::vector<uint8_t> ssid;
+ ssid.assign(wpa_ssid->ssid, wpa_ssid->ssid + wpa_ssid->ssid_len);
+ return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ssid)};
+}
+
+std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+StaNetwork::getBssidInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ std::array<uint8_t, 6> bssid{};
+ os_memcpy(bssid.data(), kZeroBssid, ETH_ALEN);
+ if (wpa_ssid->bssid_set) {
+ os_memcpy(bssid.data(), wpa_ssid->bssid, ETH_ALEN);
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, std::move(bssid)};
+}
+
+std::pair<SupplicantStatus, bool> StaNetwork::getScanSsidInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ (wpa_ssid->scan_ssid == 1)};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getKeyMgmtInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->key_mgmt & kAllowedKeyMgmtMask};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getProtoInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->proto & kAllowedProtoMask};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getAuthAlgInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->auth_alg & kAllowedAuthAlgMask};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getGroupCipherInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->group_cipher & kAllowedGroupCipherMask};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getPairwiseCipherInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ wpa_ssid->pairwise_cipher & kAllowedPairwisewCipherMask};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getPskPassphraseInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->passphrase) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->passphrase};
+}
+
+std::pair<SupplicantStatus, std::array<uint8_t, 32>>
+StaNetwork::getPskInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ WPA_ASSERT(psk.size() == sizeof(wpa_ssid->psk));
+ if (!wpa_ssid->psk_set) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ std::array<uint8_t, 32> psk;
+ os_memcpy(psk.data(), wpa_ssid->psk, psk.size());
+ return {{SupplicantStatusCode::SUCCESS, ""}, psk};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>> StaNetwork::getWepKeyInternal(
+ uint32_t key_idx)
+{
+ std::vector<uint8_t> wep_key;
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (key_idx >=
+ static_cast<uint32_t>(
+ ISupplicantStaNetwork::ParamSizeLimits::WEP_KEYS_MAX_NUM)) {
+ return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""},
+ wep_key};
+ }
+ wep_key.assign(
+ wpa_ssid->wep_key[key_idx],
+ wpa_ssid->wep_key[key_idx] + wpa_ssid->wep_key_len[key_idx]);
+ return {{SupplicantStatusCode::SUCCESS, ""}, std::move(wep_key)};
+}
+
+std::pair<SupplicantStatus, uint32_t> StaNetwork::getWepTxKeyIdxInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->wep_tx_keyidx};
+}
+
+std::pair<SupplicantStatus, bool> StaNetwork::getRequirePmfInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ (wpa_ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)};
+}
+
+std::pair<SupplicantStatus, ISupplicantStaNetwork::EapMethod>
+StaNetwork::getEapMethodInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.eap_methods) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ // wpa_supplicant can support setting multiple eap methods for each
+ // network. But, this is not really used by Android. So, just reading
+ // the first EAP method for each network.
+ const std::string eap_method_str = eap_get_name(
+ wpa_ssid->eap.eap_methods[0].vendor,
+ static_cast<EapType>(wpa_ssid->eap.eap_methods[0].method));
+ size_t eap_method_idx =
+ std::find(
+ std::begin(kEapMethodStrings), std::end(kEapMethodStrings),
+ eap_method_str) -
+ std::begin(kEapMethodStrings);
+ if (eap_method_idx >= kEapMethodMax) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ static_cast<ISupplicantStaNetwork::EapMethod>(eap_method_idx)};
+}
+
+std::pair<SupplicantStatus, ISupplicantStaNetwork::EapPhase2Method>
+StaNetwork::getEapPhase2MethodInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.phase2) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ const std::string eap_phase2_method_str_with_prefix =
+ wpa_ssid->eap.phase2;
+ std::string eap_phase2_method_str;
+ // Strip out the phase 2 method prefix before doing a reverse lookup
+ // of phase 2 string to the Eap Phase 2 type.
+ if (eap_phase2_method_str_with_prefix.find(kEapPhase2AuthPrefix) == 0) {
+ eap_phase2_method_str =
+ eap_phase2_method_str_with_prefix.substr(
+ strlen(kEapPhase2AuthPrefix),
+ eap_phase2_method_str_with_prefix.size());
+ } else if (
+ eap_phase2_method_str_with_prefix.find(kEapPhase2AuthEapPrefix) ==
+ 0) {
+ eap_phase2_method_str =
+ eap_phase2_method_str_with_prefix.substr(
+ strlen(kEapPhase2AuthEapPrefix),
+ eap_phase2_method_str_with_prefix.size());
+ }
+ size_t eap_phase2_method_idx =
+ std::find(
+ std::begin(kEapPhase2MethodStrings),
+ std::end(kEapPhase2MethodStrings), eap_phase2_method_str) -
+ std::begin(kEapPhase2MethodStrings);
+ if (eap_phase2_method_idx >= kEapPhase2MethodMax) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ static_cast<ISupplicantStaNetwork::EapPhase2Method>(
+ eap_phase2_method_idx)};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>>
+StaNetwork::getEapIdentityInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.identity) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ std::vector<uint8_t>(
+ wpa_ssid->eap.identity,
+ wpa_ssid->eap.identity + wpa_ssid->eap.identity_len)};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>>
+StaNetwork::getEapAnonymousIdentityInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.anonymous_identity) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ std::vector<uint8_t>(
+ wpa_ssid->eap.anonymous_identity,
+ wpa_ssid->eap.anonymous_identity +
+ wpa_ssid->eap.anonymous_identity_len)};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>>
+StaNetwork::getEapPasswordInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.password) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ std::vector<uint8_t>(
+ wpa_ssid->eap.password,
+ wpa_ssid->eap.password + wpa_ssid->eap.password_len)};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getEapCACertInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.ca_cert) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ reinterpret_cast<char *>(wpa_ssid->eap.ca_cert)};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getEapCAPathInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.ca_path) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ reinterpret_cast<char *>(wpa_ssid->eap.ca_path)};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getEapClientCertInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.client_cert) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ reinterpret_cast<char *>(wpa_ssid->eap.client_cert)};
+}
+
+std::pair<SupplicantStatus, std::string>
+StaNetwork::getEapPrivateKeyIdInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.key_id) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.key_id};
+}
+
+std::pair<SupplicantStatus, std::string>
+StaNetwork::getEapSubjectMatchInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.subject_match) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ reinterpret_cast<char *>(wpa_ssid->eap.subject_match)};
+}
+
+std::pair<SupplicantStatus, std::string>
+StaNetwork::getEapAltSubjectMatchInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.altsubject_match) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ reinterpret_cast<char *>(wpa_ssid->eap.altsubject_match)};
+}
+
+std::pair<SupplicantStatus, bool> StaNetwork::getEapEngineInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ return {{SupplicantStatusCode::SUCCESS, ""}, wpa_ssid->eap.engine == 1};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getEapEngineIDInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.engine_id) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->eap.engine_id}};
+}
+
+std::pair<SupplicantStatus, std::string>
+StaNetwork::getEapDomainSuffixMatchInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->eap.domain_suffix_match) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ {wpa_ssid->eap.domain_suffix_match}};
+}
+
+std::pair<SupplicantStatus, std::string> StaNetwork::getIdStrInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (!wpa_ssid->id_str) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, {wpa_ssid->id_str}};
+}
+
+std::pair<SupplicantStatus, std::vector<uint8_t>>
+StaNetwork::getWpsNfcConfigurationTokenInternal()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ auto token_buf = misc_utils::createWpaBufUniquePtr(
+ wpas_wps_network_config_token(wpa_s, 0, wpa_ssid));
+ if (!token_buf) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""},
+ misc_utils::convertWpaBufToVector(token_buf.get())};
+}
+
+SupplicantStatus StaNetwork::enableInternal(bool no_connect)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (wpa_ssid->disabled == 2) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (no_connect) {
+ wpa_ssid->disabled = 0;
+ } else {
+ wpa_s->scan_min_time.sec = 0;
+ wpa_s->scan_min_time.usec = 0;
+ wpa_supplicant_enable_network(wpa_s, wpa_ssid);
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::disableInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (wpa_ssid->disabled == 2) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ wpa_supplicant_disable_network(wpa_s, wpa_ssid);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::selectInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ if (wpa_ssid->disabled == 2) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ wpa_s->scan_min_time.sec = 0;
+ wpa_s->scan_min_time.usec = 0;
+ wpa_supplicant_select_network(wpa_s, wpa_ssid);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthResponseInternal(
+ const std::vector<ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>
+ &vec_params)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ // Convert the incoming parameters to a string to pass to
+ // wpa_supplicant.
+ std::string ctrl_rsp_param = std::string(kNetworkEapSimGsmAuthResponse);
+ for (const auto ¶ms : vec_params) {
+ uint32_t kc_hex_len = params.kc.size() * 2 + 1;
+ std::vector<char> kc_hex(kc_hex_len);
+ uint32_t sres_hex_len = params.sres.size() * 2 + 1;
+ std::vector<char> sres_hex(sres_hex_len);
+ wpa_snprintf_hex(
+ kc_hex.data(), kc_hex.size(), params.kc.data(),
+ params.kc.size());
+ wpa_snprintf_hex(
+ sres_hex.data(), sres_hex.size(), params.sres.data(),
+ params.sres.size());
+ ctrl_rsp_param += ":" + std::string(kc_hex.data()) + ":" +
+ std::string(sres_hex.data());
+ }
+ enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_supplicant_ctrl_rsp_handle(
+ wpa_s, wpa_ssid, rtype, ctrl_rsp_param.c_str())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+ wpa_hexdump_ascii_key(
+ MSG_DEBUG, "network sim gsm auth response param",
+ (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthFailureInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+ if (wpa_supplicant_ctrl_rsp_handle(
+ wpa_s, wpa_ssid, rtype, kNetworkEapSimGsmAuthFailure)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal(
+ const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams ¶ms)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ // Convert the incoming parameters to a string to pass to
+ // wpa_supplicant.
+ uint32_t ik_hex_len = params.ik.size() * 2 + 1;
+ std::vector<char> ik_hex(ik_hex_len);
+ uint32_t ck_hex_len = params.ck.size() * 2 + 1;
+ std::vector<char> ck_hex(ck_hex_len);
+ uint32_t res_hex_len = params.res.size() * 2 + 1;
+ std::vector<char> res_hex(res_hex_len);
+ wpa_snprintf_hex(
+ ik_hex.data(), ik_hex.size(), params.ik.data(), params.ik.size());
+ wpa_snprintf_hex(
+ ck_hex.data(), ck_hex.size(), params.ck.data(), params.ck.size());
+ wpa_snprintf_hex(
+ res_hex.data(), res_hex.size(), params.res.data(),
+ params.res.size());
+ std::string ctrl_rsp_param =
+ std::string(kNetworkEapSimUmtsAuthResponse) + ":" +
+ std::string(ik_hex.data()) + ":" + std::string(ck_hex.data()) +
+ ":" + std::string(res_hex.data());
+ enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_supplicant_ctrl_rsp_handle(
+ wpa_s, wpa_ssid, rtype, ctrl_rsp_param.c_str())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+ wpa_hexdump_ascii_key(
+ MSG_DEBUG, "network sim umts auth response param",
+ (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal(
+ const std::array<uint8_t, 14> &auts)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ uint32_t auts_hex_len = auts.size() * 2 + 1;
+ std::vector<char> auts_hex(auts_hex_len);
+ wpa_snprintf_hex(
+ auts_hex.data(), auts_hex.size(), auts.data(), auts.size());
+ std::string ctrl_rsp_param =
+ std::string(kNetworkEapSimUmtsAutsResponse) + ":" +
+ std::string(auts_hex.data());
+ enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_supplicant_ctrl_rsp_handle(
+ wpa_s, wpa_ssid, rtype, ctrl_rsp_param.c_str())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+ wpa_hexdump_ascii_key(
+ MSG_DEBUG, "network sim umts auts response param",
+ (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal()
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_SIM;
+ if (wpa_supplicant_ctrl_rsp_handle(
+ wpa_s, wpa_ssid, rtype, kNetworkEapSimUmtsAuthFailure)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal(
+ const std::vector<uint8_t> &identity)
+{
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+ std::string ctrl_rsp_param(identity.begin(), identity.end());
+ enum wpa_ctrl_req_type rtype = WPA_CTRL_REQ_EAP_IDENTITY;
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (wpa_supplicant_ctrl_rsp_handle(
+ wpa_s, wpa_ssid, rtype, ctrl_rsp_param.c_str())) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ eapol_sm_notify_ctrl_response(wpa_s->eapol);
+ wpa_hexdump_ascii_key(
+ MSG_DEBUG, "network identity response param",
+ (const u8 *)ctrl_rsp_param.c_str(), ctrl_rsp_param.size());
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+/**
+ * Retrieve the underlying |wpa_ssid| struct pointer for
+ * this network.
+ * If the underlying network is removed or the interface
+ * this network belong to
+ * is removed, all RPC method calls on this object will
+ * return failure.
+ */
+struct wpa_ssid *StaNetwork::retrieveNetworkPtr()
+{
+ wpa_supplicant *wpa_s = retrieveIfacePtr();
+ if (!wpa_s)
+ return nullptr;
+ return wpa_config_get_network(wpa_s->conf, network_id_);
+}
+
+/**
+ * Retrieve the underlying |wpa_supplicant| struct
+ * pointer for
+ * this network.
+ */
+struct wpa_supplicant *StaNetwork::retrieveIfacePtr()
+{
+ return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
+}
+
+/**
+ * Check if the provided psk passhrase is valid or not.
+ *
+ * Returns 0 if valid, 1 otherwise.
+ */
+int StaNetwork::isPskPassphraseValid(const std::string &psk)
+{
+ if (psk.size() <
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
+ psk.size() >
+ static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+ PSK_PASSPHRASE_MAX_LEN_IN_BYTES)) {
+ return 1;
+ }
+ if (has_ctrl_char((u8 *)psk.c_str(), psk.size())) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Reset internal wpa_supplicant state machine state
+ * after params update (except
+ * bssid).
+ */
+void StaNetwork::resetInternalStateAfterParamsUpdate()
+{
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_ssid);
+
+ if (wpa_s->current_ssid == wpa_ssid || wpa_s->current_ssid == NULL) {
+ /*
+ * Invalidate the EAP session cache if
+ * anything in the
+ * current or previously used
+ * configuration changes.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+}
+
+/**
+ * Helper function to set value in a string field in |wpa_ssid| structue
+ * instance for this network.
+ * This function frees any existing data in these fields.
+ */
+int StaNetwork::setStringFieldAndResetState(
+ const char *value, uint8_t **to_update_field, const char *hexdump_prefix)
+{
+ return setStringFieldAndResetState(
+ value, (char **)to_update_field, hexdump_prefix);
+}
+
+/**
+ * Helper function to set value in a string field in |wpa_ssid| structue
+ * instance for this network.
+ * This function frees any existing data in these fields.
+ */
+int StaNetwork::setStringFieldAndResetState(
+ const char *value, char **to_update_field, const char *hexdump_prefix)
+{
+ int value_len = strlen(value);
+ if (*to_update_field) {
+ os_free(*to_update_field);
+ }
+ *to_update_field = dup_binstr(value, value_len);
+ if (!(*to_update_field)) {
+ return 1;
+ }
+ wpa_hexdump_ascii(
+ MSG_MSGDUMP, hexdump_prefix, *to_update_field, value_len);
+ resetInternalStateAfterParamsUpdate();
+ return 0;
+}
+
+/**
+ * Helper function to set value in a string key field in |wpa_ssid| structue
+ * instance for this network.
+ * This function frees any existing data in these fields.
+ */
+int StaNetwork::setStringKeyFieldAndResetState(
+ const char *value, char **to_update_field, const char *hexdump_prefix)
+{
+ int value_len = strlen(value);
+ if (*to_update_field) {
+ str_clear_free(*to_update_field);
+ }
+ *to_update_field = dup_binstr(value, value_len);
+ if (!(*to_update_field)) {
+ return 1;
+ }
+ wpa_hexdump_ascii_key(
+ MSG_MSGDUMP, hexdump_prefix, *to_update_field, value_len);
+ resetInternalStateAfterParamsUpdate();
+ return 0;
+}
+
+/**
+ * Helper function to set value in a string field with a corresponding length
+ * field in |wpa_ssid| structue instance for this network.
+ * This function frees any existing data in these fields.
+ */
+int StaNetwork::setByteArrayFieldAndResetState(
+ const uint8_t *value, const size_t value_len, uint8_t **to_update_field,
+ size_t *to_update_field_len, const char *hexdump_prefix)
+{
+ if (*to_update_field) {
+ os_free(*to_update_field);
+ }
+ *to_update_field = (uint8_t *)os_malloc(value_len);
+ if (!(*to_update_field)) {
+ return 1;
+ }
+ os_memcpy(*to_update_field, value, value_len);
+ *to_update_field_len = value_len;
+
+ wpa_hexdump_ascii(
+ MSG_MSGDUMP, hexdump_prefix, *to_update_field,
+ *to_update_field_len);
+ resetInternalStateAfterParamsUpdate();
+ return 0;
+}
+
+/**
+ * Helper function to set value in a string key field with a corresponding
+ * length field in |wpa_ssid| structue instance for this network.
+ * This function frees any existing data in these fields.
+ */
+int StaNetwork::setByteArrayKeyFieldAndResetState(
+ const uint8_t *value, const size_t value_len, uint8_t **to_update_field,
+ size_t *to_update_field_len, const char *hexdump_prefix)
+{
+ if (*to_update_field) {
+ bin_clear_free(*to_update_field, *to_update_field_len);
+ }
+ *to_update_field = (uint8_t *)os_malloc(value_len);
+ if (!(*to_update_field)) {
+ return 1;
+ }
+ os_memcpy(*to_update_field, value, value_len);
+ *to_update_field_len = value_len;
+
+ wpa_hexdump_ascii_key(
+ MSG_MSGDUMP, hexdump_prefix, *to_update_field,
+ *to_update_field_len);
+ resetInternalStateAfterParamsUpdate();
+ return 0;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/sta_network.h b/wpa_supplicant/hidl/1.0/sta_network.h
new file mode 100644
index 0000000..6e8d42b
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/sta_network.h
@@ -0,0 +1,331 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_STA_NETWORK_H
+#define WPA_SUPPLICANT_HIDL_STA_NETWORK_H
+
+#include <array>
+#include <vector>
+
+#include <android-base/macros.h>
+
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetworkCallback.h>
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "notify.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "eap_peer/eap.h"
+#include "rsn_supp/wpa.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+
+/**
+ * Implementation of StaNetwork hidl object. Each unique hidl
+ * object is used for control operations on a specific network
+ * controlled by wpa_supplicant.
+ */
+class StaNetwork : public ISupplicantStaNetwork
+{
+public:
+ StaNetwork(
+ struct wpa_global* wpa_global, const char ifname[], int network_id);
+ ~StaNetwork() override = default;
+ // Refer to |StaIface::invalidate()|.
+ void invalidate();
+ bool isValid();
+
+ // Hidl methods exposed.
+ Return<void> getId(getId_cb _hidl_cb) override;
+ Return<void> getInterfaceName(getInterfaceName_cb _hidl_cb) override;
+ Return<void> getType(getType_cb _hidl_cb) override;
+ Return<void> registerCallback(
+ const sp<ISupplicantStaNetworkCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
+ Return<void> setSsid(
+ const hidl_vec<uint8_t>& ssid, setSsid_cb _hidl_cb) override;
+ Return<void> setBssid(
+ const hidl_array<uint8_t, 6>& bssid, setBssid_cb _hidl_cb) override;
+ Return<void> setScanSsid(bool enable, setScanSsid_cb _hidl_cb) override;
+ Return<void> setKeyMgmt(
+ uint32_t key_mgmt_mask, setKeyMgmt_cb _hidl_cb) override;
+ Return<void> setProto(
+ uint32_t proto_mask, setProto_cb _hidl_cb) override;
+ Return<void> setAuthAlg(
+ uint32_t auth_alg_mask, setAuthAlg_cb _hidl_cb) override;
+ Return<void> setGroupCipher(
+ uint32_t group_cipher_mask, setGroupCipher_cb _hidl_cb) override;
+ Return<void> setPairwiseCipher(
+ uint32_t pairwise_cipher_mask,
+ setPairwiseCipher_cb _hidl_cb) override;
+ Return<void> setPskPassphrase(
+ const hidl_string& psk, setPskPassphrase_cb _hidl_cb) override;
+ Return<void> setPsk(
+ const hidl_array<uint8_t, 32>& psk, setPsk_cb _hidl_cb) override;
+ Return<void> setWepKey(
+ uint32_t key_idx, const hidl_vec<uint8_t>& wep_key,
+ setWepKey_cb _hidl_cb) override;
+ Return<void> setWepTxKeyIdx(
+ uint32_t key_idx, setWepTxKeyIdx_cb _hidl_cb) override;
+ Return<void> setRequirePmf(
+ bool enable, setRequirePmf_cb _hidl_cb) override;
+ Return<void> setEapMethod(
+ ISupplicantStaNetwork::EapMethod method,
+ setEapMethod_cb _hidl_cb) override;
+ Return<void> setEapPhase2Method(
+ ISupplicantStaNetwork::EapPhase2Method method,
+ setEapPhase2Method_cb _hidl_cb) override;
+ Return<void> setEapIdentity(
+ const hidl_vec<uint8_t>& identity,
+ setEapIdentity_cb _hidl_cb) override;
+ Return<void> setEapAnonymousIdentity(
+ const hidl_vec<uint8_t>& identity,
+ setEapAnonymousIdentity_cb _hidl_cb) override;
+ Return<void> setEapPassword(
+ const hidl_vec<uint8_t>& password,
+ setEapPassword_cb _hidl_cb) override;
+ Return<void> setEapCACert(
+ const hidl_string& path, setEapCACert_cb _hidl_cb) override;
+ Return<void> setEapCAPath(
+ const hidl_string& path, setEapCAPath_cb _hidl_cb) override;
+ Return<void> setEapClientCert(
+ const hidl_string& path, setEapClientCert_cb _hidl_cb) override;
+ Return<void> setEapPrivateKeyId(
+ const hidl_string& id, setEapPrivateKeyId_cb _hidl_cb) override;
+ Return<void> setEapSubjectMatch(
+ const hidl_string& match, setEapSubjectMatch_cb _hidl_cb) override;
+ Return<void> setEapAltSubjectMatch(
+ const hidl_string& match,
+ setEapAltSubjectMatch_cb _hidl_cb) override;
+ Return<void> setEapEngine(
+ bool enable, setEapEngine_cb _hidl_cb) override;
+ Return<void> setEapEngineID(
+ const hidl_string& id, setEapEngineID_cb _hidl_cb) override;
+ Return<void> setEapDomainSuffixMatch(
+ const hidl_string& match,
+ setEapDomainSuffixMatch_cb _hidl_cb) override;
+ Return<void> setProactiveKeyCaching(
+ bool enable, setProactiveKeyCaching_cb _hidl_cb) override;
+ Return<void> setIdStr(
+ const hidl_string& id_str, setIdStr_cb _hidl_cb) override;
+ Return<void> setUpdateIdentifier(
+ uint32_t id, setUpdateIdentifier_cb _hidl_cb) override;
+ Return<void> getSsid(getSsid_cb _hidl_cb) override;
+ Return<void> getBssid(getBssid_cb _hidl_cb) override;
+ Return<void> getScanSsid(getScanSsid_cb _hidl_cb) override;
+ Return<void> getKeyMgmt(getKeyMgmt_cb _hidl_cb) override;
+ Return<void> getProto(getProto_cb _hidl_cb) override;
+ Return<void> getAuthAlg(getAuthAlg_cb _hidl_cb) override;
+ Return<void> getGroupCipher(getGroupCipher_cb _hidl_cb) override;
+ Return<void> getPairwiseCipher(getPairwiseCipher_cb _hidl_cb) override;
+ Return<void> getPskPassphrase(getPskPassphrase_cb _hidl_cb) override;
+ Return<void> getPsk(getPsk_cb _hidl_cb) override;
+ Return<void> getWepKey(
+ uint32_t key_idx, getWepKey_cb _hidl_cb) override;
+ Return<void> getWepTxKeyIdx(getWepTxKeyIdx_cb _hidl_cb) override;
+ Return<void> getRequirePmf(getRequirePmf_cb _hidl_cb) override;
+ Return<void> getEapMethod(getEapMethod_cb _hidl_cb) override;
+ Return<void> getEapPhase2Method(
+ getEapPhase2Method_cb _hidl_cb) override;
+ Return<void> getEapIdentity(getEapIdentity_cb _hidl_cb) override;
+ Return<void> getEapAnonymousIdentity(
+ getEapAnonymousIdentity_cb _hidl_cb) override;
+ Return<void> getEapPassword(getEapPassword_cb _hidl_cb) override;
+ Return<void> getEapCACert(getEapCACert_cb _hidl_cb) override;
+ Return<void> getEapCAPath(getEapCAPath_cb _hidl_cb) override;
+ Return<void> getEapClientCert(getEapClientCert_cb _hidl_cb) override;
+ Return<void> getEapPrivateKeyId(
+ getEapPrivateKeyId_cb _hidl_cb) override;
+ Return<void> getEapSubjectMatch(
+ getEapSubjectMatch_cb _hidl_cb) override;
+ Return<void> getEapAltSubjectMatch(
+ getEapAltSubjectMatch_cb _hidl_cb) override;
+ Return<void> getEapEngine(getEapEngine_cb _hidl_cb) override;
+ Return<void> getEapEngineID(getEapEngineID_cb _hidl_cb) override;
+ Return<void> getEapDomainSuffixMatch(
+ getEapDomainSuffixMatch_cb _hidl_cb) override;
+ Return<void> getIdStr(getIdStr_cb _hidl_cb) override;
+ Return<void> getWpsNfcConfigurationToken(
+ getWpsNfcConfigurationToken_cb _hidl_cb) override;
+ Return<void> enable(bool no_connect, enable_cb _hidl_cb) override;
+ Return<void> disable(disable_cb _hidl_cb) override;
+ Return<void> select(select_cb _hidl_cb) override;
+ Return<void> sendNetworkEapSimGsmAuthResponse(
+ const hidl_vec<
+ ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
+ vec_params,
+ sendNetworkEapSimGsmAuthResponse_cb _hidl_cb) override;
+ Return<void> sendNetworkEapSimGsmAuthFailure(
+ sendNetworkEapSimGsmAuthFailure_cb _hidl_cb) override;
+ Return<void> sendNetworkEapSimUmtsAuthResponse(
+ const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
+ params,
+ sendNetworkEapSimUmtsAuthResponse_cb _hidl_cb) override;
+ Return<void> sendNetworkEapSimUmtsAutsResponse(
+ const hidl_array<uint8_t, 14>& auts,
+ sendNetworkEapSimUmtsAutsResponse_cb _hidl_cb) override;
+ Return<void> sendNetworkEapSimUmtsAuthFailure(
+ sendNetworkEapSimUmtsAuthFailure_cb _hidl_cb) override;
+ Return<void> sendNetworkEapIdentityResponse(
+ const hidl_vec<uint8_t>& identity,
+ sendNetworkEapIdentityResponse_cb _hidl_cb) override;
+
+private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<SupplicantStatus, uint32_t> getIdInternal();
+ std::pair<SupplicantStatus, std::string> getInterfaceNameInternal();
+ std::pair<SupplicantStatus, IfaceType> getTypeInternal();
+ SupplicantStatus registerCallbackInternal(
+ const sp<ISupplicantStaNetworkCallback>& callback);
+ SupplicantStatus setSsidInternal(const std::vector<uint8_t>& ssid);
+ SupplicantStatus setBssidInternal(const std::array<uint8_t, 6>& bssid);
+ SupplicantStatus setScanSsidInternal(bool enable);
+ SupplicantStatus setKeyMgmtInternal(uint32_t key_mgmt_mask);
+ SupplicantStatus setProtoInternal(uint32_t proto_mask);
+ SupplicantStatus setAuthAlgInternal(uint32_t auth_alg_mask);
+ SupplicantStatus setGroupCipherInternal(uint32_t group_cipher_mask);
+ SupplicantStatus setPairwiseCipherInternal(
+ uint32_t pairwise_cipher_mask);
+ SupplicantStatus setPskPassphraseInternal(const std::string& psk);
+ SupplicantStatus setPskInternal(const std::array<uint8_t, 32>& psk);
+ SupplicantStatus setWepKeyInternal(
+ uint32_t key_idx, const std::vector<uint8_t>& wep_key);
+ SupplicantStatus setWepTxKeyIdxInternal(uint32_t key_idx);
+ SupplicantStatus setRequirePmfInternal(bool enable);
+ SupplicantStatus setEapMethodInternal(
+ ISupplicantStaNetwork::EapMethod method);
+ SupplicantStatus setEapPhase2MethodInternal(
+ ISupplicantStaNetwork::EapPhase2Method method);
+ SupplicantStatus setEapIdentityInternal(
+ const std::vector<uint8_t>& identity);
+ SupplicantStatus setEapAnonymousIdentityInternal(
+ const std::vector<uint8_t>& identity);
+ SupplicantStatus setEapPasswordInternal(
+ const std::vector<uint8_t>& password);
+ SupplicantStatus setEapCACertInternal(const std::string& path);
+ SupplicantStatus setEapCAPathInternal(const std::string& path);
+ SupplicantStatus setEapClientCertInternal(const std::string& path);
+ SupplicantStatus setEapPrivateKeyIdInternal(const std::string& id);
+ SupplicantStatus setEapSubjectMatchInternal(const std::string& match);
+ SupplicantStatus setEapAltSubjectMatchInternal(
+ const std::string& match);
+ SupplicantStatus setEapEngineInternal(bool enable);
+ SupplicantStatus setEapEngineIDInternal(const std::string& id);
+ SupplicantStatus setEapDomainSuffixMatchInternal(
+ const std::string& match);
+ SupplicantStatus setProactiveKeyCachingInternal(bool enable);
+ SupplicantStatus setIdStrInternal(const std::string& id_str);
+ SupplicantStatus setUpdateIdentifierInternal(uint32_t id);
+ std::pair<SupplicantStatus, std::vector<uint8_t>> getSsidInternal();
+ std::pair<SupplicantStatus, std::array<uint8_t, 6>> getBssidInternal();
+ std::pair<SupplicantStatus, bool> getScanSsidInternal();
+ std::pair<SupplicantStatus, uint32_t> getKeyMgmtInternal();
+ std::pair<SupplicantStatus, uint32_t> getProtoInternal();
+ std::pair<SupplicantStatus, uint32_t> getAuthAlgInternal();
+ std::pair<SupplicantStatus, uint32_t> getGroupCipherInternal();
+ std::pair<SupplicantStatus, uint32_t> getPairwiseCipherInternal();
+ std::pair<SupplicantStatus, std::string> getPskPassphraseInternal();
+ std::pair<SupplicantStatus, std::array<uint8_t, 32>> getPskInternal();
+ std::pair<SupplicantStatus, std::vector<uint8_t>> getWepKeyInternal(
+ uint32_t key_idx);
+ std::pair<SupplicantStatus, uint32_t> getWepTxKeyIdxInternal();
+ std::pair<SupplicantStatus, bool> getRequirePmfInternal();
+ std::pair<SupplicantStatus, ISupplicantStaNetwork::EapMethod>
+ getEapMethodInternal();
+ std::pair<SupplicantStatus, ISupplicantStaNetwork::EapPhase2Method>
+ getEapPhase2MethodInternal();
+ std::pair<SupplicantStatus, std::vector<uint8_t>>
+ getEapIdentityInternal();
+ std::pair<SupplicantStatus, std::vector<uint8_t>>
+ getEapAnonymousIdentityInternal();
+ std::pair<SupplicantStatus, std::vector<uint8_t>>
+ getEapPasswordInternal();
+ std::pair<SupplicantStatus, std::string> getEapCACertInternal();
+ std::pair<SupplicantStatus, std::string> getEapCAPathInternal();
+ std::pair<SupplicantStatus, std::string> getEapClientCertInternal();
+ std::pair<SupplicantStatus, std::string> getEapPrivateKeyIdInternal();
+ std::pair<SupplicantStatus, std::string> getEapSubjectMatchInternal();
+ std::pair<SupplicantStatus, std::string>
+ getEapAltSubjectMatchInternal();
+ std::pair<SupplicantStatus, bool> getEapEngineInternal();
+ std::pair<SupplicantStatus, std::string> getEapEngineIDInternal();
+ std::pair<SupplicantStatus, std::string>
+ getEapDomainSuffixMatchInternal();
+ std::pair<SupplicantStatus, std::string> getIdStrInternal();
+ std::pair<SupplicantStatus, std::vector<uint8_t>>
+ getWpsNfcConfigurationTokenInternal();
+ SupplicantStatus enableInternal(bool no_connect);
+ SupplicantStatus disableInternal();
+ SupplicantStatus selectInternal();
+ SupplicantStatus sendNetworkEapSimGsmAuthResponseInternal(
+ const std::vector<
+ ISupplicantStaNetwork::NetworkResponseEapSimGsmAuthParams>&
+ vec_params);
+ SupplicantStatus sendNetworkEapSimGsmAuthFailureInternal();
+ SupplicantStatus sendNetworkEapSimUmtsAuthResponseInternal(
+ const ISupplicantStaNetwork::NetworkResponseEapSimUmtsAuthParams&
+ params);
+ SupplicantStatus sendNetworkEapSimUmtsAutsResponseInternal(
+ const std::array<uint8_t, 14>& auts);
+ SupplicantStatus sendNetworkEapSimUmtsAuthFailureInternal();
+ SupplicantStatus sendNetworkEapIdentityResponseInternal(
+ const std::vector<uint8_t>& identity);
+
+ struct wpa_ssid* retrieveNetworkPtr();
+ struct wpa_supplicant* retrieveIfacePtr();
+ int isPskPassphraseValid(const std::string& psk);
+ void resetInternalStateAfterParamsUpdate();
+ int setStringFieldAndResetState(
+ const char* value, uint8_t** to_update_field,
+ const char* hexdump_prefix);
+ int setStringFieldAndResetState(
+ const char* value, char** to_update_field,
+ const char* hexdump_prefix);
+ int setStringKeyFieldAndResetState(
+ const char* value, char** to_update_field,
+ const char* hexdump_prefix);
+ int setByteArrayFieldAndResetState(
+ const uint8_t* value, const size_t value_len,
+ uint8_t** to_update_field, size_t* to_update_field_len,
+ const char* hexdump_prefix);
+ int setByteArrayKeyFieldAndResetState(
+ const uint8_t* value, const size_t value_len,
+ uint8_t** to_update_field, size_t* to_update_field_len,
+ const char* hexdump_prefix);
+
+ // Reference to the global wpa_struct. This is assumed to be valid
+ // for the lifetime of the process.
+ struct wpa_global* wpa_global_;
+ // Name of the iface this network belongs to.
+ const std::string ifname_;
+ // Id of the network this hidl object controls.
+ const int network_id_;
+ bool is_valid_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaNetwork);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
+
+#endif // WPA_SUPPLICANT_HIDL_STA_NETWORK_H
diff --git a/wpa_supplicant/hidl/1.0/supplicant.cpp b/wpa_supplicant/hidl/1.0/supplicant.cpp
new file mode 100644
index 0000000..409547f
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/supplicant.cpp
@@ -0,0 +1,184 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "hidl_manager.h"
+#include "hidl_return_util.h"
+#include "supplicant.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+// These are hardcoded for android.
+const char Supplicant::kDriverName[] = "nl80211";
+const char Supplicant::kConfigFilePath[] =
+ "/data/misc/wifi/wpa_supplicant.conf";
+
+Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {}
+bool Supplicant::isValid()
+{
+ // This top level object cannot be invalidated.
+ return true;
+}
+
+Return<void> Supplicant::getInterface(
+ const IfaceInfo& iface_info, getInterface_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &Supplicant::getInterfaceInternal, _hidl_cb, iface_info);
+}
+
+Return<void> Supplicant::listInterfaces(listInterfaces_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &Supplicant::listInterfacesInternal, _hidl_cb);
+}
+
+Return<void> Supplicant::registerCallback(
+ const sp<ISupplicantCallback>& callback, registerCallback_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &Supplicant::registerCallbackInternal, _hidl_cb, callback);
+}
+
+Return<void> Supplicant::setDebugParams(
+ ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys,
+ setDebugParams_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &Supplicant::setDebugParamsInternal, _hidl_cb, level,
+ show_timestamp, show_keys);
+}
+
+Return<void> Supplicant::setConcurrencyPriority(
+ IfaceType type, setConcurrencyPriority_cb _hidl_cb)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &Supplicant::setConcurrencyPriorityInternal, _hidl_cb, type);
+}
+
+Return<ISupplicant::DebugLevel> Supplicant::getDebugLevel()
+{
+ // TODO: Add SupplicantStatus in this method return for uniformity with
+ // the other methods in supplicant HIDL interface.
+ return (ISupplicant::DebugLevel)wpa_debug_level;
+}
+
+Return<bool> Supplicant::isDebugShowTimestampEnabled()
+{
+ // TODO: Add SupplicantStatus in this method return for uniformity with
+ // the other methods in supplicant HIDL interface.
+ return ((wpa_debug_timestamp != 0) ? true : false);
+}
+
+Return<bool> Supplicant::isDebugShowKeysEnabled()
+{
+ // TODO: Add SupplicantStatus in this method return for uniformity with
+ // the other methods in supplicant HIDL interface.
+ return ((wpa_debug_show_keys != 0) ? true : false);
+}
+
+std::pair<SupplicantStatus, sp<ISupplicantIface>>
+Supplicant::getInterfaceInternal(const IfaceInfo& iface_info)
+{
+ struct wpa_supplicant* wpa_s =
+ wpa_supplicant_get_iface(wpa_global_, iface_info.name.c_str());
+ if (!wpa_s) {
+ return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""},
+ nullptr};
+ }
+ HidlManager* hidl_manager = HidlManager::getInstance();
+ if (iface_info.type == IfaceType::P2P) {
+ android::sp<ISupplicantP2pIface> iface;
+ if (!hidl_manager ||
+ hidl_manager->getP2pIfaceHidlObjectByIfname(
+ wpa_s->ifname, &iface)) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
+ iface};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, iface};
+ } else {
+ android::sp<ISupplicantStaIface> iface;
+ if (!hidl_manager ||
+ hidl_manager->getStaIfaceHidlObjectByIfname(
+ wpa_s->ifname, &iface)) {
+ return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
+ iface};
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, iface};
+ }
+}
+
+std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>>
+Supplicant::listInterfacesInternal()
+{
+ std::vector<ISupplicant::IfaceInfo> ifaces;
+ for (struct wpa_supplicant* wpa_s = wpa_global_->ifaces; wpa_s;
+ wpa_s = wpa_s->next) {
+ if (wpa_s->global->p2p_init_wpa_s == wpa_s) {
+ ifaces.emplace_back(ISupplicant::IfaceInfo{
+ IfaceType::P2P, wpa_s->ifname});
+ } else {
+ ifaces.emplace_back(ISupplicant::IfaceInfo{
+ IfaceType::STA, wpa_s->ifname});
+ }
+ }
+ return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ifaces)};
+}
+
+SupplicantStatus Supplicant::registerCallbackInternal(
+ const sp<ISupplicantCallback>& callback)
+{
+ HidlManager* hidl_manager = HidlManager::getInstance();
+ if (!hidl_manager ||
+ hidl_manager->addSupplicantCallbackHidlObject(callback)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus Supplicant::setDebugParamsInternal(
+ ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys)
+{
+ if (wpa_supplicant_set_debug_params(
+ wpa_global_, static_cast<uint32_t>(level), show_timestamp,
+ show_keys)) {
+ return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+ }
+ return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus Supplicant::setConcurrencyPriorityInternal(IfaceType type)
+{
+ if (type == IfaceType::STA) {
+ wpa_global_->conc_pref =
+ wpa_global::wpa_conc_pref::WPA_CONC_PREF_STA;
+ } else if (type == IfaceType::P2P) {
+ wpa_global_->conc_pref =
+ wpa_global::wpa_conc_pref::WPA_CONC_PREF_P2P;
+ } else {
+ return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
+ }
+ return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
+}
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
diff --git a/wpa_supplicant/hidl/1.0/supplicant.h b/wpa_supplicant/hidl/1.0/supplicant.h
new file mode 100644
index 0000000..1ad8402
--- /dev/null
+++ b/wpa_supplicant/hidl/1.0/supplicant.h
@@ -0,0 +1,89 @@
+/*
+ * hidl interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_HIDL_SUPPLICANT_H
+#define WPA_SUPPLICANT_HIDL_SUPPLICANT_H
+
+#include <android-base/macros.h>
+
+#include <android/hardware/wifi/supplicant/1.0/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantCallback.h>
+#include <android/hardware/wifi/supplicant/1.0/ISupplicantIface.h>
+
+extern "C" {
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "utils/wpa_debug.h"
+#include "wpa_supplicant_i.h"
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace supplicant {
+namespace V1_0 {
+namespace implementation {
+/**
+ * Implementation of the supplicant hidl object. This hidl
+ * object is used core for global control operations on
+ * wpa_supplicant.
+ */
+class Supplicant : public android::hardware::wifi::supplicant::V1_0::ISupplicant
+{
+public:
+ Supplicant(struct wpa_global* global);
+ ~Supplicant() override = default;
+ bool isValid();
+
+ // Hidl methods exposed.
+ Return<void> getInterface(
+ const IfaceInfo& iface_info, getInterface_cb _hidl_cb) override;
+ Return<void> listInterfaces(listInterfaces_cb _hidl_cb) override;
+ Return<void> registerCallback(
+ const sp<ISupplicantCallback>& callback,
+ registerCallback_cb _hidl_cb) override;
+ Return<void> setDebugParams(
+ ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys,
+ setDebugParams_cb _hidl_cb) override;
+ Return<ISupplicant::DebugLevel> getDebugLevel() override;
+ Return<bool> isDebugShowTimestampEnabled() override;
+ Return<bool> isDebugShowKeysEnabled() override;
+ Return<void> setConcurrencyPriority(
+ IfaceType type, setConcurrencyPriority_cb _hidl_cb) override;
+
+private:
+ // Corresponding worker functions for the HIDL methods.
+ std::pair<SupplicantStatus, sp<ISupplicantIface>> getInterfaceInternal(
+ const IfaceInfo& iface_info);
+ std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>>
+ listInterfacesInternal();
+ SupplicantStatus registerCallbackInternal(
+ const sp<ISupplicantCallback>& callback);
+ SupplicantStatus setDebugParamsInternal(
+ ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys);
+ SupplicantStatus setConcurrencyPriorityInternal(IfaceType type);
+
+ // Raw pointer to the global structure maintained by the core.
+ struct wpa_global* wpa_global_;
+ // Driver name to be used for creating interfaces.
+ static const char kDriverName[];
+ // wpa_supplicant.conf file location on the device.
+ static const char kConfigFilePath[];
+
+ DISALLOW_COPY_AND_ASSIGN(Supplicant);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace wifi
+} // namespace supplicant
+} // namespace hardware
+} // namespace android
+
+#endif // WPA_SUPPLICANT_HIDL_SUPPLICANT_H
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 3128fcb..858636f 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -20,6 +20,7 @@
#include "driver_i.h"
#include "config.h"
#include "scan.h"
+#include "notify.h"
#include "bss.h"
#include "blacklist.h"
#include "gas_query.h"
@@ -61,6 +62,46 @@
};
+void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss = wpa_s->current_bss;
+ u8 *bssid = wpa_s->bssid;
+ const u8 *ie;
+ const u8 *ext_capa;
+ u32 filter = 0;
+
+ if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) {
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - BSS " MACSTR
+ " is not a Hotspot 2.0 network", MAC2STR(bssid));
+ return;
+ }
+
+ ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+
+ /* Check if DGAF disabled bit is zero (5th byte in the IE) */
+ if (!ie || ie[1] < 5)
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract DGAF bit");
+ else if (!(ie[6] & HS20_DGAF_DISABLED))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
+
+ ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+ if (!ext_capa || ext_capa[1] < 2) {
+ wpa_printf(MSG_DEBUG,
+ "Not configuring frame filtering - Can't extract Proxy ARP bit");
+ return;
+ }
+
+ /* Check if Proxy ARP is enabled (2nd byte in the IE) */
+ if (ext_capa[3] & BIT(4))
+ filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
+ WPA_DATA_FRAME_FILTER_FLAG_NA;
+
+ wpa_drv_configure_frame_filters(wpa_s, filter);
+}
+
+
void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
{
u8 conf;
@@ -165,8 +206,8 @@
}
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len)
+static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+ size_t payload_len)
{
struct wpabuf *buf;
@@ -280,7 +321,7 @@
return -1;
b64 = base64_encode(&icon->image[offset], size, &b64_size);
- if (buf_len >= b64_size) {
+ if (b64 && buf_len >= b64_size) {
os_memcpy(reply, b64, b64_size);
reply_size = b64_size;
} else {
@@ -396,14 +437,18 @@
icon->image_len = slen;
hs20_remove_duplicate_icons(wpa_s, icon);
wpa_msg(wpa_s, MSG_INFO,
- "RX-HS20-ICON " MACSTR " %s %u",
+ RX_HS20_ICON MACSTR " %s %u",
MAC2STR(sa), icon->file_name,
(unsigned int) icon->image_len);
+ wpas_notify_hs20_icon_query_done(wpa_s, sa,
+ icon->file_name,
+ icon->image,
+ icon->image_len);
return 0;
}
}
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
MAC2STR(sa));
if (slen < 4) {
@@ -466,7 +511,7 @@
}
fclose(f);
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
return 0;
}
@@ -530,7 +575,7 @@
switch (subtype) {
case HS20_STYPE_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" HS Capability List", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
if (anqp) {
@@ -540,7 +585,7 @@
}
break;
case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operator Friendly Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
if (anqp) {
@@ -556,7 +601,7 @@
"Metrics value from " MACSTR, MAC2STR(sa));
break;
}
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
pos[9], pos[10], WPA_GET_LE16(pos + 11));
@@ -566,7 +611,7 @@
}
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Connection Capability", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
if (anqp) {
@@ -576,7 +621,7 @@
}
break;
case HS20_STYPE_OPERATING_CLASS:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" Operating Class", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
if (anqp) {
@@ -586,7 +631,7 @@
}
break;
case HS20_STYPE_OSU_PROVIDERS_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
" OSU Providers list", MAC2STR(sa));
wpa_s->num_prov_found++;
if (anqp) {
@@ -663,6 +708,8 @@
wpa_s->conf->osu_dir);
f = fopen(fname, "w");
if (f == NULL) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Could not write OSU provider information");
hs20_free_osu_prov(wpa_s);
wpa_s->fetch_anqp_in_progress = 0;
return;
@@ -1036,7 +1083,7 @@
}
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
{
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
@@ -1067,7 +1114,16 @@
wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
wpa_s->num_osu_scans = 0;
wpa_s->num_prov_found = 0;
- hs20_start_osu_scan(wpa_s);
+ if (skip_scan) {
+ wpa_s->network_select = 0;
+ wpa_s->fetch_all_anqp = 1;
+ wpa_s->fetch_osu_info = 1;
+ wpa_s->fetch_osu_icon_in_progress = 0;
+
+ interworking_start_fetch_anqp(wpa_s);
+ } else {
+ hs20_start_osu_scan(wpa_s);
+ }
return 0;
}
@@ -1110,6 +1166,7 @@
osu_method, url);
else
wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION);
+ wpas_notify_hs20_rx_subscription_remediation(wpa_s, url, osu_method);
}
@@ -1123,6 +1180,7 @@
wpa_msg(wpa_s, MSG_INFO, HS20_DEAUTH_IMMINENT_NOTICE "%u %u %s",
code, reauth_delay, url);
+ wpas_notify_hs20_rx_deauth_imminent_notice(wpa_s, code, reauth_delay, url);
if (code == HS20_DEAUTH_REASON_CODE_BSS) {
wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to blacklist");
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 9fc654c..0dd559f 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -8,12 +8,11 @@
#ifndef HS20_SUPPLICANT_H
#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);
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
const u8 *payload, size_t payload_len, int inmem);
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
- size_t payload_len);
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
@@ -32,7 +31,7 @@
void hs20_free_osu_prov(struct wpa_supplicant *wpa_s);
void hs20_next_osu_icon(struct wpa_supplicant *wpa_s);
void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s);
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s);
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan);
void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s);
void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s);
void hs20_start_osu_scan(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index c00db31..954061a 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -221,6 +221,7 @@
peer->supp = wpa_sm_init(ctx);
if (peer->supp == NULL) {
wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed");
+ os_free(ctx);
return -1;
}
@@ -404,10 +405,18 @@
static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn,
- const u8 *own_addr)
+ const u8 *own_addr, struct wpa_ssid *ssid)
{
struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
+ static const struct wpa_auth_callbacks cb = {
+ .logger = auth_logger,
+ .set_eapol = auth_set_eapol,
+ .send_eapol = auth_send_eapol,
+ .get_psk = auth_get_psk,
+ .set_key = auth_set_key,
+ .for_each_sta = auth_for_each_sta,
+ .disconnect = ibss_rsn_disconnect,
+ };
wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
@@ -418,19 +427,11 @@
conf.rsn_pairwise = WPA_CIPHER_CCMP;
conf.wpa_group = WPA_CIPHER_CCMP;
conf.eapol_version = 2;
- conf.wpa_group_rekey = 600;
+ conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600;
+ conf.wpa_group_update_count = 4;
+ conf.wpa_pairwise_update_count = 4;
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = ibss_rsn;
- cb.logger = auth_logger;
- cb.set_eapol = auth_set_eapol;
- cb.send_eapol = auth_send_eapol;
- cb.get_psk = auth_get_psk;
- cb.set_key = auth_set_key;
- cb.for_each_sta = auth_for_each_sta;
- cb.disconnect = ibss_rsn_disconnect;
-
- ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb);
+ ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb, ibss_rsn);
if (ibss_rsn->auth_group == NULL) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
return -1;
@@ -665,7 +666,8 @@
}
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s)
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
struct ibss_rsn *ibss_rsn;
@@ -674,7 +676,7 @@
return NULL;
ibss_rsn->wpa_s = wpa_s;
- if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) {
+ if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr, ssid) < 0) {
ibss_rsn_deinit(ibss_rsn);
return NULL;
}
@@ -836,6 +838,18 @@
MAC2STR(addr));
if (peer &&
+ peer->authentication_status & (IBSS_RSN_SET_PTK_SUPP |
+ IBSS_RSN_SET_PTK_AUTH)) {
+ /* Clear the TK for this pair to allow recovery from the case
+ * where the peer STA has restarted and lost its key while we
+ * still have a pairwise key configured. */
+ wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
+ MACSTR, MAC2STR(addr));
+ wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
+ NULL, 0, NULL, 0);
+ }
+
+ if (peer &&
peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
if (peer->own_auth_tx.sec) {
struct os_reltime now, diff;
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 67fae2d..626c543 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -51,7 +51,8 @@
};
-struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 589ee57..fd2b02e 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -950,11 +950,9 @@
if (!key_mgmt)
key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
"WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
- if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
- return -1;
- if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+ if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
+ wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
+ wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
return -1;
return 0;
}
@@ -1590,9 +1588,8 @@
}
-static int interworking_connect_helper(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss, int allow_excluded,
- int only_add)
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ int only_add)
{
struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
@@ -1600,7 +1597,7 @@
struct nai_realm_eap *eap = NULL;
u16 count, i;
char buf[100];
- int excluded = 0, *excl = allow_excluded ? &excluded : NULL;
+ int excluded = 0, *excl = &excluded;
const char *name;
if (wpa_s->conf->cred == NULL || bss == NULL)
@@ -1614,8 +1611,8 @@
}
wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
- " for connection (allow_excluded=%d)",
- MAC2STR(bss->bssid), allow_excluded);
+ " for connection",
+ MAC2STR(bss->bssid));
if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
/*
@@ -1633,7 +1630,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1642,7 +1639,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1652,7 +1649,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1665,7 +1662,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
cred_rc->priority, cred_rc->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1675,7 +1672,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
cred->priority, cred->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
@@ -1685,7 +1682,7 @@
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
cred_3gpp->priority, cred_3gpp->sp_priority);
- if (allow_excluded && excl && !(*excl))
+ if (excl && !(*excl))
excl = NULL;
}
}
@@ -1850,13 +1847,6 @@
}
-int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- int only_add)
-{
- return interworking_connect_helper(wpa_s, bss, 1, only_add);
-}
-
-
#ifdef PCSC_FUNCS
static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s)
{
@@ -2540,7 +2530,8 @@
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
MAC2STR(selected->bssid));
interworking_connect(wpa_s, selected, 0);
- }
+ } else if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
}
@@ -2702,10 +2693,11 @@
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
- u16 info_ids[], size_t num_ids, u32 subtypes)
+ u16 info_ids[], size_t num_ids, u32 subtypes,
+ int get_cell_pref)
{
struct wpabuf *buf;
- struct wpabuf *hs20_buf = NULL;
+ struct wpabuf *extra_buf = NULL;
int ret = 0;
int freq;
struct wpa_bss *bss;
@@ -2728,15 +2720,31 @@
#ifdef CONFIG_HS20
if (subtypes != 0) {
- hs20_buf = wpabuf_alloc(100);
- if (hs20_buf == NULL)
+ extra_buf = wpabuf_alloc(100);
+ if (extra_buf == NULL)
return -1;
- hs20_put_anqp_req(subtypes, NULL, 0, hs20_buf);
+ hs20_put_anqp_req(subtypes, NULL, 0, extra_buf);
}
#endif /* CONFIG_HS20 */
- buf = anqp_build_req(info_ids, num_ids, hs20_buf);
- wpabuf_free(hs20_buf);
+#ifdef CONFIG_MBO
+ if (get_cell_pref) {
+ struct wpabuf *mbo;
+
+ mbo = mbo_build_anqp_buf(wpa_s, bss);
+ if (mbo) {
+ if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
+ wpabuf_free(extra_buf);
+ return -1;
+ }
+ wpabuf_put_buf(extra_buf, mbo);
+ wpabuf_free(mbo);
+ }
+ }
+#endif /* CONFIG_MBO */
+
+ buf = anqp_build_req(info_ids, num_ids, extra_buf);
+ wpabuf_free(extra_buf);
if (buf == NULL)
return -1;
@@ -2806,7 +2814,7 @@
switch (info_id) {
case ANQP_CAPABILITY_LIST:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" ANQP Capability list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
pos, slen);
@@ -2816,7 +2824,7 @@
}
break;
case ANQP_VENUE_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
if (anqp) {
@@ -2825,7 +2833,7 @@
}
break;
case ANQP_NETWORK_AUTH_TYPE:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Network Authentication Type information",
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
@@ -2836,7 +2844,7 @@
}
break;
case ANQP_ROAMING_CONSORTIUM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
@@ -2846,7 +2854,7 @@
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" IP Address Type Availability information",
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
@@ -2858,7 +2866,7 @@
}
break;
case ANQP_NAI_REALM:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" NAI Realm list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
if (anqp) {
@@ -2867,7 +2875,7 @@
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
@@ -2877,7 +2885,7 @@
}
break;
case ANQP_DOMAIN_NAME:
- wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
" Domain Name list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
if (anqp) {
@@ -2885,6 +2893,18 @@
anqp->domain_name = wpabuf_alloc_copy(pos, slen);
}
break;
+#ifdef CONFIG_FILS
+ case ANQP_FILS_REALM_INFO:
+ wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
+ " FILS Realm Information", MAC2STR(sa));
+ wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: FILS Realm Information",
+ pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->fils_realm_info);
+ anqp->fils_realm_info = wpabuf_alloc_copy(pos, slen);
+ }
+ break;
+#endif /* CONFIG_FILS */
case ANQP_VENDOR_SPECIFIC:
if (slen < 3)
return;
@@ -3018,6 +3038,7 @@
out:
wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
MAC2STR(dst), anqp_result);
+ wpas_notify_anqp_query_done(wpa_s, dst, anqp_result, bss ? bss->anqp : NULL);
}
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 3743dc0..3d22292 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -12,7 +12,8 @@
enum gas_query_result;
int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
- u16 info_ids[], size_t num_ids, u32 subtypes);
+ u16 info_ids[], size_t num_ids, u32 subtypes,
+ int get_cell_pref);
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 3292e67..d20ae5e 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -14,10 +14,12 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "bss.h"
+#include "scan.h"
/* type + length + oui + oui type */
#define MBO_IE_HEADER 6
@@ -67,14 +69,13 @@
wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].preference);
wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason);
- wpabuf_put_u8(mbo, wpa_s->non_pref_chan[start].reason_detail);
}
static void wpas_mbo_non_pref_chan_attr(struct wpa_supplicant *wpa_s,
struct wpabuf *mbo, u8 start, u8 end)
{
- size_t size = end - start + 4;
+ size_t size = end - start + 3;
if (size + 2 > wpabuf_tailroom(mbo))
return;
@@ -99,7 +100,7 @@
struct wpabuf *mbo, u8 start,
u8 end)
{
- size_t size = end - start + 8;
+ size_t size = end - start + 7;
if (size + 2 > wpabuf_tailroom(mbo))
return;
@@ -130,7 +131,6 @@
if (!non_pref ||
non_pref->oper_class != start_pref->oper_class ||
non_pref->reason != start_pref->reason ||
- non_pref->reason_detail != start_pref->reason_detail ||
non_pref->preference != start_pref->preference) {
if (subelement)
wpas_mbo_non_pref_chan_subelement(wpa_s, mbo,
@@ -249,9 +249,9 @@
*
* In MBO IE non-preferred channel subelement we can put many channels in an
* attribute if they are in the same operating class and have the same
- * preference, reason, and reason detail. To make it easy for the functions that
- * build the IE attributes and WNM Request subelements, save the channels sorted
- * by their oper_class, reason, and reason_detail.
+ * preference and reason. To make it easy for the functions that build
+ * the IE attributes and WNM Request subelements, save the channels sorted
+ * by their oper_class and reason.
*/
static int wpa_non_pref_chan_cmp(const void *_a, const void *_b)
{
@@ -261,8 +261,6 @@
return a->oper_class - b->oper_class;
if (a->reason != b->reason)
return a->reason - b->reason;
- if (a->reason_detail != b->reason_detail)
- return a->reason_detail - b->reason_detail;
return a->preference - b->preference;
}
@@ -297,7 +295,6 @@
unsigned int _chan;
unsigned int _preference;
unsigned int _reason;
- unsigned int _reason_detail;
if (num == size) {
size = size ? size * 2 : 1;
@@ -313,13 +310,11 @@
chan = &chans[num];
- ret = sscanf(token, "%u:%u:%u:%u:%u", &_oper_class,
- &_chan, &_preference, &_reason,
- &_reason_detail);
- if ((ret != 4 && ret != 5) ||
+ ret = sscanf(token, "%u:%u:%u:%u", &_oper_class,
+ &_chan, &_preference, &_reason);
+ if (ret != 4 ||
_oper_class > 255 || _chan > 255 ||
- _preference > 255 || _reason > 65535 ||
- (ret == 5 && _reason_detail > 255)) {
+ _preference > 255 || _reason > 65535 ) {
wpa_printf(MSG_ERROR, "Invalid non-pref chan input %s",
token);
goto fail;
@@ -328,7 +323,6 @@
chan->chan = _chan;
chan->preference = _preference;
chan->reason = _reason;
- chan->reason_detail = ret == 4 ? 0 : _reason_detail;
if (wpas_mbo_validate_non_pref_chan(chan->oper_class,
chan->chan, chan->reason)) {
@@ -386,258 +380,6 @@
}
-enum chan_allowed {
- NOT_ALLOWED, ALLOWED
-};
-
-static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
- unsigned int *flags)
-{
- int i;
-
- for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].chan == chan)
- break;
- }
-
- if (i == mode->num_channels ||
- (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
- return NOT_ALLOWED;
-
- if (flags)
- *flags = mode->channels[i].flag;
-
- return ALLOWED;
-}
-
-
-static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
-{
- u8 center_channels[] = {42, 58, 106, 122, 138, 155};
- size_t i;
-
- if (mode->mode != HOSTAPD_MODE_IEEE80211A)
- return 0;
-
- for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
- /*
- * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
- * so the center channel is 6 channels away from the start/end.
- */
- if (channel >= center_channels[i] - 6 &&
- channel <= center_channels[i] + 6)
- return center_channels[i];
- }
-
- return 0;
-}
-
-
-static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
-{
- u8 center_chan;
- unsigned int i;
-
- center_chan = get_center_80mhz(mode, channel);
- if (!center_chan)
- return NOT_ALLOWED;
-
- /* check all the channels are available */
- for (i = 0; i < 4; i++) {
- unsigned int flags;
- u8 adj_chan = center_chan - 6 + i * 4;
-
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
- return NOT_ALLOWED;
-
- if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
- (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
- (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
- (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
- return NOT_ALLOWED;
- }
-
- return ALLOWED;
-}
-
-
-static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
-{
- u8 center_channels[] = { 50, 114 };
- unsigned int i;
-
- if (mode->mode != HOSTAPD_MODE_IEEE80211A)
- return 0;
-
- for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
- /*
- * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
- * so the center channel is 14 channels away from the start/end.
- */
- if (channel >= center_channels[i] - 14 &&
- channel <= center_channels[i] + 14)
- return center_channels[i];
- }
-
- return 0;
-}
-
-
-static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
- u8 channel)
-{
- u8 center_chan;
- unsigned int i;
-
- center_chan = get_center_160mhz(mode, channel);
- if (!center_chan)
- return NOT_ALLOWED;
-
- /* Check all the channels are available */
- for (i = 0; i < 8; i++) {
- unsigned int flags;
- u8 adj_chan = center_chan - 14 + i * 4;
-
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
- return NOT_ALLOWED;
-
- if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
- (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
- (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
- (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
- (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
- (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
- (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
- (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
- return NOT_ALLOWED;
- }
-
- return ALLOWED;
-}
-
-
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw)
-{
- unsigned int flag = 0;
- enum chan_allowed res, res2;
-
- res2 = res = allow_channel(mode, channel, &flag);
- if (bw == BW40MINUS) {
- if (!(flag & HOSTAPD_CHAN_HT40MINUS))
- return NOT_ALLOWED;
- res2 = allow_channel(mode, channel - 4, NULL);
- } else if (bw == BW40PLUS) {
- if (!(flag & HOSTAPD_CHAN_HT40PLUS))
- return NOT_ALLOWED;
- res2 = allow_channel(mode, channel + 4, NULL);
- } else if (bw == BW80) {
- res2 = verify_80mhz(mode, channel);
- } else if (bw == BW160) {
- res2 = verify_160mhz(mode, channel);
- }
-
- if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
- return NOT_ALLOWED;
-
- return ALLOWED;
-}
-
-
-static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
- const struct oper_class_map *op_class)
-{
- int chan;
- size_t i;
- struct hostapd_hw_modes *mode;
-
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
- if (!mode)
- return 0;
-
- if (op_class->op_class == 128 || op_class->op_class == 130) {
- u8 channels[] = { 42, 58, 106, 122, 138, 155 };
-
- for (i = 0; i < ARRAY_SIZE(channels); i++) {
- if (verify_channel(mode, channels[i], op_class->bw) ==
- NOT_ALLOWED)
- return 0;
- }
-
- return 1;
- }
-
- if (op_class->op_class == 129) {
- if (verify_channel(mode, 50, op_class->bw) == NOT_ALLOWED ||
- verify_channel(mode, 114, op_class->bw) == NOT_ALLOWED)
- return 0;
-
- return 1;
- }
-
- for (chan = op_class->min_chan; chan <= op_class->max_chan;
- chan += op_class->inc) {
- if (verify_channel(mode, chan, op_class->bw) == NOT_ALLOWED)
- return 0;
- }
-
- return 1;
-}
-
-
-int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
- size_t len)
-{
- struct wpabuf *buf;
- u8 op, current, chan;
- u8 *ie_len;
- int res;
-
- /*
- * Assume 20 MHz channel for now.
- * TODO: Use the secondary channel and VHT channel width that will be
- * used after association.
- */
- if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
- ¤t, &chan) == NUM_HOSTAPD_MODES)
- return 0;
-
- /*
- * Need 3 bytes for EID, length, and current operating class, plus
- * 1 byte for every other supported operating class.
- */
- buf = wpabuf_alloc(global_op_class_size + 3);
- if (!buf)
- return 0;
-
- wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
- /* Will set the length later, putting a placeholder */
- ie_len = wpabuf_put(buf, 1);
- 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]))
- wpabuf_put_u8(buf, global_op_class[op].op_class);
- }
-
- *ie_len = wpabuf_len(buf) - 2;
- if (*ie_len < 2 || wpabuf_len(buf) > len) {
- wpa_printf(MSG_ERROR,
- "Failed to add supported operating classes IE");
- res = 0;
- } else {
- os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
- res = wpabuf_len(buf);
- wpa_hexdump_buf(MSG_DEBUG,
- "MBO: Added supported operating classes IE",
- buf);
- }
-
- wpabuf_free(buf);
- return res;
-}
-
-
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
size_t len)
{
@@ -768,4 +510,33 @@
cell_capa[6] = mbo_cell_capa;
wpas_mbo_send_wnm_notification(wpa_s, cell_capa, 7);
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+}
+
+
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+ struct wpabuf *anqp_buf;
+ u8 *len_pos;
+
+ if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
+ wpa_printf(MSG_INFO, "MBO: " MACSTR
+ " does not support MBO - cannot request MBO ANQP elements from it",
+ MAC2STR(bss->bssid));
+ return NULL;
+ }
+
+ anqp_buf = wpabuf_alloc(10);
+ if (!anqp_buf)
+ return NULL;
+
+ len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(anqp_buf, OUI_WFA);
+ wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE);
+
+ wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
+ gas_anqp_set_element_len(anqp_buf, len_pos);
+
+ return anqp_buf;
}
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 89b033b..2ca81a3 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -66,9 +66,11 @@
}
-static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+static struct mesh_conf * mesh_config_create(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
struct mesh_conf *conf;
+ int cipher;
conf = os_zalloc(sizeof(struct mesh_conf));
if (!conf)
@@ -82,6 +84,33 @@
MESH_CONF_SEC_AMPE;
else
conf->security |= MESH_CONF_SEC_NONE;
+ conf->ieee80211w = ssid->ieee80211w;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+ if (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)
+ conf->ieee80211w = wpa_s->conf->pmf;
+ else
+ conf->ieee80211w = NO_MGMT_FRAME_PROTECTION;
+ }
+
+ cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher, 0);
+ if (cipher < 0 || cipher == WPA_CIPHER_TKIP) {
+ wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid pairwise cipher");
+ os_free(conf);
+ return NULL;
+ }
+ conf->pairwise_cipher = cipher;
+
+ cipher = wpa_pick_group_cipher(ssid->group_cipher);
+ if (cipher < 0 || cipher == WPA_CIPHER_TKIP ||
+ cipher == WPA_CIPHER_GTK_NOT_USED) {
+ wpa_msg(wpa_s, MSG_INFO, "mesh: Invalid group cipher");
+ os_free(conf);
+ return NULL;
+ }
+
+ conf->group_cipher = cipher;
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+ conf->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
/* defaults */
conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
@@ -117,7 +146,8 @@
static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid,
+ struct hostapd_freq_params *freq)
{
struct hostapd_iface *ifmsh;
struct hostapd_data *bss;
@@ -127,6 +157,7 @@
static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
size_t len;
int rate_len;
+ int frequency;
if (!wpa_s->conf->user_mpm) {
/* not much for us to do here */
@@ -146,7 +177,7 @@
if (!ifmsh->bss)
goto out_free;
- ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
+ ifmsh->bss[0] = bss = hostapd_alloc_bss_data(NULL, NULL, NULL);
if (!bss)
goto out_free;
@@ -155,7 +186,13 @@
bss->drv_priv = wpa_s->drv_priv;
bss->iface = ifmsh;
bss->mesh_sta_free_cb = mesh_mpm_free_sta;
- wpa_s->assoc_freq = ssid->frequency;
+ frequency = ssid->frequency;
+ if (frequency != freq->freq &&
+ frequency == freq->freq + freq->sec_channel_offset * 20) {
+ wpa_printf(MSG_DEBUG, "mesh: pri/sec channels switched");
+ frequency = freq->freq;
+ }
+ wpa_s->assoc_freq = frequency;
wpa_s->current_ssid = ssid;
/* setup an AP config for auth processing */
@@ -175,22 +212,16 @@
wpa_s->conf->dot11RSNASAERetransPeriod;
os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
- mconf = mesh_config_create(ssid);
+ mconf = mesh_config_create(wpa_s, ssid);
if (!mconf)
goto out_free;
ifmsh->mconf = mconf;
/* need conf->hw_mode for supported rates. */
- if (ssid->frequency == 0) {
- conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
- conf->channel = 1;
- } else {
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- }
+ conf->hw_mode = ieee80211_freq_to_chan(frequency, &conf->channel);
if (conf->hw_mode == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
- ssid->frequency);
+ frequency);
goto out_free;
}
if (ssid->ht40)
@@ -201,13 +232,13 @@
case VHT_CHANWIDTH_80MHZ:
case VHT_CHANWIDTH_80P80MHZ:
ieee80211_freq_to_chan(
- ssid->frequency,
+ frequency,
&conf->vht_oper_centr_freq_seg0_idx);
conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
break;
case VHT_CHANWIDTH_160MHZ:
ieee80211_freq_to_chan(
- ssid->frequency,
+ frequency,
&conf->vht_oper_centr_freq_seg0_idx);
conf->vht_oper_centr_freq_seg0_idx += ssid->ht40 * 2;
conf->vht_oper_centr_freq_seg0_idx += 40 / 5;
@@ -341,15 +372,9 @@
wpa_supplicant_mesh_deinit(wpa_s);
- if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
- wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- wpa_s->group_cipher = WPA_CIPHER_CCMP;
- wpa_s->mgmt_group_cipher = 0;
- } else {
- wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- wpa_s->group_cipher = WPA_CIPHER_NONE;
- wpa_s->mgmt_group_cipher = 0;
- }
+ wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+ wpa_s->group_cipher = WPA_CIPHER_NONE;
+ wpa_s->mgmt_group_cipher = 0;
os_memset(¶ms, 0, sizeof(params));
params.meshid = ssid->ssid;
@@ -383,7 +408,11 @@
params.beacon_int = ssid->beacon_int;
else if (wpa_s->conf->beacon_int > 0)
params.beacon_int = wpa_s->conf->beacon_int;
- params.max_peer_links = wpa_s->conf->max_peer_links;
+ if (ssid->dtim_period > 0)
+ 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;
if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
@@ -393,35 +422,46 @@
if (wpa_s->conf->user_mpm) {
params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
- params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params.conf.auto_plinks = 0;
} else {
params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
- params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ params.conf.auto_plinks = 1;
}
params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
- if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
+ 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\n", 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);
+
out:
return ret;
}
@@ -591,7 +631,7 @@
if (!mesh_wpa_s) {
wpa_printf(MSG_ERROR,
"mesh: Failed to create new wpa_supplicant interface");
- wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+ wpa_drv_if_remove(wpa_s, WPA_IF_MESH, ifname);
return -1;
}
mesh_wpa_s->mesh_if_created = 1;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index c014eaf..f152044 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ieee802_11.h"
@@ -35,19 +36,17 @@
PLINK_UNDEFINED,
OPN_ACPT,
OPN_RJCT,
- OPN_IGNR,
CNF_ACPT,
CNF_RJCT,
- CNF_IGNR,
CLS_ACPT,
- CLS_IGNR
+ REQ_RJCT
};
static const char * const mplstate[] = {
[0] = "UNINITIALIZED",
- [PLINK_LISTEN] = "LISTEN",
- [PLINK_OPEN_SENT] = "OPEN_SENT",
- [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [PLINK_IDLE] = "IDLE",
+ [PLINK_OPN_SNT] = "OPN_SNT",
+ [PLINK_OPN_RCVD] = "OPN_RCVD",
[PLINK_CNF_RCVD] = "CNF_RCVD",
[PLINK_ESTAB] = "ESTAB",
[PLINK_HOLDING] = "HOLDING",
@@ -58,12 +57,10 @@
[PLINK_UNDEFINED] = "UNDEFINED",
[OPN_ACPT] = "OPN_ACPT",
[OPN_RJCT] = "OPN_RJCT",
- [OPN_IGNR] = "OPN_IGNR",
[CNF_ACPT] = "CNF_ACPT",
[CNF_RJCT] = "CNF_RJCT",
- [CNF_IGNR] = "CNF_IGNR",
[CLS_ACPT] = "CLS_ACPT",
- [CLS_IGNR] = "CLS_IGNR"
+ [REQ_RJCT] = "REQ_RJCT",
};
@@ -195,12 +192,13 @@
sta->my_lid = llid;
sta->peer_lid = 0;
+ sta->peer_aid = 0;
/*
* We do not use wpa_mesh_set_plink_state() here because there is no
* entry in kernel yet.
*/
- sta->plink_state = PLINK_LISTEN;
+ sta->plink_state = PLINK_IDLE;
}
@@ -290,7 +288,8 @@
/* TODO: Add Connected to Mesh Gate/AS subfields */
wpabuf_put_u8(buf, info);
/* always forwarding & accepting plinks for now */
- wpabuf_put_u8(buf, 0x1 | 0x8);
+ wpabuf_put_u8(buf, MESH_CAP_ACCEPT_ADDITIONAL_PEER |
+ MESH_CAP_FORWARDING);
} else { /* Peer closing frame */
/* IE: Mesh ID */
wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
@@ -350,7 +349,7 @@
if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) {
u8 vht_capa_oper[2 + 12 + 2 + 5];
- pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper);
+ pos = hostapd_eid_vht_capabilities(bss, vht_capa_oper, 0);
pos = hostapd_eid_vht_operation(bss, pos);
wpabuf_put_data(buf, vht_capa_oper, pos - vht_capa_oper);
}
@@ -393,6 +392,7 @@
os_memset(¶ms, 0, sizeof(params));
params.addr = sta->addr;
params.plink_state = state;
+ params.peer_aid = sta->peer_aid;
params.set = 1;
ret = wpa_drv_sta_add(wpa_s, ¶ms);
@@ -423,8 +423,8 @@
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
switch (sta->plink_state) {
- case PLINK_OPEN_RCVD:
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_RCVD:
+ case PLINK_OPN_SNT:
/* retry timer */
if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
eloop_register_timeout(
@@ -558,7 +558,7 @@
return -1;
}
- if ((PLINK_OPEN_SENT <= sta->plink_state &&
+ if ((PLINK_OPN_SNT <= sta->plink_state &&
sta->plink_state <= PLINK_ESTAB) ||
(sta->sae && sta->sae->state > SAE_NOTHING)) {
wpa_msg(wpa_s, MSG_INFO,
@@ -567,7 +567,7 @@
}
if (conf->security == MESH_CONF_SEC_NONE) {
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
} else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
@@ -630,7 +630,7 @@
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
}
/*
@@ -647,8 +647,19 @@
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
struct hostapd_data *data = wpa_s->ifmsh->bss[0];
struct sta_info *sta;
+#ifdef CONFIG_IEEE80211N
+ struct ieee80211_ht_operation *oper;
+#endif /* CONFIG_IEEE80211N */
int ret;
+ if (elems->mesh_config_len >= 7 &&
+ !(elems->mesh_config[6] & MESH_CAP_ACCEPT_ADDITIONAL_PEER)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "mesh: Ignore a crowded peer " MACSTR,
+ MAC2STR(addr));
+ return NULL;
+ }
+
sta = ap_get_sta(data, addr);
if (!sta) {
sta = ap_sta_add(data, addr);
@@ -670,6 +681,17 @@
#ifdef CONFIG_IEEE80211N
copy_sta_ht_capab(data, sta, elems->ht_capabilities);
+
+ oper = (struct ieee80211_ht_operation *) elems->ht_operation;
+ if (oper &&
+ !(oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) &&
+ sta->ht_capabilities) {
+ wpa_msg(wpa_s, MSG_DEBUG, MACSTR
+ " does not support 40 MHz bandwidth",
+ MAC2STR(sta->addr));
+ set_disable_ht40(sta->ht_capabilities, 1);
+ }
+
update_ht_state(data, sta);
#endif /* CONFIG_IEEE80211N */
@@ -691,6 +713,7 @@
params.addr = addr;
params.plink_state = sta->plink_state;
params.aid = sta->aid;
+ params.peer_aid = sta->peer_aid;
params.listen_interval = 100;
params.ht_capabilities = sta->ht_capabilities;
params.vht_capabilities = sta->vht_capabilities;
@@ -761,9 +784,9 @@
}
if (conf->security == MESH_CONF_SEC_NONE) {
- if (sta->plink_state < PLINK_OPEN_SENT ||
+ if (sta->plink_state < PLINK_OPN_SNT ||
sta->plink_state > PLINK_ESTAB)
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_SNT);
} else {
mesh_rsn_auth_sae_sta(wpa_s, sta);
}
@@ -793,18 +816,32 @@
MAC2STR(sta->addr));
if (conf->security & MESH_CONF_SEC_AMPE) {
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
- seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
- wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
- seq, sizeof(seq),
- sta->mgtk, sizeof(sta->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
+ sta->addr, 0, 0, seq, sizeof(seq),
+ sta->mtk, sta->mtk_len);
- wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
- wpa_hexdump_key(MSG_DEBUG, "mgtk:",
- sta->mgtk, sizeof(sta->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK",
+ sta->mgtk, sta->mgtk_len);
+ wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
+ sta->addr, sta->mgtk_key_id, 0,
+ sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
+ sta->mgtk, sta->mgtk_len);
+
+ if (sta->igtk_len) {
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
+ sta->igtk_rsc, sizeof(sta->igtk_rsc));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK",
+ sta->igtk, sta->igtk_len);
+ wpa_drv_set_key(
+ wpa_s,
+ wpa_cipher_to_alg(conf->mgmt_group_cipher),
+ sta->addr, sta->igtk_key_id, 0,
+ sta->igtk_rsc, sizeof(sta->igtk_rsc),
+ sta->igtk, sta->igtk_len);
+ }
}
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
@@ -824,36 +861,40 @@
static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
- enum plink_event event)
+ enum plink_event event, u16 reason)
{
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
- u16 reason = 0;
wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
MAC2STR(sta->addr), mplstate[sta->plink_state],
mplevent[event]);
switch (sta->plink_state) {
- case PLINK_LISTEN:
+ case PLINK_IDLE:
switch (event) {
case CLS_ACPT:
mesh_mpm_fsm_restart(wpa_s, sta);
break;
case OPN_ACPT:
- mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
0);
break;
+ case REQ_RJCT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
default:
break;
}
break;
- case PLINK_OPEN_SENT:
+ case PLINK_OPN_SNT:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -868,12 +909,13 @@
break;
case OPN_ACPT:
/* retry timer is left untouched */
- wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPN_RCVD);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
break;
case CNF_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
eloop_register_timeout(
conf->dot11MeshConfirmTimeout / 1000,
(conf->dot11MeshConfirmTimeout % 1000) * 1000,
@@ -883,11 +925,12 @@
break;
}
break;
- case PLINK_OPEN_RCVD:
+ case PLINK_OPN_RCVD:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -918,7 +961,8 @@
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
/* fall-through */
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
@@ -933,6 +977,8 @@
PLINK_CLOSE, reason);
break;
case OPN_ACPT:
+ if (conf->security & MESH_CONF_SEC_AMPE)
+ mesh_rsn_derive_mtk(wpa_s, sta);
mesh_mpm_plink_estab(wpa_s, sta);
mesh_mpm_send_plink_action(wpa_s, sta,
PLINK_CONFIRM, 0);
@@ -943,9 +989,12 @@
break;
case PLINK_ESTAB:
switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
case CLS_ACPT:
wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
- reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
eloop_register_timeout(
conf->dot11MeshHoldingTimeout / 1000,
@@ -1006,13 +1055,14 @@
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
struct sta_info *sta;
- u16 plid = 0, llid = 0;
+ u16 plid = 0, llid = 0, aid = 0;
enum plink_event event;
struct ieee802_11_elems elems;
struct mesh_peer_mgmt_ie peer_mgmt_ie;
const u8 *ies;
size_t ie_len;
int ret;
+ u16 reason = 0;
if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
return;
@@ -1043,7 +1093,8 @@
ie_len -= 2;
}
if (action_field == PLINK_CONFIRM) {
- wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+ aid = WPA_GET_LE16(ies);
+ wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", aid);
ies += 2; /* aid */
ie_len -= 2;
}
@@ -1087,6 +1138,10 @@
llid = WPA_GET_LE16(peer_mgmt_ie.plid);
wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+ if (action_field == PLINK_CLOSE)
+ wpa_printf(MSG_DEBUG, "MPM: close reason=%u",
+ WPA_GET_LE16(peer_mgmt_ie.reason));
+
sta = ap_get_sta(hapd, mgmt->sa);
/*
@@ -1095,7 +1150,7 @@
*/
if (!sta && action_field == PLINK_OPEN &&
(!(mconf->security & MESH_CONF_SEC_AMPE) ||
- wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa)))
+ wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa, NULL)))
sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
if (!sta) {
@@ -1114,13 +1169,24 @@
if (!sta->my_lid)
mesh_mpm_init_link(wpa_s, sta);
- if ((mconf->security & MESH_CONF_SEC_AMPE) &&
- mesh_rsn_process_ampe(wpa_s, sta, &elems,
- &mgmt->u.action.category,
- peer_mgmt_ie.chosen_pmk,
- ies, ie_len)) {
- wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
- return;
+ if (mconf->security & MESH_CONF_SEC_AMPE) {
+ int res;
+
+ res = mesh_rsn_process_ampe(wpa_s, sta, &elems,
+ &mgmt->u.action.category,
+ peer_mgmt_ie.chosen_pmk,
+ ies, ie_len);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: RSN process rejected frame (res=%d)",
+ res);
+ if (action_field == PLINK_OPEN && res == -2) {
+ /* AES-SIV decryption failed */
+ mesh_mpm_fsm(wpa_s, sta, OPN_RJCT,
+ WLAN_REASON_MESH_INVALID_GTK);
+ }
+ return;
+ }
}
if (sta->plink_state == PLINK_BLOCKED) {
@@ -1132,12 +1198,16 @@
switch (action_field) {
case PLINK_OPEN:
if (plink_free_count(hapd) == 0) {
- event = OPN_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->peer_lid && sta->peer_lid != plid) {
- event = OPN_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
sta->peer_lid = plid;
event = OPN_ACPT;
@@ -1145,16 +1215,21 @@
break;
case PLINK_CONFIRM:
if (plink_free_count(hapd) == 0) {
- event = CNF_IGNR;
+ event = REQ_RJCT;
+ reason = WLAN_REASON_MESH_MAX_PEERS;
wpa_printf(MSG_INFO,
"MPM: Peer link num over quota(%d)",
hapd->max_plinks);
} else if (sta->my_lid != llid ||
(sta->peer_lid && sta->peer_lid != plid)) {
- event = CNF_IGNR;
+ wpa_printf(MSG_DEBUG,
+ "MPM: lid mismatch: my_lid: 0x%x != 0x%x or peer_lid: 0x%x != 0x%x",
+ sta->my_lid, llid, sta->peer_lid, plid);
+ return; /* no FSM event */
} else {
if (!sta->peer_lid)
sta->peer_lid = plid;
+ sta->peer_aid = aid;
event = CNF_ACPT;
}
break;
@@ -1170,12 +1245,19 @@
* restarted.
*/
event = CLS_ACPT;
- else if (sta->peer_lid != plid)
- event = CLS_IGNR;
- else if (peer_mgmt_ie.plid && sta->my_lid != llid)
- event = CLS_IGNR;
- else
+ else if (sta->peer_lid != plid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: peer_lid mismatch: 0x%x != 0x%x",
+ sta->peer_lid, plid);
+ return; /* no FSM event */
+ } else if (peer_mgmt_ie.plid && sta->my_lid != llid) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: my_lid mismatch: 0x%x != 0x%x",
+ sta->my_lid, llid);
+ return; /* no FSM event */
+ } else {
event = CLS_ACPT;
+ }
break;
default:
/*
@@ -1185,7 +1267,7 @@
*/
return;
}
- mesh_mpm_fsm(wpa_s, sta, event);
+ mesh_mpm_fsm(wpa_s, sta, event, reason);
}
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 1994f3f..628382c 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -136,49 +136,71 @@
}
-static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
+ enum mfp_options ieee80211w)
{
struct wpa_auth_config conf;
- struct wpa_auth_callbacks cb;
+ static const struct wpa_auth_callbacks cb = {
+ .logger = auth_logger,
+ .get_psk = auth_get_psk,
+ .set_key = auth_set_key,
+ .start_ampe = auth_start_ampe,
+ };
u8 seq[6] = {};
wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
os_memset(&conf, 0, sizeof(conf));
- conf.wpa = 2;
+ conf.wpa = WPA_PROTO_RSN;
conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
- conf.wpa_pairwise = WPA_CIPHER_CCMP;
- conf.rsn_pairwise = WPA_CIPHER_CCMP;
- conf.wpa_group = WPA_CIPHER_CCMP;
+ conf.wpa_pairwise = rsn->pairwise_cipher;
+ conf.rsn_pairwise = rsn->pairwise_cipher;
+ conf.wpa_group = rsn->group_cipher;
conf.eapol_version = 0;
conf.wpa_group_rekey = -1;
+ conf.wpa_group_update_count = 4;
+ conf.wpa_pairwise_update_count = 4;
+#ifdef CONFIG_IEEE80211W
+ conf.ieee80211w = ieee80211w;
+ if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
+ conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
- os_memset(&cb, 0, sizeof(cb));
- cb.ctx = rsn;
- cb.logger = auth_logger;
- cb.get_psk = auth_get_psk;
- cb.set_key = auth_set_key;
- cb.start_ampe = auth_start_ampe;
-
- rsn->auth = wpa_init(addr, &conf, &cb);
+ rsn->auth = wpa_init(addr, &conf, &cb, rsn);
if (rsn->auth == NULL) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
return -1;
}
/* TODO: support rekeying */
- if (random_get_bytes(rsn->mgtk, 16) < 0) {
- wpa_deinit(rsn->auth);
+ rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group);
+ if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0)
return -1;
- }
+ rsn->mgtk_key_id = 1;
- /* group mgmt */
- wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
- seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+#ifdef CONFIG_IEEE80211W
+ if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
+ if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
+ return -1;
+ rsn->igtk_key_id = 4;
+
+ /* group mgmt */
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
+ rsn->igtk, rsn->igtk_len);
+ wpa_drv_set_key(rsn->wpa_s,
+ wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
+ rsn->igtk_key_id, 1,
+ seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
/* group privacy / data frames */
- wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
- seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
+ rsn->mgtk, rsn->mgtk_len);
+ wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
+ rsn->mgtk_key_id, 1, seq, sizeof(seq),
+ rsn->mgtk, rsn->mgtk_len);
return 0;
}
@@ -187,6 +209,9 @@
static void mesh_rsn_deinit(struct mesh_rsn *rsn)
{
os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+ rsn->mgtk_len = 0;
+ os_memset(rsn->igtk, 0, sizeof(rsn->igtk));
+ rsn->igtk_len = 0;
if (rsn->auth)
wpa_deinit(rsn->auth);
}
@@ -199,13 +224,20 @@
struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
const u8 *ie;
size_t ie_len;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ struct external_pmksa_cache *entry;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
if (mesh_rsn == NULL)
return NULL;
mesh_rsn->wpa_s = wpa_s;
+ mesh_rsn->pairwise_cipher = conf->pairwise_cipher;
+ mesh_rsn->group_cipher = conf->group_cipher;
+ mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
- if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+ if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
+ conf->ieee80211w) < 0) {
mesh_rsn_deinit(mesh_rsn);
os_free(mesh_rsn);
return NULL;
@@ -213,6 +245,22 @@
bss->wpa_auth = mesh_rsn->auth;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+ struct external_pmksa_cache,
+ list)) != NULL) {
+ int ret;
+
+ ret = wpa_auth_pmksa_add_entry(bss->wpa_auth,
+ entry->pmksa_cache);
+ dl_list_del(&entry->list);
+ os_free(entry);
+
+ if (ret < 0)
+ return NULL;
+ }
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
conf->rsn_ie = (u8 *) ie;
conf->rsn_ie_len = ie_len;
@@ -304,7 +352,7 @@
return -1;
}
- pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr);
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, NULL);
if (pmksa) {
if (!sta->wpa_sm)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
@@ -334,7 +382,6 @@
"AUTH: started authentication with SAE peer: " MACSTR,
MAC2STR(sta->addr));
- wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
ret = auth_sae_init_committed(hapd, sta);
if (ret)
return ret;
@@ -358,18 +405,27 @@
{
u8 *myaddr = rsn->wpa_s->own_addr;
u8 *peer = sta->addr;
- u8 *addr1 = peer, *addr2 = myaddr;
- u8 context[AES_BLOCK_SIZE];
+ u8 *addr1, *addr2;
+ u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context;
- /* SAE */
- RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+ /*
+ * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite ||
+ * min(localMAC, peerMAC) || max(localMAC, peerMAC))
+ */
+ /* Selected AKM Suite: SAE */
+ RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+ ptr += RSN_SELECTOR_LEN;
if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
addr1 = myaddr;
addr2 = peer;
+ } else {
+ addr1 = peer;
+ addr2 = myaddr;
}
- os_memcpy(context + 4, addr1, ETH_ALEN);
- os_memcpy(context + 10, addr2, ETH_ALEN);
+ os_memcpy(ptr, addr1, ETH_ALEN);
+ ptr += ETH_ALEN;
+ os_memcpy(ptr, addr2, ETH_ALEN);
sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
context, sizeof(context), sta->aek, sizeof(sta->aek));
@@ -381,40 +437,44 @@
{
u8 *ptr;
u8 *min, *max;
- u16 min_lid, max_lid;
- size_t nonce_len = sizeof(sta->my_nonce);
- size_t lid_len = sizeof(sta->my_lid);
u8 *myaddr = wpa_s->own_addr;
u8 *peer = sta->addr;
- /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
- u8 context[64 + 4 + 4 + 12];
+ u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN];
+ /*
+ * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce,
+ * peerNonce) || max(localNonce, peerNonce) || min(localLinkID,
+ * peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite ||
+ * min(localMAC, peerMAC) || max(localMAC, peerMAC))
+ */
ptr = context;
- if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+ if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) {
min = sta->my_nonce;
max = sta->peer_nonce;
} else {
min = sta->peer_nonce;
max = sta->my_nonce;
}
- os_memcpy(ptr, min, nonce_len);
- os_memcpy(ptr + nonce_len, max, nonce_len);
- ptr += 2 * nonce_len;
+ os_memcpy(ptr, min, WPA_NONCE_LEN);
+ ptr += WPA_NONCE_LEN;
+ os_memcpy(ptr, max, WPA_NONCE_LEN);
+ ptr += WPA_NONCE_LEN;
if (sta->my_lid < sta->peer_lid) {
- min_lid = host_to_le16(sta->my_lid);
- max_lid = host_to_le16(sta->peer_lid);
+ WPA_PUT_LE16(ptr, sta->my_lid);
+ ptr += 2;
+ WPA_PUT_LE16(ptr, sta->peer_lid);
+ ptr += 2;
} else {
- min_lid = host_to_le16(sta->peer_lid);
- max_lid = host_to_le16(sta->my_lid);
+ WPA_PUT_LE16(ptr, sta->peer_lid);
+ ptr += 2;
+ WPA_PUT_LE16(ptr, sta->my_lid);
+ ptr += 2;
}
- os_memcpy(ptr, &min_lid, lid_len);
- os_memcpy(ptr + lid_len, &max_lid, lid_len);
- ptr += 2 * lid_len;
- /* SAE */
- RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
- ptr += 4;
+ /* Selected AKM Suite: SAE */
+ RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
+ ptr += RSN_SELECTOR_LEN;
if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
min = myaddr;
@@ -424,22 +484,24 @@
max = myaddr;
}
os_memcpy(ptr, min, ETH_ALEN);
- os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+ ptr += ETH_ALEN;
+ os_memcpy(ptr, max, ETH_ALEN);
- sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+ sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher);
+ sha256_prf(sta->sae->pmk, SAE_PMK_LEN,
"Temporal Key Derivation", context, sizeof(context),
- sta->mtk, sizeof(sta->mtk));
+ sta->mtk, sta->mtk_len);
return 0;
}
void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
{
- if (random_get_bytes(sta->my_nonce, 32) < 0) {
+ if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) {
wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
/* TODO: How to handle this more cleanly? */
}
- os_memset(sta->peer_nonce, 0, 32);
+ os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN);
mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
}
@@ -455,65 +517,94 @@
{
struct ieee80211_ampe_ie *ampe;
u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
- u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+ u8 *ampe_ie, *pos, *mic_payload;
const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
int ret = 0;
+ size_t len;
- if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+ len = sizeof(*ampe);
+ if (cat[1] == PLINK_OPEN)
+ len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
+#ifdef CONFIG_IEEE80211W
+ if (cat[1] == PLINK_OPEN && rsn->igtk_len)
+ len += 2 + 6 + rsn->igtk_len;
+#endif /* CONFIG_IEEE80211W */
+
+ if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
wpa_printf(MSG_ERROR, "protect frame: buffer too small");
return -EINVAL;
}
- ampe_ie = os_zalloc(2 + sizeof(*ampe));
+ ampe_ie = os_zalloc(2 + len);
if (!ampe_ie) {
wpa_printf(MSG_ERROR, "protect frame: out of memory");
return -ENOMEM;
}
- mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
- if (!mic_ie) {
- wpa_printf(MSG_ERROR, "protect frame: out of memory");
- ret = -ENOMEM;
- goto free;
- }
-
/* IE: AMPE */
ampe_ie[0] = WLAN_EID_AMPE;
- ampe_ie[1] = sizeof(*ampe);
+ ampe_ie[1] = len;
ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
- wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
- os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
- os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
- /* incomplete: see 13.5.4 */
+ RSN_CIPHER_SUITE_CCMP);
+ os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN);
+ os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN);
+
+ pos = (u8 *) (ampe + 1);
+ if (cat[1] != PLINK_OPEN)
+ goto skip_keys;
+
+ /* TODO: Key Replay Counter[8] optionally for
+ * Mesh Group Key Inform/Acknowledge frames */
+
/* TODO: static mgtk for now since we don't support rekeying! */
- os_memcpy(ampe->mgtk, rsn->mgtk, 16);
- /* TODO: Populate Key RSC */
- /* expire in 13 decades or so */
- os_memset(ampe->key_expiration, 0xff, 4);
+ /*
+ * GTKdata[variable]:
+ * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+ */
+ os_memcpy(pos, rsn->mgtk, rsn->mgtk_len);
+ pos += rsn->mgtk_len;
+ wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos);
+ pos += WPA_KEY_RSC_LEN;
+ /* Use fixed GTKExpirationTime for now */
+ WPA_PUT_LE32(pos, 0xffffffff);
+ pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+ /*
+ * IGTKdata[variable]:
+ * Key ID[2], IPN[6], IGTK[variable]
+ */
+ if (rsn->igtk_len) {
+ WPA_PUT_LE16(pos, rsn->igtk_key_id);
+ pos += 2;
+ wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos);
+ pos += 6;
+ os_memcpy(pos, rsn->igtk, rsn->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
+
+skip_keys:
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
+ ampe_ie, 2 + len);
/* IE: MIC */
- mic_ie[0] = WLAN_EID_MIC;
- mic_ie[1] = AES_BLOCK_SIZE;
- wpabuf_put_data(buf, mic_ie, 2);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, AES_BLOCK_SIZE);
/* MIC field is output ciphertext */
/* encrypt after MIC */
- mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
- AES_BLOCK_SIZE);
+ mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE);
- if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+ if (aes_siv_encrypt(sta->aek, sizeof(sta->aek), ampe_ie, 2 + len, 3,
aad, aad_len, mic_payload)) {
wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
ret = -ENOMEM;
- goto free;
}
-free:
os_free(ampe_ie);
- os_free(mic_ie);
return ret;
}
@@ -526,19 +617,20 @@
{
int ret = 0;
struct ieee80211_ampe_ie *ampe;
- u8 null_nonce[32] = {};
+ u8 null_nonce[WPA_NONCE_LEN] = {};
u8 ampe_eid;
u8 ampe_ie_len;
- u8 *ampe_buf, *crypt = NULL;
+ u8 *ampe_buf, *crypt = NULL, *pos, *end;
size_t crypt_len;
const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
(elems->mic - 2) - cat };
+ size_t key_len;
if (!sta->sae) {
struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
- if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) {
+ if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, NULL)) {
wpa_printf(MSG_INFO,
"Mesh RSN: SAE is not prepared yet");
return -1;
@@ -562,7 +654,7 @@
return -1;
crypt_len = elems_len - (elems->mic - start);
- if (crypt_len < 2) {
+ if (crypt_len < 2 + AES_BLOCK_SIZE) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
return -1;
}
@@ -577,17 +669,22 @@
os_memcpy(crypt, elems->mic, crypt_len);
- if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
+ if (aes_siv_decrypt(sta->aek, sizeof(sta->aek), crypt, crypt_len, 3,
aad, aad_len, ampe_buf)) {
wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
- ret = -1;
+ ret = -2;
goto free;
}
+ crypt_len -= AES_BLOCK_SIZE;
+ wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element",
+ ampe_buf, crypt_len);
+
ampe_eid = *ampe_buf++;
ampe_ie_len = *ampe_buf++;
if (ampe_eid != WLAN_EID_AMPE ||
+ (size_t) 2 + ampe_ie_len > crypt_len ||
ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
ret = -1;
@@ -595,17 +692,89 @@
}
ampe = (struct ieee80211_ampe_ie *) ampe_buf;
- if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
- os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+ pos = (u8 *) (ampe + 1);
+ end = ampe_buf + ampe_ie_len;
+ if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 &&
+ os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
ret = -1;
goto free;
}
os_memcpy(sta->peer_nonce, ampe->local_nonce,
sizeof(ampe->local_nonce));
- os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
- /* todo parse mgtk expiration */
+ /* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge
+ * frames */
+
+ /*
+ * GTKdata shall not be included in Mesh Peering Confirm. While the
+ * standard does not state the same about IGTKdata, that same constraint
+ * needs to apply for it. It makes no sense to include the keys in Mesh
+ * Peering Close frames either, so while the standard does not seem to
+ * have a shall statement for these, they are described without
+ * mentioning GTKdata.
+ *
+ * An earlier implementation used to add GTKdata to both Mesh Peering
+ * Open and Mesh Peering Confirm frames, so ignore the possibly present
+ * GTKdata frame without rejecting the frame as a backwards
+ * compatibility mechanism.
+ */
+ if (cat[1] != PLINK_OPEN) {
+ if (end > pos) {
+ wpa_hexdump_key(MSG_DEBUG,
+ "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close",
+ pos, end - pos);
+ }
+ goto free;
+ }
+
+ /*
+ * GTKdata[variable]:
+ * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
+ */
+ sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */
+ key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher);
+ if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element");
+ ret = -1;
+ goto free;
+ }
+ sta->mgtk_len = key_len;
+ os_memcpy(sta->mgtk, pos, sta->mgtk_len);
+ wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK",
+ sta->mgtk, sta->mgtk_len);
+ pos += sta->mgtk_len;
+ wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC",
+ pos, WPA_KEY_RSC_LEN);
+ os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc));
+ pos += WPA_KEY_RSC_LEN;
+ wpa_printf(MSG_DEBUG,
+ "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds",
+ WPA_GET_LE32(pos));
+ pos += 4;
+
+#ifdef CONFIG_IEEE80211W
+ /*
+ * IGTKdata[variable]:
+ * Key ID[2], IPN[6], IGTK[variable]
+ */
+ key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher);
+ if (end - pos >= (int) (2 + 6 + key_len)) {
+ sta->igtk_key_id = WPA_GET_LE16(pos);
+ wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u",
+ sta->igtk_key_id);
+ pos += 2;
+ os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc));
+ wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN",
+ sta->igtk_rsc, sizeof(sta->igtk_rsc));
+ pos += 6;
+ os_memcpy(sta->igtk, pos, key_len);
+ sta->igtk_len = key_len;
+ wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
+ sta->igtk, sta->igtk_len);
+ }
+#endif /* CONFIG_IEEE80211W */
+
free:
os_free(crypt);
return ret;
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
index 89601d4..8775ced 100644
--- a/wpa_supplicant/mesh_rsn.h
+++ b/wpa_supplicant/mesh_rsn.h
@@ -12,7 +12,15 @@
struct mesh_rsn {
struct wpa_supplicant *wpa_s;
struct wpa_authenticator *auth;
- u8 mgtk[16];
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ u8 mgtk[WPA_TK_MAX_LEN];
+ size_t mgtk_len;
+ u8 mgtk_key_id;
+ unsigned int mgmt_group_cipher;
+ u8 igtk_key_id;
+ u8 igtk[WPA_TK_MAX_LEN];
+ size_t igtk_len;
#ifdef CONFIG_SAE
struct wpabuf *sae_token;
int sae_group_index;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index e739363..9464c4b 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -13,7 +13,6 @@
#include "config.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
-#include "binder/binder.h"
#include "dbus/dbus_common.h"
#include "dbus/dbus_old.h"
#include "dbus/dbus_new.h"
@@ -24,6 +23,7 @@
#include "p2p_supplicant.h"
#include "sme.h"
#include "notify.h"
+#include "hidl.h"
int wpas_notify_supplicant_initialized(struct wpa_global *global)
{
@@ -35,11 +35,11 @@
}
#endif /* CONFIG_DBUS */
-#ifdef CONFIG_BINDER
- global->binder = wpas_binder_init(global);
- if (!global->binder)
+#ifdef CONFIG_HIDL
+ global->hidl = wpas_hidl_init(global);
+ if (!global->hidl)
return -1;
-#endif /* CONFIG_BINDER */
+#endif /* CONFIG_HIDL */
return 0;
}
@@ -52,22 +52,25 @@
wpas_dbus_deinit(global->dbus);
#endif /* CONFIG_DBUS */
-#ifdef CONFIG_BINDER
- if (global->binder)
- wpas_binder_deinit(global->binder);
-#endif /* CONFIG_BINDER */
+#ifdef CONFIG_HIDL
+ if (global->hidl)
+ wpas_hidl_deinit(global->hidl);
+#endif /* CONFIG_HIDL */
}
int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->p2p_mgmt)
- return 0;
+ if (!wpa_s->p2p_mgmt) {
+ if (wpas_dbus_register_iface(wpa_s))
+ return -1;
- if (wpas_dbus_register_iface(wpa_s))
- return -1;
+ if (wpas_dbus_register_interface(wpa_s))
+ return -1;
+ }
- if (wpas_dbus_register_interface(wpa_s))
+ /* HIDL interface wants to keep track of the P2P mgmt iface. */
+ if (wpas_hidl_register_interface(wpa_s))
return -1;
return 0;
@@ -76,14 +79,16 @@
void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->p2p_mgmt)
- return;
+ if (!wpa_s->p2p_mgmt) {
+ /* unregister interface in old DBus ctrl iface */
+ wpas_dbus_unregister_iface(wpa_s);
- /* unregister interface in old DBus ctrl iface */
- wpas_dbus_unregister_iface(wpa_s);
+ /* unregister interface in new DBus ctrl iface */
+ wpas_dbus_unregister_interface(wpa_s);
+ }
- /* unregister interface in new DBus ctrl iface */
- wpas_dbus_unregister_interface(wpa_s);
+ /* HIDL interface wants to keep track of the P2P mgmt iface. */
+ wpas_hidl_unregister_interface(wpa_s);
}
@@ -128,6 +133,8 @@
wpa_ssid_txt(wpa_s->current_ssid->ssid,
wpa_s->current_ssid->ssid_len) : "");
#endif /* ANDROID */
+
+ wpas_hidl_notify_state_changed(wpa_s);
}
@@ -137,6 +144,8 @@
return;
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
+
+ wpas_hidl_notify_disconnect_reason(wpa_s);
}
@@ -146,8 +155,16 @@
return;
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_ASSOC_STATUS_CODE);
+
+ wpas_hidl_notify_assoc_reject(wpa_s);
}
+void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s) {
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_hidl_notify_auth_timeout(wpa_s);
+}
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
@@ -173,6 +190,8 @@
return;
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS);
+
+ wpas_hidl_notify_bssid_changed(wpa_s);
}
@@ -214,6 +233,8 @@
return;
wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
+
+ wpas_hidl_notify_network_request(wpa_s, ssid, rtype, default_txt);
}
@@ -286,6 +307,10 @@
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_fail(wpa_s, fail);
+
+ wpas_hidl_notify_wps_event_fail(wpa_s, fail->peer_macaddr,
+ fail->config_error,
+ fail->error_indication);
#endif /* CONFIG_WPS */
}
@@ -297,6 +322,8 @@
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_success(wpa_s);
+
+ wpas_hidl_notify_wps_event_success(wpa_s);
#endif /* CONFIG_WPS */
}
@@ -307,6 +334,8 @@
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_pbc_overlap(wpa_s);
+
+ wpas_hidl_notify_wps_event_pbc_overlap(wpa_s);
#endif /* CONFIG_WPS */
}
@@ -323,8 +352,10 @@
* applications since these network objects won't behave like
* regular ones.
*/
- if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
+ if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s) {
wpas_dbus_register_network(wpa_s, ssid);
+ wpas_hidl_register_network(wpa_s, ssid);
+ }
}
@@ -333,6 +364,7 @@
{
#ifdef CONFIG_P2P
wpas_dbus_register_persistent_group(wpa_s, ssid);
+ wpas_hidl_register_network(wpa_s, ssid);
#endif /* CONFIG_P2P */
}
@@ -342,6 +374,7 @@
{
#ifdef CONFIG_P2P
wpas_dbus_unregister_persistent_group(wpa_s, ssid->id);
+ wpas_hidl_unregister_network(wpa_s, ssid);
#endif /* CONFIG_P2P */
}
@@ -354,8 +387,10 @@
if (wpa_s->wpa)
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s &&
- !wpa_s->p2p_mgmt)
+ !wpa_s->p2p_mgmt) {
wpas_dbus_unregister_network(wpa_s, ssid->id);
+ wpas_hidl_unregister_network(wpa_s, ssid);
+ }
if (network_is_persistent_group(ssid))
wpas_notify_persistent_group_removed(wpa_s, ssid);
@@ -566,19 +601,27 @@
{
/* Notify P2P find has stopped */
wpas_dbus_signal_p2p_find_stopped(wpa_s);
+
+ wpas_hidl_notify_p2p_find_stopped(wpa_s);
}
void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
- const u8 *dev_addr, int new_device)
+ const u8 *addr, const struct p2p_peer_info *info,
+ const u8* peer_wfd_device_info, u8 peer_wfd_device_info_len,
+ int new_device)
{
if (new_device) {
/* Create the new peer object */
- wpas_dbus_register_peer(wpa_s, dev_addr);
+ wpas_dbus_register_peer(wpa_s, info->p2p_device_addr);
}
/* Notify a new peer has been detected*/
- wpas_dbus_signal_peer_device_found(wpa_s, dev_addr);
+ wpas_dbus_signal_peer_device_found(wpa_s, info->p2p_device_addr);
+
+ wpas_hidl_notify_p2p_device_found(wpa_s, addr, info,
+ peer_wfd_device_info,
+ peer_wfd_device_info_len);
}
@@ -589,6 +632,8 @@
/* Create signal on interface object*/
wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr);
+
+ wpas_hidl_notify_p2p_device_lost(wpa_s, dev_addr);
}
@@ -599,6 +644,8 @@
wpas_dbus_signal_p2p_group_removed(wpa_s, role);
wpas_dbus_unregister_p2p_group(wpa_s, ssid);
+
+ wpas_hidl_notify_p2p_group_removed(wpa_s, ssid, role);
}
@@ -606,6 +653,8 @@
const u8 *src, u16 dev_passwd_id, u8 go_intent)
{
wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id, go_intent);
+
+ wpas_hidl_notify_p2p_go_neg_req(wpa_s, src, dev_passwd_id, go_intent);
}
@@ -613,6 +662,8 @@
struct p2p_go_neg_results *res)
{
wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res);
+
+ wpas_hidl_notify_p2p_go_neg_completed(wpa_s, res);
}
@@ -620,6 +671,8 @@
int status, const u8 *bssid)
{
wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid);
+
+ wpas_hidl_notify_p2p_invitation_result(wpa_s, status, bssid);
}
@@ -639,6 +692,9 @@
{
wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic,
tlvs, tlvs_len);
+
+ wpas_hidl_notify_p2p_sd_response(wpa_s, sa, update_indic,
+ tlvs, tlvs_len);
}
@@ -664,17 +720,24 @@
wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request,
status, config_methods,
generated_pin);
+
+ wpas_hidl_notify_p2p_provision_discovery(wpa_s, dev_addr, request,
+ status, config_methods,
+ generated_pin);
+
}
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, int network_id,
- int client)
+ struct wpa_ssid *ssid, int persistent,
+ int client, const u8 *ip)
{
/* Notify a group has been started */
wpas_dbus_register_p2p_group(wpa_s, ssid);
- wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+ wpas_dbus_signal_p2p_group_started(wpa_s, client, persistent, ip);
+
+ wpas_hidl_notify_p2p_group_started(wpa_s, ssid, persistent, client);
}
@@ -683,6 +746,8 @@
{
/* Notify a group formation failed */
wpas_dbus_signal_p2p_group_formation_failure(wpa_s, reason);
+
+ wpas_hidl_notify_p2p_group_formation_failure(wpa_s, reason);
}
@@ -700,6 +765,9 @@
/* Notify a P2P Invitation Request */
wpas_dbus_signal_p2p_invitation_received(wpa_s, sa, go_dev_addr, bssid,
id, op_freq);
+
+ wpas_hidl_notify_p2p_invitation_received(wpa_s, sa, go_dev_addr, bssid,
+ id, op_freq);
}
#endif /* CONFIG_P2P */
@@ -722,6 +790,8 @@
/* Notify listeners a new station has been authorized */
wpas_dbus_signal_sta_authorized(wpa_s, sta);
+
+ wpas_hidl_notify_ap_sta_authorized(wpa_s, sta, p2p_dev_addr);
}
@@ -740,6 +810,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);
}
@@ -850,3 +922,53 @@
}
#endif /* CONFIG_P2P */
}
+
+void wpas_notify_anqp_query_done(struct wpa_supplicant *wpa_s, const u8* bssid,
+ const char *result,
+ const struct wpa_bss_anqp *anqp)
+{
+#ifdef CONFIG_INTERWORKING
+ if (!wpa_s || !bssid || !anqp)
+ return;
+
+ wpas_hidl_notify_anqp_query_done(wpa_s, bssid, result, anqp);
+#endif /* CONFIG_INTERWORKING */
+}
+
+void wpas_notify_hs20_icon_query_done(struct wpa_supplicant *wpa_s, const u8* bssid,
+ const char* file_name, const u8* image,
+ u32 image_length)
+{
+#ifdef CONFIG_HS20
+ if (!wpa_s || !bssid || !file_name || !image)
+ return;
+
+ wpas_hidl_notify_hs20_icon_query_done(wpa_s, bssid, file_name, image,
+ image_length);
+#endif /* CONFIG_HS20 */
+}
+
+void wpas_notify_hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
+ const char* url,
+ u8 osu_method)
+{
+#ifdef CONFIG_HS20
+ if (!wpa_s || !url)
+ return;
+
+ wpas_hidl_notify_hs20_rx_subscription_remediation(wpa_s, url, osu_method);
+#endif /* CONFIG_HS20 */
+}
+
+void wpas_notify_hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s,
+ u8 code, u16 reauth_delay,
+ const char *url)
+{
+#ifdef CONFIG_HS20
+ if (!wpa_s || !url)
+ return;
+
+ wpas_hidl_notify_hs20_rx_deauth_imminent_notice(wpa_s, code, reauth_delay,
+ url);
+#endif /* CONFIG_HS20 */
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 1b7f04d..9c98524 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -10,6 +10,7 @@
#define NOTIFY_H
#include "p2p/p2p.h"
+#include "bss.h"
struct wps_credential;
struct wps_event_m2d;
@@ -24,6 +25,7 @@
enum wpa_states old_state);
void wpas_notify_disconnect_reason(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_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);
@@ -88,7 +90,9 @@
const u8 *p2p_dev_addr);
void wpas_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s);
void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
- const u8 *dev_addr, int new_device);
+ const u8 *addr, const struct p2p_peer_info *info,
+ const u8* peer_wfd_device_info, u8 peer_wfd_device_info_len,
+ int new_device);
void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
@@ -113,8 +117,8 @@
u16 config_methods,
unsigned int generated_pin);
void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, int network_id,
- int client);
+ struct wpa_ssid *ssid, int persistent,
+ int client, const u8 *ip);
void wpas_notify_p2p_group_formation_failure(struct wpa_supplicant *wpa_s,
const char *reason);
void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
@@ -141,5 +145,16 @@
void wpas_notify_p2p_invitation_received(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *go_dev_addr,
const u8 *bssid, int id, int op_freq);
-
+void wpas_notify_anqp_query_done(struct wpa_supplicant *wpa_s, const u8* bssid,
+ const char* result,
+ const struct wpa_bss_anqp *anqp);
+void wpas_notify_hs20_icon_query_done(struct wpa_supplicant *wpa_s, const u8* bssid,
+ const char* file_name, const u8* image,
+ u32 image_length);
+void wpas_notify_hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
+ const char* url,
+ u8 osu_method);
+void wpas_notify_hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s,
+ u8 code, u16 reauth_delay,
+ const char *url);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 6b3f83c..26d41a4 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -23,8 +23,29 @@
{
struct wpa_supplicant *iface;
- if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
+ if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) {
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent &&
+ wpa_s->parent->ap_iface &&
+ os_memcmp(wpa_s->parent->own_addr,
+ wpa_s->own_addr, ETH_ALEN) == 0 &&
+ wpabuf_len(wpa_s->pending_action_tx) >= 2 &&
+ *wpabuf_head_u8(wpa_s->pending_action_tx) !=
+ WLAN_ACTION_PUBLIC) {
+ /*
+ * When P2P Device interface has same MAC address as
+ * the GO interface, make sure non-Public Action frames
+ * are sent through the GO interface. The P2P Device
+ * interface can only send Public Action frames.
+ */
+ wpa_printf(MSG_DEBUG,
+ "P2P: Use GO interface %s instead of interface %s for Action TX",
+ wpa_s->parent->ifname, wpa_s->ifname);
+ return wpa_s->parent;
+ }
+#endif /* CONFIG_P2P */
return wpa_s;
+ }
/*
* Try to find a group interface that matches with the source address.
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
new file mode 100644
index 0000000..d23b009
--- /dev/null
+++ b/wpa_supplicant/op_classes.c
@@ -0,0 +1,325 @@
+/*
+ * Operating classes
+ * Copyright(c) 2015 Intel Deutschland GmbH
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * 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 "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+
+
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+ unsigned int *flags)
+{
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].chan == chan)
+ break;
+ }
+
+ if (i == mode->num_channels ||
+ (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
+ return NOT_ALLOWED;
+
+ if (flags)
+ *flags = mode->channels[i].flag;
+
+ if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+ size_t i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ /*
+ * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+ * so the center channel is 6 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 6 &&
+ channel <= center_channels[i] + 6)
+ return center_channels[i];
+ }
+
+ return 0;
+}
+
+
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_chan;
+ unsigned int i;
+ unsigned int no_ir = 0;
+
+ center_chan = get_center_80mhz(mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+
+ /* check all the channels are available */
+ for (i = 0; i < 4; i++) {
+ unsigned int flags;
+ u8 adj_chan = center_chan - 6 + i * 4;
+
+ if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
+ (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
+ (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
+ (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
+ return NOT_ALLOWED;
+
+ if (flags & HOSTAPD_CHAN_NO_IR)
+ no_ir = 1;
+ }
+
+ if (no_ir)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
+{
+ u8 center_channels[] = { 50, 114 };
+ unsigned int i;
+
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
+ /*
+ * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+ * so the center channel is 14 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 14 &&
+ channel <= center_channels[i] + 14)
+ return center_channels[i];
+ }
+
+ return 0;
+}
+
+
+static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
+ u8 channel)
+{
+ u8 center_chan;
+ unsigned int i;
+ unsigned int no_ir = 0;
+
+ center_chan = get_center_160mhz(mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+
+ /* Check all the channels are available */
+ for (i = 0; i < 8; i++) {
+ unsigned int flags;
+ u8 adj_chan = center_chan - 14 + i * 4;
+
+ if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
+ (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
+ (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
+ (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
+ (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
+ (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
+ (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
+ (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
+ return NOT_ALLOWED;
+
+ if (flags & HOSTAPD_CHAN_NO_IR)
+ no_ir = 1;
+ }
+
+ if (no_ir)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
+ u8 bw)
+{
+ unsigned int flag = 0;
+ enum chan_allowed res, res2;
+
+ res2 = res = allow_channel(mode, channel, &flag);
+ if (bw == BW40MINUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+ return NOT_ALLOWED;
+ res2 = allow_channel(mode, channel - 4, NULL);
+ } else if (bw == BW40PLUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+ return NOT_ALLOWED;
+ res2 = allow_channel(mode, channel + 4, NULL);
+ } else if (bw == BW80) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
+ } else if (bw == BW160) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 160 MHz specific version.
+ */
+ res2 = res = verify_160mhz(mode, channel);
+ } else if (bw == BW80P80) {
+ /*
+ * channel is a center channel and as such, not necessarily a
+ * valid 20 MHz channels. Override earlier allow_channel()
+ * result and use only the 80 MHz specific version.
+ */
+ res2 = res = verify_80mhz(mode, channel);
+ }
+
+ if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+ return NOT_ALLOWED;
+
+ if (res == NO_IR || res2 == NO_IR)
+ return NO_IR;
+
+ return ALLOWED;
+}
+
+
+static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
+ const struct oper_class_map *op_class)
+{
+ int chan;
+ size_t i;
+ struct hostapd_hw_modes *mode;
+ int found;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
+ if (!mode)
+ return 0;
+
+ if (op_class->op_class == 128) {
+ u8 channels[] = { 42, 58, 106, 122, 138, 155 };
+
+ for (i = 0; i < ARRAY_SIZE(channels); i++) {
+ if (verify_channel(mode, channels[i], op_class->bw) !=
+ NOT_ALLOWED)
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (op_class->op_class == 129) {
+ /* Check if either 160 MHz channels is allowed */
+ return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+ }
+
+ if (op_class->op_class == 130) {
+ /* Need at least two non-contiguous 80 MHz segments */
+ found = 0;
+
+ if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ found++;
+ if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+ found++;
+
+ if (found >= 2)
+ return 1;
+
+ return 0;
+ }
+
+ found = 0;
+ for (chan = op_class->min_chan; chan <= op_class->max_chan;
+ chan += op_class->inc) {
+ if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+ found = 1;
+ break;
+ }
+ }
+
+ return found;
+}
+
+
+size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
+ size_t len)
+{
+ struct wpabuf *buf;
+ u8 op, current, chan;
+ u8 *ie_len;
+ size_t res;
+
+ /*
+ * Assume 20 MHz channel for now.
+ * TODO: Use the secondary channel and VHT channel width that will be
+ * used after association.
+ */
+ if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
+ ¤t, &chan) == NUM_HOSTAPD_MODES)
+ return 0;
+
+ /*
+ * Need 3 bytes for EID, length, and current operating class, plus
+ * 1 byte for every other supported operating class.
+ */
+ buf = wpabuf_alloc(global_op_class_size + 3);
+ if (!buf)
+ return 0;
+
+ wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
+ /* Will set the length later, putting a placeholder */
+ ie_len = wpabuf_put(buf, 1);
+ 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]))
+ wpabuf_put_u8(buf, global_op_class[op].op_class);
+ }
+
+ *ie_len = wpabuf_len(buf) - 2;
+ if (*ie_len < 2 || wpabuf_len(buf) > len) {
+ wpa_printf(MSG_ERROR,
+ "Failed to add supported operating classes IE");
+ res = 0;
+ } else {
+ os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
+ res = wpabuf_len(buf);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "Added supported operating classes IE", buf);
+ }
+
+ wpabuf_free(buf);
+ return res;
+}
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index b310885..a341549 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -307,7 +307,14 @@
return;
}
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
+ params->only_new_results = 1;
+ }
ret = wpa_drv_scan(wpa_s, params);
+ if (ret == 0)
+ wpa_s->curr_scan_cookie = params->scan_cookie;
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
@@ -320,6 +327,7 @@
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
wpa_s->p2p_scan_work = work;
}
@@ -807,7 +815,7 @@
wpa_s->own_addr);
} else if (!s && !go_wpa_s) {
if (wpas_p2p_add_group_interface(wpa_s,
- WPA_IF_P2P_GO) < 0) {
+ WPA_IF_P2P_GROUP) < 0) {
wpa_printf(MSG_ERROR,
"P2P: Failed to allocate a new interface for the group");
return P2PS_SETUP_NONE;
@@ -1076,7 +1084,7 @@
"go_dev_addr=" MACSTR,
MAC2STR(bssid), group_capab, MAC2STR(go_dev_addr));
- return group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+ return !!(group_capab & P2P_GROUP_CAPAB_PERSISTENT_GROUP);
}
@@ -1301,7 +1309,6 @@
int client;
int persistent;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
/*
* This callback is likely called for the main interface. Update wpa_s
@@ -1376,16 +1383,15 @@
}
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->p2pdev,
- ssid, go_dev_addr);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
else {
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
}
- if (network_id < 0 && ssid)
- network_id = ssid->id;
+
if (!client) {
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 0, NULL);
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
}
}
@@ -1750,7 +1756,6 @@
struct wpa_supplicant *wpa_s = ctx;
struct p2p_go_neg_results *params = data;
struct wpa_ssid *ssid;
- int network_id = -1;
wpa_s->ap_configured_cb = NULL;
wpa_s->ap_configured_cb_ctx = NULL;
@@ -1797,14 +1802,15 @@
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
- network_id = wpas_p2p_store_persistent_group(
+ wpas_p2p_store_persistent_group(
wpa_s->p2pdev, ssid,
wpa_s->global->p2p_dev_addr);
wpas_p2p_add_psk_list(wpa_s, ssid);
}
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid,
+ params->persistent_group, 0,
+ NULL);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
@@ -1884,7 +1890,7 @@
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
ssid->p2p_group = 1;
- ssid->p2p_persistent_group = params->persistent_group;
+ ssid->p2p_persistent_group = !!params->persistent_group;
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
@@ -1951,7 +1957,12 @@
d = dst->conf;
s = src->conf;
-#define C(n) if (s->n) d->n = os_strdup(s->n)
+#define C(n) \
+do { \
+ if (s->n && !d->n) \
+ d->n = os_strdup(s->n); \
+} while (0)
+
C(device_name);
C(manufacturer);
C(model_name);
@@ -1979,7 +1990,10 @@
d->disable_scan_offload = s->disable_scan_offload;
d->passive_scan = s->passive_scan;
- if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
+ if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
+ !d->wps_nfc_pw_from_config) {
+ wpabuf_free(d->wps_nfc_dh_privkey);
+ wpabuf_free(d->wps_nfc_dh_pubkey);
d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
}
@@ -1987,23 +2001,6 @@
}
-static void wpas_p2p_clone_config_dh(struct wpa_supplicant *dst,
- const struct wpa_supplicant *src)
-{
- struct wpa_config *d;
- const struct wpa_config *s;
-
- d = dst->conf;
- s = src->conf;
-
- if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
- !d->wps_nfc_dh_privkey && !d->wps_nfc_dh_pubkey) {
- d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
- d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
- }
-}
-
-
static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
char *ifname, size_t len)
{
@@ -2255,7 +2252,7 @@
group_wpa_s = wpa_s->parent;
wpa_s->global->p2p_group_formation = group_wpa_s;
if (group_wpa_s != wpa_s)
- wpas_p2p_clone_config_dh(group_wpa_s, wpa_s);
+ wpas_p2p_clone_config(group_wpa_s, wpa_s);
}
group_wpa_s->p2p_in_provisioning = 1;
@@ -2298,6 +2295,8 @@
const struct p2p_peer_info *info,
int new_device)
{
+ u8 *wfd_dev_info = NULL;
+ u8 wfd_dev_info_len = 0;
#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
@@ -2306,6 +2305,12 @@
#ifdef CONFIG_WIFI_DISPLAY
wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
WFD_SUBELEM_DEVICE_INFO);
+ if (wfd_dev_info_hex) {
+ wfd_dev_info_len = strlen(wfd_dev_info_hex) / 2;
+ wfd_dev_info = os_zalloc(wfd_dev_info_len);
+ // Only used for notification, so not handling error.
+ hexstr2bin(wfd_dev_info_hex, wfd_dev_info, wfd_dev_info_len);
+ }
#endif /* CONFIG_WIFI_DISPLAY */
if (info->p2ps_instance) {
@@ -2372,7 +2377,9 @@
os_free(wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
- wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
+ wpas_notify_p2p_device_found(ctx, addr, info, wfd_dev_info,
+ wfd_dev_info_len, new_device);
+ os_free(wfd_dev_info);
}
@@ -3018,12 +3025,31 @@
MAC2STR(sa), op_freq, wpa_ssid_txt(ssid, ssid_len));
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
+ if (go) {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR
+ " persistent=%d freq=%d",
+ MAC2STR(sa), s->id, op_freq);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR
+ " persistent=%d",
+ MAC2STR(sa), s->id);
+ }
wpas_p2p_group_add_persistent(
wpa_s, s, go, 0, op_freq, 0, 0, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_INVITATION_ACCEPTED
+ "sa=" MACSTR " go_dev_addr=" MACSTR
+ " bssid=" MACSTR " unknown-network",
+ MAC2STR(sa), MAC2STR(go_dev_addr),
+ MAC2STR(bssid));
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0, op_freq,
ssid, ssid_len);
@@ -3324,10 +3350,6 @@
}
-enum chan_allowed {
- NOT_ALLOWED, NO_IR, ALLOWED
-};
-
static int has_channel(struct wpa_global *global,
struct hostapd_hw_modes *mode, u8 chan, int *flags)
{
@@ -3362,7 +3384,7 @@
u8 channel)
{
u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
- unsigned int i;
+ size_t i;
if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
@@ -4996,6 +5018,12 @@
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
+ params.only_new_results = 1;
+ }
+
/*
* Run a scan to update BSS table and start Provision Discovery once
* the new scan results become available.
@@ -5005,6 +5033,7 @@
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
wpa_s->own_scan_requested = 1;
+ wpa_s->clear_driver_scan_cache = 0;
}
wpabuf_free(ies);
@@ -5229,9 +5258,11 @@
if (!res && max_pref_freq > 0) {
*num_pref_freq = max_pref_freq;
i = 0;
- while (wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]) &&
- i < *num_pref_freq) {
+ while (i < *num_pref_freq &&
+ (!p2p_supported_freq(wpa_s->global->p2p,
+ pref_freq_list[i]) ||
+ wpas_p2p_disallowed_freq(wpa_s->global,
+ pref_freq_list[i]))) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
i, pref_freq_list[i]);
@@ -5373,6 +5404,9 @@
wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
wpa_s->p2p_pin);
+ } else if (wps_method == WPS_P2PS) {
+ /* Force the P2Ps default PIN to be used */
+ os_strlcpy(wpa_s->p2p_pin, "12345670", sizeof(wpa_s->p2p_pin));
} else
wpa_s->p2p_pin[0] = '\0';
@@ -5591,9 +5625,9 @@
&size, pref_freq_list);
if (!res && size > 0) {
i = 0;
- while (wpas_p2p_disallowed_freq(wpa_s->global,
- pref_freq_list[i]) &&
- i < size) {
+ while (i < size &&
+ wpas_p2p_disallowed_freq(wpa_s->global,
+ pref_freq_list[i])) {
wpa_printf(MSG_DEBUG,
"P2P: preferred_freq_list[%d]=%d is disallowed",
i, pref_freq_list[i]);
@@ -5994,7 +6028,7 @@
"P2P: Use primary interface for group operations");
wpa_s->p2p_first_connection_timeout = 0;
if (wpa_s != wpa_s->p2pdev)
- wpas_p2p_clone_config_dh(wpa_s, wpa_s->p2pdev);
+ wpas_p2p_clone_config(wpa_s, wpa_s->p2pdev);
return wpa_s;
}
@@ -6308,7 +6342,8 @@
struct p2p_group *group;
struct p2p_group_config *cfg;
- if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL ||
+ !ssid->p2p_group)
return NULL;
cfg = os_zalloc(sizeof(*cfg));
@@ -6621,6 +6656,12 @@
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->p2p_lo_started) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Cannot start P2P listen, it is offloaded");
+ return -1;
+ }
+
wpa_supplicant_cancel_sched_scan(wpa_s);
wpas_p2p_clear_pending_action_tx(wpa_s);
@@ -6694,7 +6735,7 @@
return 0;
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len, rx_freq)) {
+ ie, ie_len, rx_freq, wpa_s->p2p_lo_started)) {
case P2P_PREQ_NOT_P2P:
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
ssi_signal);
@@ -6927,7 +6968,6 @@
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
u8 go_dev_addr[ETH_ALEN];
- int network_id = -1;
int persistent;
int freq;
u8 ip[3 * 4];
@@ -6986,11 +7026,10 @@
ip_addr);
if (persistent)
- network_id = wpas_p2p_store_persistent_group(wpa_s->p2pdev,
- ssid, go_dev_addr);
- if (network_id < 0)
- network_id = ssid->id;
- wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+ wpas_p2p_store_persistent_group(wpa_s->p2pdev,
+ ssid, go_dev_addr);
+
+ wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip);
}
@@ -8371,17 +8410,17 @@
return -1;
}
- if (wpa_s->parent->p2p_oob_dev_pw_id !=
+ if (wpa_s->p2pdev->p2p_oob_dev_pw_id !=
DEV_PW_NFC_CONNECTION_HANDOVER &&
- !wpa_s->parent->p2p_oob_dev_pw) {
+ !wpa_s->p2pdev->p2p_oob_dev_pw) {
wpa_printf(MSG_DEBUG, "P2P: No NFC Dev Pw known");
return -1;
}
res = wpas_ap_wps_add_nfc_pw(
- wpa_s, wpa_s->parent->p2p_oob_dev_pw_id,
- wpa_s->parent->p2p_oob_dev_pw,
- wpa_s->parent->p2p_peer_oob_pk_hash_known ?
- wpa_s->parent->p2p_peer_oob_pubkey_hash : NULL);
+ wpa_s, wpa_s->p2pdev->p2p_oob_dev_pw_id,
+ wpa_s->p2pdev->p2p_oob_dev_pw,
+ wpa_s->p2pdev->p2p_peer_oob_pk_hash_known ?
+ wpa_s->p2pdev->p2p_peer_oob_pubkey_hash : NULL);
if (res)
return res;
@@ -8399,16 +8438,16 @@
wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
- wpas_p2p_get_persistent(wpa_s->parent,
+ wpas_p2p_get_persistent(wpa_s->p2pdev,
params->peer->p2p_device_addr,
ssid->ssid, ssid->ssid_len);
- wpa_s->parent->pending_invite_ssid_id = -1;
+ wpa_s->p2pdev->pending_invite_ssid_id = -1;
return p2p_invite(wpa_s->global->p2p, params->peer->p2p_device_addr,
P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
ssid->ssid, ssid->ssid_len, ssid->frequency,
wpa_s->global->p2p_dev_addr, persistent, 0,
- wpa_s->parent->p2p_oob_dev_pw_id);
+ wpa_s->p2pdev->p2p_oob_dev_pw_id);
}
@@ -9197,3 +9236,86 @@
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
wpas_p2p_group_deinit(wpa_s);
}
+
+
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ u8 *device_types;
+ size_t dev_types_len;
+ struct wpabuf *buf;
+ int ret;
+
+ if (wpa_s->p2p_lo_started) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P Listen offload is already started");
+ return 0;
+ }
+
+ if (wpa_s->global->p2p == NULL ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "P2P: Listen offload not supported");
+ return -1;
+ }
+
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_ERROR, "P2P: Input channel not supported: %u",
+ freq);
+ return -1;
+ }
+
+ /* Get device type */
+ dev_types_len = (wpa_s->conf->num_sec_device_types + 1) *
+ WPS_DEV_TYPE_LEN;
+ device_types = os_malloc(dev_types_len);
+ if (!device_types)
+ return -1;
+ os_memcpy(device_types, wpa_s->conf->device_type, WPS_DEV_TYPE_LEN);
+ os_memcpy(&device_types[WPS_DEV_TYPE_LEN], wpa_s->conf->sec_device_type,
+ wpa_s->conf->num_sec_device_types * WPS_DEV_TYPE_LEN);
+
+ /* Get Probe Response IE(s) */
+ buf = p2p_build_probe_resp_template(p2p, freq);
+ if (!buf) {
+ os_free(device_types);
+ return -1;
+ }
+
+ ret = wpa_drv_p2p_lo_start(wpa_s, freq, period, interval, count,
+ device_types, dev_types_len,
+ wpabuf_mhead_u8(buf), wpabuf_len(buf));
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to start P2P listen offload");
+
+ os_free(device_types);
+ wpabuf_free(buf);
+
+ if (ret == 0) {
+ wpa_s->p2p_lo_started = 1;
+
+ /* Stop current P2P listen if any */
+ wpas_stop_listen(wpa_s);
+ }
+
+ return ret;
+}
+
+
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->p2p_lo_started)
+ return 0;
+
+ ret = wpa_drv_p2p_lo_stop(wpa_s);
+ if (ret < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Failed to stop P2P listen offload");
+
+ wpa_s->p2p_lo_started = 0;
+ return ret;
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 6a770d2..63910d1 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -207,6 +207,10 @@
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+int wpas_p2p_lo_start(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int period, unsigned int interval,
+ unsigned int count);
+int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
#else /* CONFIG_P2P */
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index f4bba98..6ae239f 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -143,7 +143,7 @@
}
-static int wpa_supplicant_add_pmkid(void *wpa_s,
+static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid)
{
printf("%s - not implemented\n", __func__);
@@ -151,7 +151,7 @@
}
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
+static int wpa_supplicant_remove_pmkid(void *wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid)
{
printf("%s - not implemented\n", __func__);
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
new file mode 100644
index 0000000..5be917c
--- /dev/null
+++ b/wpa_supplicant/rrm.c
@@ -0,0 +1,1430 @@
+/*
+ * wpa_supplicant - Radio Measurements
+ * Copyright (c) 2003-2016, 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 "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "p2p_supplicant.h"
+
+
+static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
+{
+ struct rrm_data *rrm = data;
+
+ if (!rrm->notify_neighbor_rep) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Unexpected neighbor report timeout");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
+ rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
+
+ rrm->notify_neighbor_rep = NULL;
+ rrm->neighbor_rep_cb_ctx = NULL;
+}
+
+
+/*
+ * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
+ * @wpa_s: Pointer to wpa_supplicant
+ */
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->rrm.rrm_used = 0;
+
+ eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+ NULL);
+ if (wpa_s->rrm.notify_neighbor_rep)
+ wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+ wpa_s->rrm.next_neighbor_rep_token = 1;
+ wpas_clear_beacon_rep_data(wpa_s);
+}
+
+
+/*
+ * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
+ * @wpa_s: Pointer to wpa_supplicant
+ * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
+ * @report_len: Length of neighbor report buffer
+ */
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+ const u8 *report, size_t report_len)
+{
+ struct wpabuf *neighbor_rep;
+
+ wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
+ if (report_len < 1)
+ return;
+
+ if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Discarding neighbor report with token %d (expected %d)",
+ report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
+ return;
+ }
+
+ eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+ NULL);
+
+ if (!wpa_s->rrm.notify_neighbor_rep) {
+ wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+ return;
+ }
+
+ /* skipping the first byte, which is only an id (dialog token) */
+ neighbor_rep = wpabuf_alloc(report_len - 1);
+ if (!neighbor_rep) {
+ wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+ return;
+ }
+ wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
+ wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+ report[0]);
+ wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
+ neighbor_rep);
+ wpa_s->rrm.notify_neighbor_rep = NULL;
+ wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
+}
+
+
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+/* Workaround different, undefined for Windows, error codes used here */
+#define ENOTCONN -1
+#define EOPNOTSUPP -1
+#define ECANCELED -1
+#endif
+
+/* Measurement Request element + Location Subject + Maximum Age subelement */
+#define MEASURE_REQUEST_LCI_LEN (3 + 1 + 4)
+/* Measurement Request element + Location Civic Request */
+#define MEASURE_REQUEST_CIVIC_LEN (3 + 5)
+
+
+/**
+ * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
+ * is sent in the request.
+ * @lci: if set, neighbor request will include LCI request
+ * @civic: if set, neighbor request will include civic location request
+ * @cb: Callback function to be called once the requested report arrives, or
+ * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
+ * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
+ * the requester's responsibility to free it.
+ * In the latter case NULL will be sent in 'neighbor_rep'.
+ * @cb_ctx: Context value to send the callback function
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ * In case there is a previous request which has not been answered yet, the
+ * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
+ * Request must contain a callback function.
+ */
+int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid_value *ssid,
+ int lci, int civic,
+ void (*cb)(void *ctx,
+ struct wpabuf *neighbor_rep),
+ void *cb_ctx)
+{
+ struct wpabuf *buf;
+ const u8 *rrm_ie;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+ return -ENOTCONN;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+ return -EOPNOTSUPP;
+ }
+
+ rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
+ !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: No network support for Neighbor Report.");
+ return -EOPNOTSUPP;
+ }
+
+ /* Refuse if there's a live request */
+ if (wpa_s->rrm.notify_neighbor_rep) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Currently handling previous Neighbor Report.");
+ return -EBUSY;
+ }
+
+ /* 3 = action category + action code + dialog token */
+ buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0) +
+ (lci ? 2 + MEASURE_REQUEST_LCI_LEN : 0) +
+ (civic ? 2 + MEASURE_REQUEST_CIVIC_LEN : 0));
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Failed to allocate Neighbor Report Request");
+ return -ENOMEM;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
+ (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+ wpa_s->rrm.next_neighbor_rep_token);
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
+ wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
+ if (ssid) {
+ wpabuf_put_u8(buf, WLAN_EID_SSID);
+ wpabuf_put_u8(buf, ssid->ssid_len);
+ wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
+ }
+
+ if (lci) {
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, MEASURE_REQUEST_LCI_LEN);
+
+ /*
+ * Measurement token; nonzero number that is unique among the
+ * Measurement Request elements in a particular frame.
+ */
+ wpabuf_put_u8(buf, 1); /* Measurement Token */
+
+ /*
+ * Parallel, Enable, Request, and Report bits are 0, Duration is
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ wpabuf_put_u8(buf, MEASURE_TYPE_LCI); /* Measurement Type */
+
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21.10 - LCI request */
+ /* Location Subject */
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+
+ /* Optional Subelements */
+ /*
+ * IEEE P802.11-REVmc/D5.0 Figure 9-170
+ * The Maximum Age subelement is required, otherwise the AP can
+ * send only data that was determined after receiving the
+ * request. Setting it here to unlimited age.
+ */
+ wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
+ wpabuf_put_u8(buf, 2);
+ wpabuf_put_le16(buf, 0xffff);
+ }
+
+ if (civic) {
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21 */
+ wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
+ wpabuf_put_u8(buf, MEASURE_REQUEST_CIVIC_LEN);
+
+ /*
+ * Measurement token; nonzero number that is unique among the
+ * Measurement Request elements in a particular frame.
+ */
+ wpabuf_put_u8(buf, 2); /* Measurement Token */
+
+ /*
+ * Parallel, Enable, Request, and Report bits are 0, Duration is
+ * reserved.
+ */
+ wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
+ /* Measurement Type */
+ wpabuf_put_u8(buf, MEASURE_TYPE_LOCATION_CIVIC);
+
+ /* IEEE P802.11-REVmc/D5.0 9.4.2.21.14:
+ * Location Civic request */
+ /* Location Subject */
+ wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
+ wpabuf_put_u8(buf, 0); /* Civic Location Type: IETF RFC 4776 */
+ /* Location Service Interval Units: Seconds */
+ wpabuf_put_u8(buf, 0);
+ /* Location Service Interval: 0 - Only one report is requested
+ */
+ wpabuf_put_le16(buf, 0);
+ /* No optional subelements */
+ }
+
+ wpa_s->rrm.next_neighbor_rep_token++;
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Failed to send Neighbor Report Request");
+ wpabuf_free(buf);
+ return -ECANCELED;
+ }
+
+ wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
+ wpa_s->rrm.notify_neighbor_rep = cb;
+ eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
+ wpas_rrm_neighbor_rep_timeout_handler,
+ &wpa_s->rrm, NULL);
+
+ wpabuf_free(buf);
+ return 0;
+}
+
+
+static int wpas_rrm_report_elem(struct wpabuf **buf, u8 token, u8 mode, u8 type,
+ const u8 *data, size_t data_len)
+{
+ if (wpabuf_resize(buf, 5 + data_len))
+ return -1;
+
+ wpabuf_put_u8(*buf, WLAN_EID_MEASURE_REPORT);
+ wpabuf_put_u8(*buf, 3 + data_len);
+ wpabuf_put_u8(*buf, token);
+ wpabuf_put_u8(*buf, mode);
+ wpabuf_put_u8(*buf, type);
+
+ if (data_len)
+ wpabuf_put_data(*buf, data, data_len);
+
+ return 0;
+}
+
+
+static int
+wpas_rrm_build_lci_report(struct wpa_supplicant *wpa_s,
+ const struct rrm_measurement_request_element *req,
+ struct wpabuf **buf)
+{
+ u8 subject;
+ u16 max_age = 0;
+ struct os_reltime t, diff;
+ unsigned long diff_l;
+ const u8 *subelem;
+ const u8 *request = req->variable;
+ size_t len = req->len - 3;
+
+ if (len < 1)
+ return -1;
+
+ if (!wpa_s->lci)
+ goto reject;
+
+ subject = *request++;
+ len--;
+
+ wpa_printf(MSG_DEBUG, "Measurement request location subject=%u",
+ subject);
+
+ if (subject != LOCATION_SUBJECT_REMOTE) {
+ wpa_printf(MSG_INFO,
+ "Not building LCI report - bad location subject");
+ return 0;
+ }
+
+ /* Subelements are formatted exactly like elements */
+ wpa_hexdump(MSG_DEBUG, "LCI request subelements", request, len);
+ subelem = get_ie(request, len, LCI_REQ_SUBELEM_MAX_AGE);
+ if (subelem && subelem[1] == 2)
+ max_age = WPA_GET_LE16(subelem + 2);
+
+ if (os_get_reltime(&t))
+ goto reject;
+
+ os_reltime_sub(&t, &wpa_s->lci_time, &diff);
+ /* LCI age is calculated in 10th of a second units. */
+ diff_l = diff.sec * 10 + diff.usec / 100000;
+
+ if (max_age != 0xffff && max_age < diff_l)
+ goto reject;
+
+ if (wpas_rrm_report_elem(buf, req->token,
+ MEASUREMENT_REPORT_MODE_ACCEPT, req->type,
+ wpabuf_head_u8(wpa_s->lci),
+ wpabuf_len(wpa_s->lci)) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to add LCI report element");
+ return -1;
+ }
+
+ return 0;
+
+reject:
+ if (wpas_rrm_report_elem(buf, req->token,
+ MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
+ req->type, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void wpas_rrm_send_msr_report_mpdu(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t len)
+{
+ struct wpabuf *report = wpabuf_alloc(len + 3);
+
+ if (!report)
+ return;
+
+ wpabuf_put_u8(report, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(report, WLAN_RRM_RADIO_MEASUREMENT_REPORT);
+ wpabuf_put_u8(report, wpa_s->rrm.token);
+
+ wpabuf_put_data(report, data, len);
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(report), wpabuf_len(report), 0)) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Radio measurement report failed: Sending Action frame failed");
+ }
+
+ wpabuf_free(report);
+}
+
+
+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;
+
+#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 ||
+ (send_len + next[1] + 2) > MPDU_REPORT_LEN) {
+ wpas_rrm_send_msr_report_mpdu(wpa_s, pos, send_len);
+ len -= send_len;
+ pos = next;
+ }
+
+ next += next[1] + 2;
+ }
+#undef MPDU_REPORT_LEN
+}
+
+
+static int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels,
+ int *freqs)
+{
+ size_t i;
+
+ for (i = 0; i < num_primary_channels; i++) {
+ u8 primary_chan = chan - (2 * num_primary_channels - 2) + i * 4;
+
+ freqs[i] = ieee80211_chan_to_freq(NULL, op_class, primary_chan);
+ /* ieee80211_chan_to_freq() is not really meant for this
+ * conversion of 20 MHz primary channel numbers for wider VHT
+ * channels, so handle those as special cases here for now. */
+ if (freqs[i] < 0 &&
+ (op_class == 128 || op_class == 129 || op_class == 130))
+ freqs[i] = 5000 + 5 * primary_chan;
+ if (freqs[i] < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Report: Invalid channel %u",
+ chan);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int * wpas_add_channels(const struct oper_class_map *op,
+ struct hostapd_hw_modes *mode, int active,
+ const u8 *channels, const u8 size)
+{
+ int *freqs, *next_freq;
+ u8 num_primary_channels, i;
+ u8 num_chans;
+
+ num_chans = channels ? size :
+ (op->max_chan - op->min_chan) / op->inc + 1;
+
+ if (op->bw == BW80 || op->bw == BW80P80)
+ num_primary_channels = 4;
+ else if (op->bw == BW160)
+ num_primary_channels = 8;
+ else
+ num_primary_channels = 1;
+
+ /* one extra place for the zero-terminator */
+ freqs = os_calloc(num_chans * num_primary_channels + 1, sizeof(*freqs));
+ if (!freqs) {
+ wpa_printf(MSG_ERROR,
+ "Beacon Report: Failed to allocate freqs array");
+ return NULL;
+ }
+
+ next_freq = freqs;
+ for (i = 0; i < num_chans; i++) {
+ u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
+ enum chan_allowed res = verify_channel(mode, chan, op->bw);
+
+ if (res == NOT_ALLOWED || (res == NO_IR && active))
+ continue;
+
+ if (wpas_add_channel(op->op_class, chan, num_primary_channels,
+ next_freq) < 0) {
+ os_free(freqs);
+ return NULL;
+ }
+
+ next_freq += num_primary_channels;
+ }
+
+ if (!freqs[0]) {
+ os_free(freqs);
+ return NULL;
+ }
+
+ return freqs;
+}
+
+
+static int * wpas_op_class_freqs(const struct oper_class_map *op,
+ struct hostapd_hw_modes *mode, int active)
+{
+ u8 channels_80mhz[] = { 42, 58, 106, 122, 138, 155 };
+ u8 channels_160mhz[] = { 50, 114 };
+
+ /*
+ * When adding all channels in the operating class, 80 + 80 MHz
+ * operating classes are like 80 MHz channels because we add all valid
+ * channels anyway.
+ */
+ if (op->bw == BW80 || op->bw == BW80P80)
+ return wpas_add_channels(op, mode, active, channels_80mhz,
+ ARRAY_SIZE(channels_80mhz));
+
+ if (op->bw == BW160)
+ return wpas_add_channels(op, mode, active, channels_160mhz,
+ ARRAY_SIZE(channels_160mhz));
+
+ return wpas_add_channels(op, mode, active, NULL, 0);
+}
+
+
+static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active,
+ const char *country, const u8 *subelems,
+ size_t len)
+{
+ int *freqs = NULL, *new_freqs;
+ const u8 *end = subelems + len;
+
+ while (end - subelems > 2) {
+ const struct oper_class_map *op;
+ const u8 *ap_chan_elem, *pos;
+ u8 left;
+ struct hostapd_hw_modes *mode;
+
+ ap_chan_elem = get_ie(subelems, end - subelems,
+ WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL);
+ if (!ap_chan_elem)
+ break;
+ pos = ap_chan_elem + 2;
+ left = ap_chan_elem[1];
+ if (left < 1)
+ break;
+ subelems = ap_chan_elem + 2 + left;
+
+ op = get_oper_class(country, *pos);
+ if (!op) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: unknown operating class in AP Channel Report subelement %u",
+ *pos);
+ goto out;
+ }
+ pos++;
+ left--;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ if (!mode)
+ continue;
+
+ /*
+ * For 80 + 80 MHz operating classes, this AP Channel Report
+ * element should be followed by another element specifying
+ * the second 80 MHz channel. For now just add this 80 MHz
+ * channel, the second 80 MHz channel will be added when the
+ * next element is parsed.
+ * TODO: Verify that this AP Channel Report element is followed
+ * by a corresponding AP Channel Report element as specified in
+ * IEEE Std 802.11-2016, 11.11.9.1.
+ */
+ new_freqs = wpas_add_channels(op, mode, active, pos, left);
+ if (new_freqs)
+ int_array_concat(&freqs, new_freqs);
+
+ os_free(new_freqs);
+ }
+
+ return freqs;
+out:
+ os_free(freqs);
+ return NULL;
+}
+
+
+static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
+ u8 op_class, u8 chan, int active,
+ const u8 *subelems, size_t len)
+{
+ int *freqs = NULL, *ext_freqs = NULL;
+ struct hostapd_hw_modes *mode;
+ const char *country = NULL;
+ const struct oper_class_map *op;
+ const u8 *elem;
+
+ if (!wpa_s->current_bss)
+ return NULL;
+ elem = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+ if (elem && elem[1] >= 2)
+ country = (const char *) (elem + 2);
+
+ op = get_oper_class(country, op_class);
+ if (!op) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: invalid operating class %d",
+ op_class);
+ return NULL;
+ }
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode);
+ if (!mode)
+ return NULL;
+
+ switch (chan) {
+ case 0:
+ freqs = wpas_op_class_freqs(op, mode, active);
+ if (!freqs)
+ return NULL;
+ break;
+ case 255:
+ /* freqs will be added from AP channel subelements */
+ break;
+ default:
+ freqs = wpas_add_channels(op, mode, active, &chan, 1);
+ if (!freqs)
+ return NULL;
+ break;
+ }
+
+ ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems,
+ len);
+ if (ext_freqs) {
+ int_array_concat(&freqs, ext_freqs);
+ os_free(ext_freqs);
+ }
+
+ return freqs;
+}
+
+
+static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len,
+ u8 *op_class, u8 *chan, u8 *phy_type)
+{
+ const u8 *ie;
+ int sec_chan = 0, vht = 0;
+ struct ieee80211_ht_operation *ht_oper = NULL;
+ struct ieee80211_vht_operation *vht_oper = NULL;
+ u8 seg0, seg1;
+
+ ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= sizeof(struct ieee80211_ht_operation)) {
+ u8 sec_chan_offset;
+
+ ht_oper = (struct ieee80211_ht_operation *) (ie + 2);
+ sec_chan_offset = ht_oper->ht_param &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (sec_chan_offset == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ sec_chan = 1;
+ else if (sec_chan_offset ==
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ sec_chan = -1;
+ }
+
+ ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION);
+ if (ie && ie[1] >= sizeof(struct ieee80211_vht_operation)) {
+ vht_oper = (struct ieee80211_vht_operation *) (ie + 2);
+
+ switch (vht_oper->vht_op_info_chwidth) {
+ case 1:
+ seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx;
+ seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx;
+ if (seg1 && abs(seg1 - seg0) == 8)
+ vht = VHT_CHANWIDTH_160MHZ;
+ else if (seg1)
+ vht = VHT_CHANWIDTH_80P80MHZ;
+ else
+ vht = VHT_CHANWIDTH_80MHZ;
+ break;
+ case 2:
+ vht = VHT_CHANWIDTH_160MHZ;
+ break;
+ case 3:
+ vht = VHT_CHANWIDTH_80P80MHZ;
+ break;
+ default:
+ vht = VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+ }
+
+ if (ieee80211_freq_to_channel_ext(freq, sec_chan, vht, op_class,
+ chan) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "Cannot determine operating class and channel");
+ return -1;
+ }
+
+ *phy_type = ieee80211_get_phy_type(freq, ht_oper != NULL,
+ vht_oper != NULL);
+ if (*phy_type == PHY_TYPE_UNSPECIFIED) {
+ wpa_printf(MSG_DEBUG, "Cannot determine phy type");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+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)
+{
+ u8 *ies = (u8 *) (bss + 1);
+ size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
+ u8 *pos = buf;
+ int rem_len;
+
+ rem_len = 255 - sizeof(struct rrm_measurement_beacon_report) -
+ sizeof(struct rrm_measurement_report_element) - 2;
+
+ if (detail > BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Request: Invalid reporting detail: %d",
+ detail);
+ return -1;
+ }
+
+ if (detail == BEACON_REPORT_DETAIL_NONE)
+ return 0;
+
+ /*
+ * Minimal frame body subelement size: EID(1) + length(1) + TSF(8) +
+ * beacon interval(2) + capabilities(2) = 14 bytes
+ */
+ if (buf_len < 14)
+ return 0;
+
+ *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;
+
+ rem_len -= pos - buf;
+
+ /*
+ * According to IEEE Std 802.11-2016, 9.4.2.22.7, if the reported frame
+ * body subelement causes the element to exceed the maximum element
+ * size, the subelement is truncated so that the last IE is a complete
+ * IE. So even when required to report all IEs, add elements one after
+ * the other and stop once there is no more room in the measurement
+ * element.
+ */
+ 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.
+ */
+
+ if (2 + elen > buf + buf_len - pos ||
+ 2 + elen > rem_len)
+ break;
+
+ *pos++ = ies[0];
+ *pos++ = elen;
+ os_memcpy(pos, ies + 2, elen);
+ pos += elen;
+ rem_len -= 2 + elen;
+ }
+
+ ies_len -= 2 + ies[1];
+ ies += 2 + ies[1];
+ }
+
+ /* Now the length is known */
+ buf[1] = pos - buf - 2;
+ return pos - buf;
+}
+
+
+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[2000];
+ struct rrm_measurement_beacon_report *rep;
+
+ if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 &&
+ os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0)
+ return 0;
+
+ if (data->ssid_len &&
+ (data->ssid_len != bss->ssid_len ||
+ os_memcmp(data->ssid, bss->ssid, bss->ssid_len) != 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)
+ return 0;
+
+ 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);
+
+ ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail,
+ bss, rep->variable,
+ sizeof(buf) - sizeof(*rep));
+ if (ret < 0)
+ return -1;
+
+ return wpas_rrm_report_elem(wpa_buf, wpa_s->beacon_rep_data.token,
+ MEASUREMENT_REPORT_MODE_ACCEPT,
+ MEASURE_TYPE_BEACON, buf,
+ ret + sizeof(*rep));
+}
+
+
+static int wpas_beacon_rep_no_results(struct wpa_supplicant *wpa_s,
+ struct wpabuf **buf)
+{
+ return wpas_rrm_report_elem(buf, wpa_s->beacon_rep_data.token,
+ MEASUREMENT_REPORT_MODE_ACCEPT,
+ MEASURE_TYPE_BEACON, NULL, 0);
+}
+
+
+static void wpas_beacon_rep_table(struct wpa_supplicant *wpa_s,
+ struct wpabuf **buf)
+{
+ size_t i;
+
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (wpas_add_beacon_rep(wpa_s, buf, wpa_s->last_scan_res[i],
+ 0, 0) < 0)
+ break;
+ }
+
+ if (!(*buf))
+ wpas_beacon_rep_no_results(wpa_s, buf);
+
+ wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", *buf);
+}
+
+
+static void wpas_rrm_refuse_request(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf = NULL;
+
+ if (wpas_rrm_report_elem(&buf, wpa_s->beacon_rep_data.token,
+ MEASUREMENT_REPORT_MODE_REJECT_REFUSED,
+ MEASURE_TYPE_BEACON, NULL, 0)) {
+ wpa_printf(MSG_ERROR, "RRM: Memory allocation failed");
+ wpabuf_free(buf);
+ return;
+ }
+
+ wpas_rrm_send_msr_report(wpa_s, buf);
+ wpas_clear_beacon_rep_data(wpa_s);
+ wpabuf_free(buf);
+}
+
+
+static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_driver_scan_params *params =
+ &wpa_s->beacon_rep_data.scan_params;
+ u16 prev_duration = params->duration;
+
+ if (!wpa_s->current_bss)
+ return;
+
+ if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) &&
+ params->duration) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Cannot set scan duration due to missing driver support");
+ params->duration = 0;
+ }
+ os_get_reltime(&wpa_s->beacon_rep_scan);
+ if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) ||
+ wpa_supplicant_trigger_scan(wpa_s, params))
+ wpas_rrm_refuse_request(wpa_s);
+ params->duration = prev_duration;
+}
+
+
+static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s,
+ struct beacon_rep_data *data,
+ u8 sid, u8 slen, const u8 *subelem)
+{
+ u8 report_info, i;
+
+ switch (sid) {
+ case WLAN_BEACON_REQUEST_SUBELEM_SSID:
+ if (!slen) {
+ wpa_printf(MSG_DEBUG,
+ "SSID subelement with zero length - wildcard SSID");
+ break;
+ }
+
+ if (slen > SSID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid SSID subelement length: %u", slen);
+ return -1;
+ }
+
+ data->ssid_len = slen;
+ os_memcpy(data->ssid, subelem, data->ssid_len);
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_INFO:
+ if (slen != 2) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid reporting information subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ report_info = subelem[0];
+ if (report_info != 0) {
+ wpa_printf(MSG_DEBUG,
+ "reporting information=%u is not supported",
+ report_info);
+ return 0;
+ }
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_DETAIL:
+ if (slen != 1) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid reporting detail subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ data->report_detail = subelem[0];
+ if (data->report_detail >
+ BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS) {
+ wpa_printf(MSG_DEBUG, "Invalid reporting detail: %u",
+ subelem[0]);
+ return 0;
+ }
+
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_REQUEST:
+ if (data->report_detail !=
+ BEACON_REPORT_DETAIL_REQUESTED_ONLY) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: request subelement is present but report detail is %u",
+ data->report_detail);
+ return -1;
+ }
+
+ if (!slen) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid request subelement length: %u",
+ slen);
+ return -1;
+ }
+
+ if (data->eids) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Request: Request subelement appears more than once");
+ return -1;
+ }
+
+ data->eids = bitfield_alloc(255);
+ if (!data->eids) {
+ wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap");
+ return -1;
+ }
+
+ for (i = 0; i < slen; i++)
+ bitfield_set(data->eids, subelem[i]);
+ break;
+ case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL:
+ /* Skip - it will be processed when freqs are added */
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Beacon request: Unknown subelement id %u", sid);
+ break;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Returns 0 if the next element can be processed, 1 if some operation was
+ * triggered, and -1 if processing failed (i.e., the element is in invalid
+ * format or an internal error occurred).
+ */
+static int
+wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s,
+ u8 elem_token, int duration_mandatory,
+ const struct rrm_measurement_beacon_request *req,
+ size_t len, struct wpabuf **buf)
+{
+ struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+ struct wpa_driver_scan_params *params = &data->scan_params;
+ const u8 *subelems;
+ size_t elems_len;
+ u16 rand_interval;
+ u32 interval_usec;
+ u32 _rand;
+ int ret = 0, res;
+
+ if (len < sizeof(*req))
+ return -1;
+
+ if (req->mode != BEACON_REPORT_MODE_PASSIVE &&
+ req->mode != BEACON_REPORT_MODE_ACTIVE &&
+ req->mode != BEACON_REPORT_MODE_TABLE)
+ return 0;
+
+ subelems = req->variable;
+ elems_len = len - sizeof(*req);
+ rand_interval = le_to_host16(req->rand_interval);
+
+ os_free(params->freqs);
+ os_memset(params, 0, sizeof(*params));
+
+ data->token = elem_token;
+
+ /* default reporting detail is all fixed length fields and all
+ * elements */
+ data->report_detail = BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS;
+ os_memcpy(data->bssid, req->bssid, ETH_ALEN);
+
+ while (elems_len >= 2) {
+ if (subelems[1] > elems_len - 2) {
+ wpa_printf(MSG_DEBUG,
+ "Beacon Request: Truncated subelement");
+ ret = -1;
+ goto out;
+ }
+
+ res = wpas_rm_handle_beacon_req_subelem(
+ wpa_s, data, subelems[0], subelems[1], &subelems[2]);
+ if (res != 1) {
+ ret = res;
+ goto out;
+ }
+
+ elems_len -= 2 + subelems[1];
+ subelems += 2 + subelems[1];
+ }
+
+ if (req->mode == BEACON_REPORT_MODE_TABLE) {
+ wpas_beacon_rep_table(wpa_s, buf);
+ goto out;
+ }
+
+ params->freqs = wpas_beacon_request_freqs(
+ wpa_s, req->oper_class, req->channel,
+ req->mode == BEACON_REPORT_MODE_ACTIVE,
+ req->variable, len - sizeof(*req));
+ if (!params->freqs) {
+ wpa_printf(MSG_DEBUG, "Beacon request: No valid channels");
+ goto out;
+ }
+
+ params->duration = le_to_host16(req->duration);
+ params->duration_mandatory = duration_mandatory;
+ if (!params->duration) {
+ wpa_printf(MSG_DEBUG, "Beacon request: Duration is 0");
+ ret = -1;
+ goto out;
+ }
+
+ params->only_new_results = 1;
+
+ if (req->mode == BEACON_REPORT_MODE_ACTIVE) {
+ params->ssids[params->num_ssids].ssid = data->ssid;
+ params->ssids[params->num_ssids++].ssid_len = data->ssid_len;
+ }
+
+ if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+ _rand = os_random();
+ interval_usec = (_rand % (rand_interval + 1)) * 1024;
+ eloop_register_timeout(0, interval_usec, wpas_rrm_scan_timeout, wpa_s,
+ NULL);
+ return 1;
+out:
+ wpas_clear_beacon_rep_data(wpa_s);
+ return ret;
+}
+
+
+static int
+wpas_rrm_handle_msr_req_element(
+ struct wpa_supplicant *wpa_s,
+ const struct rrm_measurement_request_element *req,
+ struct wpabuf **buf)
+{
+ int duration_mandatory;
+
+ wpa_printf(MSG_DEBUG, "Measurement request type %d token %d",
+ req->type, req->token);
+
+ if (req->mode & MEASUREMENT_REQUEST_MODE_ENABLE) {
+ /* Enable bit is not supported for now */
+ wpa_printf(MSG_DEBUG, "RRM: Enable bit not supported, ignore");
+ return 0;
+ }
+
+ if ((req->mode & MEASUREMENT_REQUEST_MODE_PARALLEL) &&
+ req->type > MEASURE_TYPE_RPI_HIST) {
+ /* Parallel measurements are not supported for now */
+ wpa_printf(MSG_DEBUG,
+ "RRM: Parallel measurements are not supported, reject");
+ goto reject;
+ }
+
+ duration_mandatory =
+ !!(req->mode & MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY);
+
+ switch (req->type) {
+ case MEASURE_TYPE_LCI:
+ return wpas_rrm_build_lci_report(wpa_s, req, buf);
+ case MEASURE_TYPE_BEACON:
+ if (duration_mandatory &&
+ !(wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Driver does not support dwell time configuration - reject beacon report with mandatory duration");
+ goto reject;
+ }
+ return wpas_rm_handle_beacon_req(wpa_s, req->token,
+ duration_mandatory,
+ (const void *) req->variable,
+ req->len - 3, buf);
+ default:
+ wpa_printf(MSG_INFO,
+ "RRM: Unsupported radio measurement type %u",
+ req->type);
+ break;
+ }
+
+reject:
+ if (wpas_rrm_report_elem(buf, req->token,
+ MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE,
+ req->type, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "RRM: Failed to add report element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static struct wpabuf *
+wpas_rrm_process_msr_req_elems(struct wpa_supplicant *wpa_s, const u8 *pos,
+ size_t len)
+{
+ struct wpabuf *buf = NULL;
+
+ while (len) {
+ const struct rrm_measurement_request_element *req;
+ int res;
+
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "RRM: Truncated element");
+ goto out;
+ }
+
+ req = (const struct rrm_measurement_request_element *) pos;
+ if (req->eid != WLAN_EID_MEASURE_REQUEST) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Expected Measurement Request element, but EID is %u",
+ req->eid);
+ goto out;
+ }
+
+ if (req->len < 3) {
+ wpa_printf(MSG_DEBUG, "RRM: Element length too short");
+ goto out;
+ }
+
+ if (req->len > len - 2) {
+ wpa_printf(MSG_DEBUG, "RRM: Element length too long");
+ goto out;
+ }
+
+ res = wpas_rrm_handle_msr_req_element(wpa_s, req, &buf);
+ if (res < 0)
+ goto out;
+
+ pos += req->len + 2;
+ len -= req->len + 2;
+ }
+
+ return buf;
+
+out:
+ wpabuf_free(buf);
+ return NULL;
+}
+
+
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len)
+{
+ struct wpabuf *report;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request: Not associated");
+ return;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring radio measurement request: Not RRM network");
+ return;
+ }
+
+ if (len < 3) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring too short radio measurement request");
+ return;
+ }
+
+ wpa_s->rrm.token = *frame;
+
+ /* Number of repetitions is not supported */
+
+ report = wpas_rrm_process_msr_req_elems(wpa_s, frame + 3, len - 3);
+ if (!report)
+ return;
+
+ wpas_rrm_send_msr_report(wpa_s, report);
+ wpabuf_free(report);
+}
+
+
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len,
+ int rssi)
+{
+ struct wpabuf *buf;
+ const struct rrm_link_measurement_request *req;
+ struct rrm_link_measurement_report report;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring link measurement request. Not associated");
+ return;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring link measurement request. Not RRM network");
+ return;
+ }
+
+ if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+ wpa_printf(MSG_INFO,
+ "RRM: Measurement report failed. TX power insertion not supported");
+ return;
+ }
+
+ req = (const struct rrm_link_measurement_request *) frame;
+ if (len < sizeof(*req)) {
+ wpa_printf(MSG_INFO,
+ "RRM: Link measurement report failed. Request too short");
+ return;
+ }
+
+ os_memset(&report, 0, sizeof(report));
+ report.dialog_token = req->dialog_token;
+ report.tpc.eid = WLAN_EID_TPC_REPORT;
+ report.tpc.len = 2;
+ /* Note: The driver is expected to update report.tpc.tx_power and
+ * report.tpc.link_margin subfields when sending out this frame.
+ * Similarly, the driver would need to update report.rx_ant_id and
+ * report.tx_ant_id subfields. */
+ report.rsni = 255; /* 255 indicates that RSNI is not available */
+ report.rcpi = rssi_to_rcpi(rssi);
+
+ /* action_category + action_code */
+ buf = wpabuf_alloc(2 + sizeof(report));
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Link measurement report failed. Buffer allocation failed");
+ return;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
+ wpabuf_put_data(buf, &report, sizeof(report));
+ wpa_hexdump_buf(MSG_DEBUG, "RRM: Link measurement report", buf);
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0)) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Link measurement report failed. Send action failed");
+ }
+ wpabuf_free(buf);
+}
+
+
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res,
+ struct scan_info *info)
+{
+ size_t i = 0;
+ struct wpabuf *buf = NULL;
+
+ if (!wpa_s->beacon_rep_data.token)
+ return 0;
+
+ if (!wpa_s->current_bss)
+ goto out;
+
+ /* If the measurement was aborted, don't report partial results */
+ if (info->aborted)
+ goto out;
+
+ wpa_printf(MSG_DEBUG, "RRM: TSF BSSID: " MACSTR " current BSS: " MACSTR,
+ MAC2STR(info->scan_start_tsf_bssid),
+ MAC2STR(wpa_s->current_bss->bssid));
+ if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) &&
+ os_memcmp(info->scan_start_tsf_bssid, wpa_s->current_bss->bssid,
+ ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Ignore scan results due to mismatching TSF BSSID");
+ goto out;
+ }
+
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_bss *bss =
+ wpa_bss_get_bssid(wpa_s, scan_res->res[i]->bssid);
+
+ if (!bss)
+ continue;
+
+ if ((wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) &&
+ os_memcmp(scan_res->res[i]->tsf_bssid,
+ wpa_s->current_bss->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Ignore scan result for " MACSTR
+ " due to mismatching TSF BSSID" MACSTR,
+ MAC2STR(scan_res->res[i]->bssid),
+ MAC2STR(scan_res->res[i]->tsf_bssid));
+ continue;
+ }
+
+ if (!(wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT)) {
+ struct os_reltime update_time, diff;
+
+ /* For now, allow 8 ms older results due to some
+ * unknown issue with cfg80211 BSS table updates during
+ * a scan with the current BSS.
+ * TODO: Fix this more properly to avoid having to have
+ * this type of hacks in place. */
+ calculate_update_time(&scan_res->fetch_time,
+ scan_res->res[i]->age,
+ &update_time);
+ os_reltime_sub(&wpa_s->beacon_rep_scan,
+ &update_time, &diff);
+ if (os_reltime_before(&update_time,
+ &wpa_s->beacon_rep_scan) &&
+ (diff.sec || diff.usec >= 8000)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Ignore scan result for " MACSTR
+ " due to old update (age(ms) %u, calculated age %u.%06u seconds)",
+ MAC2STR(scan_res->res[i]->bssid),
+ scan_res->res[i]->age,
+ (unsigned int) diff.sec,
+ (unsigned int) diff.usec);
+ continue;
+ }
+ }
+
+ /*
+ * Don't report results that were not received during the
+ * current measurement.
+ */
+ if (info->scan_start_tsf > scan_res->res[i]->parent_tsf)
+ continue;
+
+ if (wpas_add_beacon_rep(wpa_s, &buf, bss, info->scan_start_tsf,
+ scan_res->res[i]->parent_tsf) < 0)
+ break;
+ }
+
+ if (!buf && wpas_beacon_rep_no_results(wpa_s, &buf))
+ goto out;
+
+ wpa_hexdump_buf(MSG_DEBUG, "RRM: Radio Measurement report", buf);
+
+ wpas_rrm_send_msr_report(wpa_s, buf);
+ wpabuf_free(buf);
+
+out:
+ wpas_clear_beacon_rep_data(wpa_s);
+ return 1;
+}
+
+
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s)
+{
+ struct beacon_rep_data *data = &wpa_s->beacon_rep_data;
+
+ eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL);
+ bitfield_free(data->eids);
+ os_free(data->scan_params.freqs);
+ os_memset(data, 0, sizeof(*data));
+}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7f42607..3a100cd 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -36,8 +36,7 @@
if (wpa_s->current_ssid == NULL) {
wpa_s->current_ssid = ssid;
- if (wpa_s->current_ssid != NULL)
- wpas_notify_network_changed(wpa_s);
+ wpas_notify_network_changed(wpa_s);
}
wpa_supplicant_initiate_eapol(wpa_s);
wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
@@ -60,10 +59,7 @@
wps = 1;
*req_type = wpas_wps_get_req_type(ssid);
- if (!ssid->eap.phase1)
- continue;
-
- if (os_strstr(ssid->eap.phase1, "pbc=1"))
+ if (ssid->eap.phase1 && os_strstr(ssid->eap.phase1, "pbc=1"))
return 2;
}
@@ -166,6 +162,8 @@
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
+ wpa_scan_free_params(params);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
radio_work_done(work);
return;
}
@@ -178,6 +176,17 @@
params->only_new_results = 1;
}
ret = wpa_drv_scan(wpa_s, params);
+ /*
+ * Store the obtained vendor scan cookie (if any) in wpa_s context.
+ * The current design is to allow only one scan request on each
+ * interface, hence having this scan cookie stored in wpa_s context is
+ * fine for now.
+ *
+ * Revisit this logic if concurrent scan operations per interface
+ * is supported.
+ */
+ if (ret == 0)
+ wpa_s->curr_scan_cookie = params->scan_cookie;
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
@@ -229,12 +238,11 @@
}
ctx = wpa_scan_clone_params(params);
- if (ctx == NULL)
- return -1;
-
- if (radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
+ if (!ctx ||
+ radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0)
{
wpa_scan_free_params(ctx);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1");
return -1;
}
@@ -266,8 +274,9 @@
}
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params)
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
{
int ret;
@@ -282,7 +291,7 @@
}
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
{
int ret;
@@ -428,6 +437,39 @@
#endif /* CONFIG_INTERWORKING */
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *default_ies = NULL;
+ u8 ext_capab[18];
+ int ext_capab_len;
+ enum wpa_driver_if_type type = WPA_IF_STATION;
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+ type = WPA_IF_P2P_CLIENT;
+#endif /* CONFIG_P2P */
+
+ wpa_drv_get_ext_capa(wpa_s, type);
+
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+ sizeof(ext_capab));
+ if (ext_capab_len > 0 &&
+ wpabuf_resize(&default_ies, ext_capab_len) == 0)
+ wpabuf_put_data(default_ies, ext_capab, ext_capab_len);
+
+#ifdef CONFIG_MBO
+ /* Send cellular capabilities for potential MBO STAs */
+ if (wpabuf_resize(&default_ies, 9) == 0)
+ wpas_mbo_scan_ie(wpa_s, default_ies);
+#endif /* CONFIG_MBO */
+
+ if (default_ies)
+ wpa_drv_set_default_scan_ies(wpa_s, wpabuf_head(default_ies),
+ wpabuf_len(default_ies));
+ wpabuf_free(default_ies);
+}
+
+
static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *extra_ie = NULL;
@@ -438,6 +480,13 @@
enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+#endif /* CONFIG_P2P */
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab));
if (ext_capab_len > 0 &&
@@ -496,6 +545,13 @@
wpas_mbo_scan_ie(wpa_s, extra_ie);
#endif /* CONFIG_MBO */
+ if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) {
+ struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ];
+
+ if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
+ wpabuf_put_buf(extra_ie, buf);
+ }
+
return extra_ie;
}
@@ -575,11 +631,12 @@
{
unsigned int i;
struct wpa_ssid *ssid;
+
/*
- * For devices with |max_ssids| greater than 1, leave the last slot empty
+ * For devices with max_ssids greater than 1, leave the last slot empty
* for adding the wildcard scan entry.
*/
- max_ssids = (max_ssids == 1) ? max_ssids : max_ssids - 1;
+ max_ssids = max_ssids > 1 ? max_ssids - 1 : max_ssids;
for (i = 0; i < wpa_s->scan_id_count; i++) {
unsigned int j;
@@ -657,10 +714,7 @@
size_t max_ssids;
int connect_without_scan = 0;
- if (wpa_s->pno || wpa_s->pno_sched_pending) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
- return;
- }
+ wpa_s->ignore_post_flush_scan_res = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
@@ -722,6 +776,21 @@
return;
}
+ /*
+ * Don't cancel the scan based on ongoing PNO; defer it. Some scans are
+ * used for changing modes inside wpa_supplicant (roaming,
+ * auto-reconnect, etc). Discarding the scan might hurt these processes.
+ * The normal use case for PNO is to suspend the host immediately after
+ * starting PNO, so the periodic 100 ms attempts to run the scan do not
+ * normally happen in practice multiple times, i.e., this is simply
+ * restarting scanning once the host is woken up and PNO stopped.
+ */
+ if (wpa_s->pno || wpa_s->pno_sched_pending) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress");
+ wpa_supplicant_req_scan(wpa_s, 0, 100000);
+ return;
+ }
+
if (wpa_s->conf->ap_scan == 2)
max_ssids = 1;
else {
@@ -835,12 +904,10 @@
* slot for the zero-terminator.
*/
params.freqs = os_malloc(sizeof(int) * 2);
- if (params.freqs == NULL) {
- wpa_dbg(wpa_s, MSG_ERROR, "Memory allocation failed");
- return;
+ if (params.freqs) {
+ params.freqs[0] = wpa_s->assoc_freq;
+ params.freqs[1] = 0;
}
- params.freqs[0] = wpa_s->assoc_freq;
- params.freqs[1] = 0;
/*
* Reset the reattach flag so that we fall back to full scan if
@@ -1003,7 +1070,8 @@
}
#endif /* CONFIG_P2P */
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_scan) {
params.mac_addr = wpa_s->mac_addr_scan;
@@ -1181,6 +1249,26 @@
}
+static void
+wpa_scan_set_relative_rssi_params(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
+{
+ if (wpa_s->wpa_state != WPA_COMPLETED ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI) ||
+ wpa_s->srp.relative_rssi_set == 0)
+ return;
+
+ params->relative_rssi_set = 1;
+ params->relative_rssi = wpa_s->srp.relative_rssi;
+
+ if (wpa_s->srp.relative_adjust_rssi == 0)
+ return;
+
+ params->relative_adjust_band = wpa_s->srp.relative_adjust_band;
+ params->relative_adjust_rssi = wpa_s->srp.relative_adjust_rssi;
+}
+
+
/**
* wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
* @wpa_s: Pointer to wpa_supplicant data
@@ -1212,6 +1300,8 @@
if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
return -1;
+ wpa_s->sched_scan_stop_req = 0;
+
if (wpa_s->sched_scanning) {
wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
return 0;
@@ -1423,7 +1513,8 @@
wpa_setband_scan_freqs(wpa_s, scan_params);
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_sched_scan) {
params.mac_addr = wpa_s->mac_addr_sched_scan;
@@ -1432,6 +1523,8 @@
}
}
+ wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
+
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
@@ -1510,6 +1603,9 @@
if (!wpa_s->sched_scanning)
return;
+ if (wpa_s->sched_scanning)
+ wpa_s->sched_scan_stop_req = 1;
+
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
wpa_supplicant_stop_sched_scan(wpa_s);
@@ -1569,7 +1665,13 @@
*/
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
{
- return get_ie((const u8 *) (res + 1), res->ie_len, ie);
+ size_t ie_len = res->ie_len;
+
+ /* Use the Beacon frame IEs if res->ie_len is not available */
+ if (!ie_len)
+ ie_len = res->beacon_ie_len;
+
+ return get_ie((const u8 *) (res + 1), ie_len, ie);
}
@@ -1686,10 +1788,12 @@
* This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
* rule of thumb is that any SNR above 20 is good." This one
* http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
- * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a
- * conservative value.
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in
+ * scan_est_throughput() allow even smaller SNR values for the maximum rates
+ * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a
+ * somewhat conservative value here.
*/
-#define GREAT_SNR 30
+#define GREAT_SNR 25
#define IS_5GHZ(n) (n > 4000)
@@ -1737,10 +1841,12 @@
}
/* if SNR is close, decide by max rate or frequency band */
- if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
- (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
+ if (snr_a && snr_b && abs(snr_b - snr_a) < 7) {
if (wa->est_throughput != wb->est_throughput)
return wb->est_throughput - wa->est_throughput;
+ }
+ if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
+ (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
return IS_5GHZ(wa->freq) ? -1 : 1;
}
@@ -1872,8 +1978,8 @@
}
-static void filter_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *res)
+void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res)
{
size_t i, j;
@@ -1906,7 +2012,7 @@
#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
-static void scan_snr(struct wpa_scan_res *res)
+void scan_snr(struct wpa_scan_res *res)
{
if (res->flags & WPA_SCAN_NOISE_INVALID) {
res->noise = IS_5GHZ(res->freq) ?
@@ -1990,8 +2096,8 @@
}
-static void scan_est_throughput(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
{
enum local_hw_capab capab = wpa_s->hw_capab;
int rate; /* max legacy rate in 500 kb/s units */
@@ -2128,10 +2234,22 @@
}
#endif /* CONFIG_WPS */
- qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
- compar);
+ if (scan_res->res) {
+ qsort(scan_res->res, scan_res->num,
+ sizeof(struct wpa_scan_res *), compar);
+ }
dump_scan_res(scan_res);
+ if (wpa_s->ignore_post_flush_scan_res) {
+ /* FLUSH command aborted an ongoing scan and these are the
+ * results from the aborted scan. Do not process the results to
+ * maintain flushed state. */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Do not update BSS table based on pending post-FLUSH scan results");
+ wpa_s->ignore_post_flush_scan_res = 0;
+ return scan_res;
+ }
+
wpa_bss_update_start(wpa_s);
for (i = 0; i < scan_res->num; i++)
wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
@@ -2256,6 +2374,8 @@
params->p2p_probe = src->p2p_probe;
params->only_new_results = src->only_new_results;
params->low_priority = src->low_priority;
+ params->duration = src->duration;
+ params->duration_mandatory = src->duration_mandatory;
if (src->sched_scan_plans_num > 0) {
params->sched_scan_plans =
@@ -2298,6 +2418,10 @@
params->bssid = bssid;
}
+ params->relative_rssi_set = src->relative_rssi_set;
+ params->relative_rssi = src->relative_rssi;
+ params->relative_adjust_band = src->relative_adjust_band;
+ params->relative_adjust_rssi = src->relative_adjust_rssi;
return params;
failed:
@@ -2355,7 +2479,7 @@
return 0;
if ((wpa_s->wpa_state > WPA_SCANNING) &&
- (wpa_s->wpa_state <= WPA_COMPLETED)) {
+ (wpa_s->wpa_state < WPA_COMPLETED)) {
wpa_printf(MSG_ERROR, "PNO: In assoc process");
return -EAGAIN;
}
@@ -2371,6 +2495,13 @@
}
}
+ if (wpa_s->sched_scan_stop_req) {
+ wpa_printf(MSG_DEBUG,
+ "Schedule PNO after previous sched scan has stopped");
+ wpa_s->pno_sched_pending = 1;
+ return 0;
+ }
+
os_memset(¶ms, 0, sizeof(params));
num_ssid = num_match_ssid = 0;
@@ -2460,7 +2591,8 @@
params.freqs = wpa_s->manual_sched_scan_freqs;
}
- if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) {
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
+ wpa_s->wpa_state <= WPA_SCANNING) {
params.mac_addr_rand = 1;
if (wpa_s->mac_addr_pno) {
params.mac_addr = wpa_s->mac_addr_pno;
@@ -2468,6 +2600,8 @@
}
}
+ wpa_scan_set_relative_rssi_params(wpa_s, ¶ms);
+
ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms);
os_free(params.filter_ssids);
if (ret == 0)
@@ -2486,6 +2620,7 @@
return 0;
ret = wpa_supplicant_stop_sched_scan(wpa_s);
+ wpa_s->sched_scan_stop_req = 1;
wpa_s->pno = 0;
wpa_s->pno_sched_pending = 0;
@@ -2557,18 +2692,20 @@
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
{
- int scan_work = !!wpa_s->scan_work;
+ struct wpa_radio_work *work;
+ struct wpa_radio *radio = wpa_s->radio;
-#ifdef CONFIG_P2P
- scan_work |= !!wpa_s->p2p_scan_work;
-#endif /* CONFIG_P2P */
-
- if (scan_work && wpa_s->own_scan_running) {
+ dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+ if (work->wpa_s != wpa_s || !work->started ||
+ (os_strcmp(work->type, "scan") != 0 &&
+ os_strcmp(work->type, "p2p-scan") != 0))
+ continue;
wpa_dbg(wpa_s, MSG_DEBUG, "Abort an ongoing scan");
- return wpa_drv_abort_scan(wpa_s);
+ return wpa_drv_abort_scan(wpa_s, wpa_s->curr_scan_cookie);
}
- return 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "No ongoing scan/p2p-scan found to abort");
+ return -1;
}
@@ -2609,13 +2746,6 @@
goto fail;
}
- if (!scan_plan->interval) {
- wpa_printf(MSG_ERROR,
- "scan plan %u: Interval cannot be zero",
- num);
- goto fail;
- }
-
if (scan_plan->interval > wpa_s->max_sched_scan_plan_interval) {
wpa_printf(MSG_WARNING,
"scan plan %u: Scan interval too long(%u), use the maximum allowed(%u)",
@@ -2689,3 +2819,31 @@
wpa_printf(MSG_ERROR, "invalid scan plans list");
return -1;
}
+
+
+/**
+ * wpas_scan_reset_sched_scan - Reset sched_scan state
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel a running scheduled scan and to reset an
+ * internal scan state to continue with a regular scan on the following
+ * wpa_supplicant_req_scan() calls.
+ */
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->normal_scans = 0;
+ if (wpa_s->sched_scanning) {
+ wpa_s->sched_scan_timed_out = 0;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ }
+}
+
+
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s)
+{
+ /* simulate timeout to restart the sched scan */
+ wpa_s->sched_scan_timed_out = 1;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 93ec9b3..2aa0a8b 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -39,14 +39,13 @@
void scan_only_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
-int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params);
-int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s);
struct wpa_driver_scan_params *
wpa_scan_clone_params(const struct wpa_driver_scan_params *src);
void wpa_scan_free_params(struct wpa_driver_scan_params *params);
int wpas_start_pno(struct wpa_supplicant *wpa_s);
int wpas_stop_pno(struct wpa_supplicant *wpa_s);
+void wpas_scan_reset_sched_scan(struct wpa_supplicant *wpa_s);
+void wpas_scan_restart_sched_scan(struct wpa_supplicant *wpa_s);
void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
unsigned int type);
@@ -54,5 +53,11 @@
unsigned int type, const u8 *addr,
const u8 *mask);
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
+void filter_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *res);
+void scan_snr(struct wpa_scan_res *res);
+void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res);
+void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index a6ace1a..beb9d6e 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -161,9 +161,10 @@
return;
}
- if (!(wpa_s->drv_rrm_flags &
- WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
- !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) {
+ if (!((wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) &&
+ (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) &&
+ !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_RRM)) {
wpa_printf(MSG_DEBUG,
"RRM: Insufficient RRM support in driver - do not use RRM");
return;
@@ -186,6 +187,13 @@
if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+ *pos |= WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE |
+ WLAN_RRM_CAPS_BEACON_REPORT_TABLE;
+
+ if (wpa_s->lci)
+ pos[1] |= WLAN_RRM_CAPS_LCI_MEASUREMENT;
+
wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
wpa_s->rrm.rrm_used = 1;
}
@@ -208,9 +216,6 @@
u8 ext_capab[18];
int ext_capab_len;
int skip_auth;
-#ifdef CONFIG_MBO
- const u8 *mbo;
-#endif /* CONFIG_MBO */
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -436,20 +441,15 @@
sme_auth_handle_rrm(wpa_s, bss);
-#ifdef CONFIG_MBO
- mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
- if (mbo) {
- int len;
+ wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie(
+ wpa_s, 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);
- len = wpas_mbo_supp_op_class_ie(
- wpa_s, 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);
- if (len > 0)
- wpa_s->sme.assoc_req_ie_len += len;
- }
-#endif /* CONFIG_MBO */
+ if (params.p2p)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab));
@@ -502,7 +502,7 @@
}
#ifdef CONFIG_MBO
- if (mbo) {
+ if (wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
@@ -534,12 +534,37 @@
wpas_connection_failed(wpa_s, bss->bssid);
return;
}
- params.sae_data = wpabuf_head(resp);
- params.sae_data_len = wpabuf_len(resp);
+ params.auth_data = wpabuf_head(resp);
+ params.auth_data_len = wpabuf_len(resp);
wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
}
#endif /* CONFIG_SAE */
+ old_ssid = wpa_s->current_ssid;
+ wpa_s->current_ssid = ssid;
+ wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+ wpa_supplicant_initiate_eapol(wpa_s);
+
+#ifdef CONFIG_FILS
+ /* TODO: FILS operations can in some cases be done between different
+ * network_ctx (i.e., same credentials can be used with multiple
+ * networks). */
+ if (params.auth_alg == WPA_AUTH_ALG_OPEN &&
+ wpa_key_mgmt_fils(ssid->key_mgmt)) {
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ ssid, 0) == 0)
+ wpa_printf(MSG_DEBUG,
+ "SME: Try to use FILS with PMKSA caching");
+ resp = fils_build_auth(wpa_s->wpa);
+ if (resp) {
+ params.auth_alg = WPA_AUTH_ALG_FILS;
+ params.auth_data = wpabuf_head(resp);
+ params.auth_data_len = wpabuf_len(resp);
+ wpa_s->sme.auth_alg = WPA_AUTH_ALG_FILS;
+ }
+ }
+#endif /* CONFIG_FILS */
+
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
@@ -549,13 +574,13 @@
wpa_clear_keys(wpa_s, bss->bssid);
wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
- old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = ssid;
- wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
- wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+#ifdef CONFIG_HS20
+ hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+
#ifdef CONFIG_P2P
/*
* If multi-channel concurrency is not supported, check for any
@@ -637,6 +662,10 @@
return;
}
+ /* Starting new connection, so clear the possibly used WPA IE from the
+ * previous association. */
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -862,10 +891,11 @@
}
}
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AUTH_REJECT MACSTR
- " auth_type=%u auth_transaction=%u status_code=%u ie=%s",
+ " auth_type=%u auth_transaction=%u status_code=%u%s%s",
MAC2STR(data->auth.peer), data->auth.auth_type,
data->auth.auth_transaction, data->auth.status_code,
- ie_txt);
+ ie_txt ? " ie=" : "",
+ ie_txt ? ie_txt : "");
os_free(ie_txt);
if (data->auth.status_code !=
@@ -903,9 +933,17 @@
#ifdef CONFIG_IEEE80211R
if (data->auth.auth_type == WLAN_AUTH_FT) {
+ const u8 *ric_ies = NULL;
+ size_t ric_ies_len = 0;
+
+ if (wpa_s->ric_ies) {
+ ric_ies = wpabuf_head(wpa_s->ric_ies);
+ ric_ies_len = wpabuf_len(wpa_s->ric_ies);
+ }
if (wpa_ft_process_response(wpa_s->wpa, data->auth.ies,
data->auth.ies_len, 0,
- data->auth.peer, NULL, 0) < 0) {
+ data->auth.peer,
+ ric_ies, ric_ies_len) < 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: FT Authentication response processing failed");
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
@@ -920,6 +958,24 @@
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_FILS
+ if (data->auth.auth_type == WLAN_AUTH_FILS_SK) {
+ if (fils_process_auth(wpa_s->wpa, data->auth.ies,
+ data->auth.ies_len) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: FILS Authentication response processing failed");
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid="
+ MACSTR
+ " reason=%d locally_generated=1",
+ MAC2STR(wpa_s->pending_bssid),
+ WLAN_REASON_DEAUTH_LEAVING);
+ wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ return;
+ }
+ }
+#endif /* CONFIG_FILS */
+
sme_associate(wpa_s, ssid->mode, data->auth.peer,
data->auth.auth_type);
}
@@ -930,6 +986,9 @@
{
struct wpa_driver_associate_params params;
struct ieee802_11_elems elems;
+#ifdef CONFIG_FILS
+ u8 nonces[2 * FILS_NONCE_LEN];
+#endif /* CONFIG_FILS */
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -940,6 +999,62 @@
#endif /* CONFIG_VHT_OVERRIDES */
os_memset(¶ms, 0, sizeof(params));
+
+#ifdef CONFIG_FILS
+ if (auth_type == WLAN_AUTH_FILS_SK) {
+ struct wpabuf *buf;
+ const u8 *snonce, *anonce;
+ const unsigned int max_hlp = 20;
+ struct wpabuf *hlp[max_hlp];
+ unsigned int i, num_hlp = 0;
+ struct fils_hlp_req *req;
+
+ dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
+ list) {
+ hlp[num_hlp] = wpabuf_alloc(2 * ETH_ALEN + 6 +
+ wpabuf_len(req->pkt));
+ if (!hlp[num_hlp])
+ break;
+ wpabuf_put_data(hlp[num_hlp], req->dst, ETH_ALEN);
+ wpabuf_put_data(hlp[num_hlp], wpa_s->own_addr,
+ ETH_ALEN);
+ wpabuf_put_data(hlp[num_hlp],
+ "\xaa\xaa\x03\x00\x00\x00", 6);
+ wpabuf_put_buf(hlp[num_hlp], req->pkt);
+ num_hlp++;
+ if (num_hlp >= max_hlp)
+ break;
+ }
+
+ buf = fils_build_assoc_req(wpa_s->wpa, ¶ms.fils_kek,
+ ¶ms.fils_kek_len, &snonce,
+ &anonce,
+ (const struct wpabuf **) hlp,
+ num_hlp);
+ for (i = 0; i < num_hlp; i++)
+ wpabuf_free(hlp[i]);
+ if (!buf)
+ return;
+ /* TODO: Make wpa_s->sme.assoc_req_ie use dynamic allocation */
+ if (wpa_s->sme.assoc_req_ie_len + wpabuf_len(buf) >
+ sizeof(wpa_s->sme.assoc_req_ie)) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Not enough buffer room for own AssocReq elements");
+ wpabuf_free(buf);
+ return;
+ }
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
+ wpabuf_free(buf);
+
+ os_memcpy(nonces, snonce, FILS_NONCE_LEN);
+ os_memcpy(nonces + FILS_NONCE_LEN, anonce, FILS_NONCE_LEN);
+ params.fils_nonces = nonces;
+ params.fils_nonces_len = sizeof(nonces);
+ }
+#endif /* CONFIG_FILS */
+
params.bssid = bssid;
params.ssid = wpa_s->sme.ssid;
params.ssid_len = wpa_s->sme.ssid_len;
@@ -1572,8 +1687,10 @@
nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
wpa_s->sme.sa_query_count + 1,
WLAN_SA_QUERY_TR_ID_LEN);
- if (nbuf == NULL)
+ if (nbuf == NULL) {
+ sme_stop_sa_query(wpa_s);
return;
+ }
if (wpa_s->sme.sa_query_count == 0) {
/* Starting a new SA Query procedure */
os_get_reltime(&wpa_s->sme.sa_query_start);
@@ -1584,6 +1701,7 @@
if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
wpa_printf(MSG_DEBUG, "Could not generate SA Query ID");
+ sme_stop_sa_query(wpa_s);
return;
}
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
index ea964ce..bc5d49a 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.in
@@ -5,9 +5,9 @@
[Service]
Type=dbus
-BusName=fi.epitest.hostap.WPASupplicant
+BusName=@DBUS_INTERFACE@
ExecStart=@BINDIR@/wpa_supplicant -u
[Install]
WantedBy=multi-user.target
-Alias=dbus-fi.epitest.hostap.WPASupplicant.service
+Alias=dbus-@DBUS_INTERFACE@.service
diff --git a/wpa_supplicant/wmm_ac.h b/wpa_supplicant/wmm_ac.h
index 5171b16..0d15ad0 100644
--- a/wpa_supplicant/wmm_ac.h
+++ b/wpa_supplicant/wmm_ac.h
@@ -88,7 +88,7 @@
*/
struct wmm_ac_addts_request {
/*
- * dialog token - Used to link the recived ADDTS response with this
+ * dialog token - Used to link the received ADDTS response with this
* saved ADDTS request when ADDTS response is being handled
*/
u8 dialog_token;
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 7dc1909..bd0b517 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -24,6 +24,7 @@
#define MAX_TFS_IE_LEN 1024
#define WNM_MAX_NEIGHBOR_REPORT 10
+#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
@@ -501,7 +502,7 @@
static struct wpa_bss *
-compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs)
{
u8 i;
@@ -509,7 +510,7 @@
struct wpa_bss *target;
if (!bss)
- return 0;
+ return NULL;
wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
MAC2STR(wpa_s->bssid), bss->level);
@@ -534,6 +535,19 @@
continue;
}
+ if (age_secs) {
+ struct os_reltime now;
+
+ if (os_get_reltime(&now) == 0 &&
+ os_reltime_expired(&now, &target->last_update,
+ age_secs)) {
+ wpa_printf(MSG_DEBUG,
+ "Candidate BSS is more than %ld seconds old",
+ age_secs);
+ continue;
+ }
+ }
+
if (bss->ssid_len != target->ssid_len ||
os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
/*
@@ -550,7 +564,7 @@
if (wpa_s->current_ssid &&
!wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
- 1)) {
+ 1, 0)) {
wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
" (pref %d) does not match the current network profile",
MAC2STR(nei->bssid),
@@ -744,7 +758,7 @@
struct wpa_bss *bss = wpa_s->last_scan_res[i];
int res;
- if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1)) {
+ if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) {
res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--);
if (res == -2)
continue; /* could not build entry for BSS */
@@ -834,6 +848,41 @@
}
+static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ int after_new_scan)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Transition to BSS " MACSTR
+ " based on BSS Transition Management Request (old BSSID "
+ MACSTR " after_new_scan=%d)",
+ MAC2STR(bss->bssid), MAC2STR(wpa_s->bssid), after_new_scan);
+
+ /* Send the BSS Management Response - Accept */
+ if (wpa_s->wnm_reply) {
+ wpa_s->wnm_reply = 0;
+ wpa_printf(MSG_DEBUG,
+ "WNM: Sending successful BSS Transition Management Response");
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ WNM_BSS_TM_ACCEPT,
+ 0, bss->bssid);
+ }
+
+ if (bss == wpa_s->current_bss) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Already associated with the preferred candidate");
+ wnm_deallocate_memory(wpa_s);
+ return;
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_printf(MSG_DEBUG, "WNM: Issuing connect");
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ wnm_deallocate_memory(wpa_s);
+}
+
+
int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
{
struct wpa_bss *bss;
@@ -843,6 +892,8 @@
if (!wpa_s->wnm_neighbor_report_elements)
return 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Process scan results for BSS Transition Management");
if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
&wpa_s->scan_trigger_time)) {
wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
@@ -858,7 +909,7 @@
}
/* Compare the Neighbor Report and scan results */
- bss = compare_scan_neighbor_results(wpa_s);
+ bss = compare_scan_neighbor_results(wpa_s, 0);
if (!bss) {
wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
@@ -866,25 +917,7 @@
}
/* Associate to the network */
- /* Send the BSS Management Response - Accept */
- if (wpa_s->wnm_reply) {
- wpa_s->wnm_reply = 0;
- wnm_send_bss_transition_mgmt_resp(wpa_s,
- wpa_s->wnm_dialog_token,
- WNM_BSS_TM_ACCEPT,
- 0, bss->bssid);
- }
-
- if (bss == wpa_s->current_bss) {
- wpa_printf(MSG_DEBUG,
- "WNM: Already associated with the preferred candidate");
- wnm_deallocate_memory(wpa_s);
- return 1;
- }
-
- wpa_s->reassociate = 1;
- wpa_supplicant_connect(wpa_s, bss, ssid);
- wnm_deallocate_memory(wpa_s);
+ wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
return 1;
send_bss_resp_fail:
@@ -1025,6 +1058,79 @@
}
+static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_scan_results *scan_res;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ u8 i, found = 0;
+ size_t j;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Fetch current scan results from the driver for checking transition candidates");
+ scan_res = wpa_drv_get_scan_results2(wpa_s);
+ if (!scan_res) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results");
+ return 0;
+ }
+
+ if (scan_res->fetch_time.sec == 0)
+ os_get_reltime(&scan_res->fetch_time);
+
+ filter_scan_res(wpa_s, scan_res);
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ if (nei->preference_present && nei->preference == 0)
+ continue;
+
+ for (j = 0; j < scan_res->num; j++) {
+ struct wpa_scan_res *res;
+ const u8 *ssid_ie;
+
+ res = scan_res->res[j];
+ if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 ||
+ res->age > WNM_SCAN_RESULT_AGE * 1000)
+ continue;
+ bss = wpa_s->current_bss;
+ ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
+ if (bss && ssid_ie &&
+ (bss->ssid_len != ssid_ie[1] ||
+ os_memcmp(bss->ssid, ssid_ie + 2,
+ bss->ssid_len) != 0))
+ continue;
+
+ /* Potential candidate found */
+ found = 1;
+ scan_snr(res);
+ scan_est_throughput(wpa_s, res);
+ wpa_bss_update_scan_res(wpa_s, res,
+ &scan_res->fetch_time);
+ }
+ }
+
+ wpa_scan_results_free(scan_res);
+ if (!found) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: No transition candidate matches existing scan results");
+ return 0;
+ }
+
+ bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE);
+ if (!bss) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WNM: Comparison of scan results against transition candidates did not find matches");
+ return 0;
+ }
+
+ /* Associate to the network */
+ wnm_bss_tm_connect(wpa_s, bss, ssid, 0);
+ return 1;
+}
+
+
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *pos, const u8 *end,
int reply)
@@ -1055,6 +1161,19 @@
wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
wpa_s->wnm_dissoc_timer, valid_int);
+#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS)
+ if (wpa_s->reject_btm_req_reason) {
+ wpa_printf(MSG_INFO,
+ "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d",
+ wpa_s->reject_btm_req_reason);
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ wpa_s->reject_btm_req_reason,
+ 0, NULL);
+ return;
+ }
+#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */
+
pos += 5;
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
@@ -1157,6 +1276,20 @@
wpa_s->wnm_cand_valid_until.usec %= 1000000;
os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
+ /*
+ * Fetch the latest scan results from the kernel and check for
+ * candidates based on those results first. This can help in
+ * finding more up-to-date information should the driver has
+ * done some internal scanning operations after the last scan
+ * result update in wpa_supplicant.
+ */
+ if (wnm_fetch_scan_results(wpa_s) > 0)
+ return;
+
+ /*
+ * Try to use previously received scan results, if they are
+ * recent enough to use for a connection.
+ */
if (wpa_s->last_scan_res_used > 0) {
struct os_reltime now;
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 36a7a4e..964311c 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-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,7 @@
#include <dirent.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
+#include "common/cli.h"
#include "common/wpa_ctrl.h"
#include "utils/common.h"
#include "utils/eloop.h"
@@ -28,43 +29,7 @@
static const char *const wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
-
-
-static const char *const wpa_cli_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"See README for more details.\n";
-
-static const char *const wpa_cli_full_license =
-"This software may be distributed under the terms of the BSD license.\n"
-"\n"
-"Redistribution and use in source and binary forms, with or without\n"
-"modification, are permitted provided that the following conditions are\n"
-"met:\n"
-"\n"
-"1. Redistributions of source code must retain the above copyright\n"
-" notice, this list of conditions and the following disclaimer.\n"
-"\n"
-"2. Redistributions in binary form must reproduce the above copyright\n"
-" notice, this list of conditions and the following disclaimer in the\n"
-" documentation and/or other materials provided with the distribution.\n"
-"\n"
-"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
-" names of its contributors may be used to endorse or promote products\n"
-" derived from this software without specific prior written permission.\n"
-"\n"
-"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
-"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
-"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
-"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
-"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
-"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
-"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
-"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
-"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
-"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
-"\n";
+"Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi> and contributors";
#define VENDOR_ELEM_FRAME_ID \
" 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \
@@ -90,16 +55,14 @@
static int interactive = 0;
static char *ifname_prefix = NULL;
-struct cli_txt_entry {
- struct dl_list list;
- char *txt;
-};
-
static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */
+#ifdef CONFIG_AP
+static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
+#endif /* CONFIG_AP */
static void print_help(const char *cmd);
@@ -108,6 +71,7 @@
static char * wpa_cli_get_default_ifname(void);
static char ** wpa_list_cmd_list(void);
static void update_networks(struct wpa_ctrl *ctrl);
+static void update_stations(struct wpa_ctrl *ctrl);
static void usage(void)
@@ -130,168 +94,6 @@
}
-static void cli_txt_list_free(struct cli_txt_entry *e)
-{
- dl_list_del(&e->list);
- os_free(e->txt);
- os_free(e);
-}
-
-
-static void cli_txt_list_flush(struct dl_list *list)
-{
- struct cli_txt_entry *e;
- while ((e = dl_list_first(list, struct cli_txt_entry, list)))
- cli_txt_list_free(e);
-}
-
-
-static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
- const char *txt)
-{
- struct cli_txt_entry *e;
- dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
- if (os_strcmp(e->txt, txt) == 0)
- return e;
- }
- return NULL;
-}
-
-
-static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
-{
- struct cli_txt_entry *e;
- e = cli_txt_list_get(txt_list, txt);
- if (e)
- cli_txt_list_free(e);
-}
-
-
-static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
-{
- u8 addr[ETH_ALEN];
- char buf[18];
- if (hwaddr_aton(txt, addr) < 0)
- return;
- os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
- cli_txt_list_del(txt_list, buf);
-}
-
-
-#ifdef CONFIG_P2P
-static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
- int separator)
-{
- const char *end;
- char *buf;
- end = os_strchr(txt, separator);
- if (end == NULL)
- end = txt + os_strlen(txt);
- buf = dup_binstr(txt, end - txt);
- if (buf == NULL)
- return;
- cli_txt_list_del(txt_list, buf);
- os_free(buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
-{
- struct cli_txt_entry *e;
- e = cli_txt_list_get(txt_list, txt);
- if (e)
- return 0;
- e = os_zalloc(sizeof(*e));
- if (e == NULL)
- return -1;
- e->txt = os_strdup(txt);
- if (e->txt == NULL) {
- os_free(e);
- return -1;
- }
- dl_list_add(txt_list, &e->list);
- return 0;
-}
-
-
-#ifdef CONFIG_P2P
-static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
-{
- u8 addr[ETH_ALEN];
- char buf[18];
- if (hwaddr_aton(txt, addr) < 0)
- return -1;
- os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
- return cli_txt_list_add(txt_list, buf);
-}
-#endif /* CONFIG_P2P */
-
-
-static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
- int separator)
-{
- const char *end;
- char *buf;
- int ret;
- end = os_strchr(txt, separator);
- if (end == NULL)
- end = txt + os_strlen(txt);
- buf = dup_binstr(txt, end - txt);
- if (buf == NULL)
- return -1;
- ret = cli_txt_list_add(txt_list, buf);
- os_free(buf);
- return ret;
-}
-
-
-static char ** cli_txt_list_array(struct dl_list *txt_list)
-{
- unsigned int i, count = dl_list_len(txt_list);
- char **res;
- struct cli_txt_entry *e;
-
- res = os_calloc(count + 1, sizeof(char *));
- if (res == NULL)
- return NULL;
-
- i = 0;
- dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
- res[i] = os_strdup(e->txt);
- if (res[i] == NULL)
- break;
- i++;
- }
-
- return res;
-}
-
-
-static int get_cmd_arg_num(const char *str, int pos)
-{
- int arg = 0, i;
-
- for (i = 0; i <= pos; i++) {
- if (str[i] != ' ') {
- arg++;
- while (i <= pos && str[i] != ' ')
- i++;
- }
- }
-
- if (arg > 0)
- arg--;
- return arg;
-}
-
-
-static int str_starts(const char *src, const char *match)
-{
- return os_strncmp(src, match, os_strlen(match)) == 0;
-}
-
-
static int wpa_cli_show_event(const char *event)
{
const char *start;
@@ -416,7 +218,7 @@
}
-static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
{
char buf[4096];
size_t len;
@@ -452,42 +254,12 @@
}
-static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+static int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
{
return _wpa_ctrl_command(ctrl, cmd, 1);
}
-static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
- char *argv[])
-{
- int i, res;
- char *pos, *end;
-
- pos = buf;
- end = buf + buflen;
-
- res = os_snprintf(pos, end - pos, "%s", cmd);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
-
- for (i = 0; i < argc; i++) {
- res = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (os_snprintf_error(end - pos, res))
- goto fail;
- pos += res;
- }
-
- buf[buflen - 1] = '\0';
- return 0;
-
-fail:
- printf("Too long command\n");
- return -1;
-}
-
-
static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
int argc, char *argv[])
{
@@ -563,6 +335,39 @@
}
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+
+static int wpa_cli_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PMKSA_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "PMKSA_ADD", 8, argc, argv);
+}
+
+
+#ifdef CONFIG_MESH
+
+static int wpa_cli_mesh_cmd_pmksa_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PMKSA_GET", 1, argc, argv);
+}
+
+
+static int wpa_cli_mesh_cmd_pmksa_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_PMKSA_ADD", 4, argc, argv);
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
print_help(argc > 0 ? argv[0] : NULL);
@@ -587,7 +392,7 @@
static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
+ printf("%s\n\n%s\n", wpa_cli_version, cli_full_license);
return 0;
}
@@ -683,7 +488,11 @@
"tdls_external_control", "osu_dir", "wowlan_triggers",
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
- "reassoc_same_bss_optim", "wps_priority"
+ "reassoc_same_bss_optim", "wps_priority",
+#ifdef CONFIG_TESTING_OPTIONS
+ "ignore_auth_resp",
+#endif /* CONFIG_TESTING_OPTIONS */
+ "relative_rssi", "relative_band_adjust",
};
int i, num_fields = ARRAY_SIZE(fields);
@@ -711,6 +520,13 @@
}
+static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
+}
+
+
static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
@@ -1608,11 +1424,14 @@
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
+ "macsec_integ_only",
+ "macsec_port",
+ "mka_priority",
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
"update_identifier",
#endif /* CONFIG_HS20 */
- "mac_addr", "pbss"
+ "mac_addr", "pbss", "wps_disabled"
};
@@ -1817,6 +1636,48 @@
}
+static char ** wpa_cli_complete_get_capability(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ const char *fields[] = {
+ "eap", "pairwise", "group", "group_mgmt", "key_mgmt",
+ "proto", "auth_alg", "modes", "channels", "freq",
+#ifdef CONFIG_TDLS
+ "tdls",
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_ERP
+ "erp",
+#endif /* CONFIG_ERP */
+#ifdef CONFIG_FIPS
+ "fips",
+#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+ "acs",
+#endif /* CONFIG_ACS */
+ };
+ int i, num_fields = ARRAY_SIZE(fields);
+ char **res = NULL;
+
+ if (arg == 1) {
+ res = os_calloc(num_fields + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ for (i = 0; i < num_fields; i++) {
+ res[i] = os_strdup(fields[i]);
+ if (res[i] == NULL)
+ return res;
+ }
+ }
+ if (arg == 2) {
+ res = os_calloc(1 + 1, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ res[0] = os_strdup("strict");
+ }
+ return res;
+}
+
+
static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
printf("Available interfaces:\n");
@@ -1916,8 +1777,23 @@
}
-static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
- char *addr, size_t addr_len)
+static char ** wpa_cli_complete_sta(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
+ char *addr, size_t addr_len, int print)
{
char buf[4096], *pos;
size_t len;
@@ -1947,7 +1823,8 @@
buf[len] = '\0';
if (os_memcmp(buf, "FAIL", 4) == 0)
return -1;
- printf("%s", buf);
+ if (print)
+ printf("%s", buf);
pos = buf;
while (*pos != '\0' && *pos != '\n')
@@ -1962,16 +1839,33 @@
{
char addr[32], cmd[64];
- if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
return 0;
do {
os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
- } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
return -1;
}
+static int wpa_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char addr[32], cmd[64];
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return 0;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ printf("%s\n", addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+
+ return 0;
+}
+
+
static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1979,12 +1873,43 @@
}
+static char ** wpa_cli_complete_deauthenticate(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
}
+
+static char ** wpa_cli_complete_disassociate(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = cli_txt_list_array(&stations);
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2175,6 +2100,13 @@
}
+static int wpa_cli_cmd_p2p_group_member(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_MEMBER", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2349,7 +2281,7 @@
}
-static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
+static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, const char *cmd,
char *addr, size_t addr_len,
int discovered)
{
@@ -2885,6 +2817,20 @@
}
+static int wpa_cli_cmd_p2p_lo_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_START", 4, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_lo_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_LO_STOP", 0, argc, argv);
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2942,6 +2888,9 @@
{ "get", wpa_cli_cmd_get, wpa_cli_complete_get,
cli_cmd_flag_none,
"<name> = get information" },
+ { "driver_flags", wpa_cli_cmd_driver_flags, NULL,
+ cli_cmd_flag_none,
+ "= list driver flags" },
{ "logon", wpa_cli_cmd_logon, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
@@ -2954,6 +2903,22 @@
{ "pmksa_flush", wpa_cli_cmd_pmksa_flush, NULL,
cli_cmd_flag_none,
"= flush PMKSA cache entries" },
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ { "pmksa_get", wpa_cli_cmd_pmksa_get, NULL,
+ cli_cmd_flag_none,
+ "<network_id> = fetch all stored PMKSA cache entries" },
+ { "pmksa_add", wpa_cli_cmd_pmksa_add, NULL,
+ cli_cmd_flag_sensitive,
+ "<network_id> <BSSID> <PMKID> <PMK> <reauth_time in seconds> <expiration in seconds> <akmp> <opportunistic> = store PMKSA cache entry from external storage" },
+#ifdef CONFIG_MESH
+ { "mesh_pmksa_get", wpa_cli_mesh_cmd_pmksa_get, NULL,
+ cli_cmd_flag_none,
+ "<peer MAC address | any> = fetch all stored mesh PMKSA cache entries" },
+ { "mesh_pmksa_add", wpa_cli_mesh_cmd_pmksa_add, NULL,
+ cli_cmd_flag_sensitive,
+ "<BSSID> <PMKID> <PMK> <expiration in seconds> = store mesh PMKSA cache entry from external storage" },
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
{ "reassociate", wpa_cli_cmd_reassociate, NULL,
cli_cmd_flag_none,
"= force reassociation" },
@@ -2963,30 +2928,30 @@
{ "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = force preauthentication" },
- { "identity", wpa_cli_cmd_identity, NULL,
+ { "identity", wpa_cli_cmd_identity, wpa_cli_complete_network_id,
cli_cmd_flag_none,
"<network id> <identity> = configure identity for an SSID" },
- { "password", wpa_cli_cmd_password, NULL,
+ { "password", wpa_cli_cmd_password, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <password> = configure password for an SSID" },
- { "new_password", wpa_cli_cmd_new_password, NULL,
- cli_cmd_flag_sensitive,
+ { "new_password", wpa_cli_cmd_new_password,
+ wpa_cli_complete_network_id, cli_cmd_flag_sensitive,
"<network id> <password> = change password for an SSID" },
- { "pin", wpa_cli_cmd_pin, NULL,
+ { "pin", wpa_cli_cmd_pin, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <pin> = configure pin for an SSID" },
- { "otp", wpa_cli_cmd_otp, NULL,
+ { "otp", wpa_cli_cmd_otp, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
- { "passphrase", wpa_cli_cmd_passphrase, NULL,
+ { "passphrase", wpa_cli_cmd_passphrase, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
- { "sim", wpa_cli_cmd_sim, NULL,
+ { "sim", wpa_cli_cmd_sim, wpa_cli_complete_network_id,
cli_cmd_flag_sensitive,
"<network id> <pin> = report SIM operation result" },
- { "bssid", wpa_cli_cmd_bssid, NULL,
+ { "bssid", wpa_cli_cmd_bssid, wpa_cli_complete_network_id,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
{ "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
@@ -3069,8 +3034,8 @@
{ "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<<idx> | <bssid>> = get detailed scan result info" },
- { "get_capability", wpa_cli_cmd_get_capability, NULL,
- cli_cmd_flag_none,
+ { "get_capability", wpa_cli_cmd_get_capability,
+ wpa_cli_complete_get_capability, cli_cmd_flag_none,
"<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> "
"= get capabilities" },
{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
@@ -3185,17 +3150,20 @@
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
#ifdef CONFIG_AP
- { "sta", wpa_cli_cmd_sta, NULL,
+ { "sta", wpa_cli_cmd_sta, wpa_cli_complete_sta,
cli_cmd_flag_none,
"<addr> = get information about an associated station (AP)" },
{ "all_sta", wpa_cli_cmd_all_sta, NULL,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
- { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
+ { "list_sta", wpa_cli_cmd_list_sta, NULL,
cli_cmd_flag_none,
+ "= list all stations (AP)" },
+ { "deauthenticate", wpa_cli_cmd_deauthenticate,
+ wpa_cli_complete_deauthenticate, cli_cmd_flag_none,
"<addr> = deauthenticate a station" },
- { "disassociate", wpa_cli_cmd_disassociate, NULL,
- cli_cmd_flag_none,
+ { "disassociate", wpa_cli_cmd_disassociate,
+ wpa_cli_complete_disassociate, cli_cmd_flag_none,
"<addr> = disassociate a station" },
{ "chan_switch", wpa_cli_cmd_chanswitch, NULL,
cli_cmd_flag_none,
@@ -3253,6 +3221,9 @@
"<ifname> = remove P2P group interface (terminate group if GO)" },
{ "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
"[ht40] = add a new P2P group (local end as GO)" },
+ { "p2p_group_member", wpa_cli_cmd_p2p_group_member, NULL,
+ cli_cmd_flag_none,
+ "<dev_addr> = Get peer interface address on local GO using peer Device Address" },
{ "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <method> = request provisioning discovery" },
@@ -3455,8 +3426,7 @@
},
{ "neighbor_rep_request",
wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
- "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
- "(with optional given SSID, default: current SSID)"
+ "[ssid=<SSID>] [lci] [civic] = Trigger request to AP for neighboring AP report (with optional given SSID in hex or enclosed in double quotes, default: current SSID; with optional LCI and location civic request)"
},
{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
"= flush ERP keys" },
@@ -3468,6 +3438,12 @@
{ "get_pref_freq_list", wpa_cli_cmd_get_pref_freq_list, NULL,
cli_cmd_flag_none,
"<interface type> = retrieve preferred freq list for the specified interface type" },
+ { "p2p_lo_start", wpa_cli_cmd_p2p_lo_start, NULL,
+ cli_cmd_flag_none,
+ "<freq> <period> <interval> <count> = start P2P listen offload" },
+ { "p2p_lo_stop", wpa_cli_cmd_p2p_lo_stop, NULL,
+ cli_cmd_flag_none,
+ "= stop P2P listen offload" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -3666,12 +3642,6 @@
}
-static int str_match(const char *a, const char *b)
-{
- return os_strncmp(a, b, os_strlen(b)) == 0;
-}
-
-
static int wpa_cli_exec(const char *program, const char *arg1,
const char *arg2)
{
@@ -3727,7 +3697,7 @@
pos = prev;
}
- if (str_match(pos, WPA_EVENT_CONNECTED)) {
+ if (str_starts(pos, WPA_EVENT_CONNECTED)) {
int new_id = -1;
os_unsetenv("WPA_ID");
os_unsetenv("WPA_ID_STR");
@@ -3763,44 +3733,48 @@
wpa_cli_last_id = new_id;
wpa_cli_exec(action_file, ifname, "CONNECTED");
}
- } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
+ } else if (str_starts(pos, WPA_EVENT_DISCONNECTED)) {
if (wpa_cli_connected) {
wpa_cli_connected = 0;
wpa_cli_exec(action_file, ifname, "DISCONNECTED");
}
- } else if (str_match(pos, MESH_GROUP_STARTED)) {
+ } else if (str_starts(pos, AP_EVENT_ENABLED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_GROUP_REMOVED)) {
+ } else if (str_starts(pos, AP_EVENT_DISABLED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_PEER_CONNECTED)) {
+ } else if (str_starts(pos, MESH_GROUP_STARTED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
+ } else if (str_starts(pos, MESH_GROUP_REMOVED)) {
wpa_cli_exec(action_file, ctrl_ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
+ } else if (str_starts(pos, MESH_PEER_CONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_starts(pos, MESH_PEER_DISCONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_starts(pos, P2P_EVENT_GROUP_STARTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
+ } else if (str_starts(pos, P2P_EVENT_GROUP_REMOVED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
+ } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_ENABLE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
+ } else if (str_starts(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+ } else if (str_starts(pos, P2P_EVENT_GO_NEG_FAILURE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+ } else if (str_starts(pos, WPS_EVENT_SUCCESS)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPS_EVENT_FAIL)) {
+ } else if (str_starts(pos, WPS_EVENT_FAIL)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, AP_STA_CONNECTED)) {
+ } else if (str_starts(pos, AP_STA_CONNECTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, AP_STA_DISCONNECTED)) {
+ } else if (str_starts(pos, AP_STA_DISCONNECTED)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+ } else if (str_starts(pos, ESS_DISASSOC_IMMINENT)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
+ } else if (str_starts(pos, HS20_SUBSCRIPTION_REMEDIATION)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
+ } else if (str_starts(pos, HS20_DEAUTH_IMMINENT_NOTICE)) {
wpa_cli_exec(action_file, ifname, pos);
- } else if (str_match(pos, WPA_EVENT_TERMINATING)) {
+ } else if (str_starts(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
}
@@ -3825,6 +3799,7 @@
edit_clear_line();
printf("\rConnection to wpa_supplicant re-established\n");
edit_redraw();
+ update_stations(ctrl_conn);
}
}
@@ -3910,7 +3885,7 @@
pos = msg;
}
- if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+ if (str_starts(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
edit_clear_line();
printf("\rConnection to wpa_supplicant lost - trying to "
"reconnect\n");
@@ -3961,37 +3936,6 @@
}
}
-#define max_args 10
-
-static int tokenize_cmd(char *cmd, char *argv[])
-{
- char *pos;
- int argc = 0;
-
- pos = cmd;
- for (;;) {
- while (*pos == ' ')
- pos++;
- if (*pos == '\0')
- break;
- argv[argc] = pos;
- argc++;
- if (argc == max_args)
- break;
- if (*pos == '"') {
- char *pos2 = os_strrchr(pos, '"');
- if (pos2)
- pos = pos2 + 1;
- }
- while (*pos != '\0' && *pos != ' ')
- pos++;
- if (*pos == ' ')
- *pos++ = '\0';
- }
-
- return argc;
-}
-
static void wpa_cli_ping(void *eloop_ctx, void *timeout_ctx)
{
@@ -4078,7 +4022,7 @@
char buf[4096];
size_t len = sizeof(buf);
int ret;
- char *cmd = "BSS RANGE=ALL MASK=0x2";
+ const char *cmd = "BSS RANGE=ALL MASK=0x2";
char *pos, *end;
if (ctrl == NULL)
@@ -4109,7 +4053,7 @@
char buf[4096];
size_t len = sizeof(buf);
int ret;
- char *cmd = "INTERFACES";
+ const char *cmd = "INTERFACES";
char *pos, *end;
char txt[200];
@@ -4141,7 +4085,7 @@
char buf[4096];
size_t len = sizeof(buf);
int ret;
- char *cmd = "LIST_NETWORKS";
+ const char *cmd = "LIST_NETWORKS";
char *pos, *end;
int header = 1;
@@ -4168,6 +4112,27 @@
}
+static void update_stations(struct wpa_ctrl *ctrl)
+{
+#ifdef CONFIG_AP
+ char addr[32], cmd[64];
+
+ if (!ctrl || !interactive)
+ return;
+
+ cli_txt_list_flush(&stations);
+
+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
+ return;
+ do {
+ if (os_strcmp(addr, "") != 0)
+ cli_txt_list_add(&stations, addr);
+ os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
+#endif /* CONFIG_AP */
+}
+
+
static void try_connection(void *eloop_ctx, void *timeout_ctx)
{
if (ctrl_conn)
@@ -4189,6 +4154,7 @@
update_bssid_list(ctrl_conn);
update_networks(ctrl_conn);
+ update_stations(ctrl_conn);
if (warning_displayed)
printf("Connection established.\n");
@@ -4401,7 +4367,7 @@
interactive = (argc == optind) && (action_file == NULL);
if (interactive)
- printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
+ printf("%s\n\n%s\n\n", wpa_cli_version, cli_license);
if (eloop_init())
return -1;
@@ -4435,6 +4401,7 @@
"control interface\n");
}
}
+ update_stations(ctrl_conn);
}
}
diff --git a/wpa_supplicant/wpa_client_include/libwpa_client/qca-vendor.h b/wpa_supplicant/wpa_client_include/libwpa_client/qca-vendor.h
new file mode 120000
index 0000000..c074acd
--- /dev/null
+++ b/wpa_supplicant/wpa_client_include/libwpa_client/qca-vendor.h
@@ -0,0 +1 @@
+../../src/common/qca-vendor.h
\ No newline at end of file
diff --git a/wpa_supplicant/wpa_client_include/libwpa_client/wpa_ctrl.h b/wpa_supplicant/wpa_client_include/libwpa_client/wpa_ctrl.h
new file mode 120000
index 0000000..d1116dc
--- /dev/null
+++ b/wpa_supplicant/wpa_client_include/libwpa_client/wpa_ctrl.h
@@ -0,0 +1 @@
+../../src/common/wpa_ctrl.h
\ No newline at end of file
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index 9b568f0..adca1cc 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -17,6 +17,7 @@
unsigned char psk[32];
int i;
char *ssid, *passphrase, buf[64], *pos;
+ size_t len;
if (argc < 2) {
printf("usage: wpa_passphrase <ssid> [passphrase]\n"
@@ -47,10 +48,15 @@
passphrase = buf;
}
- if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) {
+ len = os_strlen(passphrase);
+ if (len < 8 || len > 63) {
printf("Passphrase must be 8..63 characters\n");
return 1;
}
+ if (has_ctrl_char((u8 *) passphrase, len)) {
+ printf("Invalid passphrase character\n");
+ return 1;
+ }
pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 511df4f..46cb95e 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -21,6 +21,7 @@
#include "common/privsep_commands.h"
#include "common/ieee802_11_defs.h"
+#define WPA_PRIV_MAX_L2 3
struct wpa_priv_interface {
struct wpa_priv_interface *next;
@@ -35,11 +36,16 @@
void *drv_priv;
void *drv_global_priv;
struct sockaddr_un drv_addr;
+ socklen_t drv_addr_len;
int wpas_registered;
- /* TODO: add support for multiple l2 connections */
- struct l2_packet_data *l2;
- struct sockaddr_un l2_addr;
+ struct l2_packet_data *l2[WPA_PRIV_MAX_L2];
+ struct sockaddr_un l2_addr[WPA_PRIV_MAX_L2];
+ socklen_t l2_addr_len[WPA_PRIV_MAX_L2];
+ struct wpa_priv_l2 {
+ struct wpa_priv_interface *parent;
+ int idx;
+ } l2_ctx[WPA_PRIV_MAX_L2];
};
struct wpa_priv_global {
@@ -48,8 +54,10 @@
static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
+ int i;
+
if (iface->drv_priv) {
wpa_printf(MSG_DEBUG, "Cleaning up forgotten driver instance");
if (iface->driver->deinit)
@@ -62,11 +70,13 @@
iface->wpas_registered = 0;
}
- if (iface->l2) {
- wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
- "instance");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+ if (iface->l2[i]) {
+ wpa_printf(MSG_DEBUG,
+ "Cleaning up forgotten l2_packet instance");
+ l2_packet_deinit(iface->l2[i]);
+ iface->l2[i] = NULL;
+ }
}
if (iface->driver->init2) {
@@ -96,7 +106,8 @@
wpa_printf(MSG_DEBUG, "Driver wrapper '%s' initialized for interface "
"'%s'", iface->driver_name, iface->ifname);
- os_memcpy(&iface->drv_addr, from, sizeof(iface->drv_addr));
+ os_memcpy(&iface->drv_addr, from, fromlen);
+ iface->drv_addr_len = fromlen;
iface->wpas_registered = 1;
if (iface->driver->set_param &&
@@ -123,18 +134,43 @@
static void wpa_priv_cmd_scan(struct wpa_priv_interface *iface,
- char *buf, size_t len)
+ void *buf, size_t len)
{
struct wpa_driver_scan_params params;
+ struct privsep_cmd_scan *scan;
+ unsigned int i;
+ int freqs[PRIVSEP_MAX_SCAN_FREQS + 1];
if (iface->drv_priv == NULL)
return;
+ if (len < sizeof(*scan)) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request");
+ return;
+ }
+
+ scan = buf;
+
os_memset(¶ms, 0, sizeof(params));
- if (len) {
- params.ssids[0].ssid = (u8 *) buf;
- params.ssids[0].ssid_len = len;
- params.num_ssids = 1;
+ if (scan->num_ssids > WPAS_MAX_SCAN_SSIDS) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request (num_ssids)");
+ return;
+ }
+ params.num_ssids = scan->num_ssids;
+ for (i = 0; i < scan->num_ssids; i++) {
+ params.ssids[i].ssid = scan->ssids[i];
+ params.ssids[i].ssid_len = scan->ssid_lens[i];
+ }
+
+ if (scan->num_freqs > PRIVSEP_MAX_SCAN_FREQS) {
+ wpa_printf(MSG_DEBUG, "Invalid scan request (num_freqs)");
+ return;
+ }
+ if (scan->num_freqs) {
+ for (i = 0; i < scan->num_freqs; i++)
+ freqs[i] = scan->freqs[i];
+ freqs[i] = 0;
+ params.freqs = freqs;
}
if (iface->driver->scan2)
@@ -143,7 +179,8 @@
static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
struct wpa_scan_results *res;
u8 *buf = NULL, *pos, *end;
@@ -165,7 +202,7 @@
for (i = 0; i < res->num; i++) {
struct wpa_scan_res *r = res->res[i];
- val = sizeof(*r) + r->ie_len;
+ val = sizeof(*r) + r->ie_len + r->beacon_ie_len;
if (end - pos < (int) sizeof(int) + val)
break;
os_memcpy(pos, &val, sizeof(int));
@@ -174,8 +211,7 @@
pos += val;
}
- sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from,
- sizeof(*from));
+ sendto(iface->fd, buf, pos - buf, 0, (struct sockaddr *) from, fromlen);
os_free(buf);
wpa_scan_results_free(res);
@@ -184,21 +220,21 @@
fail:
os_free(buf);
wpa_scan_results_free(res);
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
if (iface->drv_priv == NULL)
return;
if (iface->driver->get_scan_results2)
- wpa_priv_get_scan_results2(iface, from);
+ wpa_priv_get_scan_results2(iface, from, fromlen);
else
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from,
- sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
@@ -218,7 +254,7 @@
}
auth = buf;
- if (sizeof(*auth) + auth->ie_len + auth->sae_data_len > len) {
+ if (sizeof(*auth) + auth->ie_len + auth->auth_data_len > len) {
wpa_printf(MSG_DEBUG, "Authentication request overflow");
return;
}
@@ -244,9 +280,9 @@
params.ie = (u8 *) (auth + 1);
params.ie_len = auth->ie_len;
}
- if (auth->sae_data_len) {
- params.sae_data = ((u8 *) (auth + 1)) + auth->ie_len;
- params.sae_data_len = auth->sae_data_len;
+ if (auth->auth_data_len) {
+ params.auth_data = ((u8 *) (auth + 1)) + auth->ie_len;
+ params.auth_data_len = auth->auth_data_len;
}
res = iface->driver->authenticate(iface->drv_priv, ¶ms);
@@ -303,7 +339,7 @@
static void wpa_priv_cmd_get_bssid(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
u8 bssid[ETH_ALEN];
@@ -315,16 +351,16 @@
goto fail;
sendto(iface->fd, bssid, ETH_ALEN, 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_cmd_get_ssid(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
u8 ssid[sizeof(int) + SSID_MAX_LEN];
int res;
@@ -335,17 +371,18 @@
if (iface->driver->get_ssid == NULL)
goto fail;
+ os_memset(ssid, 0, sizeof(ssid));
res = iface->driver->get_ssid(iface->drv_priv, &ssid[sizeof(int)]);
if (res < 0 || res > SSID_MAX_LEN)
goto fail;
os_memcpy(ssid, &res, sizeof(int));
sendto(iface->fd, ssid, sizeof(ssid), 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
@@ -378,7 +415,7 @@
static void wpa_priv_cmd_get_capa(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from, socklen_t fromlen)
{
struct wpa_driver_capa capa;
@@ -394,18 +431,19 @@
capa.extended_capa_mask = NULL;
capa.extended_capa_len = 0;
sendto(iface->fd, &capa, sizeof(capa), 0, (struct sockaddr *) from,
- sizeof(*from));
+ fromlen);
return;
fail:
- sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
+ sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen);
}
static void wpa_priv_l2_rx(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
- struct wpa_priv_interface *iface = ctx;
+ struct wpa_priv_l2 *l2_ctx = ctx;
+ struct wpa_priv_interface *iface = l2_ctx->parent;
struct msghdr msg;
struct iovec io[2];
@@ -417,8 +455,8 @@
os_memset(&msg, 0, sizeof(msg));
msg.msg_iov = io;
msg.msg_iovlen = 2;
- msg.msg_name = &iface->l2_addr;
- msg.msg_namelen = sizeof(iface->l2_addr);
+ msg.msg_name = &iface->l2_addr[l2_ctx->idx];
+ msg.msg_namelen = iface->l2_addr_len[l2_ctx->idx];
if (sendmsg(iface->fd, &msg, 0) < 0) {
wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
@@ -426,14 +464,23 @@
}
+static int wpa_priv_allowed_l2_proto(u16 proto)
+{
+ return proto == ETH_P_EAPOL || proto == ETH_P_RSN_PREAUTH ||
+ proto == ETH_P_80211_ENCAP;
+}
+
+
static void wpa_priv_cmd_l2_register(struct wpa_priv_interface *iface,
struct sockaddr_un *from,
+ socklen_t fromlen,
void *buf, size_t len)
{
int *reg_cmd = buf;
u8 own_addr[ETH_ALEN];
int res;
u16 proto;
+ int idx;
if (len != 2 * sizeof(int)) {
wpa_printf(MSG_DEBUG, "Invalid l2_register length %lu",
@@ -442,50 +489,69 @@
}
proto = reg_cmd[0];
- if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH &&
- proto != ETH_P_80211_ENCAP) {
+ if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet connection for "
"ethertype 0x%x", proto);
return;
}
- if (iface->l2) {
- wpa_printf(MSG_DEBUG, "Cleaning up forgotten l2_packet "
- "instance");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (!iface->l2[idx])
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG, "No free l2_packet connection found");
+ return;
}
- os_memcpy(&iface->l2_addr, from, sizeof(iface->l2_addr));
+ os_memcpy(&iface->l2_addr[idx], from, fromlen);
+ iface->l2_addr_len[idx] = fromlen;
- iface->l2 = l2_packet_init(iface->ifname, NULL, proto,
- wpa_priv_l2_rx, iface, reg_cmd[1]);
- if (iface->l2 == NULL) {
+ iface->l2_ctx[idx].idx = idx;
+ iface->l2_ctx[idx].parent = iface;
+ iface->l2[idx] = l2_packet_init(iface->ifname, NULL, proto,
+ wpa_priv_l2_rx, &iface->l2_ctx[idx],
+ reg_cmd[1]);
+ if (!iface->l2[idx]) {
wpa_printf(MSG_DEBUG, "Failed to initialize l2_packet "
"instance for protocol %d", proto);
return;
}
- if (l2_packet_get_own_addr(iface->l2, own_addr) < 0) {
+ if (l2_packet_get_own_addr(iface->l2[idx], own_addr) < 0) {
wpa_printf(MSG_DEBUG, "Failed to get own address from "
"l2_packet");
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ l2_packet_deinit(iface->l2[idx]);
+ iface->l2[idx] = NULL;
return;
}
res = sendto(iface->fd, own_addr, ETH_ALEN, 0,
- (struct sockaddr *) from, sizeof(*from));
- wpa_printf(MSG_DEBUG, "L2 registration: res=%d", res);
+ (struct sockaddr *) from, fromlen);
+ wpa_printf(MSG_DEBUG, "L2 registration[idx=%d]: res=%d", idx, res);
}
static void wpa_priv_cmd_l2_unregister(struct wpa_priv_interface *iface,
- struct sockaddr_un *from)
+ struct sockaddr_un *from,
+ socklen_t fromlen)
{
- if (iface->l2) {
- l2_packet_deinit(iface->l2);
- iface->l2 = NULL;
+ int idx;
+
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2_addr_len[idx] == fromlen &&
+ os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG,
+ "No registered l2_packet socket found for unregister request");
+ return;
+ }
+
+ if (iface->l2[idx]) {
+ l2_packet_deinit(iface->l2[idx]);
+ iface->l2[idx] = NULL;
}
}
@@ -493,20 +559,36 @@
static void wpa_priv_cmd_l2_notify_auth_start(struct wpa_priv_interface *iface,
struct sockaddr_un *from)
{
- if (iface->l2)
- l2_packet_notify_auth_start(iface->l2);
+ int idx;
+
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2[idx])
+ l2_packet_notify_auth_start(iface->l2[idx]);
+ }
}
static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
- struct sockaddr_un *from,
+ struct sockaddr_un *from, socklen_t fromlen,
void *buf, size_t len)
{
u8 *dst_addr;
u16 proto;
int res;
+ int idx;
- if (iface->l2 == NULL)
+ for (idx = 0; idx < WPA_PRIV_MAX_L2; idx++) {
+ if (iface->l2_addr_len[idx] == fromlen &&
+ os_memcmp(&iface->l2_addr[idx], from, fromlen) == 0)
+ break;
+ }
+ if (idx == WPA_PRIV_MAX_L2) {
+ wpa_printf(MSG_DEBUG,
+ "No registered l2_packet socket found for send request");
+ return;
+ }
+
+ if (iface->l2[idx] == NULL)
return;
if (len < ETH_ALEN + 2) {
@@ -518,15 +600,15 @@
dst_addr = buf;
os_memcpy(&proto, buf + ETH_ALEN, 2);
- if (proto != ETH_P_EAPOL && proto != ETH_P_RSN_PREAUTH) {
+ if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
"0x%x", proto);
return;
}
- res = l2_packet_send(iface->l2, dst_addr, proto, buf + ETH_ALEN + 2,
- len - ETH_ALEN - 2);
- wpa_printf(MSG_DEBUG, "L2 send: res=%d", res);
+ res = l2_packet_send(iface->l2[idx], dst_addr, proto,
+ buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
@@ -571,7 +653,7 @@
switch (cmd) {
case PRIVSEP_CMD_REGISTER:
- wpa_priv_cmd_register(iface, &from);
+ wpa_priv_cmd_register(iface, &from, fromlen);
break;
case PRIVSEP_CMD_UNREGISTER:
wpa_priv_cmd_unregister(iface, &from);
@@ -580,34 +662,35 @@
wpa_priv_cmd_scan(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_SCAN_RESULTS:
- wpa_priv_cmd_get_scan_results(iface, &from);
+ wpa_priv_cmd_get_scan_results(iface, &from, fromlen);
break;
case PRIVSEP_CMD_ASSOCIATE:
wpa_priv_cmd_associate(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_BSSID:
- wpa_priv_cmd_get_bssid(iface, &from);
+ wpa_priv_cmd_get_bssid(iface, &from, fromlen);
break;
case PRIVSEP_CMD_GET_SSID:
- wpa_priv_cmd_get_ssid(iface, &from);
+ wpa_priv_cmd_get_ssid(iface, &from, fromlen);
break;
case PRIVSEP_CMD_SET_KEY:
wpa_priv_cmd_set_key(iface, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_GET_CAPA:
- wpa_priv_cmd_get_capa(iface, &from);
+ wpa_priv_cmd_get_capa(iface, &from, fromlen);
break;
case PRIVSEP_CMD_L2_REGISTER:
- wpa_priv_cmd_l2_register(iface, &from, cmd_buf, cmd_len);
+ wpa_priv_cmd_l2_register(iface, &from, fromlen,
+ cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_L2_UNREGISTER:
- wpa_priv_cmd_l2_unregister(iface, &from);
+ wpa_priv_cmd_l2_unregister(iface, &from, fromlen);
break;
case PRIVSEP_CMD_L2_NOTIFY_AUTH_START:
wpa_priv_cmd_l2_notify_auth_start(iface, &from);
break;
case PRIVSEP_CMD_L2_SEND:
- wpa_priv_cmd_l2_send(iface, &from, cmd_buf, cmd_len);
+ wpa_priv_cmd_l2_send(iface, &from, fromlen, cmd_buf, cmd_len);
break;
case PRIVSEP_CMD_SET_COUNTRY:
pos = cmd_buf;
@@ -625,8 +708,14 @@
static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
{
- if (iface->drv_priv && iface->driver->deinit)
- iface->driver->deinit(iface->drv_priv);
+ int i;
+
+ if (iface->drv_priv) {
+ if (iface->driver->deinit)
+ iface->driver->deinit(iface->drv_priv);
+ if (iface->drv_global_priv)
+ iface->driver->global_deinit(iface->drv_global_priv);
+ }
if (iface->fd >= 0) {
eloop_unregister_read_sock(iface->fd);
@@ -634,8 +723,10 @@
unlink(iface->sock_name);
}
- if (iface->l2)
- l2_packet_deinit(iface->l2);
+ for (i = 0; i < WPA_PRIV_MAX_L2; i++) {
+ if (iface->l2[i])
+ l2_packet_deinit(iface->l2[i]);
+ }
os_free(iface->ifname);
os_free(iface->driver_name);
@@ -777,7 +868,7 @@
msg.msg_iov = io;
msg.msg_iovlen = data ? 2 : 1;
msg.msg_name = &iface->drv_addr;
- msg.msg_namelen = sizeof(iface->drv_addr);
+ msg.msg_namelen = iface->drv_addr_len;
if (sendmsg(iface->fd, &msg, 0) < 0) {
wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
@@ -796,7 +887,7 @@
struct privsep_event_auth *auth;
u8 *buf, *pos;
- buf = os_malloc(buflen);
+ buf = os_zalloc(buflen);
if (buf == NULL)
return;
@@ -1061,7 +1152,7 @@
msg.msg_iov = io;
msg.msg_iovlen = 3;
msg.msg_name = &iface->drv_addr;
- msg.msg_namelen = sizeof(iface->drv_addr);
+ msg.msg_namelen = iface->drv_addr_len;
if (sendmsg(iface->fd, &msg, 0) < 0)
wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
@@ -1099,7 +1190,7 @@
static void usage(void)
{
printf("wpa_priv v" VERSION_STR "\n"
- "Copyright (c) 2007-2016, Jouni Malinen <j@w1.fi> and "
+ "Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and "
"contributors\n"
"\n"
"usage:\n"
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 51bb245..9aaedb3 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -62,7 +62,7 @@
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2017, 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"
@@ -192,7 +192,9 @@
{
struct wpa_supplicant *wpa_s = eloop_ctx;
const u8 *bssid = wpa_s->bssid;
- if (is_zero_ether_addr(bssid))
+ if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+ wpa_s->wpa_state == WPA_ASSOCIATING))
bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(bssid));
@@ -200,6 +202,7 @@
wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
+ wpas_notify_auth_timeout(wpa_s);
/*
* If we timed out, the AP or the local radio may be busy.
@@ -327,7 +330,12 @@
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
- ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#ifdef CONFIG_MACSEC
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
+ ieee802_1x_create_preshared_mka(wpa_s, ssid);
+ else
+ ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* CONFIG_MACSEC */
#endif /* IEEE8021X_EAPOL */
}
@@ -413,6 +421,19 @@
}
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
+{
+ struct fils_hlp_req *req;
+
+ while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
+ list)) != NULL) {
+ dl_list_del(&req->list);
+ wpabuf_free(req->pkt);
+ os_free(req);
+ }
+}
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@@ -432,6 +453,8 @@
#ifdef CONFIG_TESTING_OPTIONS
l2_packet_deinit(wpa_s->l2_test);
wpa_s->l2_test = NULL;
+ os_free(wpa_s->get_pref_freq_list_override);
+ wpa_s->get_pref_freq_list_override = NULL;
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
@@ -552,6 +575,8 @@
wpa_s->last_scan_res = NULL;
#ifdef CONFIG_HS20
+ if (wpa_s->drv_priv)
+ wpa_drv_configure_frame_filters(wpa_s, 0);
hs20_deinit(wpa_s);
#endif /* CONFIG_HS20 */
@@ -573,6 +598,31 @@
#endif /* CONFIG_MBO */
free_bss_tmp_disallowed(wpa_s);
+
+ wpabuf_free(wpa_s->lci);
+ wpa_s->lci = NULL;
+ wpas_clear_beacon_rep_data(wpa_s);
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+ {
+ struct external_pmksa_cache *entry;
+
+ while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
+ struct external_pmksa_cache,
+ list)) != NULL) {
+ dl_list_del(&entry->list);
+ os_free(entry->pmksa_cache);
+ os_free(entry);
+ }
+ }
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+ wpas_flush_fils_hlp_req(wpa_s);
+
+ wpabuf_free(wpa_s->ric_ies);
+ wpa_s->ric_ies = NULL;
}
@@ -1226,6 +1276,22 @@
wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT 802.1X with Suite B");
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_FILS
+#ifdef CONFIG_IEEE80211R
+ } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
+ } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
+#endif /* CONFIG_IEEE80211R */
+ } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
+ } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
+#endif /* CONFIG_FILS */
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1451,6 +1517,19 @@
break;
case 6: /* Bits 48-55 */
break;
+ case 7: /* Bits 56-63 */
+ break;
+ case 8: /* Bits 64-71 */
+ if (wpa_s->conf->ftm_responder)
+ *pos |= 0x40; /* Bit 70 - FTM responder */
+ if (wpa_s->conf->ftm_initiator)
+ *pos |= 0x80; /* Bit 71 - FTM initiator */
+ break;
+ case 9: /* Bits 72-79 */
+#ifdef CONFIG_FILS
+ *pos |= 0x01;
+#endif /* CONFIG_FILS */
+ break;
}
}
@@ -1458,7 +1537,7 @@
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 6, i;
+ u8 len = 10, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
@@ -1655,11 +1734,13 @@
wmm_ac_save_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 1;
}
- } else if (rand_style > 0) {
+ }
+
+ if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
if (wpas_update_random_addr(wpa_s, rand_style) < 0)
return;
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- } else if (wpa_s->mac_addr_changed) {
+ } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Could not restore permanent MAC address");
@@ -1678,6 +1759,13 @@
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
wpa_s->ibss_rsn = NULL;
+#else /* CONFIG_IBSS_RSN */
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "IBSS RSN not supported in the build");
+ return;
+ }
#endif /* CONFIG_IBSS_RSN */
if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
@@ -1748,6 +1836,13 @@
return;
}
+#ifdef CONFIG_SME
+ if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
+ /* Clear possibly set auth_alg, if any, from last attempt. */
+ wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
+ }
+#endif /* CONFIG_SME */
+
wpas_abort_ongoing_scan(wpa_s);
cwork = os_zalloc(sizeof(*cwork));
@@ -1779,11 +1874,6 @@
u8 channel;
int i;
-#ifdef CONFIG_HT_OVERRIDES
- if (ssid->disable_ht)
- return 0;
-#endif /* CONFIG_HT_OVERRIDES */
-
hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
if (hw_mode == NUM_HOSTAPD_MODES)
return 0;
@@ -1868,6 +1958,13 @@
if (!mode)
return;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht) {
+ freq->ht_enabled = 0;
+ return;
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
freq->ht_enabled = ht_supported(mode);
if (!freq->ht_enabled)
return;
@@ -1889,6 +1986,11 @@
if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
return;
+#ifdef CONFIG_HT_OVERRIDES
+ if (ssid->disable_ht40)
+ return;
+#endif /* CONFIG_HT_OVERRIDES */
+
/* Check/setup HT40+/HT40- */
for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
if (ht40plus[j] == channel) {
@@ -1913,22 +2015,16 @@
freq->channel = pri_chan->chan;
- switch (ht40) {
- case -1:
+ if (ht40 == -1) {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
return;
- freq->sec_channel_offset = -1;
- break;
- case 1:
+ } else {
if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
return;
- freq->sec_channel_offset = 1;
- break;
- default:
- break;
}
+ freq->sec_channel_offset = ht40;
- if (freq->sec_channel_offset && obss_scan) {
+ if (obss_scan) {
struct wpa_scan_results *scan_res;
scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
@@ -1976,6 +2072,13 @@
vht_freq = *freq;
+#ifdef CONFIG_VHT_OVERRIDES
+ if (ssid->disable_vht) {
+ freq->vht_enabled = 0;
+ return;
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
vht_freq.vht_enabled = vht_supported(mode);
if (!vht_freq.vht_enabled)
return;
@@ -2034,6 +2137,16 @@
if (chwidth == VHT_CHANWIDTH_80P80MHZ)
break;
}
+ } else if (ssid->max_oper_chwidth == VHT_CHANWIDTH_160MHZ) {
+ if (freq->freq == 5180) {
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ seg0 = 50;
+ } else if (freq->freq == 5520) {
+ chwidth = VHT_CHANWIDTH_160MHZ;
+ vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ seg0 = 114;
+ }
}
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
@@ -2074,9 +2187,6 @@
struct ieee80211_vht_capabilities vhtcaps;
struct ieee80211_vht_capabilities vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
-#ifdef CONFIG_MBO
- const u8 *mbo = NULL;
-#endif /* CONFIG_MBO */
if (deinit) {
if (work->started) {
@@ -2141,7 +2251,10 @@
} else {
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+ if (bss)
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ else
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
}
if (!wpa_s->pno)
wpa_supplicant_cancel_sched_scan(wpa_s);
@@ -2262,21 +2375,12 @@
os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
#endif /* CONFIG_P2P */
-#ifdef CONFIG_MBO
if (bss) {
- mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
- if (mbo) {
- int len;
-
- len = wpas_mbo_supp_op_class_ie(wpa_s, bss->freq,
- wpa_ie + wpa_ie_len,
- sizeof(wpa_ie) -
- wpa_ie_len);
- if (len > 0)
- wpa_ie_len += len;
- }
+ wpa_ie_len += wpas_supp_op_class_ie(wpa_s, bss->freq,
+ wpa_ie + wpa_ie_len,
+ sizeof(wpa_ie) -
+ wpa_ie_len);
}
-#endif /* CONFIG_MBO */
/*
* Workaround: Add Extended Capabilities element only if the AP
@@ -2286,6 +2390,11 @@
* element in all cases, it is justifiable to skip it to avoid
* interoperability issues.
*/
+ if (ssid->p2p_group)
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
+ else
+ wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
+
if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
u8 ext_capab[18];
int ext_capab_len;
@@ -2319,6 +2428,8 @@
wpa_ie_len += wpabuf_len(hs20);
}
wpabuf_free(hs20);
+
+ hs20_configure_frame_filters(wpa_s);
}
}
#endif /* CONFIG_HS20 */
@@ -2348,7 +2459,7 @@
#endif /* CONFIG_FST */
#ifdef CONFIG_MBO
- if (mbo) {
+ if (bss && wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) {
int len;
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
@@ -2399,12 +2510,14 @@
if (bss) {
params.ssid = bss->ssid;
params.ssid_len = bss->ssid_len;
- if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+ if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
MACSTR " freq=%u MHz based on scan results "
- "(bssid_set=%d)",
+ "(bssid_set=%d wps=%d)",
MAC2STR(bss->bssid), bss->freq,
- ssid->bssid_set);
+ ssid->bssid_set,
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
params.bssid = bss->bssid;
params.freq.freq = bss->freq;
}
@@ -2414,7 +2527,7 @@
} else {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
- params.pbss = ssid->pbss;
+ params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
}
if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
@@ -2611,8 +2724,14 @@
}
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
- if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set)
+
+ if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
wpa_s->current_bss = bss;
+#ifdef CONFIG_HS20
+ hs20_configure_frame_filters(wpa_s);
+#endif /* CONFIG_HS20 */
+ }
+
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
@@ -2657,12 +2776,12 @@
MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
- if (!is_zero_ether_addr(wpa_s->bssid))
- addr = wpa_s->bssid;
- else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
- (wpa_s->wpa_state == WPA_AUTHENTICATING ||
- wpa_s->wpa_state == WPA_ASSOCIATING))
+ if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+ wpa_s->wpa_state == WPA_ASSOCIATING))
addr = wpa_s->pending_bssid;
+ else if (!is_zero_ether_addr(wpa_s->bssid))
+ addr = wpa_s->bssid;
else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
/*
* When using driver-based BSS selection, we may not know the
@@ -2717,6 +2836,95 @@
wpa_s->reassociate = 1;
}
+/**
+ * wpa_supplicant_add_network - Add a new network.
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: The new network configuration or %NULL if operation failed
+ *
+ * This function performs the following operations:
+ * 1. Adds a new network.
+ * 2. Send network addition notification.
+ * 3. Marks the network disabled.
+ * 4. Set network default parameters.
+ */
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (!ssid) {
+ return NULL;
+ }
+ wpas_notify_network_added(wpa_s, ssid);
+ ssid->disabled = 1;
+ wpa_config_set_network_defaults(ssid);
+
+ return ssid;
+}
+
+/**
+ * wpa_supplicant_remove_network - Remove a configured network based on id
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found, -2 if the network
+ * could not be removed
+ *
+ * This function performs the following operations:
+ * 1. Removes the network.
+ * 2. Send network removal notification.
+ * 3. Update internal state machines.
+ * 4. Stop any running sched scans.
+ */
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
+{
+ struct wpa_ssid *ssid;
+ int was_disabled;
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid)
+ wpas_notify_network_removed(wpa_s, ssid);
+ if (ssid == NULL) {
+ return -1;
+ }
+
+ if (wpa_s->last_ssid == ssid)
+ wpa_s->last_ssid = NULL;
+
+ if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ /*
+ * Invalidate the EAP session cache if the current or
+ * previously used network is removed.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+
+ if (ssid == wpa_s->current_ssid) {
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+ wpa_s->own_disconnect_req = 1;
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
+
+ was_disabled = ssid->disabled;
+
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ return -2;
+ }
+
+ if (!was_disabled && wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
+ "network from filters");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+ return 0;
+}
/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
@@ -2878,6 +3086,7 @@
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
wpa_s->scan_req = NORMAL_SCAN_REQ;
+ wpas_scan_reset_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
}
@@ -3238,6 +3447,13 @@
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ignore_auth_resp) {
+ wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
+ return;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_PEERKEY
if (wpa_s->wpa_state > WPA_ASSOCIATED && wpa_s->current_ssid &&
wpa_s->current_ssid->peerkey &&
@@ -3526,6 +3742,7 @@
wpa_s->sched_scanning = 0;
dl_list_init(&wpa_s->bss_tmp_disallowed);
+ dl_list_init(&wpa_s->fils_hlp_req);
return wpa_s;
}
@@ -3553,8 +3770,11 @@
wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ long v;
+
errno = 0;
- long v = strtol(tmp, &end, 16);
+ v = strtol(tmp, &end, 16);
+
if (errno == 0) {
wpa_msg(wpa_s, MSG_DEBUG,
"htcap value[%i]: %ld end: %p tmp: %p",
@@ -3664,18 +3884,10 @@
struct ieee80211_ht_capabilities *htcaps_mask,
int disabled)
{
- /* Masking these out disables HT40 */
- le16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
- HT_CAP_INFO_SHORT_GI40MHZ);
-
wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
- if (disabled)
- htcaps->ht_capabilities_info &= ~msk;
- else
- htcaps->ht_capabilities_info |= msk;
-
- htcaps_mask->ht_capabilities_info |= msk;
+ set_disable_ht40(htcaps, disabled);
+ set_disable_ht40(htcaps_mask, 0);
return 0;
}
@@ -3778,8 +3990,8 @@
if (!vhtcaps || !vhtcaps_mask)
return;
- vhtcaps->vht_capabilities_info = ssid->vht_capa;
- vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+ vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
+ vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
#ifdef CONFIG_HT_OVERRIDES
/* if max ampdu is <= 3, we have to make the HT cap the same */
@@ -3801,15 +4013,17 @@
#define OVERRIDE_MCS(i) \
if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
- 3 << 2 * (i - 1); \
+ host_to_le16(3 << 2 * (i - 1)); \
vhtcaps->vht_supported_mcs_set.tx_map |= \
- ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \
+ host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \
+ 2 * (i - 1)); \
} \
if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \
vhtcaps_mask->vht_supported_mcs_set.rx_map |= \
- 3 << 2 * (i - 1); \
+ host_to_le16(3 << 2 * (i - 1)); \
vhtcaps->vht_supported_mcs_set.rx_map |= \
- ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \
+ host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \
+ 2 * (i - 1)); \
}
OVERRIDE_MCS(1);
@@ -3949,10 +4163,14 @@
{
struct wpa_supplicant *wpa_s = ctx;
- WPA_ASSERT(os_memcmp(wpa_s->bssid, da, ETH_ALEN) == 0);
+ if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
+ wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
+ __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
+ return -1;
+ }
return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->bssid,
- wpabuf_head(data), wpabuf_len(data),
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(data), wpabuf_len(data),
0);
}
@@ -3981,8 +4199,9 @@
}
-const u8 * wpas_fst_get_peer_first(void *ctx, struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+static const u8 * wpas_fst_get_peer_first(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -3994,8 +4213,9 @@
}
-const u8 * wpas_fst_get_peer_next(void *ctx, struct fst_get_peer_ctx **get_ctx,
- Boolean mb_only)
+static const u8 * wpas_fst_get_peer_next(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
{
return NULL;
}
@@ -4148,6 +4368,20 @@
}
+static int radio_work_is_connect(struct wpa_radio_work *work)
+{
+ return os_strcmp(work->type, "sme-connect") == 0 ||
+ os_strcmp(work->type, "connect") == 0;
+}
+
+
+static int radio_work_is_scan(struct wpa_radio_work *work)
+{
+ return os_strcmp(work->type, "scan") == 0 ||
+ os_strcmp(work->type, "p2p-scan") == 0;
+}
+
+
static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
{
struct wpa_radio_work *active_work = NULL;
@@ -4177,8 +4411,7 @@
return NULL;
}
- if (os_strcmp(active_work->type, "sme-connect") == 0 ||
- os_strcmp(active_work->type, "connect") == 0) {
+ if (radio_work_is_connect(active_work)) {
/*
* If the active work is either connect or sme-connect,
* do not parallelize them with other radio works.
@@ -4197,10 +4430,20 @@
* If connect or sme-connect are enqueued, parallelize only
* those operations ahead of them in the queue.
*/
- if (os_strcmp(tmp->type, "connect") == 0 ||
- os_strcmp(tmp->type, "sme-connect") == 0)
+ if (radio_work_is_connect(tmp))
break;
+ /* Serialize parallel scan and p2p_scan operations on the same
+ * interface since the driver_nl80211 mechanism for tracking
+ * scan cookies does not yet have support for this. */
+ if (active_work->wpa_s == tmp->wpa_s &&
+ radio_work_is_scan(active_work) &&
+ radio_work_is_scan(tmp)) {
+ wpa_dbg(active_work->wpa_s, MSG_DEBUG,
+ "Do not start work '%s' when another work '%s' is already scheduled",
+ tmp->type, active_work->type);
+ continue;
+ }
/*
* Check that the radio works are distinct and
* on different bands.
@@ -4796,6 +5039,12 @@
if (wpa_bss_init(wpa_s) < 0)
return -1;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+ dl_list_init(&wpa_s->mesh_external_pmksa_cache);
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
/*
* Set Wake-on-WLAN triggers, if configured.
* Note: We don't restore/remove the triggers on shutdown (it doesn't
@@ -4836,6 +5085,8 @@
wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
#endif /* CONFIG_MBO */
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+
return 0;
}
@@ -5043,13 +5294,15 @@
return NULL;
}
- if (iface->p2p_mgmt == 0) {
- /* Notify the control interfaces about new iface */
- if (wpas_notify_iface_added(wpa_s)) {
- wpa_supplicant_deinit_iface(wpa_s, 1, 0);
- return NULL;
- }
+ /* Notify the control interfaces about new iface */
+ if (wpas_notify_iface_added(wpa_s)) {
+ wpa_supplicant_deinit_iface(wpa_s, 1, 0);
+ return NULL;
+ }
+ /* Notify the control interfaces about new networks for non p2p mgmt
+ * ifaces. */
+ if (iface->p2p_mgmt == 0) {
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
wpas_notify_network_added(wpa_s, ssid);
}
@@ -5095,6 +5348,7 @@
#ifdef CONFIG_MESH
unsigned int mesh_if_created = wpa_s->mesh_if_created;
char *ifname = NULL;
+ struct wpa_supplicant *parent = wpa_s->parent;
#endif /* CONFIG_MESH */
/* Remove interface from the global list of interfaces */
@@ -5130,7 +5384,7 @@
#ifdef CONFIG_MESH
if (mesh_if_created) {
- wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+ wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
os_free(ifname);
}
#endif /* CONFIG_MESH */
@@ -5660,20 +5914,36 @@
}
-#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW) || defined (CONFIG_CTRL_IFACE_HIDL)
int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const char *field,
const char *value)
{
#ifdef IEEE8021X_EAPOL
- struct eap_peer_config *eap = &ssid->eap;
+ enum wpa_ctrl_req_type rtype;
wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
(const u8 *) value, os_strlen(value));
- switch (wpa_supplicant_ctrl_req_from_string(field)) {
+ rtype = wpa_supplicant_ctrl_req_from_string(field);
+ return wpa_supplicant_ctrl_rsp_handle(wpa_s, ssid, rtype, value);
+#else /* IEEE8021X_EAPOL */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+ return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+
+int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype,
+ const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+ struct eap_peer_config *eap = &ssid->eap;
+
+ switch (rtype) {
case WPA_CTRL_REQ_EAP_IDENTITY:
os_free(eap->identity);
eap->identity = (u8 *) os_strdup(value);
@@ -5723,6 +5993,7 @@
case WPA_CTRL_REQ_SIM:
str_clear_free(eap->external_sim_resp);
eap->external_sim_resp = os_strdup(value);
+ eap->pending_req_sim = 0;
break;
case WPA_CTRL_REQ_PSK_PASSPHRASE:
if (wpa_config_set(ssid, "psk", value, 0) < 0)
@@ -5744,7 +6015,7 @@
return -1;
break;
default:
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown type %d", rtype);
return -1;
}
@@ -5754,7 +6025,7 @@
return -1;
#endif /* IEEE8021X_EAPOL */
}
-#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW || CONFIG_CTRL_IFACE_HIDL */
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
@@ -5812,6 +6083,19 @@
return NO_MGMT_FRAME_PROTECTION;
}
+ if (ssid &&
+ (ssid->key_mgmt &
+ ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
+ WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
+ /*
+ * Do not use the default PMF value for non-RSN networks
+ * since PMF is available only with RSN and pmf=2
+ * configuration would otherwise prevent connections to
+ * all open networks.
+ */
+ return NO_MGMT_FRAME_PROTECTION;
+ }
+
return wpa_s->conf->pmf;
}
@@ -5969,6 +6253,26 @@
wpa_s->reattach = 0;
}
+/**
+ * wpas_request_disconnection - Request disconnection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request disconnection from the currently connected
+ * network. This will stop any ongoing scans and initiate deauthentication.
+ */
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_s->reassociate = 0;
+ wpa_s->disconnected = 1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
+}
+
void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
struct wpa_used_freq_data *freqs_data,
@@ -6067,271 +6371,6 @@
}
-static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
-{
- struct rrm_data *rrm = data;
-
- if (!rrm->notify_neighbor_rep) {
- wpa_printf(MSG_ERROR,
- "RRM: Unexpected neighbor report timeout");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
- rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
-
- rrm->notify_neighbor_rep = NULL;
- rrm->neighbor_rep_cb_ctx = NULL;
-}
-
-
-/*
- * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
- * @wpa_s: Pointer to wpa_supplicant
- */
-void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
-{
- wpa_s->rrm.rrm_used = 0;
-
- eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
- NULL);
- if (wpa_s->rrm.notify_neighbor_rep)
- wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
- wpa_s->rrm.next_neighbor_rep_token = 1;
-}
-
-
-/*
- * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
- * @wpa_s: Pointer to wpa_supplicant
- * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
- * @report_len: Length of neighbor report buffer
- */
-void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
- const u8 *report, size_t report_len)
-{
- struct wpabuf *neighbor_rep;
-
- wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
- if (report_len < 1)
- return;
-
- if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
- wpa_printf(MSG_DEBUG,
- "RRM: Discarding neighbor report with token %d (expected %d)",
- report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
- return;
- }
-
- eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
- NULL);
-
- if (!wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
- return;
- }
-
- /* skipping the first byte, which is only an id (dialog token) */
- neighbor_rep = wpabuf_alloc(report_len - 1);
- if (neighbor_rep == NULL)
- return;
- wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
- wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
- report[0]);
- wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
- neighbor_rep);
- wpa_s->rrm.notify_neighbor_rep = NULL;
- wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
-}
-
-
-#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
-/* Workaround different, undefined for Windows, error codes used here */
-#define ENOTCONN -1
-#define EOPNOTSUPP -1
-#define ECANCELED -1
-#endif
-
-/**
- * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
- * @wpa_s: Pointer to wpa_supplicant
- * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
- * is sent in the request.
- * @cb: Callback function to be called once the requested report arrives, or
- * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
- * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
- * the requester's responsibility to free it.
- * In the latter case NULL will be sent in 'neighbor_rep'.
- * @cb_ctx: Context value to send the callback function
- * Returns: 0 in case of success, negative error code otherwise
- *
- * In case there is a previous request which has not been answered yet, the
- * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
- * Request must contain a callback function.
- */
-int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
- void (*cb)(void *ctx,
- struct wpabuf *neighbor_rep),
- void *cb_ctx)
-{
- struct wpabuf *buf;
- const u8 *rrm_ie;
-
- if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
- wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
- return -ENOTCONN;
- }
-
- if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
- return -EOPNOTSUPP;
- }
-
- rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
- WLAN_EID_RRM_ENABLED_CAPABILITIES);
- if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
- !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
- wpa_printf(MSG_DEBUG,
- "RRM: No network support for Neighbor Report.");
- return -EOPNOTSUPP;
- }
-
- if (!cb) {
- wpa_printf(MSG_DEBUG,
- "RRM: Neighbor Report request must provide a callback.");
- return -EINVAL;
- }
-
- /* Refuse if there's a live request */
- if (wpa_s->rrm.notify_neighbor_rep) {
- wpa_printf(MSG_DEBUG,
- "RRM: Currently handling previous Neighbor Report.");
- return -EBUSY;
- }
-
- /* 3 = action category + action code + dialog token */
- buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
- if (buf == NULL) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to allocate Neighbor Report Request");
- return -ENOMEM;
- }
-
- wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
- (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
- wpa_s->rrm.next_neighbor_rep_token);
-
- wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
- wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
- wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
- if (ssid) {
- wpabuf_put_u8(buf, WLAN_EID_SSID);
- wpabuf_put_u8(buf, ssid->ssid_len);
- wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
- }
-
- wpa_s->rrm.next_neighbor_rep_token++;
-
- if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->bssid,
- wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "RRM: Failed to send Neighbor Report Request");
- wpabuf_free(buf);
- return -ECANCELED;
- }
-
- wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
- wpa_s->rrm.notify_neighbor_rep = cb;
- eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
- wpas_rrm_neighbor_rep_timeout_handler,
- &wpa_s->rrm, NULL);
-
- wpabuf_free(buf);
- return 0;
-}
-
-
-void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
- const u8 *src,
- const u8 *frame, size_t len,
- int rssi)
-{
- struct wpabuf *buf;
- const struct rrm_link_measurement_request *req;
- struct rrm_link_measurement_report report;
-
- if (wpa_s->wpa_state != WPA_COMPLETED) {
- wpa_printf(MSG_INFO,
- "RRM: Ignoring link measurement request. Not associated");
- return;
- }
-
- if (!wpa_s->rrm.rrm_used) {
- wpa_printf(MSG_INFO,
- "RRM: Ignoring link measurement request. Not RRM network");
- return;
- }
-
- if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
- wpa_printf(MSG_INFO,
- "RRM: Measurement report failed. TX power insertion not supported");
- return;
- }
-
- req = (const struct rrm_link_measurement_request *) frame;
- if (len < sizeof(*req)) {
- wpa_printf(MSG_INFO,
- "RRM: Link measurement report failed. Request too short");
- return;
- }
-
- os_memset(&report, 0, sizeof(report));
- report.tpc.eid = WLAN_EID_TPC_REPORT;
- report.tpc.len = 2;
- report.rsni = 255; /* 255 indicates that RSNI is not available */
- report.dialog_token = req->dialog_token;
-
- /*
- * It's possible to estimate RCPI based on RSSI in dBm. This
- * calculation will not reflect the correct value for high rates,
- * but it's good enough for Action frames which are transmitted
- * with up to 24 Mbps rates.
- */
- if (!rssi)
- report.rcpi = 255; /* not available */
- else if (rssi < -110)
- report.rcpi = 0;
- else if (rssi > 0)
- report.rcpi = 220;
- else
- report.rcpi = (rssi + 110) * 2;
-
- /* action_category + action_code */
- buf = wpabuf_alloc(2 + sizeof(report));
- if (buf == NULL) {
- wpa_printf(MSG_ERROR,
- "RRM: Link measurement report failed. Buffer allocation failed");
- return;
- }
-
- wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
- wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
- wpabuf_put_data(buf, &report, sizeof(report));
- wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
- wpabuf_head(buf), wpabuf_len(buf));
-
- if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
- wpa_s->own_addr, wpa_s->bssid,
- wpabuf_head(buf), wpabuf_len(buf), 0)) {
- wpa_printf(MSG_ERROR,
- "RRM: Link measurement report failed. Send action failed");
- }
- wpabuf_free(buf);
-}
-
-
struct wpa_supplicant *
wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
{
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index e55b380..6faa7af 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -98,9 +98,7 @@
# parameters (e.g., WPA IE generation); this mode can also be used with
# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
# APs (i.e., external program needs to control association). This mode must
-# also be used when using wired Ethernet drivers.
-# Note: macsec_qca driver is one type of Ethernet driver which implements
-# macsec feature.
+# also be used when using wired Ethernet drivers (including MACsec).
# 2: like 0, but associate with APs using security policy and SSID (but not
# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
@@ -168,10 +166,13 @@
fast_reauth=1
# OpenSSL Engine support
-# These options can be used to load OpenSSL engines.
+# These options can be used to load OpenSSL engines in special or legacy
+# modes.
# The two engines that are supported currently are shown below:
# They are both from the opensc project (http://www.opensc.org/)
-# By default no engines are loaded.
+# By default the PKCS#11 engine is loaded if the client_cert or
+# private_key option appear to be a PKCS#11 URI, and these options
+# should not need to be used explicitly.
# make the opensc engine available
#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
# make the pkcs11 engine available
@@ -197,7 +198,7 @@
#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
# Driver interface parameters
-# This field can be used to configure arbitrary driver interace parameters. The
+# This field can be used to configure arbitrary driver interface parameters. The
# format is specific to the selected driver interface. This field is not used
# in most cases.
#driver_param="field=value"
@@ -360,10 +361,12 @@
# Protected Management Frames default
# This parameter can be used to set the default behavior for the ieee80211w
-# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2
-# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF
-# is enabled/required by default, but can be disabled with the per-network
-# ieee80211w parameter.
+# parameter for RSN networks. By default, PMF is disabled unless enabled with
+# the global pmf=1/2 parameter or with the per-network ieee80211w=1/2 parameter.
+# With pmf=1/2, PMF is enabled/required by default, but can be disabled with the
+# per-network ieee80211w parameter. This global default value does not apply
+# for non-RSN networks (key_mgmt=NONE) since PMF is available only when using
+# RSN.
#pmf=0
# Enabled SAE finite cyclic groups in preference order
@@ -419,6 +422,15 @@
# 2 = like 1, but maintain OUI (with local admin bit set)
#preassoc_mac_addr=0
+# MAC address policy for GAS operations
+# 0 = use permanent MAC address
+# 1 = use random MAC address
+# 2 = like 1, but maintain OUI (with local admin bit set)
+#gas_rand_mac_addr=0
+
+# Lifetime of GAS random MAC address in seconds (default: 60)
+#gas_rand_addr_lifetime=60
+
# Interworking (IEEE 802.11u)
# Enable Interworking
@@ -438,6 +450,28 @@
# matching network block
#auto_interworking=0
+# GAS Address3 field behavior
+# 0 = P2P specification (Address3 = AP BSSID); default
+# 1 = IEEE 802.11 standard compliant (Address3 = Wildcard BSSID when
+# sent to not-associated AP; if associated, AP BSSID)
+#gas_address3=0
+
+# Publish fine timing measurement (FTM) responder functionality in
+# the Extended Capabilities element bit 70.
+# Controls whether FTM responder functionality will be published by AP/STA.
+# Note that actual FTM responder operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_responder=0
+
+# Publish fine timing measurement (FTM) initiator functionality in
+# the Extended Capabilities element bit 71.
+# Controls whether FTM initiator functionality will be published by AP/STA.
+# Note that actual FTM initiator operation is managed outside wpa_supplicant.
+# 0 = Do not publish; default
+# 1 = Publish
+#ftm_initiator=0
+
# credential block
#
# Each credential used for automatic network selection is configured as a set
@@ -472,6 +506,10 @@
# (EAP-TLS). Full path to the file should be used since working
# directory may change when wpa_supplicant is run in the background.
#
+# Certificates from PKCS#11 tokens can be referenced by a PKCS#11 URI.
+#
+# For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
# Alternatively, a named configuration blob can be used by setting
# this to blob://blob_name.
#
@@ -482,6 +520,9 @@
# used since working directory may change when wpa_supplicant is run
# in the background.
#
+# Keys in PKCS#11 tokens can be referenced by a PKCS#11 URI.
+# For example: private_key="pkcs11:manufacturer=piv_II;id=%01"
+#
# Windows certificate store can be used by leaving client_cert out and
# configuring private_key in one of the following formats:
#
@@ -643,11 +684,11 @@
# Multi Band Operation (MBO) non-preferred channels
# A space delimited list of non-preferred channels where each channel is a colon
-# delimited list of values. Reason detail is optional.
+# delimited list of values.
# Format:
-# non_pref_chan=<oper_class>:<chan>:<preference>:<reason>[:reason_detail]
+# non_pref_chan=<oper_class>:<chan>:<preference>:<reason>
# Example:
-# non_pref_chan="81:5:10:2:0 81:1:0:2:0 81:9:0:2"
+# non_pref_chan="81:5:10:2 81:1:0:2 81:9:0:2"
# MBO Cellular Data Capabilities
# 1 = Cellular data connection available
@@ -717,10 +758,14 @@
# the network will be used instead of this configured value.
#
# pbss: Whether to use PBSS. Relevant to IEEE 802.11ad networks only.
+# 0 = do not use PBSS
+# 1 = use PBSS
+# 2 = don't care (not allowed in AP mode)
# Used together with mode configuration. When mode is AP, it means to start a
# PCP instead of a regular AP. When mode is infrastructure it means connect
-# to a PCP instead of AP. P2P_GO and P2P_GROUP_FORMATION modes must use PBSS
-# in IEEE 802.11ad network.
+# to a PCP instead of AP. In this mode you can also specify 2 (don't care)
+# which means connect to either PCP or AP.
+# P2P_GO and P2P_GROUP_FORMATION modes must use PBSS in IEEE 802.11ad network.
# For more details, see IEEE Std 802.11ad-2012.
#
# scan_freq: List of frequencies to scan
@@ -784,6 +829,10 @@
# WPA-EAP-SUITE-B = Suite B 128-bit level
# WPA-EAP-SUITE-B-192 = Suite B 192-bit level
# OSEN = Hotspot 2.0 Rel 2 online signup connection
+# FILS-SHA256 = Fast Initial Link Setup with SHA256
+# FILS-SHA384 = Fast Initial Link Setup with SHA384
+# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
+# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
# If not set, this defaults to: WPA-PSK WPA-EAP
#
# ieee80211w: whether management frame protection is enabled
@@ -839,17 +888,38 @@
# bit0 (1): require dynamically generated unicast WEP key
# bit1 (2): require dynamically generated broadcast WEP key
# (3 = require both keys; default)
-# Note: When using wired authentication (including macsec_qca driver),
+# Note: When using wired authentication (including MACsec drivers),
# eapol_flags must be set to 0 for the authentication to be completed
# successfully.
#
# macsec_policy: IEEE 802.1X/MACsec options
-# This determines how sessions are secured with MACsec. It is currently
-# applicable only when using the macsec_qca driver interface.
+# This determines how sessions are secured with MACsec (only for MACsec
+# drivers).
# 0: MACsec not in use (default)
# 1: MACsec enabled - Should secure, accept key server's advice to
# determine whether to use a secure session or not.
#
+# macsec_integ_only: IEEE 802.1X/MACsec transmit mode
+# This setting applies only when MACsec is in use, i.e.,
+# - macsec_policy is enabled
+# - the key server has decided to enable MACsec
+# 0: Encrypt traffic (default)
+# 1: Integrity only
+#
+# macsec_port: IEEE 802.1X/MACsec port
+# Port component of the SCI
+# Range: 1-65534 (default: 1)
+#
+# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
+# 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_priority (Priority of MKA Actor) is in 0..255 range with 255 being
+# default priority
+#
# mixed_cell: This option can be used to configure whether so called mixed
# cells, i.e., networks that use both plaintext and encryption in the same
# SSID, are allowed when selecting a BSS from scan results.
@@ -874,9 +944,13 @@
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
+# group_rekey: Group rekeying time in seconds. This value, if non-zero, is used
+# as the dot11RSNAConfigGroupRekeyTime parameter when operating in
+# Authenticator role in IBSS, or in AP and mesh modes.
+#
# Following fields are only used with internal EAP implementation.
# eap: space-separated list of accepted EAP methods
-# MD5 = EAP-MD5 (unsecure and does not generate keying material ->
+# MD5 = EAP-MD5 (insecure and does not generate keying material ->
# cannot be used with WPA; to be used as a Phase 2 method
# with EAP-PEAP or EAP-TTLS)
# MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used
@@ -967,23 +1041,23 @@
# automatically converted into DH params.
# subject_match: Substring to be matched against the subject of the
# authentication server certificate. If this string is set, the server
-# sertificate is only accepted if it contains this string in the subject.
+# certificate is only accepted if it contains this string in the subject.
# The subject string is in following format:
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
-# Note: Since this is a substring match, this cannot be used securily to
+# Note: Since this is a substring match, this cannot be used securely to
# do a suffix match against a possible domain name in the CN entry. For
# such a use case, domain_suffix_match or domain_match should be used
# instead.
# altsubject_match: Semicolon separated string of entries to be matched against
# the alternative subject name of the authentication server certificate.
-# If this string is set, the server sertificate is only accepted if it
+# If this string is set, the server certificate is only accepted if it
# contains one of the entries in an alternative subject name extension.
# altSubjectName string is in following format: TYPE:VALUE
# Example: EMAIL:server@example.com
# Example: DNS:server.example.com;DNS:server2.example.com
# Following types are supported: EMAIL, DNS, URI
# domain_suffix_match: Constraint for server domain name. If set, this FQDN is
-# used as a suffix match requirement for the AAAserver certificate in
+# used as a suffix match requirement for the AAA server certificate in
# SubjectAltName dNSName element(s). If a matching dNSName is found, this
# constraint is met. If no dNSName values are present, this constraint is
# matched against SubjectName CN using same suffix match comparison.
@@ -1169,6 +1243,11 @@
# Beacon interval (default: 100 TU)
#beacon_int=100
+# WPS in AP mode
+# 0 = WPS enabled and configured (default)
+# 1 = WPS disabled
+#wps_disabled=0
+
# MAC address policy
# 0 = use permanent MAC address
# 1 = use random MAC address for each ESS connection
@@ -1231,13 +1310,13 @@
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
-# option CONFIG_FST is set while compiling hostapd. They allow this interface
-# to be a part of FST setup.
+# option CONFIG_FST is set while compiling wpa_supplicant. They allow this
+# interface to be a part of FST setup.
#
# FST is the transfer of a session from a channel to another channel, in the
# same or different frequency bands.
#
-# For detals, see IEEE Std 802.11ad-2012.
+# For details, see IEEE Std 802.11ad-2012.
# Identifier of an FST Group the interface belongs to.
#fst_group_id=bond0
@@ -1570,22 +1649,10 @@
group=CCMP TKIP
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
- client_cert="/etc/cert/user.pem"
- engine=1
-
- # The engine configured here must be available. Look at
- # OpenSSL engine support in the global section.
- # The key available through the engine must be the private key
- # matching the client certificate configured above.
-
- # use the opensc engine
- #engine_id="opensc"
- #key_id="45"
-
- # use the pkcs11 engine
- engine_id="pkcs11"
- key_id="id_45"
+ # Certificate and/or key identified by PKCS#11 URI (RFC7512)
+ client_cert="pkcs11:manufacturer=piv_II;id=%01"
+ private_key="pkcs11:manufacturer=piv_II;id=%01"
# Optional PIN configuration; this can be left out and PIN will be
# asked through the control interface
diff --git a/wpa_supplicant/wpa_supplicant_conf.mk b/wpa_supplicant/wpa_supplicant_conf.mk
index 74986ea..4293976 100644
--- a/wpa_supplicant/wpa_supplicant_conf.mk
+++ b/wpa_supplicant/wpa_supplicant_conf.mk
@@ -16,7 +16,7 @@
LOCAL_MODULE := wpa_supplicant.conf
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/wifi
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/wifi
include $(BUILD_SYSTEM)/base_rules.mk
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index c485891..395be3d 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -9,6 +9,7 @@
#ifndef WPA_SUPPLICANT_I_H
#define WPA_SUPPLICANT_I_H
+#include "utils/bitfield.h"
#include "utils/list.h"
#include "common/defs.h"
#include "common/sae.h"
@@ -44,7 +45,7 @@
struct ctrl_iface_priv;
struct ctrl_iface_global_priv;
struct wpas_dbus_priv;
-struct wpas_binder_priv;
+struct wpas_hidl_priv;
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
@@ -265,7 +266,7 @@
struct wpa_params params;
struct ctrl_iface_global_priv *ctrl_iface;
struct wpas_dbus_priv *dbus;
- struct wpas_binder_priv *binder;
+ struct wpas_hidl_priv *hidl;
void **drv_priv;
size_t drv_count;
struct os_time suspend_time;
@@ -393,11 +394,6 @@
u8 uuid[WPS_UUID_LEN];
};
-struct wpa_ssid_value {
- u8 ssid[SSID_MAX_LEN];
- size_t ssid_len;
-};
-
#define WPA_FREQ_USED_BY_INFRA_STATION BIT(0)
#define WPA_FREQ_USED_BY_P2P_CLIENT BIT(1)
@@ -429,6 +425,9 @@
/* next_neighbor_rep_token - Next request's dialog token */
u8 next_neighbor_rep_token;
+
+ /* token - Dialog token of the current radio measurement */
+ u8 token;
};
enum wpa_supplicant_test_failure {
@@ -451,6 +450,28 @@
struct os_reltime disallowed_until;
};
+struct beacon_rep_data {
+ u8 token;
+ struct wpa_driver_scan_params scan_params;
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len;
+ u8 bssid[ETH_ALEN];
+ enum beacon_report_detail report_detail;
+ struct bitfield *eids;
+};
+
+
+struct external_pmksa_cache {
+ struct dl_list list;
+ void *pmksa_cache;
+};
+
+struct fils_hlp_req {
+ struct dl_list list;
+ u8 dst[ETH_ALEN];
+ struct wpabuf *pkt;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -484,9 +505,9 @@
char *preq_notify_peer;
#endif /* CONFIG_AP */
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-#ifdef CONFIG_CTRL_IFACE_BINDER
- const void *binder_object_key;
-#endif /* CONFIG_CTRL_IFACE_BINDER */
+#ifdef CONFIG_CTRL_IFACE_HIDL
+ const void *hidl_object_key;
+#endif /* CONFIG_CTRL_IFACE_HIDL */
char bridge_ifname[16];
char *confname;
@@ -579,6 +600,7 @@
struct wpa_radio_work *scan_work;
int scanning;
int sched_scanning;
+ unsigned int sched_scan_stop_req:1;
int new_connection;
int eapol_received; /* number of EAPOL packets received after the
@@ -656,6 +678,12 @@
int normal_scans; /* normal scans run before sched_scan */
int scan_for_connection; /* whether the scan request was triggered for
* finding a connection */
+ /*
+ * A unique cookie representing the vendor scan request. This cookie is
+ * returned from the driver interface. 0 indicates that there is no
+ * pending vendor scan request.
+ */
+ u64 curr_scan_cookie;
#define MAX_SCAN_ID 16
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
@@ -725,7 +753,7 @@
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int freq;
- u8 assoc_req_ie[200];
+ u8 assoc_req_ie[1500];
size_t assoc_req_ie_len;
int mfp;
int ft_used;
@@ -774,6 +802,10 @@
unsigned int mesh_if_created:1;
unsigned int mesh_ht_enabled:1;
unsigned int mesh_vht_enabled:1;
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+ /* struct external_pmksa_cache::list */
+ struct dl_list mesh_external_pmksa_cache;
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
#endif /* CONFIG_MESH */
unsigned int off_channel_freq;
@@ -898,6 +930,7 @@
unsigned int p2p_go_max_oper_chwidth;
unsigned int p2p_go_vht_center_freq2;
+ int p2p_lo_started;
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;
@@ -971,6 +1004,8 @@
/* WLAN_STATUS_* status codes from (Re)Association Response frame. */
u16 assoc_status_code;
+ /* Indicates if the previous association request timed out. */
+ u8 assoc_timed_out;
struct ext_password_data *ext_pw;
@@ -984,6 +1019,7 @@
unsigned int wmm_ac_supported:1;
unsigned int ext_work_in_progress:1;
unsigned int own_disconnect_req:1;
+ unsigned int ignore_post_flush_scan_res:1;
#define MAC_ADDR_RAND_SCAN BIT(0)
#define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
@@ -1027,7 +1063,11 @@
struct l2_packet_data *l2_test;
unsigned int extra_roc_dur;
enum wpa_supplicant_test_failure test_failure;
+ char *get_pref_freq_list_override;
+ unsigned int reject_btm_req_reason;
unsigned int p2p_go_csa_on_inv:1;
+ unsigned int ignore_auth_resp:1;
+ unsigned int ignore_assoc_disallow:1;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1038,6 +1078,7 @@
u8 last_tspecs_count;
struct rrm_data rrm;
+ struct beacon_rep_data beacon_rep_data;
#ifdef CONFIG_FST
struct fst_iface *fst;
@@ -1051,7 +1092,6 @@
enum mbo_non_pref_chan_reason reason;
u8 oper_class;
u8 chan;
- u8 reason_detail;
u8 preference;
} *non_pref_chan;
size_t non_pref_chan_num;
@@ -1063,6 +1103,54 @@
* the bss_temp_disallowed list for other purposes as well.
*/
struct dl_list bss_tmp_disallowed;
+
+ /*
+ * Content of a measurement report element with type 8 (LCI),
+ * own location.
+ */
+ struct wpabuf *lci;
+ struct os_reltime lci_time;
+
+ struct os_reltime beacon_rep_scan;
+
+ /* FILS HLP requests (struct fils_hlp_req) */
+ struct dl_list fils_hlp_req;
+
+ struct sched_scan_relative_params {
+ /**
+ * relative_rssi_set - Enable relatively preferred BSS reporting
+ *
+ * 0 = Disable reporting relatively preferred BSSs
+ * 1 = Enable reporting relatively preferred BSSs
+ */
+ int relative_rssi_set;
+
+ /**
+ * relative_rssi - Relative RSSI for reporting better BSSs
+ *
+ * Amount of RSSI by which a BSS should be better than the
+ * current connected BSS so that the new BSS can be reported
+ * to user space. This applies to sched_scan operations.
+ */
+ int relative_rssi;
+
+ /**
+ * relative_adjust_band - Band in which RSSI is to be adjusted
+ */
+ enum set_band relative_adjust_band;
+
+ /**
+ * relative_adjust_rssi - RSSI adjustment
+ *
+ * An amount of relative_adjust_rssi should be added to the
+ * BSSs that belong to the relative_adjust_band while comparing
+ * with other bands for BSS reporting.
+ */
+ int relative_adjust_rssi;
+ } srp;
+
+ /* RIC elements for FT protocol */
+ struct wpabuf *ric_ies;
};
@@ -1104,6 +1192,8 @@
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code);
+struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
@@ -1159,6 +1249,7 @@
int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
size_t ssid_len);
void wpas_request_connection(struct wpa_supplicant *wpa_s);
+void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
@@ -1168,14 +1259,23 @@
void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
const u8 *report, size_t report_len);
int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
- const struct wpa_ssid *ssid,
+ const struct wpa_ssid_value *ssid,
+ int lci, int civic,
void (*cb)(void *ctx,
struct wpabuf *neighbor_rep),
void *cb_ctx);
+void wpas_rrm_handle_radio_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len);
void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
const u8 *src,
const u8 *frame, size_t len,
int rssi);
+int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res,
+ struct scan_info *info);
+void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s);
+void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s);
/* MBO functions */
@@ -1184,14 +1284,24 @@
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);
-int wpas_mbo_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
- size_t len);
void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *ie,
size_t len);
size_t wpas_mbo_ie_bss_trans_reject(struct wpa_supplicant *wpa_s, u8 *pos,
size_t len,
enum mbo_transition_reject_reason reason);
void wpas_mbo_update_cell_capa(struct wpa_supplicant *wpa_s, u8 mbo_cell_capa);
+struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss);
+
+/* op_classes.c */
+enum chan_allowed {
+ NOT_ALLOWED, NO_IR, ALLOWED
+};
+
+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);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -1207,6 +1317,20 @@
struct wpa_ssid *ssid,
const char *field,
const char *value);
+/**
+ * wpa_supplicant_ctrl_rsp_handle - Handle a control response
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Pointer to the network block the reply is for
+ * @field: field the response is a reply for
+ * @value: value (ie, password, etc) for @field
+ * Returns: 0 on success, non-zero on error
+ *
+ * Helper function to handle replies to control interface requests.
+ */
+int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ enum wpa_ctrl_req_type rtype,
+ const char *value);
void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid,
@@ -1281,6 +1405,11 @@
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
- int only_first_ssid);
+ int only_first_ssid, int debug_print);
+
+int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type if_type,
+ unsigned int *num,
+ unsigned int *freq_list);
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index f3f2a64..f55227f 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -4,3 +4,4 @@
ap_scan=1
fast_reauth=1
pmf=1
+p2p_add_cli_chan=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index f84c8b9..0d753a9 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "eap_peer/eap.h"
#include "rsn_supp/wpa.h"
#include "eloop.h"
#include "config.h"
@@ -513,16 +514,44 @@
}
-static int wpa_supplicant_add_pmkid(void *wpa_s,
+static struct wpa_ssid * wpas_get_network_ctx(struct wpa_supplicant *wpa_s,
+ void *network_ctx)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (network_ctx == ssid)
+ return ssid;
+ }
+
+ return NULL;
+}
+
+
+static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid)
{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ struct wpa_ssid *ssid;
+
+ ssid = wpas_get_network_ctx(wpa_s, network_ctx);
+ if (ssid)
+ wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_ADDED MACSTR " %d",
+ MAC2STR(bssid), ssid->id);
return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
}
-static int wpa_supplicant_remove_pmkid(void *wpa_s,
+static int wpa_supplicant_remove_pmkid(void *_wpa_s, void *network_ctx,
const u8 *bssid, const u8 *pmkid)
{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ struct wpa_ssid *ssid;
+
+ ssid = wpas_get_network_ctx(wpa_s, network_ctx);
+ if (ssid)
+ wpa_msg(wpa_s, MSG_INFO, PMKSA_CACHE_REMOVED MACSTR " %d",
+ MAC2STR(bssid), ssid->id);
return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
}
@@ -865,6 +894,7 @@
#ifdef CONFIG_EAP_PROXY
+
static void wpa_supplicant_eap_proxy_cb(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -880,6 +910,52 @@
wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
}
}
+
+
+static void wpa_sm_sim_state_error_handler(struct wpa_supplicant *wpa_s)
+{
+ int i;
+ struct wpa_ssid *ssid;
+ const struct eap_method_type *eap_methods;
+
+ if (!wpa_s->conf)
+ return;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ eap_methods = ssid->eap.eap_methods;
+ if (!eap_methods)
+ continue;
+
+ for (i = 0; eap_methods[i].method != EAP_TYPE_NONE; i++) {
+ if (eap_methods[i].vendor == EAP_VENDOR_IETF &&
+ (eap_methods[i].method == EAP_TYPE_SIM ||
+ eap_methods[i].method == EAP_TYPE_AKA ||
+ eap_methods[i].method == EAP_TYPE_AKA_PRIME)) {
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+ break;
+ }
+ }
+ }
+}
+
+
+static void
+wpa_supplicant_eap_proxy_notify_sim_status(void *ctx,
+ enum eap_proxy_sim_state sim_state)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status %u", sim_state);
+ switch (sim_state) {
+ case SIM_STATE_ERROR:
+ wpa_sm_sim_state_error_handler(wpa_s);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "eap_proxy: SIM card status unknown");
+ break;
+ }
+}
+
#endif /* CONFIG_EAP_PROXY */
@@ -990,6 +1066,8 @@
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
#ifdef CONFIG_EAP_PROXY
ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb;
+ ctx->eap_proxy_notify_sim_status =
+ wpa_supplicant_eap_proxy_notify_sim_status;
#endif /* CONFIG_EAP_PROXY */
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
@@ -1012,6 +1090,7 @@
#ifndef CONFIG_NO_WPA
+
static void wpa_supplicant_set_rekey_offload(void *ctx,
const u8 *kek, size_t kek_len,
const u8 *kck, size_t kck_len,
@@ -1035,6 +1114,25 @@
else
return 0;
}
+
+
+static void wpa_supplicant_fils_hlp_rx(void *ctx, const u8 *dst, const u8 *src,
+ const u8 *pkt, size_t pkt_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ char *hex;
+ size_t hexlen;
+
+ hexlen = pkt_len * 2 + 1;
+ hex = os_malloc(hexlen);
+ if (!hex)
+ return;
+ wpa_snprintf_hex(hex, hexlen, pkt, pkt_len);
+ wpa_msg(wpa_s, MSG_INFO, FILS_HLP_RX "dst=" MACSTR " src=" MACSTR
+ " frame=%s", MAC2STR(dst), MAC2STR(src), hex);
+ os_free(hex);
+}
+
#endif /* CONFIG_NO_WPA */
@@ -1084,6 +1182,7 @@
#endif /* CONFIG_TDLS */
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;
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 354decf..d087e00 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -38,22 +38,33 @@
}
+static int wpas_macsec_get_capability(void *priv, enum macsec_cap *cap)
+{
+ return wpa_drv_macsec_get_capability(priv, cap);
+}
+
+
static int wpas_enable_protect_frames(void *wpa_s, Boolean enabled)
{
return wpa_drv_enable_protect_frames(wpa_s, enabled);
}
+static int wpas_enable_encrypt(void *wpa_s, Boolean enabled)
+{
+ return wpa_drv_enable_encrypt(wpa_s, enabled);
+}
+
+
static int wpas_set_replay_protect(void *wpa_s, Boolean enabled, u32 window)
{
return wpa_drv_set_replay_protect(wpa_s, enabled, window);
}
-static int wpas_set_current_cipher_suite(void *wpa_s, const u8 *cs,
- size_t cs_len)
+static int wpas_set_current_cipher_suite(void *wpa_s, u64 cs)
{
- return wpa_drv_set_current_cipher_suite(wpa_s, cs, cs_len);
+ return wpa_drv_set_current_cipher_suite(wpa_s, cs);
}
@@ -63,30 +74,21 @@
}
-static int wpas_get_receive_lowest_pn(void *wpa_s, u32 channel,
- u8 an, u32 *lowest_pn)
+static int wpas_get_receive_lowest_pn(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_get_receive_lowest_pn(wpa_s, channel, an, lowest_pn);
+ return wpa_drv_get_receive_lowest_pn(wpa_s, sa);
}
-static int wpas_get_transmit_next_pn(void *wpa_s, u32 channel,
- u8 an, u32 *next_pn)
+static int wpas_get_transmit_next_pn(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_get_transmit_next_pn(wpa_s, channel, an, next_pn);
+ return wpa_drv_get_transmit_next_pn(wpa_s, sa);
}
-static int wpas_set_transmit_next_pn(void *wpa_s, u32 channel,
- u8 an, u32 next_pn)
+static int wpas_set_transmit_next_pn(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_set_transmit_next_pn(wpa_s, channel, an, next_pn);
-}
-
-
-static int wpas_get_available_receive_sc(void *wpa_s, u32 *channel)
-{
- return wpa_drv_get_available_receive_sc(wpa_s, channel);
+ return wpa_drv_set_transmit_next_pn(wpa_s, sa);
}
@@ -104,81 +106,79 @@
}
-static int wpas_create_receive_sc(void *wpa_s, u32 channel,
- struct ieee802_1x_mka_sci *sci,
+static int wpas_create_receive_sc(void *wpa_s, struct receive_sc *sc,
enum validate_frames vf,
enum confidentiality_offset co)
{
- return wpa_drv_create_receive_sc(wpa_s, channel, sci->addr, sci->port,
- conf_offset_val(co), vf);
+ return wpa_drv_create_receive_sc(wpa_s, sc, conf_offset_val(co), vf);
}
-static int wpas_delete_receive_sc(void *wpa_s, u32 channel)
+static int wpas_delete_receive_sc(void *wpa_s, struct receive_sc *sc)
{
- return wpa_drv_delete_receive_sc(wpa_s, channel);
+ return wpa_drv_delete_receive_sc(wpa_s, sc);
}
-static int wpas_create_receive_sa(void *wpa_s, u32 channel, u8 an,
- u32 lowest_pn, const u8 *sak)
+static int wpas_create_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_create_receive_sa(wpa_s, channel, an, lowest_pn, sak);
+ return wpa_drv_create_receive_sa(wpa_s, sa);
}
-static int wpas_enable_receive_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_delete_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_enable_receive_sa(wpa_s, channel, an);
+ return wpa_drv_delete_receive_sa(wpa_s, sa);
}
-static int wpas_disable_receive_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_enable_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_disable_receive_sa(wpa_s, channel, an);
+ return wpa_drv_enable_receive_sa(wpa_s, sa);
}
-static int wpas_get_available_transmit_sc(void *wpa_s, u32 *channel)
+static int wpas_disable_receive_sa(void *wpa_s, struct receive_sa *sa)
{
- return wpa_drv_get_available_transmit_sc(wpa_s, channel);
+ return wpa_drv_disable_receive_sa(wpa_s, sa);
}
static int
-wpas_create_transmit_sc(void *wpa_s, u32 channel,
- const struct ieee802_1x_mka_sci *sci,
+wpas_create_transmit_sc(void *wpa_s, struct transmit_sc *sc,
enum confidentiality_offset co)
{
- return wpa_drv_create_transmit_sc(wpa_s, channel, sci->addr, sci->port,
- conf_offset_val(co));
+ return wpa_drv_create_transmit_sc(wpa_s, sc, conf_offset_val(co));
}
-static int wpas_delete_transmit_sc(void *wpa_s, u32 channel)
+static int wpas_delete_transmit_sc(void *wpa_s, struct transmit_sc *sc)
{
- return wpa_drv_delete_transmit_sc(wpa_s, channel);
+ return wpa_drv_delete_transmit_sc(wpa_s, sc);
}
-static int wpas_create_transmit_sa(void *wpa_s, u32 channel, u8 an,
- u32 next_pn, Boolean confidentiality,
- const u8 *sak)
+static int wpas_create_transmit_sa(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_create_transmit_sa(wpa_s, channel, an, next_pn,
- confidentiality, sak);
+ return wpa_drv_create_transmit_sa(wpa_s, sa);
}
-static int wpas_enable_transmit_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_delete_transmit_sa(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_enable_transmit_sa(wpa_s, channel, an);
+ return wpa_drv_delete_transmit_sa(wpa_s, sa);
}
-static int wpas_disable_transmit_sa(void *wpa_s, u32 channel, u8 an)
+static int wpas_enable_transmit_sa(void *wpa_s, struct transmit_sa *sa)
{
- return wpa_drv_disable_transmit_sa(wpa_s, channel, an);
+ return wpa_drv_enable_transmit_sa(wpa_s, sa);
+}
+
+
+static int wpas_disable_transmit_sa(void *wpa_s, struct transmit_sa *sa)
+{
+ return wpa_drv_disable_transmit_sa(wpa_s, sa);
}
@@ -193,7 +193,14 @@
if (!ssid || ssid->macsec_policy == 0)
return 0;
- policy = ssid->macsec_policy == 1 ? SHOULD_SECURE : DO_NOT_SECURE;
+ if (ssid->macsec_policy == 1) {
+ if (ssid->macsec_integ_only == 1)
+ policy = SHOULD_SECURE;
+ else
+ policy = SHOULD_ENCRYPT;
+ } else {
+ policy = DO_NOT_SECURE;
+ }
kay_ctx = os_zalloc(sizeof(*kay_ctx));
if (!kay_ctx)
@@ -203,27 +210,30 @@
kay_ctx->macsec_init = wpas_macsec_init;
kay_ctx->macsec_deinit = wpas_macsec_deinit;
+ kay_ctx->macsec_get_capability = wpas_macsec_get_capability;
kay_ctx->enable_protect_frames = wpas_enable_protect_frames;
+ kay_ctx->enable_encrypt = wpas_enable_encrypt;
kay_ctx->set_replay_protect = wpas_set_replay_protect;
kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite;
kay_ctx->enable_controlled_port = wpas_enable_controlled_port;
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->get_available_receive_sc = wpas_get_available_receive_sc;
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;
+ kay_ctx->delete_receive_sa = wpas_delete_receive_sa;
kay_ctx->enable_receive_sa = wpas_enable_receive_sa;
kay_ctx->disable_receive_sa = wpas_disable_receive_sa;
- kay_ctx->get_available_transmit_sc = wpas_get_available_transmit_sc;
kay_ctx->create_transmit_sc = wpas_create_transmit_sc;
kay_ctx->delete_transmit_sc = wpas_delete_transmit_sc;
kay_ctx->create_transmit_sa = wpas_create_transmit_sa;
+ kay_ctx->delete_transmit_sa = wpas_delete_transmit_sa;
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, wpa_s->ifname,
+ res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_port,
+ ssid->mka_priority, wpa_s->ifname,
wpa_s->own_addr);
if (res == NULL) {
os_free(kay_ctx);
@@ -376,3 +386,51 @@
return res;
}
+
+
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct mka_key *cak;
+ struct mka_key_name *ckn;
+ void *res;
+
+ if ((ssid->mka_psk_set & MKA_PSK_SET) != MKA_PSK_SET)
+ return NULL;
+
+ if (ieee802_1x_alloc_kay_sm(wpa_s, ssid) < 0)
+ return NULL;
+
+ if (!wpa_s->kay || wpa_s->kay->policy == DO_NOT_SECURE)
+ return NULL;
+
+ ckn = os_zalloc(sizeof(*ckn));
+ if (!ckn)
+ goto dealloc;
+
+ cak = os_zalloc(sizeof(*cak));
+ if (!cak)
+ goto free_ckn;
+
+ cak->len = MACSEC_CAK_LEN;
+ os_memcpy(cak->key, ssid->mka_cak, cak->len);
+
+ ckn->len = MACSEC_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);
+ if (res)
+ return res;
+
+ /* Failed to create MKA */
+ os_free(cak);
+
+ /* fallthrough */
+
+free_ckn:
+ os_free(ckn);
+dealloc:
+ ieee802_1x_dealloc_kay_sm(wpa_s);
+
+ return NULL;
+}
diff --git a/wpa_supplicant/wpas_kay.h b/wpa_supplicant/wpas_kay.h
index b7236d0..81f8e0c 100644
--- a/wpa_supplicant/wpas_kay.h
+++ b/wpa_supplicant/wpas_kay.h
@@ -17,6 +17,9 @@
const u8 *peer_addr);
void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s);
+void * ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+
#else /* CONFIG_MACSEC */
static inline int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s,
@@ -36,6 +39,13 @@
{
}
+static inline void *
+ieee802_1x_create_preshared_mka(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ return 0;
+}
+
#endif /* CONFIG_MACSEC */
#endif /* WPAS_KAY_H */
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index 6af1678..4e37591 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/module_tests.h"
#include "wpa_supplicant_i.h"
#include "blacklist.h"
@@ -79,30 +80,18 @@
ret = -1;
#ifdef CONFIG_WPS
- {
- int wps_module_tests(void);
- if (wps_module_tests() < 0)
- ret = -1;
- }
+ if (wps_module_tests() < 0)
+ ret = -1;
#endif /* CONFIG_WPS */
- {
- int utils_module_tests(void);
- if (utils_module_tests() < 0)
- ret = -1;
- }
+ if (utils_module_tests() < 0)
+ ret = -1;
- {
- int common_module_tests(void);
- if (common_module_tests() < 0)
- ret = -1;
- }
+ if (common_module_tests() < 0)
+ ret = -1;
- {
- int crypto_module_tests(void);
- if (crypto_module_tests() < 0)
- ret = -1;
- }
+ if (crypto_module_tests() < 0)
+ ret = -1;
return ret;
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 0860eb4..228269e 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1142,6 +1142,13 @@
return -1;
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
#ifdef CONFIG_P2P
if (p2p_group && wpa_s->go_params && wpa_s->go_params->ssid_len) {
ssid->ssid = os_zalloc(wpa_s->go_params->ssid_len + 1);
@@ -1197,6 +1204,13 @@
}
ssid->temporary = 1;
ssid->p2p_group = p2p_group;
+ /*
+ * When starting a regular WPS process (not P2P group formation)
+ * the registrar/final station can be either AP or PCP
+ * so use a "don't care" value for the pbss flag.
+ */
+ if (!p2p_group)
+ ssid->pbss = 2;
if (ssid_val) {
ssid->ssid = os_malloc(ssid_len);
if (ssid->ssid) {
@@ -2196,7 +2210,7 @@
#ifdef CONFIG_WPS_NFC
#ifdef CONFIG_WPS_ER
-static struct wpabuf *
+struct wpabuf *
wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
struct wpa_ssid *ssid)
{
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index c8fe47e..eb1615a 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -62,6 +62,8 @@
int ndef, const char *uuid);
int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_network_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, struct wpa_ssid * ssid);
struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
int ndef, const char *id_str);
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);