[WCNCR00166862] security: Add security detection feature support.

[Description]
Add security detection feature support.

Change-Id: I77310e3a6e4922d7a1f496dba06b5dcc8e85183b
Signed-off-by: wayne.guo <wayne.guo@mediatek.com>
CR-Id: WCNCR00166862
Feature: security
diff --git a/common/wlan_lib.c b/common/wlan_lib.c
index 64b9454..032b244 100644
--- a/common/wlan_lib.c
+++ b/common/wlan_lib.c
@@ -6839,7 +6839,11 @@
 	prWifiVar->ucWowPwsMode = (UINT_8) wlanCfgGetUint32(prAdapter, "WowPwsMode", Param_PowerModeFast_PSP);
 	prWifiVar->ucListenDtimInterval =
 		(UINT_8) wlanCfgGetUint32(prAdapter, "ListenDtimInt", DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD);
-	prWifiVar->ucEapolOffload = (UINT_8) wlanCfgGetUint32(prAdapter, "EapolOffload", FEATURE_ENABLED);
+	/* prWifiVar->ucEapolOffload = (UINT_8) wlanCfgGetUint32(prAdapter, "EapolOffload", FEATURE_ENABLED); */
+
+	/* ucEapolOffload: only offload eapol rekey as suspen/resume case. */
+	prWifiVar->ucEapolOffload = FEATURE_DISABLED;
+
 
 #if CFG_WOW_SUPPORT
 	prAdapter->rWowCtrl.fgWowEnable = (UINT_8) wlanCfgGetUint32(prAdapter, "WowEnable", FEATURE_ENABLED);
diff --git a/common/wlan_oid.c b/common/wlan_oid.c
index a3fcd15..88a3513 100644
--- a/common/wlan_oid.c
+++ b/common/wlan_oid.c
@@ -2298,8 +2298,13 @@
 	/* compose CMD_802_11_KEY cmd pkt */
 	prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL;
 	prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY);
+#if CFG_SUPPORT_REPLAY_DETECTION
+	prCmdInfo->pfCmdDoneHandler = nicCmdEventSetAddKey;
+	prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutSetAddKey;
+#else
 	prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon;
 	prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon;
+#endif
 	prCmdInfo->fgIsOid = TRUE;
 	prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY;
 	prCmdInfo->fgSetQuery = TRUE;
diff --git a/include/config.h b/include/config.h
index 617b868..35e70a1 100644
--- a/include/config.h
+++ b/include/config.h
@@ -843,6 +843,12 @@
 #define CFG_SUPPORT_MSP				1
 
 
