qcacld-3.0: Add changes for DISA certification

Add changes to parse DISA parameters received from
user space and pass them to firmware for firmware
to encrypt data and send back to driver. Also, add
changes to print encrypted data received from firmware.

Change-Id: Ic6928a93f799c47518fbbad96564062f595287dd
CRs-Fixed: 1064970
diff --git a/Kbuild b/Kbuild
index 90b5a8e..c6ea5d2 100644
--- a/Kbuild
+++ b/Kbuild
@@ -159,6 +159,9 @@
 	#Flag to enable memdump feature
 	CONFIG_WLAN_FEATURE_MEMDUMP := n
 
+	#Flag to enable DISA
+	CONFIG_WLAN_FEATURE_DISA := y
+
 	#Flag to enable Fast Path feature
 	CONFIG_WLAN_FASTPATH := y
 
@@ -420,6 +423,10 @@
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_memdump.o
 endif
 
+ifeq ($(CONFIG_WLAN_FEATURE_DISA),y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_disa.o
+endif
+
 ifeq ($(CONFIG_LFR_SUBNET_DETECTION), y)
 HDD_OBJS +=	$(HDD_SRC_DIR)/wlan_hdd_subnet_detect.o
 endif
@@ -1545,6 +1552,10 @@
 CDEFINES += -DWLAN_FEATURE_MEMDUMP
 endif
 
+ifeq ($(CONFIG_WLAN_FEATURE_DISA),y)
+CDEFINES += -DWLAN_FEATURE_DISA
+endif
+
 ifeq ($(CONFIG_LFR_SUBNET_DETECTION), y)
 CDEFINES += -DFEATURE_LFR_SUBNET_DETECTION
 endif
diff --git a/Kconfig b/Kconfig
index bac7403..da48376 100644
--- a/Kconfig
+++ b/Kconfig
@@ -132,4 +132,8 @@
 	bool "Enable data path trace feature"
 	default n
 
+config WLAN_FEATURE_DISA
+	bool "Enable DISA certification feature"
+	default n
+
 endif # QCA_CLD_WLAN
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index c534a7d..ce3e790 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -98,6 +98,7 @@
 #include <wlan_hdd_regulatory.h>
 #include "wlan_hdd_lpass.h"
 #include "wlan_hdd_nan_datapath.h"
+#include "wlan_hdd_disa.h"
 
 #define g_mode_rates_size (12)
 #define a_mode_rates_size (8)
@@ -8410,7 +8411,18 @@
 			WIPHY_VENDOR_CMD_NEED_NETDEV |
 			WIPHY_VENDOR_CMD_NEED_RUNNING,
 		.doit = wlan_hdd_cfg80211_set_fast_roaming
-	}
+	},
+#ifdef WLAN_FEATURE_DISA
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd =
+			QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+				 WIPHY_VENDOR_CMD_NEED_NETDEV |
+				 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wlan_hdd_cfg80211_encrypt_decrypt_msg
+	},
+#endif
 };
 
 /**
diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h
index 7355b4b..80dbc42 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.h
+++ b/core/hdd/src/wlan_hdd_cfg80211.h
@@ -429,6 +429,9 @@
 	QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122,
 	QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123,
 	QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124,
+
+	/* Encrypt/Decrypt command */
+	QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137,
 };
 
 /**
@@ -2896,6 +2899,44 @@
 		QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_vendor_attr_encryption_test - Attributes to
+ * validate encryption engine
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION: Flag attribute.
+ *    This will be included if the request is for decryption; if not included,
+ *    the request is treated as a request for encryption by default.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER: Unsigned 32-bit value
+ *    indicating the key cipher suite. Takes same values as
+ *    NL80211_ATTR_KEY_CIPHER.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID: Unsigned 8-bit value
+ *    Key Id to be used for encryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK: Array of 8-bit values.
+ *    Key (TK) to be used for encryption/decryption
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN: Array of 8-bit values.
+ *    Packet number to be specified for encryption/decryption
+ *    6 bytes for TKIP/CCMP/GCMP.
+ * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA: Array of 8-bit values
+ *    representing the 802.11 packet (header + payload + FCS) that
+ *    needs to be encrypted/decrypted.
+ *    Encrypted/decrypted response from the driver will also be sent
+ *    to userspace with the same attribute.
+ */
+enum qca_wlan_vendor_attr_encryption_test {
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION,
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER,
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID,
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK,
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN,
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA,
+
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX =
+		QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1
+};
+
 struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter,
 						tCsrRoamInfo *pRoamInfo);
 
diff --git a/core/hdd/src/wlan_hdd_disa.c b/core/hdd/src/wlan_hdd_disa.c
new file mode 100644
index 0000000..a4153fc
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_disa.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+/**
+ * DOC : wlan_hdd_disa.c
+ *
+ * WLAN Host Device Driver file for DISA certification
+ *
+ */
+
+#include "wlan_hdd_disa.h"
+#include "sme_api.h"
+
+#define ENCRYPT_DECRYPT_CONTEXT_MAGIC 0x4475354
+#define WLAN_WAIT_TIME_ENCRYPT_DECRYPT 1000
+
+
+/**
+ * hdd_encrypt_decrypt_msg_context - hdd encrypt/decrypt message context
+ *
+ * @magic: magic number
+ * @completion: Completion variable for encrypt/decrypt message
+ * @response_event: encrypt/decrypt message request wait event
+ */
+struct hdd_encrypt_decrypt_msg_context {
+	unsigned int magic;
+	struct completion completion;
+	struct sir_encrypt_decrypt_rsp_params response;
+};
+static struct hdd_encrypt_decrypt_msg_context encrypt_decrypt_msg_context;
+
+/**
+ * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space
+ * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters
+ *
+ * Return: none
+ */
+static void hdd_encrypt_decrypt_msg_cb(void *hdd_context,
+	struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params)
+{
+	hdd_context_t *hdd_ctx = hdd_context;
+	int ret;
+	struct hdd_encrypt_decrypt_msg_context *context;
+
+	ENTER();
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return;
+
+	if (!encrypt_decrypt_rsp_params) {
+		hdd_err("rsp params is NULL");
+		return;
+	}
+
+	print_hex_dump(KERN_INFO, "Data in hdd_encrypt_decrypt_msg_cb: ",
+		DUMP_PREFIX_NONE, 16, 1,
+		encrypt_decrypt_rsp_params->data,
+		encrypt_decrypt_rsp_params->data_length, 0);
+
+	hdd_err("vdev_id %d,status %d data_length %d",
+		encrypt_decrypt_rsp_params->vdev_id,
+		encrypt_decrypt_rsp_params->status,
+		encrypt_decrypt_rsp_params->data_length);
+
+	spin_lock(&hdd_context_lock);
+
+	context = &encrypt_decrypt_msg_context;
+	/* The caller presumably timed out so there is nothing we can do */
+	if (context->magic != ENCRYPT_DECRYPT_CONTEXT_MAGIC) {
+		spin_unlock(&hdd_context_lock);
+		return;
+	}
+
+	/* context is valid so caller is still waiting */
+	context->response = *encrypt_decrypt_rsp_params;
+
+	if (encrypt_decrypt_rsp_params->data_length) {
+		context->response.data =
+			qdf_mem_malloc(sizeof(uint8_t) *
+				encrypt_decrypt_rsp_params->data_length);
+		if (context->response.data == NULL) {
+			hdd_err("cdf_mem_alloc failed for data");
+			spin_unlock(&hdd_context_lock);
+			return;
+		}
+		qdf_mem_copy(context->response.data,
+			encrypt_decrypt_rsp_params->data,
+			encrypt_decrypt_rsp_params->data_length);
+	}
+
+	/*
+	 * Indicate to calling thread that
+	 * response data is available
+	 */
+	context->magic = 0;
+
+	complete(&context->completion);
+
+	spin_unlock(&hdd_context_lock);
+
+
+	EXIT();
+}
+
+
+/**
+ * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space
+ * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters
+ *
+ * Return: none
+ */
+static int hdd_post_encrypt_decrypt_msg_rsp(hdd_context_t *hdd_ctx,
+	struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params)
+{
+	struct sk_buff *skb;
+	uint32_t nl_buf_len;
+
+	ENTER();
+
+	nl_buf_len = encrypt_decrypt_rsp_params->data_length + NLA_HDRLEN;
+
+	skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
+	if (!skb) {
+		hdd_err(FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
+		return -ENOMEM;
+	}
+
+	if (encrypt_decrypt_rsp_params->data_length) {
+		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA,
+				encrypt_decrypt_rsp_params->data_length,
+				encrypt_decrypt_rsp_params->data)) {
+			hdd_err(FL("put fail"));
+			goto nla_put_failure;
+		}
+	}
+
+	cfg80211_vendor_cmd_reply(skb);
+	EXIT();
+	return 0;
+
+nla_put_failure:
+	kfree_skb(skb);
+	return -EINVAL;
+}
+
+/**
+ * hdd_fill_encrypt_decrypt_params () - parses data from user space
+ * and fills encrypt/decrypt parameters
+ * @encrypt_decrypt_params: encrypt/decrypt request parameters
+ * @adapter : adapter context
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ Return: 0 on success, negative errno on failure
+ */
+static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params
+						*encrypt_decrypt_params,
+						hdd_adapter_t *adapter,
+						const void *data,
+						int data_len)
+{
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1];
+	uint8_t len, mac_hdr_len;
+	uint8_t *tmp;
+	uint8_t fc[2];
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX,
+		      data, data_len, NULL)) {
+		hdd_err("Invalid ATTR");
+		return -EINVAL;
+	}
+
+	encrypt_decrypt_params->vdev_id = adapter->sessionId;
+	hdd_err("vdev_id : %d", encrypt_decrypt_params->vdev_id);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION]) {
+		hdd_err("attr flag NEEDS_DECRYPTION not present");
+		encrypt_decrypt_params->key_flag = WMI_ENCRYPT;
+	} else {
+		hdd_err("attr flag NEEDS_DECRYPTION present");
+		encrypt_decrypt_params->key_flag = WMI_DECRYPT;
+	}
+	hdd_err("Key flag : %d", encrypt_decrypt_params->key_flag);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]) {
+		hdd_err("attr key id failed");
+		return -EINVAL;
+	}
+	encrypt_decrypt_params->key_idx = nla_get_u8(tb
+		    [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]);
+	hdd_err("Key Idx : %d", encrypt_decrypt_params->key_idx);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]) {
+		hdd_err("attr Cipher failed");
+		return -EINVAL;
+	}
+	encrypt_decrypt_params->key_cipher = nla_get_u32(tb
+		    [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]);
+	hdd_err("key_cipher : %d", encrypt_decrypt_params->key_cipher);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]) {
+		hdd_err("attr TK failed");
+		return -EINVAL;
+	}
+	encrypt_decrypt_params->key_len =
+		nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]);
+	if (!encrypt_decrypt_params->key_len) {
+		hdd_err("Invalid TK length");
+		return -EINVAL;
+	}
+	hdd_err("Key len : %d", encrypt_decrypt_params->key_len);
+
+	if (encrypt_decrypt_params->key_len > SIR_MAC_MAX_KEY_LENGTH)
+		encrypt_decrypt_params->key_len = SIR_MAC_MAX_KEY_LENGTH;
+
+	tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]);
+
+	qdf_mem_copy(encrypt_decrypt_params->key_data, tmp,
+			encrypt_decrypt_params->key_len);
+
+	print_hex_dump(KERN_INFO, "Key : ", DUMP_PREFIX_NONE, 16, 1,
+			&encrypt_decrypt_params->key_data,
+			encrypt_decrypt_params->key_len, 0);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]) {
+		hdd_err("attr PN failed");
+		return -EINVAL;
+	}
+	len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]);
+	if (!len) {
+		hdd_err("Invalid PN length");
+		return -EINVAL;
+	}
+
+	tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]);
+
+	qdf_mem_copy(encrypt_decrypt_params->pn, tmp, len);
+
+	print_hex_dump(KERN_INFO, "PN received : ", DUMP_PREFIX_NONE, 16, 1,
+			&encrypt_decrypt_params->pn, len, 0);
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]) {
+		hdd_err("attr header failed");
+		return -EINVAL;
+	}
+	len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]);
+	if (!len) {
+		hdd_err("Invalid header and payload length");
+		return -EINVAL;
+	}
+
+	hdd_err("Header and Payload length %d ", len);
+
+	tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]);
+
+	print_hex_dump(KERN_INFO, "Header and Payload received: ",
+			DUMP_PREFIX_NONE, 16, 1,
+			tmp, len, 0);
+
+	mac_hdr_len = MIN_MAC_HEADER_LEN;
+
+	/*
+	 * Check to find out address 4. Address 4 is present if ToDS and FromDS
+	 * are 1 and data representation is little endian.
+	 */
+	fc[1] = *tmp;
+	fc[0] = *(tmp + 1);
+	if ((fc[0] & 0x03) == 0x03) {
+		hdd_err("Address 4 is present");
+		mac_hdr_len += IEEE80211_ADDR_LEN;
+	}
+
+	/*
+	 * Check to find out Qos control field. Qos control field is present
+	 * if msb of subtype field is 1 and data representation is
+	 * little endian.
+	 */
+	if (fc[1] & 0x80) {
+		hdd_err("Qos control is present");
+		mac_hdr_len += QOS_CONTROL_LEN;
+	}
+
+	hdd_err("mac_hdr_len %d", mac_hdr_len);
+
+	qdf_mem_copy(encrypt_decrypt_params->mac_header,
+			tmp, mac_hdr_len);
+
+	print_hex_dump(KERN_INFO, "Header received in request: ",
+			DUMP_PREFIX_NONE, 16, 1,
+			encrypt_decrypt_params->mac_header,
+			mac_hdr_len, 0);
+
+	encrypt_decrypt_params->data_len =
+			len - mac_hdr_len;
+
+	hdd_err("Payload length : %d", encrypt_decrypt_params->data_len);
+
+	if (encrypt_decrypt_params->data_len) {
+		encrypt_decrypt_params->data =
+			qdf_mem_malloc(sizeof(uint8_t) *
+				encrypt_decrypt_params->data_len);
+
+		if (encrypt_decrypt_params->data == NULL) {
+			hdd_err("cdf_mem_alloc failed for data");
+			return -ENOMEM;
+		}
+
+		qdf_mem_copy(encrypt_decrypt_params->data,
+			tmp + mac_hdr_len,
+			encrypt_decrypt_params->data_len);
+
+		print_hex_dump(KERN_INFO, "Data received in request: ",
+			DUMP_PREFIX_NONE, 16, 1,
+			encrypt_decrypt_params->data,
+			encrypt_decrypt_params->data_len, 0);
+	}
+
+	return 0;
+}
+
+/**
+ * hdd_encrypt_decrypt_msg () - process encrypt/decrypt message
+ * @adapter : adapter context
+ * @hdd_ctx: hdd context
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ Return: 0 on success, negative errno on failure
+ */
+static int hdd_encrypt_decrypt_msg(hdd_adapter_t *adapter,
+						hdd_context_t *hdd_ctx,
+						const void *data,
+						int data_len)
+{
+	struct encrypt_decrypt_req_params encrypt_decrypt_params = {0};
+	QDF_STATUS qdf_status;
+	int ret;
+	struct hdd_encrypt_decrypt_msg_context *context;
+	unsigned long rc;
+
+	ret = hdd_fill_encrypt_decrypt_params(&encrypt_decrypt_params,
+				adapter, data, data_len);
+	if (ret)
+		return ret;
+
+	spin_lock(&hdd_context_lock);
+	context = &encrypt_decrypt_msg_context;
+	context->magic = ENCRYPT_DECRYPT_CONTEXT_MAGIC;
+	INIT_COMPLETION(context->completion);
+	spin_unlock(&hdd_context_lock);
+
+	qdf_status = sme_encrypt_decrypt_msg(hdd_ctx->hHal,
+					&encrypt_decrypt_params);
+
+	qdf_mem_free(encrypt_decrypt_params.data);
+
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		hdd_err("Unable to post encrypt/decrypt message");
+		return -EINVAL;
+	}
+
+	rc = wait_for_completion_timeout(&context->completion,
+			msecs_to_jiffies(WLAN_WAIT_TIME_ENCRYPT_DECRYPT));
+
+	spin_lock(&hdd_context_lock);
+	if (!rc && (context->magic ==
+			ENCRYPT_DECRYPT_CONTEXT_MAGIC)) {
+		hdd_err("Target response timed out");
+		context->magic = 0;
+		spin_unlock(&hdd_context_lock);
+		return -ETIMEDOUT;
+	}
+
+	spin_unlock(&hdd_context_lock);
+	ret = hdd_post_encrypt_decrypt_msg_rsp(hdd_ctx,
+				&encrypt_decrypt_msg_context.response);
+	if (ret)
+		hdd_err("Failed to post encrypt/decrypt message response");
+
+	qdf_mem_free(encrypt_decrypt_msg_context.response.data);
+
+	EXIT();
+	return ret;
+}
+
+/**
+ * hdd_encrypt_decrypt_init () - exposes encrypt/decrypt initialization
+ * functionality
+ * @hdd_ctx: hdd context
+ *
+ Return: 0 on success, negative errno on failure
+ */
+int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx)
+{
+	QDF_STATUS status;
+
+	init_completion(&encrypt_decrypt_msg_context.completion);
+
+	status = sme_encrypt_decrypt_msg_register_callback(hdd_ctx->hHal,
+					hdd_encrypt_decrypt_msg_cb);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		hdd_err("encrypt/decrypt callback failed %d", status);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * hdd_encrypt_decrypt_deinit () - exposes encrypt/decrypt deinitialization
+ * functionality
+ * @hdd_ctx: hdd context
+ *
+ Return: 0 on success, negative errno on failure
+ */
+int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx)
+{
+	QDF_STATUS status;
+
+	status = sme_encrypt_decrypt_msg_deregister_callback(hdd_ctx->hHal);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		hdd_err("De-register encrypt/decrypt callback failed: %d",
+			status);
+	return 0;
+}
+
+/**
+ * __wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int __wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy,
+						struct wireless_dev *wdev,
+						const void *data,
+						int data_len)
+{
+	hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+	struct net_device *dev = wdev->netdev;
+	hdd_adapter_t *adapter = NULL;
+	int ret;
+
+	ENTER_DEV(dev);
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return ret;
+
+	adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+	ret = hdd_encrypt_decrypt_msg(adapter, hdd_ctx, data, data_len);
+
+	return ret;
+}
+
+/**
+ * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy,
+						struct wireless_dev *wdev,
+						const void *data,
+						int data_len)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_cfg80211_encrypt_decrypt_msg(wiphy, wdev,
+						data, data_len);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
diff --git a/core/hdd/src/wlan_hdd_disa.h b/core/hdd/src/wlan_hdd_disa.h
new file mode 100644
index 0000000..b35c02c
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_disa.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 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 _WLAN_HDD_DISA_H
+#define _WLAN_HDD_DISA_H
+
+#include "wlan_hdd_main.h"
+#include "sir_api.h"
+
+#ifdef WLAN_FEATURE_DISA
+/**
+ * hdd_encrypt_decrypt_init () - exposes encrypt/decrypt initialization
+ * functionality
+ * @hdd_ctx: hdd context
+ *
+ Return: 0 on success, negative errno on failure
+ */
+int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx);
+
+/**
+ * hdd_encrypt_decrypt_deinit () - exposes encrypt/decrypt deinitialization
+ * functionality
+ * @hdd_ctx: hdd context
+ *
+ Return: 0 on success, negative errno on failure
+ */
+int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx);
+#else
+static inline int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx)
+{
+	return -ENOTSUPP;
+}
+static inline int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx)
+{
+	return -ENOTSUPP;
+}
+#endif
+
+#ifdef WLAN_FEATURE_DISA
+/**
+ * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg
+ * @wiphy: Pointer to wireless phy
+ * @wdev: Pointer to wireless device
+ * @data: Pointer to data
+ * @data_len: Data length
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy,
+			struct wireless_dev *wdev,
+			const void *data,
+			int data_len);
+#endif
+
+#endif
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 33f9cfc..9aeee91 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -107,6 +107,7 @@
 #include "wlan_hdd_lpass.h"
 #include "nan_api.h"
 #include <wlan_hdd_napi.h>
+#include "wlan_hdd_disa.h"
 
 #ifdef MODULE
 #define WLAN_MODULE_NAME  module_name(THIS_MODULE)
@@ -4695,8 +4696,7 @@
 	/* Free up RoC request queue and flush workqueue */
 	cds_flush_work(&hdd_ctx->roc_req_work);
 
-
-
+	hdd_encrypt_decrypt_deinit(hdd_ctx);
 	wlansap_global_deinit();
 	wlan_hdd_deinit_tx_rx_histogram(hdd_ctx);
 	wiphy_unregister(wiphy);
@@ -7781,6 +7781,7 @@
 		goto err_debugfs_exit;
 
 	memdump_init();
+	hdd_encrypt_decrypt_init(hdd_ctx);
 
 	if (hdd_ctx->config->fIsImpsEnabled)
 		hdd_set_idle_ps_config(hdd_ctx, true);
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 43b6ccd..0fdac5c 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -6536,4 +6536,18 @@
 	uint8_t access_policy;
 };
 
+/**
+ * struct sir_encrypt_decrypt_rsp_params - encrypt/decrypt rsp params
+ * @vdev_id: vdev id
+ * @status: status
+ * @data_length: data length
+ * @data: data pointer
+ */
+struct sir_encrypt_decrypt_rsp_params {
+	uint32_t vdev_id;
+	int32_t status;
+	uint32_t data_length;
+	uint8_t *data;
+};
+
 #endif /* __SIR_API_H */
diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h
index 903f3a6..2b71b51 100644
--- a/core/mac/src/include/sir_params.h
+++ b/core/mac/src/include/sir_params.h
@@ -633,6 +633,7 @@
 #define SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 360)
 #define SIR_HAL_POWER_DBG_CMD               (SIR_HAL_ITC_MSG_TYPES_BEGIN + 362)
 #define SIR_HAL_SET_DTIM_PERIOD             (SIR_HAL_ITC_MSG_TYPES_BEGIN + 363)
+#define SIR_HAL_ENCRYPT_DECRYPT_MSG         (SIR_HAL_ITC_MSG_TYPES_BEGIN + 364)
 
 #define SIR_HAL_MSG_TYPES_END                (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h
index 9afb984..15f8455 100644
--- a/core/sme/inc/sme_api.h
+++ b/core/sme/inc/sme_api.h
@@ -1276,4 +1276,44 @@
  */
 QDF_STATUS sme_update_session_param(tHalHandle hal, uint8_t session_id,
 		uint32_t param_type, uint32_t param_val);
+
+/**
+ * sme_encrypt_decrypt_msg_register_callback() - Registers
+ * encrypt/decrypt message callback
+ *
+ * @hal - MAC global handle
+ * @callback_routine - callback routine from HDD
+ *
+ * This API is invoked by HDD to register its callback in SME
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_encrypt_decrypt_msg_register_callback(tHalHandle hal,
+		void (*encrypt_decrypt_cb)(void *hdd_context,
+			struct sir_encrypt_decrypt_rsp_params
+					*encrypt_decrypt_rsp_params));
+
+/**
+ * sme_encrypt_decrypt_msg_deregister_callback() - Registers
+ * encrypt/decrypt message callback
+ *
+ * @h_hal - MAC global handle
+ * @callback_routine - callback routine from HDD
+ *
+ * This API is invoked by HDD to de-register its callback in SME
+ *
+ * Return: QDF_STATUS Enumeration
+ */
+QDF_STATUS sme_encrypt_decrypt_msg_deregister_callback(tHalHandle h_hal);
+
+/**
+ * sme_encrypt_decrypt_msg() - handles encrypt/decrypt mesaage
+ * @hal: HAL handle
+ * @encrypt_decrypt_params: struct to set encryption/decryption params.
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS sme_encrypt_decrypt_msg(tHalHandle hal,
+	struct encrypt_decrypt_req_params *encrypt_decrypt_params);
+
 #endif /* #if !defined( __SME_API_H ) */
diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h
index 51c135e..0afada7 100644
--- a/core/sme/inc/sme_internal.h
+++ b/core/sme/inc/sme_internal.h
@@ -244,6 +244,8 @@
 	p2p_lo_callback p2p_lo_event_callback;
 	void *p2p_lo_event_context;
 	sme_send_oem_data_rsp_msg oem_data_rsp_callback;
+	void (*encrypt_decrypt_cb)(void *,
+			struct sir_encrypt_decrypt_rsp_params *);
 } tSmeStruct, *tpSmeStruct;
 
 #endif /* #if !defined( __SMEINTERNAL_H ) */
diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c
index 1a04362..2983525 100644
--- a/core/sme/src/common/sme_api.c
+++ b/core/sme/src/common/sme_api.c
@@ -16593,3 +16593,134 @@
 	sms_log(mac_ctx, LOG1, FL("Set default scan IE status %d"), status);
 	return status;
 }
+
+/**
+ * sme_encrypt_decrypt_msg() - handles encrypt/decrypt mesaage
+ * @hal: HAL handle
+ * @encrypt_decrypt_params: struct to set encryption/decryption params.
+ *
+ * Return: QDF_STATUS enumeration.
+ */
+QDF_STATUS sme_encrypt_decrypt_msg(tHalHandle hal,
+	struct encrypt_decrypt_req_params *encrypt_decrypt_params)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+	cds_msg_t cds_msg;
+	struct encrypt_decrypt_req_params *params;
+	uint8_t *ptr;
+
+	ptr = qdf_mem_malloc(sizeof(*params) +
+				encrypt_decrypt_params->data_len);
+	if (ptr == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			FL("Failed to alloc memory for encrypt/decrypt params"));
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	params = (struct encrypt_decrypt_req_params *)ptr;
+
+	*params = *encrypt_decrypt_params;
+
+	if (params->data_len) {
+		params->data = ptr + sizeof(*params);
+
+		qdf_mem_copy(params->data, encrypt_decrypt_params->data,
+					params->data_len);
+	}
+
+	status = sme_acquire_global_lock(&mac_ctx->sme);
+	if (status == QDF_STATUS_SUCCESS) {
+		/* Serialize the req through MC thread */
+		cds_msg.bodyptr = params;
+		cds_msg.type = WMA_ENCRYPT_DECRYPT_MSG;
+		status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_msg);
+
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+				FL("Post encrypt/decrypt msg fail"));
+			status = QDF_STATUS_E_FAILURE;
+			qdf_mem_free(params);
+		}
+		sme_release_global_lock(&mac_ctx->sme);
+	} else {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+				FL("sme_acquire_global_lock failed"));
+		qdf_mem_free(params);
+	}
+	return status;
+
+}
+
+/**
+ * sme_encrypt_decrypt_msg_register_callback() - Registers
+ * encrypt/decrypt message callback
+ *
+ * @hal - MAC global handle
+ * @callback_routine - callback routine from HDD
+ *
+ * This API is invoked by HDD to register its callback in SME
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_encrypt_decrypt_msg_register_callback(tHalHandle hal,
+		void (*encrypt_decrypt_cb)(void *hdd_context,
+			struct sir_encrypt_decrypt_rsp_params
+				*encrypt_decrypt_rsp_params))
+{
+	QDF_STATUS status   = QDF_STATUS_SUCCESS;
+	tpAniSirGlobal mac;
+
+	if (!hal) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+				  FL("hHal is not valid"));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mac = PMAC_STRUCT(hal);
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.encrypt_decrypt_cb = encrypt_decrypt_cb;
+		sme_release_global_lock(&mac->sme);
+	} else {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			FL("sme_acquire_global_lock failed"));
+	}
+	return status;
+}
+
+/**
+ * sme_encrypt_decrypt_msg_deregister_callback() - Registers
+ * encrypt/decrypt message callback
+ *
+ * @h_hal - MAC global handle
+ * @callback_routine - callback routine from HDD
+ *
+ * This API is invoked by HDD to de-register its callback in SME
+ *
+ * Return: QDF_STATUS Enumeration
+ */
+QDF_STATUS sme_encrypt_decrypt_msg_deregister_callback(tHalHandle h_hal)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tpAniSirGlobal mac;
+
+	if (!h_hal) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+				  FL("hHal is not valid"));
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mac = PMAC_STRUCT(h_hal);
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		mac->sme.encrypt_decrypt_cb = NULL;
+		sme_release_global_lock(&mac->sme);
+	} else {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			FL("sme_acquire_global_lock failed"));
+	}
+	return status;
+}
diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h
index 0879247..f22aea6 100644
--- a/core/wma/inc/wma.h
+++ b/core/wma/inc/wma.h
@@ -415,6 +415,9 @@
 };
 
 typedef void (*txFailIndCallback)(uint8_t *peer_mac, uint8_t seqNo);
+typedef void (*encrypt_decrypt_cb)(struct sir_encrypt_decrypt_rsp_params
+		*encrypt_decrypt_rsp_params);
+
 
 /**
  * enum t_wma_drv_type - wma driver type
diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h
index 951048c..dcd121e 100644
--- a/core/wma/inc/wma_api.h
+++ b/core/wma/inc/wma_api.h
@@ -301,4 +301,6 @@
 	wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry,
 	struct sir_hw_mode_trans_ind *hw_mode_trans_ind);
 QDF_STATUS wma_set_powersave_config(uint8_t val);
+QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE wma,
+		struct encrypt_decrypt_req_params *encrypt_decrypt_params);
 #endif
diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h
index dadac75..f35044e 100644
--- a/core/wma/inc/wma_internal.h
+++ b/core/wma/inc/wma_internal.h
@@ -1214,4 +1214,7 @@
 				       struct sir_mac_pwr_dbg_cmd *
 				       sir_pwr_dbg_params);
 
+int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data,
+			uint32_t data_len);
+
 #endif
diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h
index e0fe6e4..89f06c9 100644
--- a/core/wma/inc/wma_types.h
+++ b/core/wma/inc/wma_types.h
@@ -474,6 +474,7 @@
 #define WMA_SET_PDEV_IE_REQ                  SIR_HAL_SET_PDEV_IE_REQ
 #define WMA_UPDATE_WEP_DEFAULT_KEY           SIR_HAL_UPDATE_WEP_DEFAULT_KEY
 #define WMA_SEND_FREQ_RANGE_CONTROL_IND      SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND
+#define WMA_ENCRYPT_DECRYPT_MSG              SIR_HAL_ENCRYPT_DECRYPT_MSG
 
 /* Bit 6 will be used to control BD rate for Management frames */
 #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40
diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c
index 9a823e8..7850fa7 100644
--- a/core/wma/src/wma_features.c
+++ b/core/wma/src/wma_features.c
@@ -8225,3 +8225,108 @@
 
 	return QDF_STATUS_SUCCESS;
 }
+
+/**
+ * wma_encrypt_decrypt_msg() -
+ * @encrypt_decrypt_params: encryption/decryption params
+ * @data_len: data length
+ * @encrypt_decrypt_cb: encrypt/decrypt callback
+ *
+ *  This function sends WMI command to check encryption/decryption engine.
+ *
+ *  Return: QDF_STATUS enumeration
+ */
+QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE handle,
+		struct encrypt_decrypt_req_params *encrypt_decrypt_params)
+{
+	int ret;
+	tp_wma_handle wma = (tp_wma_handle) handle;
+
+	if (!wma || !wma->wmi_handle) {
+		WMA_LOGE("%s: WMA is closed, can not issue encrypt/decrypt msg",
+			__func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (encrypt_decrypt_params == NULL) {
+		WMA_LOGE("%s: encrypt/decrypt ptr NULL",
+			__func__);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	ret = wmi_unified_encrypt_decrypt_send_cmd(wma->wmi_handle,
+				encrypt_decrypt_params);
+
+	return ret;
+}
+
+/**
+ * wma_encrypt_decrypt_msg_handler() - handle encrypt/decrypt data
+ * indicated by FW
+ * @handle: wma context
+ * @data: event buffer
+ * @data len: length of event buffer
+ *
+ * Return: 0 on success
+ */
+int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data,
+			uint32_t data_len)
+{
+	WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID_param_tlvs *param_buf;
+	wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param *data_event;
+	struct sir_encrypt_decrypt_rsp_params encrypt_decrypt_rsp_params;
+	tp_wma_handle wma = handle;
+	u_int8_t *buf_ptr;
+	tpAniSirGlobal pmac;
+
+	if (data == NULL) {
+		WMA_LOGE("%s: invalid pointer", __func__);
+		return -EINVAL;
+	}
+
+	if (wma == NULL) {
+		WMA_LOGE("%s: wma context is NULL", __func__);
+		return -EINVAL;
+	}
+
+	WMA_LOGE("%s: received WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID ",
+			__func__);
+
+	pmac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE);
+
+	if (!pmac) {
+		WMA_LOGE("%s: Invalid pmac", __func__);
+		return -EINVAL;
+	}
+	if (!pmac->sme.encrypt_decrypt_cb) {
+		WMA_LOGE("%s: Callback not registered", __func__);
+		return -EINVAL;
+	}
+
+	param_buf =
+		(WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID_param_tlvs *)data;
+	if (!param_buf) {
+		WMA_LOGE("%s: Invalid response data buf", __func__);
+		return -EINVAL;
+	}
+
+	data_event = param_buf->fixed_param;
+
+	encrypt_decrypt_rsp_params.vdev_id = data_event->vdev_id;
+	encrypt_decrypt_rsp_params.status = data_event->status;
+	encrypt_decrypt_rsp_params.data_length = data_event->data_length;
+
+	if (encrypt_decrypt_rsp_params.data_length) {
+		buf_ptr =
+			(uint8_t *)data_event +
+			sizeof(
+			wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param) +
+			WMI_TLV_HDR_SIZE;
+
+		encrypt_decrypt_rsp_params.data = buf_ptr;
+	}
+
+	pmac->sme.encrypt_decrypt_cb(pmac->hHdd, &encrypt_decrypt_rsp_params);
+
+	return 0;
+}
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 35cf0b8..00f1735 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -2147,6 +2147,10 @@
 					   WMI_BPF_CAPABILIY_INFO_EVENTID,
 					   wma_get_bpf_caps_event_handler,
 					   WMA_RX_SERIALIZER_CTX);
+	wmi_unified_register_event_handler(wma_handle->wmi_handle,
+				WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID,
+				wma_encrypt_decrypt_msg_handler,
+				WMA_RX_SERIALIZER_CTX);
 	wma_ndp_register_all_event_handlers(wma_handle);
 	return QDF_STATUS_SUCCESS;
 
@@ -6303,6 +6307,10 @@
 	case WMA_SEND_FREQ_RANGE_CONTROL_IND:
 		wma_enable_disable_caevent_ind(wma_handle, msg->bodyval);
 		break;
+	case WMA_ENCRYPT_DECRYPT_MSG:
+		wma_encrypt_decrypt_msg(wma_handle, msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
 	default:
 		WMA_LOGD("unknow msg type %x", msg->type);
 		/* Do Nothing? MSG Body should be freed at here */