|
@@ -34,6 +34,8 @@
|
|
|
#include "hif.h"
|
|
|
#include <qca_vendor.h>
|
|
|
#include "wma_api.h"
|
|
|
+#include "wlan_hdd_hostapd.h"
|
|
|
+#include "wlan_hdd_request_manager.h"
|
|
|
#include "wlan_hdd_debugfs_llstat.h"
|
|
|
|
|
|
/* 11B, 11G Rate table include Basic rate and Extended rate
|
|
@@ -4706,3 +4708,236 @@ void hdd_clear_hif_stats(void)
|
|
|
return;
|
|
|
hif_clear_stats(hif_ctx);
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_is_rcpi_applicable() - validates RCPI request
|
|
|
+ * @adapter: adapter upon which the measurement is requested
|
|
|
+ * @mac_addr: peer addr for which measurement is requested
|
|
|
+ * @rcpi_value: pointer to where the RCPI should be returned
|
|
|
+ * @reassoc: used to return cached RCPI during reassoc
|
|
|
+ *
|
|
|
+ * Return: true for success, false for failure
|
|
|
+ */
|
|
|
+
|
|
|
+static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter,
|
|
|
+ struct qdf_mac_addr *mac_addr,
|
|
|
+ int32_t *rcpi_value,
|
|
|
+ bool *reassoc)
|
|
|
+{
|
|
|
+ struct hdd_station_ctx *hdd_sta_ctx;
|
|
|
+
|
|
|
+ if (adapter->device_mode == QDF_STA_MODE ||
|
|
|
+ adapter->device_mode == QDF_P2P_CLIENT_MODE) {
|
|
|
+ hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
|
|
|
+ if (hdd_sta_ctx->conn_info.connState !=
|
|
|
+ eConnectionState_Associated)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (hdd_sta_ctx->hdd_reassoc_scenario) {
|
|
|
+ /* return the cached rcpi, if mac addr matches */
|
|
|
+ hdd_debug("Roaming in progress, return cached RCPI");
|
|
|
+ if (!qdf_mem_cmp(&adapter->rcpi.mac_addr,
|
|
|
+ mac_addr, sizeof(*mac_addr))) {
|
|
|
+ *rcpi_value = adapter->rcpi.rcpi;
|
|
|
+ *reassoc = true;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssId,
|
|
|
+ sizeof(*mac_addr))) {
|
|
|
+ hdd_err("mac addr is different from bssid connected");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else if (adapter->device_mode == QDF_SAP_MODE ||
|
|
|
+ adapter->device_mode == QDF_P2P_GO_MODE) {
|
|
|
+ if (!test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
|
|
|
+ hdd_err("Invalid rcpi request, softap not started");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* check if peer mac addr is associated to softap */
|
|
|
+ if (!hdd_is_peer_associated(adapter, mac_addr)) {
|
|
|
+ hdd_err("invalid peer mac-addr: not associated");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ hdd_err("Invalid rcpi request");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ *reassoc = false;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * wlan_hdd_get_rcpi_cb() - callback function for rcpi response
|
|
|
+ * @context: Pointer to rcpi context
|
|
|
+ * @rcpi_req: Pointer to rcpi response
|
|
|
+ *
|
|
|
+ * Return: None
|
|
|
+ */
|
|
|
+static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr,
|
|
|
+ int32_t rcpi, QDF_STATUS status)
|
|
|
+{
|
|
|
+ struct hdd_request *request;
|
|
|
+ struct rcpi_info *priv;
|
|
|
+
|
|
|
+ if (!context) {
|
|
|
+ hdd_err("No rcpi context");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ request = hdd_request_get(context);
|
|
|
+ if (!request) {
|
|
|
+ hdd_err("Obsolete RCPI request");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ priv = hdd_request_priv(request);
|
|
|
+ priv->mac_addr = mac_addr;
|
|
|
+
|
|
|
+ if (!QDF_IS_STATUS_SUCCESS(status)) {
|
|
|
+ priv->rcpi = 0;
|
|
|
+ hdd_err("Error in computing RCPI");
|
|
|
+ } else {
|
|
|
+ priv->rcpi = rcpi;
|
|
|
+ }
|
|
|
+
|
|
|
+ hdd_request_complete(request);
|
|
|
+ hdd_request_put(request);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * __wlan_hdd_get_rcpi() - local function to get RCPI
|
|
|
+ * @adapter: adapter upon which the measurement is requested
|
|
|
+ * @mac: peer addr for which measurement is requested
|
|
|
+ * @rcpi_value: pointer to where the RCPI should be returned
|
|
|
+ * @measurement_type: type of rcpi measurement
|
|
|
+ *
|
|
|
+ * Return: 0 for success, non-zero for failure
|
|
|
+ */
|
|
|
+static int __wlan_hdd_get_rcpi(struct hdd_adapter *adapter,
|
|
|
+ uint8_t *mac,
|
|
|
+ int32_t *rcpi_value,
|
|
|
+ enum rcpi_measurement_type measurement_type)
|
|
|
+{
|
|
|
+ struct hdd_context *hdd_ctx;
|
|
|
+ int status = 0, ret = 0;
|
|
|
+ struct qdf_mac_addr mac_addr;
|
|
|
+ QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
|
|
|
+ struct sme_rcpi_req *rcpi_req;
|
|
|
+ void *cookie;
|
|
|
+ struct rcpi_info *priv;
|
|
|
+ struct hdd_request *request;
|
|
|
+ static const struct hdd_request_params params = {
|
|
|
+ .priv_size = sizeof(*priv),
|
|
|
+ .timeout_ms = WLAN_WAIT_TIME_RCPI,
|
|
|
+ };
|
|
|
+ bool reassoc;
|
|
|
+
|
|
|
+ ENTER();
|
|
|
+
|
|
|
+ /* initialize the rcpi value to zero, useful in error cases */
|
|
|
+ *rcpi_value = 0;
|
|
|
+
|
|
|
+ if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
|
|
|
+ hdd_err("Command not allowed in FTM mode");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!adapter) {
|
|
|
+ hdd_warn("adapter context is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ hdd_ctx = WLAN_HDD_GET_CTX(adapter);
|
|
|
+ status = wlan_hdd_validate_context(hdd_ctx);
|
|
|
+ if (status)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!hdd_ctx->rcpi_enabled) {
|
|
|
+ hdd_debug("RCPI not supported");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!mac) {
|
|
|
+ hdd_warn("RCPI peer mac-addr is NULL");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE);
|
|
|
+
|
|
|
+ if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc))
|
|
|
+ return -EINVAL;
|
|
|
+ if (reassoc)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req));
|
|
|
+ if (!rcpi_req) {
|
|
|
+ hdd_err("unable to allocate memory for RCPI req");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ request = hdd_request_alloc(¶ms);
|
|
|
+ if (!request) {
|
|
|
+ hdd_err("Request allocation failure");
|
|
|
+ qdf_mem_free(rcpi_req);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ cookie = hdd_request_cookie(request);
|
|
|
+
|
|
|
+ rcpi_req->mac_addr = mac_addr;
|
|
|
+ rcpi_req->session_id = adapter->sessionId;
|
|
|
+ rcpi_req->measurement_type = measurement_type;
|
|
|
+ rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb;
|
|
|
+ rcpi_req->rcpi_context = cookie;
|
|
|
+
|
|
|
+ qdf_status = sme_get_rcpi(hdd_ctx->hHal, rcpi_req);
|
|
|
+ if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
|
|
|
+ hdd_err("Unable to retrieve RCPI");
|
|
|
+ status = qdf_status_to_os_return(qdf_status);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* request was sent -- wait for the response */
|
|
|
+ ret = hdd_request_wait_for_response(request);
|
|
|
+ if (ret) {
|
|
|
+ hdd_err("SME timed out while retrieving RCPI");
|
|
|
+ status = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* update the adapter with the fresh results */
|
|
|
+ priv = hdd_request_priv(request);
|
|
|
+ adapter->rcpi.mac_addr = priv->mac_addr;
|
|
|
+ adapter->rcpi.rcpi = priv->rcpi;
|
|
|
+ if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) {
|
|
|
+ hdd_err("mis match of mac addr from call-back");
|
|
|
+ status = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ *rcpi_value = adapter->rcpi.rcpi;
|
|
|
+ hdd_debug("RCPI = %d", *rcpi_value);
|
|
|
+out:
|
|
|
+ qdf_mem_free(rcpi_req);
|
|
|
+ hdd_request_put(request);
|
|
|
+
|
|
|
+ EXIT();
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac,
|
|
|
+ int32_t *rcpi_value,
|
|
|
+ enum rcpi_measurement_type measurement_type)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ cds_ssr_protect(__func__);
|
|
|
+ ret = __wlan_hdd_get_rcpi(adapter, mac, rcpi_value, measurement_type);
|
|
|
+ cds_ssr_unprotect(__func__);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|