+/*------------------------------------------------------------------------------
+ * Flags of Drop Packet Replay SUPPORT
+ *------------------------------------------------------------------------------
+ */
+#define CFG_SUPPORT_REPLAY_DETECTION		1
+
 
 /*------------------------------------------------------------------------------
  * Flags of driver fw customization
diff --git a/include/nic/adapter.h b/include/nic/adapter.h
index da9275d..30645b4 100644
--- a/include/nic/adapter.h
+++ b/include/nic/adapter.h
@@ -483,6 +483,11 @@
 	/* AP PMF */
 	struct AP_PMF_CFG rApPmfCfg;
 #endif
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+	struct GL_DETECT_REPLAY_INFO prDetRplyInfo;
+#endif
+
 };
 
 struct _AIS_SPECIFIC_BSS_INFO_T {
diff --git a/include/nic/que_mgt.h b/include/nic/que_mgt.h
index bba4e5b..d04eeef 100644
--- a/include/nic/que_mgt.h
+++ b/include/nic/que_mgt.h
@@ -952,6 +952,11 @@
 #endif
 
 VOID qmResetTcControlResource(IN P_ADAPTER_T prAdapter);
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+BOOLEAN qmHandleRxReplay(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb);
+#endif
+
 /*******************************************************************************
  *                              F U N C T I O N S
  ********************************************************************************
diff --git a/include/nic_cmd_event.h b/include/nic_cmd_event.h
index f79135b..31d9c24 100644
--- a/include/nic_cmd_event.h
+++ b/include/nic_cmd_event.h
@@ -3267,6 +3267,11 @@
 #endif
 VOID nicEventCSIData(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent);
 
+#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);
+#endif
+
 /*******************************************************************************
 *                              F U N C T I O N S
 ********************************************************************************
diff --git a/nic/nic_cmd_event.c b/nic/nic_cmd_event.c
index 613413d..f1a8821 100644
--- a/nic/nic_cmd_event.c
+++ b/nic/nic_cmd_event.c
@@ -3393,3 +3393,54 @@
 	kalMemCopy(prAdapter->rCsiData.ac2QData,
 		prCsiData->ac2QData, sizeof(prCsiData->ac2QData));
 }
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+VOID nicCmdEventSetAddKey(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN PUINT_8 pucEventBuf)
+{
+	P_WIFI_CMD_T prWifiCmd = NULL;
+	P_CMD_802_11_KEY prCmdKey = NULL;
+	struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	UINT_8 ucBssIndex = 0;
+	P_BSS_INFO_T prBssInfo = NULL;
+
+	ASSERT(prAdapter);
+	ASSERT(prCmdInfo);
+
+	if (prCmdInfo->fgIsOid) {
+		/* Update Set Information Length */
+		kalOidComplete(prAdapter->prGlueInfo,
+			       prCmdInfo->fgSetQuery, prCmdInfo->u4InformationBufferLength, WLAN_STATUS_SUCCESS);
+	}
+
+	prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer);
+	prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer);
+	ucBssIndex = prCmdKey->ucBssIdx;
+
+	prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex);
+	ASSERT(prBssInfo);
+
+	prDetRplyInfo = &prBssInfo->prDetRplyInfo;
+
+	if (pucEventBuf) {
+		prWifiCmd = (P_WIFI_CMD_T) (pucEventBuf);
+		prCmdKey = (P_CMD_802_11_KEY) (prWifiCmd->aucBuffer);
+		if (!prCmdKey->ucKeyType) {
+			prDetRplyInfo->ucCurKeyId = prCmdKey->ucKeyId;
+			prDetRplyInfo->ucKeyType = prCmdKey->ucKeyType;
+			prDetRplyInfo->arReplayPNInfo[prCmdKey->ucKeyId].fgRekey = TRUE;
+			prDetRplyInfo->arReplayPNInfo[prCmdKey->ucKeyId].fgFirstPkt = TRUE;
+			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)
+{
+	ASSERT(prAdapter);
+
+	DBGLOG(NIC, WARN, "Wlan setaddkey timeout.\n");
+	if (prCmdInfo->fgIsOid)
+		kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE);
+}
+#endif
diff --git a/nic/que_mgt.c b/nic/que_mgt.c
index e4e8be5..e3c62a1 100644
--- a/nic/que_mgt.c
+++ b/nic/que_mgt.c
@@ -2249,6 +2249,10 @@
 	PUINT_8 pucEthDestAddr;
 	BOOLEAN fgIsBMC, fgIsHTran;
 	BOOLEAN fgMicErr;
+#if CFG_SUPPORT_REPLAY_DETECTION
+	UINT_8 ucBssIndexRly = 0;
+	P_BSS_INFO_T prBssInfoRly = NULL;
+#endif
 
 	/* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */
 
