[WCNCR00169658] security: Add KRAC fw support.

[Description]
Add replay detection in suspend mode support
with PN sync between drv and fw

Change-Id: I58845a047708f1116a564eb4556a0a439fb44fc7
Signed-off-by: wayne.guo <wayne.guo@mediatek.com>
CR-Id: WCNCR00169658
Feature: security
Reviewed-on: http://gerrit.mediatek.inc:8080/1253739
CheckPatch: Check Patch <srv_checkpatch@mediatek.com>
Reviewed-by: Deren Wu <deren.wu@mediatek.com>
Build: srv_neptune_adm <srv_neptune_adm@mediatek.com>
diff --git a/common/wlan_lib.c b/common/wlan_lib.c
index da0926a..81cd8a2 100644
--- a/common/wlan_lib.c
+++ b/common/wlan_lib.c
@@ -6890,6 +6890,9 @@
 	/* ucEapolOffload: only offload eapol rekey as suspen/resume case. */
 	prWifiVar->ucEapolOffload = FEATURE_DISABLED;
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	prWifiVar->ucRpyDetectOffload = (UINT_8) wlanCfgGetUint32(prAdapter, "rpydetectoffload", FEATURE_ENABLED);
+#endif
 
 #if CFG_WOW_SUPPORT
 	prAdapter->rWowCtrl.fgWowEnable = (UINT_8) wlanCfgGetUint32(prAdapter, "WowEnable", FEATURE_ENABLED);
@@ -9500,25 +9503,50 @@
 * @return VOID
 */
 /*----------------------------------------------------------------------------*/
