/* * 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" #include "dpp_supplicant.h" #include "dpp.h" } namespace { using android::hardware::wifi::supplicant::V1_0::SupplicantStatus; using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode; using android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface; using android::hardware::wifi::supplicant::V1_2::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_2 { 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::registerCallback_1_2( const sp<V1_2::ISupplicantStaIfaceCallback> &callback, registerCallback_cb _hidl_cb) { sp<V1_1::ISupplicantStaIfaceCallback> callback_1_1 = callback; return validateAndCall( this, SupplicantStatusCode::FAILURE_IFACE_INVALID, &StaIface::registerCallbackInternal, _hidl_cb, callback_1_1); } 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); } Return<void> StaIface::getKeyMgmtCapabilities( getKeyMgmtCapabilities_cb _hidl_cb) { return validateAndCall( this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, &StaIface::getKeyMgmtCapabilitiesInternal, _hidl_cb); } Return<void> StaIface::addDppPeerUri(const hidl_string& uri, addDppPeerUri_cb _hidl_cb) { return validateAndCall( this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, &StaIface::addDppPeerUriInternal, _hidl_cb, uri); } Return<void> StaIface::removeDppUri(uint32_t bootstrap_id, removeDppUri_cb _hidl_cb) { return validateAndCall( this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, &StaIface::removeDppUriInternal, _hidl_cb, bootstrap_id); } Return<void> StaIface::startDppConfiguratorInitiator(uint32_t peer_bootstrap_id, uint32_t own_bootstrap_id, const hidl_string& ssid, const hidl_string& password, const hidl_string& psk, DppNetRole net_role, DppAkm security_akm, startDppConfiguratorInitiator_cb _hidl_cb) { return validateAndCall( this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, &StaIface::startDppConfiguratorInitiatorInternal, _hidl_cb, peer_bootstrap_id, own_bootstrap_id, ssid, password, psk, net_role, security_akm); } Return<void> StaIface::startDppEnrolleeInitiator(uint32_t peer_bootstrap_id, uint32_t own_bootstrap_id, startDppConfiguratorInitiator_cb _hidl_cb) { return validateAndCall( this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, &StaIface::startDppEnrolleeInitiatorInternal, _hidl_cb, peer_bootstrap_id, own_bootstrap_id); } Return<void> StaIface::stopDppInitiator(stopDppInitiator_cb _hidl_cb) { return validateAndCall( this, SupplicantStatusCode::FAILURE_NETWORK_INVALID, &StaIface::stopDppInitiatorInternal, _hidl_cb); } 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, 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, ""}; } std::pair<SupplicantStatus, uint32_t> StaIface::getKeyMgmtCapabilitiesInternal() { struct wpa_supplicant *wpa_s = retrieveIfacePtr(); struct wpa_driver_capa capa; uint32_t mask = 0; /* Get capabilities from driver and populate the key management mask */ if (wpa_drv_get_capa(wpa_s, &capa) < 0) { return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, mask}; } /* Logic from ctrl_iface.c, NONE and IEEE8021X have no capability * flags and always enabled. */ mask |= (ISupplicantStaNetwork::KeyMgmtMask::NONE | ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X); if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { mask |= ISupplicantStaNetwork::KeyMgmtMask::WPA_EAP; } if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { mask |= ISupplicantStaNetwork::KeyMgmtMask::WPA_PSK; } #ifdef CONFIG_SUITEB192 if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) { mask |= ISupplicantStaNetwork::KeyMgmtMask::SUITE_B_192; } #endif /* CONFIG_SUITEB192 */ #ifdef CONFIG_OWE if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) { mask |= ISupplicantStaNetwork::KeyMgmtMask::OWE; } #endif /* CONFIG_OWE */ #ifdef CONFIG_SAE if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) { mask |= ISupplicantStaNetwork::KeyMgmtMask::SAE; } #endif /* CONFIG_SAE */ #ifdef CONFIG_DPP if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) { mask |= ISupplicantStaNetwork::KeyMgmtMask::DPP; } #endif return {{SupplicantStatusCode::SUCCESS, ""}, mask}; } std::pair<SupplicantStatus, uint32_t> StaIface::addDppPeerUriInternal(const std::string& uri) { #ifdef CONFIG_DPP struct wpa_supplicant *wpa_s = retrieveIfacePtr(); int32_t id; id = wpas_dpp_qr_code(wpa_s, uri.c_str()); if (id > 0) { return {{SupplicantStatusCode::SUCCESS, ""}, id}; } #endif return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, -1}; } SupplicantStatus StaIface::removeDppUriInternal(uint32_t bootstrap_id) { #ifdef CONFIG_DPP struct wpa_supplicant *wpa_s = retrieveIfacePtr(); std::string bootstrap_id_str; if (bootstrap_id == 0) { bootstrap_id_str = "*"; } else { bootstrap_id_str = std::to_string(bootstrap_id); } if (dpp_bootstrap_remove(wpa_s->dpp, bootstrap_id_str.c_str()) >= 0) { return {SupplicantStatusCode::SUCCESS, ""}; } #endif return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } SupplicantStatus StaIface::startDppConfiguratorInitiatorInternal( uint32_t peer_bootstrap_id, uint32_t own_bootstrap_id, const std::string& ssid, const std::string& password, const std::string& psk, DppNetRole net_role, DppAkm security_akm) { #ifdef CONFIG_DPP struct wpa_supplicant *wpa_s = retrieveIfacePtr(); std::string cmd = ""; if (net_role != DppNetRole::AP && net_role != DppNetRole::STA) { wpa_printf(MSG_ERROR, "DPP: Error: Invalid network role specified: %d", net_role); return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } cmd += " peer=" + std::to_string(peer_bootstrap_id); cmd += (own_bootstrap_id > 0) ? " own=" + std::to_string(own_bootstrap_id) : ""; /* Check for supported AKMs */ if (security_akm != DppAkm::PSK && security_akm != DppAkm::SAE && security_akm != DppAkm::PSK_SAE) { wpa_printf(MSG_ERROR, "DPP: Error: invalid AKM specified: %d", security_akm); return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } /* SAE AKM requires SSID and password to be initialized */ if ((security_akm == DppAkm::SAE || security_akm == DppAkm::PSK_SAE) && (ssid.empty() || password.empty())) { wpa_printf(MSG_ERROR, "DPP: Error: Password or SSID not specified"); return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } else if (security_akm == DppAkm::PSK || security_akm == DppAkm::PSK_SAE) { /* PSK AKM requires SSID and password/psk to be initialized */ if (ssid.empty()) { wpa_printf(MSG_ERROR, "DPP: Error: SSID not specified"); return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } if (password.empty() && psk.empty()) { wpa_printf(MSG_ERROR, "DPP: Error: Password or PSK not specified"); return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } } cmd += " role=configurator"; cmd += (ssid.empty()) ? "" : " ssid=" + ssid; if (!psk.empty()) { cmd += " psk=" + psk; } else { cmd += (password.empty()) ? "" : " pass=" + password; } std::string role = ""; if (net_role == DppNetRole::AP) { role = "ap-"; } else { role = "sta-"; } switch (security_akm) { case DppAkm::PSK: role += "psk"; break; case DppAkm::SAE: role += "sae"; break; case DppAkm::PSK_SAE: role += "psk-sae"; break; default: wpa_printf(MSG_ERROR, "DPP: Invalid or unsupported security AKM specified: %d", security_akm); return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } cmd += " conf="; cmd += role; wpa_printf(MSG_DEBUG, "DPP initiator command: %s", cmd.c_str()); if (wpas_dpp_auth_init(wpa_s, cmd.c_str()) == 0) { return {SupplicantStatusCode::SUCCESS, ""}; } #endif return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } SupplicantStatus StaIface::startDppEnrolleeInitiatorInternal(uint32_t peer_bootstrap_id, uint32_t own_bootstrap_id) { #ifdef CONFIG_DPP struct wpa_supplicant *wpa_s = retrieveIfacePtr(); std::string cmd = ""; /* Report received configuration to HIDL and create an internal profile */ wpa_s->conf->dpp_config_processing = 1; cmd += " peer=" + std::to_string(peer_bootstrap_id); cmd += (own_bootstrap_id > 0) ? " own=" + std::to_string(own_bootstrap_id) : ""; cmd += " role=enrollee"; wpa_printf(MSG_DEBUG, "DPP initiator command: %s", cmd.c_str()); if (wpas_dpp_auth_init(wpa_s, cmd.c_str()) == 0) { return {SupplicantStatusCode::SUCCESS, ""}; } #endif return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; } SupplicantStatus StaIface::stopDppInitiatorInternal() { #ifdef CONFIG_DPP struct wpa_supplicant *wpa_s = retrieveIfacePtr(); wpas_dpp_stop(wpa_s); return {SupplicantStatusCode::SUCCESS, ""}; #else return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; #endif } /** * 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_2 } // namespace supplicant } // namespace wifi } // namespace hardware } // namespace android