[WCNCR00152277] softap: add 802.11w PMF mandatory item for AP role

[Description]
Add 802.11w PMF feature

Change-Id: Ia35840b65ba244fde0b11077f08c87a19de24353
Signed-off-by: Bennett Ou <bennett.ou@mediatek.com>
CR-Id: WCNCR00152277
Feature: sofap/pmf
diff --git a/common/wlan_oid.c b/common/wlan_oid.c
index 53a66cf..72696aa 100644
--- a/common/wlan_oid.c
+++ b/common/wlan_oid.c
@@ -2354,6 +2354,15 @@
 						   &prCmdKey->aucKeyMaterial[24], MIC_KEY_LEN);
 				}
 			}
+		} else {
+#if CFG_SUPPORT_802_11W
+			/* AP PMF */
+			if ((prCmdKey->ucKeyId >= 4 && prCmdKey->ucKeyId <= 5) &&
+				(prCmdKey->ucAlgorithmId == CIPHER_SUITE_BIP)) {
+				DBGLOG(RSN, INFO, "AP mode set BIP\n");
+				prBssInfo->rApPmfCfg.fgBipKeyInstalled = TRUE;
+			}
+#endif
 		}
 	} else {		/* Legacy windows NDIS no cipher info */
 #if 0
@@ -2441,10 +2450,16 @@
 #endif
 
 #if CFG_SUPPORT_802_11W
+		/* AP PMF */
+		/* 20170519 BIP optional item is not support now */
+		DBGLOG(RSN, INFO, "802.11w BIP optional not support now\n");
+		if ((prNewKey->u4KeyIndex & 0xff) >= 4)
+			return WLAN_STATUS_SUCCESS;
+
 		if (prCmdKey->ucAlgorithmId == CIPHER_SUITE_BIP) {
 			if (prCmdKey->ucIsAuthenticator) {
-				DBGLOG(RSN, ERROR, "Not support 111w AP mode ");
-				ASSERT(FALSE);
+				DBGLOG(RSN, INFO, "Authenticator follow AIS method\n");
+
 			}
 			prCmdKey->ucWlanIndex =
 			    secPrivacySeekForBcEntry(prAdapter,
@@ -2453,6 +2468,7 @@
 						     prBssInfo->prStaRecOfAP->ucIndex,
 						     prCmdKey->ucAlgorithmId, prCmdKey->ucKeyId);
 
+			DBGLOG(RSN, INFO, "BIP BC wtbl index:%d\n", prCmdKey->ucWlanIndex);
 		} else
 #endif
 		if (1) {
@@ -2466,6 +2482,12 @@
 					prCmdKey->ucWlanIndex = prStaRec->ucWlanIndex;
 					prStaRec->fgTransmitKeyExist = TRUE;	/* wait for CMD Done ? */
 					kalMemCopy(prCmdKey->aucPeerAddr, prNewKey->arBSSID, MAC_ADDR_LEN);
+#if CFG_SUPPORT_802_11W
+					/* AP PMF */
+					DBGLOG(RSN, INFO, "Assign client PMF flag = %d\n",
+						prStaRec->rPmfCfg.fgApplyPmf);
+					prCmdKey->ucMgmtProtection = prStaRec->rPmfCfg.fgApplyPmf;
+#endif
 				} else {
 					ASSERT(FALSE);
 				}
@@ -2790,7 +2812,7 @@
 	prGlueInfo = prAdapter->prGlueInfo;
 	prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prDefaultKey->ucBssIdx);
 
-	/* DBGLOG(RSN, LOUD, "WlanIdx = %d\n", prBssInfo->wepkeyWlanIdx); */
+	DBGLOG(RSN, INFO, "WlanIdx = %d\n", prBssInfo->wepkeyWlanIdx);
 
 	if (prDefaultKey->ucMulticast) {
 		if (!prBssInfo)
diff --git a/include/mgmt/cnm_mem.h b/include/mgmt/cnm_mem.h
index 4a0292e..ed3df96 100644
--- a/include/mgmt/cnm_mem.h
+++ b/include/mgmt/cnm_mem.h
@@ -211,6 +211,34 @@
 	OS_SYSTIME rReceiveLifetimeLimit;	/* The receive time of 1st fragment */
 } FRAG_INFO_T, *P_FRAG_INFO_T;
 
+#if CFG_SUPPORT_802_11W
+/* AP PMF */
+struct AP_PMF_CFG {
+	BOOLEAN fgMfpc;
+	BOOLEAN fgMfpr;
+	BOOLEAN fgSha256;
+	BOOLEAN fgAPApplyPmfReq;
+	BOOLEAN fgBipKeyInstalled;
+};
+
+struct STA_PMF_CFG {
+	BOOLEAN fgMfpc;
+	BOOLEAN fgMfpr;
+	BOOLEAN fgSha256;
+	BOOLEAN fgApplyPmf;
+	BOOLEAN fgBipKeyInstalled;
+	BOOLEAN fgRxDeauthResp; /* for certification 4.3.3.1, 4.3.3.2 TX unprotected deauth */
+
+	/* For PMF SA query TX request retry a timer */
+	UINT_32 u4SAQueryStart; /* record the start time of 1st SAQ request */
+	UINT_32 u4SAQueryCount;
+	UINT_8 ucSAQueryTimedOut; /* retry more than 1000ms */
+	TIMER_T rSAQueryTimer;
+	UINT_16 u2TransactionID;
+
+};
+#endif
+
 /* Define STA record structure */
 struct _STA_RECORD_T {
 	LINK_ENTRY_T rLinkEntry;
@@ -518,6 +546,10 @@
 	UINT_8 ucSmDialogToken;	/* Spectrum Mngt Dialog Token */
 	UINT_8 ucSmMsmtRequestMode; /* Measurement Request Mode */
 	UINT_8 ucSmMsmtToken; /* Measurement Request Token */
+#if CFG_SUPPORT_802_11W
+	/* AP PMF */
+	struct STA_PMF_CFG rPmfCfg;
+#endif
 };
 
 #if 0