-int wlanSuspendRekeyOffload(P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRekeyDisable)
+int wlanSuspendRekeyOffload(P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRekeyMode)
 {
 	UINT_32 u4BufLen;
 	P_PARAM_GTK_REKEY_DATA prGtkData;
 	WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
 	INT_32 i4Rslt = -EINVAL;
+#if CFG_SUPPORT_REPLAY_DETECTION
+	P_BSS_INFO_T prBssInfo = NULL;
+	struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	UINT_8 ucCurKeyId;
+	UINT_8 ucRpyOffload;
+#endif
 
 	ASSERT(prGlueInfo);
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	ucRpyOffload = prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload;
+
+	if ((ucRekeyMode == GTK_REKEY_CMD_MODE_SET_BCMC_PN) &&
+		(ucRpyOffload == FALSE)) {
+		DBGLOG(RSN, INFO, "Set PN to fw, but feature off. no action\n");
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if ((ucRekeyMode == GTK_REKEY_CMD_MODE_GET_BCMC_PN) &&
+		(ucRpyOffload == FALSE)) {
+		DBGLOG(RSN, INFO, "Get PN from fw, but feature off. no action\n");
+		return WLAN_STATUS_SUCCESS;
+	}
+#endif
+
 	prGtkData =
 		(P_PARAM_GTK_REKEY_DATA) kalMemAlloc(sizeof(PARAM_GTK_REKEY_DATA), VIR_MEM_TYPE);
 
 	if (!prGtkData)
 		return WLAN_STATUS_SUCCESS;
 
-	/* if enable => enable FW rekey offload. if disable, let rekey back to supplicant */
-	prGtkData->ucRekeyDisable = ucRekeyDisable;
+	kalMemZero(prGtkData, sizeof(PARAM_GTK_REKEY_DATA));
 
-	if (!ucRekeyDisable) {
+	/* if enable => enable FW rekey offload. if disable, let rekey back to supplicant */
+	prGtkData->ucRekeyMode = ucRekeyMode;
+	DBGLOG(RSN, INFO, "GTK Rekey ucRekeyMode = %d\n", ucRekeyMode);
+
+	if (ucRekeyMode == GTK_REKEY_CMD_MODE_OFFLOAD_ON) {
 		DBGLOG(RSN, INFO, "kek\n");
 		DBGLOG_MEM8(RSN, ERROR, (PUINT_8)prGlueInfo->rWpaInfo.aucKek, NL80211_KEK_LEN);
 		DBGLOG(RSN, INFO, "kck\n");
@@ -9557,11 +9585,43 @@
 		prGtkData->u4KeyMgmt = prGlueInfo->rWpaInfo.u4KeyMgmt;
 		prGtkData->u4MgmtGroupCipher = 0;
 
-	} else {
+	}
+
+	if (ucRekeyMode == GTK_REKEY_CMD_MODE_OFLOAD_OFF) {
 		/* inform FW disable EAPOL offload */
 		DBGLOG(RSN, INFO, "Disable EAPOL offload\n");
 	}
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	if (ucRekeyMode == GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON)
+		DBGLOG(RSN, INFO, "ucRekeyMode(rpy rekey offload on): %d\n", ucRekeyMode);
+
+	if (ucRekeyMode == GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF)
+		DBGLOG(RSN, INFO, "ucRekeyMode(rpy rekey offload off): %d\n", ucRekeyMode);
+
+	if ((ucRekeyMode == GTK_REKEY_CMD_MODE_SET_BCMC_PN) &&
+		(ucRpyOffload == TRUE)) {
+		prGtkData->ucBssIndex = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter,
+			prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex);
+		prDetRplyInfo = &prBssInfo->rDetRplyInfo;
+		ucCurKeyId = prDetRplyInfo->ucCurKeyId;
+		prGtkData->ucCurKeyId = ucCurKeyId;
+		DBGLOG_MEM8(RSN, INFO, (PUINT_8)prGtkData->aucReplayCtr, NL80211_REPLAY_CTR_LEN);
+		kalMemCopy(prGtkData->aucReplayCtr,
+			prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN,
+			NL80211_REPLAY_CTR_LEN);
+
+		/* set bc/mc PN zero before suspend */
+		kalMemZero(prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, NL80211_REPLAY_CTR_LEN);
+	}
+
+	if ((ucRekeyMode == GTK_REKEY_CMD_MODE_GET_BCMC_PN) &&
+		(ucRpyOffload == TRUE)) {
+		prGtkData->ucBssIndex = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex;
+	}
+#endif
+
 	rStatus = kalIoctl(prGlueInfo,
 				wlanoidSetGtkRekeyData,
 				prGtkData, sizeof(PARAM_GTK_REKEY_DATA), FALSE, FALSE, TRUE, &u4BufLen);
@@ -9592,13 +9652,71 @@
 	UINT_8 idx;
 	PARAM_POWER_MODE ePwrMode;
 	P_BSS_INFO_T prBssInfo;
+	UINT_8 ucKekZeroCnt = 0;
+	UINT_8 ucKckZeroCnt = 0;
+	UINT_8 ucGtkOffload = TRUE;
+	UINT_8 i = 0;
+#if CFG_SUPPORT_REPLAY_DETECTION
+	struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	UINT_8 ucIdx = 0;
+	UINT_8 ucKeyIdx = 0;
+	UINT_8 ucRpyOffload = 0;
+#endif
 
 	if (prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap)
 		wlanKeepFullPwr(prGlueInfo->prAdapter, FALSE);
 
 	/* if wifi.cfg EAPOL offload is 0, we set rekey offload when enter wow */
 	if (!prGlueInfo->prAdapter->rWifiVar.ucEapolOffload) {
-		wlanSuspendRekeyOffload(prGlueInfo, FALSE);
+
+		/*
+		 * check if KCK, KEK not sync from supplicant.
+		 * if no these info updated from supplicant,
+		 *disable GTK offload feature.
+		 */
+		for (i = 0; i < NL80211_KEK_LEN; i++) {
+			if (prGlueInfo->rWpaInfo.aucKek[i] == 0x00)
+				ucKekZeroCnt++;
+		}
+
+		for (i = 0; i < NL80211_KCK_LEN; i++) {
+			if (prGlueInfo->rWpaInfo.aucKck[i] == 0x00)
+				ucKckZeroCnt++;
+		}
+
+		if ((ucKekZeroCnt == NL80211_KCK_LEN) ||
+				(ucKckZeroCnt == NL80211_KCK_LEN)) {
+			DBGLOG(RSN, INFO, "no rekey offload, due to no KCK/KEK from cfg80211\n");
+
+			prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload = FEATURE_DISABLED;
+
+			ucGtkOffload = FALSE;
+			/* set bc/mc replay detection off to fw */
+			wlanSuspendRekeyOffload(prGlueInfo,
+				GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF);
+		}
+
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+		ucRpyOffload = prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload;
+
+		if (ucRpyOffload && ucGtkOffload)
+			wlanSuspendRekeyOffload(prGlueInfo, GTK_REKEY_CMD_MODE_SET_BCMC_PN);
+#endif
+		if (ucGtkOffload)
+			wlanSuspendRekeyOffload(prGlueInfo, GTK_REKEY_CMD_MODE_OFFLOAD_ON);
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter,
+			prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex);
+		prDetRplyInfo = &prBssInfo->rDetRplyInfo;
+
+		for (ucKeyIdx = 0; ucKeyIdx < 4; ucKeyIdx++) {
+			for (ucIdx = 0; ucIdx < 6; ucIdx++)
+				prDetRplyInfo->arReplayPNInfo[ucKeyIdx].auPN[ucIdx] = 0x0;
+		}
+#endif
 		DBGLOG(HAL, STATE, "Suspend rekey offload\n");
 	}
 
@@ -9645,12 +9763,73 @@
 VOID wlanResumePmHandle(P_GLUE_INFO_T prGlueInfo)
 {
 	PARAM_POWER_MODE ePwrMode = Param_PowerModeCAM;
+	UINT_8 ucKekZeroCnt = 0;
+	UINT_8 ucKckZeroCnt = 0;
+	UINT_8 ucGtkOffload = TRUE;
+	UINT_8 i = 0;
+#if CFG_SUPPORT_REPLAY_DETECTION
+	struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	P_BSS_INFO_T prBssInfo = NULL;
+	UINT_8 ucIdx = 0;
+	UINT_8 ucKeyIdx = 0;
+	UINT_8 ucRpyOffload = 0;
+#endif
 
 	/* if wifi.cfg EAPOL offload is disble, we disable FW offload when leave wow */
 	if (!prGlueInfo->prAdapter->rWifiVar.ucEapolOffload) {
-		wlanSuspendRekeyOffload(prGlueInfo, TRUE);
+
+		/*
+		 * check if KCK, KEK not sync from supplicant.
+		 * if no these info updated from supplicant,
+		 *disable GTK offload feature.
+		 */
+		for (i = 0; i < NL80211_KEK_LEN; i++) {
+			if (prGlueInfo->rWpaInfo.aucKek[i] == 0x00)
+				ucKekZeroCnt++;
+		}
+
+		for (i = 0; i < NL80211_KCK_LEN; i++) {
+			if (prGlueInfo->rWpaInfo.aucKck[i] == 0x00)
+				ucKckZeroCnt++;
+		}
+
+		if ((ucKekZeroCnt == NL80211_KCK_LEN) ||
+				(ucKckZeroCnt == NL80211_KCK_LEN)) {
+
+			DBGLOG(RSN, INFO, "no rekey offload, due to no KCK/KEK from cfg80211\n");
+
+			prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload = FEATURE_DISABLED;
+
+			ucGtkOffload = FALSE;
+			/* set bc/mc replay detection off to fw */
+			wlanSuspendRekeyOffload(prGlueInfo,
+				GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF);
+
+		}
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter,
+			prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex);
+		prDetRplyInfo = &prBssInfo->rDetRplyInfo;
+
+		/* as resume performed, reset BC/MC KeyRSC, to prevent incorrect replay detection. */
+		for (ucKeyIdx = 0; ucKeyIdx < 4; ucKeyIdx++) {
+			for (ucIdx = 0; ucIdx < NL80211_KEYRSC_LEN; ucIdx++)
+				prDetRplyInfo->arReplayPNInfo[ucKeyIdx].auPN[ucIdx] = 0x0;
+		}
+
+		ucRpyOffload = prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload;
+
+		/* sync BC/MC PN */
+		if (ucRpyOffload && ucGtkOffload)
+			wlanSuspendRekeyOffload(prGlueInfo, GTK_REKEY_CMD_MODE_GET_BCMC_PN);
+#endif
+
+		if (ucGtkOffload) {
+			wlanSuspendRekeyOffload(prGlueInfo, GTK_REKEY_CMD_MODE_OFLOAD_OFF);
 		DBGLOG(HAL, STATE, "Resume rekey offload disable\n");
 	}
+	}
 
 	if (prGlueInfo->prAdapter->rWifiVar.ucWow && prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) {
 		if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) {
diff --git a/include/mgmt/rsn.h b/include/mgmt/rsn.h
index be94150..3f08c36 100644
--- a/include/mgmt/rsn.h
+++ b/include/mgmt/rsn.h
@@ -132,6 +132,15 @@
 #define RSN_AUTH_MFP_REQUIRED   2	/* MFP required */
 #endif
 
+
+#define GTK_REKEY_CMD_MODE_OFFLOAD_ON		0
+#define GTK_REKEY_CMD_MODE_OFLOAD_OFF		1
+#define GTK_REKEY_CMD_MODE_SET_BCMC_PN		2
+#define GTK_REKEY_CMD_MODE_GET_BCMC_PN		3
+#define GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON	4
+#define GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF	5
+
+
 /*******************************************************************************
 *                             D A T A   T Y P E S
 ********************************************************************************
diff --git a/include/nic/adapter.h b/include/nic/adapter.h
index 2a55cc3..4309ce8 100644
--- a/include/nic/adapter.h
+++ b/include/nic/adapter.h
@@ -821,6 +821,10 @@
 	UINT_8 ucListenDtimInterval; /* adjust the listen interval by dtim interval */
 	UINT_8 ucEapolOffload; /* eapol offload when active mode / wow mode */
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	UINT_8 ucRpyDetectOffload; /* eapol offload when active mode / wow mode */
+#endif
+
 	UINT_8 u4SwTestMode;
 	UINT_8	ucCtrlFlagAssertPath;
 	UINT_8	ucCtrlFlagDebugLevel;
diff --git a/include/nic/que_mgt.h b/include/nic/que_mgt.h
index d04eeef..ae134fc 100644
--- a/include/nic/que_mgt.h
+++ b/include/nic/que_mgt.h
@@ -955,6 +955,7 @@
 
 #if CFG_SUPPORT_REPLAY_DETECTION
 BOOLEAN qmHandleRxReplay(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb);
+BOOLEAN qmRxDetectReplay(PUINT_8 pucPNS, PUINT_8 pucPNT);
 #endif
 
 /*******************************************************************************
diff --git a/include/nic_cmd_event.h b/include/nic_cmd_event.h
index 27a4f86..7b408ce 100644
--- a/include/nic_cmd_event.h
+++ b/include/nic_cmd_event.h
@@ -611,6 +611,7 @@
 	EVENT_ID_BATCH_RESULT = 0x2b,	/* 0x2b (Query) */
 
 	EVENT_ID_CSI_DATA = 0x3c, /* 0x3c (Query) */
+	EVENT_ID_GET_GTK_REKEY_DATA = 0x3d, /* 0x3d (Query) */
 
 	EVENT_ID_UART_ACK = 0x40,	/* 0x40 (Unsolicited) */
 	EVENT_ID_UART_NAK,	/* 0x41 (Unsolicited) */
@@ -3334,6 +3335,8 @@
 #if CFG_SUPPORT_REPLAY_DETECTION
 VOID nicCmdEventSetAddKey(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf);
 VOID nicOidCmdTimeoutSetAddKey(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo);
+
+VOID nicEventGetGtkDataSync(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent);
 #endif
 
 /*******************************************************************************
diff --git a/include/wlan_lib.h b/include/wlan_lib.h
index c660539..9d4bf5f 100644
--- a/include/wlan_lib.h
+++ b/include/wlan_lib.h
@@ -1376,7 +1376,7 @@
 WLAN_STATUS wlanUpdateExtInfo(IN P_ADAPTER_T prAdapter);
 #endif
 
-int wlanSuspendRekeyOffload(P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRekeyDisable);
+int wlanSuspendRekeyOffload(P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRekeyMode);
 VOID wlanSuspendPmHandle(P_GLUE_INFO_T prGlueInfo);
 VOID wlanResumePmHandle(P_GLUE_INFO_T prGlueInfo);
 
diff --git a/include/wlan_oid.h b/include/wlan_oid.h
index f4ff862..08f2cce 100644
--- a/include/wlan_oid.h
+++ b/include/wlan_oid.h
@@ -571,14 +571,16 @@
 #define NL80211_KCK_LEN                 16
 #define NL80211_KEK_LEN                 16
 #define NL80211_REPLAY_CTR_LEN          8
+#define NL80211_KEYRSC_LEN		8
 
 typedef struct _PARAM_GTK_REKEY_DATA {
 	UINT_8 aucKek[NL80211_KEK_LEN];
 	UINT_8 aucKck[NL80211_KCK_LEN];
 	UINT_8 aucReplayCtr[NL80211_REPLAY_CTR_LEN];
 	UINT_8 ucBssIndex;
-	UINT_8 ucRekeyDisable; /* disable rekey offload. 0: enable */
-	UINT_8 ucRsv[2];
+	UINT_8 ucRekeyMode;
+	UINT_8 ucCurKeyId;
+	UINT_8 ucRsv;
 	UINT_32 u4Proto;
 	UINT_32 u4PairwiseCipher;
 	UINT_32 u4GroupCipher;
diff --git a/nic/nic_cmd_event.c b/nic/nic_cmd_event.c
index 2ec04f5..a99f9e7 100644
--- a/nic/nic_cmd_event.c
+++ b/nic/nic_cmd_event.c
@@ -3486,7 +3486,7 @@
 			DBGLOG(NIC, TRACE, "Keyid is %d, ucKeyType is %d\n",
 				prCmdKey->ucKeyId, prCmdKey->ucKeyType);
 		}
-}
+	}
 }
 
 VOID nicOidCmdTimeoutSetAddKey(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo)
