Bladeren bron

qcacmn: IOT SIM target interface

IOT SIM target interface updates

Change-Id: Ia9b048ecccd476df822e61f4ccb16e70352f630d
CRs-Fixed: 2665426
Jayachandran Sreekumaran 5 jaren geleden
bovenliggende
commit
77c068dda2

+ 4 - 6
iot_sim/Kbuild

@@ -100,7 +100,7 @@ INCS += -I$(obj)/$(DEPTH)/include -I$(obj)/$(DEPTH)/umac/include \
         -I$(obj)/$(DEPTH)/cmn_dev/umac/mlme/pdev_mgr/dispatcher/inc \
         -I$(obj)/$(DEPTH)/direct_attach/hal/linux \
 
-#INCS += -I$(obj)/$(DEPTH)/cmn_dev/target_if/iot_sim
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/target_if/iot_sim
 INCS += -I$(obj)/$(DEPTH)/cmn_dev/wmi/inc
 #end of offload related defines
 
@@ -122,15 +122,13 @@ ifeq ($(strip ${QCA_PARTNER_MAKE_F_SUPPORT}),1)
 MOD_CFLAGS = -D"KBUILD_STR(s)=\#s" -D"KBUILD_BASENAME=KBUILD_STR(qca_iot_sim.mod)"  -D"KBUILD_MODNAME=KBUILD_STR(qca_iot_sim)"
 endif
 
-IOT_SIM_TIF_OBJS +=
-
 IOT_SIM_CMN_OBJS +=  core/iot_sim_common.o \
                      dispatcher/src/wlan_iot_sim_utils_api.o \
                      dispatcher/src/wlan_iot_sim_tgt_api.o \
-                     core/iot_sim_module.o
+		     core/iot_sim_utils.o \
+		     core/iot_sim_module.o
 
-qca_iot_sim-objs +=  ${IOT_SIM_CMN_OBJS} \
-                     ${IOT_SIM_TIF_OBJS}
+qca_iot_sim-objs +=  ${IOT_SIM_CMN_OBJS}
 
 ifeq ($(strip ${QCA_PARTNER_MAKE_F_SUPPORT}),1)
 all: qca_iot_sim.ko

+ 13 - 0
iot_sim/core/iot_sim_cmn_api_i.h

@@ -64,6 +64,19 @@ QDF_STATUS wlan_iot_sim_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev,
 QDF_STATUS wlan_iot_sim_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev,
 						 void *arg);
 