diff --git a/include/mgmt/rsn.h b/include/mgmt/rsn.h
index 0281a5b..be94150 100644
--- a/include/mgmt/rsn.h
+++ b/include/mgmt/rsn.h
@@ -160,6 +160,7 @@
 #define WPA_IE(fp)              ((P_WPA_INFO_ELEM_T) fp)
 
 #define ELEM_MAX_LEN_ASSOC_RSP_WSC_IE          (32 - ELEM_HDR_LEN)
+#define ELEM_MAX_LEN_TIMEOUT_IE          (5)
 
 /*******************************************************************************
 *                  F U N C T I O N   D E C L A R A T I O N S
@@ -188,7 +189,8 @@
 			    IN PUINT_8 pucBuf, OUT PUINT_8 pucOuiType, OUT PUINT_16 pu2SubTypeVersion);
 
 #if CFG_SUPPORT_AAA
-void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode);
+void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, P_STA_RECORD_T prStaRec,
+	PUINT_16 pu2StatusCode);
 #endif
 
 VOID rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, IN BOOLEAN fgErrorKeyType);
@@ -224,7 +226,16 @@
 void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb);
 
 void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb);
-#endif
+
+UINT_16 rsnPmfCapableValidation(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec);
+
+VOID rsnPmfGenerateTimeoutIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo);
+
+void rsnApStartSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec);
+
+void rsnApSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb);
+
+#endif /* CFG_SUPPORT_802_11W */
 
 #if CFG_SUPPORT_AAA
 VOID rsnGenerateWSCIEForAssocRsp(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo);
diff --git a/include/nic/adapter.h b/include/nic/adapter.h
index 777003d..4dd1c45 100644
--- a/include/nic/adapter.h
+++ b/include/nic/adapter.h
@@ -474,6 +474,11 @@
 	ENUM_BAND_T eBandGranted;
 	UINT_8 ucPrimaryChannelGranted;
 	PARAM_CUSTOM_ACL rACL;
+
+#if CFG_SUPPORT_802_11W
+	/* AP PMF */
+	struct AP_PMF_CFG rApPmfCfg;
+#endif
 };
 
 struct _AIS_SPECIFIC_BSS_INFO_T {
diff --git a/include/nic_cmd_event.h b/include/nic_cmd_event.h
index 419283b..27dca40 100644
--- a/include/nic_cmd_event.h
+++ b/include/nic_cmd_event.h
@@ -1014,7 +1014,7 @@
 	UINT_8 ucKeyId;
 	UINT_8 ucKeyLen;
 	UINT_8 ucWlanIndex;
-	UINT_8 ucReverved;
+	UINT_8 ucMgmtProtection;
 	UINT_8 aucKeyMaterial[32];
 	UINT_8 aucKeyRsc[16];
 } CMD_802_11_KEY, *P_CMD_802_11_KEY;
diff --git a/mgmt/aaa_fsm.c b/mgmt/aaa_fsm.c
index 83522b9..3e9b48d 100644
--- a/mgmt/aaa_fsm.c
+++ b/mgmt/aaa_fsm.c
@@ -447,8 +447,10 @@
 	P_STA_RECORD_T prStaRec = (P_STA_RECORD_T) NULL;
 	UINT_16 u2StatusCode = STATUS_CODE_RESERVED;
 	BOOLEAN fgReplyAssocResp = FALSE;
+	BOOLEAN fgSendSAQ = FALSE;
 
 	ASSERT(prAdapter);
+	DBGLOG(AAA, INFO, "aaaFsmRunEventRxAssoc\n");
 
 	do {
 
@@ -604,13 +606,24 @@
 			}
 #endif
 		} else {
-			prStaRec->u2AssocId = 0;	/* Invalid Association ID */
 
-			/* If (Re)association fail, remove sta record and use class error to handle sta */
-			prStaRec->eAuthAssocState = AA_STATE_IDLE;
+#if CFG_SUPPORT_802_11W
+			/* AP PMF */
+			/* don't change state, just send assoc resp (NO need TX done, TIE + code30) and then SAQ */
+			if (u2StatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY) {
+				DBGLOG(AAA, INFO, "AP send SAQ\n");
+				fgSendSAQ = TRUE;
+			} else
+#endif
+			{
+				prStaRec->u2AssocId = 0;	/* Invalid Association ID */
 
-			/* NOTE(Kevin): Better to change state here, not at TX Done */
-			cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2);
+				/* If (Re)association fail, remove sta record and use class error to handle sta */
+				prStaRec->eAuthAssocState = AA_STATE_IDLE;
+
+				/* NOTE(Kevin): Better to change state here, not at TX Done */
+				cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2);
+			}
 		}
 
 		/* Update the record join time. */
@@ -623,6 +636,14 @@
 		/* 4 <4.2> Reply  Assoc Resp */
 		assocSendReAssocRespFrame(prAdapter, prStaRec);
 
+#if CFG_SUPPORT_802_11W
+		/* AP PMF */
+		if (fgSendSAQ) {
+			/* if PMF connection, and return code 30, send SAQ */
+			rsnApStartSaQuery(prAdapter, prStaRec);
+		}
+#endif
+
 	}
 
 	return WLAN_STATUS_SUCCESS;
diff --git a/mgmt/assoc.c b/mgmt/assoc.c
index b73009e..c6da3e3 100644
--- a/mgmt/assoc.c
+++ b/mgmt/assoc.c
@@ -161,6 +161,10 @@
 #if CFG_SUPPORT_MTK_SYNERGY
 	{(ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI), NULL, rlmGenerateMTKOuiIE}	/* 221 */
 #endif
+	,
+#if CFG_SUPPORT_802_11W
+	{(ELEM_HDR_LEN + ELEM_MAX_LEN_TIMEOUT_IE), NULL, rsnPmfGenerateTimeoutIE}	/* 56 */
+#endif
 
 };
 #endif /* CFG_SUPPORT_AAA */
