qcacld-3.0: Add OEM DATA vendor command support
This command is used to send OEM data binary blobs
from application/service to firmware.
Change-Id: I0b5d7dd5a030b70e59c8581fb51d99079b38385f
CRs-Fixed: 2477332
diff --git a/core/hdd/inc/wlan_hdd_oemdata.h b/core/hdd/inc/wlan_hdd_oemdata.h
index 9769f3d..00c1e4b 100644
--- a/core/hdd/inc/wlan_hdd_oemdata.h
+++ b/core/hdd/inc/wlan_hdd_oemdata.h
@@ -46,7 +46,7 @@
#define OEM_CAP_MAX_NUM_CHANNELS 128
/**
- * typedef eOemErrorCode - OEM error codes
+ * enum oem_err_code - OEM error codes
* @OEM_ERR_NULL_CONTEXT: %NULL context
* @OEM_ERR_APP_NOT_REGISTERED: OEM App is not registered
* @OEM_ERR_INVALID_SIGNATURE: Invalid signature
@@ -231,4 +231,32 @@
uint16_t chan,
void *hdd_chan_info) {}
#endif /* FEATURE_OEM_DATA_SUPPORT */
+
+#ifdef FEATURE_OEM_DATA
+#define OEM_DATA_MAX_SIZE 1024
+/**
+ * wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data
+ * @wiphy: wiphy structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of @data
+ *
+ * Return: 0 on success; errno on failure
+ */
+int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len);
+
+#define FEATURE_OEM_DATA_VENDOR_COMMANDS \
+{ \
+ .info.vendor_id = QCA_NL80211_VENDOR_ID, \
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OEM_DATA, \
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
+ WIPHY_VENDOR_CMD_NEED_NETDEV | \
+ WIPHY_VENDOR_CMD_NEED_RUNNING, \
+ .doit = wlan_hdd_cfg80211_oem_data_handler \
+},
+#else
+#define FEATURE_OEM_DATA_VENDOR_COMMANDS
+#endif
#endif /* __WLAN_HDD_OEM_DATA_H__ */
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 24e6e1c..8cf6375 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -143,6 +143,7 @@
#include "wlan_hdd_bcn_recv.h"
#include "wlan_blm_ucfg_api.h"
#include "wlan_hdd_hw_capability.h"
+#include "wlan_hdd_oemdata.h"
#define g_mode_rates_size (12)
#define a_mode_rates_size (8)
@@ -12710,6 +12711,7 @@
},
#endif
FEATURE_RSSI_MONITOR_VENDOR_COMMANDS
+ FEATURE_OEM_DATA_VENDOR_COMMANDS
FEATURE_INTEROP_ISSUES_AP_VENDOR_COMMANDS
#ifdef WLAN_NS_OFFLOAD
diff --git a/core/hdd/src/wlan_hdd_oemdata.c b/core/hdd/src/wlan_hdd_oemdata.c
index 69aa916..1024a0b 100644
--- a/core/hdd/src/wlan_hdd_oemdata.c
+++ b/core/hdd/src/wlan_hdd_oemdata.c
@@ -16,8 +16,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef FEATURE_OEM_DATA_SUPPORT
-
/**
* DOC: wlan_hdd_oemdata.c
*
@@ -25,6 +23,7 @@
*
*/
+#if defined(FEATURE_OEM_DATA_SUPPORT) || defined(FEATURE_OEM_DATA)
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -38,7 +37,9 @@
#include "wma.h"
#include "sme_api.h"
#include "wlan_nlink_srv.h"
+#include "wlan_hdd_oemdata.h"
+#ifdef FEATURE_OEM_DATA_SUPPORT
#ifdef CNSS_GENL
#include <net/cnss_nl.h>
#endif
@@ -372,7 +373,7 @@
oem_data_req.data_len = oem_data_len;
qdf_mem_copy(oem_data_req.data, oem_data, oem_data_len);
- status = sme_oem_data_req(p_hdd_ctx->mac_handle, &oem_data_req);
+ status = sme_oem_req_cmd(p_hdd_ctx->mac_handle, &oem_data_req);
qdf_mem_free(oem_data_req.data);
oem_data_req.data = NULL;
@@ -1126,3 +1127,85 @@
#endif
#endif
+
+#ifdef FEATURE_OEM_DATA
+static const struct nla_policy
+oem_data_attr_policy[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1] = {
+ [QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA] = {
+ .type = NLA_BINARY,
+ .len = OEM_DATA_MAX_SIZE
+ },
+};
+
+/**
+ * __wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data
+ * @wiphy: wiphy structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of @data
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int
+__wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct net_device *dev = wdev->netdev;
+ QDF_STATUS status;
+ int ret;
+ struct oem_data oem_data = {0};
+ struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1];
+
+ ret = wlan_hdd_validate_context(hdd_ctx);
+ if (ret)
+ return ret;
+
+ if (wlan_cfg80211_nla_parse(tb,
+ QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX,
+ data, data_len, oem_data_attr_policy)) {
+ hdd_err("Invalid attributes");
+ return -EINVAL;
+ }
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]) {
+ hdd_err("oem data is missing!");
+ return -EINVAL;
+ }
+
+ oem_data.data_len =
+ nla_len(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]);
+ if (!oem_data.data_len) {
+ hdd_err("oem data len is 0!");
+ return -EINVAL;
+ }
+
+ oem_data.vdev_id = adapter->vdev_id;
+ oem_data.data = nla_data(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]);
+
+ status = sme_oem_data_cmd(hdd_ctx->mac_handle, &oem_data);
+
+ return qdf_status_to_os_return(status);
+}
+
+int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct osif_vdev_sync *vdev_sync;
+ int ret;
+
+ ret = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
+ if (ret)
+ return ret;
+
+ ret = __wlan_hdd_cfg80211_oem_data_handler(wiphy, wdev,
+ data, data_len);
+ osif_vdev_sync_op_stop(vdev_sync);
+
+ return ret;
+}
+#endif
+#endif
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index f6f0490..942b55e 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -44,6 +44,7 @@
#include "wlan_serialization_legacy_api.h"
#include <qca_vendor.h>
#include "wmi_unified.h"
+#include "wmi_unified_param.h"
/*--------------------------------------------------------------------------
Preprocessor definitions and constants
@@ -671,9 +672,29 @@
uint8_t sessionId,
tpRrmNeighborReq pRrmNeighborReq,
tpRrmNeighborRspCallbackInfo callbackInfo);
+
+#ifdef FEATURE_OEM_DATA
+/**
+ * sme_oem_data_cmd() - the wrapper to send oem data cmd to wma
+ * @mac_handle: Opaque handle to the global MAC context.
+ * @oem_data: the pointer of oem data
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle,
+ struct oem_data *oem_data);
+#endif
+
#ifdef FEATURE_OEM_DATA_SUPPORT
-QDF_STATUS sme_oem_data_req(mac_handle_t mac_handle,
- struct oem_data_req *hdd_oem_req);
+/**
+ * sme_oem_req_cmd() - send oem request cmd to WMA
+ * @mac_handle: Opaque handle to the global MAC context
+ * @oem_req: OEM data request
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_oem_req_cmd(mac_handle_t mac_handle,
+ struct oem_data_req *oem_req);
QDF_STATUS sme_oem_update_capability(mac_handle_t mac_handle,
struct sme_oem_capability *cap);
QDF_STATUS sme_oem_get_capability(mac_handle_t mac_handle,
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index cf2348c..8e3b0b2 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -3853,15 +3853,8 @@
}
#ifdef FEATURE_OEM_DATA_SUPPORT
-/**
- * sme_oem_data_req() - send oem data request to WMA
- * @mac_handle: Opaque handle to the global MAC context
- * @hdd_oem_req: OEM data request from HDD
- *
- * Return: QDF_STATUS
- */
-QDF_STATUS sme_oem_data_req(mac_handle_t mac_handle,
- struct oem_data_req *hdd_oem_req)
+QDF_STATUS sme_oem_req_cmd(mac_handle_t mac_handle,
+ struct oem_data_req *oem_req)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct oem_data_req *oem_data_req;
@@ -3878,17 +3871,17 @@
if (!oem_data_req)
return QDF_STATUS_E_NOMEM;
- oem_data_req->data_len = hdd_oem_req->data_len;
+ oem_data_req->data_len = oem_req->data_len;
oem_data_req->data = qdf_mem_malloc(oem_data_req->data_len);
if (!oem_data_req->data) {
qdf_mem_free(oem_data_req);
return QDF_STATUS_E_NOMEM;
}
- qdf_mem_copy(oem_data_req->data, hdd_oem_req->data,
+ qdf_mem_copy(oem_data_req->data, oem_req->data,
oem_data_req->data_len);
- status = wma_start_oem_data_req(wma_handle, oem_data_req);
+ status = wma_start_oem_req_cmd(wma_handle, oem_data_req);
if (!QDF_IS_STATUS_SUCCESS(status))
sme_err("Post oem data request msg fail");
@@ -3905,6 +3898,29 @@
}
#endif /*FEATURE_OEM_DATA_SUPPORT */
+#ifdef FEATURE_OEM_DATA
+QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle,
+ struct oem_data *oem_data)
+{
+ QDF_STATUS status;
+ void *wma_handle;
+
+ SME_ENTER();
+ wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+ if (!wma_handle) {
+ sme_err("wma_handle is NULL");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ status = wma_start_oem_data_cmd(wma_handle, oem_data);
+ if (!QDF_IS_STATUS_SUCCESS(status))
+ sme_err("fail to call wma_start_oem_data_cmd.");
+
+ SME_EXIT();
+ return status;
+}
+#endif
+
#define STA_NSS_CHAINS_SHIFT 0
#define SAP_NSS_CHAINS_SHIFT 3
#define P2P_GO_NSS_CHAINS_SHIFT 6
diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h
index cf87e04..e9fd2e0 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -44,6 +44,7 @@
#include <cdp_txrx_handle.h>
#include <wlan_policy_mgr_api.h>
#include "wma_api.h"
+#include "wmi_unified_param.h"
/* Platform specific configuration for max. no. of fragments */
#define QCA_OL_11AC_TX_MAX_FRAGS 2
@@ -1881,8 +1882,27 @@
uint8_t dot11_mode);
#ifdef FEATURE_OEM_DATA_SUPPORT
-QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle,
- struct oem_data_req *oem_req);
+/**
+ * wma_start_oem_req_cmd() - send oem request command to fw
+ * @wma_handle: wma handle
+ * @oem_data_req: the pointer of oem req buf
+ *
+ * Return: QDF status
+ */
+QDF_STATUS wma_start_oem_req_cmd(tp_wma_handle wma_handle,
+ struct oem_data_req *oem_data_req);
+#endif
+
+#ifdef FEATURE_OEM_DATA
+/**
+ * wma_start_oem_data_cmd() - send oem data command to fw
+ * @wma_handle: wma handle
+ * @oem_data: the pointer of oem data buf
+ *
+ * Return: QDF status
+ */
+QDF_STATUS wma_start_oem_data_cmd(tp_wma_handle wma_handle,
+ struct oem_data *oem_data);
#endif
QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma_handle,
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index 130b07f..6f678cb 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -1259,17 +1259,10 @@
return 0;
}
-/**
- * wma_start_oem_data_req() - start OEM data request to target
- * @wma_handle: wma handle
- * @oem_data_req: start request params
- *
- * Return: QDF_STATUS
- */
-QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle,
- struct oem_data_req *oem_data_req)
+QDF_STATUS wma_start_oem_req_cmd(tp_wma_handle wma_handle,
+ struct oem_data_req *oem_data_req)
{
- int ret = 0;
+ QDF_STATUS ret;
WMA_LOGD(FL("Send OEM Data Request to target"));
@@ -1284,9 +1277,10 @@
return QDF_STATUS_E_INVAL;
}
+ /* legacy api, for oem data request case */
ret = wmi_unified_start_oem_data_cmd(wma_handle->wmi_handle,
- oem_data_req->data_len,
- oem_data_req->data);
+ oem_data_req->data_len,
+ oem_data_req->data);
if (!QDF_IS_STATUS_SUCCESS(ret))
WMA_LOGE(FL("wmi cmd send failed"));
@@ -1295,6 +1289,34 @@
}
#endif /* FEATURE_OEM_DATA_SUPPORT */
+#ifdef FEATURE_OEM_DATA
+QDF_STATUS wma_start_oem_data_cmd(tp_wma_handle wma_handle,
+ struct oem_data *oem_data)
+{
+ QDF_STATUS ret;
+
+ wma_debug("Send OEM Data to target");
+
+ if (!oem_data || !oem_data->data) {
+ wma_err("oem_data is null");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (!wma_handle || !wma_handle->wmi_handle) {
+ wma_err("WMA - closed");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ /* common api, for oem data command case */
+ ret = wmi_unified_start_oemv2_data_cmd(wma_handle->wmi_handle,
+ oem_data);
+ if (!QDF_IS_STATUS_SUCCESS(ret))
+ wma_err("call start wmi cmd failed");
+
+ return ret;
+}
+#endif
+
#if !defined(REMOVE_PKT_LOG) && defined(FEATURE_PKTLOG)
/**
* wma_pktlog_wmi_send_cmd() - send pktlog enable/disable command to target