| /* |
| * 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 |