@@ -962,6 +966,8 @@
 	ASSERT(prStaRec);
 	ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX);
 
+	DBGLOG(RSN, INFO, "assocSendDisAssocFrame\n");
+
 	/* 4 <1> Allocate a PKT_INFO_T for Disassociation Frame */
 	/* Init with MGMT Header Length + Length of Fixed Fields + IE Length */
 	u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN;
@@ -981,12 +987,18 @@
 					     MAC_TX_RESERVED_FIELD), pucMacAddress, u2ReasonCode);
 
 #if CFG_SUPPORT_802_11W
+	/* AP PMF */
 	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
-		P_WLAN_DISASSOC_FRAME_T prDisassocFrame;
+		/* PMF certification 4.3.3.1, 4.3.3.2 send unprotected deauth reason 6/7 */
+		if (prStaRec->rPmfCfg.fgRxDeauthResp != TRUE) {
 
-		prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
+			P_WLAN_DISASSOC_FRAME_T prDisassocFrame;
 
-		prDisassocFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
+			prDisassocFrame =
+				(P_WLAN_DISASSOC_FRAME_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
+
+			prDisassocFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
+		}
 	}
 #endif
 
@@ -1000,9 +1012,16 @@
 		     WLAN_MAC_MGMT_HEADER_LEN, WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, MSDU_RATE_MODE_AUTO);
 
 #if CFG_SUPPORT_802_11W
+	/* AP PMF */
+	/* caution: access prStaRec only if true */
 	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
-		/* DBGLOG(RSN, TRACE, ("Set MSDU_OPT_PROTECTED_FRAME\n")); */
-		nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
+		/* 4.3.3.1 send unprotected deauth reason 6/7 */
+		if (prStaRec->rPmfCfg.fgRxDeauthResp != TRUE) {
+			DBGLOG(RSN, INFO, "Disassoc Set MSDU_OPT_PROTECTED_FRAME\n");
+			nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
+		}
+
+		prStaRec->rPmfCfg.fgRxDeauthResp = FALSE;
 	}
 #endif
 
@@ -1051,6 +1070,7 @@
 		       MAC2STR(prDisassocFrame->aucSrcAddr));
 		return WLAN_STATUS_FAILURE;
 	}
+
 	/* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */
 	WLAN_GET_FIELD_16(&prDisassocFrame->u2ReasonCode, &u2RxReasonCode);
 	*pu2ReasonCode = u2RxReasonCode;
@@ -1190,7 +1210,7 @@
 #if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK
 			if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) {
 				prIeRsn = RSN_IE(pucIE);
-				rsnParserCheckForRSNCCMPPSK(prAdapter, prIeRsn, &u2StatusCode);
+				rsnParserCheckForRSNCCMPPSK(prAdapter, prIeRsn, prStaRec, &u2StatusCode);
 				if (u2StatusCode != STATUS_CODE_SUCCESSFUL) {
 					*pu2StatusCode = u2StatusCode;
 					return WLAN_STATUS_SUCCESS;
diff --git a/mgmt/auth.c b/mgmt/auth.c
index f6db0de..79f1320 100644
--- a/mgmt/auth.c
+++ b/mgmt/auth.c
@@ -798,6 +798,8 @@
 	UINT_8 ucBssIndex = BSS_INFO_NUM;
 	UINT_8 aucBMC[] = BC_MAC_ADDR;
 
+	DBGLOG(RSN, INFO, "authSendDeauthFrame\n");
+
 	/* NOTE(Kevin): The best way to reply the Deauth is according to the incoming data
 	 * frame
 	 */
@@ -905,13 +907,23 @@
 					  pucBssid, u2ReasonCode);
 
 #if CFG_SUPPORT_802_11W
+	/* AP PMF */
 	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
-		P_WLAN_DEAUTH_FRAME_T prDeauthFrame;
+		/* PMF certification 4.3.3.1, 4.3.3.2 send unprotected deauth reason 6/7 */
+		/* if (AP mode & not for PMF reply case) OR (STA PMF) */
+		if (((GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eCurrentOPMode ==
+				OP_MODE_ACCESS_POINT) &&
+			(prStaRec->rPmfCfg.fgRxDeauthResp != TRUE)) ||
+			(GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eNetworkType ==
+				(UINT_8) NETWORK_TYPE_AIS)) {
 
-		prDeauthFrame =
-		    (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
+			P_WLAN_DEAUTH_FRAME_T prDeauthFrame;
 
-		prDeauthFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
+			prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T) (PUINT_8) ((ULONG) (prMsduInfo->prPacket) +
+				MAC_TX_RESERVED_FIELD);
+
+			prDeauthFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
+		}
 	}
 #endif
 	nicTxSetPktLifeTime(prMsduInfo, 100);
@@ -927,8 +939,17 @@
 		     WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN, pfTxDoneHandler, MSDU_RATE_MODE_AUTO);
 
 #if CFG_SUPPORT_802_11W
-	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec))
-		nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
+	/* AP PMF */
+	/* caution: access prStaRec only if true */
+	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
+		/* 4.3.3.1 send unprotected deauth reason 6/7 */
+		if (prStaRec->rPmfCfg.fgRxDeauthResp != TRUE) {
+			DBGLOG(RSN, INFO, "Deauth Set MSDU_OPT_PROTECTED_FRAME\n");
+			nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
+		}
+
+		prStaRec->rPmfCfg.fgRxDeauthResp = FALSE;
+	}
 
 #endif
 
diff --git a/mgmt/p2p_func.c b/mgmt/p2p_func.c
index f85d6e6..6100891 100644
--- a/mgmt/p2p_func.c
+++ b/mgmt/p2p_func.c
@@ -2435,6 +2435,8 @@
 	PUINT_8 pucIE = (PUINT_8) NULL;
 	UINT_16 u2Offset = 0;
 	P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T) NULL;
+	UINT_8 i = 0;
+	RSN_INFO_T rRsnIe;
 
 	do {
 		ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL));
@@ -2590,20 +2592,40 @@
 				}
 				break;
 			case ELEM_ID_RSN:	/* 48 *//* V */
-				{
-					RSN_INFO_T rRsnIe;
 
-					DBGLOG(P2P, TRACE, "RSN IE\n");
-					kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP,
-						(UINT_8) prP2pBssInfo->u4PrivateData);
+				DBGLOG(P2P, TRACE, "RSN IE\n");
+				kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP,
+					(UINT_8) prP2pBssInfo->u4PrivateData);
 
-					if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &rRsnIe)) {
-						prP2pBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP;
-						prP2pBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP;
-						prP2pBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK;
-						prP2pBssInfo->u2RsnSelectedCapInfo = rRsnIe.u2RsnCap;
+				if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &rRsnIe)) {
+					prP2pBssInfo->u4RsnSelectedGroupCipher = RSN_CIPHER_SUITE_CCMP;
+					prP2pBssInfo->u4RsnSelectedPairwiseCipher = RSN_CIPHER_SUITE_CCMP;
+					prP2pBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK;
+					prP2pBssInfo->u2RsnSelectedCapInfo = rRsnIe.u2RsnCap;
+				}
+
+#if CFG_SUPPORT_802_11W
+				/* AP PMF */
+				prP2pBssInfo->rApPmfCfg.fgMfpc = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPC) ? 1 : 0;
+				prP2pBssInfo->rApPmfCfg.fgMfpr = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPR) ? 1 : 0;
+
+				for (i = 0; i < rRsnIe.u4AuthKeyMgtSuiteCount; i++) {
+					if ((rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_PSK_SHA256) ||
+						(rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_802_1X_SHA256)) {
+						DBGLOG(RSN, INFO, "SHA256 support\n");
+						/* over-write u4RsnSelectedAKMSuite by SHA256 AKM */
+						prP2pBssInfo->u4RsnSelectedAKMSuite =
+							rRsnIe.au4AuthKeyMgtSuite[i];
+						prP2pBssInfo->rApPmfCfg.fgSha256 = TRUE;
+						break;
 					}
 				}
+				DBGLOG(RSN, ERROR, "bcn mfpc:%d, mfpr:%d, sha256:%d\n",
+					prP2pBssInfo->rApPmfCfg.fgMfpc,
+					prP2pBssInfo->rApPmfCfg.fgMfpr,
+					prP2pBssInfo->rApPmfCfg.fgSha256);
+#endif
+
 				break;
 			case ELEM_ID_EXTENDED_SUP_RATES:	/* 50 *//* V */
 				/* ELEM_ID_SUP_RATES should be placed before ELEM_ID_EXTENDED_SUP_RATES. */
diff --git a/mgmt/p2p_role_fsm.c b/mgmt/p2p_role_fsm.c
index 70b65b4..501d26e 100644
--- a/mgmt/p2p_role_fsm.c
+++ b/mgmt/p2p_role_fsm.c
@@ -585,6 +585,7 @@
 {
 	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
 	UINT_16 u2ReasonCode = 0;
+	BOOLEAN fgSendDeauth = FALSE; /* flag to send deauth when rx sta disassc/deauth */
 
 	do {
 		ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL));
@@ -650,9 +651,29 @@
 			/* Delete client from client list. */
 			if (authProcessRxDeauthFrame(prSwRfb,
 						     prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) {
+
+#if CFG_SUPPORT_802_11W
+				/* AP PMF */
+				if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
+					if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) ||
+						HAL_RX_STATUS_IS_CLM_ERROR(prSwRfb->prRxStatus)) {
+						/* if cipher mismatch, or incorrect encrypt, just drop */
+						DBGLOG(P2P, ERROR, "Rx deauth CM/CLM=1\n");
+						return;
+					}
+
+					/* 4.3.3.1 send unprotected deauth reason 6/7 */
+					DBGLOG(P2P, INFO, "deauth reason=6\n");
+					fgSendDeauth = TRUE;
+					u2ReasonCode = REASON_CODE_CLASS_2_ERR;
+					prStaRec->rPmfCfg.fgRxDeauthResp = TRUE;
+				}
+#endif
+
 				if (bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec)) {
 					/* Indicate disconnect to Host. */
-					p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, FALSE, u2ReasonCode);
+					p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, fgSendDeauth,
+						u2ReasonCode);
 					/* Deactive BSS if PWR is IDLE and no peer */
 					if (IS_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex) &&
 						(bssGetClientCount(prAdapter, prP2pBssInfo) == 0)) {
@@ -678,6 +699,7 @@
 {
 	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
 	UINT_16 u2ReasonCode = 0;
+	BOOLEAN fgSendDeauth = FALSE; /* flag to send deauth when rx sta disassc/deauth */
 
 	do {
 		ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL));
@@ -743,9 +765,29 @@
 			if (assocProcessRxDisassocFrame(prAdapter,
 							prSwRfb,
 							prP2pBssInfo->aucBSSID, &u2ReasonCode) == WLAN_STATUS_SUCCESS) {
+
+#if CFG_SUPPORT_802_11W
+				/* AP PMF */
+				if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
+					if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) ||
+						HAL_RX_STATUS_IS_CLM_ERROR(prSwRfb->prRxStatus)) {
+						/* if cipher mismatch, or incorrect encrypt, just drop */
+						DBGLOG(P2P, ERROR, "Rx disassoc CM/CLM=1\n");
+						return;
+					}
+
+					/* 4.3.3.1 send unprotected deauth reason 6/7 */
+					DBGLOG(P2P, INFO, "deauth reason=6\n");
+					fgSendDeauth = TRUE;
+					u2ReasonCode = REASON_CODE_CLASS_2_ERR;
+					prStaRec->rPmfCfg.fgRxDeauthResp = TRUE;
+				}
+#endif
+
 				if (bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec)) {
 					/* Indicate disconnect to Host. */
-					p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, FALSE, u2ReasonCode);
+					p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, fgSendDeauth,
+						u2ReasonCode);
 					/* Deactive BSS if PWR is IDLE and no peer */
 					if (IS_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex) &&
 						(bssGetClientCount(prAdapter, prP2pBssInfo) == 0)) {
diff --git a/mgmt/rsn.c b/mgmt/rsn.c
index c34ca52..101fc52 100644
--- a/mgmt/rsn.c
+++ b/mgmt/rsn.c
@@ -1307,6 +1307,19 @@
 			} else {
 				DBGLOG(RSN, TRACE, "!RSN_AUTH_MFP - No MFPC!\n");
 			}