@@ -3497,4 +3497,39 @@
 	if (prCmdInfo->fgIsOid)
 		kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE);
 }
+
+
+VOID nicEventGetGtkDataSync(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
+{
+	P_PARAM_GTK_REKEY_DATA prGtkData = NULL;
+	struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	P_BSS_INFO_T prBssInfo = NULL;
+	UINT_8 ucCurKeyId;
+
+	prGtkData = (P_PARAM_GTK_REKEY_DATA) (prEvent->aucBuffer);
+
+	prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter,
+		prAdapter->prAisBssInfo->ucBssIndex);
+
+	prDetRplyInfo = &prBssInfo->rDetRplyInfo;
+	prDetRplyInfo->ucCurKeyId = prGtkData->ucCurKeyId;
+	ucCurKeyId = prDetRplyInfo->ucCurKeyId;
+
+	kalMemZero(prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, NL80211_REPLAY_CTR_LEN);
+
+#if 0
+	/* if Drv alread rx a new PN value large than fw PN, then skip PN update */
+	if (qmRxDetectReplay(prGtkData->aucReplayCtr,
+		prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN))
+		return;
+#endif
+
+	kalMemCopy(prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN,
+		prGtkData->aucReplayCtr, 6);
+
+	DBGLOG(RSN, INFO, "Get BC/MC PN update from fw.\n");
+
+	DBGLOG_MEM8(RSN, INFO, (PUINT_8)prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, NL80211_REPLAY_CTR_LEN);
+}
+
 #endif
