qcacld-3.0: Retry Auth from host in case ack is not received for Auth

qcacld-2.0 to qcacld-3.0 propagation

In few APs with power save feature, if no STA is connected, the AP
does not respond to the Auth from STA, unless Auth is sent near to
the AP's CT window. With current implementation host does not
retry the auth and wait for the auth timeout to happen before
returning connect failure.

With this change Host will retry the Auth frame with interval of
3/5 * beacon interval, if no Ack is received for the frame,
until the auth timeout happens.

This increases the probability for the Auth to be received by AP near
to its beacon and thus initiate the connection.

CRs-Fixed: 816177
Change-Id: I51a6032f910b32eb91d67cb078e6434016ae8650
diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h
index db0618a..8f68465 100644
--- a/core/mac/inc/ani_global.h
+++ b/core/mac/inc/ani_global.h
@@ -324,6 +324,7 @@
 	 * for a period of time on a particular DFS channel
 	 */
 	TX_TIMER gLimActiveToPassiveChannelTimer;
+	TX_TIMER g_lim_periodic_auth_retry_timer;
 
 /* ********************TIMER SECTION ENDS************************************************** */
 /* ALL THE FIELDS BELOW THIS CAN BE ZEROED OUT in lim_initialize */
@@ -962,6 +963,21 @@
 
 } tHalMacStartParameters;
 
+/**
+ * enum auth_tx_ack_status - Indicate TX status of AUTH
+ * @LIM_AUTH_ACK_NOT_RCD : Default status while waiting for ack status.
+ * @LIM_AUTH_ACK_RCD_SUCCESS : Ack is received.
+ * @LIM_AUTH_ACK_RCD_FAILURE : No Ack received.
+ *
+ * Indicate if driver is waiting for ACK status of auth or ACK received for AUTH
+ * OR NO ACK is received for the auth sent.
+ */
+enum auth_tx_ack_status {
+	LIM_AUTH_ACK_NOT_RCD,
+	LIM_AUTH_ACK_RCD_SUCCESS,
+	LIM_AUTH_ACK_RCD_FAILURE,
+};
+
 /* ------------------------------------------------------------------- */
 /* / MAC Sirius parameter structure */
 typedef struct sAniSirGlobal {
@@ -1030,6 +1046,7 @@
 	sir_mgmt_frame_ind_callback mgmt_frame_ind_cb;
 	bool first_scan_done;
 	int8_t first_scan_bucket_threshold;
+	enum auth_tx_ack_status auth_ack_status;
 } tAniSirGlobal;
 
 typedef enum {
diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h
index 89a0505..d8b6418 100644
--- a/core/mac/src/include/sir_params.h
+++ b/core/mac/src/include/sir_params.h
@@ -693,6 +693,7 @@
 
 #define SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE \
 					 (SIR_LIM_TIMEOUT_MSG_START + 0x2C)
+#define SIR_LIM_AUTH_RETRY_TIMEOUT     (SIR_LIM_TIMEOUT_MSG_START + 0x2D)
 
 #define SIR_LIM_MSG_TYPES_END            (SIR_LIM_MSG_TYPES_BEGIN+0xFF)
 
diff --git a/core/mac/src/pe/lim/lim_ft.c b/core/mac/src/pe/lim/lim_ft.c
index fd8cd22..82f2498 100644
--- a/core/mac/src/pe/lim/lim_ft.c
+++ b/core/mac/src/pe/lim/lim_ft.c
@@ -359,7 +359,7 @@
 
 	lim_send_auth_mgmt_frame(pMac, &authFrame,
 		 psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId,
-		 LIM_NO_WEP_IN_FC, psessionEntry);
+		 LIM_NO_WEP_IN_FC, psessionEntry, false);
 
 	return;
 
