blob: a4c2c3649c72119c9ead02cc0bccd7b44772557b [file] [log] [blame]
/*
* WPA Supplicant - Sta Iface Aidl interface
* Copyright (c) 2021, Google Inc. All rights reserved.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "aidl_manager.h"
#include "aidl_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.h"
#include "dpp_supplicant.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
}
namespace {
using aidl::android::hardware::wifi::supplicant::AidlManager;
using aidl::android::hardware::wifi::supplicant::BtCoexistenceMode;
using aidl::android::hardware::wifi::supplicant::ConnectionCapabilities;
using aidl::android::hardware::wifi::supplicant::DppCurve;
using aidl::android::hardware::wifi::supplicant::DppResponderBootstrapInfo;
using aidl::android::hardware::wifi::supplicant::ISupplicant;
using aidl::android::hardware::wifi::supplicant::ISupplicantStaIface;
using aidl::android::hardware::wifi::supplicant::ISupplicantStaNetwork;
using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
using aidl::android::hardware::wifi::supplicant::LegacyMode;
using aidl::android::hardware::wifi::supplicant::RxFilterType;
using aidl::android::hardware::wifi::supplicant::SupplicantStatusCode;
using aidl::android::hardware::wifi::supplicant::WifiTechnology;
using aidl::android::hardware::wifi::supplicant::misc_utils::createStatus;
// Enum definition copied from the Vendor HAL interface.
// See android.hardware.wifi.WifiChannelWidthInMhz
enum WifiChannelWidthInMhz {
WIDTH_20 = 0,
WIDTH_40 = 1,
WIDTH_80 = 2,
WIDTH_160 = 3,
WIDTH_80P80 = 4,
WIDTH_5 = 5,
WIDTH_10 = 6,
WIDTH_320 = 7,
WIDTH_INVALID = -1
};
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>(ISupplicant::EXT_RADIO_WORK_TIMEOUT_IN_SECS);
constexpr char kExtRadioWorkNamePrefix[] = "ext:";
uint8_t convertAidlRxFilterTypeToInternal(
RxFilterType type)
{
switch (type) {
case RxFilterType::V4_MULTICAST:
return 2;
case RxFilterType::V6_MULTICAST:
return 3;
};
WPA_ASSERT(false);
}
uint8_t convertAidlBtCoexModeToInternal(
BtCoexistenceMode mode)
{
switch (mode) {
case BtCoexistenceMode::ENABLED:
return 0;
case BtCoexistenceMode::DISABLED:
return 1;
case BtCoexistenceMode::SENSE:
return 2;
};
WPA_ASSERT(false);
}
ndk::ScopedAStatus 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 createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus 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());
}
ndk::ScopedAStatus 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);
AidlManager *aidl_manager = AidlManager::getInstance();
WPA_ASSERT(aidl_manager);
aidl_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 AIDL
// 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);
AidlManager *aidl_manager = AidlManager::getInstance();
WPA_ASSERT(aidl_manager);
aidl_manager->notifyExtRadioWorkStart(work->wpa_s, ework->id);
startExtRadioWork(work);
}
KeyMgmtMask convertWpaKeyMgmtCapabilitiesToAidl (
struct wpa_supplicant *wpa_s, struct wpa_driver_capa *capa) {
uint32_t mask = 0;
/* Logic from ctrl_iface.c, NONE and IEEE8021X have no capability
* flags and always enabled.
*/
mask |=
(static_cast<uint32_t>(KeyMgmtMask::NONE) |
static_cast<uint32_t>(KeyMgmtMask::IEEE8021X));
if (capa->key_mgmt &
(WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
mask |= static_cast<uint32_t>(KeyMgmtMask::WPA_EAP);
}
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
mask |= static_cast<uint32_t>(KeyMgmtMask::WPA_PSK);
}
#ifdef CONFIG_SUITEB192
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
mask |= static_cast<uint32_t>(KeyMgmtMask::SUITE_B_192);
}
#endif /* CONFIG_SUITEB192 */
#ifdef CONFIG_OWE
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE) {
mask |= static_cast<uint32_t>(KeyMgmtMask::OWE);
}
#endif /* CONFIG_OWE */
#ifdef CONFIG_SAE
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
mask |= static_cast<uint32_t>(KeyMgmtMask::SAE);
}
#endif /* CONFIG_SAE */
#ifdef CONFIG_DPP
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP) {
mask |= static_cast<uint32_t>(KeyMgmtMask::DPP);
}
#endif
#ifdef CONFIG_WAPI_INTERFACE
mask |= static_cast<uint32_t>(KeyMgmtMask::WAPI_PSK);
mask |= static_cast<uint32_t>(KeyMgmtMask::WAPI_CERT);
#endif /* CONFIG_WAPI_INTERFACE */
#ifdef CONFIG_FILS
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256) {
mask |= static_cast<uint32_t>(KeyMgmtMask::FILS_SHA256);
}
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384) {
mask |= static_cast<uint32_t>(KeyMgmtMask::FILS_SHA384);
}
#endif /* CONFIG_FILS */
return static_cast<KeyMgmtMask>(mask);
}
const std::string getDppListenChannel(struct wpa_supplicant *wpa_s, int32_t *listen_channel)
{
struct hostapd_hw_modes *mode;
int chan44 = 0, chan149 = 0;
*listen_channel = 0;
/* Check if device support 2.4GHz band*/
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
HOSTAPD_MODE_IEEE80211G, 0);
if (mode) {
*listen_channel = 6;
return "81/6";
}
/* Check if device support 5GHz band */
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
HOSTAPD_MODE_IEEE80211A, 0);
if (mode) {
for (int i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if (chan->flag & (HOSTAPD_CHAN_DISABLED |
HOSTAPD_CHAN_RADAR))
continue;
if (chan->freq == 5220)
chan44 = 1;
if (chan->freq == 5745)
chan149 = 1;
}
if (chan149) {
*listen_channel = 149;
return "124/149";
} else if (chan44) {
*listen_channel = 44;
return "115/44";
}
}
return "";
}
const std::string convertCurveTypeToName(DppCurve curve)
{
switch (curve) {
case DppCurve::PRIME256V1:
return "prime256v1";
case DppCurve::SECP384R1:
return "secp384r1";
case DppCurve::SECP521R1:
return "secp521r1";
case DppCurve::BRAINPOOLP256R1:
return "brainpoolP256r1";
case DppCurve::BRAINPOOLP384R1:
return "brainpoolP384r1";
case DppCurve::BRAINPOOLP512R1:
return "brainpoolP512r1";
}
WPA_ASSERT(false);
}
inline std::array<uint8_t, ETH_ALEN> macAddrToArray(const uint8_t* mac_addr) {
std::array<uint8_t, ETH_ALEN> arr;
std::copy(mac_addr, mac_addr + ETH_ALEN, std::begin(arr));
return arr;
}
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace supplicant {
using aidl_return_util::validateAndCall;
using misc_utils::createStatus;
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));
}
::ndk::ScopedAStatus StaIface::getName(
std::string* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::getNameInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::getType(
IfaceType* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::getTypeInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::addNetwork(
std::shared_ptr<ISupplicantStaNetwork>* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::addNetworkInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::removeNetwork(
int32_t in_id)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::removeNetworkInternal, in_id);
}
::ndk::ScopedAStatus StaIface::filsHlpFlushRequest()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::filsHlpFlushRequestInternal);
}
::ndk::ScopedAStatus StaIface::filsHlpAddRequest(
const std::vector<uint8_t>& in_dst_mac,
const std::vector<uint8_t>& in_pkt)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::filsHlpAddRequestInternal, in_dst_mac, in_pkt);
}
::ndk::ScopedAStatus StaIface::getNetwork(
int32_t in_id, std::shared_ptr<ISupplicantStaNetwork>* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::getNetworkInternal, _aidl_return, in_id);
}
::ndk::ScopedAStatus StaIface::listNetworks(
std::vector<int32_t>* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::listNetworksInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::registerCallback(
const std::shared_ptr<ISupplicantStaIfaceCallback>& in_callback)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::registerCallbackInternal, in_callback);
}
::ndk::ScopedAStatus StaIface::reassociate()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::reassociateInternal);
}
::ndk::ScopedAStatus StaIface::reconnect()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::reconnectInternal);
}
::ndk::ScopedAStatus StaIface::disconnect()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::disconnectInternal);
}
::ndk::ScopedAStatus StaIface::setPowerSave(
bool in_enable)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setPowerSaveInternal, in_enable);
}
::ndk::ScopedAStatus StaIface::initiateTdlsDiscover(
const std::vector<uint8_t>& in_macAddress)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::initiateTdlsDiscoverInternal, in_macAddress);
}
::ndk::ScopedAStatus StaIface::initiateTdlsSetup(
const std::vector<uint8_t>& in_macAddress)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::initiateTdlsSetupInternal, in_macAddress);
}
::ndk::ScopedAStatus StaIface::initiateTdlsTeardown(
const std::vector<uint8_t>& in_macAddress)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::initiateTdlsTeardownInternal, in_macAddress);
}
::ndk::ScopedAStatus StaIface::initiateAnqpQuery(
const std::vector<uint8_t>& in_macAddress,
const std::vector<AnqpInfoId>& in_infoElements,
const std::vector<Hs20AnqpSubtypes>& in_subTypes)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::initiateAnqpQueryInternal, in_macAddress,
in_infoElements, in_subTypes);
}
::ndk::ScopedAStatus StaIface::initiateVenueUrlAnqpQuery(
const std::vector<uint8_t>& in_macAddress)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::initiateVenueUrlAnqpQueryInternal, in_macAddress);
}
::ndk::ScopedAStatus StaIface::initiateHs20IconQuery(
const std::vector<uint8_t>& in_macAddress,
const std::string& in_fileName)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::initiateHs20IconQueryInternal, in_macAddress,
in_fileName);
}
::ndk::ScopedAStatus StaIface::getMacAddress(
std::vector<uint8_t>* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::getMacAddressInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::startRxFilter()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::startRxFilterInternal);
}
::ndk::ScopedAStatus StaIface::stopRxFilter()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::stopRxFilterInternal);
}
::ndk::ScopedAStatus StaIface::addRxFilter(
RxFilterType in_type)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::addRxFilterInternal, in_type);
}
::ndk::ScopedAStatus StaIface::removeRxFilter(
RxFilterType in_type)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::removeRxFilterInternal, in_type);
}
::ndk::ScopedAStatus StaIface::setBtCoexistenceMode(
BtCoexistenceMode in_mode)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setBtCoexistenceModeInternal, in_mode);
}
::ndk::ScopedAStatus StaIface::setBtCoexistenceScanModeEnabled(
bool in_enable)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setBtCoexistenceScanModeEnabledInternal,
in_enable);
}
::ndk::ScopedAStatus StaIface::setSuspendModeEnabled(
bool in_enable)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setSuspendModeEnabledInternal, in_enable);
}
::ndk::ScopedAStatus StaIface::setCountryCode(
const std::vector<uint8_t>& in_code)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setCountryCodeInternal, in_code);
}
::ndk::ScopedAStatus StaIface::startWpsRegistrar(
const std::vector<uint8_t>& in_bssid,
const std::string& in_pin)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::startWpsRegistrarInternal, in_bssid, in_pin);
}
::ndk::ScopedAStatus StaIface::startWpsPbc(
const std::vector<uint8_t>& in_bssid)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::startWpsPbcInternal, in_bssid);
}
::ndk::ScopedAStatus StaIface::startWpsPinKeypad(
const std::string& in_pin)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::startWpsPinKeypadInternal, in_pin);
}
::ndk::ScopedAStatus StaIface::startWpsPinDisplay(
const std::vector<uint8_t>& in_bssid,
std::string* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::startWpsPinDisplayInternal, _aidl_return, in_bssid);
}
::ndk::ScopedAStatus StaIface::cancelWps()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::cancelWpsInternal);
}
::ndk::ScopedAStatus StaIface::setWpsDeviceName(
const std::string& in_name)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setWpsDeviceNameInternal, in_name);
}
::ndk::ScopedAStatus StaIface::setWpsDeviceType(
const std::vector<uint8_t>& in_type)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setWpsDeviceTypeInternal, in_type);
}
::ndk::ScopedAStatus StaIface::setWpsManufacturer(
const std::string& in_manufacturer)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setWpsManufacturerInternal, in_manufacturer);
}
::ndk::ScopedAStatus StaIface::setWpsModelName(
const std::string& in_modelName)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setWpsModelNameInternal, in_modelName);
}
::ndk::ScopedAStatus StaIface::setWpsModelNumber(
const std::string& in_modelNumber)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setWpsModelNumberInternal, in_modelNumber);
}
::ndk::ScopedAStatus StaIface::setWpsSerialNumber(
const std::string& in_serialNumber)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setWpsSerialNumberInternal, in_serialNumber);
}
::ndk::ScopedAStatus StaIface::setWpsConfigMethods(
WpsConfigMethods in_configMethods)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setWpsConfigMethodsInternal, in_configMethods);
}
::ndk::ScopedAStatus StaIface::setExternalSim(
bool in_useExternalSim)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::setExternalSimInternal, in_useExternalSim);
}
::ndk::ScopedAStatus StaIface::addExtRadioWork(
const std::string& in_name, int32_t in_freqInMhz,
int32_t in_timeoutInSec,
int32_t* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::addExtRadioWorkInternal, _aidl_return, in_name, in_freqInMhz,
in_timeoutInSec);
}
::ndk::ScopedAStatus StaIface::removeExtRadioWork(
int32_t in_id)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::removeExtRadioWorkInternal, in_id);
}
::ndk::ScopedAStatus StaIface::enableAutoReconnect(
bool in_enable)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::enableAutoReconnectInternal, in_enable);
}
::ndk::ScopedAStatus StaIface::getKeyMgmtCapabilities(
KeyMgmtMask* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaIface::getKeyMgmtCapabilitiesInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::addDppPeerUri(
const std::string& in_uri, int32_t* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaIface::addDppPeerUriInternal, _aidl_return, in_uri);
}
::ndk::ScopedAStatus StaIface::removeDppUri(
int32_t in_id)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaIface::removeDppUriInternal, in_id);
}
::ndk::ScopedAStatus StaIface::startDppConfiguratorInitiator(
int32_t in_peerBootstrapId, int32_t in_ownBootstrapId,
const std::string& in_ssid, const std::string& in_password,
const std::string& in_psk, DppNetRole in_netRole,
DppAkm in_securityAkm, const std::vector<uint8_t>& in_privEcKey,
std::vector<uint8_t>* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaIface::startDppConfiguratorInitiatorInternal, _aidl_return,
in_peerBootstrapId,in_ownBootstrapId, in_ssid, in_password,
in_psk, in_netRole, in_securityAkm, in_privEcKey);
}
::ndk::ScopedAStatus StaIface::startDppEnrolleeInitiator(
int32_t in_peerBootstrapId, int32_t in_ownBootstrapId)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaIface::startDppEnrolleeInitiatorInternal, in_peerBootstrapId,
in_ownBootstrapId);
}
::ndk::ScopedAStatus StaIface::stopDppInitiator()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
&StaIface::stopDppInitiatorInternal);
}
::ndk::ScopedAStatus StaIface::getConnectionCapabilities(
ConnectionCapabilities* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::getConnectionCapabilitiesInternal,
_aidl_return);
}
::ndk::ScopedAStatus StaIface::generateDppBootstrapInfoForResponder(
const std::vector<uint8_t>& in_macAddress, const std::string& in_deviceInfo,
DppCurve in_curve, DppResponderBootstrapInfo* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::generateDppBootstrapInfoForResponderInternal, _aidl_return,
in_macAddress, in_deviceInfo, in_curve);
}
::ndk::ScopedAStatus StaIface::startDppEnrolleeResponder(
int32_t in_listenChannel)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::startDppEnrolleeResponderInternal, in_listenChannel);
}
::ndk::ScopedAStatus StaIface::stopDppResponder(
int32_t in_ownBootstrapId)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::stopDppResponderInternal, in_ownBootstrapId);
}
::ndk::ScopedAStatus StaIface::generateSelfDppConfiguration(
const std::string& in_ssid, const std::vector<uint8_t>& in_privEcKey)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&StaIface::generateSelfDppConfigurationInternal, in_ssid, in_privEcKey);
}
::ndk::ScopedAStatus StaIface::getWpaDriverCapabilities(
WpaDriverCapabilitiesMask* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::getWpaDriverCapabilitiesInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::setMboCellularDataStatus(
bool in_available)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::setMboCellularDataStatusInternal, in_available);
}
::ndk::ScopedAStatus StaIface::setQosPolicyFeatureEnabled(
bool in_enable)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::setQosPolicyFeatureEnabledInternal, in_enable);
}
::ndk::ScopedAStatus StaIface::sendQosPolicyResponse(
int32_t in_qosPolicyRequestId, bool in_morePolicies,
const std::vector<QosPolicyStatus>& in_qosPolicyStatusList)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::sendQosPolicyResponseInternal, in_qosPolicyRequestId,
in_morePolicies, in_qosPolicyStatusList);
}
::ndk::ScopedAStatus StaIface::removeAllQosPolicies()
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::removeAllQosPoliciesInternal);
}
::ndk::ScopedAStatus StaIface::getConnectionMloLinksInfo(MloLinksInfo* _aidl_return) {
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::getConnectionMloLinksInfoInternal, _aidl_return);
}
::ndk::ScopedAStatus StaIface::getSignalPollResults(
std::vector<SignalPollResult> *results)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::getSignalPollResultsInternal, results);
}
::ndk::ScopedAStatus StaIface::addQosPolicyRequestForScs(
const std::vector<QosPolicyScsData>& in_qosPolicyData,
std::vector<QosPolicyScsRequestStatus>* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::addQosPolicyRequestForScsInternal, _aidl_return, in_qosPolicyData);
}
::ndk::ScopedAStatus StaIface::removeQosPolicyForScs(
const std::vector<uint8_t>& in_scsPolicyIds,
std::vector<QosPolicyScsRequestStatus>* _aidl_return)
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::removeQosPolicyForScsInternal, _aidl_return, in_scsPolicyIds);
}
::ndk::ScopedAStatus StaIface::configureMscs(const MscsParams& in_params) {
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::configureMscsInternal, in_params);
}
::ndk::ScopedAStatus StaIface::disableMscs() {
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
&StaIface::disableMscsInternal);
}
std::pair<std::string, ndk::ScopedAStatus> StaIface::getNameInternal()
{
return {ifname_, ndk::ScopedAStatus::ok()};
}
std::pair<IfaceType, ndk::ScopedAStatus> StaIface::getTypeInternal()
{
return {IfaceType::STA, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::filsHlpFlushRequestInternal()
{
#ifdef CONFIG_FILS
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
wpas_flush_fils_hlp_req(wpa_s);
return ndk::ScopedAStatus::ok();
#else /* CONFIG_FILS */
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN, "");
#endif /* CONFIG_FILS */
}
ndk::ScopedAStatus StaIface::filsHlpAddRequestInternal(
const std::vector<uint8_t> &dst_mac, const std::vector<uint8_t> &pkt)
{
#ifdef CONFIG_FILS
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct fils_hlp_req *req;
if (!pkt.size())
return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
if (dst_mac.size() != ETH_ALEN)
return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
req = (struct fils_hlp_req *)os_zalloc(sizeof(*req));
if (!req)
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
os_memcpy(req->dst, dst_mac.data(), ETH_ALEN);
req->pkt = wpabuf_alloc_copy(pkt.data(), pkt.size());
if (!req->pkt) {
os_free(req);
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
dl_list_add_tail(&wpa_s->fils_hlp_req, &req->list);
return ndk::ScopedAStatus::ok();
#else /* CONFIG_FILS */
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
#endif /* CONFIG_FILS */
}
std::pair<std::shared_ptr<ISupplicantStaNetwork>, ndk::ScopedAStatus>
StaIface::addNetworkInternal()
{
std::shared_ptr<ISupplicantStaNetwork> network;
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
if (!ssid) {
return {network, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
AidlManager *aidl_manager = AidlManager::getInstance();
if (!aidl_manager ||
aidl_manager->getStaNetworkAidlObjectByIfnameAndNetworkId(
wpa_s->ifname, ssid->id, &network)) {
return {network, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
return {network, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::removeNetworkInternal(int32_t id)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
int result = wpa_supplicant_remove_network(wpa_s, id);
if (result == -1) {
return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
}
if (result != 0) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
std::pair<std::shared_ptr<ISupplicantStaNetwork>, ndk::ScopedAStatus>
StaIface::getNetworkInternal(int32_t id)
{
std::shared_ptr<ISupplicantStaNetwork> network;
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, id);
if (!ssid) {
return {network, createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN)};
}
AidlManager *aidl_manager = AidlManager::getInstance();
if (!aidl_manager ||
aidl_manager->getStaNetworkAidlObjectByIfnameAndNetworkId(
wpa_s->ifname, ssid->id, &network)) {
return {network, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
return {network, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<int32_t>, ndk::ScopedAStatus>
StaIface::listNetworksInternal()
{
std::vector<int32_t> 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 {std::move(network_ids), ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::registerCallbackInternal(
const std::shared_ptr<ISupplicantStaIfaceCallback> &callback)
{
AidlManager *aidl_manager = AidlManager::getInstance();
if (!aidl_manager ||
aidl_manager->addStaIfaceCallbackAidlObject(ifname_, callback)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::reassociateInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
}
wpas_request_connection(wpa_s);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::reconnectInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
}
if (!wpa_s->disconnected) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_NOT_DISCONNECTED);
}
wpas_request_connection(wpa_s);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::disconnectInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
}
wpas_request_disconnection(wpa_s);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::setPowerSaveInternal(bool enable)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
}
if (wpa_drv_set_p2p_powersave(wpa_s, enable, -1, -1)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::initiateTdlsDiscoverInternal(
const std::vector<uint8_t> &mac_address)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
int ret;
if (mac_address.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
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 ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::initiateTdlsSetupInternal(
const std::vector<uint8_t> &mac_address)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
int ret;
if (mac_address.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
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 ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::initiateTdlsTeardownInternal(
const std::vector<uint8_t> &mac_address)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
int ret;
if (mac_address.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
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 ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::initiateAnqpQueryInternal(
const std::vector<uint8_t> &mac_address,
const std::vector<AnqpInfoId> &info_elements,
const std::vector<Hs20AnqpSubtypes> &sub_types)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (info_elements.size() > kMaxAnqpElems) {
return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
}
#ifdef CONFIG_INTERWORKING
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<
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<
Hs20AnqpSubtypes>::type>(type));
}
if (mac_address.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
if (anqp_send_req(
wpa_s, mac_address.data(), 0, info_elems_buf, num_info_elems,
sub_types_bitmask, 0)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
#else
return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
#endif /* CONFIG_INTERWORKING */
}
ndk::ScopedAStatus StaIface::initiateVenueUrlAnqpQueryInternal(
const std::vector<uint8_t> &mac_address)
{
#ifdef CONFIG_INTERWORKING
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
uint16_t info_elems_buf[1] = {ANQP_VENUE_URL};
if (mac_address.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
if (anqp_send_req(
wpa_s, mac_address.data(), 0, info_elems_buf, 1, 0, 0)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
#else
return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
#endif /* CONFIG_INTERWORKING */
}
ndk::ScopedAStatus StaIface::initiateHs20IconQueryInternal(
const std::vector<uint8_t> &mac_address, const std::string &file_name)
{
#ifdef CONFIG_HS20
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (mac_address.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
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 createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
#else
return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
#endif /* CONFIG_HS20 */
}
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus>
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 {std::vector<uint8_t>(),
createStatus(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::vector<uint8_t> mac_addr(6);
if (hwaddr_aton(mac_addr_str.c_str(), mac_addr.data())) {
return {std::vector<uint8_t>(),
createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
return {mac_addr, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::startRxFilterInternal()
{
return doZeroArgDriverCommand(retrieveIfacePtr(), kStartRxFilter);
}
ndk::ScopedAStatus StaIface::stopRxFilterInternal()
{
return doZeroArgDriverCommand(retrieveIfacePtr(), kStopRxFilter);
}
ndk::ScopedAStatus StaIface::addRxFilterInternal(
RxFilterType type)
{
return doOneArgDriverCommand(
retrieveIfacePtr(), kAddRxFilter,
convertAidlRxFilterTypeToInternal(type));
}
ndk::ScopedAStatus StaIface::removeRxFilterInternal(
RxFilterType type)
{
return doOneArgDriverCommand(
retrieveIfacePtr(), kRemoveRxFilter,
convertAidlRxFilterTypeToInternal(type));
}
ndk::ScopedAStatus StaIface::setBtCoexistenceModeInternal(
BtCoexistenceMode mode)
{
return doOneArgDriverCommand(
retrieveIfacePtr(), kSetBtCoexistenceMode,
convertAidlBtCoexModeToInternal(mode));
}
ndk::ScopedAStatus StaIface::setBtCoexistenceScanModeEnabledInternal(bool enable)
{
const char *cmd;
if (enable) {
cmd = kSetBtCoexistenceScanStart;
} else {
cmd = kSetBtCoexistenceScanStop;
}
return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
}
ndk::ScopedAStatus StaIface::setSuspendModeEnabledInternal(bool enable)
{
const char *cmd;
if (enable) {
cmd = kSetSupendModeEnabled;
} else {
cmd = kSetSupendModeDisabled;
}
return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
}
ndk::ScopedAStatus StaIface::setCountryCodeInternal(
const std::vector<uint8_t> &code)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
//2-Character alphanumeric country code
if (code.size() != 2) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
ndk::ScopedAStatus status = doOneArgDriverCommand(
wpa_s, kSetCountryCode,
std::string(std::begin(code), std::end(code)));
if (!status.isOk()) {
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 ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::startWpsRegistrarInternal(
const std::vector<uint8_t> &bssid, const std::string &pin)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (bssid.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
if (wpas_wps_start_reg(wpa_s, bssid.data(), pin.c_str(), nullptr)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::startWpsPbcInternal(
const std::vector<uint8_t> &bssid)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (bssid.size() != ETH_ALEN) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
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 createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus 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 createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
std::pair<std::string, ndk::ScopedAStatus> StaIface::startWpsPinDisplayInternal(
const std::vector<uint8_t> &bssid)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (bssid.size() != ETH_ALEN) {
return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
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 {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
return {misc_utils::convertWpsPinToString(pin),
ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::cancelWpsInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (wpas_wps_cancel(wpa_s)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::setWpsDeviceNameInternal(const std::string &name)
{
return iface_config_utils::setWpsDeviceName(retrieveIfacePtr(), name);
}
ndk::ScopedAStatus StaIface::setWpsDeviceTypeInternal(
const std::vector<uint8_t> &type)
{
std::array<uint8_t, 8> type_arr;
std::copy_n(type.begin(), 8, type_arr.begin());
return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type_arr);
}
ndk::ScopedAStatus StaIface::setWpsManufacturerInternal(
const std::string &manufacturer)
{
return iface_config_utils::setWpsManufacturer(
retrieveIfacePtr(), manufacturer);
}
ndk::ScopedAStatus StaIface::setWpsModelNameInternal(
const std::string &model_name)
{
return iface_config_utils::setWpsModelName(
retrieveIfacePtr(), model_name);
}
ndk::ScopedAStatus StaIface::setWpsModelNumberInternal(
const std::string &model_number)
{
return iface_config_utils::setWpsModelNumber(
retrieveIfacePtr(), model_number);
}
ndk::ScopedAStatus StaIface::setWpsSerialNumberInternal(
const std::string &serial_number)
{
return iface_config_utils::setWpsSerialNumber(
retrieveIfacePtr(), serial_number);
}
ndk::ScopedAStatus StaIface::setWpsConfigMethodsInternal(WpsConfigMethods config_methods)
{
return iface_config_utils::setWpsConfigMethods(
retrieveIfacePtr(), static_cast<uint16_t>(config_methods));
}
ndk::ScopedAStatus StaIface::setExternalSimInternal(bool useExternalSim)
{
return iface_config_utils::setExternalSim(
retrieveIfacePtr(), useExternalSim);
}
std::pair<uint32_t, ndk::ScopedAStatus> 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 {UINT32_MAX, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
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 {UINT32_MAX, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
return {ework->id, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus 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 ndk::ScopedAStatus::ok();
}
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
ndk::ScopedAStatus StaIface::enableAutoReconnectInternal(bool enable)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
wpa_s->auto_reconnect_disabled = enable ? 0 : 1;
return ndk::ScopedAStatus::ok();
}
std::pair<uint32_t, ndk::ScopedAStatus>
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 {id, ndk::ScopedAStatus::ok()};
}
#endif
return {-1, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
ndk::ScopedAStatus 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 ndk::ScopedAStatus::ok();
}
#endif
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
std::pair<std::vector<uint8_t>, ndk::ScopedAStatus>
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,
const std::vector<uint8_t> &privEcKey)
{
#ifdef CONFIG_DPP
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
std::string cmd = "";
std::string cmd2 = "";
int32_t id;
char key[1024];
if (net_role != DppNetRole::AP &&
net_role != DppNetRole::STA) {
wpa_printf(MSG_ERROR,
"DPP: Error: Invalid network role specified: %d", net_role);
return {std::vector<uint8_t>(),
createStatus(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 && security_akm != DppAkm::DPP) {
wpa_printf(MSG_ERROR, "DPP: Error: invalid AKM specified: %d",
security_akm);
return {std::vector<uint8_t>(),
createStatus(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 {std::vector<uint8_t>(),
createStatus(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 {std::vector<uint8_t>(),
createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
if (password.empty() && psk.empty()) {
wpa_printf(MSG_ERROR, "DPP: Error: Password or PSK not specified");
return {std::vector<uint8_t>(),
createStatus(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;
case DppAkm::DPP:
role += "dpp";
break;
default:
wpa_printf(MSG_ERROR,
"DPP: Invalid or unsupported security AKM specified: %d", security_akm);
return {std::vector<uint8_t>(),
createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
cmd += " conf=";
cmd += role;
if (net_role == DppNetRole::STA) {
/* DPP R2 connection status request */
cmd += " conn_status=1";
}
if (security_akm == DppAkm::DPP) {
if (!privEcKey.empty()) {
cmd2 += " key=" + std::string(privEcKey.begin(), privEcKey.end());
}
id = dpp_configurator_add(wpa_s->dpp, cmd2.c_str());
if (id < 0 || (privEcKey.empty() &&
(dpp_configurator_get_key_id(wpa_s->dpp, id, key, sizeof(key)) < 0)))
{
wpa_printf(MSG_ERROR, "DPP configurator add failed. "
"Input key might be incorrect");
return {std::vector<uint8_t>(),
createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
cmd += " configurator=" + std::to_string(id);
}
wpa_printf(MSG_DEBUG,
"DPP initiator command: %s", cmd.c_str());
if (wpas_dpp_auth_init(wpa_s, cmd.c_str()) == 0) {
// Return key if input privEcKey was null/empty.
if (security_akm == DppAkm::DPP && privEcKey.empty()) {
std::string k(key);
std::vector<uint8_t> vKey(k.begin(), k.end());
return {vKey, ndk::ScopedAStatus::ok()};
}
return {std::vector<uint8_t>(), ndk::ScopedAStatus::ok()};
}
#endif
return {std::vector<uint8_t>(), createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
ndk::ScopedAStatus 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 AIDL 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 ndk::ScopedAStatus::ok();
}
#endif
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
ndk::ScopedAStatus StaIface::stopDppInitiatorInternal()
{
#ifdef CONFIG_DPP
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
wpas_dpp_stop(wpa_s);
return ndk::ScopedAStatus::ok();
#else
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
#endif
}
std::pair<DppResponderBootstrapInfo, ndk::ScopedAStatus>
StaIface::generateDppBootstrapInfoForResponderInternal(
const std::vector<uint8_t> &mac_address,
const std::string& device_info, DppCurve curve)
{
#ifdef CONFIG_DPP
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
std::string cmd = "type=qrcode";
int32_t id;
int32_t listen_channel = 0;
DppResponderBootstrapInfo bootstrap_info;
const char *uri;
std::string listen_channel_str;
std::string mac_addr_str;
char buf[3] = {0};
cmd += (device_info.empty()) ? "" : " info=" + device_info;
listen_channel_str = getDppListenChannel(wpa_s, &listen_channel);
if (listen_channel == 0) {
wpa_printf(MSG_ERROR, "StaIface: Failed to derive DPP listen channel");
return {bootstrap_info, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
cmd += " chan=" + listen_channel_str;
if (mac_address.size() != ETH_ALEN) {
return {bootstrap_info, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
cmd += " mac=";
for (int i = 0;i < 6;i++) {
snprintf(buf, sizeof(buf), "%02x", mac_address[i]);
mac_addr_str.append(buf);
}
cmd += mac_addr_str;
cmd += " curve=" + convertCurveTypeToName(curve);
id = dpp_bootstrap_gen(wpa_s->dpp, cmd.c_str());
wpa_printf(MSG_DEBUG,
"DPP generate bootstrap QR code command: %s id: %d", cmd.c_str(), id);
if (id > 0) {
uri = dpp_bootstrap_get_uri(wpa_s->dpp, id);
if (uri) {
wpa_printf(MSG_DEBUG, "DPP Bootstrap info: id: %d "
"listen_channel: %d uri: %s", id, listen_channel, uri);
bootstrap_info.bootstrapId = id;
bootstrap_info.listenChannel = listen_channel;
bootstrap_info.uri = uri;
return {bootstrap_info, ndk::ScopedAStatus::ok()};
}
}
return {bootstrap_info, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
#else
return {bootstrap_info, createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
#endif
}
ndk::ScopedAStatus StaIface::startDppEnrolleeResponderInternal(uint32_t listen_channel)
{
#ifdef CONFIG_DPP
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
std::string cmd = "";
uint32_t freq = (listen_channel <= 14 ? 2407 : 5000) + listen_channel * 5;
/* Report received configuration to AIDL and create an internal profile */
wpa_s->conf->dpp_config_processing = 1;
cmd += std::to_string(freq);
cmd += " role=enrollee netrole=sta";
wpa_printf(MSG_DEBUG,
"DPP Enrollee Responder command: %s", cmd.c_str());
if (wpas_dpp_listen(wpa_s, cmd.c_str()) == 0) {
return ndk::ScopedAStatus::ok();
}
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
#else
return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
#endif
}
ndk::ScopedAStatus StaIface::stopDppResponderInternal(uint32_t own_bootstrap_id)
{
#ifdef CONFIG_DPP
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
std::string bootstrap_id_str;
if (own_bootstrap_id == 0) {
bootstrap_id_str = "*";
}
else {
bootstrap_id_str = std::to_string(own_bootstrap_id);
}
wpa_printf(MSG_DEBUG, "DPP Stop DPP Responder id: %d ", own_bootstrap_id);
wpas_dpp_stop(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (dpp_bootstrap_remove(wpa_s->dpp, bootstrap_id_str.c_str()) < 0) {
wpa_printf(MSG_ERROR, "StaIface: dpp_bootstrap_remove failed");
}
return ndk::ScopedAStatus::ok();
#else
return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
#endif
}
ndk::ScopedAStatus StaIface::generateSelfDppConfigurationInternal(const std::string& ssid,
const std::vector<uint8_t> &privEcKey)
{
#ifdef CONFIG_DPP
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
std::string cmd = "";
char *ssid_hex_str;
int len;
int32_t id;
if (ssid.empty() || privEcKey.empty()) {
wpa_printf(MSG_ERROR, "DPP generate self configuration failed. ssid/key empty");
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
cmd += " key=" + std::string(privEcKey.begin(), privEcKey.end());
id = dpp_configurator_add(wpa_s->dpp, cmd.c_str());
if (id < 0) {
wpa_printf(MSG_ERROR, "DPP configurator add failed. Input key might be incorrect");
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
cmd = " conf=sta-dpp";
cmd += " configurator=" + std::to_string(id);
ssid_hex_str = (char *) os_zalloc(ssid.size() * 2 + 1);
if (!ssid_hex_str) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
wpa_snprintf_hex(ssid_hex_str, ssid.size() * 2 + 1, (u8*)ssid.data(), ssid.size());
cmd += " ssid=" + std::string(ssid_hex_str);
/* Report received configuration to AIDL and create an internal profile */
wpa_s->conf->dpp_config_processing = 1;
if (wpas_dpp_configurator_sign(wpa_s, cmd.c_str()) == 0) {
os_free(ssid_hex_str);
return ndk::ScopedAStatus::ok();
}
os_free(ssid_hex_str);
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
#else
return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
#endif
}
std::pair<ConnectionCapabilities, ndk::ScopedAStatus>
StaIface::getConnectionCapabilitiesInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
ConnectionCapabilities capa;
if (wpa_s->connection_set) {
capa.legacyMode = LegacyMode::UNKNOWN;
if (wpa_s->connection_eht) {
capa.technology = WifiTechnology::EHT;
} else if (wpa_s->connection_he) {
capa.technology = WifiTechnology::HE;
} else if (wpa_s->connection_vht) {
capa.technology = WifiTechnology::VHT;
} else if (wpa_s->connection_ht) {
capa.technology = WifiTechnology::HT;
} else {
capa.technology = WifiTechnology::LEGACY;
if (wpas_freq_to_band(wpa_s->assoc_freq) == BAND_2_4_GHZ) {
capa.legacyMode = (wpa_s->connection_11b_only) ? LegacyMode::B_MODE
: LegacyMode::G_MODE;
} else {
capa.legacyMode = LegacyMode::A_MODE;
}
}
switch (wpa_s->connection_channel_bandwidth) {
case CHAN_WIDTH_20:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
break;
case CHAN_WIDTH_40:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_40;
break;
case CHAN_WIDTH_80:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80;
break;
case CHAN_WIDTH_160:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_160;
break;
case CHAN_WIDTH_80P80:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
break;
case CHAN_WIDTH_320:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_320;
break;
default:
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
break;
}
capa.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
capa.maxNumberTxSpatialStreams = wpa_s->connection_max_nss_tx;
capa.apTidToLinkMapNegotiationSupported = wpa_s->ap_t2lm_negotiation_support;
} else {
capa.technology = WifiTechnology::UNKNOWN;
capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
capa.maxNumberTxSpatialStreams = 1;
capa.maxNumberRxSpatialStreams = 1;
capa.legacyMode = LegacyMode::UNKNOWN;
}
return {capa, ndk::ScopedAStatus::ok()};
}
std::pair<WpaDriverCapabilitiesMask, ndk::ScopedAStatus>
StaIface::getWpaDriverCapabilitiesInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
uint32_t mask = 0;
#ifdef CONFIG_MBO
/* MBO has no capability flags. It's mainly legacy 802.11v BSS
* transition + Cellular steering. 11v is a default feature in
* supplicant. And cellular steering is handled in framework.
*/
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::MBO);
if (wpa_s->enable_oce & OCE_STA) {
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::OCE);
}
#endif
#ifdef CONFIG_SAE_PK
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::SAE_PK);
#endif
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::WFD_R2);
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::TRUST_ON_FIRST_USE);
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::SET_TLS_MINIMUM_VERSION);
#ifdef EAP_TLSV1_3
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::TLS_V1_3);
#endif
wpa_printf(MSG_DEBUG, "Driver capability mask: 0x%x", mask);
return {static_cast<WpaDriverCapabilitiesMask>(mask),
ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::setMboCellularDataStatusInternal(bool available)
{
#ifdef CONFIG_MBO
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
enum mbo_cellular_capa mbo_cell_capa;
if (available) {
mbo_cell_capa = MBO_CELL_CAPA_AVAILABLE;
} else {
mbo_cell_capa = MBO_CELL_CAPA_NOT_AVAILABLE;
}
#ifdef ENABLE_PRIV_CMD_UPDATE_MBO_CELL_STATUS
char mbo_cmd[32];
char buf[32];
os_snprintf(mbo_cmd, sizeof(mbo_cmd), "%s %d", "MBO CELL_DATA_CAP", mbo_cell_capa);
if (wpa_drv_driver_cmd(wpa_s, mbo_cmd, buf, sizeof(buf)) < 0) {
wpa_printf(MSG_ERROR, "MBO CELL_DATA_CAP cmd failed CAP:%d", mbo_cell_capa);
}
#else
wpas_mbo_update_cell_capa(wpa_s, mbo_cell_capa);
#endif
return ndk::ScopedAStatus::ok();
#else
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
#endif
}
std::pair<KeyMgmtMask, ndk::ScopedAStatus>
StaIface::getKeyMgmtCapabilitiesInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct wpa_driver_capa capa;
/* Get capabilities from driver and populate the key management mask */
if (wpa_drv_get_capa(wpa_s, &capa) < 0) {
return {static_cast<KeyMgmtMask>(0),
createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
return {convertWpaKeyMgmtCapabilitiesToAidl(wpa_s, &capa),
ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::setQosPolicyFeatureEnabledInternal(bool enable)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
wpa_s->enable_dscp_policy_capa = enable ? 1 : 0;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::sendQosPolicyResponseInternal(
int32_t qos_policy_request_id, bool more_policies,
const std::vector<QosPolicyStatus>& qos_policy_status_list)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct dscp_resp_data resp_data;
int num_policies = qos_policy_status_list.size();
memset(&resp_data, 0, sizeof(resp_data));
resp_data.more = more_policies ? 1 : 0;
resp_data.policy = (struct dscp_policy_status *) malloc(
sizeof(struct dscp_policy_status) * num_policies);
if (num_policies && !resp_data.policy){
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
resp_data.solicited = true;
wpa_s->dscp_req_dialog_token = qos_policy_request_id;
for (int i = 0; i < num_policies; i++) {
resp_data.policy[i].id = qos_policy_status_list.at(i).policyId;
resp_data.policy[i].status =
static_cast<uint8_t>(qos_policy_status_list.at(i).status);
}
resp_data.num_policies = num_policies;
if (wpas_send_dscp_response(wpa_s, &resp_data)) {
free(resp_data.policy);
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
free(resp_data.policy);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::removeAllQosPoliciesInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct dscp_resp_data resp_data;
memset(&resp_data, 0, sizeof(resp_data));
resp_data.reset = true;
resp_data.solicited = false;
wpa_s->dscp_req_dialog_token = 0;
if (wpas_send_dscp_response(wpa_s, &resp_data)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
std::pair<MloLinksInfo, ndk::ScopedAStatus> StaIface::getConnectionMloLinksInfoInternal()
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct driver_sta_mlo_info mlo;
MloLinksInfo linksInfo;
MloLink link;
linksInfo.apMldMacAddress = macAddrToArray(wpa_s->ap_mld_addr);
if (!wpa_s->valid_links)
return {linksInfo, ndk::ScopedAStatus::ok()};
wpas_drv_get_sta_mlo_info(wpa_s, &mlo);
for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
if (!(wpa_s->valid_links & BIT(i)))
continue;
wpa_printf(MSG_DEBUG, "Add MLO Link ID %d info", i);
// Associated link id.
if (os_memcmp(wpa_s->links[i].bssid, wpa_s->bssid, ETH_ALEN) == 0) {
linksInfo.apMloLinkId = i;
}
link.linkId = i;
link.staLinkMacAddress.assign(
wpa_s->links[i].addr, wpa_s->links[i].addr + ETH_ALEN);
link.apLinkMacAddress = macAddrToArray(wpa_s->links[i].bssid);
link.frequencyMHz = wpa_s->links[i].freq;
// TODO (b/259710591): Once supplicant implements TID-to-link
// mapping, copy it here. Mapping can be changed in two
// scenarios
// 1. Mandatory mapping from AP
// 2. Negotiated mapping
// After association, framework call this API to get
// MloLinksInfo. If there is an update in mapping later, notify
// framework on the change using the callback,
// ISupplicantStaIfaceCallback.onMloLinksInfoChanged() with
// reason code as TID_TO_LINK_MAP. In absence of an advertised
// mapping by the AP, a default TID-to-link mapping is assumed
// unless an individual TID-to-link mapping is successfully
// negotiated.
if (!mlo.default_map) {
link.tidsUplinkMap = mlo.links[i].t2lmap.uplink;
link.tidsDownlinkMap = mlo.links[i].t2lmap.downlink;
} else {
link.tidsUplinkMap = 0xFF;
link.tidsDownlinkMap = 0xFF;
}
linksInfo.links.push_back(link);
}
return {linksInfo, ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<SignalPollResult>, ndk::ScopedAStatus>
StaIface::getSignalPollResultsInternal()
{
std::vector<SignalPollResult> results;
struct wpa_signal_info si;
struct wpa_mlo_signal_info mlo_si;
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
if (wpa_s->valid_links && (wpa_drv_mlo_signal_poll(wpa_s, &mlo_si) == 0)) {
for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
if (!(mlo_si.valid_links & BIT(i)))
continue;
SignalPollResult result;
result.linkId = i;
result.currentRssiDbm = mlo_si.links[i].data.signal;
result.txBitrateMbps = mlo_si.links[i].data.current_tx_rate / 1000;
result.rxBitrateMbps = mlo_si.links[i].data.current_rx_rate / 1000;
result.frequencyMhz = mlo_si.links[i].frequency;
results.push_back(result);
}
} else if (wpa_drv_signal_poll(wpa_s, &si) == 0) {
SignalPollResult result;
result.linkId = 0;
result.currentRssiDbm = si.data.signal;
result.txBitrateMbps = si.data.current_tx_rate / 1000;
result.rxBitrateMbps = si.data.current_rx_rate / 1000;
result.frequencyMhz = si.frequency;
results.push_back(result);
}
return {results, ndk::ScopedAStatus::ok()};
}
static int set_type4_frame_classifier(QosPolicyScsData qos_policy_data,
struct type4_params *param)
{
u8 classifier_mask = 0;
uint32_t inMask = static_cast<uint32_t>(qos_policy_data.classifierParams.classifierParamMask);
if (qos_policy_data.classifierParams.ipVersion ==
IpVersion::VERSION_4) {
param->ip_version = IPV4;
} else if (qos_policy_data.classifierParams.ipVersion ==
IpVersion::VERSION_6) {
param->ip_version = IPV6;
} else {
wpa_printf(MSG_ERROR, "IP version missing/invalid");
return -1;
}
/* Classifier Mask - bit 0 = Ip Version */
classifier_mask |= BIT(0);
if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::SRC_IP)) {
if (param->ip_version == IPV4) {
if (qos_policy_data.classifierParams.srcIp.size() !=
sizeof(param->ip_params.v4.src_ip)) {
wpa_printf(MSG_ERROR, "Invalid source IP");
return -1;
}
os_memcpy(&param->ip_params.v4.src_ip, qos_policy_data.classifierParams.srcIp.data(), 4);
} else {
if (qos_policy_data.classifierParams.srcIp.size() !=
sizeof(param->ip_params.v6.src_ip)) {
wpa_printf(MSG_ERROR, "Invalid source IP");
return -1;
}
os_memcpy(&param->ip_params.v6.src_ip, qos_policy_data.classifierParams.srcIp.data(), 16);
}
/* Classifier Mask - bit 1 = Source IP Address */
classifier_mask |= BIT(1);
}
if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::DST_IP)) {
if (param->ip_version == IPV4) {
if (qos_policy_data.classifierParams.dstIp.size() !=
sizeof(param->ip_params.v4.dst_ip)) {
wpa_printf(MSG_ERROR, "Invalid destination IP");
return -1;
}
os_memcpy(&param->ip_params.v4.dst_ip, qos_policy_data.classifierParams.dstIp.data(), 4);
} else {
if (qos_policy_data.classifierParams.dstIp.size() !=
sizeof(param->ip_params.v6.dst_ip)) {
wpa_printf(MSG_ERROR, "Invalid destination IP");
return -1;
}
os_memcpy(&param->ip_params.v6.dst_ip, qos_policy_data.classifierParams.dstIp.data(), 16);
}
/* Classifier Mask - bit 2 = Destination IP Address */
classifier_mask |= BIT(2);
}
if ((inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::SRC_PORT))
&& (qos_policy_data.classifierParams.srcPort > 0)) {
if (param->ip_version == IPV4)
param->ip_params.v4.src_port = qos_policy_data.classifierParams.srcPort;
else
param->ip_params.v6.src_port = qos_policy_data.classifierParams.srcPort;
/* Classifier Mask - bit 3 = Source Port */
classifier_mask |= BIT(3);
}
if ((inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::DST_PORT_RANGE))
&& (qos_policy_data.classifierParams.dstPortRange.startPort > 0)) {
if (param->ip_version == IPV4)
param->ip_params.v4.dst_port = qos_policy_data.classifierParams.dstPortRange.startPort;
else
param->ip_params.v6.dst_port = qos_policy_data.classifierParams.dstPortRange.startPort;
/* Classifier Mask - bit 4 = Destination Port range */
classifier_mask |= BIT(4);
}
if ((inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::DSCP))
&& (qos_policy_data.classifierParams.dscp > 0)) {
if (param->ip_version == IPV4)
param->ip_params.v4.dscp = qos_policy_data.classifierParams.dscp;
else
param->ip_params.v6.dscp = qos_policy_data.classifierParams.dscp;
/* Classifier Mask - bit 5 = DSCP */
classifier_mask |= BIT(5);
}
if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::PROTOCOL_NEXT_HEADER)) {
if (!((qos_policy_data.classifierParams.protocolNextHdr ==
ProtocolNextHeader::TCP) ||
(qos_policy_data.classifierParams.protocolNextHdr ==
ProtocolNextHeader::UDP) ||
(qos_policy_data.classifierParams.protocolNextHdr ==
ProtocolNextHeader::ESP))) {
wpa_printf(MSG_ERROR, "Invalid protocol");
return -1;
}
if (param->ip_version == IPV4) {
param->ip_params.v4.protocol =
(u8)qos_policy_data.classifierParams.protocolNextHdr;
} else {
param->ip_params.v6.next_header =
(u8)qos_policy_data.classifierParams.protocolNextHdr;
}
/* Classifier Mask - bit 6 = Protocol Number*/
classifier_mask |= BIT(6);
}
if (inMask & static_cast<uint32_t>(QosPolicyClassifierParamsMask::FLOW_LABEL)) {
if (qos_policy_data.classifierParams.flowLabelIpv6.size() !=
sizeof(param->ip_params.v6.flow_label)) {
wpa_printf(MSG_ERROR, "Invalid flow label");
return -1;
}
os_memcpy(param->ip_params.v6.flow_label, qos_policy_data.classifierParams.flowLabelIpv6.data(),
sizeof(qos_policy_data.classifierParams.flowLabelIpv6));
/* Classifier Mask - bit 7 = flow level */
classifier_mask |= BIT(7);
}
param->classifier_mask = classifier_mask;
return 0;
}
static int scs_parse_type4(struct tclas_element *elem, QosPolicyScsData qos_policy_data)
{
struct type4_params type4_param;
memset(&type4_param, 0, sizeof(type4_param));
if (set_type4_frame_classifier(qos_policy_data, &type4_param) < 0) {
wpa_printf(MSG_ERROR, "Failed to set frame_classifier 4");
return -1;
}
os_memcpy(&elem->frame_classifier.type4_param,
&type4_param, sizeof(struct type4_params));
return 0;
}
inline bool hasOptQosCharField(QosCharacteristics chars, QosCharacteristics::QosCharacteristicsMask field) {
return chars.optionalFieldMask & static_cast<uint32_t>(field);
}
static int parseQosCharacteristics(struct scs_desc_elem *descElem, QosPolicyScsData qosPolicy) {
struct qos_characteristics* suppChars = &descElem->qos_char_elem;
if (!qosPolicy.QosCharacteristics) {
suppChars->available = false;
return 0;
}
QosCharacteristics inputChars = qosPolicy.QosCharacteristics.value();
suppChars->available = true;
if (qosPolicy.direction == QosPolicyScsData::LinkDirection::DOWNLINK) {
suppChars->direction = SCS_DIRECTION_DOWN;
} else if (qosPolicy.direction == QosPolicyScsData::LinkDirection::UPLINK) {
suppChars->direction = SCS_DIRECTION_UP;
} else {
wpa_printf(MSG_ERROR, "Invalid QoS direction: %d", static_cast<int>(qosPolicy.direction));
return -1;
}
// Mandatory fields
suppChars->min_si = inputChars.minServiceIntervalUs;
suppChars->max_si = inputChars.maxServiceIntervalUs;
suppChars->min_data_rate = inputChars.minDataRateKbps;
suppChars->delay_bound = inputChars.delayBoundUs;
// Optional fields
uint16_t suppMask = 0;
if (hasOptQosCharField(inputChars, QosCharacteristics::QosCharacteristicsMask::MAX_MSDU_SIZE)) {
suppMask |= SCS_QOS_BIT_MAX_MSDU_SIZE;
suppChars->max_msdu_size = inputChars.maxMsduSizeOctets;
}
if (hasOptQosCharField(inputChars, QosCharacteristics::QosCharacteristicsMask::SERVICE_START_TIME)) {
// Client must provide both the service start time and the link ID if this field exists.
suppMask |= SCS_QOS_BIT_SERVICE_START_TIME | SCS_QOS_BIT_SERVICE_START_TIME_LINKID;
suppChars->service_start_time = inputChars.serviceStartTimeUs;
suppChars->service_start_time_link_id = inputChars.serviceStartTimeLinkId;
}
if (hasOptQosCharField(inputChars, QosCharacteristics::QosCharacteristicsMask::MEAN_DATA_RATE)) {
suppMask |= SCS_QOS_BIT_MEAN_DATA_RATE;
suppChars->mean_data_rate = inputChars.meanDataRateKbps;
}
if (hasOptQosCharField(inputChars, QosCharacteristics::QosCharacteristicsMask::BURST_SIZE)) {
suppMask |= SCS_QOS_BIT_DELAYED_BOUNDED_BURST_SIZE;
suppChars->burst_size = inputChars.burstSizeOctets;
}
if (hasOptQosCharField(inputChars, QosCharacteristics::QosCharacteristicsMask::MSDU_LIFETIME)) {
suppMask |= SCS_QOS_BIT_MSDU_LIFETIME;
suppChars->msdu_lifetime = inputChars.msduLifetimeMs;
}
if (hasOptQosCharField(inputChars, QosCharacteristics::QosCharacteristicsMask::MSDU_DELIVERY_INFO)) {
suppMask |= SCS_QOS_BIT_MSDU_DELIVERY_INFO;
// Expects the delivery ratio in the lower 4 bits and the count exponent
// in the upper 4 bits. See Figure 9-1001aw in the 802.11be spec.
suppChars->msdu_delivery_info = inputChars.msduDeliveryInfo.countExponent << 4
| (uint8_t) inputChars.msduDeliveryInfo.deliveryRatio;
}
suppChars->mask = suppMask;
return 0;
}
/**
* This is a request to the AP (if it supports the feature) to apply the QoS policy
* on traffic in the Downlink or Uplink direction.
*/
std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
StaIface::addQosPolicyRequestForScsInternal(const std::vector<QosPolicyScsData>& qosPolicyData)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct scs_robust_av_data *scs_data = &wpa_s->scs_robust_av_req;
struct scs_desc_elem desc_elem;
int user_priority, num_qos_policies;
unsigned int num_scs_ids = 0;
std::vector<QosPolicyScsRequestStatus> reports;
if (wpa_s->ongoing_scs_req) {
wpa_printf(MSG_ERROR, "AIDL: SCS Request already in queue");
return {std::vector<QosPolicyScsRequestStatus>(),
createStatus(SupplicantStatusCode::FAILURE_ONGOING_REQUEST)};
}
free_up_scs_desc(scs_data);
// Uplink policies are not supported before AIDL V3.
AidlManager *aidl_manager = AidlManager::getInstance();
WPA_ASSERT(aidl_manager);
bool supportsUplink = aidl_manager->isAidlServiceVersionAtLeast(3);
/**
* format:
* [scs_id=<decimal number>] [scs_up=<0-7>]
* [classifier params based on classifier type]
* [scs_id=<decimal number>] ...
*/
num_qos_policies = qosPolicyData.size();
for (int i = 0; i < num_qos_policies; i++) {
struct scs_desc_elem *new_desc_elems;
struct active_scs_elem *active_scs_desc;
struct tclas_element *elem;
bool scsid_active = false;
QosPolicyScsRequestStatus status;
memset(&desc_elem, 0, sizeof(desc_elem));
desc_elem.scs_id = qosPolicyData[i].policyId;
status.policyId = desc_elem.scs_id;
desc_elem.request_type = SCS_REQ_ADD;
dl_list_for_each(active_scs_desc, &wpa_s->active_scs_ids,
struct active_scs_elem, list) {
if (desc_elem.scs_id == active_scs_desc->scs_id) {
scsid_active = true;
break;
}
}
if (scsid_active) {
wpa_printf(MSG_ERROR, "SCSID %d already active",
desc_elem.scs_id);
status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::ALREADY_ACTIVE;
reports.push_back(status);
continue;
}
status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::INVALID;
if (parseQosCharacteristics(&desc_elem, qosPolicyData[i])) {
reports.push_back(status);
continue;
}
// TCLAS elements only need to be processed for downlink policies.
QosPolicyScsData::LinkDirection policyDirection = supportsUplink
? qosPolicyData[i].direction : QosPolicyScsData::LinkDirection::DOWNLINK;
if (policyDirection == QosPolicyScsData::LinkDirection::DOWNLINK) {
user_priority = qosPolicyData[i].userPriority;
if (user_priority < 0 || user_priority > 7) {
wpa_printf(MSG_ERROR,
"Intra-Access user priority invalid %d", user_priority);
reports.push_back(status);
continue;
}
desc_elem.intra_access_priority = user_priority;
desc_elem.scs_up_avail = true;
/**
* Supported classifier type 4.
*/
desc_elem.tclas_elems = (struct tclas_element *) os_malloc(sizeof(struct tclas_element));
if (!desc_elem.tclas_elems) {
wpa_printf(MSG_ERROR,
"Classifier type4 failed with Bad malloc");
reports.push_back(status);
continue;
}
elem = desc_elem.tclas_elems;
memset(elem, 0, sizeof(struct tclas_element));
elem->classifier_type = 4;
if (scs_parse_type4(elem, qosPolicyData[i]) < 0) {
os_free(elem);
reports.push_back(status);
continue;
}
desc_elem.num_tclas_elem = 1;
}
/* Reallocate memory to scs_desc_elems to accomodate further policies */
new_desc_elems = static_cast<struct scs_desc_elem *>(os_realloc(scs_data->scs_desc_elems,
(num_scs_ids + 1) * sizeof(struct scs_desc_elem)));
if (!new_desc_elems) {
os_free(elem);
reports.push_back(status);
continue;
}
scs_data->scs_desc_elems = new_desc_elems;
os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_ids *
sizeof(desc_elem), &desc_elem, sizeof(desc_elem));
num_scs_ids++;
scs_data->num_scs_desc = num_scs_ids;
status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::SENT;
reports.push_back(status);
}
wpas_send_scs_req(wpa_s);
return {std::vector<QosPolicyScsRequestStatus>(reports),
ndk::ScopedAStatus::ok()};
}
std::pair<std::vector<QosPolicyScsRequestStatus>, ndk::ScopedAStatus>
StaIface::removeQosPolicyForScsInternal(const std::vector<uint8_t>& scsPolicyIds)
{
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct scs_robust_av_data *scs_data = &wpa_s->scs_robust_av_req;
struct scs_desc_elem desc_elem;
int count;
unsigned int num_scs_ids = 0;
std::vector<QosPolicyScsRequestStatus> reports;
struct active_scs_elem *scs_desc;
if (wpa_s->ongoing_scs_req) {
wpa_printf(MSG_ERROR, "AIDL: SCS Request already in queue");
return {std::vector<QosPolicyScsRequestStatus>(),
createStatus(SupplicantStatusCode::FAILURE_ONGOING_REQUEST)};
}
free_up_scs_desc(scs_data);
count = scsPolicyIds.size();
for (int i = 0; i < count; i++) {
struct scs_desc_elem *new_desc_elems;
QosPolicyScsRequestStatus status;
bool policy_id_exists = false;
memset(&desc_elem, 0, sizeof(desc_elem));
desc_elem.scs_id = scsPolicyIds[i];
status.policyId = scsPolicyIds[i];
desc_elem.request_type = SCS_REQ_REMOVE;
dl_list_for_each(scs_desc, &wpa_s->active_scs_ids,
struct active_scs_elem, list) {
if (desc_elem.scs_id == scs_desc->scs_id) {
policy_id_exists = true;
break;
}
}
if (policy_id_exists == false) {
status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::NOT_EXIST;
reports.push_back(status);
continue;
}
new_desc_elems = static_cast<struct scs_desc_elem *>(os_realloc(scs_data->scs_desc_elems, (num_scs_ids + 1) *
sizeof(struct scs_desc_elem)));
if (!new_desc_elems) {
status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::INVALID;
reports.push_back(status);
continue;
}
scs_data->scs_desc_elems = new_desc_elems;
os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_ids *
sizeof(desc_elem), &desc_elem, sizeof(desc_elem));
num_scs_ids++;
scs_data->num_scs_desc = num_scs_ids;
status.qosPolicyScsRequestStatusCode = QosPolicyScsRequestStatusCode::SENT;
reports.push_back(status);
}
wpas_send_scs_req(wpa_s);
return {std::vector<QosPolicyScsRequestStatus>(reports),
ndk::ScopedAStatus::ok()};
}
::ndk::ScopedAStatus StaIface::configureMscsInternal(const MscsParams& params) {
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct robust_av_data *robust_av = &wpa_s->robust_av;
os_memset(robust_av, 0, sizeof(struct robust_av_data));
if (params.upLimit < 0 || params.upLimit > 7) {
wpa_printf(MSG_ERROR, "Invalid MSCS params - upLimit=%d", params.upLimit);
return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
}
if (params.streamTimeoutUs < 0 || params.streamTimeoutUs > 60000000 /* 60 sec */) {
wpa_printf(MSG_ERROR, "Invalid MSCS params - streamTimeoutUs=%d", params.streamTimeoutUs);
return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
}
robust_av->request_type = SCS_REQ_ADD;
robust_av->up_bitmap = params.upBitmap;
robust_av->up_limit = params.upLimit;
robust_av->stream_timeout = params.streamTimeoutUs;
robust_av->frame_classifier[0] = params.frameClassifierMask; // single type-4 frame classifier mask
robust_av->frame_classifier_len = 1;
int status = wpas_send_mscs_req(wpa_s);
wpa_printf(MSG_INFO, "MSCS add request status: %d", status);
// Mark config as invalid to avoid retransmitting automatically.
robust_av->valid_config = false;
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus StaIface::disableMscsInternal() {
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
struct robust_av_data *robust_av = &wpa_s->robust_av;
os_memset(robust_av, 0, sizeof(struct robust_av_data));
robust_av->request_type = SCS_REQ_REMOVE;
robust_av->valid_config = false;
int status = wpas_send_mscs_req(wpa_s);
wpa_printf(MSG_INFO, "MSCS remove request status: %d", status);
return ndk::ScopedAStatus::ok();
}
/**
* 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 supplicant
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl