qcacld-3.0: Fix to send the deauthentication frame from HDD

qcacld-2.0 to qcacld-3.0 propagation

Currently, On sending disassoc from HDD lim will process
disassoc and clear's session of station and thus leading to
drop deauth in lim since context is already cleared. Hence
deauth frame is not sent from SoftAP although deauth command
is executed on hostapd_cli.
Fix will ensure to send disassoc command through new API
and doesn't clear's session and the same is cleared after
sending deauth.

Change-Id: I912a91f1df4001bb2d4f1f0d6031cc102d1bbd65
CRs-Fixed: 981121
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index de87474..b20231a 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -6432,4 +6432,24 @@
 	uint32_t args[MAX_POWER_DBG_ARGS_SUPPORTED];
 };
 
+/**
+ * struct sme_send_disassoc_frm_req - send disassoc request frame
+ * @msg_type: message type
+ * @length: length of message
+ * @session_id: session id
+ * @trans_id: transaction id
+ * @peer_mac: peer mac address
+ * @reason: reason for disassoc
+ * @wait_for_ack: wait for acknowledgment
+ **/
+ struct sme_send_disassoc_frm_req {
+	uint16_t msg_type;
+	uint16_t length;
+	uint8_t session_id;
+	uint16_t trans_id;
+	uint8_t peer_mac[6];
+	uint16_t reason;
+	uint8_t wait_for_ack;
+ };
+
 #endif /* __SIR_API_H */
diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h
index 3703f93..0798123 100644
--- a/core/mac/inc/wni_api.h
+++ b/core/mac/inc/wni_api.h
@@ -261,6 +261,7 @@
 	eWNI_SME_NDP_PEER_DEPARTED_IND,
 	eWNI_SME_NDP_END_IND,
 	eWNI_SME_REGISTER_P2P_ACK_CB,
+	eWNI_SME_SEND_DISASSOC_FRAME,
 	eWNI_SME_MSG_TYPES_END
 };
 
diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c
index 6174266..e7820b1 100644
--- a/core/mac/src/pe/lim/lim_process_message_queue.c
+++ b/core/mac/src/pe/lim/lim_process_message_queue.c
@@ -1364,7 +1364,10 @@
 		/* These messages are from HDD. Need to respond to HDD */
 		lim_process_normal_hdd_msg(mac_ctx, msg, true);
 		break;
-
+	case eWNI_SME_SEND_DISASSOC_FRAME:
+		/* Need to response to hdd */
+		lim_process_normal_hdd_msg(mac_ctx, msg, true);
+		break;
 	case eWNI_SME_SCAN_ABORT_IND:
 		req_msg = msg->bodyptr;
 		if (req_msg) {
diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
index a5e8d81..cc4e317 100644
--- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
@@ -90,6 +90,8 @@
 static void __lim_process_sme_deauth_req(tpAniSirGlobal, uint32_t *);
 static void __lim_process_sme_set_context_req(tpAniSirGlobal, uint32_t *);
 static bool __lim_process_sme_stop_bss_req(tpAniSirGlobal, tpSirMsgQ pMsg);
+static void __lim_process_send_disassoc_frame(tpAniSirGlobal mac_ctx,
+				uint32_t *msg_buf);
 static void lim_process_sme_channel_change_request(tpAniSirGlobal pMac,
 						   uint32_t *pMsg);
 static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg);
@@ -120,7 +122,6 @@
 static void lim_process_ext_change_channel(tpAniSirGlobal mac_ctx,
 						uint32_t *msg);
 