+		} else if ((GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P) &&
+					(GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eCurrentOPMode ==
+					(UINT_8) OP_MODE_ACCESS_POINT)) {
+			/* AP PMF */
+			if (prBssInfo->rApPmfCfg.fgMfpr) {
+				WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | ELEM_WPA_CAP_MFPR);	/* Capabilities */
+				DBGLOG(RSN, TRACE, "AP RSN_AUTH_MFP - MFPC & MFPR\n");
+			} else if (prBssInfo->rApPmfCfg.fgMfpc) {
+				WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC);	/* Capabilities */
+				DBGLOG(RSN, TRACE, "AP RSN_AUTH_MFP - MFPC\n");
+			} else {
+				DBGLOG(RSN, TRACE, "!AP RSN_AUTH_MFP - No MFPC!\n");
+			}
 		}
 #else
 		/* Capabilities */
@@ -1435,13 +1448,18 @@
 * \retval none
 */
 /*----------------------------------------------------------------------------*/
-void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, PUINT_16 pu2StatusCode)
+void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe,
+			P_STA_RECORD_T prStaRec, PUINT_16 pu2StatusCode)
 {
 
 	RSN_INFO_T rRsnIe;
+	P_BSS_INFO_T prBssInfo;
+	UINT_8 i;
+	UINT_16 statusCode;
 
 	ASSERT(prAdapter);
 	ASSERT(prIe);
+	ASSERT(prStaRec);
 	ASSERT(pu2StatusCode);
 
 	*pu2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT;
@@ -1464,6 +1482,44 @@
 
 		DBGLOG(RSN, TRACE, "RSN with CCMP-PSK\n");
 		*pu2StatusCode = WLAN_STATUS_SUCCESS;
+
+#if CFG_SUPPORT_802_11W
+		/* AP PMF */
+		/* 1st check: if already PMF connection, reject assoc req: error 30 ASSOC_REJECTED_TEMPORARILY */
+		if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
+			*pu2StatusCode = STATUS_CODE_ASSOC_REJECTED_TEMPORARILY;
+			return;
+		}
+
+		/* if RSN capability not exist, just return */
+		if (!rRsnIe.fgRsnCapPresent) {
+			*pu2StatusCode = WLAN_STATUS_SUCCESS;
+			return;
+		}
+
+		prStaRec->rPmfCfg.fgMfpc = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPC) ? 1 : 0;
+		prStaRec->rPmfCfg.fgMfpr = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPR) ? 1 : 0;
+
+		for (i = 0; i < rRsnIe.u4AuthKeyMgtSuiteCount; i++) {
+			if ((rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_802_1X_SHA256) ||
+				(rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_PSK_SHA256)) {
+				DBGLOG(RSN, INFO, "STA SHA256 support\n");
+				prStaRec->rPmfCfg.fgSha256 = TRUE;
+				break;
+			}
+		}
+
+		DBGLOG(RSN, INFO, "STA Assoc req mfpc:%d, mfpr:%d, sha256:%d, bssIndex:%d, applyPmf:%d\n",
+			prStaRec->rPmfCfg.fgMfpc, prStaRec->rPmfCfg.fgMfpr,
+			prStaRec->rPmfCfg.fgSha256, prStaRec->ucBssIndex, prStaRec->rPmfCfg.fgApplyPmf);
+
+
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
+
+		/* if PMF validation fail, return success as legacy association */
+		statusCode = rsnPmfCapableValidation(prAdapter, prBssInfo, prStaRec);
+		*pu2StatusCode = statusCode;
+#endif
 	}
 
 }
@@ -1968,11 +2024,21 @@
 /*----------------------------------------------------------------------------*/
 UINT_32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
 {
-	if (prStaRec
-	    && GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eNetworkType == (UINT_8) NETWORK_TYPE_AIS)
-		return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled;
-	else
+	/* caution: prStaRec might be null ! */
+	if (prStaRec) {
+		if (GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eNetworkType == (UINT_8) NETWORK_TYPE_AIS) {
+			return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled;
+		} else if ((GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eNetworkType == NETWORK_TYPE_P2P) &&
+				(GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->eCurrentOPMode ==
+					OP_MODE_ACCESS_POINT)) {
+			DBGLOG(RSN, INFO, "AP-STA PMF capable:%d\n", prStaRec->rPmfCfg.fgApplyPmf);
+			return prStaRec->rPmfCfg.fgApplyPmf;
+		} else {
+			return FALSE;
+		}
+	} else
 		return FALSE;
+
 }
 
 /*----------------------------------------------------------------------------*/
@@ -2393,3 +2459,403 @@
 }
 
 #endif