+/**
+ * iot_sim_frame_update() - Management frame update
+ * @pdev: reference to global pdev object
+ * @nbuf: frame buffer
+ *
+ * This function updates the outgoing management frame with
+ * the content stored in iot_sim_context.
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ * QDF_STATUS_E_FAILURE on failure
+ */
+QDF_STATUS iot_sim_frame_update(struct wlan_objmgr_pdev *pdev, qdf_nbuf_t nbuf);
+
 /*
  * iot_sim_get_ctx_from_pdev() - API to get iot_sim context object
  *                               from pdev

+ 121 - 0
iot_sim/core/iot_sim_utils.c

@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <wlan_iot_sim_utils_api.h>
+#include <qdf_module.h>
+#include "../../core/iot_sim_cmn_api_i.h"
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+
+#define IEEE80211_FRAME_BODY_OFFSET 0x18
+
+QDF_STATUS iot_sim_frame_update(struct wlan_objmgr_pdev *pdev, qdf_nbuf_t nbuf)
+{
+	u8 type, subtype, seq = 0;
+	struct iot_sim_context *isc;
+	u8 *buf = qdf_nbuf_data(nbuf);
+	int fixed_param_length = 0;
+
+	type = (buf[0] & IEEE80211_FC0_TYPE_MASK) >> IEEE80211_FC0_TYPE_SHIFT;
+	subtype = (buf[0] & IEEE80211_FC0_SUBTYPE_MASK);
+	subtype >>= IEEE80211_FC0_SUBTYPE_SHIFT;
+	isc = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_IOT_SIM_COMP);
+	if (!isc) {
+		iot_sim_err("pdev IOT_SIM object is NULL!");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (type == 0x00 && subtype == 0x0b) {
+	/* Authentication frame */
+		int auth_seq_index = IEEE80211_FRAME_BODY_OFFSET + 2;
+
+		seq = le16toh(*(u_int16_t *)(buf + auth_seq_index));
+	} else if (type == 0x00 && subtype == 0x05)
+	/* Probe response frame */
+		fixed_param_length = 12;
+	else if (type == 0x00 && (subtype == 0x01 || subtype == 0x03))
+	/* Assoc/Reassoc response frame */
+		fixed_param_length = 6;
+
+	/* Only broadcast peer is getting handled right now.
+	 * Need to add support for peer based content modification
+	 */
+	if ((isc->bcast_peer.rule_per_seq[seq]) &&
+	    (isc->bcast_peer.rule_per_seq[seq]->rule_per_type[type][subtype])) {
+		if (isc->bcast_peer.rule_per_seq[seq]->
+		    rule_per_type[type][subtype]) {
+			struct iot_sim_rule *piot_sim_rule =
+			isc->bcast_peer.rule_per_seq[seq]->
+			rule_per_type[type][subtype];
+			qdf_size_t buf_len = qdf_nbuf_len(nbuf);
+
+			if (piot_sim_rule->frm_content && piot_sim_rule->len) {
+				int offset;
+
+				if (piot_sim_rule->offset ==
+				    IEEE80211_FRAME_BODY_OFFSET) {
+					offset = IEEE80211_FRAME_BODY_OFFSET;
+				} else if (piot_sim_rule->offset == 0) {
+					offset = 0;
+				} else if (buf[piot_sim_rule->offset] ==
+					   piot_sim_rule->frm_content[0]) {
+					offset = piot_sim_rule->offset;
+				}  else {
+					offset = IEEE80211_FRAME_BODY_OFFSET +
+							fixed_param_length;
+					while (((offset + 1) < buf_len) &&
+					       (buf[offset] <
+						piot_sim_rule->
+						frm_content[0])) {
+						offset += buf[offset + 1] + 2;
+					}
+				}
+
+				if (offset <= buf_len) {
+					buf += offset;
+					qdf_mem_copy(buf,
+						     piot_sim_rule->frm_content,
+						     piot_sim_rule->len);
+					qdf_nbuf_set_pktlen(nbuf,
+							    offset +
+							    piot_sim_rule->len);
+					iot_sim_err("Content updated  for peer");
+					iot_sim_err("frame type:%d, subtype:%d",
+						    type, subtype);
+					iot_sim_err("seq:%d", seq);
+				} else {
+					iot_sim_err("Failed to modify content");
+					iot_sim_err("type:%d, subtype:%d",
+						    type, subtype);
+					iot_sim_err("seq:%d", seq);
+				}
+			} else {
+				iot_sim_err("Content update rule not set");
+				iot_sim_err("frame type:%d, subtype:%d, seq:%d",
+					    type, subtype, seq);
+			}
+		} else {
+			iot_sim_err("Content update rule not set");
+			iot_sim_err("frame type:%d, subtype:%d, seq:%d",
+				    type, subtype, seq);
+		}
+	} else {
+		iot_sim_err("Content update rule not set for peer frame");
+		iot_sim_err("type:%d, subtype:%d, seq:%d", type, subtype, seq);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}

+ 3 - 0
iot_sim/dispatcher/inc/wlan_iot_sim_tgt_api.h

@@ -21,4 +21,7 @@
 #include <qdf_types.h>
 #include "../../core/iot_sim_cmn_api_i.h"
 
+QDF_STATUS tgt_send_simulation_cmd(struct wlan_objmgr_pdev *pdev,
+				   struct simulation_test_params *param);
+
 #endif /* _WLAN_IOT_SIM_TGT_API_H_ */

+ 1 - 0
iot_sim/dispatcher/inc/wlan_iot_sim_utils_api.h

@@ -19,6 +19,7 @@
 
 #include <wlan_objmgr_cmn.h>
 #include <wlan_lmac_if_def.h>
+#include <wmi_unified_param.h>
 
 /* Forward Declarations */
 struct wmi_iot_sim_cmd_ops;

+ 9 - 0
iot_sim/dispatcher/src/wlan_iot_sim_tgt_api.c

@@ -34,3 +34,12 @@ tgt_get_target_handle(struct wlan_objmgr_pdev *pdev)
 	}
 	return isc->p_iot_sim_target_handle;
 }
+
+QDF_STATUS tgt_send_simulation_cmd(struct wlan_objmgr_pdev *pdev,
+				   struct simulation_test_params *param)
+{
+	struct wlan_objmgr_psoc *psoc = NULL;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	return psoc->soc_cb.tx_ops.iot_sim_tx_ops.iot_sim_send_cmd(pdev, param);
+}