diff --git a/core/mac/src/pe/lim/lim_process_auth_frame.c b/core/mac/src/pe/lim/lim_process_auth_frame.c
index ce612bf..5eb8084 100644
--- a/core/mac/src/pe/lim/lim_process_auth_frame.c
+++ b/core/mac/src/pe/lim/lim_process_auth_frame.c
@@ -141,7 +141,8 @@
 			eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
 
 		lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 		return;
 	} else {
 		/* Create entry for this STA in pre-auth list */
@@ -188,7 +189,8 @@
 				eSIR_MAC_UNSPEC_FAILURE_STATUS;
 
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
 			return;
 		}
@@ -219,7 +221,8 @@
 				auth_node->challengeText,
 				SIR_MAC_AUTH_CHALLENGE_LENGTH);
 		lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 	}
 }
 
@@ -262,7 +265,8 @@
 			rx_auth_frm_body->authTransactionSeqNumber + 1;
 	auth_frame->authStatusCode = eSIR_MAC_SUCCESS_STATUS;
 	lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa,
-					LIM_NO_WEP_IN_FC, pe_session);
+					LIM_NO_WEP_IN_FC,
+					pe_session, false);
 }
 
 static void lim_process_auth_frame_type1(tpAniSirGlobal mac_ctx,
@@ -427,7 +431,8 @@
 			eSIR_MAC_UNSPEC_FAILURE_STATUS;
 
 		lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 		return;
 	}
 	/* No Pre-auth context exists for the STA. */
@@ -466,7 +471,8 @@
 			auth_frame->authStatusCode =
 				eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 	} else {
@@ -489,7 +495,8 @@
 
 		lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 				mac_hdr->sa,
-				LIM_NO_WEP_IN_FC, pe_session);
+				LIM_NO_WEP_IN_FC,
+				pe_session, false);
 		return;
 	}
 }
@@ -671,7 +678,7 @@
 				eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 					mac_hdr->sa, LIM_NO_WEP_IN_FC,
-					pe_session);
+					pe_session, false);
 			return;
 		}
 		if (rx_auth_frm_body->type != SIR_MAC_CHALLENGE_TEXT_EID) {
@@ -704,7 +711,8 @@
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx,
 					auth_frame, mac_hdr->sa,
-					LIM_NO_WEP_IN_FC, pe_session);
+					LIM_NO_WEP_IN_FC,
+					pe_session, false);
 			lim_restore_from_auth_state(mac_ctx,
 					eSIR_SME_INVALID_WEP_DEFAULT_KEY,
 					eSIR_MAC_UNSPEC_FAILURE_REASON,
@@ -737,7 +745,8 @@
 					pe_session->limMlmState));
 		lim_send_auth_mgmt_frame(mac_ctx,
 				(tpSirMacAuthFrameBody)encr_auth_frame,
-				mac_hdr->sa, LIM_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_WEP_IN_FC,
+				pe_session, false);
 
 		return;
 	}
@@ -768,7 +777,8 @@
 		auth_frame->authStatusCode =
 			eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
 		lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-			mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+			mac_hdr->sa, LIM_NO_WEP_IN_FC,
+			pe_session, false);
 		return;
 	}
 
@@ -794,7 +804,7 @@
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 					mac_hdr->sa,
 					LIM_NO_WEP_IN_FC,
-					pe_session);
+					pe_session, false);
 			return;
 		}
 
@@ -815,7 +825,8 @@
 			auth_frame->authStatusCode =
 				eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 
@@ -836,7 +847,8 @@
 				eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS;
 
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			/* Delete pre-auth context of STA */
 			lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
 			return;
@@ -881,7 +893,8 @@
 			auth_frame->authStatusCode =
 				eSIR_MAC_SUCCESS_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		} else {
 			lim_log(mac_ctx, LOGW,
@@ -901,7 +914,8 @@
 			auth_frame->authStatusCode =
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 	}
@@ -1147,7 +1161,8 @@
 				FL("rx Auth frm with wep bit set role=%d %pM"),
 				GET_LIM_SYSTEM_ROLE(pe_session), mac_hdr->sa);
 			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 