@@ -2406,6 +2410,29 @@
 
 		/* Todo:: Move the data class error check here */
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+		if (prCurrSwRfb->prStaRec) {
+			ucBssIndexRly = prCurrSwRfb->prStaRec->ucBssIndex;
+			prBssInfoRly = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndexRly);
+			if (!IS_BSS_ACTIVE(prBssInfoRly)) {
+				DBGLOG(QM, INFO,
+					"Mark NULL the Packet for inactive Bss %u\n",
+					ucBssIndexRly);
+				prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
+				QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
+				continue;
+			}
+		}
+		if (fgIsBMC
+			&& prBssInfoRly
+			&& (IS_BSS_AIS(prBssInfoRly) || IS_BSS_P2P(prBssInfoRly))
+			&& qmHandleRxReplay(prAdapter, prCurrSwRfb)) {
+			prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL;
+			QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T) prCurrSwRfb);
+			continue;
+		}
+#endif
+
 		if (prCurrSwRfb->fgReorderBuffer && !fgIsBMC && fgIsHTran) {
 			/* If this packet should dropped or indicated to the host immediately,
 			 *  it should be enqueued into the rReturnedQue with specific flags. If
@@ -5924,3 +5951,138 @@
 
 }
 #endif
+
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+/* To change PN number to UINT64 */
+#define CCMPTSCPNNUM	6
+BOOLEAN qmRxPNtoU64(PUINT_8 pucPN, UINT_8 uPNNum, PUINT_64 pu8Rets)
+{
+	UINT_8 ucCount = 0;
+	UINT_64 u8Data = 0;
+
+	if (!pu8Rets) {
+		DBGLOG(QM, ERROR, "Please input valid pu8Rets\n");
+		return FALSE;
+	}
+
+	if (uPNNum > CCMPTSCPNNUM) {
+		DBGLOG(QM, ERROR, "Please input valid uPNNum:%d\n", uPNNum);
+		return FALSE;
+	}
+
+	*pu8Rets = 0;
+	for (; ucCount < uPNNum; ucCount++) {
+		u8Data = pucPN[ucCount] << 8*ucCount;
+		*pu8Rets +=  u8Data;
+	}
+	return TRUE;
+}
+
+/* To check PN/TSC between RxStatus and local record. return TRUE if PNS is not bigger than PNT */
+BOOLEAN qmRxDetectReplay(PUINT_8 pucPNS, PUINT_8 pucPNT)
+{
+	UINT_64 u8RxNum = 0;
+	UINT_64 u8LocalRec = 0;
+
+	if (!pucPNS || !pucPNT) {
+		DBGLOG(QM, ERROR, "Please input valid PNS:%p and PNT:%p\n", pucPNS, pucPNT);
+		return TRUE;
+	}
+
+	if (!qmRxPNtoU64(pucPNS, CCMPTSCPNNUM, &u8RxNum)
+		|| !qmRxPNtoU64(pucPNT, CCMPTSCPNNUM, &u8LocalRec)) {
+		DBGLOG(QM, ERROR, "PN2U64 failed\n");
+		return TRUE;
+	}
+	/* PN overflow ? */
+
+	return !(u8RxNum > u8LocalRec);
+}
+
+/* TO filter broadcast and multicast data packet replay issue. */
+BOOLEAN qmHandleRxReplay(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb)
+{
+	PUINT_8 pucPN = NULL;
+	UINT_8 ucKeyID = 0;				/* 0~4 */
+	UINT_8 ucSecMode = CIPHER_SUITE_NONE;		/* CIPHER_SUITE_NONE~CIPHER_SUITE_GCMP */
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	P_GL_WPA_INFO_T prWpaInfo = NULL;
+	struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	P_HW_MAC_RX_DESC_T prRxStatus = NULL;
+	UINT_8 ucBssIndex = 0;
+	P_BSS_INFO_T prBssInfo = NULL;
+
+	if (!prAdapter)
+		return TRUE;
+	if (prSwRfb->u2PacketLen <= ETHER_HEADER_LEN)
+		return TRUE;
+
+	ucBssIndex = prSwRfb->prStaRec->ucBssIndex;
+	prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex);
+
+	ASSERT(prBssInfo);
+
+	/* BMC only need check CCMP and TKIP Cipher suite */
+	prRxStatus = prSwRfb->prRxStatus;
+	ucSecMode = HAL_RX_STATUS_GET_SEC_MODE(prRxStatus);
+	if (ucSecMode != CIPHER_SUITE_CCMP
+		&& ucSecMode != CIPHER_SUITE_TKIP) {
+		DBGLOG(QM, TRACE, "SecMode: %d and CipherGroup: %d, no need check replay\n",
+				ucSecMode, prWpaInfo->u4CipherGroup);
+
+		if (!(prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_1))) {
+			DBGLOG(QM, ERROR, "Group 1 invalid\n");
+			return TRUE;
+		}
+		return FALSE;
+	}
+
+	ucKeyID = HAL_RX_STATUS_GET_KEY_ID(prRxStatus);
+	if (ucKeyID >= MAX_KEY_NUM) {
+		DBGLOG(QM, ERROR, "KeyID: %d error\n", ucKeyID);
+		return TRUE;
+	}
+
+	prGlueInfo = prAdapter->prGlueInfo;
+	prWpaInfo = &prGlueInfo->rWpaInfo;
+	prDetRplyInfo = &prBssInfo->prDetRplyInfo;
+
+	/* TODO : Need check fw rekey while fw rekey event. */
+	if (ucKeyID != prDetRplyInfo->ucCurKeyId) {
+		DBGLOG(QM, TRACE,
+			"use last keyID while detect replay information.(0x%x->0x%x)\n",
+			prDetRplyInfo->ucCurKeyId, ucKeyID);
+		ucKeyID = prDetRplyInfo->ucCurKeyId;
+	}
+
+#if 0
+	if (prDetRplyInfo->arReplayPNInfo[ucKeyID].fgFirstPkt) {
+		prDetRplyInfo->arReplayPNInfo[ucKeyID].fgFirstPkt = FALSE;
+		HAL_RX_STATUS_GET_PN(prSwRfb->prRxStatusGroup1, prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN);
+		DBGLOG(QM, INFO,
+			"First check packet. Key ID:0x%x\n", ucKeyID);
+		return FALSE;
+	}
+#endif
+
+	pucPN = prSwRfb->prRxStatusGroup1->aucPN;
+	DBGLOG(QM, TRACE,
+			"BC packet 0x%x:0x%x:0x%x:0x%x:0x%x:0x%x--0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n",
+			pucPN[0], pucPN[1], pucPN[2], pucPN[3], pucPN[4], pucPN[5],
+			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[0],
+			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[1],
+			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[2],
+			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[3],
+			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[4],
+			prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[5]);
+	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;
+}
+
+#endif
diff --git a/os/linux/gl_cfg80211.c b/os/linux/gl_cfg80211.c
index 9224841..2989bed 100644
--- a/os/linux/gl_cfg80211.c
+++ b/os/linux/gl_cfg80211.c
@@ -187,6 +187,12 @@
 	INT_32 i4Rslt = -EINVAL;
 	UINT_32 u4BufLen = 0;
 	UINT_8 tmp1[8], tmp2[8];
