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/Kbuild b/Kbuild
index 4996ace..711ac6f 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2038,6 +2038,7 @@
 cppflags-$(CONFIG_FEATURE_INTEROP_ISSUES_AP) += -DWLAN_FEATURE_INTEROP_ISSUES_AP
 cppflags-$(CONFIG_FEATURE_MEMDUMP_ENABLE) += -DWLAN_FEATURE_MEMDUMP_ENABLE
 cppflags-$(CONFIG_FEATURE_FW_LOG_PARSING) += -DFEATURE_FW_LOG_PARSING
+cppflags-$(CONFIG_FEATURE_OEM_DATA) += -DFEATURE_OEM_DATA
 
 cppflags-$(CONFIG_PLD_SDIO_CNSS_FLAG) += -DCONFIG_PLD_SDIO_CNSS
 cppflags-$(CONFIG_PLD_PCIE_CNSS_FLAG) += -DCONFIG_PLD_PCIE_CNSS
diff --git a/configs/default_defconfig b/configs/default_defconfig
index 0e9efa5..8a342c2 100644
--- a/configs/default_defconfig
+++ b/configs/default_defconfig
@@ -825,6 +825,9 @@
 #Enable STATE MACHINE HISTORY
 CONFIG_SM_ENG_HIST := n
 
+#Enable OEM DATA feature
+CONFIG_FEATURE_OEM_DATA := y
+
 ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM)))
 CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y
 endif
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