@@ -1192,7 +1207,8 @@
 			auth_frame.authStatusCode =
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 
@@ -1219,7 +1235,8 @@
 			auth_frame.authStatusCode =
 				eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 		/* Change the auth-response timeout */
@@ -1248,7 +1265,8 @@
 				eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
 
 			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 
@@ -1276,7 +1294,8 @@
 			auth_frame.authStatusCode =
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
 			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 
@@ -1299,7 +1318,8 @@
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
 
 			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
-				mac_hdr->sa, LIM_NO_WEP_IN_FC, pe_session);
+				mac_hdr->sa, LIM_NO_WEP_IN_FC,
+				pe_session, false);
 			return;
 		}
 		if ((sir_convert_auth_frame2_struct(mac_ctx, plainbody,
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 17073ce..e4b1649 100644
--- a/core/mac/src/pe/lim/lim_process_message_queue.c
+++ b/core/mac/src/pe/lim/lim_process_message_queue.c
@@ -1766,6 +1766,7 @@
 	case SIR_LIM_DISASSOC_ACK_TIMEOUT:
 	case SIR_LIM_DEAUTH_ACK_TIMEOUT:
 	case SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE:
+	case SIR_LIM_AUTH_RETRY_TIMEOUT:
 		/* These timeout messages are handled by MLM sub module */
 		lim_process_mlm_req_messages(mac_ctx, msg);
 		break;
diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
index a7be640..6d5b78a 100644
--- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
@@ -66,6 +66,7 @@
 static void lim_process_auth_rsp_timeout(tpAniSirGlobal, uint32_t);
 static void lim_process_assoc_failure_timeout(tpAniSirGlobal, uint32_t);
 static void lim_process_periodic_join_probe_req_timer(tpAniSirGlobal);
+static void lim_process_auth_retry_timer(tpAniSirGlobal);
 
 /**
  * lim_process_mlm_req_messages() - process mlm request messages
@@ -154,6 +155,9 @@
 	case SIR_LIM_DEAUTH_ACK_TIMEOUT:
 		lim_process_deauth_ack_timeout(mac_ctx);
 		break;
+	case SIR_LIM_AUTH_RETRY_TIMEOUT:
+		lim_process_auth_retry_timer(mac_ctx);
+		break;
 	case LIM_MLM_TSPEC_REQ:
 	default:
 		break;
@@ -1284,25 +1288,39 @@
 	lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_START_EVENT, session,
 			      eSIR_SUCCESS, auth_frame_body.authStatusCode);
 #endif
-
+	mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD;
 	lim_send_auth_mgmt_frame(mac_ctx,
 		&auth_frame_body, mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr,
-		LIM_NO_WEP_IN_FC, session);
+		LIM_NO_WEP_IN_FC, session, true);
 
 	/* assign appropriate session_id to the timer object */
 	mac_ctx->lim.limTimers.gLimAuthFailureTimer.sessionId = session_id;
 
+	/* assign appropriate sessionId to the timer object */
+	 mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer.sessionId =
+								  session_id;
+	 lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER);
 	/* Activate Auth failure timer */
 	MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE,
 			 session->peSessionId, eLIM_AUTH_FAIL_TIMER));
 	if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimAuthFailureTimer)
 	    != TX_SUCCESS) {
 		/* Could not start Auth failure timer. */
-		lim_log(mac_ctx, LOGP,
+		lim_log(mac_ctx, LOGE,
 			FL("could not start Auth failure timer"));
 		/* Cleanup as if auth timer expired */
 		lim_process_auth_failure_timeout(mac_ctx);
+	} else {
+		MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE,
+			   session->peSessionId, eLIM_AUTH_RETRY_TIMER));
+		/* Activate Auth Retry timer */
+		if (tx_timer_activate
+		    (&mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer)
+							      != TX_SUCCESS)
+			lim_log(mac_ctx, LOGE,
+			    FL("could not activate Auth Retry timer"));
 	}