diff --git a/nic/nic_rx.c b/nic/nic_rx.c
index 8295378..dc1a940 100644
--- a/nic/nic_rx.c
+++ b/nic/nic_rx.c
@@ -189,6 +189,9 @@
 #endif
 	{EVENT_ID_CSI_DATA,                 nicEventCSIData},
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	{EVENT_ID_GET_GTK_REKEY_DATA,       nicEventGetGtkDataSync},
+#endif
 };
 
 /*******************************************************************************
diff --git a/nic/que_mgt.c b/nic/que_mgt.c
index ba8460c..2eeb30a 100644
--- a/nic/que_mgt.c
+++ b/nic/que_mgt.c
@@ -6014,6 +6014,8 @@
 	P_HW_MAC_RX_DESC_T prRxStatus = NULL;
 	UINT_8 ucBssIndex = 0;
 	P_BSS_INFO_T prBssInfo = NULL;
+	UINT_8 ucCheckZeroPN;
+	UINT_8 i;
 
 	if (!prAdapter)
 		return TRUE;
@@ -6083,12 +6085,32 @@
 			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[3],
 			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[4],
 			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[5]);
+
+	if (prDetRplyInfo->fgKeyRscFresh == TRUE) {
+
+		/* PN non-fresh setting */
+		prDetRplyInfo->fgKeyRscFresh = FALSE;
+		ucCheckZeroPN = 0;
+
+		for (i = 0; i < 8; i++) {
+			if (prSwRfb->prRxStatusGroup1->aucPN[i] == 0x0)
+				ucCheckZeroPN++;
+		}
+
+		/* for AP start PN from 0, bypass PN check and update */
+		if (ucCheckZeroPN == 8) {
+			DBGLOG(QM, WARN, "Fresh BC_PN with AP PN=0\n");
+			return FALSE;
+		}
+	}
+
 	if (qmRxDetectReplay(pucPN, prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN)) {
 		DBGLOG(QM, WARN, "Drop BC replay packet!\n");
 		return TRUE;
 	}
 
 	HAL_RX_STATUS_GET_PN(prSwRfb->prRxStatusGroup1, prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN);
+
 	return FALSE;
 }
 
diff --git a/os/linux/gl_cfg80211.c b/os/linux/gl_cfg80211.c
index 9f0d6a4..32d12ce 100644
--- a/os/linux/gl_cfg80211.c
+++ b/os/linux/gl_cfg80211.c
@@ -259,6 +259,12 @@
 		rKey.u4KeyIndex |= BIT(31);
 		rKey.u4KeyIndex |= BIT(30);
 		COPY_MAC_ADDR(rKey.arBSSID, mac_addr);
+
+		/* reset KCK, KEK, EAPOL Replay counter */
+		kalMemZero(prGlueInfo->rWpaInfo.aucKek, NL80211_KEK_LEN);
+		kalMemZero(prGlueInfo->rWpaInfo.aucKck, NL80211_KCK_LEN);
+		kalMemZero(prGlueInfo->rWpaInfo.aucReplayCtr, NL80211_REPLAY_CTR_LEN);
+
 	} else {		/* Group key */
 		COPY_MAC_ADDR(rKey.arBSSID, aucBCAddr);
 	}
@@ -305,6 +311,8 @@
 			prDetRplyInfo->u4KeyLength = params->key_len;
 			kalMemCopy(prDetRplyInfo->aucKeyMaterial, params->key, params->key_len);
 		}