+
+#if CFG_SUPPORT_802_11W
+/* AP PMF */
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief This routine is called to validate setting if PMF connection capable or not
+* If AP MFPC=1, and STA MFPC=1, we let this as PMF connection
+*
+*
+* \return (none)
+*/
+/*----------------------------------------------------------------------------*/
+UINT_16 rsnPmfCapableValidation(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P_STA_RECORD_T prStaRec)
+{
+	BOOLEAN selfMfpc, selfMfpr, peerMfpc, peerMfpr;
+
+	selfMfpc = prBssInfo->rApPmfCfg.fgMfpc;
+	selfMfpr = prBssInfo->rApPmfCfg.fgMfpr;
+	peerMfpc = prStaRec->rPmfCfg.fgMfpc;
+	peerMfpr = prStaRec->rPmfCfg.fgMfpr;
+
+	DBGLOG(RSN, INFO, "AP mfpc:%d, mfpr:%d / STA mfpc:%d, mfpr:%d\n",
+		selfMfpc, selfMfpr, peerMfpc, peerMfpr);
+
+	if ((selfMfpc == TRUE) && (peerMfpc == FALSE)) {
+		if ((selfMfpr == TRUE) && (peerMfpr == FALSE)) {
+			DBGLOG(RSN, ERROR, "PMF policy violation for case 4\n");
+			return STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+		}
+
+		if (peerMfpr == TRUE) {
+			DBGLOG(RSN, ERROR, "PMF policy violation for case 7\n");
+			return STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+		}
+	}
+
+	if ((selfMfpc == TRUE) && (peerMfpc == TRUE)) {
+		DBGLOG(RSN, ERROR, "PMF Connection\n");
+		prStaRec->rPmfCfg.fgApplyPmf = TRUE;
+	}
+
+	return STATUS_CODE_SUCCESSFUL;
+
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief This routine is called to generate TIMEOUT INTERVAL IE for association resp
+* Add Timeout interval IE (56) when PMF invalid association
+*
+*
+* \return (none)
+*/
+/*----------------------------------------------------------------------------*/
+VOID rsnPmfGenerateTimeoutIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo)
+{
+	IE_TIMEOUT_INTERVAL_T *prTimeout;
+	P_STA_RECORD_T prStaRec;
+
+	ASSERT(prAdapter);
+	ASSERT(prMsduInfo);
+
+	DBGLOG(RSN, INFO, "rsnPmfGenerateTimeoutIE\n");
+
+	prTimeout = (IE_TIMEOUT_INTERVAL_T *)
+	    (((PUINT_8) prMsduInfo->prPacket) + prMsduInfo->u2FrameLength);
+
+	prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex);
+
+	/* only when PMF connection, and association error code is 30 */
+	if ((rsnCheckBipKeyInstalled(prAdapter, prStaRec) == TRUE) &&
+		(prStaRec->u2StatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY)) {
+
+		prTimeout->ucId = ELEM_ID_TIMEOUT_INTERVAL;
+		prTimeout->ucLength = ELEM_MAX_LEN_TIMEOUT_IE;
+		prTimeout->ucType = IE_TIMEOUT_INTERVAL_TYPE_ASSOC_COMEBACK;
+		prTimeout->u4Value = 1<<10;
+		prMsduInfo->u2FrameLength += IE_SIZE(prTimeout);
+	}
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+*
+* \brief This routine is called to check the Sa query timeout.
+* check if total retry time is greater than 1000ms
+*
+* \retval 1: retry max timeout. 0: not timeout
+* \note
+*      Called by: AAA module, Handle by Sa Query timeout
+*/
+/*----------------------------------------------------------------------------*/
+UINT_8 rsnApCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
+{
+	P_BSS_INFO_T prBssInfo;
+	UINT_32 now;
+
+	GET_CURRENT_SYSTIME(&now);
+
+	if (CHECK_FOR_TIMEOUT(now, prStaRec->rPmfCfg.u4SAQueryStart, TU_TO_MSEC(1000))) {
+		DBGLOG(RSN, INFO, "association SA Query timed out\n");
+
+		/* XXX PMF TODO how to report STA REC disconnect?? */
+		/* when SAQ retry count timeout, clear this STA */
+		prStaRec->rPmfCfg.ucSAQueryTimedOut = 1;
+		prStaRec->rPmfCfg.u2TransactionID = 0;
+		prStaRec->rPmfCfg.u4SAQueryCount = 0;
+		cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer);
+
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
+
+		/* refer to p2pRoleFsmRunEventRxDeauthentication*/
+		if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) {
+			if (bssRemoveClient(prAdapter, prBssInfo, prStaRec)) {
+				/* Indicate disconnect to Host. */
+				p2pFuncDisconnect(prAdapter, prBssInfo, prStaRec, FALSE, 0);
+				/* Deactive BSS if PWR is IDLE and no peer */
+				if (IS_NET_PWR_STATE_IDLE(prAdapter, prBssInfo->ucBssIndex) &&
+					(bssGetClientCount(prAdapter, prBssInfo) == 0)) {
+					/* All Peer disconnected !! Stop BSS now!! */
+					p2pFuncStopComplete(prAdapter, prBssInfo);
+				}
+			}
+		}
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+*
+* \brief This routine is called to start the 802.11w sa query timer.
+* This routine is triggered every 201ms, and every time enter function, check max timeout
+*
+* \note
+*      Called by: AAA module, Handle TX SAQ request
+*/
+/*----------------------------------------------------------------------------*/
+void rsnApStartSaQueryTimer(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN ULONG ulParamPtr)
+{
+	P_BSS_INFO_T prBssInfo;
+	P_MSDU_INFO_T prMsduInfo;
+	P_ACTION_SA_QUERY_FRAME prTxFrame;
+	UINT_16 u2PayloadLen;
+
+	ASSERT(prStaRec);
+
+	DBGLOG(RSN, INFO, "MFP: AP Start Sa Query\n");
+
+	prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex);
+
+	if (prStaRec->rPmfCfg.u4SAQueryCount > 0 && rsnApCheckSaQueryTimeout(prAdapter, prStaRec)) {
+		DBGLOG(RSN, INFO, "MFP: retry max timeout, u4SaQueryCount count =%lu\n",
+			prStaRec->rPmfCfg.u4SAQueryCount);
+		return;
+	}
+
+	prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN);
+
+	if (!prMsduInfo)
+		return;
+
+	prTxFrame = (P_ACTION_SA_QUERY_FRAME)
+	    ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
+
+	prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION;
+	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec))
+		prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
+	COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr);
+	COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr);
+	COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucOwnMacAddr);
+
+	prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION;
+	prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST;
+
+	if (prStaRec->rPmfCfg.u4SAQueryCount == 0)
+		GET_CURRENT_SYSTIME(&prStaRec->rPmfCfg.u4SAQueryStart);
+
+	/* if retry, transcation id ++ */
+	if (prStaRec->rPmfCfg.u4SAQueryCount) {
+		prStaRec->rPmfCfg.u2TransactionID++;
+	} else {
+		/* if first SAQ request, random pick transaction id */
+		prStaRec->rPmfCfg.u2TransactionID = (UINT_16) (kalRandomNumber() & 0xFFFF);
+	}
+
+	/* trnsform U16 to U8 array */
+	prTxFrame->ucTransId[0] = ((prStaRec->rPmfCfg.u2TransactionID & 0xff00) >> 8);
+	prTxFrame->ucTransId[1] = ((prStaRec->rPmfCfg.u2TransactionID & 0x00ff) >> 0);
+
+	prStaRec->rPmfCfg.u4SAQueryCount++;
+
+	u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN;
+
+	/* 4 <3> Update information of MSDU_INFO_T */
+	TX_SET_MMPDU(prAdapter,
+		     prMsduInfo,
+		     prStaRec->ucBssIndex,
+		     prStaRec->ucIndex,
+		     WLAN_MAC_MGMT_HEADER_LEN, WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, MSDU_RATE_MODE_AUTO);
+
+	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
+		DBGLOG(RSN, INFO, "SAQ Set MSDU_OPT_PROTECTED_FRAME\n");
+		nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
+	}
+	/* 4 Enqueue the frame to send this action frame. */
+	nicTxEnqueueMsdu(prAdapter, prMsduInfo);
+
+	DBGLOG(RSN, INFO, "AP Set SA Query timer %lu (%d Tu)\n", prStaRec->rPmfCfg.u4SAQueryCount, 201);
+
+	cnmTimerStartTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer, TU_TO_MSEC(201));
+
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+*
+* \brief This routine is called to start the 802.11w TX SA query.
+*
+*
+* \note
+*      Called by: AAA module, Handle Tx action frame request
+*/
+/*----------------------------------------------------------------------------*/
+void rsnApStartSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
+{
+	ASSERT(prStaRec);
+
+	DBGLOG(RSN, INFO, "rsnApStartSaQuery\n");
+
+	if (prStaRec) {
+		cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer);
+		cnmTimerInitTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer,
+			(PFN_MGMT_TIMEOUT_FUNC)rsnApStartSaQueryTimer, (ULONG) prStaRec);
+	}
+
+	if (prStaRec->rPmfCfg.u4SAQueryCount == 0)
+		rsnApStartSaQueryTimer(prAdapter, prStaRec, (ULONG) NULL);
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+*
+* \brief This routine is called to stop the 802.11w SA query.
+*
+*
+* \note
+*      Called by: AAA module, stop TX SAQ if receive correct SAQ response
+*/
+/*----------------------------------------------------------------------------*/
+void rsnApStopSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec)
+{
+	ASSERT(prStaRec);
+
+	cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer);
+	prStaRec->rPmfCfg.u2TransactionID = 0;
+	prStaRec->rPmfCfg.u4SAQueryCount = 0;
+	prStaRec->rPmfCfg.ucSAQueryTimedOut = 0;
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+*
+* \brief This routine is called to process the 802.11w sa query action frame.
+*
+*
+* \note
+*      Called by: AAA module, Handle Rx action request
+*/
+/*----------------------------------------------------------------------------*/
+void rsnApSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
+{
+	P_BSS_INFO_T prBssInfo;
+	P_MSDU_INFO_T prMsduInfo;
+	P_ACTION_SA_QUERY_FRAME prRxFrame = NULL;
+	UINT_16 u2PayloadLen;
+	P_STA_RECORD_T prStaRec;
+	P_ACTION_SA_QUERY_FRAME prTxFrame;
+
+	prBssInfo = prAdapter->prAisBssInfo;
+	ASSERT(prBssInfo);
+
+	if (!prSwRfb)
+		return;
+
+	prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader;
+	if (!prRxFrame)
+		return;
+
+	prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
+	if (!prStaRec)		/* Todo:: for not AIS check */
+		return;
+
+	DBGLOG(RSN, INFO, "IEEE 802.11: Received SA Query Request from " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
+
+	DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
+
+	if (!rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
+		DBGLOG(RSN, INFO, "IEEE 802.11: Ignore SA Query Request non-PMF STA "
+		       MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
+		return;
+	}
+
+	DBGLOG(RSN, INFO, "IEEE 802.11: Sending SA Query Response to " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
+
+	prMsduInfo = (P_MSDU_INFO_T) cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN);
+
+	if (!prMsduInfo)
+		return;
+
+	prTxFrame = (P_ACTION_SA_QUERY_FRAME)
+	    ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD);
+
+	prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION;
+	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec))
+		prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME;
+	COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr);
+	COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucBSSID);
+	COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID);
+
+	prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION;
+	prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE;
+
+	kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
+
+	u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN;
+
+	/* 4 <3> Update information of MSDU_INFO_T */
+	TX_SET_MMPDU(prAdapter,
+		     prMsduInfo,
+		     prStaRec->ucBssIndex,
+		     prStaRec->ucIndex,
+		     WLAN_MAC_MGMT_HEADER_LEN, WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, MSDU_RATE_MODE_AUTO);
+
+	if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) {
+		DBGLOG(RSN, INFO, "SAQ Set MSDU_OPT_PROTECTED_FRAME\n");
+		nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE);
+	}
+
+	/* 4 Enqueue the frame to send this action frame. */
+	nicTxEnqueueMsdu(prAdapter, prMsduInfo);
+
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+*
+* \brief This routine is called to process the 802.11w sa query action frame.
+*
+*
+* \note
+*      Called by: AAA module, Handle Rx action request
+*/
+/*----------------------------------------------------------------------------*/
+void rsnApSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb)
+{
+	P_ACTION_SA_QUERY_FRAME prRxFrame;
+	P_STA_RECORD_T prStaRec;
+	UINT_16 u2SwapTrID;
+
+	prRxFrame = (P_ACTION_SA_QUERY_FRAME) prSwRfb->pvHeader;
+	prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx);
+
+	if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) {
+		DBGLOG(RSN, INFO, "IEEE 802.11: Too short SA Query Action frame (len=%lu)\n",
+		       (unsigned long)prSwRfb->u2PacketLen);
+		return;
+	}
+
+	if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) {
+		rsnSaQueryRequest(prAdapter, prSwRfb);
+		return;
+	}
+
+	if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) {
+		DBGLOG(RSN, INFO, "IEEE 802.11: Unexpected SA Query Action %d\n", prRxFrame->ucAction);
+		return;
+	}
+
+	DBGLOG(RSN, INFO, "IEEE 802.11: Received SA Query Response from " MACSTR "\n", MAC2STR(prStaRec->aucMacAddr));
+
+	DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN);
+
+	/* MLME-SAQuery.confirm */
+	/* transform to network byte order */
+	u2SwapTrID = htons(prStaRec->rPmfCfg.u2TransactionID);
+	if (kalMemCmp((UINT_8 *)&u2SwapTrID, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN) == 0) {
+		DBGLOG(RSN, INFO, "Reply to SA Query received\n");
+		rsnApStopSaQuery(prAdapter, prStaRec);
+	} else {
+		DBGLOG(RSN, INFO, "IEEE 802.11: No matching SA Query transaction identifier found\n");
+	}
+
+}
+
+#endif /* CFG_SUPPORT_802_11W */
+
diff --git a/nic/nic_rx.c b/nic/nic_rx.c
index 5019455..914f272 100644
--- a/nic/nic_rx.c
+++ b/nic/nic_rx.c
@@ -3308,6 +3308,13 @@
 				    prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection /* Use MFP */) {
 					/* MFP test plan 5.3.3.4 */
 					rsnSaQueryAction(prAdapter, prSwRfb);
+				} else if ((prBssInfo->eNetworkType == NETWORK_TYPE_P2P) &&
+					(prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) {
+					/* AP PMF */
+					if (rsnCheckBipKeyInstalled(prAdapter, prSwRfb->prStaRec)) {
+						/* MFP test plan 4.3.3.4 */
+						rsnApSaQueryAction(prAdapter, prSwRfb);
+					}
 				}
 			}
 		}