+
 	return;
 end:
 	qdf_mem_copy((uint8_t *) &mlm_auth_cnf.peerMacAddr,
@@ -2603,6 +2621,68 @@
 }
 
 /**
+ * lim_process_auth_retry_timer()- function to Retry Auth
+ * @mac_ctx:pointer to global mac
+ *
+ * Return: void
+ */
+
+static void lim_process_auth_retry_timer(tpAniSirGlobal mac_ctx)
+{
+	tpPESession  session_entry;
+
+	lim_log(mac_ctx, LOG1, FL("ENTER"));
+
+	session_entry =
+	  pe_find_session_by_session_id(mac_ctx,
+	  mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer.sessionId);
+	if (NULL == session_entry) {
+		lim_log(mac_ctx, LOGE,
+		  FL("session does not exist for given SessionId : %d"),
+		  mac_ctx->lim.limTimers.
+			g_lim_periodic_auth_retry_timer.sessionId);
+		return;
+	}
+
+	if (tx_timer_running(&mac_ctx->lim.limTimers.gLimAuthFailureTimer) &&
+	     (session_entry->limMlmState == eLIM_MLM_WT_AUTH_FRAME2_STATE) &&
+	     (LIM_AUTH_ACK_RCD_SUCCESS != mac_ctx->auth_ack_status)) {
+		tSirMacAuthFrameBody    auth_frame;
+
+		/*
+		 * Send the auth retry only in case we have received ack failure
+		 * else just restart the retry timer.
+		 */
+		if (LIM_AUTH_ACK_RCD_FAILURE == mac_ctx->auth_ack_status) {
+			/* Prepare & send Authentication frame */
+			auth_frame.authAlgoNumber =
+			    (uint8_t) mac_ctx->lim.gpLimMlmAuthReq->authType;
+			auth_frame.authTransactionSeqNumber =
+						SIR_MAC_AUTH_FRAME_1;
+			auth_frame.authStatusCode = 0;
+			lim_log(mac_ctx, LOGW, FL("Retry Auth "));
+			mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD;
+			lim_send_auth_mgmt_frame(mac_ctx,
+				&auth_frame,
+				mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr,
+				LIM_NO_WEP_IN_FC, session_entry, true);
+		}
+
+		lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER);
+
+		/* Activate Auth Retry timer */
+		if (tx_timer_activate
+		     (&mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer)
+			 != TX_SUCCESS) {
+			lim_log(mac_ctx, LOGE,
+			  FL("could not activate Auth Retry failure timer"));
+			return;
+		}
+	}
+	return;
+} /*** lim_process_auth_retry_timer() ***/
+
+/**
  * lim_process_auth_failure_timeout() - This function is called to process Min
  * Channel Timeout during channel scan.
  *
diff --git a/core/mac/src/pe/lim/lim_security_utils.c b/core/mac/src/pe/lim/lim_security_utils.c
index 77edf9f..a76eea6 100644
--- a/core/mac/src/pe/lim/lim_security_utils.c
+++ b/core/mac/src/pe/lim/lim_security_utils.c
@@ -500,6 +500,15 @@
 		       (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId,
 		       sessionEntry->limMlmState));
 
+	/*
+	 * Set the auth_ack_status status flag as success as
+	 * host have received the auth rsp and no longer auth
+	 * retry is needed also cancel the auth rety timer
+	 */
+	pMac->auth_ack_status = LIM_AUTH_ACK_RCD_SUCCESS;
+	/* 'Change' timer for future activations */
+	lim_deactivate_and_change_timer(pMac, eLIM_AUTH_RETRY_TIMER);
+
 	/* 'Change' timer for future activations */
 	lim_deactivate_and_change_timer(pMac, eLIM_AUTH_FAIL_TIMER);
 
diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c
index e36f2a6..0b6d8ba 100644
--- a/core/mac/src/pe/lim/lim_send_management_frames.c
+++ b/core/mac/src/pe/lim/lim_send_management_frames.c
@@ -2690,6 +2690,30 @@
 } /* lim_send_reassoc_req_mgmt_frame */
 
 /**
+ * lim_auth_tx_complete_cnf()- Confirmation for auth sent over the air
+ *
+ * @mac_ctx: pointer to global mac
+ * @tx_complete : Sent status
+ *
+ * Return: This returns QDF_STATUS
+ */
+
+QDF_STATUS lim_auth_tx_complete_cnf(tpAniSirGlobal mac_ctx,
+					uint32_t tx_complete)
+{
+	lim_log(mac_ctx, LOG1,
+		 FL("tx_complete= %d"), tx_complete);
+	if (tx_complete) {
+		mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_SUCCESS;
+		/* 'Change' timer for future activations */
+		lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER);
+	} else {
+		mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_FAILURE;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
  * lim_send_auth_mgmt_frame() - Send an Authentication frame
  *
  * @mac_ctx: Pointer to Global MAC structure
@@ -2708,7 +2732,8 @@
 lim_send_auth_mgmt_frame(tpAniSirGlobal mac_ctx,
 			 tpSirMacAuthFrameBody auth_frame,
 			 tSirMacAddr peer_addr,
-			 uint8_t wep_bit, tpPESession session)
+			 uint8_t wep_bit,
+			 tpPESession session, bool wait_for_ack)
 {
 	uint8_t *frame, *body;
 	uint32_t frame_len = 0, body_len = 0;
@@ -2727,10 +2752,12 @@
 	sme_sessionid = session->smeSessionId;
 
 	lim_log(mac_ctx, LOG1,
-		FL("Sending Auth seq# %d status %d (%d) to " MAC_ADDRESS_STR),
+		FL("Sending Auth seq# %d status %d (%d) wait_for_ack %d to "
+		MAC_ADDRESS_STR),
 		auth_frame->authTransactionSeqNumber,
 		auth_frame->authStatusCode,
 		(auth_frame->authStatusCode == eSIR_MAC_SUCCESS_STATUS),
+		wait_for_ack,
 		MAC_ADDR_ARRAY(peer_addr));
 
 	switch (auth_frame->authTransactionSeqNumber) {
@@ -2959,18 +2986,37 @@
 
 	MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT,
 			 session->peSessionId, mac_hdr->fc.subType));
-	/* Queue Authentication frame in high priority WQ */
-	qdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) frame_len,
-				TXRX_FRM_802_11_MGMT,
-				ANI_TXDIR_TODS, 7, lim_tx_complete,
-				frame, tx_flag, sme_sessionid, 0);
-	MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE,
-			 session->peSessionId, qdf_status));
-	if (!QDF_IS_STATUS_SUCCESS(qdf_status))
-		lim_log(mac_ctx, LOGE,
-			FL("*** Could not send Auth frame, retCode=%X ***"),
-			qdf_status);
 
+	if (wait_for_ack) {
+		mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD;
+		qdf_status = wma_tx_frameWithTxComplete(mac_ctx, packet,
+					 (uint16_t)frame_len,
+					 TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS,
+					 7, lim_tx_complete, frame,
+					 lim_auth_tx_complete_cnf,
+					 tx_flag, sme_sessionid, false, 0);
+		MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE,
+			session->peSessionId, qdf_status));
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+			lim_log(mac_ctx, LOGE,
+			  FL("*** Could not send Auth frame, retCode=%X ***"),
+			  qdf_status);
+			mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_FAILURE;
+		/* Pkt will be freed up by the callback */
+		}
+	} else {
+		/* Queue Authentication frame in high priority WQ */
+		qdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) frame_len,
+					TXRX_FRM_802_11_MGMT,
+					ANI_TXDIR_TODS, 7, lim_tx_complete,
+					frame, tx_flag, sme_sessionid, 0);
+		MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE,
+				 session->peSessionId, qdf_status));
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
+			lim_log(mac_ctx, LOGE,
+			  FL("*** Could not send Auth frame, retCode=%X ***"),
+			  qdf_status);
+	}
 	return;
 }
 
diff --git a/core/mac/src/pe/lim/lim_timer_utils.c b/core/mac/src/pe/lim/lim_timer_utils.c
index 14222a6..bcf3c68 100644
--- a/core/mac/src/pe/lim/lim_timer_utils.c
+++ b/core/mac/src/pe/lim/lim_timer_utils.c
@@ -50,6 +50,9 @@
 #define LIM_KEEPALIVE_TIMER_MS                   3000
 /* Lim JoinProbeRequest Retry  timer default (200)ms */
 #define LIM_JOIN_PROBE_REQ_TIMER_MS              200
+/* Lim Periodic Auth Retry timer default 60 ms */
+#define LIM_AUTH_RETRY_TIMER_MS   60
+
 
 /* This timer is a periodic timer which expires at every 1 sec to
    convert  ACTIVE DFS channel to DFS channels */
@@ -122,6 +125,18 @@
 		return false;
 	}
 
+	/* Send Auth frame every 60 ms */
+	if ((tx_timer_create(pMac,
+		&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer,
+		"Periodic AUTH Timer",
+		lim_timer_handler, SIR_LIM_AUTH_RETRY_TIMEOUT,
+		SYS_MS_TO_TICKS(LIM_AUTH_RETRY_TIMER_MS), 0,
+		TX_NO_ACTIVATE)) != TX_SUCCESS) {
+		lim_log(pMac, LOGP,
+			FL("could not create Periodic AUTH Timer"));
+		return false;
+	}
+
 	if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT,
 			     &cfgValue) != eSIR_SUCCESS)
 		lim_log(pMac, LOGP,
@@ -429,6 +444,7 @@
 	tx_timer_delete(&pMac->lim.limTimers.gLimAssocFailureTimer);
 	tx_timer_delete(&pMac->lim.limTimers.gLimJoinFailureTimer);
 	tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer);
+	tx_timer_delete(&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer);
 	tx_timer_delete(&pMac->lim.limTimers.gLimQuietBssTimer);
 	tx_timer_delete(&pMac->lim.limTimers.gLimQuietTimer);
 	tx_timer_delete(&pMac->lim.limTimers.gLimChannelSwitchTimer);