+ 1 - 87
iot_sim/dispatcher/src/wlan_iot_sim_utils_api.c

@@ -26,94 +26,8 @@
 QDF_STATUS iot_sim_cmd_handler(struct wlan_objmgr_vdev *vdev, qdf_nbuf_t nbuf)
 {
 	struct wlan_objmgr_pdev *pdev = vdev->vdev_objmgr.wlan_pdev;
-	u8 type, subtype, seq = 0;
-	struct iot_sim_context *isc;
-	u8 *buf = qdf_nbuf_data(nbuf);
 
-	type = (buf[0] & IEEE80211_FC0_TYPE_MASK) >> IEEE80211_FC0_TYPE_SHIFT;
-	subtype = (buf[0] & IEEE80211_FC0_SUBTYPE_MASK);
-	subtype >>= IEEE80211_FC0_SUBTYPE_SHIFT;
-	isc = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_IOT_SIM_COMP);
-
-	if (!isc) {
-		iot_sim_err("pdev IOT_SIM object is NULL!");
-		return QDF_STATUS_SUCCESS;
-	}
-
-	if (type == 0x00 && subtype == 0xb0) {
-	/* Authentication frame */
-		int auth_seq_index = IEEE80211_FRAME_BODY_OFFSET + 2;
-
-		seq = le16toh(*(u_int16_t *)(buf + auth_seq_index));
-	}
-
-	/* Only broadcast peer is getting handled right now.
-	 * Need to add support for peer based content modification
-	 */
-	if ((isc->bcast_peer.rule_per_seq[seq]) &&
-	    (isc->bcast_peer.rule_per_seq[seq]->rule_per_type[type][subtype])) {
-		if (isc->bcast_peer.rule_per_seq[seq]->
-		    rule_per_type[type][subtype]) {
-			struct iot_sim_rule *piot_sim_rule =
-			isc->bcast_peer.rule_per_seq[seq]->
-			rule_per_type[type][subtype];
-			qdf_size_t buf_len = qdf_nbuf_len(nbuf);
-
-			if (piot_sim_rule->frm_content && piot_sim_rule->len) {
-				int offset;
-
-				if (piot_sim_rule->offset ==
-				    IEEE80211_FRAME_BODY_OFFSET) {
-					offset = IEEE80211_FRAME_BODY_OFFSET;
-				} else if (buf[piot_sim_rule->offset] ==
-					   piot_sim_rule->frm_content[0]) {
-					offset = piot_sim_rule->offset;
-				} else if (piot_sim_rule->offset == 0) {
-					offset = 0;
-				}  else {
-					offset = IEEE80211_FRAME_BODY_OFFSET;
-					while (((offset + 1) < buf_len) &&
-					       (buf[offset] <
-					       piot_sim_rule->frm_content[0])) {
-						offset += buf[offset + 1] + 2;
-					}
-				}
-
-				if (offset <= buf_len) {
-					buf += offset;
-					qdf_mem_copy(buf,
-						     piot_sim_rule->
-						     frm_content,
-						     piot_sim_rule->len);
-					qdf_nbuf_set_pktlen(nbuf,
-							    offset +
-							    piot_sim_rule->len);
-					iot_sim_err("Content updated  for peer");
-					iot_sim_err("frame type:%d, subtype:%d",
-						    type, subtype);
-					iot_sim_err("seq:%d", seq);
-				} else {
-					iot_sim_err("Failed to modify content");
-					iot_sim_err("type:%d, subtype:%d",
-						    type, subtype);
-					iot_sim_err("seq:%d", seq);
-				}
-			} else {
-				iot_sim_err("Content update rule not set");
-				iot_sim_err("frame type:%d, subtype:%d, seq:%d",
-					    type, subtype, seq);
-			}
-		} else {
-			iot_sim_err("Content update rule not set");
-			iot_sim_err("frame type:%d, subtype:%d, seq:%d",
-				    type, subtype, seq);
-		}
-	} else {
-		iot_sim_err("Content update rule not set for peer frame");
-		iot_sim_err("type:%d, subtype:%d, seq:%d", type, subtype, seq);
-	}
-
-	return QDF_STATUS_SUCCESS;
+	return iot_sim_frame_update(pdev, nbuf);
 }
 
 QDF_STATUS