+#if CFG_SUPPORT_REPLAY_DETECTION
+	P_BSS_INFO_T prBssInfo = NULL;
+	struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	UINT_8 ucCheckZeroKey = 0;
+	UINT_8 i = 0;
+#endif
 
 	const UINT_8 aucBCAddr[] = BC_MAC_ADDR;
 	/* const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; */
@@ -258,6 +264,15 @@
 	}
 
 	if (params->key) {
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+		for (i = 0; i < params->key_len; i++)
+			ucCheckZeroKey += params->key[i];
+
+		if (ucCheckZeroKey == 0)
+			return 0;
+#endif
+
 		kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len);
 		if (rKey.ucCipher == CIPHER_SUITE_TKIP) {
 			kalMemCopy(tmp1, &params->key[16], 8);
@@ -272,6 +287,26 @@
 	rKey.u4KeyLength = params->key_len;
 	rKey.u4Length = ((ULONG)&(((P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength;
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex);
+	ASSERT(prBssInfo);
+
+	prDetRplyInfo = &prBssInfo->prDetRplyInfo;
+
+	if ((!pairwise) && ((params->cipher == WLAN_CIPHER_SUITE_TKIP) || (params->cipher == WLAN_CIPHER_SUITE_CCMP))) {
+		if ((prDetRplyInfo->ucCurKeyId == key_index) &&
+			(!kalMemCmp(prDetRplyInfo->aucKeyMaterial, params->key, params->key_len))) {
+			DBGLOG(RSN, TRACE, "M3/G1, KeyID and KeyValue equal.\n");
+			DBGLOG(RSN, TRACE, "hit group key reinstall case, so no update BC/MC PN.\n");
+		} else {
+			kalMemCopy(prDetRplyInfo->arReplayPNInfo[key_index].auPN, params->seq, params->seq_len);
+			prDetRplyInfo->ucCurKeyId = key_index;
+			prDetRplyInfo->u4KeyLength = params->key_len;
+			kalMemCopy(prDetRplyInfo->aucKeyMaterial, params->key, params->key_len);
+		}
+	}
+#endif
+
 	rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, &u4BufLen);
 
 	if (rStatus == WLAN_STATUS_SUCCESS)
@@ -865,6 +900,11 @@
 	ENUM_PARAM_OP_MODE_T eOpMode;
 	UINT_32 i, u4AkmSuite = 0;
 	P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry;
+#if CFG_SUPPORT_REPLAY_DETECTION
+	P_BSS_INFO_T prBssInfo = NULL;
+	struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+#endif
+
 
 	prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy);
 	ASSERT(prGlueInfo);
@@ -891,6 +931,20 @@
 	prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE;
 	prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE;
 	prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM;
+
+#if CFG_SUPPORT_REPLAY_DETECTION
+	/* reset Detect replay information */
+	prDetRplyInfo = &prGlueInfo->prDetRplyInfo;
+	kalMemZero(prDetRplyInfo, sizeof(struct GL_DETECT_REPLAY_INFO));
+
+	prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex);
+	ASSERT(prBssInfo);
+
+	prDetRplyInfo = &prBssInfo->prDetRplyInfo;
+	kalMemZero(prDetRplyInfo, sizeof(struct GL_DETECT_REPLAY_INFO));
+#endif
+
+
 #if CFG_SUPPORT_802_11W
 	prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED;
 	switch (sme->mfp) {
diff --git a/os/linux/gl_p2p_cfg80211.c b/os/linux/gl_p2p_cfg80211.c
index 038b7e4..c632ea3 100644
--- a/os/linux/gl_p2p_cfg80211.c
+++ b/os/linux/gl_p2p_cfg80211.c
@@ -604,6 +604,12 @@
 	UINT_8 ucRoleIdx = 0;
 	const UINT_8 aucBCAddr[] = BC_MAC_ADDR;
 	/* const UINT_8 aucZeroMacAddr[] = NULL_MAC_ADDR; */
+#if CFG_SUPPORT_REPLAY_DETECTION
+	P_BSS_INFO_T prBssInfo = NULL;
+	struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+	UINT_8 ucCheckZeroKey = 0;
+	UINT_8 i = 0;
+#endif
 
 	ASSERT(wiphy);
 
@@ -683,12 +689,41 @@
 	if (kalP2PGetRole(prGlueInfo, ucRoleIdx) == 2)
 		rKey.u4KeyIndex |= BIT(28); /* authenticator */
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	if (params->key) {
+		for (i = 0; i < params->key_len; i++)
+			ucCheckZeroKey += params->key[i];
+
+		if (ucCheckZeroKey == 0)
+			return 0;
+	}
+#endif
 
 	if (params->key)
 		kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len);
 	rKey.u4KeyLength = params->key_len;
 	rKey.u4Length = ((ULONG)&(((P_P2P_PARAM_KEY_T) 0)->aucKeyMaterial)) + rKey.u4KeyLength;
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, rKey.ucBssIdx);
+
+	ASSERT(prBssInfo);
+	prDetRplyInfo = &prBssInfo->prDetRplyInfo;
+
+	if ((!pairwise) && ((params->cipher == WLAN_CIPHER_SUITE_TKIP) || (params->cipher == WLAN_CIPHER_SUITE_CCMP))) {
+		if ((prDetRplyInfo->ucCurKeyId == key_index) &&
+			(!kalMemCmp(prDetRplyInfo->aucKeyMaterial, params->key, params->key_len))) {
+			DBGLOG(RSN, TRACE, "M3/G1, KeyID and KeyValue equal.\n");
+			DBGLOG(RSN, TRACE, "hit group key reinstall case, so no update BC/MC PN.\n");
+		} else {
+			kalMemCopy(prDetRplyInfo->arReplayPNInfo[key_index].auPN, params->seq, params->seq_len);
+			prDetRplyInfo->ucCurKeyId = key_index;
+			prDetRplyInfo->u4KeyLength = params->key_len;
+			kalMemCopy(prDetRplyInfo->aucKeyMaterial, params->key, params->key_len);
+		}
+	}
+#endif
+
 	rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey, rKey.u4Length, FALSE, FALSE, TRUE, &u4BufLen);
 	if (rStatus == WLAN_STATUS_SUCCESS)
 		i4Rslt = 0;
@@ -2438,6 +2473,11 @@
 	P_GLUE_INFO_T prGlueInfo = NULL;
 	P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T) NULL;
 	UINT_8 ucRoleIdx = 0;
+#if CFG_SUPPORT_REPLAY_DETECTION
+	UINT_8 ucBssIndex = 0;
+	P_BSS_INFO_T prBssInfo = NULL;
+	struct GL_DETECT_REPLAY_INFO *prDetRplyInfo = NULL;
+#endif
 
 	do {
 		if ((wiphy == NULL) || (dev == NULL) || (sme == NULL))
@@ -2500,6 +2540,16 @@
 
 		mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prConnReqMsg, MSG_SEND_METHOD_BUF);
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+		if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIndex) != WLAN_STATUS_SUCCESS)
+			return -EINVAL;
+
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIndex);
+		ASSERT(prBssInfo);
+		prDetRplyInfo = &prBssInfo->prDetRplyInfo;
+		kalMemZero(prDetRplyInfo, sizeof(struct GL_DETECT_REPLAY_INFO));
+#endif
+
 		i4Rslt = 0;
 	} while (FALSE);
 
diff --git a/os/linux/include/gl_os.h b/os/linux/include/gl_os.h
index fd2631f..267392e 100644
--- a/os/linux/include/gl_os.h
+++ b/os/linux/include/gl_os.h
@@ -310,6 +310,22 @@
 	UINT_8 aucReplayCtr[NL80211_REPLAY_CTR_LEN];
 } GL_WPA_INFO_T, *P_GL_WPA_INFO_T;
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+struct GL_REPLEY_PN_INFO {
+	UINT_8 auPN[16];
+	BOOLEAN fgRekey;
+	BOOLEAN fgFirstPkt;
+};
+struct GL_DETECT_REPLAY_INFO {
+	UINT_8 ucCurKeyId;
+	UINT_8 ucKeyType;
+	struct GL_REPLEY_PN_INFO arReplayPNInfo[4];
+	UINT_32 u4KeyLength;
+	UINT_8 aucKeyMaterial[32];
+	BOOLEAN fgPairwiseInstalled;
+};
+#endif
+
 typedef enum _ENUM_NET_DEV_IDX_T {
 	NET_DEV_WLAN_IDX = 0,
 	NET_DEV_P2P_IDX,
@@ -461,6 +477,10 @@
 	/*! \brief wext wpa related information */
 	GL_WPA_INFO_T rWpaInfo;
 
+#if CFG_SUPPORT_REPLAY_DETECTION
+	struct GL_DETECT_REPLAY_INFO prDetRplyInfo;
+#endif
+
 	/* Pointer to ADAPTER_T - main data structure of internal protocol stack */
 	P_ADAPTER_T prAdapter;