+
+		prDetRplyInfo->fgKeyRscFresh = TRUE;
 	}
 #endif
 
@@ -1608,7 +1616,7 @@
 	prGtkData->u4KeyMgmt = prGlueInfo->rWpaInfo.u4KeyMgmt;
 	prGtkData->u4MgmtGroupCipher = 0;
 
-	prGtkData->ucRekeyDisable = FALSE;
+	prGtkData->ucRekeyMode = GTK_REKEY_CMD_MODE_OFFLOAD_ON;
 
 	rStatus = kalIoctl(prGlueInfo,
 			   wlanoidSetGtkRekeyData,
diff --git a/os/linux/gl_init.c b/os/linux/gl_init.c
index 8ebd1b2..9c0c4a9 100644
--- a/os/linux/gl_init.c
+++ b/os/linux/gl_init.c
@@ -2218,6 +2218,9 @@
 #if (MTK_WCN_HIF_SDIO && CFG_WMT_WIFI_PATH_SUPPORT)
 	INT_32 i4RetVal = 0;
 #endif
+#if CFG_SUPPORT_REPLAY_DETECTION
+	UINT_8 ucRpyDetectOffload;
+#endif
 
 #if 0
 		PUINT_8 pucConfigBuf = NULL, pucCfgBuf = NULL;
@@ -2565,6 +2568,20 @@
 		DBGLOG(INIT, LOUD, "wlanProbe: probe failed\n");
 	}
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	ucRpyDetectOffload = prAdapter->rWifiVar.ucRpyDetectOffload;
+
+	if (ucRpyDetectOffload == FEATURE_ENABLED) {
+		DBGLOG(INIT, INFO, "Send CMD to enable Replay Detection offload feature\n");
+		wlanSuspendRekeyOffload(prAdapter->prGlueInfo,
+			GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON);
+	} else {
+		DBGLOG(INIT, INFO, "Send CMD to disable Replay Detection offload feature\n");
+		wlanSuspendRekeyOffload(prAdapter->prGlueInfo,
+			GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF);
+	}
+#endif
+
 	return i4Status;
 }				/* end of wlanProbe() */
 
diff --git a/os/linux/gl_p2p_cfg80211.c b/os/linux/gl_p2p_cfg80211.c
index f83d115..3c4b025 100644
--- a/os/linux/gl_p2p_cfg80211.c
+++ b/os/linux/gl_p2p_cfg80211.c
@@ -740,6 +740,8 @@
 			prDetRplyInfo->u4KeyLength = params->key_len;
 			kalMemCopy(prDetRplyInfo->aucKeyMaterial, params->key, params->key_len);
 		}
+
+		prDetRplyInfo->fgKeyRscFresh = TRUE;
 	}
 #endif
 
diff --git a/os/linux/include/gl_os.h b/os/linux/include/gl_os.h
index 2ddc544..b1e7dad 100644
--- a/os/linux/include/gl_os.h
+++ b/os/linux/include/gl_os.h
@@ -323,6 +323,7 @@
 	UINT_32 u4KeyLength;
 	UINT_8 aucKeyMaterial[32];
 	BOOLEAN fgPairwiseInstalled;
+	BOOLEAN fgKeyRscFresh;
 };
 #endif