+ 19 - 0
target_if/core/src/target_if_main.c

@@ -35,6 +35,10 @@
 #ifdef WLAN_CONV_SPECTRAL_ENABLE
 #include "target_if_spectral.h"
 #endif
+
+#ifdef WLAN_IOT_SIM_SUPPORT
+#include <target_if_iot_sim.h>
+#endif
 #include <target_if_reg.h>
 #include <target_if_scan.h>
 #include <target_if_ftm.h>
@@ -308,6 +312,19 @@ static void target_if_sptrl_tx_ops_register(
 }
 #endif /* WLAN_CONV_SPECTRAL_ENABLE */
 
+#ifdef WLAN_IOT_SIM_SUPPORT
+static void target_if_iot_sim_tx_ops_register(
+				struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	target_if_iot_sim_register_tx_ops(tx_ops);
+}
+#else
+static void target_if_iot_sim_tx_ops_register(
+				struct wlan_lmac_if_tx_ops *tx_ops)
+{
+}
+#endif
+
 #ifdef DIRECT_BUF_RX_ENABLE
 static void target_if_direct_buf_rx_tx_ops_register(
 				struct wlan_lmac_if_tx_ops *tx_ops)
@@ -497,6 +514,8 @@ QDF_STATUS target_if_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
 	/* Components parallel to UMAC to register their TX-ops here */
 	target_if_sptrl_tx_ops_register(tx_ops);
 
+	target_if_iot_sim_tx_ops_register(tx_ops);
+
 	/* Register direct buffer rx component tx ops here */
 	target_if_direct_buf_rx_tx_ops_register(tx_ops);
 

+ 43 - 0
target_if/iot_sim/target_if_iot_sim.c

@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <wmi_unified_api.h>
+#include <target_if_iot_sim.h>
+#include <init_deinit_lmac.h>
+#include <target_if.h>
+#include <qdf_module.h>
+
+QDF_STATUS
+target_if_iot_sim_send_cmd(struct wlan_objmgr_pdev *pdev,
+			   struct simulation_test_params *param)
+{
+	if (pdev && pdev->tgt_if_handle) {
+		struct wmi_unified *wmi_hdl;
+
+		wmi_hdl = pdev->tgt_if_handle->wmi_handle;
+		return wmi_unified_simulation_test_cmd_send(wmi_hdl, param);
+	} else
+		return QDF_STATUS_E_FAILURE;
+}
+
+void target_if_iot_sim_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	tx_ops->iot_sim_tx_ops.iot_sim_send_cmd =
+						target_if_iot_sim_send_cmd;
+}
+
+qdf_export_symbol(target_if_iot_sim_register_tx_ops);
+

+ 39 - 0
target_if/iot_sim/target_if_iot_sim.h

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TARGET_IF_IOT_SIM_H_
+#define _TARGET_IOT_SIM_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_pdev_obj.h>
+
+#ifdef WLAN_IOT_SIM_SUPPORT
+#include <wlan_iot_sim_utils_api.h>
+
+/**
+ * target_if_iot_sim_register_tx_ops() - Register IOT Sim target_if Tx Ops
+ * @tx_ops: Tx Ops
+ *
+ * Return: void
+ */
+void target_if_iot_sim_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops);
+
+QDF_STATUS
+target_if_iot_sim_send_cmd(struct wlan_objmgr_pdev *pdev,
+			   struct simulation_test_params *param);
+
+#endif
+#endif

+ 8 - 5
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -663,6 +663,13 @@ struct wlan_lmac_if_sptrl_tx_ops {
 };
 #endif /* WLAN_CONV_SPECTRAL_ENABLE */
 
+struct simulation_test_params;
+
+struct wlan_lmac_if_iot_sim_tx_ops {
+	QDF_STATUS (*iot_sim_send_cmd)(struct wlan_objmgr_pdev *pdev,
+				       struct simulation_test_params *param);
+};
+
 #ifdef WIFI_POS_CONVERGED
 /*
  * struct wlan_lmac_if_wifi_pos_tx_ops - structure of firmware tx function
@@ -1008,6 +1015,7 @@ struct wlan_lmac_if_tx_ops {
 #ifdef CONVERGED_P2P_ENABLE
 	struct wlan_lmac_if_p2p_tx_ops p2p;
 #endif
+	struct wlan_lmac_if_iot_sim_tx_ops iot_sim_tx_ops;
 #ifdef QCA_SUPPORT_SON
 	struct wlan_lmac_if_son_tx_ops son_tx_ops;
 #endif
@@ -1382,12 +1390,10 @@ struct wlan_lmac_if_sptrl_rx_ops {
 };
 #endif /* WLAN_CONV_SPECTRAL_ENABLE */
 
-#ifdef WLAN_IOT_SIM_SUPPORT
 struct wlan_lmac_if_iot_sim_rx_ops {
 	QDF_STATUS (*iot_sim_cmd_handler)(struct wlan_objmgr_vdev *vdev,
 					  qdf_nbuf_t n_buf);
 };
-#endif
 
 #ifdef WIFI_POS_CONVERGED
 /**
@@ -1732,10 +1738,7 @@ struct wlan_lmac_if_rx_ops {
 #ifdef CONVERGED_P2P_ENABLE
 	struct wlan_lmac_if_p2p_rx_ops p2p;
 #endif
-
-#ifdef WLAN_IOT_SIM_SUPPORT
 	struct wlan_lmac_if_iot_sim_rx_ops iot_sim_rx_ops;
-#endif
 
 #ifdef WLAN_ATF_ENABLE
 	struct wlan_lmac_if_atf_rx_ops atf_rx_ops;

+ 12 - 0
wmi/inc/wmi_unified_api.h

@@ -1991,6 +1991,18 @@ QDF_STATUS wmi_unified_smart_ant_enable_tx_feedback_cmd_send(
 			wmi_unified_t wmi_handle,
 			struct smart_ant_enable_tx_feedback_params *param);
 
+/**
+ *  wmi_unified_simulation_test_cmd_send() -
+ *  WMI simulation test command
+ *  @wmi_handle: handle to WMI.
+ *  @param: pointer to hold simulation test param
+ *
+ *  Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure
+ */
+QDF_STATUS wmi_unified_simulation_test_cmd_send(wmi_unified_t wmi_handle,
+						struct simulation_test_params
+						*param);
+
 /**
  *  wmi_unified_vdev_spectral_configure_cmd_send() -
  *					WMI set spectral config function

+ 31 - 0
wmi/inc/wmi_unified_param.h

@@ -2903,6 +2903,37 @@ struct smart_ant_enable_tx_feedback_params {
 	int enable;
 };
 
+/**
+ * struct simulation_test_params
+ * pdev_id: pdev id
+ * vdev_id: vdev id
+ * peer_macaddr: peer MAC address
+ * test_cmd_type: test command type
+ * test_subcmd_type: test command sub type
+ * frame_type: frame type
+ * frame_subtype: frame subtype
+ * seq: sequence number
+ * offset: Frame content offset
+ * frame_length: Frame content length
+ * buf_len: Buffer length
+ * bufp: buffer
+ */
+struct simulation_test_params {
+	u32 pdev_id;
+	u32 vdev_id;
+	u8 peer_mac[QDF_MAC_ADDR_SIZE];
+	u32 test_cmd_type;
+	u32 test_subcmd_type;
+	u8 frame_type;
+	u8 frame_subtype;
+	u8 seq;
+	u8 reserved;
+	u16 offset;
+	u16 frame_length;
+	u32 buf_len;
+	u8 *bufp;
+};
+
 /**
  * struct vdev_spectral_configure_params - SPectral config params
  * @vdev_id: VDEV id

+ 3 - 0
wmi/inc/wmi_unified_priv.h

@@ -1201,6 +1201,9 @@ QDF_STATUS (*send_smart_ant_set_node_config_cmd)(wmi_unified_t wmi_handle,
 		struct smart_ant_node_config_params *param);
 #endif
 
+QDF_STATUS (*send_simulation_test_cmd)(wmi_unified_t wmi_handle,
+				       struct simulation_test_params *param);
+
 QDF_STATUS (*send_smart_ant_enable_tx_feedback_cmd)(wmi_unified_t wmi_handle,
 		struct smart_ant_enable_tx_feedback_params *param);
 

+ 13 - 0
wmi/src/wmi_unified_api.c

@@ -1296,6 +1296,19 @@ wmi_unified_smart_ant_enable_tx_feedback_cmd_send(
 }
 qdf_export_symbol(wmi_unified_smart_ant_enable_tx_feedback_cmd_send);
 
+QDF_STATUS
+wmi_unified_simulation_test_cmd_send(
+		wmi_unified_t wmi_handle,
+		struct simulation_test_params *param)
+{
+	if (wmi_handle->ops->send_simulation_test_cmd)
+		return wmi_handle->ops->send_simulation_test_cmd(
+							wmi_handle, param);
+
+	return QDF_STATUS_E_FAILURE;
+}
+qdf_export_symbol(wmi_unified_simulation_test_cmd_send);
+
 QDF_STATUS
 wmi_unified_vdev_spectral_configure_cmd_send(
 		wmi_unified_t wmi_handle,

+ 67 - 0
wmi/src/wmi_unified_tlv.c

@@ -6399,6 +6399,72 @@ send_periodic_chan_stats_config_cmd_tlv(wmi_unified_t wmi_handle,
 	return ret;
 }
 
+/**
+ * send_simulation_test_cmd_tlv() - send simulation test command to fw
+ *
+ * @wmi_handle: wmi handle
+ * @param: pointer to hold simulation test parameter
+ *
+ * Return: 0 for success or error code
+ */
+static QDF_STATUS send_simulation_test_cmd_tlv(wmi_unified_t wmi_handle,
+					       struct simulation_test_params
+					       *param)
+{
+	wmi_simulation_test_cmd_fixed_param *cmd;
+	u32 wmi_buf_len;
+	wmi_buf_t buf;
+	u8 *buf_ptr;
+	u32 aligned_len = 0;
+
+	wmi_buf_len = sizeof(*cmd);
+	if (param->buf_len) {
+		aligned_len = roundup(param->buf_len, sizeof(A_UINT32));
+		wmi_buf_len += WMI_TLV_HDR_SIZE + aligned_len;
+	}
+
+	buf = wmi_buf_alloc(wmi_handle, wmi_buf_len);
+	if (!buf) {
+		WMI_LOGP("%s: wmi_buf_alloc failed", __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	buf_ptr = wmi_buf_data(buf);
+	cmd = (wmi_simulation_test_cmd_fixed_param *)buf_ptr;
+	WMITLV_SET_HDR(&cmd->tlv_header,
+		       WMITLV_TAG_STRUC_wmi_simulation_test_cmd_fixed_param,
+		       WMITLV_GET_STRUCT_TLVLEN(
+					wmi_simulation_test_cmd_fixed_param));
+	cmd->pdev_id = param->pdev_id;
+	cmd->vdev_id = param->vdev_id;
+	WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_mac, &cmd->peer_macaddr);
+	cmd->test_cmd_type = param->test_cmd_type;
+	cmd->test_subcmd_type = param->test_subcmd_type;
+	WMI_SIM_FRAME_TYPE_SET(cmd->frame_type_subtype_seq, param->frame_type);
+	WMI_SIM_FRAME_SUBTYPE_SET(cmd->frame_type_subtype_seq,
+				  param->frame_subtype);
+	WMI_SIM_FRAME_SEQ_SET(cmd->frame_type_subtype_seq, param->seq);
+	WMI_SIM_FRAME_OFFSET_SET(cmd->frame_offset_length, param->offset);
+	WMI_SIM_FRAME_LENGTH_SET(cmd->frame_offset_length, param->frame_length);
+	cmd->buf_len = param->buf_len;
+
+	if (param->buf_len) {
+		buf_ptr += sizeof(*cmd);
+		WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, aligned_len);
+		buf_ptr += WMI_TLV_HDR_SIZE;
+		qdf_mem_copy(buf_ptr, param->bufp, param->buf_len);
+	}
+
+	if (wmi_unified_cmd_send(wmi_handle, buf, wmi_buf_len,
+				 WMI_SIMULATION_TEST_CMDID)) {
+		WMI_LOGE("%s: Failed to send test simulation cmd", __func__);
+		wmi_buf_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * send_vdev_spectral_configure_cmd_tlv() - send VDEV spectral configure
  * command to fw
@@ -13740,6 +13806,7 @@ struct wmi_ops tlv_ops =  {
 	.send_phyerr_enable_cmd = send_phyerr_enable_cmd_tlv,
 	.send_periodic_chan_stats_config_cmd =
 		send_periodic_chan_stats_config_cmd_tlv,
+	.send_simulation_test_cmd = send_simulation_test_cmd_tlv,
 	.send_vdev_spectral_configure_cmd =
 				send_vdev_spectral_configure_cmd_tlv,
 	.send_vdev_spectral_enable_cmd =