summaryrefslogtreecommitdiff
path: root/wcn6740/qcwcn/wifi_hal/rssi_monitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wcn6740/qcwcn/wifi_hal/rssi_monitor.cpp')
-rw-r--r--wcn6740/qcwcn/wifi_hal/rssi_monitor.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/wcn6740/qcwcn/wifi_hal/rssi_monitor.cpp b/wcn6740/qcwcn/wifi_hal/rssi_monitor.cpp
new file mode 100644
index 0000000..a2038f8
--- /dev/null
+++ b/wcn6740/qcwcn/wifi_hal/rssi_monitor.cpp
@@ -0,0 +1,380 @@
+/* Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
+ */
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+#include "rssi_monitor.h"
+
+/* Used to handle rssi command events from driver/firmware.*/
+typedef struct rssi_monitor_event_handler_s {
+ RSSIMonitorCommand* mRSSIMonitorCommandInstance;
+} rssi_monitor_event_handlers;
+
+wifi_error initializeRSSIMonitorHandler(hal_info *info)
+{
+ info->rssi_handlers = (rssi_monitor_event_handlers *)malloc(sizeof(
+ rssi_monitor_event_handlers));
+ if (info->rssi_handlers) {
+ memset(info->rssi_handlers, 0, sizeof(rssi_monitor_event_handlers));
+ }
+ else {
+ ALOGE("%s: Allocation of RSSI event handlers failed",
+ __FUNCTION__);
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ return WIFI_SUCCESS;
+}
+
+wifi_error cleanupRSSIMonitorHandler(hal_info *info)
+{
+ rssi_monitor_event_handlers* event_handlers;
+ if (info && info->rssi_handlers) {
+ event_handlers = (rssi_monitor_event_handlers*) info->rssi_handlers;
+ if (event_handlers->mRSSIMonitorCommandInstance) {
+ delete event_handlers->mRSSIMonitorCommandInstance;
+ }
+ memset(event_handlers, 0, sizeof(rssi_monitor_event_handlers));
+ free(info->rssi_handlers);
+ info->rssi_handlers = NULL;
+ return WIFI_SUCCESS;
+ }
+ ALOGE ("%s: info or info->rssi_handlers NULL", __FUNCTION__);
+ return WIFI_ERROR_UNKNOWN;
+}
+
+void RSSIMonitorCommand::enableEventHandling()
+{
+ pthread_mutex_lock(&rm_lock);
+ mEventHandlingEnabled = true;
+ pthread_mutex_unlock(&rm_lock);
+}
+
+void RSSIMonitorCommand::disableEventHandling()
+{
+ pthread_mutex_lock(&rm_lock);
+ mEventHandlingEnabled = false;
+ pthread_mutex_unlock(&rm_lock);
+}
+
+bool RSSIMonitorCommand::isEventHandlingEnabled()
+{
+ bool eventHandlingEnabled;
+ pthread_mutex_lock(&rm_lock);
+ eventHandlingEnabled = mEventHandlingEnabled;
+ pthread_mutex_unlock(&rm_lock);
+
+ return eventHandlingEnabled;
+}
+
+void RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler handler)
+{
+ mHandler = handler;
+}
+
+RSSIMonitorCommand::RSSIMonitorCommand(wifi_handle handle, int id,
+ u32 vendor_id, u32 subcmd)
+ : WifiVendorCommand(handle, id, vendor_id, subcmd)
+{
+ memset(&mHandler, 0, sizeof(mHandler));
+ if (registerVendorHandler(vendor_id, subcmd)) {
+ /* Error case should not happen print log */
+ ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
+ __FUNCTION__, vendor_id, subcmd);
+ }
+ pthread_mutex_init(&rm_lock, NULL);
+ disableEventHandling();
+}
+
+RSSIMonitorCommand::~RSSIMonitorCommand()
+{
+ unregisterVendorHandler(mVendor_id, mSubcmd);
+ pthread_mutex_destroy(&rm_lock);
+}
+
+void RSSIMonitorCommand::setReqId(wifi_request_id reqid)
+{
+ mId = reqid;
+}
+
+RSSIMonitorCommand* RSSIMonitorCommand::instance(wifi_handle handle,
+ wifi_request_id id)
+{
+ if (handle == NULL) {
+ ALOGE("Interface Handle is invalid");
+ return NULL;
+ }
+ hal_info *info = getHalInfo(handle);
+ if (!info || !info->rssi_handlers) {
+ ALOGE("rssi_handlers is invalid");
+ return NULL;
+ }
+
+ RSSIMonitorCommand* mRSSIMonitorCommandInstance =
+ info->rssi_handlers->mRSSIMonitorCommandInstance;
+
+ if (mRSSIMonitorCommandInstance == NULL) {
+ mRSSIMonitorCommandInstance = new RSSIMonitorCommand(handle, id,
+ OUI_QCA,
+ QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
+ info->rssi_handlers->mRSSIMonitorCommandInstance = mRSSIMonitorCommandInstance;
+ return mRSSIMonitorCommandInstance;
+ }
+ else
+ {
+ if (handle != getWifiHandle(mRSSIMonitorCommandInstance->mInfo))
+ {
+ /* upper layer must have cleaned up the handle and reinitialized,
+ so we need to update the same */
+ ALOGV("Handle different, update the handle");
+ mRSSIMonitorCommandInstance->mInfo = (hal_info *)handle;
+ }
+ mRSSIMonitorCommandInstance->setReqId(id);
+ }
+ return mRSSIMonitorCommandInstance;
+}
+
+/* This function will be the main handler for incoming event.
+ * Call the appropriate callback handler after parsing the vendor data.
+ */
+int RSSIMonitorCommand::handleEvent(WifiEvent &event)
+{
+ int ret = WIFI_SUCCESS;
+
+ if (isEventHandlingEnabled() == false) {
+ ALOGE("%s: RSSI monitor isn't running or already stopped. "
+ "Nothing to do. Exit", __FUNCTION__);
+ return ret;
+ }
+
+ WifiVendorCommand::handleEvent(event);
+
+ /* Parse the vendordata and get the attribute */
+ switch(mSubcmd)
+ {
+ case QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI:
+ {
+ mac_addr addr;
+ s8 rssi;
+ wifi_request_id reqId;
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
+ + 1];
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX,
+ (struct nlattr *)mVendorData,
+ mDataLen, NULL);
+
+ memset(addr, 0, sizeof(mac_addr));
+
+ if (!tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID])
+ {
+ ALOGE("%s: ATTR_RSSI_MONITORING_REQUEST_ID not found. Exit.",
+ __FUNCTION__);
+ ret = WIFI_ERROR_INVALID_ARGS;
+ break;
+ }
+ reqId = nla_get_u32(
+ tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID]
+ );
+ /* If event has a different request_id, ignore that and use the
+ * request_id value which we're maintaining.
+ */
+ if (reqId != id()) {
+ ALOGV("%s: Event has Req. ID:%d <> Ours:%d, continue...",
+ __FUNCTION__, reqId, id());
+ reqId = id();
+ }
+ ret = get_mac_addr(tb_vendor,
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
+ addr);
+ if (ret != WIFI_SUCCESS) {
+ return ret;
+ }
+ ALOGV(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));
+
+ if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI])
+ {
+ ALOGE("%s: QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI"
+ " not found", __FUNCTION__);
+ return WIFI_ERROR_INVALID_ARGS;
+ }
+ rssi = get_s8(tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI]);
+ ALOGV("Current RSSI : %d ", rssi);
+
+ if (mHandler.on_rssi_threshold_breached)
+ (*mHandler.on_rssi_threshold_breached)(reqId, addr, rssi);
+ else
+ ALOGE("RSSI Monitoring: No Callback registered: ");
+ }
+ break;
+
+ default:
+ /* Error case should not happen print log */
+ ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
+ }
+
+ return ret;
+}
+
+wifi_error wifi_start_rssi_monitoring(wifi_request_id id,
+ wifi_interface_handle iface,
+ s8 max_rssi,
+ s8 min_rssi,
+ wifi_rssi_event_handler eh)
+{
+ wifi_error ret;
+ struct nlattr *nlData;
+ WifiVendorCommand *vCommand = NULL;
+ wifi_handle wifiHandle = getWifiHandle(iface);
+ RSSIMonitorCommand *rssiCommand;
+
+ ret = initialize_vendor_cmd(iface, id,
+ QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
+ &vCommand);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: Initialization failed", __FUNCTION__);
+ return ret;
+ }
+
+ ALOGV("%s: Max RSSI:%d Min RSSI:%d", __FUNCTION__,
+ max_rssi, min_rssi);
+ /* Add the vendor specific attributes for the NL command. */
+ nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nlData){
+ ret = WIFI_ERROR_UNKNOWN;
+ goto cleanup;
+ }
+
+ ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
+ QCA_WLAN_RSSI_MONITORING_START);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+ ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
+ id);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+ ret = vCommand->put_s8(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
+ max_rssi);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+ ret = vCommand->put_s8(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
+ min_rssi);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ vCommand->attr_end(nlData);
+
+ rssiCommand = RSSIMonitorCommand::instance(wifiHandle, id);
+ if (rssiCommand == NULL) {
+ ALOGE("%s: Error rssiCommand NULL", __FUNCTION__);
+ ret = WIFI_ERROR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+
+ rssiCommand->setCallbackHandler(eh);
+
+ ret = vCommand->requestResponse();
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ rssiCommand->enableEventHandling();
+
+cleanup:
+ delete vCommand;
+ return ret;
+}
+
+wifi_error wifi_stop_rssi_monitoring(wifi_request_id id,
+ wifi_interface_handle iface)
+{
+ wifi_error ret;
+ struct nlattr *nlData;
+ WifiVendorCommand *vCommand = NULL;
+ wifi_handle wifiHandle = getWifiHandle(iface);
+ RSSIMonitorCommand *rssiCommand;
+ rssi_monitor_event_handlers* event_handlers;
+ hal_info *info = getHalInfo(wifiHandle);
+
+ event_handlers = info->rssi_handlers;
+ rssiCommand = event_handlers->mRSSIMonitorCommandInstance;
+
+ if (rssiCommand == NULL ||
+ rssiCommand->isEventHandlingEnabled() == false) {
+ ALOGE("%s: RSSI monitor isn't running or already stopped. "
+ "Nothing to do. Exit", __FUNCTION__);
+ return WIFI_ERROR_NOT_AVAILABLE;
+ }
+
+ ret = initialize_vendor_cmd(iface, id,
+ QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
+ &vCommand);
+ if (ret != WIFI_SUCCESS) {
+ ALOGE("%s: Initialization failed", __FUNCTION__);
+ return ret;
+ }
+
+ /* Add the vendor specific attributes for the NL command. */
+ nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
+ if (!nlData){
+ ret = WIFI_ERROR_UNKNOWN;
+ goto cleanup;
+ }
+
+ ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
+ QCA_WLAN_RSSI_MONITORING_STOP);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+ ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
+ id);
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ vCommand->attr_end(nlData);
+
+ ret = vCommand->requestResponse();
+ if (ret != WIFI_SUCCESS)
+ goto cleanup;
+
+ rssiCommand->disableEventHandling();
+
+cleanup:
+ delete vCommand;
+ return ret;
+}