-
 /**
  * lim_process_set_hw_mode() - Send set HW mode command to WMA
  * @mac: Globacl MAC pointer
@@ -4763,6 +4764,69 @@
 }
 
 /**
+ *__lim_process_send_disassoc_frame: function processes disassoc frame
+ * @mac_ctx: pointer to mac context
+ * @msg_buf: message buffer
+ *
+ * function processes disassoc request received from SME
+ *
+ * return: none
+ */
+static void __lim_process_send_disassoc_frame(tpAniSirGlobal mac_ctx,
+					uint32_t *msg_buf)
+{
+	struct sme_send_disassoc_frm_req sme_send_disassoc_frame_req;
+	tSirRetStatus status;
+	tpPESession session_entry = NULL;
+	uint8_t sme_session_id;
+	uint16_t sme_trans_id;
+
+	if (msg_buf == NULL) {
+		lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL"));
+		return;
+	}
+
+	lim_get_session_info(mac_ctx, (uint8_t *)msg_buf, &sme_session_id,
+			&sme_trans_id);
+
+	status = lim_send_disassoc_frm_req_ser_des(mac_ctx,
+				&sme_send_disassoc_frame_req,
+				(uint8_t *)msg_buf);
+
+	if ((eSIR_FAILURE == status) ||
+		(lim_is_group_addr(sme_send_disassoc_frame_req.peer_mac) &&
+		!lim_is_addr_bc(sme_send_disassoc_frame_req.peer_mac))) {
+		PELOGE(lim_log(mac_ctx, LOGE,
+			FL("received invalid SME_DISASSOC_REQ message"));)
+		return;
+	}
+
+	session_entry = pe_find_session_by_sme_session_id(
+				mac_ctx, sme_session_id);
+	if (session_entry == NULL) {
+		lim_log(mac_ctx, LOGE,
+			FL("session does not exist for given bssId "MAC_ADDRESS_STR),
+			MAC_ADDR_ARRAY(sme_send_disassoc_frame_req.peer_mac));
+		return;
+	}
+
+	lim_log(mac_ctx, LOG1,
+			FL("msg_type->%d len->%d sess_id->%d trans_id->%d mac->"MAC_ADDRESS_STR" reason->%d wait_for_ack->%d"),
+			sme_send_disassoc_frame_req.msg_type,
+			sme_send_disassoc_frame_req.length,
+			sme_send_disassoc_frame_req.session_id,
+			sme_send_disassoc_frame_req.trans_id,
+			MAC_ADDR_ARRAY(sme_send_disassoc_frame_req.peer_mac),
+			sme_send_disassoc_frame_req.reason,
+			sme_send_disassoc_frame_req.wait_for_ack);
+
+	lim_send_disassoc_mgmt_frame(mac_ctx,
+		sme_send_disassoc_frame_req.reason,
+		sme_send_disassoc_frame_req.peer_mac,
+		session_entry, sme_send_disassoc_frame_req.wait_for_ack);
+}
+
+/**
  * lim_set_pdev_ht_ie() - sends the set HT IE req to FW
  * @mac_ctx: Pointer to Global MAC structure
  * @pdev_id: pdev id to set the IE.
@@ -5031,6 +5095,10 @@
 		__lim_process_sme_deauth_req(pMac, pMsgBuf);
 		break;
 
+	case eWNI_SME_SEND_DISASSOC_FRAME:
+		__lim_process_send_disassoc_frame(pMac, pMsgBuf);
+		break;
+
 	case eWNI_SME_SETCONTEXT_REQ:
 		__lim_process_sme_set_context_req(pMac, pMsgBuf);
 		break;
diff --git a/core/mac/src/pe/lim/lim_ser_des_utils.c b/core/mac/src/pe/lim/lim_ser_des_utils.c
index bd778f5..55da544 100644
--- a/core/mac/src/pe/lim/lim_ser_des_utils.c
+++ b/core/mac/src/pe/lim/lim_ser_des_utils.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015,2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -43,6 +43,7 @@
 #include "lim_utils.h"
 #include "lim_ser_des_utils.h"
 
+
 /**---------------------------------------------------------------
    \fn     lim_get_session_info
    \brief  This function returns the sessionId and transactionId
@@ -76,3 +77,77 @@
 
 	return;
 }
+
+/**
+ * lim_send_disassoc_frm_req_ser_des - called on receiving SME_DISASSOC_REQ
+ * @mac_ctx: pointer to mac context
+ * @disassoc_frm_req: pointer to structure sme_send_disassoc_frm_req
+ *
+ * function send's disassoc frame request on receiving SME_DISASSOC_REQ
+ *
+ * return: eSIR_SUCCESS:Success Error value: Failure
+ */
+tSirRetStatus lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx,
+			struct sme_send_disassoc_frm_req *disassoc_frm_req,
+			uint8_t *buf)
+{
+	A_INT16 len = 0;
+
+	if (!disassoc_frm_req || !buf)
+		return eSIR_FAILURE;
+
+	disassoc_frm_req->msg_type = lim_get_u16(buf);
+	buf += sizeof(A_UINT16);
+
+	len = disassoc_frm_req->length = lim_get_u16(buf);
+	buf += sizeof(A_UINT16);
+
+	PELOG1(lim_log(mac_ctx, LOG1,
+		FL("SME_DISASSOC_REQ length %d bytes is:"), len);)
+		PELOG1(sirDumpBuf(mac_ctx, SIR_LIM_MODULE_ID, LOG1, buf, len);)
+
+	if (len < (A_INT16) sizeof(A_UINT32))
+		return eSIR_FAILURE;
+
+	/* skip message header */
+	len -= sizeof(A_UINT32);
+	if (len < 0)
+		return eSIR_FAILURE;
+
+	/* Extract sessionID */
+	disassoc_frm_req->session_id = *buf;
+	buf += sizeof(A_UINT8);
+	len -= sizeof(A_UINT8);
+	if (len < 0)
+		return eSIR_FAILURE;
+
+	/* Extract transactionid */
+	disassoc_frm_req->trans_id = lim_get_u16(buf);
+	buf += sizeof(A_UINT16);
+	len -= sizeof(A_UINT16);
+
+	if (len < 0)
+		return eSIR_FAILURE;
+
+	/* Extract peerMacAddr */
+	qdf_mem_copy(disassoc_frm_req->peer_mac, buf, sizeof(tSirMacAddr));
+	buf += sizeof(tSirMacAddr);
+	len  -= sizeof(tSirMacAddr);
+
+	if (len < 0)
+		return eSIR_FAILURE;
+
+	/* Extract reasonCode */
+	disassoc_frm_req->reason = lim_get_u16(buf);
+	buf += sizeof(A_UINT16);
+	len  -= sizeof(A_UINT16);
+
+	if (len < 0)
+		return eSIR_FAILURE;
+
+	disassoc_frm_req->wait_for_ack = *buf;
+	buf += sizeof(A_UINT8);
+	len -= sizeof(A_UINT8);
+
+	return eSIR_SUCCESS;
+}
diff --git a/core/mac/src/pe/lim/lim_ser_des_utils.h b/core/mac/src/pe/lim/lim_ser_des_utils.h
index f05f4dd..82b9c48 100644
--- a/core/mac/src/pe/lim/lim_ser_des_utils.h
+++ b/core/mac/src/pe/lim/lim_ser_des_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015,2016 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -95,4 +95,8 @@
 #endif
 }
 
+tSirRetStatus lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx,
+		struct sme_send_disassoc_frm_req *disassoc_frm_req,
+		uint8_t *buf);
+
 #endif /* __LIM_SERDES_UTILS_H */