diff options
author | Xin Li <delphij@google.com> | 2018-08-07 16:51:27 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2018-08-07 16:51:27 +0000 |
commit | 9c793357f5ea5bf80017cc65721bd63d148b3e64 (patch) | |
tree | 6ab40060ee8d3b22218ad4ab7da35332fc37b708 | |
parent | a0685c87c833bba74f77135c179b535f3779d724 (diff) | |
parent | 0bc1d6a17a0fbf278c657508c00fa2f608e4f04d (diff) | |
download | wpa_supplicant_8-9c793357f5ea5bf80017cc65721bd63d148b3e64.tar.gz |
Merge "Merge Android Pie into master"android-o-mr1-iot-release-smart-display-r3android-o-mr1-iot-release-1.0.5android-o-mr1-iot-release-1.0.4android-o-mr1-iot-release-1.0.3oreo-mr1-1.2-iot-releasemaster-cuttlefish-testing-release
59 files changed, 13178 insertions, 60 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk index a9ded3cb..54d12f6c 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -46,11 +46,11 @@ L_CFLAGS += -DANDROID_LIB_STUB endif # Use Android specific directory for control interface sockets -L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" -L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/hostapd\" +L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/hostapd/sockets\" +L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/hostapd/ctrl\" # Use Android specific directory for hostapd_cli command completion history -L_CFLAGS += -DCONFIG_HOSTAPD_CLI_HISTORY_DIR=\"/data/misc/wifi\" +L_CFLAGS += -DCONFIG_HOSTAPD_CLI_HISTORY_DIR=\"/data/vendor/wifi/hostapd\" # To force sizeof(enum) = 4 ifeq ($(TARGET_ARCH),arm) @@ -1072,6 +1072,14 @@ else OBJS_c += src/utils/edit_simple.c endif +ifeq ($(filter gce_x86 gce_x86_64 calypso generic_x86 generic_x86_64 generic generic_arm64, $(TARGET_DEVICE)),) +ifdef CONFIG_CTRL_IFACE_HIDL +HOSTAPD_USE_HIDL=y +L_CFLAGS += -DCONFIG_CTRL_IFACE_HIDL +L_CPPFLAGS = -Wall -Werror +endif +endif + ######################## include $(CLEAR_VARS) @@ -1089,6 +1097,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := hostapd LOCAL_MODULE_TAGS := optional LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw ifdef CONFIG_DRIVER_CUSTOM LOCAL_STATIC_LIBRARIES := libCustomWifi endif @@ -1103,10 +1112,40 @@ else LOCAL_STATIC_LIBRARIES += libnl_2 endif endif +ifeq ($(HOSTAPD_USE_HIDL), y) +LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.0 +LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhidltransport libhwbinder libutils +LOCAL_STATIC_LIBRARIES += libhostapd_hidl +endif LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_SRC_FILES := $(OBJS) LOCAL_C_INCLUDES := $(INCLUDES) LOCAL_INIT_RC := hostapd.android.rc include $(BUILD_EXECUTABLE) +ifeq ($(HOSTAPD_USE_HIDL), y) +### Hidl service library ### +######################## +include $(CLEAR_VARS) +LOCAL_MODULE := libhostapd_hidl +LOCAL_VENDOR_MODULE := true +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)/hostapd.cpp +LOCAL_SHARED_LIBRARIES := \ + android.hardware.wifi.hostapd@1.0 \ + libbase \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + libutils \ + liblog +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/hidl/$(HIDL_INTERFACE_VERSION) +include $(BUILD_STATIC_LIBRARY) +endif # HOSTAPD_USE_HIDL == y endif # ifeq ($(WPA_BUILD_HOSTAPD),true) diff --git a/hostapd/CleanSpec.mk b/hostapd/CleanSpec.mk index 653aebb5..5d50cd41 100644 --- a/hostapd/CleanSpec.mk +++ b/hostapd/CleanSpec.mk @@ -49,4 +49,5 @@ # 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)/vendor/bin/hostapd) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/hostapd_cli) diff --git a/hostapd/android.config b/hostapd/android.config index 08d21f04..5a244388 100644 --- a/hostapd/android.config +++ b/hostapd/android.config @@ -134,6 +134,9 @@ CONFIG_IPV6=y # IEEE 802.11n (High Throughput) support CONFIG_IEEE80211N=y +# IEEE 802.11ac (Very High Throughput) support +CONFIG_IEEE80211AC=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. @@ -210,3 +213,10 @@ CONFIG_WPA_CLI_EDIT=y # /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before # either wpa_supplicant or hostapd are run. CONFIG_NO_RANDOM_POOL=y + +# Add support for Hidl control interface +# Only applicable for Android platforms. +CONFIG_CTRL_IFACE_HIDL=y + +# Enable support of Automatic Channel Selection +CONFIG_ACS=y diff --git a/hostapd/hidl/.clang-format b/hostapd/hidl/.clang-format new file mode 100644 index 00000000..42fadb55 --- /dev/null +++ b/hostapd/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/hostapd/hidl/1.0/hidl.cpp b/hostapd/hidl/1.0/hidl.cpp new file mode 100644 index 00000000..a0dc50ef --- /dev/null +++ b/hostapd/hidl/1.0/hidl.cpp @@ -0,0 +1,70 @@ +/* + * hidl interface for wpa_supplicant daemon + * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2018, 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 "hostapd.h" + +extern "C" +{ +#include "hidl.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::hostapd::V1_0::IHostapd; +using android::hardware::wifi::hostapd::V1_0::implementation::Hostapd; + +// This file is a bridge between the hostapd code written in 'C' and the HIDL +// interface in C++. So, using "C" style static globals here! +static int hidl_fd = -1; +static android::sp<IHostapd> service; + +void hostapd_hidl_sock_handler( + int /* sock */, void * /* eloop_ctx */, void * /* sock_ctx */) +{ + IPCThreadState::self()->handlePolledCommands(); +} + +int hostapd_hidl_init(struct hapd_interfaces *interfaces) +{ + wpa_printf(MSG_DEBUG, "Initing hidl control"); + + IPCThreadState::self()->setupPolling(&hidl_fd); + if (hidl_fd < 0) + goto err; + + wpa_printf(MSG_INFO, "Processing hidl events on FD %d", hidl_fd); + // Look for read events from the hidl socket in the eloop. + if (eloop_register_read_sock( + hidl_fd, hostapd_hidl_sock_handler, interfaces, NULL) < 0) + goto err; + service = new Hostapd(interfaces); + if (!service) + goto err; + if (service->registerAsService() != android::NO_ERROR) + goto err; + return 0; +err: + hostapd_hidl_deinit(interfaces); + return -1; +} + +void hostapd_hidl_deinit(struct hapd_interfaces *interfaces) +{ + wpa_printf(MSG_DEBUG, "Deiniting hidl control"); + eloop_unregister_read_sock(hidl_fd); + IPCThreadState::shutdown(); + hidl_fd = -1; + service.clear(); +} diff --git a/hostapd/hidl/1.0/hidl.h b/hostapd/hidl/1.0/hidl.h new file mode 100644 index 00000000..5decf64e --- /dev/null +++ b/hostapd/hidl/1.0/hidl.h @@ -0,0 +1,30 @@ +/* + * hidl interface for wpa_supplicant daemon + * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef HOSTAPD_HIDL_HIDL_H +#define HOSTAPD_HIDL_HIDL_H + +#ifdef __cplusplus +extern "C" +{ +#endif // _cplusplus +#include "ap/hostapd.h" + +/** + * This is the hidl RPC interface entry point to the hostapd core. + * This initializes the hidl driver & IHostapd instance. + */ +int hostapd_hidl_init(struct hapd_interfaces *interfaces); +void hostapd_hidl_deinit(struct hapd_interfaces *interfaces); + +#ifdef __cplusplus +} +#endif // _cplusplus + +#endif // HOSTAPD_HIDL_HIDL_H diff --git a/hostapd/hidl/1.0/hidl_return_util.h b/hostapd/hidl/1.0/hidl_return_util.h new file mode 100644 index 00000000..1625dc27 --- /dev/null +++ b/hostapd/hidl/1.0/hidl_return_util.h @@ -0,0 +1,44 @@ +/* + * hidl interface for wpa_hostapd daemon + * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2018, 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_ + +#include <functional> + +namespace android { +namespace hardware { +namespace wifi { +namespace hostapd { +namespace V1_0 { +namespace implementation { +namespace hidl_return_util { + +/** + * These utility functions are used to invoke a method on the provided + * HIDL interface object. + */ +// Use for HIDL methods which return only an instance of HostapdStatus. +template <typename ObjT, typename WorkFuncT, typename... Args> +Return<void> call( + ObjT* obj, WorkFuncT&& work, + const std::function<void(const HostapdStatus&)>& hidl_cb, Args&&... args) +{ + hidl_cb((obj->*work)(std::forward<Args>(args)...)); + return Void(); +} + +} // namespace hidl_return_util +} // namespace implementation +} // namespace V1_0 +} // namespace hostapd +} // namespace wifi +} // namespace hardware +} // namespace android +#endif // HIDL_RETURN_UTIL_H_ diff --git a/hostapd/hidl/1.0/hostapd.cpp b/hostapd/hidl/1.0/hostapd.cpp new file mode 100644 index 00000000..3cd78b36 --- /dev/null +++ b/hostapd/hidl/1.0/hostapd.cpp @@ -0,0 +1,286 @@ +/* + * hidl interface for wpa_hostapd daemon + * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include <iomanip> +#include <sstream> +#include <string> +#include <vector> + +#include <android-base/file.h> +#include <android-base/stringprintf.h> + +#include "hostapd.h" +#include "hidl_return_util.h" + +extern "C" +{ +#include "utils/eloop.h" +} + +// The HIDL implementation for hostapd creates a hostapd.conf dynamically for +// each interface. This file can then be used to hook onto the normal config +// file parsing logic in hostapd code. Helps us to avoid duplication of code +// in the HIDL interface. +// TOOD(b/71872409): Add unit tests for this. +namespace { +constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf"; + +using android::base::RemoveFileIfExists; +using android::base::StringPrintf; +using android::base::WriteStringToFile; +using android::hardware::wifi::hostapd::V1_0::IHostapd; + +std::string WriteHostapdConfig( + const std::string& interface_name, const std::string& config) +{ + const std::string file_path = + StringPrintf(kConfFileNameFmt, interface_name.c_str()); + if (WriteStringToFile( + config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + getuid(), getgid())) { + return file_path; + } + // Diagnose failure + int error = errno; + wpa_printf( + MSG_ERROR, "Cannot write hostapd config to %s, error: %s", + file_path.c_str(), strerror(error)); + struct stat st; + int result = stat(file_path.c_str(), &st); + if (result == 0) { + wpa_printf( + MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d", + st.st_uid, st.st_gid, st.st_mode); + } else { + wpa_printf( + MSG_ERROR, + "Error calling stat() on hostapd config file: %s", + strerror(errno)); + } + return ""; +} + +std::string CreateHostapdConfig( + const IHostapd::IfaceParams& iface_params, + const IHostapd::NetworkParams& nw_params) +{ + if (nw_params.ssid.size() > + static_cast<uint32_t>( + IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) { + wpa_printf( + MSG_ERROR, "Invalid SSID size: %zu", nw_params.ssid.size()); + return ""; + } + if ((nw_params.encryptionType != IHostapd::EncryptionType::NONE) && + (nw_params.pskPassphrase.size() < + static_cast<uint32_t>( + IHostapd::ParamSizeLimits:: + WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES) || + nw_params.pskPassphrase.size() > + static_cast<uint32_t>( + IHostapd::ParamSizeLimits:: + WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) { + wpa_printf( + MSG_ERROR, "Invalid psk passphrase size: %zu", + nw_params.pskPassphrase.size()); + return ""; + } + + // SSID string + std::stringstream ss; + ss << std::hex; + ss << std::setfill('0'); + for (uint8_t b : nw_params.ssid) { + ss << std::setw(2) << static_cast<unsigned int>(b); + } + const std::string ssid_as_string = ss.str(); + + // Encryption config string + std::string encryption_config_as_string; + switch (nw_params.encryptionType) { + case IHostapd::EncryptionType::NONE: + // no security params + break; + case IHostapd::EncryptionType::WPA: + encryption_config_as_string = StringPrintf( + "wpa=3\n" + "wpa_pairwise=TKIP CCMP\n" + "wpa_passphrase=%s", + nw_params.pskPassphrase.c_str()); + break; + case IHostapd::EncryptionType::WPA2: + encryption_config_as_string = StringPrintf( + "wpa=2\n" + "rsn_pairwise=CCMP\n" + "wpa_passphrase=%s", + nw_params.pskPassphrase.c_str()); + break; + default: + wpa_printf(MSG_ERROR, "Unknown encryption type"); + return ""; + } + + std::string channel_config_as_string; + if (iface_params.channelParams.enableAcs) { + channel_config_as_string = StringPrintf( + "channel=0\n" + "acs_exclude_dfs=%d", + iface_params.channelParams.acsShouldExcludeDfs); + } else { + channel_config_as_string = StringPrintf( + "channel=%d", iface_params.channelParams.channel); + } + + // Hw Mode String + std::string hw_mode_as_string; + std::string ht_cap_vht_oper_chwidth_as_string; + switch (iface_params.channelParams.band) { + case IHostapd::Band::BAND_2_4_GHZ: + hw_mode_as_string = "hw_mode=g"; + break; + case IHostapd::Band::BAND_5_GHZ: + hw_mode_as_string = "hw_mode=a"; + if (iface_params.channelParams.enableAcs) { + ht_cap_vht_oper_chwidth_as_string = + "ht_capab=[HT40+]\n" + "vht_oper_chwidth=1"; + } + break; + case IHostapd::Band::BAND_ANY: + hw_mode_as_string = "hw_mode=any"; + if (iface_params.channelParams.enableAcs) { + ht_cap_vht_oper_chwidth_as_string = + "ht_capab=[HT40+]\n" + "vht_oper_chwidth=1"; + } + break; + default: + wpa_printf(MSG_ERROR, "Invalid band"); + return ""; + } + + return StringPrintf( + "interface=%s\n" + "driver=nl80211\n" + "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n" + // ssid2 signals to hostapd that the value is not a literal value + // for use as a SSID. In this case, we're giving it a hex + // std::string and hostapd needs to expect that. + "ssid2=%s\n" + "%s\n" + "ieee80211n=%d\n" + "ieee80211ac=%d\n" + "%s\n" + "%s\n" + "ignore_broadcast_ssid=%d\n" + "wowlan_triggers=any\n" + "%s\n", + iface_params.ifaceName.c_str(), ssid_as_string.c_str(), + channel_config_as_string.c_str(), + iface_params.hwModeParams.enable80211N ? 1 : 0, + iface_params.hwModeParams.enable80211AC ? 1 : 0, + hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(), + nw_params.isHidden ? 1 : 0, encryption_config_as_string.c_str()); +} +} // namespace + +namespace android { +namespace hardware { +namespace wifi { +namespace hostapd { +namespace V1_0 { +namespace implementation { +using hidl_return_util::call; + +Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces) +{} + +Return<void> Hostapd::addAccessPoint( + const IfaceParams& iface_params, const NetworkParams& nw_params, + addAccessPoint_cb _hidl_cb) +{ + return call( + this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params, + nw_params); +} + +Return<void> Hostapd::removeAccessPoint( + const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb) +{ + return call( + this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name); +} + +Return<void> Hostapd::terminate() { + wpa_printf(MSG_INFO, "Terminating..."); + eloop_terminate(); + return Void(); +} + +HostapdStatus Hostapd::addAccessPointInternal( + const IfaceParams& iface_params, const NetworkParams& nw_params) +{ + if (hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str())) { + wpa_printf( + MSG_ERROR, "Interface %s already present", + iface_params.ifaceName.c_str()); + return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""}; + } + const auto conf_params = CreateHostapdConfig(iface_params, nw_params); + if (conf_params.empty()) { + wpa_printf(MSG_ERROR, "Failed to create config params"); + return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""}; + } + const auto conf_file_path = + WriteHostapdConfig(iface_params.ifaceName, conf_params); + if (conf_file_path.empty()) { + wpa_printf(MSG_ERROR, "Failed to write config file"); + return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; + } + std::string add_iface_param_str = StringPrintf( + "%s config=%s", iface_params.ifaceName.c_str(), + conf_file_path.c_str()); + std::vector<char> add_iface_param_vec( + add_iface_param_str.begin(), add_iface_param_str.end() + 1); + if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) { + wpa_printf( + MSG_ERROR, "Adding interface %s failed", + add_iface_param_str.c_str()); + return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; + } + struct hostapd_data* iface_hapd = + hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str()); + WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr); + if (hostapd_enable_iface(iface_hapd->iface) < 0) { + wpa_printf( + MSG_ERROR, "Enabling interface %s failed", + iface_params.ifaceName.c_str()); + return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; + } + return {HostapdStatusCode::SUCCESS, ""}; +} + +HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name) +{ + std::vector<char> remove_iface_param_vec( + iface_name.begin(), iface_name.end() + 1); + if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) < + 0) { + wpa_printf( + MSG_ERROR, "Removing interface %s failed", + iface_name.c_str()); + return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; + } + return {HostapdStatusCode::SUCCESS, ""}; +} +} // namespace implementation +} // namespace V1_0 +} // namespace hostapd +} // namespace wifi +} // namespace hardware +} // namespace android diff --git a/hostapd/hidl/1.0/hostapd.h b/hostapd/hidl/1.0/hostapd.h new file mode 100644 index 00000000..7985fd9a --- /dev/null +++ b/hostapd/hidl/1.0/hostapd.h @@ -0,0 +1,72 @@ +/* + * hidl interface for wpa_hostapd daemon + * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> + * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef HOSTAPD_HIDL_SUPPLICANT_H +#define HOSTAPD_HIDL_SUPPLICANT_H + +#include <string> + +#include <android-base/macros.h> + +#include <android/hardware/wifi/hostapd/1.0/IHostapd.h> + +extern "C" +{ +#include "utils/common.h" +#include "utils/includes.h" +#include "utils/wpa_debug.h" +#include "ap/hostapd.h" +} + +namespace android { +namespace hardware { +namespace wifi { +namespace hostapd { +namespace V1_0 { +namespace implementation { + +/** + * Implementation of the hostapd hidl object. This hidl + * object is used core for global control operations on + * hostapd. + */ +class Hostapd : public V1_0::IHostapd +{ +public: + Hostapd(hapd_interfaces* interfaces); + ~Hostapd() override = default; + + // Hidl methods exposed. + Return<void> addAccessPoint( + const IfaceParams& iface_params, const NetworkParams& nw_params, + addAccessPoint_cb _hidl_cb) override; + Return<void> removeAccessPoint( + const hidl_string& iface_name, + removeAccessPoint_cb _hidl_cb) override; + Return<void> terminate() override; + +private: + // Corresponding worker functions for the HIDL methods. + HostapdStatus addAccessPointInternal( + const IfaceParams& iface_params, const NetworkParams& nw_params); + HostapdStatus removeAccessPointInternal(const std::string& iface_name); + + // Raw pointer to the global structure maintained by the core. + struct hapd_interfaces* interfaces_; + + DISALLOW_COPY_AND_ASSIGN(Hostapd); +}; +} // namespace implementation +} // namespace V1_0 +} // namespace hostapd +} // namespace wifi +} // namespace hardware +} // namespace android + +#endif // HOSTAPD_HIDL_SUPPLICANT_H diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc index 048c6674..37a95c22 100644 --- a/hostapd/hostapd.android.rc +++ b/hostapd/hostapd.android.rc @@ -7,14 +7,15 @@ # on post-fs-data - mkdir /data/misc/wifi/hostapd 0770 wifi wifi + mkdir /data/vendor/wifi 0770 wifi wifi + mkdir /data/vendor/wifi/hostapd 0770 wifi wifi + mkdir /data/vendor/wifi/hostapd/sockets 0770 wifi wifi -service hostapd /vendor/bin/hostapd \ - /data/misc/wifi/hostapd.conf +service hostapd /vendor/bin/hw/hostapd + interface android.hardware.wifi.hostapd@1.0::IHostapd default class main capabilities NET_ADMIN NET_RAW user wifi group wifi net_raw net_admin - writepid /data/misc/wifi/hostapd.pid disabled oneshot diff --git a/hostapd/main.c b/hostapd/main.c index ce94d057..6c0490f0 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -28,7 +28,9 @@ #include "config_file.h" #include "eap_register.h" #include "ctrl_iface.h" - +#ifdef CONFIG_CTRL_IFACE_HIDL +#include "hidl.h" +#endif /* CONFIG_CTRL_IFACE_HIDL */ struct hapd_global { void **drv_priv; @@ -751,9 +753,11 @@ int main(int argc, char *argv[]) } } +#ifndef CONFIG_CTRL_IFACE_HIDL if (optind == argc && interfaces.global_iface_path == NULL && num_bss_configs == 0) usage(); +#endif wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); @@ -893,6 +897,12 @@ int main(int argc, char *argv[]) goto out; } +#ifdef CONFIG_CTRL_IFACE_HIDL + if (hostapd_hidl_init(&interfaces)) { + wpa_printf(MSG_ERROR, "Failed to initialize HIDL interface"); + goto out; + } +#endif /* CONFIG_CTRL_IFACE_HIDL */ hostapd_global_ctrl_iface_init(&interfaces); if (hostapd_global_run(&interfaces, daemonize, pid_file)) { @@ -903,6 +913,9 @@ int main(int argc, char *argv[]) ret = 0; out: +#ifdef CONFIG_CTRL_IFACE_HIDL + hostapd_hidl_deinit(&interfaces); +#endif /* CONFIG_CTRL_IFACE_HIDL */ hostapd_global_ctrl_iface_deinit(&interfaces); /* Deinitialize all interfaces */ for (i = 0; i < interfaces.count; i++) { diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index f77e6ec7..d7c67206 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -372,6 +372,16 @@ struct hostapd_sta_info { #endif /* CONFIG_TAXONOMY */ }; +enum hostapd_iface_state { + HAPD_IFACE_UNINITIALIZED, + HAPD_IFACE_DISABLED, + HAPD_IFACE_COUNTRY_UPDATE, + HAPD_IFACE_ACS, + HAPD_IFACE_HT_SCAN, + HAPD_IFACE_DFS, + HAPD_IFACE_ENABLED +}; + /** * struct hostapd_iface - hostapd per-interface data structure */ @@ -382,16 +392,7 @@ struct hostapd_iface { struct hostapd_config *conf; char phy[16]; /* Name of the PHY (radio) */ - enum hostapd_iface_state { - HAPD_IFACE_UNINITIALIZED, - HAPD_IFACE_DISABLED, - HAPD_IFACE_COUNTRY_UPDATE, - HAPD_IFACE_ACS, - HAPD_IFACE_HT_SCAN, - HAPD_IFACE_DFS, - HAPD_IFACE_ENABLED - } state; - + enum hostapd_iface_state state; #ifdef CONFIG_MESH struct mesh_conf *mconf; #endif /* CONFIG_MESH */ diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 988c9d2d..7243d9fb 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -116,6 +116,20 @@ static int RSA_bits(const RSA *r) #include <openssl/pem.h> #include <keystore/keystore_get.h> +#include <log/log.h> +#include <log/log_event_list.h> + +#define CERT_VALIDATION_FAILURE 210033 + +static void log_cert_validation_failure(const char *reason) +{ + android_log_context ctx = create_android_logger(CERT_VALIDATION_FAILURE); + android_log_write_string8(ctx, reason); + android_log_write_list(ctx, LOG_ID_SECURITY); + android_log_destroy(&ctx); +} + + static BIO * BIO_from_keystore(const char *key) { BIO *bio = NULL; @@ -1787,6 +1801,10 @@ static void openssl_tls_fail_event(struct tls_connection *conn, struct wpabuf *cert = NULL; struct tls_context *context = conn->context; +#ifdef ANDROID + log_cert_validation_failure(err_str); +#endif + if (context->event_cb == NULL) return; diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 00437070..52b04913 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -94,6 +94,12 @@ static void eap_notify_status(struct eap_sm *sm, const char *status, sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter); } +static void eap_report_error(struct eap_sm *sm, int error_code) +{ + wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code); + if (sm->eapol_cb->notify_eap_error) + sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code); +} static void eap_sm_free_key(struct eap_sm *sm) { @@ -1934,6 +1940,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req) const struct eap_hdr *hdr; size_t plen; const u8 *pos; + int error_code; sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE; sm->reqId = 0; @@ -2018,6 +2025,13 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req) case EAP_CODE_FAILURE: wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure"); eap_notify_status(sm, "completion", "failure"); + + /* Get the error code from method */ + if (sm->m && sm->m->get_error_code) { + error_code = sm->m->get_error_code(sm->eap_method_priv); + if (error_code != NO_EAP_METHOD_ERROR) + eap_report_error(sm, error_code); + } sm->rxFailure = TRUE; break; case EAP_CODE_INITIATE: diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index b5591a01..d0837e37 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -246,6 +246,13 @@ struct eapol_callbacks { void (*notify_status)(void *ctx, const char *status, const char *parameter); + /** + * notify_eap_error - Report EAP method error code + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @error_code: Error code from the used EAP method + */ + void (*notify_eap_error)(void *ctx, int error_code); + #ifdef CONFIG_EAP_PROXY /** * eap_proxy_cb - Callback signifying any updates from eap_proxy diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index f7e3cd6b..679f1014 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -56,6 +56,7 @@ struct eap_aka_data { int kdf_negotiation; u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX]; size_t last_kdf_count; + int error_code; }; @@ -99,6 +100,9 @@ static void * eap_aka_init(struct eap_sm *sm) data->eap_method = EAP_TYPE_AKA; + /* Zero is a valid error code, so we need to initialize */ + data->error_code = NO_EAP_METHOD_ERROR; + eap_aka_state(data, CONTINUE); data->prev_id = -1; @@ -1025,8 +1029,17 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, } else if (data->pseudonym) { identity = data->pseudonym; identity_len = data->pseudonym_len; - } else - identity = eap_get_config_identity(sm, &identity_len); + } else { + struct eap_peer_config *config; + + config = eap_get_config(sm); + if (config && config->imsi_identity) { + identity = config->imsi_identity; + identity_len = config->imsi_identity_len; + } else { + identity = eap_get_config_identity(sm, &identity_len); + } + } wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK " "derivation", identity, identity_len); if (data->eap_method == EAP_TYPE_AKA_PRIME) { @@ -1171,6 +1184,7 @@ static struct wpabuf * eap_aka_process_notification( eap_sim_report_notification(sm->msg_ctx, attr->notification, 1); if (attr->notification >= 0 && attr->notification < 32768) { + data->error_code = attr->notification; eap_aka_state(data, FAILURE); } else if (attr->notification == EAP_SIM_SUCCESS && data->state == RESULT_SUCCESS) @@ -1514,6 +1528,20 @@ static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) return key; } +static int eap_aka_get_error_code(void *priv) +{ + struct eap_aka_data *data = priv; + + if (!data) + return NO_EAP_METHOD_ERROR; + + int current_data_error = data->error_code; + + /* Now reset for next transaction */ + data->error_code = NO_EAP_METHOD_ERROR; + + return current_data_error; +} int eap_peer_aka_register(void) { @@ -1535,6 +1563,7 @@ int eap_peer_aka_register(void) eap->init_for_reauth = eap_aka_init_for_reauth; eap->get_identity = eap_aka_get_identity; eap->get_emsk = eap_aka_get_emsk; + eap->get_error_code = eap_aka_get_error_code; return eap_peer_method_register(eap); } @@ -1562,6 +1591,7 @@ int eap_peer_aka_prime_register(void) eap->init_for_reauth = eap_aka_init_for_reauth; eap->get_identity = eap_aka_get_identity; eap->get_emsk = eap_aka_get_emsk; + eap->get_error_code = eap_aka_get_error_code; return eap_peer_method_register(eap); } diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index 16521c3a..d416afd5 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -46,6 +46,9 @@ struct eap_peer_config { */ size_t anonymous_identity_len; + u8 *imsi_identity; + size_t imsi_identity_len; + /** * password - Password string for EAP * diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h index 6ab24834..5b389690 100644 --- a/src/eap_peer/eap_i.h +++ b/src/eap_peer/eap_i.h @@ -14,6 +14,8 @@ #include "eap_peer/eap.h" #include "eap_common/eap_common.h" +#define NO_EAP_METHOD_ERROR (-1) + /* RFC 4137 - EAP Peer state machine */ typedef enum { @@ -206,6 +208,17 @@ struct eap_method { const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len); /** + * get_error_code - Get latest EAP method error code + * @priv: Pointer to private EAP method data from eap_method::init() + * Returns: An int for the EAP Method Error code if exists or + * NO_EAP_METHOD_ERROR otherwise + * + * This method is an optional handler that only EAP methods that need to + * report their error code need to implement. + */ + int (*get_error_code)(void *priv); + + /** * free - Free EAP method data * @method: Pointer to the method data registered with * eap_peer_method_register(). diff --git a/src/eap_peer/eap_proxy_qmi_oc.c b/src/eap_peer/eap_proxy_qmi_oc.c new file mode 100644 index 00000000..4c07da5e --- /dev/null +++ b/src/eap_peer/eap_proxy_qmi_oc.c @@ -0,0 +1,2300 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +#include "includes.h" +#include "common.h" + +#ifdef CONFIG_EAP_PROXY +#include "qmi_client.h" +#include "eap_proxy_qmi.h" +#include "qmi_client.h" +#include "qmi_idl_lib.h" +#include "authentication_service_v01.h" +#include "user_identity_module_v01.h" +#include "eap_config.h" +#include "common/wpa_ctrl.h" +#if defined(ANDROID) +#include <cutils/properties.h> +#ifdef CONFIG_EAP_PROXY_MDM_DETECT +#include "mdm_detect.h" +#endif /* CONFIG_EAP_PROXY_MDM_DETECT */ +#if defined(__BIONIC_FORTIFY) +#include <sys/system_properties.h> +#endif +#endif +#include <pthread.h> +#include <sys/syscall.h> +#include <sys/types.h> + +#define IMSI_LENGTH 15 +#define WPA_UIM_QMI_EVENT_MASK_CARD_STATUS \ + (1 << QMI_UIM_EVENT_CARD_STATUS_BIT_V01) +#define WPA_UIM_QMI_EVENT_READ_TRANSPARENT_REQ \ + (1 << QMI_UIM_READ_TRANSPARENT_REQ_V01) + +/* Default timeout (in milli-seconds) for synchronous QMI message */ +#define WPA_UIM_QMI_DEFAULT_TIMEOUT 5000 + +#define EAP_PROXY_PROPERTY_BASEBAND "ro.baseband" +#ifdef CONFIG_EAP_PROXY_MSM8994_TARGET +#define EAP_PROXY_TARGET_PLATFORM "ro.board.platform" +#endif /* CONFIG_EAP_PROXY_MSM8994_TARGET */ +#if defined(__BIONIC_FORTIFY) +#define EAP_PROXY_PROPERTY_BASEBAND_SIZE PROP_VALUE_MAX +#else +#define EAP_PROXY_PROPERTY_BASEBAND_SIZE 10 +#endif +#define EAP_PROXY_BASEBAND_VALUE_MSM "msm" +#define EAP_PROXY_BASEBAND_VALUE_APQ "apq" +#define EAP_PROXY_BASEBAND_VALUE_SVLTE1 "svlte1" +#define EAP_PROXY_BASEBAND_VALUE_SVLTE2A "svlte2a" +#define EAP_PROXY_BASEBAND_VALUE_SGLTE "sglte" +#define EAP_PROXY_BASEBAND_VALUE_CSFB "csfb" +#define EAP_PROXY_BASEBAND_VALUE_MDMUSB "mdm" +#ifdef CONFIG_EAP_PROXY_MSM8994_TARGET +#define EAP_PROXY_TARGET_PLATFORM_MSM8994 "msm8994" +#endif /* CONFIG_EAP_PROXY_MSM8994_TARGET */ +#define EAP_PROXY_TARGET_FUSION4_5_PCIE "fusion4_5_pcie" +#define EAP_PROXY_BASEBAND_VALUE_UNDEFINED "undefined" + +#ifndef ANDROID +#ifdef SYS_gettid +static inline pid_t gettid(void) +{ + return syscall(SYS_gettid); +} +#else +static inline pid_t gettid(void) +{ + return -1; +} +#endif +#endif + +static Boolean wpa_qmi_ssr = FALSE; +static void eap_proxy_qmi_deinit(struct eap_proxy_sm *eap_proxy); +static void eap_proxy_eapol_sm_set_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var, Boolean value); +struct eap_proxy_sm * +eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb, + void *msg_ctx); +static Boolean eap_proxy_eapol_sm_get_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var); + +/* Call-back function to process an authenticationr result indication from + * QMI EAP service */ +static void handle_qmi_eap_ind(qmi_client_type user_handle, + unsigned int msg_id, + void* ind_buf, + unsigned int ind_buf_len, + void* ind_cb_data); + +static u8 *eap_proxy_getKey(struct eap_proxy_sm *eap_proxy); +static enum eap_proxy_status eap_proxy_qmi_response_wait(struct eap_proxy_sm *eap_proxy); +static int eap_proxy_is_state_changed(struct eap_proxy_sm *sm); +static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy, + u8 *eapReqData, int eapReqDataLen, struct eap_sm *eap_sm); +static char bin_to_hexchar(u8 ch); + +static void wpa_qmi_client_indication_cb +( + qmi_client_type user_handle, + unsigned long msg_id, + unsigned char *ind_buf_ptr, + int ind_buf_len, + void *ind_cb_data +); +static void dump_buff(u8 *buff, int len); +#ifdef CONFIG_CTRL_IFACE +static const char *eap_proxy_sm_state_txt(int state); +#endif /* CONFIG_CTRL_IFACE */ +static Boolean eap_proxy_build_identity(struct eap_proxy_sm *eap_proxy, u8 id, + struct eap_sm *eap_sm); + +#ifdef SIM_AKA_IDENTITY_IMSI +static char *imsi; +static int imsi_len_g = 0; +static int card_mnc_len = -1; +#ifdef CONFIG_EAP_PROXY_DUAL_SIM +static unsigned int slot = 0; +static unsigned int session_type; +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + +static Boolean wpa_qmi_register_events(int sim_num, wpa_uim_struct_type *wpa_uim); +static Boolean wpa_qmi_read_card_imsi(int sim_num, wpa_uim_struct_type *wpa_uim); +static Boolean wpa_qmi_read_card_status(int sim_num, wpa_uim_struct_type *wpa_uim); +static Boolean wpa_qmi_register_auth_inds(struct eap_proxy_sm *eap_proxy); + +#endif +#define EAP_SUB_TYPE_SIM_START 0x0a +#define EAP_SUB_TYPE_AKA_IDENTITY 0x05 +#define EAP_RESP_TYPE_NAK 3 + + +#ifdef SIM_AKA_IDENTITY_IMSI +static void wpa_qmi_client_indication_cb +( + qmi_client_type user_handle, + unsigned long msg_id, + unsigned char *ind_buf_ptr, + int ind_buf_len, + void *ind_cb_data +) +{ + u32 decoded_payload_len = 0; + qmi_client_error_type qmi_err = QMI_NO_ERR; + void * decoded_payload = NULL; + struct eap_proxy_sm *eap_proxy = ind_cb_data; + uim_status_change_ind_msg_v01* status_change_ind_ptr = NULL; + struct wpa_supplicant *wpa_s = NULL; + u32 i, card_info_len = 0; + + wpa_printf(MSG_DEBUG, "eap_proxy: %s: msg_id=0x%lx", __func__, msg_id); + + if (user_handle == NULL) { + wpa_printf(MSG_ERROR, "eap_proxy: qmi_client_type missing in callback"); + return; + } + + if (eap_proxy == NULL) { + wpa_printf(MSG_ERROR, "eap_proxy: not initialized, discard client indiataion"); + return; + } + + if (ind_buf_ptr == NULL) { + wpa_printf(MSG_ERROR, "eap_proxy: indication buffer NULL, discard client indiataion"); + return; + } + + qmi_idl_get_message_c_struct_len(uim_get_service_object_v01(), + QMI_IDL_INDICATION, msg_id, + &decoded_payload_len); + + if(!decoded_payload_len) { + wpa_printf(MSG_ERROR, "eap_proxy: cann't decode payload, discard client indiataion"); + return; + } + + decoded_payload = os_zalloc(decoded_payload_len); + if (decoded_payload == NULL) { + wpa_printf(MSG_ERROR, "eap_proxy: failed to allocate memory"); + return; + } + + qmi_err = qmi_client_message_decode(user_handle, + QMI_IDL_INDICATION, msg_id, + ind_buf_ptr, ind_buf_len, + decoded_payload, decoded_payload_len); + + if (qmi_err == QMI_NO_ERR) { + switch (msg_id) { + case QMI_UIM_STATUS_CHANGE_IND_V01: + status_change_ind_ptr = (uim_status_change_ind_msg_v01*)decoded_payload; + if (!status_change_ind_ptr->card_status_valid) + goto fail; + + card_info_len = status_change_ind_ptr->card_status.card_info_len; + for (i = 0; i < card_info_len; i++) { + if(UIM_CARD_STATE_PRESENT_V01 != + status_change_ind_ptr->card_status.card_info[i].card_state) { + wpa_printf(MSG_DEBUG, "eap_proxy: %s SIM card removed. flush pmksa entries.", __func__); + eap_proxy->eapol_cb->eap_proxy_notify_sim_status(eap_proxy->ctx, SIM_STATE_ERROR); + break; /* only one flush will do */ + } + } + break; + default: + wpa_printf(MSG_DEBUG, "eap_proxy: Unknown QMI Indicaiton %lu", msg_id); + break; + } + } +fail: + os_free(decoded_payload); + return; +} + +static Boolean wpa_qmi_register_auth_inds(struct eap_proxy_sm *eap_proxy) +{ + qmi_client_error_type qmi_err_code = 0; + auth_indication_register_resp_msg_v01 event_resp_msg; + auth_indication_register_req_msg_v01 event_reg_params; + + /* Register for events first */ + os_memset(&event_reg_params, 0, sizeof(auth_indication_register_req_msg_v01)); + os_memset(&event_resp_msg, 0, sizeof(auth_indication_register_resp_msg_v01)); + + event_reg_params.report_eap_notification_code_valid = TRUE; + event_reg_params.report_eap_notification_code = 1; + + wpa_printf(MSG_DEBUG, "registering for notification codes\n"); + qmi_err_code = qmi_client_send_msg_sync( + eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim], + QMI_AUTH_INDICATION_REGISTER_REQ_V01, + (void *) &event_reg_params, + sizeof(auth_indication_register_req_msg_v01), + (void*) &event_resp_msg, + sizeof(auth_indication_register_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + if (qmi_err_code != QMI_NO_ERR || + (event_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01 && + event_resp_msg.resp.error != QMI_ERR_NO_EFFECT_V01)) { + wpa_printf(MSG_ERROR,"QMI-ERROR Error for " + "QMI_AUTH_INDICATION_REGISTER_REQ_V01, qmi_err_code=%d" + "Error=%d\n", qmi_err_code, + event_resp_msg.resp.error); + return FALSE; + } + + return TRUE; + +} + +static Boolean wpa_qmi_register_events(int sim_num, wpa_uim_struct_type *wpa_uim) +{ + qmi_client_error_type qmi_err_code = 0; + uim_event_reg_resp_msg_v01 event_resp_msg; + uim_event_reg_req_msg_v01 event_reg_params; + + /* Register for events first */ + os_memset(&event_reg_params, 0, sizeof(uim_event_reg_req_msg_v01)); + os_memset(&event_resp_msg, 0, sizeof(uim_event_reg_resp_msg_v01)); + + event_reg_params.event_mask |= (WPA_UIM_QMI_EVENT_MASK_CARD_STATUS); + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_EVENT_REG_REQ_V01, + (void *) &event_reg_params, + sizeof(uim_event_reg_req_msg_v01), + (void *) &event_resp_msg, + sizeof(uim_event_reg_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + wpa_printf(MSG_ERROR, "eap_proxy: QMI_UIM_EVENT_REG_REQ_V01, " + "qmi_err_code: 0x%x wpa_uim[%d].qmi_uim_svc_client_ptr =%p" + "Error=0x%x", qmi_err_code, sim_num, + wpa_uim[sim_num].qmi_uim_svc_client_ptr, + event_resp_msg.resp.error); + + if (qmi_err_code != QMI_NO_ERR || + (event_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01 && + event_resp_msg.resp.error != QMI_ERR_NO_EFFECT_V01)) { + wpa_printf(MSG_ERROR,"QMI-ERROR Error for " + "QMI_UIM_EVENT_REG_REQ_V01, qmi_err_code=%d" + "Error=%d\n", qmi_err_code, + event_resp_msg.resp.error); + return FALSE; + } + + if(event_resp_msg.event_mask_valid) + { + wpa_printf(MSG_ERROR, "eap_proxy: event_resp_msg.event=%d,\n", + event_resp_msg.event_mask); + + } + + if (wpa_qmi_read_card_status(sim_num, wpa_uim)) + return TRUE; + else { + wpa_printf(MSG_ERROR,"eap_proxy: Error while reading SIM card status\n"); + return FALSE; + } +} + +static Boolean wpa_qmi_read_card_status(int sim_num, wpa_uim_struct_type *wpa_uim) +{ + unsigned int i = 0, j = 0; + Boolean card_found = FALSE; + qmi_client_error_type qmi_err_code = 0; + uim_get_card_status_resp_msg_v01 card_status_resp_msg; + + wpa_printf (MSG_ERROR, "eap_proxy: reading card %d values\n", sim_num+1); + os_memset(&card_status_resp_msg, + 0, + sizeof(uim_get_card_status_resp_msg_v01)); + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_GET_CARD_STATUS_REQ_V01, + NULL, + 0, + (void *)&card_status_resp_msg, + sizeof(uim_get_card_status_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + if (qmi_err_code != QMI_NO_ERR || + card_status_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01) { + wpa_printf(MSG_ERROR, "QMI-ERROR Error for " + "QMI_UIM_GET_CARD_STATUS_REQ_V01, qmi_err_code: 0x%x\n " + "resp_err = %d \n", qmi_err_code, card_status_resp_msg.resp.error); + return FALSE; + } + + /* Updated global card status if needed */ + if (!card_status_resp_msg.card_status_valid || + (card_status_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01)) { + wpa_printf(MSG_ERROR, "eap_proxy: card_status is not valid !\n"); + return FALSE; + } + /* Update global in case of new card state or error code */ + i = sim_num; + if ( i < QMI_UIM_CARDS_MAX_V01 && + i < card_status_resp_msg.card_status.card_info_len ) { + wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].card_state: 0x%x\n", + card_status_resp_msg.card_status.card_info[i].card_state); + wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].error_code: 0x%x\n", + card_status_resp_msg.card_status.card_info[i].error_code); + + wpa_uim[sim_num].card_info[i].card_state = + card_status_resp_msg.card_status.card_info[i].card_state; + + wpa_uim[sim_num].card_info[i].card_error_code = + card_status_resp_msg.card_status.card_info[i].error_code; +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + do { + if (card_status_resp_msg.card_status.index_gw_pri != 0xFFFF) { + slot = (card_status_resp_msg.card_status.index_gw_pri & 0xFF00) >> 8; + if (slot == i) { + session_type = UIM_SESSION_TYPE_PRIMARY_GW_V01; + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status:" + " prime slot = %d\n", slot); + break; + } + } + if (card_status_resp_msg.card_status.index_gw_sec != 0xFFFF) { + slot = (card_status_resp_msg.card_status.index_gw_sec & 0xFF00) >> 8; + if (slot == i) { + session_type = UIM_SESSION_TYPE_SECONDARY_GW_V01; + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: " + "second slot = %d\n", slot); + break; + } + } + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: Not GW it's 1x\n"); + return FALSE; + }while(0); + + if (slot > 1){ + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: " + "INVALID slot = %d and i = %d\n", slot, i); + return FALSE; + } +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + + if (card_status_resp_msg.card_status.card_info[i].card_state == + UIM_CARD_STATE_PRESENT_V01) { + for (j = 0 ; j < QMI_UIM_APPS_MAX_V01 ; j++) { + wpa_uim[sim_num].card_info[i].app_type = card_status_resp_msg. + card_status.card_info[i].app_info[j].app_type; + + wpa_uim[sim_num].card_info[i].app_state = card_status_resp_msg. + card_status.card_info[i].app_info[j].app_state; + + if (((card_status_resp_msg.card_status.card_info[i]. + app_info[j].app_type == 1) || (card_status_resp_msg. + card_status.card_info[i].app_info[j].app_type == 2)) && + (card_status_resp_msg.card_status.card_info[i].app_info[j]. + app_state == UIM_APP_STATE_READY_V01)) { + wpa_printf(MSG_ERROR, "eap_proxy: card READY\n"); + wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].app_ty" + "pe: 0x%x\n", card_status_resp_msg.card_status. + card_info[i].app_info[j].app_type); + wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].app_sta" + "te : 0x%x\n", card_status_resp_msg.card_status + .card_info[i].app_info[j].app_state); + card_found = TRUE; + break; + } + } + } + + if (card_found) { + wpa_printf(MSG_ERROR, "eap_proxy: card found for SIM = %d\n", sim_num+1); + } + } + + if ((!card_found) || (i == QMI_UIM_CARDS_MAX_V01) || + (j == QMI_UIM_APPS_MAX_V01)) { + wpa_printf(MSG_ERROR, "eap_proxy: SIM/USIM not ready card_found=%d\n",card_found); + return FALSE; + } + + wpa_printf(MSG_ERROR, "eap_proxy: SIM/USIM ready\n"); + wpa_uim[sim_num].card_ready_idx = i; + + return TRUE; +} /* wpa_qmi_read_card_status */ + +static int check_for_3_digit() +{ + int mcc = 0,i =0; + /* + -- 3 digits if MCC belongs to this group: 302, 310, 311, 312, 313, 314, 315, + 316, 334, 348 (decimal) + -- 2 digits in all other cases + Note: imsi values are hex characters + */ + int valid_mcc[] = {302, 310, 311, 312, 313, 314, 315, 316, 334, 348}; + + mcc = ((imsi[0]-0x30)*100) + ((imsi[1]-0x30)*10) + (imsi[2]-0x30); + + wpa_printf(MSG_ERROR, "mcc from the SIM is %d\n", mcc); + for(i = 0; i < sizeof(valid_mcc)/sizeof(valid_mcc[0]); i++) + { + if(mcc == valid_mcc[i]) + return 1; + } + return 0; +} + +static Boolean wpa_qmi_read_card_imsi(int sim_num, wpa_uim_struct_type *wpa_uim) +{ + int length; + unsigned char *data; + int src = 0, dst = 0; + Boolean card_found = FALSE, + qmi_status = TRUE; + qmi_client_error_type qmi_err_code = 0; + uim_read_transparent_req_msg_v01 qmi_read_trans_req; + uim_read_transparent_resp_msg_v01 read_trans_resp; + card_mnc_len = -1; + + + os_memset(&read_trans_resp, 0, + sizeof(uim_read_transparent_resp_msg_v01)); + os_memset(&qmi_read_trans_req, 0, + sizeof(uim_read_transparent_req_msg_v01)); + + qmi_read_trans_req.read_transparent.length = 0; + qmi_read_trans_req.read_transparent.offset = 0; + qmi_read_trans_req.file_id.file_id = 0x6F07; + qmi_read_trans_req.file_id.path_len = 4; + +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + wpa_printf (MSG_ERROR, "eap_proxy: read_card_imsi: session_type = %d\n", session_type); + qmi_read_trans_req.session_information.session_type = session_type; +#else + qmi_read_trans_req.session_information.session_type = + UIM_SESSION_TYPE_PRIMARY_GW_V01; +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + qmi_read_trans_req.session_information.aid_len = 0; + + /* For USIM*/ + if ((wpa_uim[sim_num].card_info[wpa_uim[sim_num].card_ready_idx].app_type == + UIM_APP_TYPE_USIM_V01)) { + qmi_read_trans_req.file_id.path[0] = 0x00; + qmi_read_trans_req.file_id.path[1] = 0x3F; + qmi_read_trans_req.file_id.path[2] = 0xFF; + qmi_read_trans_req.file_id.path[3] = 0x7F; + + } else /* For SIM*/ + if ((wpa_uim[sim_num].card_info[wpa_uim[sim_num].card_ready_idx].app_type == + UIM_APP_TYPE_SIM_V01)) { + qmi_read_trans_req.file_id.path[0] = 0x00; + qmi_read_trans_req.file_id.path[1] = 0x3F; + qmi_read_trans_req.file_id.path[2] = 0x20; + qmi_read_trans_req.file_id.path[3] = 0x7F; + } + else { + return FALSE; + } + + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_READ_TRANSPARENT_REQ_V01, + (void *)&qmi_read_trans_req, + sizeof(uim_read_transparent_req_msg_v01), + (void *) &read_trans_resp, + sizeof(uim_read_transparent_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + if (QMI_NO_ERR != qmi_err_code || + read_trans_resp.resp.result != QMI_RESULT_SUCCESS_V01) { + wpa_printf(MSG_ERROR, "QMI-ERROR Unable to read IMSI from UIM service;" + " error_ret=%d; qmi_err=%d\n", qmi_err_code, + read_trans_resp.resp.error); + qmi_status = FALSE; + } + + if (QMI_NO_ERR == qmi_err_code) { + if (read_trans_resp.read_result_valid) { + length = + read_trans_resp.read_result.content_len; + data = + read_trans_resp.read_result.content; + wpa_printf(MSG_ERROR, + "eap_proxy: IMSI SIM content length = %d\n", + length); + + /* Received IMSI is in the 3GPP format + converting it into ascii string */ + imsi = os_zalloc(2 * length); + if (imsi == NULL) { + wpa_printf(MSG_ERROR, + "eap_proxy: Couldn't allocate memmory for imsi"); + return FALSE; + } + for (src = 1, dst = 0; + (src < length) && (dst < (length * 2)); + src++) { + wpa_printf(MSG_ERROR, + "eap_proxy: IMSI read from SIM = %d src %d\n", + data[src], src); + if(data[src] == 0xFF) { + break; + } + if (src > 1) { + imsi[dst] = bin_to_hexchar(data[src] & 0x0F); + dst++; + wpa_printf(MSG_ERROR, + "eap_proxy: IMSI dst = %d dst %d\n", + imsi[dst-1], dst); + } + /* Process upper part of byte for all bytes */ + imsi[dst] = bin_to_hexchar(data[src] >> 4); + dst++; + wpa_printf(MSG_ERROR, + "eap_proxy: IMSI dst = %d dst %d\n", + imsi[dst-1], dst); + } + imsi_len_g = (data[0]*2 - 1); //dst; + wpa_printf(MSG_ERROR, + "eap_proxy: IMSI first digit = %d read length = %d" + "imsi %20s\n", data[0],imsi_len_g, imsi); + } else{ + wpa_printf(MSG_ERROR, + "eap_proxy: IMSI read failure read_result_valid = %d\n", + read_trans_resp.read_result_valid); + qmi_status = FALSE; + } + } + /* READ EF_AD */ + /* if qmi_status is FALSE, UIM read for mnc may not be required - To Do */ + qmi_read_trans_req.file_id.file_id = 0x6FAD; + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_READ_TRANSPARENT_REQ_V01, + (void *)&qmi_read_trans_req, + sizeof(uim_read_transparent_req_msg_v01), + (void *)&read_trans_resp, + sizeof(uim_read_transparent_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + if (QMI_NO_ERR != qmi_err_code || + read_trans_resp.resp.result != QMI_RESULT_SUCCESS_V01) { + wpa_printf(MSG_ERROR, "QMI-ERROR Unable to read MNC from UIM service;" + " error_ret=%d; qmi_err=%d\n", qmi_err_code, + read_trans_resp.resp.error); + qmi_status = FALSE; + } + if (QMI_NO_ERR == qmi_err_code) { + if (read_trans_resp.read_result_valid) { + length = + read_trans_resp.read_result.content_len; + data = + read_trans_resp.read_result.content; + + if(length >= 4) + card_mnc_len = 0x0f & data[3]; + if ((card_mnc_len != 2) && (card_mnc_len != 3)) { + if(check_for_3_digit()) + card_mnc_len = 3; + else + card_mnc_len = 2; + wpa_printf(MSG_ERROR, "Failed to get MNC length from (U)SIM " + "assuming %d as mcc %s to 3 digit mnc group\n", + card_mnc_len, card_mnc_len == 3? "belongs":"not belongs"); + } + } + } + + + return qmi_status; +} /* wpa_qmi_read_card_imsi */ +#endif /* SIM_AKA_IDENTITY_IMSI */ + +#ifdef CONFIG_EAP_PROXY_MDM_DETECT +static int eap_modem_compatible(struct dev_info *mdm_detect_info) +{ + char args[EAP_PROXY_PROPERTY_BASEBAND_SIZE] = {0}; + int ret = 0; + + /* Get the hardware property */ + ret = property_get(EAP_PROXY_PROPERTY_BASEBAND, args, ""); + if (ret > EAP_PROXY_PROPERTY_BASEBAND_SIZE){ + wpa_printf(MSG_ERROR,"eap_proxy: property [%s] has size [%d] that exceeds max [%d]", + EAP_PROXY_PROPERTY_BASEBAND, + ret, + EAP_PROXY_PROPERTY_BASEBAND_SIZE); + return FALSE; + } + + /* This will check for the type of hardware, and if the hardware type + * needs external modem, it will check if the modem type is external */ + if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_APQ, args, 3)) { + for (ret = 0; ret < mdm_detect_info->num_modems; ret++) { + if (mdm_detect_info->mdm_list[ret].type == MDM_TYPE_EXTERNAL) { + wpa_printf(MSG_INFO, "eap_proxy: hardware supports external modem"); + return TRUE; + } + } + wpa_printf(MSG_ERROR, "eap_proxy: hardware does not support external modem"); + return FALSE; + } + return TRUE; +} +#endif /* CONFIG_EAP_PROXY_MDM_DETECT */ + +void wpa_qmi_register_notification(void *eloop_ctx, void *timeout_ctx) +{ + struct eap_proxy_sm *eap_proxy = eloop_ctx; + wpa_printf(MSG_DEBUG, "eap_proxy: %s", __func__); + + eap_proxy_qmi_deinit(eap_proxy); + eap_proxy_init(eap_proxy, NULL, NULL); +} + +void wpa_qmi_handle_ssr(qmi_client_type user_handle, qmi_client_error_type error, void *err_cb_data) +{ + struct eap_proxy_sm *eap_proxy = err_cb_data; + + wpa_printf(MSG_DEBUG, "eap_proxy: %s ", __func__); + + wpa_qmi_ssr = TRUE; + eloop_register_timeout(0, 0, wpa_qmi_register_notification, eap_proxy, NULL); +} + + +static void exit_proxy_init(int signum) +{ + pthread_exit(NULL); +} + +static void eap_proxy_post_init(struct eap_proxy_sm *eap_proxy) +{ + int qmiErrorCode; + int qmiRetCode; + qmi_idl_service_object_type qmi_client_service_obj[MAX_NO_OF_SIM_SUPPORTED]; + int index; + static Boolean flag = FALSE; + struct sigaction actions; + int ret = 0; + wpa_uim_struct_type *wpa_uim = eap_proxy->wpa_uim; +#ifdef CONFIG_EAP_PROXY_MDM_DETECT + struct dev_info mdm_detect_info; + + /* Call ESOC API to get the number of modems. + * If the number of modems is not zero, only then proceed + * with the eap_proxy intialization. + */ + ret = get_system_info(&mdm_detect_info); + if (ret > 0) + wpa_printf(MSG_ERROR, "eap_proxy: Failed to get system info, ret %d", ret); + + if (mdm_detect_info.num_modems == 0) { + eap_proxy->proxy_state = EAP_PROXY_DISABLED; + wpa_printf(MSG_ERROR, "eap_proxy: No Modem support for this target" + " number of modems is %d", mdm_detect_info.num_modems); + return; + } + wpa_printf(MSG_DEBUG, "eap_proxy: num_modems = %d", mdm_detect_info.num_modems); + + if(eap_modem_compatible(&mdm_detect_info) == FALSE) { + eap_proxy->proxy_state = EAP_PROXY_DISABLED; + wpa_printf(MSG_ERROR, "eap_proxy: build does not support EAP-SIM feature"); + return; + } +#endif /* CONFIG_EAP_PROXY_MDM_DETECT */ + + sigemptyset(&actions.sa_mask); + actions.sa_flags = 0; + actions.sa_handler = exit_proxy_init; + ret = sigaction(SIGUSR1,&actions,NULL); + if(ret < 0) + wpa_printf(MSG_DEBUG, "sigaction\n"); + eap_proxy->proxy_state = EAP_PROXY_INITIALIZE; + eap_proxy->qmi_state = QMI_STATE_IDLE; + eap_proxy->key = NULL; + eap_proxy->iskey_valid = FALSE; + eap_proxy->is_state_changed = FALSE; + eap_proxy->isEap = FALSE; + eap_proxy->eap_type = EAP_TYPE_NONE; + eap_proxy->user_selected_sim = 0; + +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + wpa_printf (MSG_ERROR, + "eap_proxy: eap_proxy Initializing for DUAL SIM build %d tid %d", + MAX_NO_OF_SIM_SUPPORTED, gettid()); +#else + wpa_printf (MSG_ERROR, + "eap_proxy: eap_proxy Initializing for Single SIM build %d tid %d", + MAX_NO_OF_SIM_SUPPORTED, gettid()); +#endif + + + for (index = 0; index < MAX_NO_OF_SIM_SUPPORTED; ++index) { + +#ifdef SIM_AKA_IDENTITY_IMSI + if (FALSE == eap_proxy->qmi_uim_svc_client_initialized[index]) { + qmi_client_os_params eap_os_params; + /* Init QMI_UIM service for EAP-SIM/AKA */ + os_memset(&eap_os_params, 0, sizeof(qmi_client_os_params)); + + qmiErrorCode = qmi_client_init_instance( + uim_get_service_object_v01(), + QMI_CLIENT_INSTANCE_ANY, + wpa_qmi_client_indication_cb, + eap_proxy, &eap_os_params, + 10000, + &wpa_uim[index].qmi_uim_svc_client_ptr); + + if ((wpa_uim[index].qmi_uim_svc_client_ptr == NULL) || (qmiErrorCode > 0)) { + wpa_printf(MSG_ERROR, "eap_proxy: Could not register with QMI UIM" + "Service, qmi_uim_svc_client_ptr: %p,qmi_err_code: %d\n", + wpa_uim[index].qmi_uim_svc_client_ptr, qmiErrorCode); + wpa_uim[index].qmi_uim_svc_client_ptr = NULL; + flag = FALSE; + continue; + } + eap_proxy->qmi_uim_svc_client_initialized[index] = TRUE; + + wpa_printf (MSG_ERROR, "eap_proxy: QMI uim service client initialized with" + "success tid is %d %p %d\n", + gettid(), wpa_uim[index].qmi_uim_svc_client_ptr, qmiErrorCode); + /* Register the card events with the QMI / UIM */ + wpa_qmi_register_events(index, wpa_uim); + qmiErrorCode = qmi_client_register_error_cb( + wpa_uim[index].qmi_uim_svc_client_ptr, wpa_qmi_handle_ssr, eap_proxy); + wpa_printf(MSG_DEBUG, + "eap_proxy: qmi_client_register_error_cb() status %d\n", qmiErrorCode); + wpa_qmi_ssr = FALSE; + } else + wpa_printf (MSG_ERROR, "eap_proxy: QMI uim service client is already init" + "ialized tid is %d \n", gettid()); + + + qmi_client_os_params eap_os_params; + os_memset(&eap_os_params, 0, sizeof(qmi_client_os_params)); + + qmiErrorCode = qmi_client_init_instance(auth_get_service_object_v01(), + QMI_CLIENT_INSTANCE_ANY, + handle_qmi_eap_ind, + eap_proxy, + &eap_os_params, + 10000, + &eap_proxy->qmi_auth_svc_client_ptr[index]); + + + if ((eap_proxy->qmi_auth_svc_client_ptr[index] == NULL) || (qmiErrorCode > 0)) { + wpa_printf(MSG_ERROR, "eap_proxy: Could not register with QMI auth Service " + "qmi_auth_svc_client_ptr: %p,qmi_err_code: %d\n", + eap_proxy->qmi_auth_svc_client_ptr[index], qmiErrorCode); + eap_proxy->qmi_auth_svc_client_ptr[index] = NULL; + flag = FALSE; + continue; + } + wpa_printf (MSG_ERROR, "eap_proxy: QMI auth service client initialized with success" + " tid is %d %p eapol_proxy=%p\n", gettid(), + eap_proxy->qmi_auth_svc_client_ptr[index], eap_proxy); + flag = TRUE; + /* Register for the notifications from QMI / AUTH */ + wpa_qmi_register_auth_inds(eap_proxy); +#endif /* SIM_AKA_IDENTITY_IMSI */ + } + + if ( flag == FALSE ) { + eap_proxy->proxy_state = EAP_PROXY_DISABLED; + wpa_printf(MSG_ERROR, "eap_proxy: flag = %d proxy init failed\n", flag); + return; + } + + eap_proxy->proxy_state = EAP_PROXY_IDLE; + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapSuccess, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapFail, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapRestart, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapResp, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, FALSE); + wpa_printf (MSG_ERROR, "eap_proxy: Eap_proxy initialized successfully" + " tid is %d \n", gettid()); + return; + +} + +int eap_auth_end_eap_session(qmi_client_type qmi_auth_svc_client_ptr) +{ + qmi_client_error_type qmiRetCode = 0; + auth_end_eap_session_resp_msg_v01 end_eap_session_resp_msg ; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_end_eap_session: Ending EAP auth session"); + + + /* Send QMI_AUTH_END_EAP_SESSION_REQ */ + + os_memset(&end_eap_session_resp_msg, + 0, + sizeof(auth_end_eap_session_resp_msg_v01)); + + qmiRetCode = qmi_client_send_msg_sync(qmi_auth_svc_client_ptr, + QMI_AUTH_END_EAP_SESSION_REQ_V01, + NULL, + 0, + (void *) &end_eap_session_resp_msg, + sizeof(auth_end_eap_session_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + if (QMI_NO_ERR != qmiRetCode || + end_eap_session_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01) { + wpa_printf(MSG_ERROR, "QMI-ERROR Unable to End the EAP session;" + " error_ret=%d; qmi_err=%d\n", qmiRetCode, + end_eap_session_resp_msg.resp.error); + return -1; + } + + wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_end_eap_session:" + " EAP auth session ended successfuly"); + + return 0; +} + +static void eap_proxy_schedule_thread(void *eloop_ctx, void *timeout_ctx) +{ + struct eap_proxy_sm *eap_proxy = eloop_ctx; + pthread_attr_t attr; + int ret = -1; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + ret = pthread_create(&eap_proxy->thread_id, &attr, eap_proxy_post_init, eap_proxy); + if(ret < 0) + wpa_printf(MSG_ERROR, "eap_proxy: starting thread is failed %d\n", ret); +} + +struct eap_proxy_sm * +eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb, + void *msg_ctx) +{ + int qmiErrorCode; + int qmiRetCode; + struct eap_proxy_sm *eap_proxy; + qmi_idl_service_object_type qmi_client_service_obj; + + wpa_printf(MSG_DEBUG, "eap_proxy: %s " + "wpa_qmi_ssr %d", __func__, wpa_qmi_ssr); + if(wpa_qmi_ssr) { + eap_proxy = eapol_ctx; + } else { + eap_proxy = os_malloc(sizeof(struct eap_proxy_sm)); + if (NULL == eap_proxy) { + wpa_printf(MSG_ERROR, "Error memory alloc for eap_proxy" + "eap_proxy_init\n"); + return NULL; + } + os_memset(eap_proxy, 0, sizeof(*eap_proxy)); + eap_proxy->ctx = eapol_ctx; + eap_proxy->eapol_cb = eapol_cb; + eap_proxy->msg_ctx = msg_ctx; + } + + eap_proxy->proxy_state = EAP_PROXY_DISABLED; + eap_proxy->qmi_state = QMI_STATE_IDLE; + eap_proxy->key = NULL; + eap_proxy->iskey_valid = FALSE; + eap_proxy->is_state_changed = FALSE; + eap_proxy->isEap = FALSE; + eap_proxy->eap_type = EAP_TYPE_NONE; + + /* delay the qmi client initialization after the eloop_run starts, + * in order to avoid the case of daemonize enabled, which exits the + * parent process that created the qmi client context. + */ + + eloop_register_timeout(0, 0, eap_proxy_schedule_thread, eap_proxy, NULL); + return eap_proxy; +} + + +static void eap_proxy_qmi_deinit(struct eap_proxy_sm *eap_proxy) +{ + int qmiRetCode; + int qmiErrorCode; + int index; + wpa_uim_struct_type *wpa_uim = eap_proxy->wpa_uim; + + if (NULL == eap_proxy) + return; + + pthread_kill(eap_proxy->thread_id, SIGUSR1); + eap_proxy->proxy_state = EAP_PROXY_DISABLED; + + for (index = 0; index < MAX_NO_OF_SIM_SUPPORTED; ++index) { + if (TRUE == eap_proxy->eap_auth_session_flag[index]) { + + /* end the current EAP session */ + if(eap_auth_end_eap_session(eap_proxy->qmi_auth_svc_client_ptr[index]) < 0 ){ + wpa_printf(MSG_ERROR, "eap_proxy: Unable to end the EAP session for" + " client %d", index+1); + } else { + wpa_printf(MSG_ERROR, "eap_proxy: Ended the QMI EAP session for " + "client %d\n", + index+1); + eap_proxy->eap_auth_session_flag[index] = FALSE; + } + } else { + wpa_printf (MSG_ERROR, "eap_proxy: session not started" + " for client = %d\n", index+1); + continue; + } + + if ((TRUE == eap_proxy->qmi_uim_svc_client_initialized[index])) { + qmiRetCode = qmi_client_release(wpa_uim[index].qmi_uim_svc_client_ptr); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf (MSG_ERROR, "eap_proxy: Unable to Releas the connection" + " to uim service for client=%d; error_ret=%d\n;", + index+1, qmiRetCode); + } + wpa_printf(MSG_ERROR, "eap_proxy: Released QMI UIM service client\n"); + eap_proxy->qmi_uim_svc_client_initialized[index] = FALSE; + } + + qmiRetCode = qmi_client_release(eap_proxy->qmi_auth_svc_client_ptr[index]); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf (MSG_ERROR, "eap_proxy: Unable to Releas the connection" + " to auth service for client=%d; error_ret=%d\n;", + index+1, qmiRetCode); + } else { + wpa_printf(MSG_ERROR, "eap_proxy: Released QMI EAP service client\n"); + } + + } + + if (NULL != eap_proxy->key) { + os_free(eap_proxy->key); + eap_proxy->key = NULL; + } + + eap_proxy->iskey_valid = FALSE; + eap_proxy->is_state_changed = FALSE; + eap_proxy->user_selected_sim = 0; + +} + +void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy) +{ + eap_proxy_qmi_deinit(eap_proxy); + if (eap_proxy != NULL) { + os_free(eap_proxy); + eap_proxy = NULL; + wpa_printf(MSG_INFO, "eap_proxy: eap_proxy Deinitialzed\n"); + } +} + +/* Call-back function to process an authentication result indication +* from QMI EAP service */ +static void handle_qmi_eap_ind(qmi_client_type user_handle, + unsigned int msg_id, + void* ind_buf, + unsigned int ind_buf_len, + void* ind_cb_data) +{ + qmi_client_error_type qmi_err; + auth_eap_session_result_ind_msg_v01 eap_session_result; + memset(&eap_session_result, 0, sizeof(auth_eap_session_result_ind_msg_v01)); + eap_session_result.eap_result = -1; + struct eap_proxy_sm *sm = (struct eap_proxy_sm *)ind_cb_data; + + auth_eap_notification_code_ind_msg_v01 eap_notification; + memset(&eap_notification, 0, sizeof(auth_eap_notification_code_ind_msg_v01)); + + wpa_printf(MSG_ERROR, "eap_proxy: Handle_qmi_eap_ind msgId =%d sm=%p\n", msg_id,sm); + /* Decode */ + + switch(msg_id) + { + case QMI_AUTH_EAP_SESSION_RESULT_IND_V01: + + qmi_err = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION, + msg_id, (void*)ind_buf, ind_buf_len, + &eap_session_result, + sizeof(auth_eap_session_result_ind_msg_v01)); + if (qmi_err != QMI_NO_ERR) + { + wpa_printf(MSG_ERROR, "eap_proxy: Error in qmi_client_message_de" + "code; error_code=%d \n", qmi_err); + sm->srvc_result = EAP_PROXY_QMI_SRVC_FAILURE; + return; + } + if ((eap_session_result.eap_result == 0) && + (QMI_STATE_RESP_TIME_OUT != sm->qmi_state)) { + sm->proxy_state = EAP_PROXY_AUTH_SUCCESS; + sm->qmi_state = QMI_STATE_RESP_RECEIVED; + wpa_printf(MSG_ERROR, "eap_proxy: Handle_qmi_eap_ind EAP PROXY AUTH" + " SUCCESS %p set to %d\n", + (void *)&sm->qmi_state, sm->qmi_state); + } else { + sm->proxy_state = EAP_PROXY_AUTH_FAILURE; + wpa_printf(MSG_ERROR, "eap_proxy: Handle_qmi_eap_ind EAP PROXY AUTH" + " FAILURE \n"); + } + sm->srvc_result = EAP_PROXY_QMI_SRVC_SUCCESS; + break; + + case QMI_AUTH_EAP_NOTIFICATION_CODE_IND_V01: + + qmi_err = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION, + msg_id, (void*)ind_buf, ind_buf_len, + &eap_notification, + sizeof(auth_eap_notification_code_ind_msg_v01)); + if (qmi_err != QMI_NO_ERR) + { + wpa_printf(MSG_ERROR, "eap_proxy: Error in qmi_client_" + "message_decode; error_code=%d \n", qmi_err); + } + sm->notification_code = eap_notification.eap_notification_code; + wpa_printf(MSG_ERROR, "eap_proxy: notificatio code is %x\n", + eap_notification.eap_notification_code); + break; + + default: + wpa_printf(MSG_ERROR, "eap_proxy: An unexpected msg Id=%d" + " is given\n", msg_id); + break; + } + + +} + + +/* Call-back function to process an EAP response from QMI EAP service */ +static void handle_qmi_eap_reply( + qmi_client_type userHandle, unsigned int msg_id, + void *resp_c_struct, unsigned int resp_c_struct_len, + void *userData, qmi_client_error_type sysErrCode) +{ + struct eap_proxy_sm *eap_proxy = (struct eap_proxy_sm *)userData; + auth_send_eap_packet_resp_msg_v01* rspData = + (auth_send_eap_packet_resp_msg_v01*)resp_c_struct; + + u8 *resp_data; + u32 length; + + wpa_printf(MSG_ERROR, "eap_proxy: %s started\n", __func__); + if (eap_proxy == NULL) { + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy is NULL"); + return; + } + if (QMI_STATE_RESP_PENDING == eap_proxy->qmi_state) { + + wpa_printf(MSG_ERROR, "eap_proxy: user_selected_sim = %d\n", + eap_proxy->user_selected_sim+1); + + + if (QMI_NO_ERR != sysErrCode) { + wpa_printf(MSG_ERROR, "eap_proxy: An error is encountered with" + " the request: sysErrorCode=%d\n", + sysErrCode); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + if (NULL == rspData) { + wpa_printf(MSG_ERROR, "eap_proxy: Response data is NULL\n"); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + if((QMI_AUTH_SEND_EAP_PACKET_REQ_V01 != msg_id) && + (QMI_AUTH_SEND_EAP_PACKET_EXT_REQ_V01 != msg_id)) + { + wpa_printf(MSG_ERROR, "eap_proxy: Invalid msgId =%d\n", msg_id); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + /* ensure the reply packet exists */ + if (rspData->eap_response_pkt_len <= 0 || + rspData->eap_response_pkt_len > QMI_AUTH_EAP_RESP_PACKET_EXT_MAX_V01) { + wpa_printf(MSG_ERROR, "eap_proxy: Reply packet is of invalid length %d" + " error %d result %d\n", rspData->eap_response_pkt_len, + rspData->resp.error, rspData->resp.result); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + length = rspData->eap_response_pkt_len; + eap_proxy->qmi_resp_data.eap_send_pkt_resp.length = length; + /* allocate a buffer to store the response data; size is EAP resp len field */ + eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data = + os_malloc(rspData->eap_response_pkt_len); + + resp_data = + (u8 *)eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data; + + if (NULL == resp_data) { + wpa_printf(MSG_ERROR, "eap_proxy: Unable to allocate memory for" + " reply packet\n"); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + + return; + } + + /* copy the response data to the allocated buffer */ + os_memcpy(resp_data, + rspData->eap_response_pkt, length); + eap_proxy->qmi_state = QMI_STATE_RESP_RECEIVED; + wpa_printf(MSG_ERROR, "eap_proxy: **HANDLE_QMI_EAP_REPLY CALLBACK ENDDED **"); + + wpa_printf(MSG_ERROR, "eap_proxy: Dump Resp Data len %d\n", length); + dump_buff(resp_data, length); + } + + return; +} + +static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy, + u8 *eapReqData, int eapReqDataLen, struct eap_sm *eap_sm) +{ + struct eap_hdr *hdr; + int qmiErrorCode; + enum eap_proxy_status proxy_status = EAP_PROXY_SUCCESS; + auth_send_eap_packet_req_msg_v01 eap_send_packet_req; + auth_send_eap_packet_resp_msg_v01 eap_send_packet_resp; + qmi_txn_handle async_txn_hdl = 0; + + auth_send_eap_packet_ext_req_msg_v01 eap_send_packet_ext_req; + auth_send_eap_packet_ext_resp_msg_v01 eap_send_packet_ext_resp; + + + hdr = (struct eap_hdr *)eapReqData; + if ((EAP_CODE_REQUEST == hdr->code) && + (EAP_TYPE_IDENTITY == eapReqData[4])) { + if (eap_proxy_eapol_sm_get_bool(eap_proxy, EAPOL_eapRestart) && + eap_proxy_eapol_sm_get_bool(eap_proxy, EAPOL_portEnabled)) { + wpa_printf (MSG_ERROR, "eap_proxy: Already Authenticated." + " Clear all the flags"); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapSuccess, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapFail, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapResp, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, FALSE); + if (eap_proxy->key) { + os_free(eap_proxy->key); + eap_proxy->key = NULL; + } + eap_proxy->iskey_valid = FALSE; + eap_proxy->is_state_changed = TRUE; + } + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapRestart, FALSE); + + if(eap_proxy_build_identity(eap_proxy, hdr->identifier, eap_sm)) { + eap_proxy->proxy_state = EAP_PROXY_IDENTITY; + } else { + wpa_printf(MSG_ERROR, "eap_proxy: Error in build identity\n"); + return EAP_PROXY_FAILURE; + } + } + wpa_printf(MSG_ERROR, "eap_proxy: ***********Dump ReqData len %d***********", + eapReqDataLen); + dump_buff(eapReqData, eapReqDataLen); + if (eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_MAX_V01) { + os_memset(&eap_send_packet_req, 0, sizeof(auth_send_eap_packet_req_msg_v01)); + os_memset(&eap_send_packet_resp, 0, sizeof(auth_send_eap_packet_resp_msg_v01)); + eap_send_packet_req.eap_request_pkt_len = eapReqDataLen ; + memcpy(eap_send_packet_req.eap_request_pkt, eapReqData, eapReqDataLen); + } else if (eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_EXT_MAX_V01) { + os_memset(&eap_send_packet_ext_req, 0, + sizeof(auth_send_eap_packet_ext_req_msg_v01)); + os_memset(&eap_send_packet_ext_resp, 0, + sizeof(auth_send_eap_packet_ext_resp_msg_v01)); + eap_send_packet_ext_req.eap_request_ext_pkt_len = eapReqDataLen; + memcpy(eap_send_packet_ext_req.eap_request_ext_pkt, eapReqData, eapReqDataLen); + } else { + wpa_printf(MSG_ERROR, "eap_proxy: Error in eap_send_packet_req\n"); + return EAP_PROXY_FAILURE; + } + + wpa_printf(MSG_ERROR, "eap_proxy: SIM selected by User: Selected sim = %d\n", + eap_proxy->user_selected_sim+1); + if (eap_proxy->qmi_state != QMI_STATE_IDLE) { + wpa_printf(MSG_ERROR, "Error in QMI state=%d\n", + eap_proxy->qmi_state); + return EAP_PROXY_FAILURE; + } + + wpa_printf (MSG_ERROR, "eap_proxy: In eap_proxy_process case %d\n", hdr->code); + eap_proxy->qmi_state = QMI_STATE_RESP_PENDING; + + if(eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_MAX_V01) { + qmiErrorCode = qmi_client_send_msg_async( + eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim], + QMI_AUTH_SEND_EAP_PACKET_REQ_V01, + (void *) &eap_send_packet_req, + sizeof(auth_send_eap_packet_req_msg_v01), + (void *) &eap_send_packet_resp, + sizeof(auth_send_eap_packet_resp_msg_v01), + &handle_qmi_eap_reply, eap_proxy, + &async_txn_hdl); + } else if(eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_EXT_MAX_V01) { + qmiErrorCode = qmi_client_send_msg_async( + eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim], + QMI_AUTH_SEND_EAP_PACKET_EXT_REQ_V01, + (void *) &eap_send_packet_ext_req, + sizeof(auth_send_eap_packet_ext_req_msg_v01), + (void *) &eap_send_packet_ext_resp, + sizeof(auth_send_eap_packet_ext_resp_msg_v01), + &handle_qmi_eap_reply, eap_proxy, + &async_txn_hdl); + } + + if (QMI_NO_ERR != qmiErrorCode) { + wpa_printf(MSG_ERROR, "QMI-ERROR Error in sending EAP packet;" + " error_code=%d\n", qmiErrorCode); + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, TRUE); + eap_proxy->qmi_state = QMI_STATE_RESP_PENDING; + return EAP_PROXY_FAILURE; + } else { + wpa_printf (MSG_ERROR, "eap_proxy: In eap_proxy_process case %d\n", hdr->code); + switch (hdr->code) { + case EAP_CODE_SUCCESS: + if (EAP_PROXY_SUCCESS != + eap_proxy_qmi_response_wait(eap_proxy)) { + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + return EAP_PROXY_FAILURE; + } else if( eap_proxy->proxy_state == EAP_PROXY_AUTH_SUCCESS ) { + eap_proxy_getKey(eap_proxy); + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapSuccess, TRUE); + /* + * RFC 4137 does not clear eapReq here, but this seems to be required + * to avoid processing the same request twice when state machine is + * initialized. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + + /* + * RFC 4137 does not set eapNoResp here, but this seems to be required + * to get EAPOL Supplicant backend state machine into SUCCESS state. In + * addition, either eapResp or eapNoResp is required to be set after + * processing the received EAP frame. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + + wpa_msg(eap_proxy->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS + "eap_proxy: EAP authentication completed successfully"); + + eap_proxy->is_state_changed = TRUE; + + /* Retrieve the keys and store*/ + } else if( eap_proxy->proxy_state == EAP_PROXY_AUTH_FAILURE ){ + + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapFail, TRUE); + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + eap_proxy->is_state_changed = TRUE; + + } + + break; + + case EAP_CODE_FAILURE: + wpa_printf (MSG_ERROR, + "eap_proxy: in eap_proxy_process case EAP_CODE_FAILURE\n"); + eap_proxy->proxy_state = EAP_PROXY_AUTH_FAILURE; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapFail, TRUE); + + /* + * RFC 4137 does not clear eapReq here, but this seems to be required + * to avoid processing the same request twice when state machine is + * initialized. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + + /* + * RFC 4137 does not set eapNoResp here. However, either eapResp or + * eapNoResp is required to be set after processing the received EAP + * frame. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + + wpa_msg(eap_proxy->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE + "EAP authentication failed notification code 0x%x", + eap_proxy->notification_code); + + eap_proxy->is_state_changed = TRUE; + break; + + case EAP_CODE_REQUEST: + eap_proxy->proxy_state = EAP_PROXY_SEND_RESPONSE; + if (EAP_PROXY_SUCCESS != + eap_proxy_qmi_response_wait(eap_proxy)) { + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + return EAP_PROXY_FAILURE; + } else { + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapResp, TRUE); + eap_proxy->proxy_state = + EAP_PROXY_SEND_RESPONSE; + } + + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + eap_proxy->is_state_changed = TRUE; + break; + + default: + wpa_printf(MSG_ERROR, "eap_proxy: Error in sending EAP packet;" + " error_code=%d\n", qmiErrorCode); + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + return EAP_PROXY_FAILURE; + } + } + + return EAP_PROXY_SUCCESS; +} + + + +static u8 *eap_proxy_getKey(struct eap_proxy_sm *eap_proxy) +{ + int qmiErrorCode; + int qmiRetCode; + + auth_get_eap_session_keys_resp_msg_v01 key_resp_msg; + os_memset(&key_resp_msg, 0, sizeof(auth_get_eap_session_keys_resp_msg_v01)); + + qmiRetCode = qmi_client_send_msg_sync( + eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim], + QMI_AUTH_GET_EAP_SESSION_KEYS_REQ_V01, + NULL, + 0, + (void *) &key_resp_msg, + sizeof(auth_get_eap_session_keys_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + + /* see if the MSK is acquired successfully */ + if (QMI_NO_ERR != qmiRetCode || key_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01) { + wpa_printf(MSG_ERROR, "QMI-ERROR Unable to get session keys;" + " err_code=%d qmiErr=%d\n", qmiRetCode, key_resp_msg.resp.error); + eap_proxy->key = NULL; + return NULL; + } + wpa_printf(MSG_ERROR, "eap_proxy: %s:session_key_len =%d", __func__, + key_resp_msg.session_key_len); + + if(key_resp_msg.session_key_len <=0 || + key_resp_msg.session_key_len > EAP_PROXY_KEYING_DATA_LEN) + { + return NULL; + + } + eap_proxy->key = os_malloc(EAP_PROXY_KEYING_DATA_LEN); + if(eap_proxy->key == NULL) + return NULL; + + memset(eap_proxy->key, 0, EAP_PROXY_KEYING_DATA_LEN); + memcpy(eap_proxy->key, key_resp_msg.session_key, key_resp_msg.session_key_len); + + eap_proxy->iskey_valid = TRUE; + eap_proxy->proxy_state = EAP_PROXY_AUTH_SUCCESS; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_getkey EAP KEYS "); + dump_buff(eap_proxy->key, EAP_PROXY_KEYING_DATA_LEN); + return eap_proxy->key; +} + + +/** + * eap_key_available - Get key availability (eapKeyAvailable variable) + * @sm: Pointer to EAP state machine allocated with eap_sm_init() + * Returns: 1 if EAP keying material is available, 0 if not + */ +int eap_proxy_key_available(struct eap_proxy_sm *sm) +{ + return sm ? sm->iskey_valid : 0; +} + + +static int eap_proxy_is_state_changed(struct eap_proxy_sm *sm) +{ + if (NULL == sm) + return 0; + + if (TRUE == sm->is_state_changed) { + sm->is_state_changed = FALSE; + return 1; + } else { + return 0; + } +} + + +/** + * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine + * @sm: Pointer to EAP state machine allocated with eap_sm_init() + * @len: Pointer to variable that will be set to number of bytes in the key + * Returns: Pointer to the EAP keying data or %NULL on failure + * + * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The + * key is available only after a successful authentication. EAP state machine + * continues to manage the key data and the caller must not change or free the + * returned data. + */ +const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len) +{ + if (sm == NULL || sm->key == NULL) { + *len = 0; + return NULL; + } + + *len = EAP_PROXY_KEYING_DATA_LEN; + return sm->key; +} + +/** + * eap_proxy_get_eapRespData - Get EAP response data + * @sm: Pointer to EAP state machine allocated with eap_sm_init() + * @len: Pointer to variable that will be set to the length of the response + * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure + * + * Fetch EAP response (eapRespData) from the EAP state machine. This data is + * available when EAP state machine has processed an incoming EAP request. The + * EAP state machine does not maintain a reference to the response after this + * function is called and the caller is responsible for freeing the data. + */ +struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *eap_proxy) +{ + struct wpabuf *resp; + int len; + //int i; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_get_eapRespData"); + if ( (eap_proxy == NULL) || + (eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data == NULL) + ) + { + return NULL; + } + + len = eap_proxy->qmi_resp_data.eap_send_pkt_resp.length; + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_get_eapRespData len = %d", len); + resp = wpabuf_alloc(len); + if (resp == NULL) { + wpa_printf(MSG_ERROR, "eap_proxy: buf allocation failed\n"); + return NULL; + } + + resp->used = len; + os_memcpy(resp->buf, eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data, + len); + /* + for (i = 0; i < len; i++) { + wpa_printf (MSG_ERROR, "%c", resp->buf[i]); + } + */ + os_free(eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data); + eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data = NULL; + eap_proxy->qmi_resp_data.eap_send_pkt_resp.length = 0; + + return resp; +} + + +static enum eap_proxy_status eap_proxy_qmi_response_wait(struct eap_proxy_sm *eap_proxy) +{ + + int count = 0; + + wpa_printf(MSG_DEBUG, "eap_proxy_qmi_response_wait: Start blocking " + "wait eap_proxy=%p",eap_proxy); + do { + count++; + if (count > QMI_RESP_TIME_OUT / 2) { + wpa_printf(MSG_ERROR, + "eap_proxy: eap_proxy_qmi_response_wait " + "!QMI STATE %d TIME_OUT\n", + eap_proxy->qmi_state); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + break; + } + + os_sleep(0, 2000); + + if ((QMI_STATE_RESP_RECEIVED == eap_proxy->qmi_state) || + (QMI_STATE_RESP_TIME_OUT == eap_proxy->qmi_state)) + break; + } while (1); + + wpa_printf(MSG_DEBUG, "eap_proxy: eap_proxy_qmi_response_wait: Wait done after %d " + "iterations: qmi_state=%d", count, + eap_proxy->qmi_state); + + if (QMI_STATE_RESP_TIME_OUT == eap_proxy->qmi_state) { + wpa_printf(MSG_ERROR, "eap_proxy: QMI state Response Time out\n"); + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + return EAP_PROXY_FAILURE; + } + eap_proxy->qmi_state = QMI_STATE_IDLE; + + return EAP_PROXY_SUCCESS; +} + + +static void eap_proxy_eapol_sm_set_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var, Boolean value) +{ + sm->eapol_cb->set_bool(sm->ctx, var, value); +} + + +static Boolean eap_proxy_eapol_sm_get_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var) +{ + return sm->eapol_cb->get_bool(sm->ctx, var); +} + + +int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm) +{ + if ((sm->proxy_state != EAP_PROXY_INITIALIZE) && + (sm->proxy_state != EAP_PROXY_DISABLED)) { + if (TRUE == sm->isEap) { + if(!eap_proxy_process(sm, sm->eapReqData, + sm->eapReqDataLen,eap_sm)) { + sm->proxy_state = EAP_PROXY_AUTH_FAILURE; + eap_proxy_eapol_sm_set_bool(sm, EAPOL_eapRestart, TRUE); + } + sm->isEap = FALSE; + } + } + return eap_proxy_is_state_changed(sm); +} + + +enum eap_proxy_status +eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData, + int eapReqDataLen) +{ + eap_proxy->eapReqData = eapReqData; + eap_proxy->eapReqDataLen = eapReqDataLen; + eap_proxy->isEap = TRUE; + return EAP_PROXY_SUCCESS; +} + + +u8 * eap_proxy_get_eap_session_id(struct eap_proxy_sm *sm, size_t *len) +{ + wpa_printf(MSG_ERROR, "%s: enter: not implemented\n", __func__); + return NULL; +} + + +u8 * eap_proxy_get_emsk(struct eap_proxy_sm *sm, size_t *len) +{ + wpa_printf(MSG_ERROR, "%s: enter: not implemented\n", __func__); + return NULL; +} + + +void eap_proxy_sm_abort(struct eap_proxy_sm *sm) +{ + wpa_printf(MSG_ERROR, "%s: enter: not implemented\n", __func__); + return; +} + + +static void dump_buff(u8 *buff, int len) +{ + int i ; + + wpa_printf(MSG_ERROR, "eap_proxy: ---- EAP Buffer----LEN %d\n",len); + for (i = 0; i < len; i++) { + if (0 == i%8) + wpa_printf(MSG_DEBUG, " \n"); + wpa_printf(MSG_ERROR, "eap_proxy: 0x%x ", buff[i]); + } + return; +} +static char bin_to_hexchar(u8 ch) +{ + if (ch < 0x0a) { + return ch + '0'; + } + return ch + 'a' - 10; +} +static Boolean eap_proxy_build_identity(struct eap_proxy_sm *eap_proxy, u8 id, struct eap_sm *eap_sm) +{ + struct eap_hdr *resp; + unsigned int len; + u8 identity_len = 0, ret; + u8 imsi_id_len = 0; + int mnc_len = -1; + u8 *pos; + int qmiRetCode; + u8 idx = 0, mcc_idx = 0; + unsigned char *identity = NULL; + unsigned char *imsi_identity = NULL; + auth_start_eap_session_req_msg_v01 eap_auth_start; + auth_start_eap_session_resp_msg_v01 eap_auth_start_resp; + auth_set_subscription_binding_req_msg_v01 sub_req_binding; + auth_set_subscription_binding_resp_msg_v01 sub_resp_binding; + + struct eap_method_type *m; + eap_identity_format_e identity_format = EAP_IDENTITY_ANNONYMOUS; + Boolean simEnabled = FALSE, akaEnabled = FALSE; + struct eap_peer_config *config = eap_get_config(eap_sm); + const char *realm_3gpp = "@wlan.mnc000.mcc000.3gppnetwork.org"; + int sim_num; + + wpa_printf(MSG_ERROR, "eap_proxy: %s\n", __func__); + sim_num = config->sim_num - 1; + os_memset(&eap_auth_start, 0, sizeof(eap_auth_start)); + os_memset(&eap_auth_start_resp, 0, sizeof(eap_auth_start_resp)); + + eap_auth_start.user_id_len = 0; + m = config->eap_methods; + + if (sim_num >= MAX_NO_OF_SIM_SUPPORTED || sim_num < 0) { + wpa_printf (MSG_ERROR, "eap_proxy: Invalid SIM selected sim by user = %d\n", + sim_num+1); + return FALSE; + } + wpa_printf(MSG_ERROR, "eap_proxy: User selected sim = %d\n", sim_num + 1); + + if (m != NULL) { + for (idx = 0; m[idx].vendor != EAP_VENDOR_IETF || + m[idx].method != EAP_TYPE_NONE; idx++) { + if (m[idx].method == EAP_TYPE_AKA) { + akaEnabled = TRUE; + eap_auth_start.eap_method_mask_valid = 1; + eap_auth_start.eap_method_mask |= QMI_AUTH_EAP_METHOD_MASK_AKA_V01; + wpa_printf(MSG_ERROR, "eap_proxy: AKA Enabled\n"); + } else if (m[idx].method == EAP_TYPE_SIM) { + simEnabled = TRUE; + eap_auth_start.eap_method_mask_valid = 1; + eap_auth_start.eap_method_mask |= QMI_AUTH_EAP_METHOD_MASK_SIM_V01; + wpa_printf(MSG_ERROR, "eap_proxy: SIM Enabled\n"); +#ifdef CONFIG_EAP_PROXY_AKA_PRIME + } else if (m[idx].method == EAP_TYPE_AKA_PRIME) { + eap_auth_start.eap_method_mask_valid = 1; + eap_auth_start.eap_method_mask |= + QMI_AUTH_EAP_METHOD_MASK_AKA_PRIME_V01; + wpa_printf(MSG_ERROR, "eap_proxy: AKA Prime Enabled\n"); +#endif /* CONFIG_EAP_PROXY_AKA_PRIME */ + } + } + } else { + wpa_printf(MSG_ERROR, "eap_proxy: eap_methods is NULL!\n"); + return FALSE; + } + + eap_auth_start.eap_method_mask_valid = 1; + + idx = 0; +#ifdef SIM_AKA_IMSI_RAW_ENABLED + + identity_format = EAP_IDENTITY_IMSI_RAW; + eap_auth_start.user_id_valid = 1; + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_RAW selected %d \n", + eap_auth_start.user_id_len); + +#else /* SIM_AKA_IMSI_RAW_ENABLED */ + + if (config->identity_len && config->identity != NULL) { + for (idx = 0; idx < config->identity_len; idx++) { + if (config->identity[idx] == 64) { + wpa_printf(MSG_ERROR, "eap_proxy: @ found \n"); + mcc_idx = idx; + if ((mcc_idx + 18) > config->identity_len) + mcc_idx = 0; + else { + /* Looking for mnc and mcc pattern */ + if (109 == config->identity[mcc_idx + 6] && + (110 == config->identity[mcc_idx + 7]) && + (99 == config->identity[mcc_idx + 8]) && + (109 == config->identity[mcc_idx + 13]) && + (99 == config->identity[mcc_idx + 14]) && + (99 == config->identity[mcc_idx + 15])) { + mcc_idx += 9; + } else + mcc_idx = 0; + } + break; + } + } + + wpa_printf(MSG_ERROR, "eap_proxy: idx %d\n", idx); + wpa_printf(MSG_ERROR, "eap_proxy: mcc idx %d\n", mcc_idx); + + if (!idx && (config->identity_len == 1)) { + /* config file : @ */ + config->identity_len = 0; + identity_format = EAP_IDENTITY_IMSI_3GPP_REALM; + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_3GPP_REALM " + "selected \n"); + } else if (idx && (idx < config->identity_len) && (config->identity != NULL)) { + + /* config file : <>@<> or <>@<wlan.mnc000.mcc000.<>.<> */ + identity_len = config->identity_len; + identity = os_malloc(config->identity_len); + + if (NULL != identity) { + os_memset(identity, 0, config->identity_len); + os_memcpy(identity, config->identity, + config->identity_len); + } + + /* To Do for 3GPP realm */ + identity_format = EAP_IDENTITY_CFG_3GPP_REALM; + eap_auth_start.user_id_valid = 1; + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_CFG_3GPP_REALM " + "selected %d \n", eap_auth_start.user_id_len); + + } else if ((idx == config->identity_len) && config->identity_len && + (config->identity != NULL)) { + + /* config file : <identity in RAW format >*/ + identity_len = config->identity_len; + identity = os_malloc(config->identity_len); + + if (NULL != identity) { + os_memset(identity, 0, config->identity_len); + os_memcpy(identity, config->identity, + config->identity_len); + } + + identity_format = EAP_IDENTITY_CFG_RAW; + eap_auth_start.user_id_valid = 1; + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_CFG_RAW selected %d \n", + eap_auth_start.user_id_len); + } else if (!idx && mcc_idx) { + + /* config file: @wlan.mnc000.mcc000.<>.<> */ + identity_len = config->identity_len; + identity = os_malloc(config->identity_len); + + if (NULL != identity) { + os_memset(identity, 0, config->identity_len); + os_memcpy(identity, config->identity, + config->identity_len); + } + + identity_format = EAP_IDENTITY_IMSI_3GPP_REALM; + eap_auth_start.user_id_valid = 1; + wpa_printf(MSG_ERROR, "eap_proxy: config EAP_IDENTITY_IMSI_3GPP_REALM " + "selected %d\n", eap_auth_start.user_id_len); + } + } else { + + if (config->anonymous_identity_len && config->anonymous_identity != NULL) { + + eap_auth_start.eap_meta_identity_len = config->anonymous_identity_len; + os_memcpy(&eap_auth_start.eap_meta_identity , + config->anonymous_identity , + config->anonymous_identity_len); + + identity_format = EAP_IDENTITY_ANNONYMOUS; + eap_auth_start.eap_meta_identity_valid = 1; + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_ANNONYMOUS selected user id " + "%d, annonymous %d\n", eap_auth_start.user_id_len, + eap_auth_start.eap_meta_identity_len); + } else { + /* config file doesn't contain any identity + generating IMSI@realm */ + identity_format = EAP_IDENTITY_IMSI_3GPP_REALM; + eap_auth_start.user_id_valid = 1; + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_3GPP_REALM id len %d\n", + eap_auth_start.user_id_len); + } + } +#endif /* SIM_AKA_IMSI_RAW_ENABLED */ + if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM || + identity_format == EAP_IDENTITY_IMSI_RAW || mcc_idx) { + + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_3GPP_REALM is selected\n"); + if (!wpa_qmi_read_card_status(sim_num, eap_proxy->wpa_uim)) { + wpa_printf(MSG_INFO, "eap_proxy: Read Card Status failed, return\n"); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } + + if (!wpa_qmi_read_card_imsi(sim_num, eap_proxy->wpa_uim)) { + wpa_printf(MSG_INFO, "eap_proxy: Read Card IMSI failed, return\n"); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } + + if (imsi == NULL) { + wpa_printf(MSG_INFO, "eap_proxy: IMSI not available, return\n"); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } else { + wpa_printf(MSG_ERROR, "eap_proxy: IMSI not NULL \n"); + if (NULL == identity) + wpa_printf(MSG_ERROR, + "eap_proxy: config file doesn't contain identity \n"); + else + wpa_printf(MSG_ERROR, "eap_proxy: config file contains identity\n"); + + wpa_printf(MSG_ERROR, "eap_proxy: eap_type: %d\n", eap_proxy->eap_type); + + if (!idx) { + + /* IMSI is expected as username */ + wpa_printf(MSG_ERROR, "eap_proxy: username is not available in" + " config picking IMSI \n"); + + if (config->identity_len > 1) + /* @realm provided in config */ + imsi_identity = + os_malloc(1 + IMSI_LENGTH + config->identity_len); + else if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM) + /* IMSI@realm not provided through config */ + imsi_identity = + os_malloc(1 + IMSI_LENGTH + os_strlen(realm_3gpp)); + else + /* IMSI RAW */ + imsi_identity = os_malloc(1 + IMSI_LENGTH); + + if (NULL == imsi_identity) { + wpa_printf(MSG_ERROR, "eap_proxy: Memory not available\n"); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } else { + if (config->identity_len > 1) + os_memset(imsi_identity, 0, + (1 + IMSI_LENGTH + config->identity_len)); + else if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM) + os_memset(imsi_identity, 0, + (1 + IMSI_LENGTH + os_strlen(realm_3gpp))); + else + os_memset(imsi_identity, 0, (1 + IMSI_LENGTH)); + + if (eap_proxy->eap_type == EAP_TYPE_SIM) + imsi_identity[0] = '1'; + else if (eap_proxy->eap_type == EAP_TYPE_AKA) + imsi_identity[0] = '0'; +#ifdef CONFIG_EAP_PROXY_AKA_PRIME + else if (eap_proxy->eap_type == EAP_TYPE_AKA_PRIME) + imsi_identity[0] = '6'; +#endif /* CONFIG_EAP_PROXY_AKA_PRIME */ + else + /* Default value is set as SIM */ + imsi_identity[0] = '1'; + + /* copying IMSI value */ + os_memcpy(imsi_identity + 1 , imsi , imsi_len_g); + + if (config->identity_len > 1 && NULL != identity) { + /* copying realm tag */ + os_memcpy(imsi_identity + 1 + imsi_len_g , identity, + config->identity_len); + imsi_id_len = imsi_len_g + 1 + config->identity_len; + os_free(identity); + identity = NULL; + } else if(identity_format == EAP_IDENTITY_IMSI_3GPP_REALM) { + /* realm is not available so append it */ + os_memcpy(imsi_identity + 1 + imsi_len_g, + realm_3gpp, os_strlen(realm_3gpp)); + imsi_id_len = imsi_len_g + 1 + + os_strlen(realm_3gpp); + } else + /* IMSI RAW */ + imsi_id_len = imsi_len_g + 1; + } + } else if (identity) { + /* idx is non-zero implies username available */ + imsi_identity = identity; + imsi_id_len = config->identity_len; + } + } + + if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM || mcc_idx) { + + if (0 == idx) { + /* id = @wlan.mnc000.mcc000.<>.<> realm exist + but need to insert mnc and mcc values */ + idx = imsi_len_g + 1; + } + + if (imsi_identity != NULL) { + /* mcc valus */ + imsi_identity[idx + 16] = imsi[0]; + imsi_identity[idx + 17] = imsi[1]; + imsi_identity[idx + 18] = imsi[2]; + } + + /* mnc valus */ + mnc_len = card_mnc_len; + wpa_printf(MSG_ERROR, "eap_proxy: card mnc len %d\n", card_mnc_len); + + if ((mnc_len == 2) && (imsi_identity != NULL)) { + imsi_identity[idx + 9] = '0'; + imsi_identity[idx + 10] = imsi[3]; + imsi_identity[idx + 11] = imsi[4]; + } else if ((mnc_len == 3) && (imsi_identity != NULL)) { + imsi_identity[idx + 9] = imsi[3]; + imsi_identity[idx + 10] = imsi[4]; + imsi_identity[idx + 11] = imsi[5]; + } + wpa_printf(MSG_ERROR, "eap_proxy: Appending 3gpp realm\n "); + } + identity = imsi_identity; + identity_len = imsi_id_len; + eap_auth_start.user_id_valid = 1; + } + + eap_auth_start.user_id_len = identity_len; + + if(identity_len >= QMI_AUTH_EAP_IDENTITY_MAX_CHAR_V01) + { + wpa_printf(MSG_ERROR, "eap_proxy: Invalid User Identity length =%d",identity_len); + return FALSE; + } + + if(identity) + { + memcpy(&eap_auth_start.user_id, identity, identity_len); + eap_auth_start.user_id_valid = 1; + } + + wpa_printf(MSG_ERROR, "eap_proxy: eap auth user identity - %20s length-%d\n ", + eap_auth_start.user_id, eap_auth_start.user_id_len); + + if ( (sim_num < 0) || (sim_num >= MAX_NO_OF_SIM_SUPPORTED)) { + wpa_printf(MSG_ERROR, "eap_proxy: SIM: Invalid SIM selected by " + "User: Selected sim = %d\n", sim_num+1); + return FALSE; + } + + + eap_proxy->user_selected_sim = sim_num; + wpa_printf(MSG_ERROR, "eap_proxy: SIM selected by User: Selected sim = %d\n", + eap_proxy->user_selected_sim+1); + + memset(&sub_req_binding, 0, sizeof(auth_set_subscription_binding_req_msg_v01)); + memset(&sub_resp_binding, 0, sizeof(auth_set_subscription_binding_resp_msg_v01)); +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + if (sim_num == 0) { + sub_req_binding.bind_subs = AUTH_PRIMARY_SUBS_V01; + qmiRetCode = qmi_client_send_msg_sync(eap_proxy->qmi_auth_svc_client_ptr[sim_num], + QMI_AUTH_SET_SUBSCRIPTION_BINDING_REQ_V01, + (void *) &sub_req_binding, + sizeof(auth_set_subscription_binding_req_msg_v01), + (void *) &sub_resp_binding, + sizeof(auth_set_subscription_binding_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + if ((QMI_NO_ERR != qmiRetCode || + sub_resp_binding.resp.result != QMI_RESULT_SUCCESS_V01 ) && + (QMI_ERR_OP_DEVICE_UNSUPPORTED_V01 != sub_resp_binding.resp.error)) { + wpa_printf(MSG_ERROR, "QMI-ERROR Unable to get the qmi_auth_set_subscriptio" + "n_binding for sim 1; error_ret=%d; error_code=%d\n", qmiRetCode, + sub_resp_binding.resp.error); + return FALSE; + } + wpa_printf (MSG_ERROR, "eap_proxy: Binded with PRIMARY Subscription\n"); + } else if (sim_num == 1) { + sub_req_binding.bind_subs = AUTH_SECONDARY_SUBS_V01; + qmiRetCode = qmi_client_send_msg_sync(eap_proxy->qmi_auth_svc_client_ptr[sim_num], + QMI_AUTH_SET_SUBSCRIPTION_BINDING_REQ_V01, + (void *) &sub_req_binding, + sizeof(auth_set_subscription_binding_req_msg_v01), + (void *) &sub_resp_binding, + sizeof(auth_set_subscription_binding_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + if (QMI_NO_ERR != qmiRetCode || + sub_resp_binding.resp.result != QMI_RESULT_SUCCESS_V01 ) { + wpa_printf(MSG_ERROR, "QMI-ERROR Unable to get the qmi_auth_set_subscriptio" + "n_binding for sim 2; error_ret=%d; error_code=%d\n", qmiRetCode, + sub_resp_binding.resp.error); + return FALSE; + } + + wpa_printf (MSG_ERROR, "eap_proxy: Binded with SECONDARY Subscription\n"); + } else { + wpa_printf(MSG_ERROR, "eap_proxy: Invalid SIM selected by User: " + "Selected sim = %d\n", sim_num+1); + return FALSE; + } +#endif + if (TRUE == eap_proxy->eap_auth_session_flag[sim_num]) { + if(eap_auth_end_eap_session(eap_proxy->qmi_auth_svc_client_ptr[sim_num]) < 0) { + wpa_printf(MSG_ERROR, "eap_proxy: Unable to end the EAP session;" + " sim_num%d;", sim_num); + } + eap_proxy->eap_auth_session_flag[sim_num] = FALSE; + } + + if (FALSE == eap_proxy->eap_auth_session_flag[sim_num]) { + wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start values\n"); + wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start.eap_method_mask = %d\n", + eap_auth_start.eap_method_mask); + wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start.user_id_len = %d\n", + eap_auth_start.user_id_len); + wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start.eap_meta_id_len = %d\n", + eap_auth_start.eap_meta_identity_len); + wpa_printf(MSG_ERROR, "eap_auth_start.eap_sim_aka_algo = %d\n", + eap_auth_start.eap_sim_aka_algo); + qmiRetCode = qmi_client_send_msg_sync(eap_proxy->qmi_auth_svc_client_ptr[sim_num], + QMI_AUTH_START_EAP_SESSION_REQ_V01, + (void *) &eap_auth_start, + sizeof(auth_start_eap_session_req_msg_v01), + (void *) &eap_auth_start_resp, + sizeof(auth_start_eap_session_resp_msg_v01), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + if (QMI_NO_ERR != qmiRetCode || + eap_auth_start_resp.resp.result != QMI_RESULT_SUCCESS_V01) { + wpa_printf(MSG_ERROR, " QMI-ERROR Unable to start the EAP session;" + " error_ret=%d; qmi_err=%d\n", qmiRetCode, + eap_auth_start_resp.resp.error); + if(eap_auth_start.eap_method_mask == QMI_AUTH_EAP_METHOD_MASK_AKA_PRIME_V01 && + eap_auth_start_resp.resp.error == QMI_ERR_INVALID_ARG_V01) + wpa_printf(MSG_ERROR, "QMI-ERROR AKA' not supported\n"); + + return FALSE; + } + eap_proxy->eap_auth_session_flag[sim_num] = TRUE; + eap_proxy->notification_code = 0; + eap_proxy->qmi_state = QMI_STATE_IDLE; + wpa_printf(MSG_ERROR, "eap_proxy: EAP session started" + " error_ret=%d; Resp=%d\n", qmiRetCode, + eap_auth_start_resp.resp.error); + } + + return TRUE; +} + + + +#ifdef CONFIG_CTRL_IFACE + +/** + * eap_proxyl_sm_get_status - Get EAP state machine status + * @sm: Pointer to EAP state machine allocated with eap_sm_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 EAP state machine for status information. This function fills in a + * text area with current status information from the EAPOL state machine. If + * the buffer (buf) is not large enough, status information will be truncated + * to fit the buffer. + */ +int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen, + int verbose) +{ + int len, ret; + + if (sm == NULL) + return 0; + + len = os_snprintf(buf, buflen, "eap_proxy: EAP state=%s\n", + eap_proxy_sm_state_txt(sm->proxy_state)); + if (len < 0 || (size_t)len >= buflen) + return 0; + + if (sm->eap_type != EAP_TYPE_NONE) { + char name[8]; + + if (sm->eap_type == EAP_TYPE_SIM) + os_strlcpy(name, "SIM", 4); + else if (sm->eap_type == EAP_TYPE_AKA) + os_strlcpy(name, "AKA", 4); + else if (sm->eap_type == EAP_TYPE_AKA_PRIME) + os_strlcpy(name, "AKA'", 5); + else + os_strlcpy(name, "Unknown", 8); + + ret = os_snprintf(buf + len, buflen - len, + "selectedMethod=%d (EAP-%s)\n", + sm->eap_type, name); + if (ret < 0 || (size_t)ret >= buflen - len) + return len; + len += ret; + } + + return len; +} + + +static const char *eap_proxy_sm_state_txt(int state) +{ + switch (state) { + case EAP_PROXY_INITIALIZE: + return "INITIALIZE"; + case EAP_PROXY_DISABLED: + return "DISABLED"; + case EAP_PROXY_IDLE: + return "IDLE"; + case EAP_PROXY_RECEIVED: + return "RECEIVED"; + case EAP_PROXY_GET_METHOD: + return "GET_METHOD"; + case EAP_PROXY_METHOD: + return "METHOD"; + case EAP_PROXY_SEND_RESPONSE: + return "SEND_RESPONSE"; + case EAP_PROXY_DISCARD: + return "DISCARD"; + case EAP_PROXY_IDENTITY: + return "IDENTITY"; + case EAP_PROXY_NOTIFICATION: + return "NOTIFICATION"; + case EAP_PROXY_RETRANSMIT: + return "RETRANSMIT"; + case EAP_PROXY_AUTH_SUCCESS: + return "SUCCESS"; + case EAP_PROXY_AUTH_FAILURE: + return "FAILURE"; + default: + return "UNKNOWN"; + } +} +#endif /* CONFIG_CTRL_IFACE */ + + +/** + * eap_proxy_get_mcc_mnc - Get MCC/MNC + * @imsi_buf: Buffer for returning IMSI + * @imsi_len: Buffer for returning IMSI length + * Returns: MNC length (2 or 3) or -1 on error + */ +int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf, + size_t *imsi_len) +{ +#ifdef SIM_AKA_IDENTITY_IMSI + int mnc_len; + int sim_num = eap_proxy->user_selected_sim; + + if ((eap_proxy->proxy_state == EAP_PROXY_DISABLED) || + (eap_proxy->proxy_state == EAP_PROXY_INITIALIZE)) { + wpa_printf(MSG_ERROR, "eap_proxy:%s: Not initialized\n", __func__); + return FALSE; + } + if (!wpa_qmi_read_card_status(sim_num, eap_proxy->wpa_uim)) { + wpa_printf(MSG_INFO, "eap_proxy: Card not ready"); + return -1; + } + + if (!wpa_qmi_read_card_imsi(sim_num, eap_proxy->wpa_uim) || imsi == NULL) { + wpa_printf(MSG_INFO, "eap_proxy: Failed to read card IMSI"); + return -1; + } + + *imsi_len = os_strlen(imsi); + os_memcpy(imsi_buf, imsi, *imsi_len + 1); + + mnc_len = card_mnc_len; + if (mnc_len < 2 || mnc_len > 3) + mnc_len = 3; /* Default to 3 if MNC length is unknown */ + + os_free(imsi); + imsi = NULL; + + return mnc_len; +#else /* SIM_AKA_IDENTITY_IMSI */ + return -1; +#endif /* SIM_AKA_IDENTITY_IMSI */ +} + +int eap_proxy_notify_config(struct eap_proxy_sm *eap_proxy, + struct eap_peer_config *config) +{ + int ret_val; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_notify_config\n"); + if (!eap_proxy) { + wpa_printf(MSG_ERROR, "eap_proxy: is NULL"); + return FALSE; + } + + if ((eap_proxy->proxy_state == EAP_PROXY_DISABLED) || + (eap_proxy->proxy_state == EAP_PROXY_INITIALIZE)) { + wpa_printf(MSG_ERROR, "eap_proxy: Not initialized\n"); + return FALSE; + } + + if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF, + EAP_TYPE_SIM)) { + eap_proxy->eap_type = EAP_TYPE_SIM; + ret_val = TRUE; + } else if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF, + EAP_TYPE_AKA)) { + eap_proxy->eap_type = EAP_TYPE_AKA; + ret_val = TRUE; + } else if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF, + EAP_TYPE_AKA_PRIME)) { + eap_proxy->eap_type = EAP_TYPE_AKA_PRIME; + ret_val = TRUE; + } else + ret_val = FALSE; + + return ret_val; +} + +int eap_proxy_allowed_method(struct eap_peer_config *config, int vendor, + u32 method) +{ + int i; + struct eap_method_type *m; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_allowed_method"); + if (config == NULL || config->eap_methods == NULL) + return -1; + + m = config->eap_methods; + for (i = 0; m[i].vendor != EAP_VENDOR_IETF || + m[i].method != EAP_TYPE_NONE; i++) { + if (m[i].vendor == vendor && m[i].method == method) + return 1; + } + return 0; +} + +#endif /* CONFIG_EAP_PROXY */ diff --git a/src/eap_peer/eap_proxy_qmi_oc.h b/src/eap_peer/eap_proxy_qmi_oc.h new file mode 100644 index 00000000..f597afda --- /dev/null +++ b/src/eap_peer/eap_proxy_qmi_oc.h @@ -0,0 +1,140 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +#ifndef EAP_PROXY_QMI_H +#define EAP_PROXY_QMI_H + + +#include "eap_i.h" +#include "eap_config.h" +#include "eloop.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "user_identity_module_v01.h" + +/*msec Response Timeout*/ +#define QMI_RESP_TIME_OUT 2000 +#define EAP_PROXY_KEYING_DATA_LEN 64 + +#ifdef CONFIG_EAP_PROXY_DUAL_SIM +#define MAX_NO_OF_SIM_SUPPORTED 2 +#else +#define MAX_NO_OF_SIM_SUPPORTED 1 +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + +typedef enum { + QMI_STATE_IDLE = 0x00, + QMI_STATE_RESP_PENDING = 0x01, + QMI_STATE_RESP_RECEIVED = 0x02, + QMI_STATE_RESP_TIME_OUT = 0x03 +} qmi_state_e; + +typedef enum { + EAP_PROXY_QMI_SRVC_NO_RESULT, + EAP_PROXY_QMI_SRVC_SUCCESS, + EAP_PROXY_QMI_SRVC_FAILURE +} eap_proxy_qmi_srv_result; + +/* should match the EAP_state of eap_i.h */ +typedef enum { + EAP_PROXY_INITIALIZE, EAP_PROXY_DISABLED, EAP_PROXY_IDLE, EAP_PROXY_RECEIVED, + EAP_PROXY_GET_METHOD, EAP_PROXY_METHOD, EAP_PROXY_SEND_RESPONSE, + EAP_PROXY_DISCARD, EAP_PROXY_IDENTITY, EAP_PROXY_NOTIFICATION, + EAP_PROXY_RETRANSMIT, + EAP_PROXY_AUTH_SUCCESS, EAP_PROXY_AUTH_FAILURE +} eap_proxy_state; + + +enum eap_proxy_status { + EAP_PROXY_FAILURE = 0x00, + EAP_PROXY_SUCCESS +}; + +typedef enum { + EAP_IDENTITY_ANNONYMOUS = 0x00, + EAP_IDENTITY_IMSI_RAW = 0x02, + EAP_IDENTITY_IMSI_3GPP_REALM = 0x03, + EAP_IDENTITY_IMSI_REALM = 0x04, + EAP_IDENTITY_CFG_RAW = 0x05, + EAP_IDENTITY_CFG_3GPP_REALM = 0x06, + EAP_IDENTITY_CFG_REALM = 0x07, +} eap_identity_format_e; + +typedef union +{ + struct + { + void *resp_data; /* Pointer to the Response Packet*/ + unsigned long length; /*Length of the Response Packet*/ + }eap_send_pkt_resp; + +}qmi_eap_sync_rsp_data_type; + +typedef struct { + uim_card_state_enum_v01 card_state; + uim_card_error_code_enum_v01 card_error_code; + u8 app_state; + u8 app_type; +} wpa_uim_card_info_type; + +typedef struct { + int card_ready_idx; + wpa_uim_card_info_type card_info[QMI_UIM_CARDS_MAX_V01]; + qmi_client_type qmi_uim_svc_client_ptr; + int qmi_msg_lib_handle; +} wpa_uim_struct_type; + + +struct eap_proxy_sm { + qmi_client_type qmi_auth_svc_client_ptr[MAX_NO_OF_SIM_SUPPORTED]; + qmi_state_e qmi_state; + eap_proxy_qmi_srv_result srvc_result; + qmi_eap_sync_rsp_data_type qmi_resp_data; + eap_proxy_state proxy_state; + Boolean iskey_valid; + u8 *key; + Boolean is_state_changed; + void *ctx; + void *msg_ctx; + struct eapol_callbacks *eapol_cb; + u8 *eapReqData; + size_t eapReqDataLen; + Boolean isEap; + int eap_type; + int user_selected_sim; + int eap_auth_session_flag[MAX_NO_OF_SIM_SUPPORTED]; + int notification_code; + pthread_t thread_id; + wpa_uim_struct_type wpa_uim[MAX_NO_OF_SIM_SUPPORTED]; + Boolean qmi_uim_svc_client_initialized[MAX_NO_OF_SIM_SUPPORTED]; +}; + +int eap_proxy_allowed_method(struct eap_peer_config *config, int vendor, + u32 method); + +#endif /* EAP_PROXY_QMI_H */ diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index 25f592cd..c0896aaa 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -47,6 +47,7 @@ struct eap_sim_data { } state; int result_ind, use_result_ind; int use_pseudonym; + int error_code; }; @@ -94,6 +95,9 @@ static void * eap_sim_init(struct eap_sm *sm) return NULL; } + /* Zero is a valid error code, so we need to initialize */ + data->error_code = NO_EAP_METHOD_ERROR; + data->min_num_chal = 2; if (config && config->phase1) { char *pos = os_strstr(config->phase1, "sim_min_num_chal="); @@ -767,8 +771,17 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, } else if (data->pseudonym) { identity = data->pseudonym; identity_len = data->pseudonym_len; - } else - identity = eap_get_config_identity(sm, &identity_len); + } else { + struct eap_peer_config *config; + + config = eap_get_config(sm); + if (config && config->imsi_identity) { + identity = config->imsi_identity; + identity_len = config->imsi_identity_len; + } else { + identity = eap_get_config_identity(sm, &identity_len); + } + } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK " "derivation", identity, identity_len); eap_sim_derive_mk(identity, identity_len, data->nonce_mt, @@ -911,6 +924,7 @@ static struct wpabuf * eap_sim_process_notification( eap_sim_report_notification(sm->msg_ctx, attr->notification, 0); if (attr->notification >= 0 && attr->notification < 32768) { + data->error_code = attr->notification; eap_sim_state(data, FAILURE); } else if (attr->notification == EAP_SIM_SUCCESS && data->state == RESULT_SUCCESS) @@ -1234,6 +1248,20 @@ static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) return key; } +static int eap_sim_get_error_code(void *priv) +{ + struct eap_sim_data *data = priv; + + if (!data) + return NO_EAP_METHOD_ERROR; + + int current_data_error = data->error_code; + + /* Now reset for next transaction */ + data->error_code = NO_EAP_METHOD_ERROR; + + return current_data_error; +} int eap_peer_sim_register(void) { @@ -1255,6 +1283,7 @@ int eap_peer_sim_register(void) eap->init_for_reauth = eap_sim_init_for_reauth; eap->get_identity = eap_sim_get_identity; eap->get_emsk = eap_sim_get_emsk; + eap->get_error_code = eap_sim_get_error_code; return eap_peer_method_register(eap); } diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index 8e4f0e46..cb463ef2 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -2014,6 +2014,13 @@ static void eapol_sm_notify_status(void *ctx, const char *status, sm->ctx->status_cb(sm->ctx->ctx, status, parameter); } +static void eapol_sm_notify_eap_error(void *ctx, int error_code) +{ + struct eapol_sm *sm = ctx; + + if (sm->ctx->eap_error_cb) + sm->ctx->eap_error_cb(sm->ctx->ctx, error_code); +} #ifdef CONFIG_EAP_PROXY @@ -2062,6 +2069,7 @@ static const struct eapol_callbacks eapol_cb = eapol_sm_eap_param_needed, eapol_sm_notify_cert, eapol_sm_notify_status, + eapol_sm_notify_eap_error, #ifdef CONFIG_EAP_PROXY eapol_sm_eap_proxy_cb, eapol_sm_eap_proxy_notify_sim_status, diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index a25c7998..74f40bb1 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -271,6 +271,13 @@ struct eapol_ctx { void (*status_cb)(void *ctx, const char *status, const char *parameter); + /** + * eap_error_cb - Notification of EAP method error + * @ctx: Callback context (ctx) + * @error_code: EAP method error code + */ + void (*eap_error_cb)(void *ctx, int error_code); + #ifdef CONFIG_EAP_PROXY /** * eap_proxy_cb - Callback signifying any updates from eap_proxy diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 15b0e606..ff4a6ed7 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -505,7 +505,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4"); + wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Sending EAPOL-Key 2/4"); return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -545,7 +545,7 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, } wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way " + wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RX message 1 of 4-Way " "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); os_memset(&ie, 0, sizeof(ie)); @@ -1326,7 +1326,7 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, 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"); + wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Sending EAPOL-Key 4/4"); return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -1341,7 +1341,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, struct wpa_eapol_ie_parse ie; wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way " + wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RX message 3 of 4-Way " "Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver); key_info = WPA_GET_BE16(key->key_info); diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 3f6388d2..381846ab 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -341,22 +341,28 @@ int os_program_init(void) gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; if (!gid_wifi || !uid_wifi) return -1; + setgroups(ARRAY_SIZE(groups), groups); #else /* ANDROID_SETGROUPS_OVERRIDE */ - gid_t groups[3]; + gid_t groups[4]; + int group_idx = 0; if (!gid_wifi || !uid_wifi) return -1; - groups[0] = gid_wifi; + groups[group_idx] = gid_wifi; grp = getgrnam("inet"); - groups[1] = grp ? grp->gr_gid : 0; - if (!groups[1]) return -1; + groups[++group_idx] = grp ? grp->gr_gid : 0; + if (!groups[group_idx]) return -1; grp = getgrnam("keystore"); - groups[2] = grp ? grp->gr_gid : 0; - if (!groups[2]) return -1; -#endif /* ANDROID_SETGROUPS_OVERRIDE */ + groups[++group_idx] = grp ? grp->gr_gid : 0; + if (!groups[group_idx]) return -1; - setgroups(ARRAY_SIZE(groups), groups); + grp = getgrnam("log"); + groups[++group_idx] = grp ? grp->gr_gid : 0; + if (!groups[group_idx]) group_idx--; + + setgroups(group_idx + 1, groups); +#endif /* ANDROID_SETGROUPS_OVERRIDE */ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index df278351..d57446ce 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -65,11 +65,11 @@ L_CFLAGS += -DCONFIG_NO_ROAMING endif # Use Android specific directory for control interface sockets -L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" -L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/misc/wifi/sockets\" +L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/wpa/sockets\" +L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/wpa/sockets\" # Use Android specific directory for wpa_cli command completion history -L_CFLAGS += -DCONFIG_WPA_CLI_HISTORY_DIR=\"/data/misc/wifi\" +L_CFLAGS += -DCONFIG_WPA_CLI_HISTORY_DIR=\"/data/vendor/wifi/wpa\" # To force sizeof(enum) = 4 ifeq ($(TARGET_ARCH),arm) @@ -1723,6 +1723,7 @@ LOCAL_SHARED_LIBRARIES += libdbus endif ifeq ($(WPA_SUPPLICANT_USE_HIDL), y) LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.0 +LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.1 LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils libbase LOCAL_STATIC_LIBRARIES += libwpa_hidl endif @@ -1773,7 +1774,7 @@ LOCAL_VENDOR_MODULE := true LOCAL_CPPFLAGS := $(L_CPPFLAGS) LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_C_INCLUDES := $(INCLUDES) -HIDL_INTERFACE_VERSION = 1.0 +HIDL_INTERFACE_VERSION = 1.1 LOCAL_SRC_FILES := \ hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \ hidl/$(HIDL_INTERFACE_VERSION)/hidl_manager.cpp \ @@ -1784,11 +1785,11 @@ LOCAL_SRC_FILES := \ hidl/$(HIDL_INTERFACE_VERSION)/sta_network.cpp \ hidl/$(HIDL_INTERFACE_VERSION)/supplicant.cpp LOCAL_SHARED_LIBRARIES := \ - android.hardware.wifi.supplicant@$(HIDL_INTERFACE_VERSION) \ + android.hardware.wifi.supplicant@1.0 \ + android.hardware.wifi.supplicant@1.1 \ libbase \ libhidlbase \ libhidltransport \ - libhwbinder \ libutils \ liblog LOCAL_EXPORT_C_INCLUDE_DIRS := \ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a0d480ed..a22434cb 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2154,6 +2154,7 @@ static const struct parse_data ssid_fields[] = { { FUNC(eap) }, { STR_LENe(identity) }, { STR_LENe(anonymous_identity) }, + { STR_LENe(imsi_identity) }, { FUNC_KEY(password) }, { STRe(ca_cert) }, { STRe(ca_path) }, @@ -2411,6 +2412,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap) os_free(eap->eap_methods); bin_clear_free(eap->identity, eap->identity_len); os_free(eap->anonymous_identity); + os_free(eap->imsi_identity); bin_clear_free(eap->password, eap->password_len); os_free(eap->ca_cert); os_free(eap->ca_path); diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 0d708507..1fd432d1 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -761,6 +761,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) write_eap(f, ssid); STR(identity); STR(anonymous_identity); + STR(imsi_identity); STR(password); STR(ca_cert); STR(ca_path); diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c index 24f496b1..0ba1aa5e 100644 --- a/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant/config_winreg.c @@ -880,6 +880,7 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) write_eap(netw, ssid); STR(identity); STR(anonymous_identity); + STR(imsi_identity); STR(password); STR(ca_cert); STR(ca_path); diff --git a/wpa_supplicant/eap_proxy_qmi_oc.mak b/wpa_supplicant/eap_proxy_qmi_oc.mak new file mode 100644 index 00000000..0a046f62 --- /dev/null +++ b/wpa_supplicant/eap_proxy_qmi_oc.mak @@ -0,0 +1,19 @@ +CFLAGS += -DSIM_AKA_IDENTITY_IMSI +CFLAGS += -DSIM_AKA_IMSI_RAW_ENABLED + +CFLAGS += $(shell $(PKG_CONFIG) --cflags qmi qmi-framework) + +LIBS += $(shell $(PKG_CONFIG) --libs qmi qmi-framework) -lpthread + +# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). +# This requires CONFIG_EAP_AKA to be enabled, too. +# This is supported only in B Family devices. +CONFIG_EAP_AKA_PRIME=y + +ifdef CONFIG_EAP_PROXY_AKA_PRIME +CFLAGS += -DCONFIG_EAP_PROXY_AKA_PRIME +endif + +ifdef CONFIG_EAP_PROXY_DUAL_SIM +CFLAGS += -DCONFIG_EAP_PROXY_DUAL_SIM +endif diff --git a/wpa_supplicant/eap_proxy_qmi_oc.mk b/wpa_supplicant/eap_proxy_qmi_oc.mk new file mode 100644 index 00000000..fe0a4a9a --- /dev/null +++ b/wpa_supplicant/eap_proxy_qmi_oc.mk @@ -0,0 +1,37 @@ + +LOCAL_PATH := $(call my-dir) + +ifeq ($(BOARD_HAS_QCOM_WLAN), true) +L_CFLAGS += -DSIM_AKA_IDENTITY_IMSI +#L_CFLAGS += -DSIM_AKA_IMSI_RAW_ENABLED + +ifdef CONFIG_EAP_PROXY_DUAL_SIM +L_CFLAGS += -DCONFIG_EAP_PROXY_DUAL_SIM +endif + +LIB_SHARED_EAP_PROXY := libqmi_cci libqmiservices libidl +INCLUDES += $(TARGET_OUT_HEADERS)/qmi-framework/inc +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/inc +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/platform +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/core/lib/inc + +ifdef CONFIG_EAP_PROXY_MDM_DETECT +L_CFLAGS += -DCONFIG_EAP_PROXY_MDM_DETECT +INCLUDES += $(TARGET_OUT_HEADERS)/libmdmdetect/inc +LIB_SHARED_EAP_PROXY += libmdmdetect +endif + +# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). +# This requires CONFIG_EAP_AKA to be enabled, too. +# This is supported only in B Family devices. +ifdef CONFIG_EAP_PROXY_AKA_PRIME +L_CFLAGS += -DCONFIG_EAP_PROXY_AKA_PRIME +endif + +ifdef CONFIG_EAP_PROXY_MSM8994_TARGET +L_CFLAGS += -DCONFIG_EAP_PROXY_MSM8994_TARGET +endif + +#ANDROID_SETGROUPS_OVERRIDE := AID_RADIO AID_WIFI AID_KEYSTORE AID_DIAG AID_INET AID_QCOM_DIAG AID_NET_RAW +L_CFLAGS += -DANDROID_SETGROUPS_OVERRIDE=1001,1010,1017,2002,1003,3009,3004 +endif diff --git a/wpa_supplicant/hidl/1.0/hidl.cpp b/wpa_supplicant/hidl/1.0/hidl.cpp index ab2043de..ce8a4590 100644 --- a/wpa_supplicant/hidl/1.0/hidl.cpp +++ b/wpa_supplicant/hidl/1.0/hidl.cpp @@ -21,13 +21,14 @@ extern "C" { } using android::hardware::configureRpcThreadpool; -using android::hardware::IPCThreadState; +using android::hardware::setupTransportPolling; +using android::hardware::handleTransportPoll; using android::hardware::wifi::supplicant::V1_0::implementation::HidlManager; void wpas_hidl_sock_handler( - int /* sock */, void * /* eloop_ctx */, void * /* sock_ctx */) + int sock, void * /* eloop_ctx */, void * /* sock_ctx */) { - IPCThreadState::self()->handlePolledCommands(); + handleTransportPoll(sock); } struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global) @@ -43,7 +44,7 @@ struct wpas_hidl_priv *wpas_hidl_init(struct wpa_global *global) wpa_printf(MSG_DEBUG, "Initing hidl control"); configureRpcThreadpool(1, true /* callerWillJoin */); - IPCThreadState::self()->setupPolling(&priv->hidl_fd); + priv->hidl_fd = setupTransportPolling(); if (priv->hidl_fd < 0) goto err; @@ -76,7 +77,6 @@ void wpas_hidl_deinit(struct wpas_hidl_priv *priv) HidlManager::destroyInstance(); eloop_unregister_read_sock(priv->hidl_fd); - IPCThreadState::shutdown(); os_free(priv); } diff --git a/wpa_supplicant/hidl/1.0/p2p_iface.cpp b/wpa_supplicant/hidl/1.0/p2p_iface.cpp index ab4014d3..7a94a310 100644 --- a/wpa_supplicant/hidl/1.0/p2p_iface.cpp +++ b/wpa_supplicant/hidl/1.0/p2p_iface.cpp @@ -697,11 +697,13 @@ std::pair<SupplicantStatus, std::string> P2pIface::connectInternal( wps_method = WPS_PIN_KEYPAD; break; } + int vht = wpa_s->conf->p2p_go_vht; + int ht40 = wpa_s->conf->p2p_go_ht40 || vht; 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); + false, ht40, vht, VHT_CHANWIDTH_USE_HT, nullptr, 0); if (new_pin < 0) { return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}}; } diff --git a/wpa_supplicant/hidl/1.0/sta_network.cpp b/wpa_supplicant/hidl/1.0/sta_network.cpp index 72185b30..f4719417 100644 --- a/wpa_supplicant/hidl/1.0/sta_network.cpp +++ b/wpa_supplicant/hidl/1.0/sta_network.cpp @@ -1519,7 +1519,8 @@ SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthResponseInternal( 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())) { + wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(), + ctrl_rsp_param.size())) { return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } eapol_sm_notify_ctrl_response(wpa_s->eapol); @@ -1535,7 +1536,8 @@ SupplicantStatus StaNetwork::sendNetworkEapSimGsmAuthFailureInternal() 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)) { + wpa_s, wpa_ssid, rtype, kNetworkEapSimGsmAuthFailure, + strlen(kNetworkEapSimGsmAuthFailure))) { return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } eapol_sm_notify_ctrl_response(wpa_s->eapol); @@ -1568,7 +1570,8 @@ SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthResponseInternal( 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())) { + wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(), + ctrl_rsp_param.size())) { return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } eapol_sm_notify_ctrl_response(wpa_s->eapol); @@ -1592,7 +1595,8 @@ SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAutsResponseInternal( 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())) { + wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(), + ctrl_rsp_param.size())) { return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } eapol_sm_notify_ctrl_response(wpa_s->eapol); @@ -1608,7 +1612,8 @@ SupplicantStatus StaNetwork::sendNetworkEapSimUmtsAuthFailureInternal() 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)) { + wpa_s, wpa_ssid, rtype, kNetworkEapSimUmtsAuthFailure, + strlen(kNetworkEapSimUmtsAuthFailure))) { return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } eapol_sm_notify_ctrl_response(wpa_s->eapol); @@ -1623,7 +1628,8 @@ SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal( 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())) { + wpa_s, wpa_ssid, rtype, ctrl_rsp_param.data(), + ctrl_rsp_param.size())) { return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } eapol_sm_notify_ctrl_response(wpa_s->eapol); diff --git a/wpa_supplicant/hidl/1.1/hidl.cpp b/wpa_supplicant/hidl/1.1/hidl.cpp new file mode 100644 index 00000000..95194afa --- /dev/null +++ b/wpa_supplicant/hidl/1.1/hidl.cpp @@ -0,0 +1,645 @@ +/* + * 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::setupTransportPolling; +using android::hardware::handleTransportPoll; +using android::hardware::wifi::supplicant::V1_1::implementation::HidlManager; + +void wpas_hidl_sock_handler( + int sock, void * /* eloop_ctx */, void * /* sock_ctx */) +{ + handleTransportPoll(sock); +} + +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 */); + priv->hidl_fd = setupTransportPolling(); + 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); + 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) + return; + if (bssid) { + wpa_printf( + MSG_DEBUG, + "Notifying P2P invitation result to hidl control: " MACSTR, + MAC2STR(bssid)); + } else { + wpa_printf( + MSG_DEBUG, + "Notifying P2P invitation result to hidl control: NULL 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); +} + +void wpas_hidl_notify_eap_error( + struct wpa_supplicant *wpa_s, int error_code) +{ + if (!wpa_s) + return; + + wpa_printf( + MSG_DEBUG, + "Notifying EAP Error: %d ", error_code); + + HidlManager *hidl_manager = HidlManager::getInstance(); + if (!hidl_manager) + return; + + hidl_manager->notifyEapError(wpa_s, error_code); +} + diff --git a/wpa_supplicant/hidl/1.1/hidl.h b/wpa_supplicant/hidl/1.1/hidl.h new file mode 100644 index 00000000..1dfadc66 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/hidl.h @@ -0,0 +1,226 @@ +/* + * 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); +void wpas_hidl_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code); +#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) +{ +} +static void wpas_hidl_notify_eap_error( + struct wpa_supplicant *wpa_s, int error_code) +{ +} +#endif // CONFIG_CTRL_IFACE_HIDL + +#ifdef _cplusplus +} +#endif // _cplusplus + +#endif // WPA_SUPPLICANT_HIDL_HIDL_H diff --git a/wpa_supplicant/hidl/1.1/hidl_constants.h b/wpa_supplicant/hidl/1.1/hidl_constants.h new file mode 100644 index 00000000..988a5900 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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.1/hidl_i.h b/wpa_supplicant/hidl/1.1/hidl_i.h new file mode 100644 index 00000000..c7a01423 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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.1/hidl_manager.cpp b/wpa_supplicant/hidl/1.1/hidl_manager.cpp new file mode 100644 index 00000000..ca614d20 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/hidl_manager.cpp @@ -0,0 +1,1845 @@ +/* + * 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 CallbackTypeV1_0, class CallbackTypeV1_1> +void callWithEachIfaceCallback_1_1( + const std::string &ifname, + const std::function< + android::hardware::Return<void>(android::sp<CallbackTypeV1_1>)> &method, + const std::map<const std::string, std::vector<android::sp<CallbackTypeV1_0>>> + &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) { + android::sp<CallbackTypeV1_1> callback_1_1 = + CallbackTypeV1_1::castFrom(callback); + if (callback_1_1 == nullptr) + continue; + + if (!method(callback_1_1).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_1 { +namespace implementation { + +using namespace android::hardware::wifi::supplicant::V1_0; +using namespace android::hardware::wifi::supplicant::V1_1; +using V1_0::ISupplicantStaIfaceCallback; + +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; + + // Check if this interface is present in P2P map first, else check in + // STA map. + // Note: We can't use isP2pIface() here because interface + // pointers (wpa_s->global->p2p_init_wpa_s == wpa_s) used by the helper + // function is cleared by the core before notifying the HIDL interface. + bool success = + !removeHidlObjectFromMap(wpa_s->ifname, p2p_iface_object_map_); + if (success) { // assumed to be P2P + success = !removeAllIfaceCallbackHidlObjectsFromMap( + wpa_s->ifname, p2p_iface_callbacks_map_); + } else { // assumed to be STA + success = !removeHidlObjectFromMap( + wpa_s->ifname, sta_iface_object_map_); + if (success) { + success = !removeAllIfaceCallbackHidlObjectsFromMap( + wpa_s->ifname, sta_iface_callbacks_map_); + } + } + if (!success) { + wpa_printf( + MSG_ERROR, + "Failed to unregister interface with HIDL " + "control: %s", + wpa_s->ifname); + 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>( + abs(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) + 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 ? bssid : kZeroBssid, + 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)); +} + +void HidlManager::notifyEapError(struct wpa_supplicant *wpa_s, int error_code) +{ + typedef V1_1::ISupplicantStaIfaceCallback::EapErrorCode EapErrorCode; + + if (!wpa_s) + return; + + switch (static_cast<EapErrorCode>(error_code)) { + case EapErrorCode::SIM_GENERAL_FAILURE_AFTER_AUTH: + case EapErrorCode::SIM_TEMPORARILY_DENIED: + case EapErrorCode::SIM_NOT_SUBSCRIBED: + case EapErrorCode::SIM_GENERAL_FAILURE_BEFORE_AUTH: + case EapErrorCode::SIM_VENDOR_SPECIFIC_EXPIRED_CERT: + break; + default: + return; + } + + callWithEachStaIfaceCallback_1_1( + wpa_s->ifname, + std::bind( + &V1_1::ISupplicantStaIfaceCallback::onEapFailure_1_1, + std::placeholders::_1, + static_cast<EapErrorCode>(error_code))); +} + +/** + * 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 V1.1 iface callback hidl objects for the specified + * |ifname|. + * + * @param ifname Name of the corresponding interface. + * @param method Pointer to the required hidl method from + * |V1_1::ISupplicantIfaceCallback|. + */ +void HidlManager::callWithEachStaIfaceCallback_1_1( + const std::string &ifname, + const std::function<Return<void> + (android::sp<V1_1::ISupplicantStaIfaceCallback>)> &method) +{ + callWithEachIfaceCallback_1_1(ifname, method, sta_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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android diff --git a/wpa_supplicant/hidl/1.1/hidl_manager.h b/wpa_supplicant/hidl/1.1/hidl_manager.h new file mode 100644 index 00000000..4f100aae --- /dev/null +++ b/wpa_supplicant/hidl/1.1/hidl_manager.h @@ -0,0 +1,687 @@ +/* + * 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.1/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_1 { +namespace implementation { +using namespace android::hardware::wifi::supplicant::V1_0; +using namespace android::hardware::wifi::supplicant::V1_1; +using V1_0::ISupplicantStaIfaceCallback; + +/** + * 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); + void notifyEapError( + struct wpa_supplicant *wpa_s, int error_code); + + // 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 callWithEachStaIfaceCallback_1_1( + const std::string &ifname, + const std::function<android::hardware::Return<void>( + android::sp<V1_1::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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android +#endif // WPA_SUPPLICANT_HIDL_HIDL_MANAGER_H diff --git a/wpa_supplicant/hidl/1.1/hidl_return_util.h b/wpa_supplicant/hidl/1.1/hidl_return_util.h new file mode 100644 index 00000000..dba5f377 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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_1 { +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_1 +} // namespace supplicant +} // namespace wifi +} // namespace hardware +} // namespace android +#endif // HIDL_RETURN_UTIL_H_ diff --git a/wpa_supplicant/hidl/1.1/iface_config_utils.cpp b/wpa_supplicant/hidl/1.1/iface_config_utils.cpp new file mode 100644 index 00000000..7fe6d194 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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_1 { +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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android diff --git a/wpa_supplicant/hidl/1.1/iface_config_utils.h b/wpa_supplicant/hidl/1.1/iface_config_utils.h new file mode 100644 index 00000000..39f55487 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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_1 { +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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android + +#endif // WPA_SUPPLICANT_HIDL_IFACE_CONFIG_UTILS_H diff --git a/wpa_supplicant/hidl/1.1/misc_utils.h b/wpa_supplicant/hidl/1.1/misc_utils.h new file mode 100644 index 00000000..8b2ae3fa --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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_1 { +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_1 +} // namespace supplicant +} // namespace wifi +} // namespace hardware +} // namespace android +#endif // MISC_UTILS_H_ diff --git a/wpa_supplicant/hidl/1.1/p2p_iface.cpp b/wpa_supplicant/hidl/1.1/p2p_iface.cpp new file mode 100644 index 00000000..5de383d6 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/p2p_iface.cpp @@ -0,0 +1,1284 @@ +/* + * 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_1 { +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; + } + int vht = wpa_s->conf->p2p_go_vht; + int ht40 = wpa_s->conf->p2p_go_ht40 || vht; + 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, ht40, vht, 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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android diff --git a/wpa_supplicant/hidl/1.1/p2p_iface.h b/wpa_supplicant/hidl/1.1/p2p_iface.h new file mode 100644 index 00000000..019e5347 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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_1 { +namespace implementation { +using namespace android::hardware::wifi::supplicant::V1_0; + +/** + * 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 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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android + +#endif // WPA_SUPPLICANT_HIDL_P2P_IFACE_H diff --git a/wpa_supplicant/hidl/1.1/p2p_network.cpp b/wpa_supplicant/hidl/1.1/p2p_network.cpp new file mode 100644 index 00000000..7458fd94 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/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_1 { +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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android diff --git a/wpa_supplicant/hidl/1.1/p2p_network.h b/wpa_supplicant/hidl/1.1/p2p_network.h new file mode 100644 index 00000000..3c36f6df --- /dev/null +++ b/wpa_supplicant/hidl/1.1/p2p_network.h @@ -0,0 +1,103 @@ +/* + * 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_1 { +namespace implementation { +using namespace android::hardware::wifi::supplicant::V1_0; + +/** + * 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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android + +#endif // WPA_SUPPLICANT_HIDL_P2P_NETWORK_H diff --git a/wpa_supplicant/hidl/1.1/sta_iface.cpp b/wpa_supplicant/hidl/1.1/sta_iface.cpp new file mode 100644 index 00000000..64367451 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/sta_iface.cpp @@ -0,0 +1,1034 @@ +/* + * 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_1::ISupplicantStaIface; +using android::hardware::wifi::supplicant::V1_0::SupplicantStatus; +using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; +using android::hardware::wifi::supplicant::V1_1::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_1 { +namespace implementation { +using hidl_return_util::validateAndCall; + +using namespace android::hardware::wifi::supplicant::V1_0; +using namespace android::hardware::wifi::supplicant::V1_1; +using V1_0::ISupplicantStaIfaceCallback; + +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::registerCallback_1_1( + const sp<V1_1::ISupplicantStaIfaceCallback> &callback, + registerCallback_cb _hidl_cb) +{ + sp<V1_0::ISupplicantStaIfaceCallback> callback_1_0 = callback; + return validateAndCall( + this, SupplicantStatusCode::FAILURE_IFACE_INVALID, + &StaIface::registerCallbackInternal, _hidl_cb, callback_1_0); +} + +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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android diff --git a/wpa_supplicant/hidl/1.1/sta_iface.h b/wpa_supplicant/hidl/1.1/sta_iface.h new file mode 100644 index 00000000..1f1e64b3 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/sta_iface.h @@ -0,0 +1,255 @@ +/* + * 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.1/ISupplicantStaIface.h> +#include <android/hardware/wifi/supplicant/1.1/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_1 { +namespace implementation { +using namespace android::hardware::wifi::supplicant::V1_0; + +/** + * 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 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<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback> + & callback, registerCallback_cb _hidl_cb) override; + Return<void> registerCallback_1_1( + 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<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIfaceCallback> + & callback); + SupplicantStatus registerCallbackInternal_1_1( + 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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android + +#endif // WPA_SUPPLICANT_HIDL_STA_IFACE_H diff --git a/wpa_supplicant/hidl/1.1/sta_network.cpp b/wpa_supplicant/hidl/1.1/sta_network.cpp new file mode 100644 index 00000000..9d4cc913 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/sta_network.cpp @@ -0,0 +1,1888 @@ +/* + * 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_1 { +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::setEapEncryptedImsiIdentity( + const EapSimEncryptedIdentity &identity, setEapEncryptedImsiIdentity_cb _hidl_cb) +{ + return validateAndCall( + this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, + &StaNetwork::setEapEncryptedImsiIdentityInternal, _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); +} + +Return<void> StaNetwork::sendNetworkEapIdentityResponse_1_1( + const EapSimIdentity &identity, + const EapSimEncryptedIdentity &encrypted_imsi_identity, + sendNetworkEapIdentityResponse_1_1_cb _hidl_cb) +{ + return validateAndCall( + this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, + &StaNetwork::sendNetworkEapIdentityResponseInternal_1_1, _hidl_cb, + identity, encrypted_imsi_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, ""}; + } + // plain IMSI identity + if (setByteArrayFieldAndResetState( + identity.data(), identity.size(), &(wpa_ssid->eap.imsi_identity), + &(wpa_ssid->eap.imsi_identity_len), "eap imsi identity")) { + return { SupplicantStatusCode::FAILURE_UNKNOWN, ""}; + } + return {SupplicantStatusCode::SUCCESS, ""}; +} + +SupplicantStatus StaNetwork::setEapEncryptedImsiIdentityInternal( + const std::vector<uint8_t> &identity) +{ + struct wpa_ssid *wpa_ssid = retrieveNetworkPtr(); + // encrypted IMSI identity + if (setByteArrayFieldAndResetState( + identity.data(), identity.size(), &(wpa_ssid->eap.identity), + &(wpa_ssid->eap.identity_len), "eap encrypted imsi 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; + // Make sure that the supplicant is updated to the latest + // MAC address, which might have changed due to MAC randomization. + wpa_supplicant_update_mac_addr(wpa_s); + 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(), + ctrl_rsp_param.size())) { + 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, + strlen(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(), + ctrl_rsp_param.size())) { + 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(), + ctrl_rsp_param.size())) { + 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, + strlen(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(), + ctrl_rsp_param.size())) { + 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, ""}; +} + +SupplicantStatus StaNetwork::sendNetworkEapIdentityResponseInternal_1_1( + const std::vector<uint8_t> &identity, const std::vector<uint8_t> &encrypted_imsi_identity) +{ + struct wpa_ssid *wpa_ssid = retrieveNetworkPtr(); + // format: plain identity + ":" + encrypted identity(encrypted_imsi_identity) + std::string ctrl_rsp_param = + std::string(identity.begin(), identity.end()) + ":" + + std::string(encrypted_imsi_identity.begin(), encrypted_imsi_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(), + ctrl_rsp_param.size())) { + 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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android diff --git a/wpa_supplicant/hidl/1.1/sta_network.h b/wpa_supplicant/hidl/1.1/sta_network.h new file mode 100644 index 00000000..b6477731 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/sta_network.h @@ -0,0 +1,344 @@ +/* + * 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.1/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_1 { +namespace implementation { +using namespace android::hardware::wifi::supplicant::V1_0; + +/** + * 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 V1_1::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> setEapEncryptedImsiIdentity( + const EapSimEncryptedIdentity& identity, + setEapEncryptedImsiIdentity_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; + Return<void> sendNetworkEapIdentityResponse_1_1( + const EapSimIdentity& identity, + const EapSimEncryptedIdentity& imsiIdentity, + sendNetworkEapIdentityResponse_1_1_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 setEapEncryptedImsiIdentityInternal( + 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); + SupplicantStatus sendNetworkEapIdentityResponseInternal_1_1( + const std::vector<uint8_t>& identity, + const std::vector<uint8_t>& imsi_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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android + +#endif // WPA_SUPPLICANT_HIDL_STA_NETWORK_H diff --git a/wpa_supplicant/hidl/1.1/supplicant.cpp b/wpa_supplicant/hidl/1.1/supplicant.cpp new file mode 100644 index 00000000..4785c375 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/supplicant.cpp @@ -0,0 +1,423 @@ +/* + * 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" + +#include <android-base/file.h> +#include <fcntl.h> +#include <sys/stat.h> + +namespace { +// Pre-populated interface params for interfaces controlled by wpa_supplicant. +// Note: This may differ for other OEM's. So, modify this accordingly. +constexpr char kIfaceDriverName[] = "nl80211"; +constexpr char kStaIfaceConfPath[] = + "/data/vendor/wifi/wpa/wpa_supplicant.conf"; +constexpr char kStaIfaceConfOverlayPath[] = + "/vendor/etc/wifi/wpa_supplicant_overlay.conf"; +constexpr char kP2pIfaceConfPath[] = + "/data/vendor/wifi/wpa/p2p_supplicant.conf"; +constexpr char kP2pIfaceConfOverlayPath[] = + "/vendor/etc/wifi/p2p_supplicant_overlay.conf"; +// Migrate conf files for existing devices. +constexpr char kSystemTemplateConfPath[] = + "/system/etc/wifi/wpa_supplicant.conf"; +constexpr char kVendorTemplateConfPath[] = + "/vendor/etc/wifi/wpa_supplicant.conf"; +constexpr char kOldStaIfaceConfPath[] = + "/data/misc/wifi/wpa_supplicant.conf"; +constexpr char kOldP2pIfaceConfPath[] = + "/data/misc/wifi/p2p_supplicant.conf"; +constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + +int copyFile( + const std::string& src_file_path, const std::string& dest_file_path) +{ + std::string file_contents; + if (!android::base::ReadFileToString(src_file_path, &file_contents)) { + wpa_printf( + MSG_ERROR, "Failed to read from %s. Errno: %s", + src_file_path.c_str(), strerror(errno)); + return -1; + } + if (!android::base::WriteStringToFile( + file_contents, dest_file_path, kConfigFileMode, getuid(), + getgid())) { + wpa_printf( + MSG_ERROR, "Failed to write to %s. Errno: %s", + dest_file_path.c_str(), strerror(errno)); + return -1; + } + return 0; +} + +/** + * Copy |src_file_path| to |dest_file_path| if it exists. + * + * Returns 1 if |src_file_path| does not exist or not accessible, + * Returns -1 if the copy fails. + * Returns 0 if the copy succeeds. + */ +int copyFileIfItExists( + const std::string& src_file_path, const std::string& dest_file_path) +{ + int ret = access(src_file_path.c_str(), R_OK); + // Sepolicy denial (2018+ device) will return EACCESS instead of ENOENT. + if ((ret != 0) && ((errno == ENOENT) || (errno == EACCES))) { + return 1; + } + ret = copyFile(src_file_path, dest_file_path); + if (ret != 0) { + wpa_printf( + MSG_ERROR, "Failed copying %s to %s.", + src_file_path.c_str(), dest_file_path.c_str()); + return -1; + } + return 0; +} + +/** + * Ensure that the specified config file pointed by |config_file_path| exists. + * a) If the |config_file_path| exists with the correct permissions, return. + * b) If the |config_file_path| does not exist, but |old_config_file_path| + * exists, copy over the contents of the |old_config_file_path| to + * |config_file_path|. + * c) If the |config_file_path| & |old_config_file_path| + * does not exists, copy over the contents of |template_config_file_path|. + */ +int ensureConfigFileExists( + const std::string& config_file_path, + const std::string& old_config_file_path) +{ + int ret = access(config_file_path.c_str(), R_OK | W_OK); + if (ret == 0) { + return 0; + } + if (errno == EACCES) { + ret = chmod(config_file_path.c_str(), kConfigFileMode); + if (ret == 0) { + return 0; + } else { + wpa_printf( + MSG_ERROR, "Cannot set RW to %s. Errno: %s", + config_file_path.c_str(), strerror(errno)); + return -1; + } + } else if (errno != ENOENT) { + wpa_printf( + MSG_ERROR, "Cannot acces %s. Errno: %s", + config_file_path.c_str(), strerror(errno)); + return -1; + } + ret = copyFileIfItExists(old_config_file_path, config_file_path); + if (ret == 0) { + wpa_printf( + MSG_INFO, "Migrated conf file from %s to %s", + old_config_file_path.c_str(), config_file_path.c_str()); + unlink(old_config_file_path.c_str()); + return 0; + } else if (ret == -1) { + unlink(config_file_path.c_str()); + return -1; + } + ret = copyFileIfItExists(kVendorTemplateConfPath, config_file_path); + if (ret == 0) { + wpa_printf( + MSG_INFO, "Copied template conf file from %s to %s", + kVendorTemplateConfPath, config_file_path.c_str()); + return 0; + } else if (ret == -1) { + unlink(config_file_path.c_str()); + return -1; + } + ret = copyFileIfItExists(kSystemTemplateConfPath, config_file_path); + if (ret == 0) { + wpa_printf( + MSG_INFO, "Copied template conf file from %s to %s", + kSystemTemplateConfPath, config_file_path.c_str()); + return 0; + } else if (ret == -1) { + unlink(config_file_path.c_str()); + return -1; + } + // Did not create the conf file. + return -1; +} +} // namespace + +namespace android { +namespace hardware { +namespace wifi { +namespace supplicant { +namespace V1_1 { +namespace implementation { +using hidl_return_util::validateAndCall; + +Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {} +bool Supplicant::isValid() +{ + // This top level object cannot be invalidated. + return true; +} + +Return<void> Supplicant::addInterface( + const IfaceInfo& iface_info, addInterface_cb _hidl_cb) +{ + return validateAndCall( + this, SupplicantStatusCode::FAILURE_IFACE_INVALID, + &Supplicant::addInterfaceInternal, _hidl_cb, iface_info); +} + +Return<void> Supplicant::removeInterface( + const IfaceInfo& iface_info, removeInterface_cb _hidl_cb) +{ + return validateAndCall( + this, SupplicantStatusCode::FAILURE_IFACE_INVALID, + &Supplicant::removeInterfaceInternal, _hidl_cb, iface_info); +} + +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); +} + +Return<void> Supplicant::terminate() +{ + wpa_printf(MSG_INFO, "Terminating..."); + wpa_supplicant_terminate_proc(wpa_global_); + return Void(); +} + +std::pair<SupplicantStatus, sp<ISupplicantIface>> +Supplicant::addInterfaceInternal(const IfaceInfo& iface_info) +{ + android::sp<ISupplicantIface> iface; + + // Check if required |ifname| argument is empty. + if (iface_info.name.empty()) { + return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}}; + } + // Try to get the wpa_supplicant record for this iface, return + // the iface object with the appropriate status code if it exists. + SupplicantStatus status; + std::tie(status, iface) = getInterfaceInternal(iface_info); + if (status.code == SupplicantStatusCode::SUCCESS) { + return {{SupplicantStatusCode::FAILURE_IFACE_EXISTS, ""}, + iface}; + } + + struct wpa_interface iface_params = {}; + iface_params.driver = kIfaceDriverName; + if (iface_info.type == IfaceType::P2P) { + if (ensureConfigFileExists( + kP2pIfaceConfPath, kOldP2pIfaceConfPath) != 0) { + wpa_printf( + MSG_ERROR, "Conf file does not exists: %s", + kP2pIfaceConfPath); + return {{SupplicantStatusCode::FAILURE_UNKNOWN, + "Conf file does not exist"}, + {}}; + } + iface_params.confname = kP2pIfaceConfPath; + int ret = access(kP2pIfaceConfOverlayPath, R_OK); + if (ret == 0) { + iface_params.confanother = kP2pIfaceConfOverlayPath; + } + } else { + if (ensureConfigFileExists( + kStaIfaceConfPath, kOldStaIfaceConfPath) != 0) { + wpa_printf( + MSG_ERROR, "Conf file does not exists: %s", + kStaIfaceConfPath); + return {{SupplicantStatusCode::FAILURE_UNKNOWN, + "Conf file does not exist"}, + {}}; + } + iface_params.confname = kStaIfaceConfPath; + int ret = access(kStaIfaceConfOverlayPath, R_OK); + if (ret == 0) { + iface_params.confanother = kStaIfaceConfOverlayPath; + } + } + iface_params.ifname = iface_info.name.c_str(); + struct wpa_supplicant* wpa_s = + wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL); + if (!wpa_s) { + return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}}; + } + // The supplicant core creates a corresponding hidl object via + // HidlManager when |wpa_supplicant_add_iface| is called. + return getInterfaceInternal(iface_info); +} + +SupplicantStatus Supplicant::removeInterfaceInternal( + 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, ""}; + } + if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0)) { + return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; + } + return {SupplicantStatusCode::SUCCESS, ""}; +} + +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}; + } + // Set this flag true here, since there is no HIDL initialize method for the p2p + // config, and the supplicant interface is not ready when the p2p iface is created. + wpa_s->conf->persistent_reconnect = true; + 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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android diff --git a/wpa_supplicant/hidl/1.1/supplicant.h b/wpa_supplicant/hidl/1.1/supplicant.h new file mode 100644 index 00000000..327e0613 --- /dev/null +++ b/wpa_supplicant/hidl/1.1/supplicant.h @@ -0,0 +1,99 @@ +/* + * 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.1/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_1 { +namespace implementation { +using namespace android::hardware::wifi::supplicant::V1_0; + +/** + * Implementation of the supplicant hidl object. This hidl + * object is used core for global control operations on + * wpa_supplicant. + */ +class Supplicant : public V1_1::ISupplicant +{ +public: + Supplicant(struct wpa_global* global); + ~Supplicant() override = default; + bool isValid(); + + // Hidl methods exposed. + Return<void> addInterface( + const IfaceInfo& iface_info, addInterface_cb _hidl_cb) override; + Return<void> removeInterface( + const IfaceInfo& iface_info, removeInterface_cb _hidl_cb) override; + 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; + Return<void> terminate() override; + +private: + // Corresponding worker functions for the HIDL methods. + std::pair<SupplicantStatus, sp<ISupplicantIface>> getInterfaceInternal( + const IfaceInfo& iface_info); + std::pair<SupplicantStatus, sp<ISupplicantIface>> addInterfaceInternal( + const IfaceInfo& iface_info); + SupplicantStatus removeInterfaceInternal(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_1 +} // namespace wifi +} // namespace supplicant +} // namespace hardware +} // namespace android + +#endif // WPA_SUPPLICANT_HIDL_SUPPLICANT_H diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index a5db82c5..3832a33d 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -887,6 +887,12 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, status, parameter); } +void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code) +{ + wpa_dbg(wpa_s, MSG_ERROR, + "EAP Error code = %d", error_code); + wpas_hidl_notify_eap_error(wpa_s, error_code); +} void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 26b07f52..c3ac3d15 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -138,6 +138,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s, const u8 *ie, size_t ie_len, u32 ssi_signal); void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); +void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code); void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index f8e5bf7f..ee5710f1 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -6353,7 +6353,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, (const u8 *) value, os_strlen(value)); rtype = wpa_supplicant_ctrl_req_from_string(field); - return wpa_supplicant_ctrl_rsp_handle(wpa_s, ssid, rtype, value); + return wpa_supplicant_ctrl_rsp_handle(wpa_s, ssid, rtype, value, strlen(value)); #else /* IEEE8021X_EAPOL */ wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included"); return -1; @@ -6363,16 +6363,35 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, enum wpa_ctrl_req_type rtype, - const char *value) + const char *value, int value_len) { #ifdef IEEE8021X_EAPOL struct eap_peer_config *eap = &ssid->eap; + char *identity, *imsi_identity; switch (rtype) { case WPA_CTRL_REQ_EAP_IDENTITY: os_free(eap->identity); - eap->identity = (u8 *) os_strdup(value); - eap->identity_len = os_strlen(value); + os_free(eap->imsi_identity); + if (value == NULL) + return -1; + identity = os_strchr(value, ':'); + if (identity == NULL) { + /* plain identity */ + eap->identity = (u8 *)os_strdup(value); + eap->identity_len = os_strlen(value); + } else { + /* have both plain identity and encrypted identity */ + imsi_identity = value; + *identity++ = '\0'; + /* plain identity */ + eap->imsi_identity = (u8 *)dup_binstr(imsi_identity, strlen(imsi_identity)); + eap->imsi_identity_len = strlen(imsi_identity); + /* encrypted identity */ + eap->identity = (u8 *)dup_binstr(identity, + value_len - strlen(imsi_identity) - 1); + eap->identity_len = value_len - strlen(imsi_identity) - 1; + } eap->pending_req_identity = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; @@ -6380,7 +6399,7 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_PASSWORD: bin_clear_free(eap->password, eap->password_len); eap->password = (u8 *) os_strdup(value); - eap->password_len = os_strlen(value); + eap->password_len = value_len; eap->pending_req_password = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; @@ -6388,7 +6407,7 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_NEW_PASSWORD: bin_clear_free(eap->new_password, eap->new_password_len); eap->new_password = (u8 *) os_strdup(value); - eap->new_password_len = os_strlen(value); + eap->new_password_len = value_len; eap->pending_req_new_password = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; @@ -6403,7 +6422,7 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_OTP: bin_clear_free(eap->otp, eap->otp_len); eap->otp = (u8 *) os_strdup(value); - eap->otp_len = os_strlen(value); + eap->otp_len = value_len; os_free(eap->pending_req_otp); eap->pending_req_otp = NULL; eap->pending_req_otp_len = 0; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index d0172faf..acde7c5b 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1389,7 +1389,7 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, enum wpa_ctrl_req_type rtype, - const char *value); + const char *value, int len); void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index e44f6afa..e29f13ba 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -1037,6 +1037,12 @@ static void wpa_supplicant_status_cb(void *ctx, const char *status, wpas_notify_eap_status(wpa_s, status, parameter); } +static void wpa_supplicant_eap_error_cb(void *ctx, int error_code) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpas_notify_eap_error(wpa_s, error_code); +} static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len) { @@ -1115,6 +1121,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->cert_cb = wpa_supplicant_cert_cb; ctx->cert_in_cb = wpa_s->conf->cert_in_cb; ctx->status_cb = wpa_supplicant_status_cb; + ctx->eap_error_cb = wpa_supplicant_eap_error_cb; ctx->set_anon_id = wpa_supplicant_set_anon_id; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); |