/* * WPA Supplicant - Manager for Aidl interface objects * 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 #include #include #include #include "aidl_manager.h" #include "misc_utils.h" #include #include #include extern "C" { #include "scan.h" #include "src/eap_common/eap_sim_common.h" #include "list.h" } namespace { constexpr uint8_t kWfdDeviceInfoLen = 6; constexpr uint8_t kWfdR2DeviceInfoLen = 2; // GSM-AUTH::[:] constexpr char kGsmAuthRegex2[] = "GSM-AUTH:([0-9a-f]+):([0-9a-f]+)"; constexpr char kGsmAuthRegex3[] = "GSM-AUTH:([0-9a-f]+):([0-9a-f]+):([0-9a-f]+)"; // UMTS-AUTH:: constexpr char kUmtsAuthRegex[] = "UMTS-AUTH:([0-9a-f]+):([0-9a-f]+)"; constexpr size_t kGsmRandLenBytes = GSM_RAND_LEN; constexpr size_t kUmtsRandLenBytes = EAP_AKA_RAND_LEN; constexpr size_t kUmtsAutnLenBytes = EAP_AKA_AUTN_LEN; const std::vector kZeroBssid = {0, 0, 0, 0, 0, 0}; using aidl::android::hardware::wifi::supplicant::GsmRand; using aidl::android::hardware::wifi::supplicant::KeyMgmtMask; /** * Check if the provided |wpa_supplicant| structure represents a P2P iface or * not. */ constexpr bool isP2pIface(const struct wpa_supplicant *wpa_s) { return wpa_s->global->p2p_init_wpa_s == wpa_s; } /** * Creates a unique key for the network using the provided |ifname| and * |network_id| to be used in the internal map of |ISupplicantNetwork| objects. * This is of the form |ifname|_|network_id|. For ex: "wlan0_1". * * @param ifname Name of the corresponding interface. * @param network_id ID of the corresponding network. */ const std::string getNetworkObjectMapKey( const std::string &ifname, int network_id) { return ifname + "_" + std::to_string(network_id); } /** * Add callback to the corresponding list after linking to death on the * corresponding aidl object reference. */ template int registerForDeathAndAddCallbackAidlObjectToList( AIBinder_DeathRecipient* death_notifier, const std::shared_ptr &callback, std::vector> &callback_list) { binder_status_t status = AIBinder_linkToDeath(callback->asBinder().get(), death_notifier, nullptr /* cookie */); if (status != STATUS_OK) { wpa_printf( MSG_ERROR, "Error registering for death notification for " "supplicant callback object"); return 1; } callback_list.push_back(callback); return 0; } template int addAidlObjectToMap( const std::string &key, const std::shared_ptr &object, std::map> &object_map) { // Return failure if we already have an object for that |key|. if (object_map.find(key) != object_map.end()) return 1; object_map[key] = object; if (!object_map[key].get()) return 1; return 0; } template int removeAidlObjectFromMap( const std::string &key, std::map> &object_map) { // Return failure if we dont have an object for that |key|. const auto &object_iter = object_map.find(key); if (object_iter == object_map.end()) return 1; object_iter->second->invalidate(); object_map.erase(object_iter); return 0; } template int addIfaceCallbackAidlObjectToMap( AIBinder_DeathRecipient* death_notifier, const std::string &ifname, const std::shared_ptr &callback, std::map>> &callbacks_map) { if (ifname.empty()) return 1; auto iface_callback_map_iter = callbacks_map.find(ifname); if (iface_callback_map_iter == callbacks_map.end()) return 1; auto &iface_callback_list = iface_callback_map_iter->second; // Register for death notification before we add it to our list. return registerForDeathAndAddCallbackAidlObjectToList( death_notifier, callback, iface_callback_list); } template int addNetworkCallbackAidlObjectToMap( AIBinder_DeathRecipient* death_notifier, const std::string &ifname, int network_id, const std::shared_ptr &callback, std::map>> &callbacks_map) { if (ifname.empty() || network_id < 0) return 1; // Generate the key to be used to lookup the network. const std::string network_key = getNetworkObjectMapKey(ifname, network_id); auto network_callback_map_iter = callbacks_map.find(network_key); if (network_callback_map_iter == callbacks_map.end()) return 1; auto &network_callback_list = network_callback_map_iter->second; // Register for death notification before we add it to our list. return registerForDeathAndAddCallbackAidlObjectToList( death_notifier, callback, network_callback_list); } template int removeAllIfaceCallbackAidlObjectsFromMap( AIBinder_DeathRecipient* death_notifier, const std::string &ifname, std::map>> &callbacks_map) { auto iface_callback_map_iter = callbacks_map.find(ifname); if (iface_callback_map_iter == callbacks_map.end()) return 1; const auto &iface_callback_list = iface_callback_map_iter->second; for (const auto &callback : iface_callback_list) { binder_status_t status = AIBinder_linkToDeath(callback->asBinder().get(), death_notifier, nullptr /* cookie */); if (status != STATUS_OK) { wpa_printf( MSG_ERROR, "Error deregistering for death notification for " "iface callback object"); } } callbacks_map.erase(iface_callback_map_iter); return 0; } template int removeAllNetworkCallbackAidlObjectsFromMap( AIBinder_DeathRecipient* death_notifier, const std::string &network_key, std::map>> &callbacks_map) { auto network_callback_map_iter = callbacks_map.find(network_key); if (network_callback_map_iter == callbacks_map.end()) return 1; const auto &network_callback_list = network_callback_map_iter->second; for (const auto &callback : network_callback_list) { binder_status_t status = AIBinder_linkToDeath(callback->asBinder().get(), death_notifier, nullptr /* cookie */); if (status != STATUS_OK) { wpa_printf( MSG_ERROR, "Error deregistering for death " "notification for " "network callback object"); } } callbacks_map.erase(network_callback_map_iter); return 0; } template void removeIfaceCallbackAidlObjectFromMap( const std::string &ifname, const std::shared_ptr &callback, std::map>> &callbacks_map) { if (ifname.empty()) return; auto iface_callback_map_iter = callbacks_map.find(ifname); if (iface_callback_map_iter == callbacks_map.end()) return; auto &iface_callback_list = iface_callback_map_iter->second; iface_callback_list.erase( std::remove( iface_callback_list.begin(), iface_callback_list.end(), callback), iface_callback_list.end()); } template void removeNetworkCallbackAidlObjectFromMap( const std::string &ifname, int network_id, const std::shared_ptr &callback, std::map>> &callbacks_map) { if (ifname.empty() || network_id < 0) return; // Generate the key to be used to lookup the network. const std::string network_key = getNetworkObjectMapKey(ifname, network_id); auto network_callback_map_iter = callbacks_map.find(network_key); if (network_callback_map_iter == callbacks_map.end()) return; auto &network_callback_list = network_callback_map_iter->second; network_callback_list.erase( std::remove( network_callback_list.begin(), network_callback_list.end(), callback), network_callback_list.end()); } template void callWithEachIfaceCallback( const std::string &ifname, const std::function)> &method, const std::map>> &callbacks_map) { if (ifname.empty()) return; auto iface_callback_map_iter = callbacks_map.find(ifname); if (iface_callback_map_iter == callbacks_map.end()) return; const auto &iface_callback_list = iface_callback_map_iter->second; for (const auto &callback : iface_callback_list) { if (!method(callback).isOk()) { wpa_printf( MSG_ERROR, "Failed to invoke AIDL iface callback"); } } } template void callWithEachNetworkCallback( const std::string &ifname, int network_id, const std::function< ndk::ScopedAStatus(std::shared_ptr)> &method, const std::map>> &callbacks_map) { if (ifname.empty() || network_id < 0) return; // Generate the key to be used to lookup the network. const std::string network_key = getNetworkObjectMapKey(ifname, network_id); auto network_callback_map_iter = callbacks_map.find(network_key); if (network_callback_map_iter == callbacks_map.end()) return; const auto &network_callback_list = network_callback_map_iter->second; for (const auto &callback : network_callback_list) { if (!method(callback).isOk()) { wpa_printf( MSG_ERROR, "Failed to invoke AIDL network callback"); } } } int parseGsmAuthNetworkRequest( const std::string ¶ms_str, std::vector *out_rands) { std::smatch matches; std::regex params_gsm_regex2(kGsmAuthRegex2); std::regex params_gsm_regex3(kGsmAuthRegex3); if (!std::regex_match(params_str, matches, params_gsm_regex3) && !std::regex_match(params_str, matches, params_gsm_regex2)) { return 1; } for (uint32_t i = 1; i < matches.size(); i++) { GsmRand rand; rand.data = std::vector(kGsmRandLenBytes); const auto &match = matches[i]; WPA_ASSERT(match.size() >= 2 * rand.data.size()); if (hexstr2bin(match.str().c_str(), rand.data.data(), rand.data.size())) { wpa_printf(MSG_ERROR, "Failed to parse GSM auth params"); return 1; } out_rands->push_back(rand); } return 0; } int parseUmtsAuthNetworkRequest( const std::string ¶ms_str, std::vector *out_rand, std::vector *out_autn) { std::smatch matches; std::regex params_umts_regex(kUmtsAuthRegex); if (!std::regex_match(params_str, matches, params_umts_regex)) { return 1; } WPA_ASSERT(matches[1].size() >= 2 * out_rand->size()); if (hexstr2bin( matches[1].str().c_str(), out_rand->data(), out_rand->size())) { wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params"); return 1; } WPA_ASSERT(matches[2].size() >= 2 * out_autn->size()); if (hexstr2bin( matches[2].str().c_str(), out_autn->data(), out_autn->size())) { wpa_printf(MSG_ERROR, "Failed to parse UMTS auth params"); return 1; } return 0; } inline std::vector byteArrToVec(const uint8_t* arr, int len) { return std::vector{arr, arr + len}; } inline std::vector macAddrToVec(const uint8_t* mac_addr) { return byteArrToVec(mac_addr, ETH_ALEN); } inline std::array macAddrToArray(const uint8_t* mac_addr) { std::array arr; std::copy(mac_addr, mac_addr + ETH_ALEN, std::begin(arr)); return arr; } // Raw pointer to the global structure maintained by the core. // Declared here to be accessible to onDeath() struct wpa_global *wpa_global_; void onDeath(void* cookie) { wpa_printf(MSG_ERROR, "Client died. Terminating..."); wpa_supplicant_terminate_proc(wpa_global_); } } // namespace namespace aidl { namespace android { namespace hardware { namespace wifi { namespace supplicant { AidlManager *AidlManager::instance_ = NULL; AidlManager *AidlManager::getInstance() { if (!instance_) instance_ = new AidlManager(); return instance_; } void AidlManager::destroyInstance() { if (instance_) delete instance_; instance_ = NULL; } int AidlManager::registerAidlService(struct wpa_global *global) { // Create the main aidl service object and register it. wpa_printf(MSG_INFO, "Starting AIDL supplicant"); wpa_printf(MSG_INFO, "Interface version: %d", Supplicant::version); supplicant_object_ = ndk::SharedRefBase::make(global); wpa_global_ = global; std::string instance = std::string() + Supplicant::descriptor + "/default"; if (AServiceManager_addService(supplicant_object_->asBinder().get(), instance.c_str()) != STATUS_OK) { return 1; } // Initialize the death notifier. death_notifier_ = AIBinder_DeathRecipient_new(onDeath); return 0; } /** * Register an interface to aidl manager. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface. * * @return 0 on success, 1 on failure. */ int AidlManager::registerInterface(struct wpa_supplicant *wpa_s) { if (!wpa_s) return 1; if (isP2pIface(wpa_s)) { if (addAidlObjectToMap( wpa_s->ifname, ndk::SharedRefBase::make(wpa_s->global, wpa_s->ifname), p2p_iface_object_map_)) { wpa_printf( MSG_ERROR, "Failed to register P2P interface with AIDL " "control: %s", wpa_s->ifname); return 1; } p2p_iface_callbacks_map_[wpa_s->ifname] = std::vector>(); } else { if (addAidlObjectToMap( wpa_s->ifname, ndk::SharedRefBase::make(wpa_s->global, wpa_s->ifname), sta_iface_object_map_)) { wpa_printf( MSG_ERROR, "Failed to register STA interface with AIDL " "control: %s", wpa_s->ifname); return 1; } sta_iface_callbacks_map_[wpa_s->ifname] = std::vector>(); // Turn on Android specific customizations for STA interfaces // here! // // Turn on scan mac randomization only if driver supports. if (wpa_s->mac_addr_rand_supported & MAC_ADDR_RAND_SCAN) { if (wpas_mac_addr_rand_scan_set( wpa_s, MAC_ADDR_RAND_SCAN, nullptr, nullptr)) { wpa_printf( MSG_ERROR, "Failed to enable scan mac randomization"); } } // Enable randomized source MAC address for GAS/ANQP // Set the lifetime to 0, guarantees a unique address for each GAS // session wpa_s->conf->gas_rand_mac_addr = WPAS_MAC_ADDR_STYLE_RANDOM; wpa_s->conf->gas_rand_addr_lifetime = 0; } // Invoke the |onInterfaceCreated| method on all registered callbacks. callWithEachSupplicantCallback(std::bind( &ISupplicantCallback::onInterfaceCreated, std::placeholders::_1, misc_utils::charBufToString(wpa_s->ifname))); return 0; } /** * Unregister an interface from aidl manager. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface. * * @return 0 on success, 1 on failure. */ int AidlManager::unregisterInterface(struct wpa_supplicant *wpa_s) { if (!wpa_s) return 1; // Check if this interface is present in P2P map first, else check in // STA map. // Note: We can't use isP2pIface() here because interface // pointers (wpa_s->global->p2p_init_wpa_s == wpa_s) used by the helper // function is cleared by the core before notifying the AIDL interface. bool success = !removeAidlObjectFromMap(wpa_s->ifname, p2p_iface_object_map_); if (success) { // assumed to be P2P success = !removeAllIfaceCallbackAidlObjectsFromMap( death_notifier_, wpa_s->ifname, p2p_iface_callbacks_map_); } else { // assumed to be STA success = !removeAidlObjectFromMap( wpa_s->ifname, sta_iface_object_map_); if (success) { success = !removeAllIfaceCallbackAidlObjectsFromMap( death_notifier_, wpa_s->ifname, sta_iface_callbacks_map_); } } if (!success) { wpa_printf( MSG_ERROR, "Failed to unregister interface with AIDL " "control: %s", wpa_s->ifname); return 1; } // Invoke the |onInterfaceRemoved| method on all registered callbacks. callWithEachSupplicantCallback(std::bind( &ISupplicantCallback::onInterfaceRemoved, std::placeholders::_1, misc_utils::charBufToString(wpa_s->ifname))); return 0; } /** * Register a network to aidl manager. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the network is added. * @param ssid |wpa_ssid| struct corresponding to the network being added. * * @return 0 on success, 1 on failure. */ int AidlManager::registerNetwork( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { if (!wpa_s || !ssid) return 1; // Generate the key to be used to lookup the network. const std::string network_key = getNetworkObjectMapKey(wpa_s->ifname, ssid->id); if (isP2pIface(wpa_s)) { if (addAidlObjectToMap( network_key, ndk::SharedRefBase::make(wpa_s->global, wpa_s->ifname, ssid->id), p2p_network_object_map_)) { wpa_printf( MSG_ERROR, "Failed to register P2P network with AIDL " "control: %d", ssid->id); return 1; } } else { if (addAidlObjectToMap( network_key, ndk::SharedRefBase::make(wpa_s->global, wpa_s->ifname, ssid->id), sta_network_object_map_)) { wpa_printf( MSG_ERROR, "Failed to register STA network with AIDL " "control: %d", ssid->id); return 1; } sta_network_callbacks_map_[network_key] = std::vector>(); // Invoke the |onNetworkAdded| method on all registered // callbacks. callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onNetworkAdded, std::placeholders::_1, ssid->id)); } return 0; } /** * Unregister a network from aidl manager. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the network is added. * @param ssid |wpa_ssid| struct corresponding to the network being added. * * @return 0 on success, 1 on failure. */ int AidlManager::unregisterNetwork( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { if (!wpa_s || !ssid) return 1; // Generate the key to be used to lookup the network. const std::string network_key = getNetworkObjectMapKey(wpa_s->ifname, ssid->id); if (isP2pIface(wpa_s)) { if (removeAidlObjectFromMap( network_key, p2p_network_object_map_)) { wpa_printf( MSG_ERROR, "Failed to unregister P2P network with AIDL " "control: %d", ssid->id); return 1; } } else { if (removeAidlObjectFromMap( network_key, sta_network_object_map_)) { wpa_printf( MSG_ERROR, "Failed to unregister STA network with AIDL " "control: %d", ssid->id); return 1; } if (removeAllNetworkCallbackAidlObjectsFromMap( death_notifier_, network_key, sta_network_callbacks_map_)) { return 1; } // Invoke the |onNetworkRemoved| method on all registered // callbacks. callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onNetworkRemoved, std::placeholders::_1, ssid->id)); } return 0; } // Some of the undefined AKMs in AIDL (Mostly extension AKMs like FT AKMs) // are mapped to the main AKM. This is for the framework to map the AKM to // correct security type. KeyMgmtMask convertSupplicantSelectedKeyMgmtForConnectionToAidl(int key_mgmt) { switch (key_mgmt) { case WPA_KEY_MGMT_IEEE8021X: return KeyMgmtMask::WPA_EAP; case WPA_KEY_MGMT_PSK: return KeyMgmtMask::WPA_PSK; case WPA_KEY_MGMT_NONE: return KeyMgmtMask::NONE; case WPA_KEY_MGMT_IEEE8021X_NO_WPA: return KeyMgmtMask::IEEE8021X; case WPA_KEY_MGMT_FT_IEEE8021X: return KeyMgmtMask::FT_EAP; case WPA_KEY_MGMT_FT_PSK: return KeyMgmtMask::FT_PSK; case WPA_KEY_MGMT_IEEE8021X_SHA256: return KeyMgmtMask::WPA_EAP_SHA256; case WPA_KEY_MGMT_PSK_SHA256: return KeyMgmtMask::WPA_PSK_SHA256; case WPA_KEY_MGMT_SAE: case WPA_KEY_MGMT_FT_SAE: case WPA_KEY_MGMT_SAE_EXT_KEY: case WPA_KEY_MGMT_FT_SAE_EXT_KEY: return KeyMgmtMask::SAE; case WPA_KEY_MGMT_WAPI_PSK: return KeyMgmtMask::WAPI_PSK; case WPA_KEY_MGMT_WAPI_CERT: return KeyMgmtMask::WAPI_CERT; case WPA_KEY_MGMT_OSEN: return KeyMgmtMask::OSEN; case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: return KeyMgmtMask::SUITE_B_192; case WPA_KEY_MGMT_FILS_SHA256: case WPA_KEY_MGMT_FT_FILS_SHA256: return KeyMgmtMask::FILS_SHA256; case WPA_KEY_MGMT_FILS_SHA384: case WPA_KEY_MGMT_FT_FILS_SHA384: return KeyMgmtMask::FILS_SHA384; case WPA_KEY_MGMT_OWE: return KeyMgmtMask::OWE; case WPA_KEY_MGMT_DPP: return KeyMgmtMask::DPP; default: wpa_printf(MSG_INFO, "Unable to convert supplicant key_mgmt 0x%x to AIDL", key_mgmt); return (KeyMgmtMask) key_mgmt; } } /** * Notify all listeners about any state changes on a particular interface. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the state change event occured. */ int AidlManager::notifyStateChange(struct wpa_supplicant *wpa_s) { if (!wpa_s) return 1; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return 1; // Invoke the |onStateChanged| method on all registered callbacks. SupplicantStateChangeData aidl_state_change_data = {}; aidl_state_change_data.id = UINT32_MAX; aidl_state_change_data.newState = static_cast(wpa_s->wpa_state); if (wpa_s->current_ssid) { aidl_state_change_data.id = wpa_s->current_ssid->id; std::vector aidl_ssid( wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len); aidl_state_change_data.ssid = aidl_ssid; wpa_printf(MSG_INFO, "assoc key_mgmt 0x%x network key_mgmt 0x%x", wpa_s->key_mgmt, wpa_s->current_ssid->key_mgmt); } std::array aidl_bssid; // wpa_supplicant sets the |pending_bssid| field when it starts a // connection. Only after association state does it update the |bssid| // field. So, in the AIDL callback send the appropriate bssid. if (wpa_s->wpa_state <= WPA_ASSOCIATED) { aidl_bssid = macAddrToArray(wpa_s->pending_bssid); } else { aidl_bssid = macAddrToArray(wpa_s->bssid); } aidl_state_change_data.bssid = aidl_bssid; aidl_state_change_data.filsHlpSent = (wpa_auth_alg_fils(wpa_s->auth_alg) && !dl_list_empty(&wpa_s->fils_hlp_req) && (wpa_s->wpa_state == WPA_COMPLETED)) ? true : false; if (wpa_s->wpa_state >= WPA_ASSOCIATED) { // wpa_supplicant sets the frequency on receiving the EVENT_ASSOC. aidl_state_change_data.frequencyMhz = wpa_s->assoc_freq; // The key_mgmt is selected prior to sending the connect command // to driver. But in case of CROSS-AKM Connection/Roaming, the // key_mgmt is updated with the one from association IE. So the // selected key_mgmt is accurate only after moving to // associated state. aidl_state_change_data.keyMgmtMask = convertSupplicantSelectedKeyMgmtForConnectionToAidl(wpa_s->key_mgmt); } // Invoke the |onStateChanged| method on all registered callbacks. std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaIfaceCallback::onSupplicantStateChanged, std::placeholders::_1, aidl_state_change_data); callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), func); return 0; } /** * Notify all listeners about a request on a particular network. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the network is present. * @param ssid |wpa_ssid| struct corresponding to the network. * @param type type of request. * @param param addition params associated with the request. */ int AidlManager::notifyNetworkRequest( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type, const char *param) { if (!wpa_s || !ssid) return 1; const std::string network_key = getNetworkObjectMapKey(wpa_s->ifname, ssid->id); if (sta_network_object_map_.find(network_key) == sta_network_object_map_.end()) return 1; if (type == WPA_CTRL_REQ_EAP_IDENTITY) { callWithEachStaNetworkCallback( misc_utils::charBufToString(wpa_s->ifname), ssid->id, std::bind( &ISupplicantStaNetworkCallback:: onNetworkEapIdentityRequest, std::placeholders::_1)); return 0; } if (type == WPA_CTRL_REQ_SIM) { std::vector gsm_rands; std::vector umts_rand = std::vector(16); std::vector umts_autn = std::vector(16); if (!parseGsmAuthNetworkRequest(param, &gsm_rands)) { NetworkRequestEapSimGsmAuthParams aidl_params; aidl_params.rands = gsm_rands; callWithEachStaNetworkCallback( misc_utils::charBufToString(wpa_s->ifname), ssid->id, std::bind( &ISupplicantStaNetworkCallback:: onNetworkEapSimGsmAuthRequest, std::placeholders::_1, aidl_params)); return 0; } if (!parseUmtsAuthNetworkRequest( param, &umts_rand, &umts_autn)) { NetworkRequestEapSimUmtsAuthParams aidl_params; aidl_params.rand = umts_rand; aidl_params.autn = umts_autn; callWithEachStaNetworkCallback( misc_utils::charBufToString(wpa_s->ifname), ssid->id, std::bind( &ISupplicantStaNetworkCallback:: onNetworkEapSimUmtsAuthRequest, std::placeholders::_1, aidl_params)); return 0; } } return 1; } #ifdef CONFIG_INTERWORKING /** * Notify that the AT_PERMANENT_ID_REQ is denied from eap_peer when the strict * conservative peer mode is enabled. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the network is present. */ void AidlManager::notifyPermanentIdReqDenied(struct wpa_supplicant *wpa_s) { if (!wpa_s->current_ssid) { wpa_printf(MSG_ERROR, "Current network NULL. Drop permanent_id_req_denied event!"); return; } struct wpa_ssid *current_ssid = wpa_s->current_ssid; callWithEachStaNetworkCallback( misc_utils::charBufToString(wpa_s->ifname), current_ssid->id, std::bind( &ISupplicantStaNetworkCallback:: onPermanentIdReqDenied, std::placeholders::_1)); } /** * Notify all listeners about the end of an ANQP query. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface. * @param bssid BSSID of the access point. * @param result Result of the operation ("SUCCESS" or "FAILURE"). * @param anqp |wpa_bss_anqp| ANQP data fetched. */ void AidlManager::notifyAnqpQueryDone( struct wpa_supplicant *wpa_s, const u8 *bssid, const char *result, const struct wpa_bss_anqp *anqp) { if (!wpa_s || !bssid || !result || !anqp) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; AnqpData aidl_anqp_data; Hs20AnqpData aidl_hs20_anqp_data; if (std::string(result) == "SUCCESS") { aidl_anqp_data.venueName = misc_utils::convertWpaBufToVector(anqp->venue_name); aidl_anqp_data.roamingConsortium = misc_utils::convertWpaBufToVector(anqp->roaming_consortium); aidl_anqp_data.ipAddrTypeAvailability = misc_utils::convertWpaBufToVector( anqp->ip_addr_type_availability); aidl_anqp_data.naiRealm = misc_utils::convertWpaBufToVector(anqp->nai_realm); aidl_anqp_data.anqp3gppCellularNetwork = misc_utils::convertWpaBufToVector(anqp->anqp_3gpp); aidl_anqp_data.domainName = misc_utils::convertWpaBufToVector(anqp->domain_name); struct wpa_bss_anqp_elem *elem; dl_list_for_each(elem, &anqp->anqp_elems, struct wpa_bss_anqp_elem, list) { if (elem->infoid == ANQP_VENUE_URL && elem->protected_response) { aidl_anqp_data.venueUrl = misc_utils::convertWpaBufToVector(elem->payload); break; } } #ifdef CONFIG_HS20 aidl_hs20_anqp_data.operatorFriendlyName = misc_utils::convertWpaBufToVector( anqp->hs20_operator_friendly_name); aidl_hs20_anqp_data.wanMetrics = misc_utils::convertWpaBufToVector(anqp->hs20_wan_metrics); aidl_hs20_anqp_data.connectionCapability = misc_utils::convertWpaBufToVector( anqp->hs20_connection_capability); aidl_hs20_anqp_data.osuProvidersList = misc_utils::convertWpaBufToVector( anqp->hs20_osu_providers_list); #else aidl_hs20_anqp_data.operatorFriendlyName = misc_utils::convertWpaBufToVector(NULL); aidl_hs20_anqp_data.wanMetrics = misc_utils::convertWpaBufToVector(NULL); aidl_hs20_anqp_data.connectionCapability = misc_utils::convertWpaBufToVector(NULL); aidl_hs20_anqp_data.osuProvidersList = misc_utils::convertWpaBufToVector(NULL); #endif /* CONFIG_HS20 */ } callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onAnqpQueryDone, std::placeholders::_1, macAddrToVec(bssid), aidl_anqp_data, aidl_hs20_anqp_data)); } #endif /* CONFIG_INTERWORKING */ /** * Notify all listeners about the end of an HS20 icon query. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface. * @param bssid BSSID of the access point. * @param file_name Name of the icon file. * @param image Raw bytes of the icon file. * @param image_length Size of the the icon file. */ void AidlManager::notifyHs20IconQueryDone( struct wpa_supplicant *wpa_s, const u8 *bssid, const char *file_name, const u8 *image, u32 image_length) { if (!wpa_s || !bssid || !file_name || !image) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onHs20IconQueryDone, std::placeholders::_1, macAddrToVec(bssid), file_name, std::vector(image, image + image_length))); } /** * Notify all listeners about the reception of HS20 subscription * remediation notification from the server. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface. * @param url URL of the server. * @param osu_method OSU method (OMA_DM or SOAP_XML_SPP). */ void AidlManager::notifyHs20RxSubscriptionRemediation( struct wpa_supplicant *wpa_s, const char *url, u8 osu_method) { if (!wpa_s || !url) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; OsuMethod aidl_osu_method; if (osu_method & 0x1) { aidl_osu_method = OsuMethod::OMA_DM; } else if (osu_method & 0x2) { aidl_osu_method = OsuMethod::SOAP_XML_SPP; } callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onHs20SubscriptionRemediation, std::placeholders::_1, macAddrToVec(wpa_s->bssid), aidl_osu_method, url)); } /** * Notify all listeners about the reception of HS20 imminent death * notification from the server. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface. * @param code Death reason code sent from server. * @param reauth_delay Reauthentication delay in seconds sent from server. * @param url URL of the server containing the reason text. */ void AidlManager::notifyHs20RxDeauthImminentNotice( struct wpa_supplicant *wpa_s, u8 code, u16 reauth_delay, const char *url) { if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onHs20DeauthImminentNotice, std::placeholders::_1, macAddrToVec(wpa_s->bssid), code, reauth_delay, misc_utils::charBufToString(url))); } /** * Notify all listeners about the reception of HS20 terms and conditions * acceptance notification from the server. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface. * @param url URL of the T&C server. */ void AidlManager::notifyHs20RxTermsAndConditionsAcceptance( struct wpa_supplicant *wpa_s, const char *url) { if (!wpa_s || !url) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback ::onHs20TermsAndConditionsAcceptanceRequestedNotification, std::placeholders::_1, macAddrToVec(wpa_s->bssid), url)); } /** * Notify all listeners about the reason code for disconnection from the * currently connected network. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the network is present. */ void AidlManager::notifyDisconnectReason(struct wpa_supplicant *wpa_s) { if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; const u8 *bssid = wpa_s->bssid; if (is_zero_ether_addr(bssid)) { bssid = wpa_s->pending_bssid; } callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onDisconnected, std::placeholders::_1, macAddrToVec(bssid), wpa_s->disconnect_reason < 0, static_cast( abs(wpa_s->disconnect_reason)))); } /** * Notify all listeners about association reject from the access point to which * we are attempting to connect. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the network is present. * @param bssid bssid of AP that rejected the association. * @param timed_out flag to indicate failure is due to timeout * (auth, assoc, ...) rather than explicit rejection response from the AP. * @param assoc_resp_ie Association response IE. * @param assoc_resp_ie_len Association response IE length. */ void AidlManager::notifyAssocReject(struct wpa_supplicant *wpa_s, const u8 *bssid, u8 timed_out, const u8 *assoc_resp_ie, size_t assoc_resp_ie_len) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); #ifdef CONFIG_MBO struct wpa_bss *reject_bss; #endif /* CONFIG_MBO */ AssociationRejectionData aidl_assoc_reject_data{}; if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; if (wpa_s->current_ssid) { aidl_assoc_reject_data.ssid = std::vector( wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len); } aidl_assoc_reject_data.bssid = macAddrToVec(bssid); aidl_assoc_reject_data.statusCode = static_cast( wpa_s->assoc_status_code); if (timed_out) { aidl_assoc_reject_data.timedOut = true; } #ifdef CONFIG_MBO if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) { reject_bss = wpa_s->current_bss; } else { reject_bss = wpa_bss_get_bssid(wpa_s, bssid); } if (reject_bss && assoc_resp_ie && assoc_resp_ie_len > 0) { if (wpa_s->assoc_status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS) { const u8 *rssi_rej; rssi_rej = mbo_get_attr_from_ies( assoc_resp_ie, assoc_resp_ie_len, OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT); if (rssi_rej && rssi_rej[1] == 2) { wpa_printf(MSG_INFO, "OCE: RSSI-based association rejection from " MACSTR " Delta RSSI: %u, Retry Delay: %u bss rssi: %d", MAC2STR(reject_bss->bssid), rssi_rej[2], rssi_rej[3], reject_bss->level); aidl_assoc_reject_data.isOceRssiBasedAssocRejectAttrPresent = true; aidl_assoc_reject_data.oceRssiBasedAssocRejectData.deltaRssi = rssi_rej[2]; aidl_assoc_reject_data.oceRssiBasedAssocRejectData.retryDelayS = rssi_rej[3]; } } else if (wpa_s->assoc_status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY || wpa_s->assoc_status_code == WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA) { const u8 *assoc_disallowed; assoc_disallowed = mbo_get_attr_from_ies( assoc_resp_ie, assoc_resp_ie_len, MBO_ATTR_ID_ASSOC_DISALLOW); if (assoc_disallowed && assoc_disallowed[1] == 1) { wpa_printf(MSG_INFO, "MBO: association disallowed indication from " MACSTR " Reason: %d", MAC2STR(reject_bss->bssid), assoc_disallowed[2]); aidl_assoc_reject_data.isMboAssocDisallowedReasonCodePresent = true; aidl_assoc_reject_data.mboAssocDisallowedReason = static_cast(assoc_disallowed[2]); } } } #endif /* CONFIG_MBO */ const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaIfaceCallback::onAssociationRejected, std::placeholders::_1, aidl_assoc_reject_data); callWithEachStaIfaceCallback(aidl_ifname, func); } void AidlManager::notifyAuthTimeout(struct wpa_supplicant *wpa_s) { if (!wpa_s) return; const std::string ifname(wpa_s->ifname); if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end()) return; const u8 *bssid = wpa_s->bssid; if (is_zero_ether_addr(bssid)) { bssid = wpa_s->pending_bssid; } callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onAuthenticationTimeout, std::placeholders::_1, macAddrToVec(bssid))); } void AidlManager::notifyBssidChanged(struct wpa_supplicant *wpa_s) { if (!wpa_s) return; const std::string ifname(wpa_s->ifname); if (sta_iface_object_map_.find(ifname) == sta_iface_object_map_.end()) return; // wpa_supplicant does not explicitly give us the reason for bssid // change, but we figure that out from what is set out of |wpa_s->bssid| // & |wpa_s->pending_bssid|. const u8 *bssid; BssidChangeReason reason; if (is_zero_ether_addr(wpa_s->bssid) && !is_zero_ether_addr(wpa_s->pending_bssid)) { bssid = wpa_s->pending_bssid; reason = BssidChangeReason::ASSOC_START; } else if ( !is_zero_ether_addr(wpa_s->bssid) && is_zero_ether_addr(wpa_s->pending_bssid)) { bssid = wpa_s->bssid; reason = BssidChangeReason::ASSOC_COMPLETE; } else if ( is_zero_ether_addr(wpa_s->bssid) && is_zero_ether_addr(wpa_s->pending_bssid)) { bssid = wpa_s->pending_bssid; reason = BssidChangeReason::DISASSOC; } else { wpa_printf(MSG_ERROR, "Unknown bssid change reason"); return; } callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onBssidChanged, std::placeholders::_1, reason, macAddrToVec(bssid))); } void AidlManager::notifyWpsEventFail( struct wpa_supplicant *wpa_s, uint8_t *peer_macaddr, uint16_t config_error, uint16_t error_indication) { if (!wpa_s || !peer_macaddr) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onWpsEventFail, std::placeholders::_1, macAddrToVec(peer_macaddr), static_cast( config_error), static_cast( error_indication))); } void AidlManager::notifyWpsEventSuccess(struct wpa_supplicant *wpa_s) { if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onWpsEventSuccess, std::placeholders::_1)); } void AidlManager::notifyWpsEventPbcOverlap(struct wpa_supplicant *wpa_s) { if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onWpsEventPbcOverlap, std::placeholders::_1)); } void AidlManager::notifyP2pDeviceFound( struct wpa_supplicant *wpa_s, const u8 *addr, const struct p2p_peer_info *info, const u8 *peer_wfd_device_info, u8 peer_wfd_device_info_len, const u8 *peer_wfd_r2_device_info, u8 peer_wfd_r2_device_info_len) { if (!wpa_s || !addr || !info) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; std::vector aidl_peer_wfd_device_info(kWfdDeviceInfoLen); if (peer_wfd_device_info) { if (peer_wfd_device_info_len != kWfdDeviceInfoLen) { wpa_printf( MSG_ERROR, "Unexpected WFD device info len: %d", peer_wfd_device_info_len); } else { os_memcpy( aidl_peer_wfd_device_info.data(), peer_wfd_device_info, kWfdDeviceInfoLen); } } std::vector aidl_peer_wfd_r2_device_info; if (peer_wfd_r2_device_info) { if (peer_wfd_r2_device_info_len != kWfdR2DeviceInfoLen) { wpa_printf( MSG_ERROR, "Unexpected WFD R2 device info len: %d", peer_wfd_r2_device_info_len); return; } else { std::copy(peer_wfd_r2_device_info, peer_wfd_r2_device_info + peer_wfd_r2_device_info_len, std::back_inserter(aidl_peer_wfd_r2_device_info)); } } std::vector aidl_vendor_elems; if (NULL != info->vendor_elems && wpabuf_len(info->vendor_elems) > 0) { aidl_vendor_elems.reserve(wpabuf_len(info->vendor_elems)); std::copy(wpabuf_head_u8(info->vendor_elems), wpabuf_head_u8(info->vendor_elems) + wpabuf_len(info->vendor_elems), std::back_inserter(aidl_vendor_elems)); } const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantP2pIfaceCallback::onDeviceFoundWithVendorElements, std::placeholders::_1, macAddrToVec(addr), macAddrToVec(info->p2p_device_addr), byteArrToVec(info->pri_dev_type, 8), misc_utils::charBufToString(info->device_name), static_cast(info->config_methods), info->dev_capab, static_cast(info->group_capab), aidl_peer_wfd_device_info, aidl_peer_wfd_r2_device_info, aidl_vendor_elems); callWithEachP2pIfaceCallback(wpa_s->ifname, func); } void AidlManager::notifyP2pDeviceLost( struct wpa_supplicant *wpa_s, const u8 *p2p_device_addr) { if (!wpa_s || !p2p_device_addr) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onDeviceLost, std::placeholders::_1, macAddrToVec(p2p_device_addr))); } void AidlManager::notifyP2pFindStopped(struct wpa_supplicant *wpa_s) { if (!wpa_s) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onFindStopped, std::placeholders::_1)); } void AidlManager::notifyP2pGoNegReq( struct wpa_supplicant *wpa_s, const u8 *src_addr, u16 dev_passwd_id, u8 /* go_intent */) { if (!wpa_s || !src_addr) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onGoNegotiationRequest, std::placeholders::_1, macAddrToVec(src_addr), static_cast( dev_passwd_id))); } void AidlManager::notifyP2pGoNegCompleted( struct wpa_supplicant *wpa_s, const struct p2p_go_neg_results *res) { if (!wpa_s || !res) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onGoNegotiationCompleted, std::placeholders::_1, static_cast( res->status))); } void AidlManager::notifyP2pGroupFormationFailure( struct wpa_supplicant *wpa_s, const char *reason) { if (!wpa_s || !reason) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onGroupFormationFailure, std::placeholders::_1, reason)); } void AidlManager::notifyP2pGroupStarted( struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid, int persistent, int client, const u8 *ip) { if (!wpa_group_s || !wpa_group_s->parent || !ssid) return; // For group notifications, need to use the parent iface for callbacks. struct wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s); if (!wpa_s) return; uint32_t aidl_freq = wpa_group_s->current_bss ? wpa_group_s->current_bss->freq : wpa_group_s->assoc_freq; std::vector aidl_psk(32); if (ssid->psk_set) { aidl_psk.assign(ssid->psk, ssid->psk + 32); } bool aidl_is_go = (client == 0 ? true : false); bool aidl_is_persistent = (persistent == 1 ? true : false); // notify the group device again to ensure the framework knowing this device. struct p2p_data *p2p = wpa_s->global->p2p; struct p2p_device *dev = p2p_get_device(p2p, wpa_group_s->go_dev_addr); if (NULL != dev) { wpa_printf(MSG_DEBUG, "P2P: Update GO device on group started."); p2p->cfg->dev_found(p2p->cfg->cb_ctx, wpa_group_s->go_dev_addr, &dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE)); dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; } P2pGroupStartedEventParams params; params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname); params.isGroupOwner = aidl_is_go; params.ssid = byteArrToVec(ssid->ssid, ssid->ssid_len); params.frequencyMHz = aidl_freq; params.psk = aidl_psk; params.passphrase = misc_utils::charBufToString(ssid->passphrase); params.isPersistent = aidl_is_persistent; params.goDeviceAddress = macAddrToArray(wpa_group_s->go_dev_addr); params.goInterfaceAddress = aidl_is_go ? macAddrToArray(wpa_group_s->own_addr) : macAddrToArray(wpa_group_s->current_bss->bssid); if (NULL != ip && !aidl_is_go) { params.isP2pClientEapolIpAddressInfoPresent = true; os_memcpy(¶ms.p2pClientIpInfo.ipAddressClient, &ip[0], 4); os_memcpy(¶ms.p2pClientIpInfo.ipAddressMask, &ip[4], 4); os_memcpy(¶ms.p2pClientIpInfo.ipAddressGo, &ip[8], 4); wpa_printf(MSG_DEBUG, "P2P: IP Address allocated - CLI: 0x%x MASK: 0x%x GO: 0x%x", params.p2pClientIpInfo.ipAddressClient, params.p2pClientIpInfo.ipAddressMask, params.p2pClientIpInfo.ipAddressGo); } callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind(&ISupplicantP2pIfaceCallback::onGroupStartedWithParams, std::placeholders::_1, params)); } void AidlManager::notifyP2pGroupRemoved( struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid, const char *role) { if (!wpa_group_s || !wpa_group_s->parent || !ssid || !role) return; // For group notifications, need to use the parent iface for callbacks. struct wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s); if (!wpa_s) return; bool aidl_is_go = (std::string(role) == "GO"); callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onGroupRemoved, std::placeholders::_1, misc_utils::charBufToString(wpa_group_s->ifname), aidl_is_go)); } void AidlManager::notifyP2pInvitationReceived( struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *go_dev_addr, const u8 *bssid, int id, int op_freq) { if (!wpa_s || !sa || !go_dev_addr || !bssid) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; int aidl_network_id; if (id < 0) { aidl_network_id = UINT32_MAX; } aidl_network_id = id; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onInvitationReceived, std::placeholders::_1, macAddrToVec(sa), macAddrToVec(go_dev_addr), macAddrToVec(bssid), aidl_network_id, op_freq)); } void AidlManager::notifyP2pInvitationResult( struct wpa_supplicant *wpa_s, int status, const u8 *bssid) { if (!wpa_s) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onInvitationResult, std::placeholders::_1, bssid ? macAddrToVec(bssid) : kZeroBssid, static_cast( status))); } void AidlManager::notifyP2pProvisionDiscovery( struct wpa_supplicant *wpa_s, const u8 *dev_addr, int request, enum p2p_prov_disc_status status, u16 config_methods, unsigned int generated_pin, const char *group_ifname) { if (!wpa_s || !dev_addr) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; P2pProvisionDiscoveryCompletedEventParams params; params.p2pDeviceAddress = macAddrToArray(dev_addr); params.isRequest = (request == 1); params.status = static_cast(status); params.configMethods = static_cast(config_methods); if (generated_pin > 0) { params.generatedPin = misc_utils::convertWpsPinToString(generated_pin); } if (group_ifname != NULL) { params.groupInterfaceName = misc_utils::charBufToString(group_ifname); } callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onProvisionDiscoveryCompletedEvent, std::placeholders::_1, params)); } void AidlManager::notifyP2pSdResponse( struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic, const u8 *tlvs, size_t tlvs_len) { if (!wpa_s || !sa || !tlvs) return; if (p2p_iface_object_map_.find(wpa_s->ifname) == p2p_iface_object_map_.end()) return; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onServiceDiscoveryResponse, std::placeholders::_1, macAddrToVec(sa), update_indic, byteArrToVec(tlvs, tlvs_len))); } void AidlManager::notifyApStaAuthorized( struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr, const u8 *ip) { if (!wpa_group_s || !wpa_group_s->parent || !sta) return; wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s); if (!wpa_s) return; int aidl_ip = 0; if (NULL != ip) { os_memcpy(&aidl_ip, &ip[0], 4); } P2pPeerClientJoinedEventParams params; params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname); params.clientInterfaceAddress = macAddrToArray(sta); params.clientDeviceAddress = p2p_dev_addr ? macAddrToArray(p2p_dev_addr) : macAddrToArray(kZeroBssid.data()); params.clientIpAddress = aidl_ip; callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onPeerClientJoined, std::placeholders::_1, params)); } void AidlManager::notifyApStaDeauthorized( struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr) { if (!wpa_group_s || !wpa_group_s->parent || !sta) return; wpa_supplicant *wpa_s = getTargetP2pIfaceForGroup(wpa_group_s); if (!wpa_s) return; P2pPeerClientDisconnectedEventParams params; params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname); params.clientInterfaceAddress = macAddrToArray(sta); params.clientDeviceAddress = p2p_dev_addr ? macAddrToArray(p2p_dev_addr) : macAddrToArray(kZeroBssid.data()); callWithEachP2pIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantP2pIfaceCallback::onPeerClientDisconnected, std::placeholders::_1, params)); } void AidlManager::notifyExtRadioWorkStart( struct wpa_supplicant *wpa_s, uint32_t id) { if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onExtRadioWorkStart, std::placeholders::_1, id)); } void AidlManager::notifyExtRadioWorkTimeout( struct wpa_supplicant *wpa_s, uint32_t id) { if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onExtRadioWorkTimeout, std::placeholders::_1, id)); } void AidlManager::notifyEapError(struct wpa_supplicant *wpa_s, int error_code) { if (!wpa_s) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onEapFailure, std::placeholders::_1, macAddrToVec(wpa_s->bssid), error_code)); } /** * Notify listener about a new DPP configuration received success event * * @param ifname Interface name * @param config Configuration object */ void AidlManager::notifyDppConfigReceived(struct wpa_supplicant *wpa_s, struct wpa_ssid *config, bool conn_status_requested) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); DppConfigurationData aidl_dpp_config_data = {}; if ((config->key_mgmt & WPA_KEY_MGMT_SAE) && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) { aidl_dpp_config_data.securityAkm = DppAkm::SAE; } else if (config->key_mgmt & WPA_KEY_MGMT_PSK) { aidl_dpp_config_data.securityAkm = DppAkm::PSK; } else if (config->key_mgmt & WPA_KEY_MGMT_DPP) { aidl_dpp_config_data.securityAkm = DppAkm::DPP; } else { /* Unsupported AKM */ wpa_printf(MSG_ERROR, "DPP: Error: Unsupported AKM 0x%X", config->key_mgmt); notifyDppFailure(wpa_s, DppFailureCode::NOT_SUPPORTED); return; } aidl_dpp_config_data.password = misc_utils::charBufToString(config->passphrase); aidl_dpp_config_data.psk = byteArrToVec(config->psk, 32); std::vector aidl_ssid( config->ssid, config->ssid + config->ssid_len); aidl_dpp_config_data.ssid = aidl_ssid; if (aidl_dpp_config_data.securityAkm == DppAkm::DPP) { std::string connector_str = misc_utils::charBufToString(config->dpp_connector); aidl_dpp_config_data.dppConnectionKeys.connector = std::vector(connector_str.begin(), connector_str.end()); aidl_dpp_config_data.dppConnectionKeys.cSign = byteArrToVec(config->dpp_csign, config->dpp_csign_len); aidl_dpp_config_data.dppConnectionKeys.netAccessKey = byteArrToVec(config->dpp_netaccesskey, config->dpp_netaccesskey_len); } aidl_dpp_config_data.connStatusRequested = conn_status_requested; /* At this point, the network is already registered, notify about new * received configuration */ callWithEachStaIfaceCallback(aidl_ifname, std::bind( &ISupplicantStaIfaceCallback::onDppConfigReceived, std::placeholders::_1, aidl_dpp_config_data)); } /** * Notify listener about a DPP configuration sent success event * * @param ifname Interface name */ void AidlManager::notifyDppConfigSent(struct wpa_supplicant *wpa_s) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); callWithEachStaIfaceCallback(aidl_ifname, std::bind(&ISupplicantStaIfaceCallback::onDppSuccessConfigSent, std::placeholders::_1)); } DppStatusErrorCode convertSupplicantDppStatusErrorCodeToAidl( enum dpp_status_error code) { switch (code) { case DPP_STATUS_OK: return DppStatusErrorCode::SUCCESS; case DPP_STATUS_NOT_COMPATIBLE: return DppStatusErrorCode::NOT_COMPATIBLE; case DPP_STATUS_AUTH_FAILURE: return DppStatusErrorCode::AUTH_FAILURE; case DPP_STATUS_UNWRAP_FAILURE: return DppStatusErrorCode::UNWRAP_FAILURE; case DPP_STATUS_BAD_GROUP: return DppStatusErrorCode::BAD_GROUP; case DPP_STATUS_CONFIGURE_FAILURE: return DppStatusErrorCode::CONFIGURE_FAILURE; case DPP_STATUS_RESPONSE_PENDING: return DppStatusErrorCode::RESPONSE_PENDING; case DPP_STATUS_INVALID_CONNECTOR: return DppStatusErrorCode::INVALID_CONNECTOR; case DPP_STATUS_CONFIG_REJECTED: return DppStatusErrorCode::CONFIG_REJECTED; case DPP_STATUS_NO_MATCH: return DppStatusErrorCode::NO_MATCH; case DPP_STATUS_NO_AP: return DppStatusErrorCode::NO_AP; case DPP_STATUS_CONFIGURE_PENDING: return DppStatusErrorCode::CONFIGURE_PENDING; case DPP_STATUS_CSR_NEEDED: return DppStatusErrorCode::CSR_NEEDED; case DPP_STATUS_CSR_BAD: return DppStatusErrorCode::CSR_BAD; case DPP_STATUS_NEW_KEY_NEEDED: return DppStatusErrorCode::NEW_KEY_NEEDED; default: return DppStatusErrorCode::UNKNOWN; } } void AidlManager::notifyDppConnectionStatusSent(struct wpa_supplicant *wpa_s, enum dpp_status_error result) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); callWithEachStaIfaceCallback(aidl_ifname, std::bind(&ISupplicantStaIfaceCallback::onDppConnectionStatusResultSent, std::placeholders::_1, convertSupplicantDppStatusErrorCodeToAidl(result))); } /** * Notify listener about a DPP failure event * * @param ifname Interface name * @param code Status code */ void AidlManager::notifyDppFailure(struct wpa_supplicant *wpa_s, android::hardware::wifi::supplicant::DppFailureCode code) { notifyDppFailure(wpa_s, code, NULL, NULL, NULL, 0); } /** * Notify listener about a DPP failure event * * @param ifname Interface name * @param code Status code */ void AidlManager::notifyDppFailure(struct wpa_supplicant *wpa_s, DppFailureCode code, const char *ssid, const char *channel_list, unsigned short band_list[], int size) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); std::vector band_list_vec(band_list, band_list + size); callWithEachStaIfaceCallback(aidl_ifname, std::bind(&ISupplicantStaIfaceCallback::onDppFailure, std::placeholders::_1, code, misc_utils::charBufToString(ssid), misc_utils::charBufToString(channel_list), band_list_vec)); } /** * Notify listener about a DPP progress event * * @param ifname Interface name * @param code Status code */ void AidlManager::notifyDppProgress( struct wpa_supplicant *wpa_s, DppProgressCode code) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); callWithEachStaIfaceCallback(aidl_ifname, std::bind(&ISupplicantStaIfaceCallback::onDppProgress, std::placeholders::_1, code)); } /** * Notify listener about a DPP success event * * @param ifname Interface name * @param code Status code */ void AidlManager::notifyDppSuccess(struct wpa_supplicant *wpa_s, DppEventType code) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); callWithEachStaIfaceCallback(aidl_ifname, std::bind(&ISupplicantStaIfaceCallback::onDppSuccess, std::placeholders::_1, code)); } /** * Notify listener about a PMK cache added event * * @param ifname Interface name * @param entry PMK cache entry */ void AidlManager::notifyPmkCacheAdded( struct wpa_supplicant *wpa_s, struct rsn_pmksa_cache_entry *pmksa_entry) { std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); PmkSaCacheData aidl_pmksa_data = {}; aidl_pmksa_data.bssid = macAddrToArray(pmksa_entry->aa); // Serialize PmkCacheEntry into blob. std::stringstream ss( std::stringstream::in | std::stringstream::out | std::stringstream::binary); misc_utils::serializePmkCacheEntry(ss, pmksa_entry); std::vector serializedEntry( std::istreambuf_iterator(ss), {}); aidl_pmksa_data.serializedEntry = serializedEntry; aidl_pmksa_data.expirationTimeInSec = pmksa_entry->expiration; const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaIfaceCallback::onPmkSaCacheAdded, std::placeholders::_1, aidl_pmksa_data); callWithEachStaIfaceCallback(aidl_ifname, func); } #ifdef CONFIG_WNM BssTmStatusCode convertSupplicantBssTmStatusToAidl( enum bss_trans_mgmt_status_code bss_tm_status) { switch (bss_tm_status) { case WNM_BSS_TM_ACCEPT: return BssTmStatusCode::ACCEPT; case WNM_BSS_TM_REJECT_UNSPECIFIED: return BssTmStatusCode::REJECT_UNSPECIFIED; case WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON: return BssTmStatusCode::REJECT_INSUFFICIENT_BEACON; case WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY: return BssTmStatusCode::REJECT_INSUFFICIENT_CAPABITY; case WNM_BSS_TM_REJECT_UNDESIRED: return BssTmStatusCode::REJECT_BSS_TERMINATION_UNDESIRED; case WNM_BSS_TM_REJECT_DELAY_REQUEST: return BssTmStatusCode::REJECT_BSS_TERMINATION_DELAY_REQUEST; case WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED: return BssTmStatusCode::REJECT_STA_CANDIDATE_LIST_PROVIDED; case WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES: return BssTmStatusCode::REJECT_NO_SUITABLE_CANDIDATES; case WNM_BSS_TM_REJECT_LEAVING_ESS: return BssTmStatusCode::REJECT_LEAVING_ESS; default: return BssTmStatusCode::REJECT_UNSPECIFIED; } } BssTmDataFlagsMask setBssTmDataFlagsMask(struct wpa_supplicant *wpa_s) { uint32_t flags = 0; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { flags |= static_cast(BssTmDataFlagsMask::WNM_MODE_BSS_TERMINATION_INCLUDED); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { flags |= static_cast(BssTmDataFlagsMask::WNM_MODE_ESS_DISASSOCIATION_IMMINENT); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { flags |= static_cast(BssTmDataFlagsMask::WNM_MODE_DISASSOCIATION_IMMINENT); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ABRIDGED) { flags |= static_cast(BssTmDataFlagsMask::WNM_MODE_ABRIDGED); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { flags |= static_cast(BssTmDataFlagsMask::WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED); } #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_assoc_retry_delay_present) { flags |= static_cast(BssTmDataFlagsMask::MBO_ASSOC_RETRY_DELAY_INCLUDED); } if (wpa_s->wnm_mbo_trans_reason_present) { flags |= static_cast(BssTmDataFlagsMask::MBO_TRANSITION_REASON_CODE_INCLUDED); } if (wpa_s->wnm_mbo_cell_pref_present) { flags |= static_cast(BssTmDataFlagsMask::MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED); } #endif return static_cast(flags); } uint32_t getBssTmDataAssocRetryDelayMs(struct wpa_supplicant *wpa_s) { uint32_t beacon_int; uint32_t duration_ms = 0; if (wpa_s->current_bss) beacon_int = wpa_s->current_bss->beacon_int; else beacon_int = 100; /* best guess */ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { // number of tbtts to milliseconds duration_ms = wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125; } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { //wnm_bss_termination_duration contains 12 bytes of BSS //termination duration subelement. Format of IE is // Sub eid | Length | BSS termination TSF | Duration // 1 1 8 2 // Duration indicates number of minutes for which BSS is not // present. duration_ms = WPA_GET_LE16(wpa_s->wnm_bss_termination_duration + 10); // minutes to milliseconds duration_ms = duration_ms * 60 * 1000; } #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_assoc_retry_delay_present) { // number of seconds to milliseconds duration_ms = wpa_s->wnm_mbo_assoc_retry_delay_sec * 1000; } #endif return duration_ms; } #endif /** * Notify listener about the status of BSS transition management * request frame handling. * * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which * the network is present. */ void AidlManager::notifyBssTmStatus(struct wpa_supplicant *wpa_s) { #ifdef CONFIG_WNM std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); BssTmData aidl_bsstm_data{}; aidl_bsstm_data.status = convertSupplicantBssTmStatusToAidl(wpa_s->bss_tm_status); aidl_bsstm_data.flags = setBssTmDataFlagsMask(wpa_s); aidl_bsstm_data.assocRetryDelayMs = getBssTmDataAssocRetryDelayMs(wpa_s); #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_cell_pref_present) { aidl_bsstm_data.mboCellPreference = static_cast (wpa_s->wnm_mbo_cell_preference); } if (wpa_s->wnm_mbo_trans_reason_present) { aidl_bsstm_data.mboTransitionReason = static_cast (wpa_s->wnm_mbo_transition_reason); } #endif const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaIfaceCallback::onBssTmHandlingDone, std::placeholders::_1, aidl_bsstm_data); callWithEachStaIfaceCallback(aidl_ifname, func); #endif } TransitionDisableIndication setTransitionDisableFlagsMask(u8 bitmap) { uint32_t flags = 0; if (bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) { flags |= static_cast(TransitionDisableIndication:: USE_WPA3_PERSONAL); bitmap &= ~TRANSITION_DISABLE_WPA3_PERSONAL; } if (bitmap & TRANSITION_DISABLE_SAE_PK) { flags |= static_cast(TransitionDisableIndication:: USE_SAE_PK); bitmap &= ~TRANSITION_DISABLE_SAE_PK; } if (bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) { flags |= static_cast(TransitionDisableIndication:: USE_WPA3_ENTERPRISE); bitmap &= ~TRANSITION_DISABLE_WPA3_ENTERPRISE; } if (bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) { flags |= static_cast(TransitionDisableIndication:: USE_ENHANCED_OPEN); bitmap &= ~TRANSITION_DISABLE_ENHANCED_OPEN; } if (bitmap != 0) { wpa_printf(MSG_WARNING, "Unhandled transition disable bit: 0x%x", bitmap); } return static_cast(flags); } void AidlManager::notifyTransitionDisable(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, u8 bitmap) { TransitionDisableIndication flag = setTransitionDisableFlagsMask(bitmap); const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaNetworkCallback::onTransitionDisable, std::placeholders::_1, flag); callWithEachStaNetworkCallback( misc_utils::charBufToString(wpa_s->ifname), ssid->id, func); } void AidlManager::notifyNetworkNotFound(struct wpa_supplicant *wpa_s) { std::vector aidl_ssid; if (!wpa_s->current_ssid) { wpa_printf(MSG_ERROR, "Current network NULL. Drop WPA_EVENT_NETWORK_NOT_FOUND!"); return; } aidl_ssid.assign( wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len); const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaIfaceCallback::onNetworkNotFound, std::placeholders::_1, aidl_ssid); callWithEachStaIfaceCallback(misc_utils::charBufToString(wpa_s->ifname), func); } void AidlManager::notifyFrequencyChanged(struct wpa_supplicant *wpa_s, int frequency) { if (!wpa_s) return; std::string aidl_ifname = misc_utils::charBufToString(wpa_s->ifname); struct wpa_supplicant *wpa_p2pdev_s = getTargetP2pIfaceForGroup(wpa_s); if (wpa_p2pdev_s) { // Notify frequency changed event on P2P interface const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind(&ISupplicantP2pIfaceCallback::onGroupFrequencyChanged, std::placeholders::_1, aidl_ifname, frequency); // For group notifications, need to use the parent iface for callbacks. callWithEachP2pIfaceCallback(misc_utils::charBufToString(wpa_p2pdev_s->ifname), func); } else if (wpa_s->current_ssid) { // Notify frequency changed event on STA interface const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaIfaceCallback::onBssFrequencyChanged, std::placeholders::_1, frequency); callWithEachStaIfaceCallback(aidl_ifname, func); } else { wpa_printf(MSG_INFO, "Drop frequency changed event"); return; } } void AidlManager::notifyCertification(struct wpa_supplicant *wpa_s, int depth, const char *subject, const char *altsubject[], int num_altsubject, const char *cert_hash, const struct wpabuf *cert) { if (!wpa_s->current_ssid) { wpa_printf(MSG_ERROR, "Current network NULL. Drop Certification event!"); return; } struct wpa_ssid *current_ssid = wpa_s->current_ssid; if (!wpa_key_mgmt_wpa_ieee8021x(current_ssid->key_mgmt)) { return; } if (NULL == subject || NULL == cert_hash || NULL == cert) { wpa_printf(MSG_ERROR, "Incomplete certificate information. Drop Certification event!"); return; } if (current_ssid->eap.cert.ca_cert) { return; } wpa_printf(MSG_DEBUG, "notifyCertification: depth=%d subject=%s hash=%s cert-size=%zu", depth, subject, cert_hash, cert->used); std::vector subjectBlob(subject, subject + strlen(subject)); std::vector certHashBlob(cert_hash, cert_hash + strlen(cert_hash)); std::vector certBlob(cert->buf, cert->buf + cert->used); const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaNetworkCallback::onServerCertificateAvailable, std::placeholders::_1, depth, subjectBlob, certHashBlob, certBlob); callWithEachStaNetworkCallback( misc_utils::charBufToString(wpa_s->ifname), current_ssid->id, func); } void AidlManager::notifyAuxiliaryEvent(struct wpa_supplicant *wpa_s, AuxiliarySupplicantEventCode event_code, const char *reason_string) { if (!wpa_s) return; const std::function< ndk::ScopedAStatus(std::shared_ptr)> func = std::bind( &ISupplicantStaIfaceCallback::onAuxiliarySupplicantEvent, std::placeholders::_1, event_code, macAddrToVec(wpa_s->bssid), misc_utils::charBufToString(reason_string)); callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), func); } /** * Retrieve the |ISupplicantP2pIface| aidl object reference using the provided * ifname. * * @param ifname Name of the corresponding interface. * @param iface_object Aidl reference corresponding to the iface. * * @return 0 on success, 1 on failure. */ int AidlManager::getP2pIfaceAidlObjectByIfname( const std::string &ifname, std::shared_ptr *iface_object) { if (ifname.empty() || !iface_object) return 1; auto iface_object_iter = p2p_iface_object_map_.find(ifname); if (iface_object_iter == p2p_iface_object_map_.end()) return 1; *iface_object = iface_object_iter->second; return 0; } /** * Retrieve the |ISupplicantStaIface| aidl object reference using the provided * ifname. * * @param ifname Name of the corresponding interface. * @param iface_object Aidl reference corresponding to the iface. * * @return 0 on success, 1 on failure. */ int AidlManager::getStaIfaceAidlObjectByIfname( const std::string &ifname, std::shared_ptr *iface_object) { if (ifname.empty() || !iface_object) return 1; auto iface_object_iter = sta_iface_object_map_.find(ifname); if (iface_object_iter == sta_iface_object_map_.end()) return 1; *iface_object = iface_object_iter->second; return 0; } /** * Retrieve the |ISupplicantP2pNetwork| aidl object reference using the provided * ifname and network_id. * * @param ifname Name of the corresponding interface. * @param network_id ID of the corresponding network. * @param network_object Aidl reference corresponding to the network. * * @return 0 on success, 1 on failure. */ int AidlManager::getP2pNetworkAidlObjectByIfnameAndNetworkId( const std::string &ifname, int network_id, std::shared_ptr *network_object) { if (ifname.empty() || network_id < 0 || !network_object) return 1; // Generate the key to be used to lookup the network. const std::string network_key = getNetworkObjectMapKey(ifname, network_id); auto network_object_iter = p2p_network_object_map_.find(network_key); if (network_object_iter == p2p_network_object_map_.end()) return 1; *network_object = network_object_iter->second; return 0; } /** * Retrieve the |ISupplicantStaNetwork| aidl object reference using the provided * ifname and network_id. * * @param ifname Name of the corresponding interface. * @param network_id ID of the corresponding network. * @param network_object Aidl reference corresponding to the network. * * @return 0 on success, 1 on failure. */ int AidlManager::getStaNetworkAidlObjectByIfnameAndNetworkId( const std::string &ifname, int network_id, std::shared_ptr *network_object) { if (ifname.empty() || network_id < 0 || !network_object) return 1; // Generate the key to be used to lookup the network. const std::string network_key = getNetworkObjectMapKey(ifname, network_id); auto network_object_iter = sta_network_object_map_.find(network_key); if (network_object_iter == sta_network_object_map_.end()) return 1; *network_object = network_object_iter->second; return 0; } /** * Add a new |ISupplicantCallback| aidl object reference to our * global callback list. * * @param callback Aidl reference of the |ISupplicantCallback| object. * * @return 0 on success, 1 on failure. */ int AidlManager::addSupplicantCallbackAidlObject( const std::shared_ptr &callback) { return registerForDeathAndAddCallbackAidlObjectToList< ISupplicantCallback>( death_notifier_, callback, supplicant_callbacks_); } /** * Store the |INonStandardCertCallback| aidl object reference. * * @param callback Aidl reference of the |INonStandardCertCallback| object. * * @return 0 on success, 1 on failure. */ int AidlManager::registerNonStandardCertCallbackAidlObject( const std::shared_ptr &callback) { if (callback == nullptr) return 1; non_standard_cert_callback_ = callback; return 0; } /** * Add a new iface callback aidl object reference to our * interface callback list. * * @param ifname Name of the corresponding interface. * @param callback Aidl reference of the callback object. * * @return 0 on success, 1 on failure. */ int AidlManager::addP2pIfaceCallbackAidlObject( const std::string &ifname, const std::shared_ptr &callback) { return addIfaceCallbackAidlObjectToMap( death_notifier_, ifname, callback, p2p_iface_callbacks_map_); } /** * Add a new iface callback aidl object reference to our * interface callback list. * * @param ifname Name of the corresponding interface. * @param callback Aidl reference of the callback object. * * @return 0 on success, 1 on failure. */ int AidlManager::addStaIfaceCallbackAidlObject( const std::string &ifname, const std::shared_ptr &callback) { return addIfaceCallbackAidlObjectToMap( death_notifier_, ifname, callback, sta_iface_callbacks_map_); } /** * Add a new network callback aidl object reference to our network callback * list. * * @param ifname Name of the corresponding interface. * @param network_id ID of the corresponding network. * @param callback Aidl reference of the callback object. * * @return 0 on success, 1 on failure. */ int AidlManager::addStaNetworkCallbackAidlObject( const std::string &ifname, int network_id, const std::shared_ptr &callback) { return addNetworkCallbackAidlObjectToMap( death_notifier_, ifname, network_id, callback, sta_network_callbacks_map_); } /** * Finds the correct |wpa_supplicant| object for P2P notifications * * @param wpa_s the |wpa_supplicant| that triggered the P2P event. * @return appropriate |wpa_supplicant| object or NULL if not found. */ struct wpa_supplicant *AidlManager::getTargetP2pIfaceForGroup( struct wpa_supplicant *wpa_group_s) { if (!wpa_group_s || !wpa_group_s->parent) return NULL; struct wpa_supplicant *target_wpa_s = wpa_group_s->parent; // check wpa_supplicant object is a p2p device interface if ((wpa_group_s == wpa_group_s->p2pdev) && wpa_group_s->p2p_mgmt) { if (p2p_iface_object_map_.find(wpa_group_s->ifname) != p2p_iface_object_map_.end()) return wpa_group_s; } if (p2p_iface_object_map_.find(target_wpa_s->ifname) != p2p_iface_object_map_.end()) return target_wpa_s; // try P2P device if available if (!target_wpa_s->p2pdev || !target_wpa_s->p2pdev->p2p_mgmt) return NULL; target_wpa_s = target_wpa_s->p2pdev; if (p2p_iface_object_map_.find(target_wpa_s->ifname) != p2p_iface_object_map_.end()) return target_wpa_s; return NULL; } /** * Removes the provided |ISupplicantCallback| aidl object reference * from our global callback list. * * @param callback Aidl reference of the |ISupplicantCallback| object. */ void AidlManager::removeSupplicantCallbackAidlObject( const std::shared_ptr &callback) { supplicant_callbacks_.erase( std::remove( supplicant_callbacks_.begin(), supplicant_callbacks_.end(), callback), supplicant_callbacks_.end()); } /** * Removes the provided iface callback aidl object reference from * our interface callback list. * * @param ifname Name of the corresponding interface. * @param callback Aidl reference of the callback object. */ void AidlManager::removeP2pIfaceCallbackAidlObject( const std::string &ifname, const std::shared_ptr &callback) { return removeIfaceCallbackAidlObjectFromMap( ifname, callback, p2p_iface_callbacks_map_); } /** * Removes the provided iface callback aidl object reference from * our interface callback list. * * @param ifname Name of the corresponding interface. * @param callback Aidl reference of the callback object. */ void AidlManager::removeStaIfaceCallbackAidlObject( const std::string &ifname, const std::shared_ptr &callback) { return removeIfaceCallbackAidlObjectFromMap( ifname, callback, sta_iface_callbacks_map_); } /** * Removes the provided network callback aidl object reference from * our network callback list. * * @param ifname Name of the corresponding interface. * @param network_id ID of the corresponding network. * @param callback Aidl reference of the callback object. */ void AidlManager::removeStaNetworkCallbackAidlObject( const std::string &ifname, int network_id, const std::shared_ptr &callback) { return removeNetworkCallbackAidlObjectFromMap( ifname, network_id, callback, sta_network_callbacks_map_); } /** * Helper function to invoke the provided callback method on all the * registered |ISupplicantCallback| callback aidl objects. * * @param method Pointer to the required aidl method from * |ISupplicantCallback|. */ void AidlManager::callWithEachSupplicantCallback( const std::function)> &method) { for (const auto &callback : supplicant_callbacks_) { if (!method(callback).isOk()) { wpa_printf(MSG_ERROR, "Failed to invoke AIDL callback"); } } } /** * Helper function to invoke the provided callback method on all the * registered iface callback aidl objects for the specified * |ifname|. * * @param ifname Name of the corresponding interface. * @param method Pointer to the required aidl method from * |ISupplicantIfaceCallback|. */ void AidlManager::callWithEachP2pIfaceCallback( const std::string &ifname, const std::function)> &method) { callWithEachIfaceCallback(ifname, method, p2p_iface_callbacks_map_); } /** * Helper function to invoke the provided callback method on all the * registered interface callback aidl objects for the specified * |ifname|. * * @param ifname Name of the corresponding interface. * @param method Pointer to the required aidl method from * |ISupplicantIfaceCallback|. */ void AidlManager::callWithEachStaIfaceCallback( const std::string &ifname, const std::function)> &method) { callWithEachIfaceCallback(ifname, method, sta_iface_callbacks_map_); } /** * Helper function to invoke the provided callback method on all the * registered network callback aidl objects for the specified * |ifname| & |network_id|. * * @param ifname Name of the corresponding interface. * @param network_id ID of the corresponding network. * @param method Pointer to the required aidl method from * |ISupplicantStaNetworkCallback|. */ void AidlManager::callWithEachStaNetworkCallback( const std::string &ifname, int network_id, const std::function< ndk::ScopedAStatus(std::shared_ptr)> &method) { callWithEachNetworkCallback( ifname, network_id, method, sta_network_callbacks_map_); } void AidlManager::notifyQosPolicyReset( struct wpa_supplicant *wpa_s) { if (!wpa_s) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onQosPolicyReset, std::placeholders::_1)); } void AidlManager::notifyQosPolicyRequest(struct wpa_supplicant *wpa_s, struct dscp_policy_data *policies, int num_policies) { if (!wpa_s || !policies) return; std::vector qosPolicyData; uint32_t mask = 0; for (int num = 0; num < num_policies; num++) { QosPolicyData policy; QosPolicyClassifierParams classifier_params; QosPolicyClassifierParamsMask classifier_param_mask; bool ip_ver4 = false; if (policies[num].type4_param.ip_version == 4) { classifier_params.ipVersion = IpVersion::VERSION_4; ip_ver4 = true; } else { classifier_params.ipVersion = IpVersion::VERSION_6; ip_ver4 = false; } // classifier_mask parameters are defined in IEEE Std 802.11-2020, Table 9-170 if (policies[num].type4_param.classifier_mask & BIT(1)) { mask |= static_cast(QosPolicyClassifierParamsMask::SRC_IP); if (ip_ver4) { classifier_params.srcIp = byteArrToVec((const uint8_t *) &policies[num].type4_param.ip_params.v4.src_ip, 4); } else { classifier_params.srcIp = byteArrToVec((const uint8_t *) &policies[num].type4_param.ip_params.v6.src_ip, 16); } } if (policies[num].type4_param.classifier_mask & BIT(2)) { mask |= static_cast(QosPolicyClassifierParamsMask::DST_IP); if (ip_ver4){ classifier_params.dstIp = byteArrToVec((const uint8_t *) &policies[num].type4_param.ip_params.v4.dst_ip, 4); } else { classifier_params.dstIp = byteArrToVec((const uint8_t *) &policies[num].type4_param.ip_params.v6.dst_ip, 16); } } if (policies[num].type4_param.classifier_mask & BIT(3)) { mask |= static_cast(QosPolicyClassifierParamsMask::SRC_PORT); if (ip_ver4){ classifier_params.srcPort = policies[num].type4_param.ip_params.v4.src_port; } else { classifier_params.srcPort = policies[num].type4_param.ip_params.v6.src_port; } } if (policies[num].type4_param.classifier_mask & BIT(4)) { mask |= static_cast( QosPolicyClassifierParamsMask::DST_PORT_RANGE); if (ip_ver4) { classifier_params.dstPortRange.startPort = policies[num].type4_param.ip_params.v4.dst_port; classifier_params.dstPortRange.endPort = policies[num].type4_param.ip_params.v4.dst_port; } else { classifier_params.dstPortRange.startPort = policies[num].type4_param.ip_params.v6.dst_port; classifier_params.dstPortRange.endPort = policies[num].type4_param.ip_params.v6.dst_port; } } else if (policies[num].port_range_info) { mask |= static_cast( QosPolicyClassifierParamsMask::DST_PORT_RANGE); classifier_params.dstPortRange.startPort = policies[num].start_port; classifier_params.dstPortRange.endPort = policies[num].end_port; } if (policies[num].type4_param.classifier_mask & BIT(6)) { mask |= static_cast( QosPolicyClassifierParamsMask::PROTOCOL_NEXT_HEADER); if (ip_ver4) { classifier_params.protocolNextHdr = static_cast( policies[num].type4_param.ip_params.v4.protocol); } else { classifier_params.protocolNextHdr = static_cast( policies[num].type4_param.ip_params.v6.next_header); } } if (policies[num].type4_param.classifier_mask & BIT(7)) { mask |= static_cast(QosPolicyClassifierParamsMask::FLOW_LABEL); classifier_params.flowLabelIpv6 = byteArrToVec(policies[num].type4_param.ip_params.v6.flow_label, 3); } if (policies[num].domain_name_len != 0) { mask |= static_cast(QosPolicyClassifierParamsMask::DOMAIN_NAME); classifier_params.domainName = misc_utils::charBufToString( reinterpret_cast(policies[num].domain_name)); } classifier_params.classifierParamMask = static_cast(mask); policy.policyId = policies[num].policy_id; policy.requestType = static_cast(policies[num].req_type); policy.dscp = policies[num].dscp; policy.classifierParams = classifier_params; qosPolicyData.push_back(policy); } callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onQosPolicyRequest, std::placeholders::_1, wpa_s->dscp_req_dialog_token, qosPolicyData)); } void AidlManager::notifyMloLinksInfoChanged(struct wpa_supplicant *wpa_s, enum mlo_info_change_reason reason) { if (!wpa_s) return; if (sta_iface_object_map_.find(wpa_s->ifname) == sta_iface_object_map_.end()) return; callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind(&ISupplicantStaIfaceCallback::onMloLinksInfoChanged, std::placeholders::_1, static_cast(reason))); } ssize_t AidlManager::getCertificate(const char* alias, uint8_t** value) { if (alias == nullptr || value == nullptr) { wpa_printf(MSG_ERROR, "Null pointer argument was passed to getCertificate"); return -1; } if (auto cert = certificate_utils::getCertificate(alias, non_standard_cert_callback_)) { *value = (uint8_t *) os_malloc(cert->size()); if (*value == nullptr) return -1; os_memcpy(*value, cert->data(), cert->size()); return cert->size(); } return -1; } ssize_t AidlManager::listAliases(const char *prefix, char ***aliases) { if (prefix == nullptr || aliases == nullptr) { wpa_printf(MSG_ERROR, "Null pointer argument was passed to listAliases"); return -1; } if (auto results = certificate_utils::listAliases(prefix, non_standard_cert_callback_)) { int count = results->size(); *aliases = (char **) os_malloc(sizeof(char *) * count); if (*aliases == nullptr) { wpa_printf(MSG_ERROR, "listAliases: os_malloc alias array error"); return -1; } os_memset(*aliases, 0, sizeof(char *) * count); int index = 0; for (auto it = results->begin(); it != results->end(); ++it) { int alias_len = it->length(); char *alias = (char *) os_malloc(alias_len + 1); if (alias == nullptr) { wpa_printf(MSG_ERROR, "listAliases: os_malloc alias string error"); for (int i = 0; i < index; ++i) os_free((*aliases)[i]); os_free(*aliases); return -1; } os_memcpy(alias, it->data(), alias_len + 1); (*aliases)[index] = alias; index++; } return count; } return -1; } QosPolicyScsResponseStatusCode getQosPolicyScsResponseStatusCode(int scsResponseCode) { QosPolicyScsResponseStatusCode status = QosPolicyScsResponseStatusCode::TIMEOUT; /* Status code as per Ieee802.11-2020 Table 9-50—Status codes */ switch (scsResponseCode) { case 0: /* SUCCESS */ status = QosPolicyScsResponseStatusCode::SUCCESS; break; case 37: /* REQUEST_DECLINED */ status = QosPolicyScsResponseStatusCode::TCLAS_REQUEST_DECLINED; break; case 56: /* REQUESTED_TCLAS_NOT_SUPPORTED */ case 80: /* REQUESTED_TCLAS_NOT_SUPPORTED */ status = QosPolicyScsResponseStatusCode::TCLAS_NOT_SUPPORTED_BY_AP; break; case 57: /* INSUFFICIENT_TCLAS_PROCESSING_RESOURCES */ status = QosPolicyScsResponseStatusCode::TCLAS_INSUFFICIENT_RESOURCES; break; case 81: /* TCLAS_RESOURCES_EXHAUSTED */ status = QosPolicyScsResponseStatusCode::TCLAS_RESOURCES_EXHAUSTED; break; case 128: /* TCLAS_PROCESSING_TERMINATED_INSUFFICIENT_QOS */ status = QosPolicyScsResponseStatusCode::TCLAS_PROCESSING_TERMINATED_INSUFFICIENT_QOS; break; case 129: /* TCLAS_PROCESSING_TERMINATED_POLICY_CONFLICT */ status = QosPolicyScsResponseStatusCode::TCLAS_PROCESSING_TERMINATED_POLICY_CONFLICT; break; case 97: /* TCLAS_PROCESSING_TERMINATED */ status = QosPolicyScsResponseStatusCode::TCLAS_PROCESSING_TERMINATED; break; default: status = QosPolicyScsResponseStatusCode::TIMEOUT; break; return status; } return status; } void AidlManager::notifyQosPolicyScsResponse(struct wpa_supplicant *wpa_s, unsigned int count, int **scs_resp) { if (!wpa_s || !count || !scs_resp) return; std::vector scsResponses; for (int i = 0; i < count; i++) { QosPolicyScsResponseStatus resp; resp.policyId = scs_resp[0][i] & 0xFF; resp.qosPolicyScsResponseStatusCode = getQosPolicyScsResponseStatusCode(scs_resp[1][i]); scsResponses.push_back(resp); } callWithEachStaIfaceCallback( misc_utils::charBufToString(wpa_s->ifname), std::bind( &ISupplicantStaIfaceCallback::onQosPolicyResponseForScs, std::placeholders::_1, scsResponses)); } } // namespace supplicant } // namespace wifi } // namespace hardware } // namespace android } // namespace aidl