diff --git a/os/linux/gl_p2p.c b/os/linux/gl_p2p.c
index 76ea3d4..1f5d119 100644
--- a/os/linux/gl_p2p.c
+++ b/os/linux/gl_p2p.c
@@ -153,6 +153,7 @@
 	.get_key = mtk_p2p_cfg80211_get_key,
 	.del_key = mtk_p2p_cfg80211_del_key,
 	.set_default_key = mtk_p2p_cfg80211_set_default_key,
+	.set_default_mgmt_key = mtk_p2p_cfg80211_set_mgmt_key,
 	.join_ibss = mtk_p2p_cfg80211_join_ibss,
 	.leave_ibss = mtk_p2p_cfg80211_leave_ibss,
 	.set_tx_power = mtk_p2p_cfg80211_set_txpower,
diff --git a/os/linux/gl_p2p_cfg80211.c b/os/linux/gl_p2p_cfg80211.c
index b02e43c..a98d31a 100644
--- a/os/linux/gl_p2p_cfg80211.c
+++ b/os/linux/gl_p2p_cfg80211.c
@@ -588,10 +588,10 @@
 #if DBG
 	DBGLOG(RSN, TRACE, "mtk_p2p_cfg80211_add_key\n");
 	if (mac_addr) {
-		DBGLOG(RSN, TRACE,
+		DBGLOG(RSN, INFO,
 		       "keyIdx = %d pairwise = %d mac = " MACSTR "\n", key_index, pairwise, MAC2STR(mac_addr));
 	} else {
-		DBGLOG(RSN, TRACE, "keyIdx = %d pairwise = %d null mac\n", key_index, pairwise);
+		DBGLOG(RSN, INFO, "keyIdx = %d pairwise = %d null mac\n", key_index, pairwise);
 	}
 	DBGLOG(RSN, TRACE, "Cipher = %x\n", params->cipher);
 	DBGLOG_MEM8(RSN, TRACE, params->key, params->key_len);
@@ -790,6 +790,23 @@
 	return i4Rst;
 }
 
+/*----------------------------------------------------------------------------*/
+/*!
+ * @brief This routine is responsible for setting the default mgmt key index
+ *
+ * @param
+ *
+ * @retval 0:       successful
+ *         others:  failure
+ */
+/*----------------------------------------------------------------------------*/
+int mtk_p2p_cfg80211_set_mgmt_key(struct wiphy *wiphy, struct net_device *dev, u8 key_index)
+{
+	DBGLOG(RSN, INFO, "mtk_p2p_cfg80211_set_mgmt_key, kid:%d\n", key_index);
+
+	return 0;
+}
+
 #if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
 int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
 		const u8 *mac, struct station_info *sinfo)
diff --git a/os/linux/include/gl_p2p_ioctl.h b/os/linux/include/gl_p2p_ioctl.h
index a277288..414f383 100644
--- a/os/linux/include/gl_p2p_ioctl.h
+++ b/os/linux/include/gl_p2p_ioctl.h
@@ -405,6 +405,10 @@
 int
 mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy,
 				 struct net_device *netdev, u8 key_index, bool unicast, bool multicast);
+
+int
+mtk_p2p_cfg80211_set_mgmt_key(struct wiphy *wiphy, struct net_device *dev, u8 key_index);
+
 #if KERNEL_VERSION(3, 16, 0) <= CFG80211_VERSION_CODE
 int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
 				const u8 *mac, struct station_info *sinfo);