@@ -668,6 +684,7 @@
 void lim_deactivate_and_change_timer(tpAniSirGlobal pMac, uint32_t timerId)
 {
 	uint32_t val = 0;
+	tpPESession  session_entry;
 
 	MTRACE(mac_trace
 		       (pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, timerId));
@@ -799,6 +816,37 @@
 
 		break;
 
+	case eLIM_AUTH_RETRY_TIMER:
+
+		if (tx_timer_deactivate
+			  (&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer)
+							 != TX_SUCCESS) {
+			/* Could not deactivate Auth Retry Timer. */
+			lim_log(pMac, LOGE,
+				   FL("Unable to deactivate Auth Retry timer"));
+		}
+		session_entry = pe_find_session_by_session_id(pMac,
+			pMac->lim.limTimers.
+				g_lim_periodic_auth_retry_timer.sessionId);
+		if (NULL == session_entry) {
+			lim_log(pMac, LOGE,
+			  FL("session does not exist for given SessionId : %d"),
+			pMac->lim.limTimers.
+				g_lim_periodic_auth_retry_timer.sessionId);
+			break;
+		}
+		/* 3/5 of the beacon interval */
+		val = (session_entry->beaconParams.beaconInterval * 3) / 5;
+		val = SYS_MS_TO_TICKS(val);
+		if (tx_timer_change
+			 (&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer,
+							val, 0) != TX_SUCCESS) {
+			/* Could not change Auth Retry timer. */
+			lim_log(pMac, LOGE,
+			  FL("Unable to change Auth Retry timer"));
+		}
+		break;
+
 	case eLIM_ASSOC_FAIL_TIMER:
 		if (tx_timer_deactivate
 			    (&pMac->lim.limTimers.gLimAssocFailureTimer) !=
diff --git a/core/mac/src/pe/lim/lim_timer_utils.h b/core/mac/src/pe/lim/lim_timer_utils.h
index 1f1af1d..50f3ef4 100644
--- a/core/mac/src/pe/lim/lim_timer_utils.h
+++ b/core/mac/src/pe/lim/lim_timer_utils.h
@@ -67,7 +67,8 @@
 	eLIM_DEAUTH_ACK_TIMER,
 	eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER,
 	eLIM_INSERT_SINGLESHOT_NOA_TIMER,
-	eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE
+	eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE,
+	eLIM_AUTH_RETRY_TIMER
 };
 
 #define LIM_DISASSOC_DEAUTH_ACK_TIMEOUT         500
diff --git a/core/mac/src/pe/lim/lim_trace.c b/core/mac/src/pe/lim/lim_trace.c
index d287ca3..89d9d02 100644
--- a/core/mac/src/pe/lim/lim_trace.c
+++ b/core/mac/src/pe/lim/lim_trace.c
@@ -79,6 +79,7 @@
 		CASE_RETURN_STRING(eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER);
 		CASE_RETURN_STRING(eLIM_INSERT_SINGLESHOT_NOA_TIMER);
 		CASE_RETURN_STRING(eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE);
+		CASE_RETURN_STRING(eLIM_AUTH_RETRY_TIMER);
 	default:
 		return "UNKNOWN";
 		break;
diff --git a/core/mac/src/pe/lim/lim_types.h b/core/mac/src/pe/lim/lim_types.h
index c6067ac..616147c 100644
--- a/core/mac/src/pe/lim/lim_types.h
+++ b/core/mac/src/pe/lim/lim_types.h
@@ -456,7 +456,7 @@
 void lim_send_probe_rsp_mgmt_frame(tpAniSirGlobal, tSirMacAddr, tpAniSSID, short,
 				   uint8_t, tpPESession, uint8_t);
 void lim_send_auth_mgmt_frame(tpAniSirGlobal, tSirMacAuthFrameBody *, tSirMacAddr,
-			      uint8_t, tpPESession);
+			      uint8_t, tpPESession, bool wait_for_ack);
 void lim_send_assoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmAssocReq *, tpPESession);
 void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmReassocReq *,
 				     tpPESession);
diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c
index 16eabf4..23af25a 100644
--- a/core/mac/src/pe/lim/lim_utils.c
+++ b/core/mac/src/pe/lim/lim_utils.c
@@ -625,6 +625,11 @@
 		tx_timer_deactivate(&lim_timer->gLimPeriodicJoinProbeReqTimer);
 		tx_timer_delete(&lim_timer->gLimPeriodicJoinProbeReqTimer);
 
+		/* Deactivate and delete Auth Retry timer. */
+		tx_timer_deactivate
+				(&lim_timer->g_lim_periodic_auth_retry_timer);
+		tx_timer_delete(&lim_timer->g_lim_periodic_auth_retry_timer);
+
 		/* Deactivate and delete Association failure timer. */
 		tx_timer_deactivate(&lim_timer->gLimAssocFailureTimer);
 		tx_timer_delete(&lim_timer->gLimAssocFailureTimer);
diff --git a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c
index b249ed6..e9adfc8 100644
--- a/core/mac/src/sys/legacy/src/utils/src/mac_trace.c
+++ b/core/mac/src/sys/legacy/src/utils/src/mac_trace.c
@@ -654,6 +654,7 @@
 		CASE_RETURN_STRING(SIR_LIM_DISASSOC_ACK_TIMEOUT);
 		CASE_RETURN_STRING(SIR_LIM_DEAUTH_ACK_TIMEOUT);
 		CASE_RETURN_STRING(SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT);
+		CASE_RETURN_STRING(SIR_LIM_AUTH_RETRY_TIMEOUT);
 		CASE_RETURN_STRING(SIR_LIM_MSG_TYPES_END);
 
 	default: