[WCNCR00148136] softap: add dfs master feature

[Description]
Add dfs master feature
1. Add commands and events for dfs master
2. Add dfs driver flow

Change-Id: I0701c8bc689ec21530b09b05922cd9e71622b0e8
Feature: softap
Signed-off-by: Chun Lee <chun.lee@mediatek.com>
CR-Id: WCNCR00148136
diff --git a/common/wlan_lib.c b/common/wlan_lib.c
index e74b4d0..cff2fc4 100644
--- a/common/wlan_lib.c
+++ b/common/wlan_lib.c
@@ -165,6 +165,9 @@
 	wlanoidRftestSetTestMode,
 	wlanoidRftestSetAbortTestMode,
 	wlanoidSetAcpiDevicePowerState,
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	wlanoidQuerySetRddReport,
+#endif
 };
 #if CFG_SUPPORT_COMPRESSION_FW_OPTION
 #define COMPRESSION_OPTION_OFFSET   4
diff --git a/common/wlan_oid.c b/common/wlan_oid.c
index 4defa5a..40ef18b 100644
--- a/common/wlan_oid.c
+++ b/common/wlan_oid.c
@@ -11926,6 +11926,75 @@
 	return rWlanStatus;
 }
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief This routine is called to set rdd report.
+*
+* \param[in] pvAdapter Pointer to the Adapter structure.
+* \param[out] pvQueryBuf A pointer to the buffer that holds the result of
+*                           the query.
+* \param[in] u4QueryBufLen The length of the query buffer.
+* \param[out] pu4QueryInfoLen If the call is successful, returns the number of
+*                            bytes written into the query buffer. If the call
+*                            failed due to invalid length of the query buffer,
+*                            returns the amount of storage needed.
+*
+* \retval WLAN_STATUS_SUCCESS
+* \retval WLAN_STATUS_INVALID_LENGTH
+*/
+/*----------------------------------------------------------------------------*/
+WLAN_STATUS
+wlanoidQuerySetRddReport(IN P_ADAPTER_T prAdapter, IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen,
+			 OUT PUINT_32 pu4SetInfoLen)
+{
+	P_PARAM_CUSTOM_SET_RDD_REPORT_T prSetRddReport;
+	P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl;
+	WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS;
+
+	DEBUGFUNC("wlanoidQuerySetRddReport");
+
+	ASSERT(prAdapter);
+	ASSERT(pu4SetInfoLen);
+
+	*pu4SetInfoLen = sizeof(P_PARAM_CUSTOM_SET_RDD_REPORT_T);
+
+	/*if (u4SetBufferLen < sizeof(P_PARAM_CUSTOM_SET_RDD_REPORT_T))*/
+		/*return WLAN_STATUS_INVALID_LENGTH;*/
+
+	ASSERT(pvSetBuffer);
+
+	prSetRddReport = (P_PARAM_CUSTOM_SET_RDD_REPORT_T) pvSetBuffer;
+
+	prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG,
+					sizeof(P_CMD_RDD_ON_OFF_CTRL_T));
+
+	prCmdRddOnOffCtrl->ucDfsCtrl = RDD_RADAR_EMULATE;
+
+	prCmdRddOnOffCtrl->ucRddIdx = prSetRddReport->ucDbdcIdx;
+
+	if (prCmdRddOnOffCtrl->ucRddIdx)
+		prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_1;
+	else
+		prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_0;
+
+	DBGLOG(INIT, INFO, "MT6632 : wlanoidQuerySetRddReport -  DFS ctrl: %.d, RDD index: %d\n",
+	prCmdRddOnOffCtrl->ucDfsCtrl, prCmdRddOnOffCtrl->ucRddIdx);
+
+	rWlanStatus = wlanSendSetQueryCmd(prAdapter,
+					CMD_ID_RDD_ON_OFF_CTRL,
+					TRUE,   /* fgSetQuery Bit:  True->write  False->read*/
+					FALSE,   /* fgNeedResp */
+					FALSE,   /* fgIsOid*/
+					NULL,
+					NULL,
+					sizeof(CMD_RDD_ON_OFF_CTRL_T),
+					(PUINT_8) (prCmdRddOnOffCtrl), NULL, 0);
+
+	return rWlanStatus;
+}
+#endif
+
 /*----------------------------------------------------------------------------*/
 /*!
 * \brief This routine is used to turn radio off.
diff --git a/include/config.h b/include/config.h
index b7b2581..a7cb895 100644
--- a/include/config.h
+++ b/include/config.h
@@ -154,6 +154,7 @@
 
 #define CFG_SUPPORT_RRM             0	/* Radio Reasource Measurement (802.11k) */
 #define CFG_SUPPORT_DFS             1	/* DFS (802.11h) */
+#define CFG_SUPPORT_DFS_MASTER      0
 
 #if (CFG_SUPPORT_DFS == 1)	/* Add by Enlai */
 #define CFG_SUPPORT_QUIET           0	/* Quiet (802.11h) */
diff --git a/include/mgmt/cnm.h b/include/mgmt/cnm.h
index 2b92884..5695b9c 100644
--- a/include/mgmt/cnm.h
+++ b/include/mgmt/cnm.h
@@ -89,6 +89,9 @@
 	CH_REQ_TYPE_P2P_LISTEN,
 	CH_REQ_TYPE_OFFCHNL_TX,
 	CH_REQ_TYPE_GO_START_BSS,
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	CH_REQ_TYPE_DFS_CAC,
+#endif
 	CH_REQ_TYPE_NUM
 } ENUM_CH_REQ_TYPE_T, *P_ENUM_CH_REQ_TYPE_T;
 
@@ -211,6 +214,12 @@
 
 VOID cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID cnmRadarDetectEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent);
+
+VOID cnmCsaDoneEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent);
+#endif
+
 BOOLEAN
 cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, PUINT_8 pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO);
 
diff --git a/include/mgmt/hem_mbox.h b/include/mgmt/hem_mbox.h
index 314995e..52a2f65 100644
--- a/include/mgmt/hem_mbox.h
+++ b/include/mgmt/hem_mbox.h
@@ -89,6 +89,10 @@
 	MID_CNM_P2P_CH_GRANT,	/* CNM notify P2P for indicating channel granted */
 	MID_CNM_BOW_CH_GRANT,	/* CNM notify BOW for indicating channel granted */
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	MID_CNM_P2P_RADAR_DETECT,
+	MID_CNM_P2P_CSA_DONE,
+#endif
     /*--------------------------------------------------*/
 	/* SCN Module Mailbox Messages                      */
     /*--------------------------------------------------*/
@@ -150,6 +154,10 @@
 	MID_MNY_P2P_START_AP,
 	MID_MNY_P2P_DEL_IFACE,
 	MID_MNY_P2P_MGMT_FRAME_UPDATE,
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	MID_MNY_P2P_DFS_CAC,
+	MID_MNY_P2P_SET_NEW_CHANNEL,
+#endif
 #if CFG_SUPPORT_WFD
 	MID_MNY_P2P_WFD_CFG_UPDATE,
 #endif
diff --git a/include/mgmt/p2p_func.h b/include/mgmt/p2p_func.h
index 3d25b38..81ae4a0 100644
--- a/include/mgmt/p2p_func.h
+++ b/include/mgmt/p2p_func.h
@@ -136,6 +136,12 @@
 
 VOID p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID p2pFuncStartRdd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx);
+
+VOID p2pFuncDfsSwitchCh(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P2P_CHNL_REQ_INFO_T rP2pChnlReqInfo);
+#endif
+
 VOID p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN UINT_8 ucRoleIdx, IN P_RF_CHANNEL_INFO_T prRfChannelInfo);
 
 BOOLEAN p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN P_P2P_JOIN_INFO_T prJoinInfo);
diff --git a/include/mgmt/p2p_role.h b/include/mgmt/p2p_role.h
index 0a06eb7..ea224ba 100644
--- a/include/mgmt/p2p_role.h
+++ b/include/mgmt/p2p_role.h
@@ -166,6 +166,31 @@
 	INT_32 i4InactiveTimeout;
 } MSG_P2P_START_AP_T, *P_MSG_P2P_START_AP_T;
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+typedef struct _MSG_P2P_DFS_CAC_T {
+	MSG_HDR_T rMsgHdr;
+	ENUM_CHANNEL_WIDTH_T eChannelWidth;
+	UINT_8 ucRoleIdx;
+} MSG_P2P_DFS_CAC_T, *P_MSG_P2P_DFS_CAC_T;
+
+typedef struct _MSG_P2P_RADAR_DETECT_T {
+	MSG_HDR_T rMsgHdr;
+	UINT_8 ucBssIndex;
+} MSG_P2P_RADAR_DETECT_T, *P_MSG_P2P_RADAR_DETECT_T;
+
+typedef struct _MSG_P2P_SET_NEW_CHANNEL_T {
+	MSG_HDR_T rMsgHdr;
+	ENUM_CHANNEL_WIDTH_T eChannelWidth;
+	UINT_8 ucRoleIdx;
+	UINT_8 ucBssIndex;
+} MSG_P2P_SET_NEW_CHANNEL_T, *P_MSG_P2P_SET_NEW_CHANNEL_T;
+
+typedef struct _MSG_P2P_CSA_DONE_T {
+	MSG_HDR_T rMsgHdr;
+	UINT_8 ucBssIndex;
+} MSG_P2P_CSA_DONE_T, *P_MSG_P2P_CSA_DONE_T;
+#endif
+
 typedef struct _MSG_P2P_DEL_IFACE_T {
 	MSG_HDR_T rMsgHdr;
 	UINT_8 ucRoleIdx;
@@ -199,6 +224,10 @@
 	P2P_ROLE_STATE_REQING_CHANNEL,
 	P2P_ROLE_STATE_AP_CHNL_DETECTION,	/* Requesting Channel to Send Specific Frame. */
 	P2P_ROLE_STATE_GC_JOIN,
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	P2P_ROLE_STATE_DFS_CAC,
+	P2P_ROLE_STATE_SWITCH_CHANNEL,
+#endif
 	P2P_ROLE_STATE_NUM
 } ENUM_P2P_ROLE_STATE_T, *P_ENUM_P2P_ROLE_STATE_T;
 
@@ -285,6 +314,16 @@
 
 VOID p2pRoleFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID p2pRoleFsmRunEventDfsCac(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr);
+
+VOID p2pRoleFsmRunEventRadarDet(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr);
+
+VOID p2pRoleFsmRunEventSetNewChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr);
+
+VOID p2pRoleFsmRunEventCsaDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr);
+#endif
+
 VOID p2pRoleFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr);
 
 VOID
diff --git a/include/mgmt/p2p_role_state.h b/include/mgmt/p2p_role_state.h
index 2edf010..a6fad85 100644
--- a/include/mgmt/p2p_role_state.h
+++ b/include/mgmt/p2p_role_state.h
@@ -94,6 +94,32 @@
 			  IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo,
 			  IN P_P2P_JOIN_INFO_T prJoinInfo, IN ENUM_P2P_ROLE_STATE_T eNextState);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID
+p2pRoleStateInit_DFS_CAC(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo);
+
+VOID
+p2pRoleStateAbort_DFS_CAC(IN P_ADAPTER_T prAdapter,
+				 IN P_BSS_INFO_T prP2pRoleBssInfo,
+				 IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, IN ENUM_P2P_ROLE_STATE_T eNextState);
+
+VOID
+p2pRoleStateInit_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo);
+
+VOID
+p2pRoleStateAbort_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter,
+				 IN P_BSS_INFO_T prP2pRoleBssInfo,
+				 IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, IN ENUM_P2P_ROLE_STATE_T eNextState);
+
+VOID
+p2pRoleStatePrepare_To_DFS_CAC_STATE(IN P_ADAPTER_T prAdapter,
+					    IN P_BSS_INFO_T prBssInfo,
+					    IN ENUM_CHANNEL_WIDTH_T rChannelWidth,
+					    IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo,
+					    OUT P_P2P_CHNL_REQ_INFO_T prChnlReqInfo);
+
+#endif
+
 VOID
 p2pRoleStatePrepare_To_REQING_CHANNEL_STATE(IN P_ADAPTER_T prAdapter,
 					    IN P_BSS_INFO_T prBssInfo,
diff --git a/include/mgmt/rlm.h b/include/mgmt/rlm.h
index 3a374c1..eebb855 100644
--- a/include/mgmt/rlm.h
+++ b/include/mgmt/rlm.h
@@ -289,6 +289,10 @@
 
 BOOLEAN rlmParseCheckMTKOuiIE(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, IN PUINT_32 pu4Cap);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID rlmGenerateCsaIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo);
+#endif
+
 VOID rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength);
 
 VOID rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, PUINT_8 pucIE, UINT_16 u2IELength);
diff --git a/include/nic/adapter.h b/include/nic/adapter.h
index faf317e..f00b541 100644
--- a/include/nic/adapter.h
+++ b/include/nic/adapter.h
@@ -243,6 +243,10 @@
 	ENUM_OP_MODE_T eIntendOPMode;
 #endif
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	BOOLEAN fgIsDfsActive;
+#endif
+
 	BOOLEAN fgIsInUse;	/* For CNM to assign BSS_INFO */
 	BOOLEAN fgIsNetActive;	/* TRUE if this network has been activated */
 
@@ -744,6 +748,11 @@
 	UINT_8 aucMtkFeature[4];
 #endif
 
+	BOOLEAN fgCsaInProgress;
+	UINT_8 ucChannelSwitchMode;
+	UINT_8 ucNewChannelNumber;
+	UINT_8 ucChannelSwitchCount;
+
 	UINT_32 u4HifIstLoopCount;
 	UINT_32 u4Rx2OsLoopCount;
 	UINT_32 u4HifTxloopCount;
diff --git a/include/nic/mac.h b/include/nic/mac.h
index fe90d83..4891f5f 100644
--- a/include/nic/mac.h
+++ b/include/nic/mac.h
@@ -1234,6 +1234,9 @@
 #define MTK_SYNERGY_CAP2                            0x0
 #define MTK_SYNERGY_CAP3                            0x0
 
+/* 802.11h CSA element */
+#define ELEM_MIN_LEN_CSA                            3
+
 /* 3 Management frame body components (III): 7.4 Action frame format details. */
 /* 7.4.1 Spectrum Measurement Action frame details */
 #define ACTION_MEASUREMENT_REQ                      0	/* Spectrum measurement request */
@@ -2617,6 +2620,8 @@
 
 #define MTK_OUI_IE(fp)          ((P_IE_MTK_OUI_T) fp)
 
+#define CSA_IE(fp)              ((P_IE_CHANNEL_SWITCH_T) fp)
+
 #define SUPPORTED_CHANNELS_IE(fp) ((P_IE_SUPPORTED_CHANNELS_T)fp)
 #define TIMEOUT_INTERVAL_IE(fp)	((IE_TIMEOUT_INTERVAL_T *)fp)
 
diff --git a/include/nic_cmd_event.h b/include/nic_cmd_event.h
index a30ca6b..077c143 100644
--- a/include/nic_cmd_event.h
+++ b/include/nic_cmd_event.h
@@ -123,6 +123,11 @@
 #define RDD_PULSE_OFFSET6               6
 #define RDD_PULSE_OFFSET7               7
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+#define RDD_IN_SEL_0                    0
+#define RDD_IN_SEL_1                    1
+#endif
+
 #if CFG_SUPPORT_QA_TOOL
 #define IQ_FILE_LINE_OFFSET     18
 #define IQ_FILE_IQ_STR_LEN	 8
@@ -505,6 +510,10 @@
 	CMD_ID_GET_BUG_REPORT = 0x89,	/* 0x89 (Query) */
 	CMD_ID_GET_NIC_CAPABILITY_V2 = 0x8A,/* 0x8A (Query) */
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	CMD_ID_RDD_ON_OFF_CTRL = 0x8F, /* 0x8F(Set) */
+#endif
+
 #if CFG_SUPPORT_CAL_RESULT_BACKUP_TO_HOST
 	CMD_ID_CAL_BACKUP_IN_HOST_V2 = 0xAE,	/* 0xAE (Set / Query) */
 #endif
@@ -611,6 +620,11 @@
 	EVENT_ID_MU_GET_LQ = 0x54,
 #endif
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	EVENT_ID_RDD_REPORT = 0x60,
+	EVENT_ID_CSA_DONE = 0x61,
+#endif
+
 	EVENT_ID_TDLS = 0x80,	/* TDLS event_id */
 
 	EVENT_ID_UPDATE_COEX_PHYRATE = 0x90,	/* 0x90 (Unsolicited) */
@@ -1562,6 +1576,15 @@
 	UINT_8 ucReserved[1];
 } CMD_BT_OVER_WIFI, *P_CMD_BT_OVER_WIFI;
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+typedef struct _CMD_RDD_ON_OFF_CTRL_T {
+	UINT_8 ucDfsCtrl;
+	UINT_8 ucRddIdx;
+	UINT_8 ucRddInSel;
+	UINT_8 ucReserve[1];
+} CMD_RDD_ON_OFF_CTRL_T, *P_CMD_RDD_ON_OFF_CTRL_T;
+#endif
+
 /* EVENT_BT_OVER_WIFI */
 typedef struct _EVENT_BT_OVER_WIFI {
 	UINT_8 ucLinkStatus;
@@ -1755,6 +1778,16 @@
 	TXS_IS_EXIST
 } ENUM_TXS_CONTROL_FLAG_T, *P_ENUM_TXS_CONTROL_FLAG_T;
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+typedef enum _ENUM_DFS_CTRL_T {
+	RDD_STOP = 0,
+	RDD_START,
+	RDD_DET_MODE,
+	RDD_RADAR_EMULATE,
+	RDD_START_TXQ
+} ENUM_DFS_CTRL_T, *P_ENUM_DFS_CTRL_T;
+#endif
+
 typedef struct _CMD_BSS_ACTIVATE_CTRL {
 	UINT_8 ucBssIndex;
 	UINT_8 ucActive;
diff --git a/include/wlan_oid.h b/include/wlan_oid.h
index 0f77fd9..7f3527e 100644
--- a/include/wlan_oid.h
+++ b/include/wlan_oid.h
@@ -719,6 +719,11 @@
 	INT_8 cTxPwr5GHT40_MCS7;
 } PARAM_CUSTOM_SET_TX_TARGET_POWER_T, *P_PARAM_CUSTOM_SET_TX_TARGET_POWER_T;
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+typedef struct _PARAM_CUSTOM_SET_RDD_REPORT_T {
+	UINT_8 ucDbdcIdx; /* 0:Band 0, 1: Band1 */
+} PARAM_CUSTOM_SET_RDD_REPORT_T, *P_PARAM_CUSTOM_SET_RDD_REPORT_T;
+#endif
 
 typedef struct _PARAM_CUSTOM_ACCESS_RX_STAT {
 	UINT_32 u4SeqNum;
@@ -2734,6 +2739,12 @@
 wlanoidQuerySetTxTargetPower(IN P_ADAPTER_T prAdapter,
 			IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+WLAN_STATUS
+wlanoidQuerySetRddReport(IN P_ADAPTER_T prAdapter,
+			IN PVOID pvSetBuffer, IN UINT_32 u4SetBufferLen, OUT PUINT_32 pu4SetInfoLen);
+#endif
+
 #if CFG_AUTO_CHANNEL_SEL_SUPPORT
 WLAN_STATUS
 wlanoidQueryLteSafeChannel(IN P_ADAPTER_T prAdapter,
diff --git a/mgmt/bss.c b/mgmt/bss.c
index 748d641..1e011db 100644
--- a/mgmt/bss.c
+++ b/mgmt/bss.c
@@ -133,6 +133,9 @@
 #if CFG_SUPPORT_MTK_SYNERGY
 	, {(ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI), NULL, rlmGenerateMTKOuiIE}	/* 221 */
 #endif
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	, {(ELEM_HDR_LEN + ELEM_MIN_LEN_CSA), NULL, rlmGenerateCsaIE}            /* 37 */
+#endif
 
 };
 
diff --git a/mgmt/cnm.c b/mgmt/cnm.c
index e6243e2..3c47e49 100644
--- a/mgmt/cnm.c
+++ b/mgmt/cnm.c
@@ -409,6 +409,60 @@
 	prCnmInfo->fgChGranted = TRUE;
 }
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID cnmRadarDetectEvent(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
+{
+	P_BSS_INFO_T prBssInfo;
+	P_MSG_P2P_RADAR_DETECT_T prP2pRddDetMsg;
+	UINT_8 ucBssIndex;
+
+	DBGLOG(CNM, INFO, "cnmRadarDetectEvent.\n");
+
+	prP2pRddDetMsg = (P_MSG_P2P_RADAR_DETECT_T) cnmMemAlloc(prAdapter,
+					RAM_TYPE_MSG, sizeof(P_MSG_P2P_RADAR_DETECT_T));
+
+	prP2pRddDetMsg->rMsgHdr.eMsgId = MID_CNM_P2P_RADAR_DETECT;
+
+	for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) {
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex);
+
+		if (prBssInfo && prBssInfo->fgIsDfsActive) {
+			prP2pRddDetMsg->ucBssIndex = ucBssIndex;
+			break;
+		}
+	}
+
+	mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prP2pRddDetMsg, MSG_SEND_METHOD_BUF);
+}
+
+VOID cnmCsaDoneEvent(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent)
+{
+	P_BSS_INFO_T prBssInfo;
+	P_MSG_P2P_CSA_DONE_T prP2pCsaDoneMsg;
+	UINT_8 ucBssIndex;
+
+	DBGLOG(CNM, INFO, "cnmCsaDoneEvent.\n");
+
+	prP2pCsaDoneMsg = (P_MSG_P2P_CSA_DONE_T) cnmMemAlloc(prAdapter,
+					RAM_TYPE_MSG, sizeof(P_MSG_P2P_CSA_DONE_T));
+
+	prAdapter->rWifiVar.fgCsaInProgress = FALSE;
+
+	prP2pCsaDoneMsg->rMsgHdr.eMsgId = MID_CNM_P2P_CSA_DONE;
+
+	for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) {
+		prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex);
+
+		if (prBssInfo && prBssInfo->fgIsDfsActive) {
+			prP2pCsaDoneMsg->ucBssIndex = ucBssIndex;
+			break;
+		}
+	}
+
+	mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prP2pCsaDoneMsg, MSG_SEND_METHOD_BUF);
+}
+#endif
+
 /*----------------------------------------------------------------------------*/
 /*!
 * @brief This function is invoked for P2P or BOW networks
diff --git a/mgmt/hem_mbox.c b/mgmt/hem_mbox.c
index d8acb48..af49380 100644
--- a/mgmt/hem_mbox.c
+++ b/mgmt/hem_mbox.c
@@ -146,6 +146,13 @@
 	(PUINT_8) DISP_STRING("MID_MNY_P2P_NET_DEV_REGISTER"),
 	(PUINT_8) DISP_STRING("MID_MNY_P2P_START_AP"),
 	(PUINT_8) DISP_STRING("MID_MNY_P2P_UPDATE_IE_BUF"),
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	(PUINT_8) DISP_STRING("MID_CNM_P2P_RADAR_DETECT"),
+	(PUINT_8) DISP_STRING("MID_CNM_P2P_CSA_DONE"),
+	(PUINT_8) DISP_STRING("MID_MNY_P2P_DFS_CAC"),
+	(PUINT_8) DISP_STRING("MID_MNY_P2P_SET_NEW_CHANNEL"),
+#endif
+
 #endif
 
 #if CFG_SUPPORT_ADHOC
@@ -179,6 +186,11 @@
 	{MID_CNM_P2P_CH_GRANT, mboxDummy},
 #endif
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	{MID_CNM_P2P_RADAR_DETECT, p2pRoleFsmRunEventRadarDet},
+	{MID_CNM_P2P_CSA_DONE, p2pRoleFsmRunEventCsaDone},
+#endif
+
 #if CFG_ENABLE_BT_OVER_WIFI
 	{MID_CNM_BOW_CH_GRANT, bowRunEventChGrant},
 #else
@@ -252,6 +264,10 @@
 	{MID_MNY_P2P_START_AP, p2pRoleFsmRunEventStartAP},
 	{MID_MNY_P2P_DEL_IFACE, p2pRoleFsmRunEventDelIface},
 	{MID_MNY_P2P_MGMT_FRAME_UPDATE, p2pFsmRunEventUpdateMgmtFrame},
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	{MID_MNY_P2P_DFS_CAC, p2pRoleFsmRunEventDfsCac},
+	{MID_MNY_P2P_SET_NEW_CHANNEL, p2pRoleFsmRunEventSetNewChannel},
+#endif
 #if CFG_SUPPORT_WFD
 	{MID_MNY_P2P_WFD_CFG_UPDATE, p2pFsmRunEventWfdSettingUpdate},
 #endif
diff --git a/mgmt/p2p_func.c b/mgmt/p2p_func.c
index 162ce5c..4bbacee 100644
--- a/mgmt/p2p_func.c
+++ b/mgmt/p2p_func.c
@@ -963,6 +963,98 @@
 	} while (FALSE);
 }				/* p2pFuncAcquireCh */
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID p2pFuncStartRdd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx)
+{
+	P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl;
+
+	DEBUGFUNC("p2pFuncStartRdd()");
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL));
+
+		prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG,
+					sizeof(P_CMD_RDD_ON_OFF_CTRL_T));
+
+		prCmdRddOnOffCtrl->ucDfsCtrl = RDD_START;
+
+		prCmdRddOnOffCtrl->ucRddIdx = prAdapter->aprBssInfo[ucBssIdx]->eDBDCBand;
+
+		if (prCmdRddOnOffCtrl->ucRddIdx)
+			prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_1;
+		else
+			prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_0;
+
+		DBGLOG(P2P, INFO, "p2pFuncStartRdd: Start Radar detection - DFS ctrl: %.d, RDD index: %d\n",
+				prCmdRddOnOffCtrl->ucDfsCtrl, prCmdRddOnOffCtrl->ucRddIdx);
+
+		wlanSendSetQueryCmd(prAdapter,
+					CMD_ID_RDD_ON_OFF_CTRL,
+					TRUE,
+					FALSE,
+					FALSE,
+					NULL,
+					NULL,
+					sizeof(CMD_RDD_ON_OFF_CTRL_T), (PUINT_8) prCmdRddOnOffCtrl, NULL, 0);
+
+	} while (FALSE);
+}				/* p2pFuncStartRdd */
+
+VOID p2pFuncDfsSwitchCh(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, IN P2P_CHNL_REQ_INFO_T rP2pChnlReqInfo)
+{
+
+	P_GLUE_INFO_T prGlueInfo;
+	P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
+	P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl;
+
+	DEBUGFUNC("p2pFuncDfsSwitchCh()");
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL));
+
+		/*  Setup Channel, Band */
+		prBssInfo->ucPrimaryChannel = rP2pChnlReqInfo.ucReqChnlNum;
+		prBssInfo->eBand = rP2pChnlReqInfo.eBand;
+		prBssInfo->eBssSCO = rP2pChnlReqInfo.eChnlSco;
+
+		/* Setup channel and bandwidth */
+		rlmBssInitForAPandIbss(prAdapter, prBssInfo);
+
+		/* Update Beacon again for network phy type confirmed. */
+		bssUpdateBeaconContent(prAdapter, prBssInfo->ucBssIndex);
+
+		/* Reset HW TSF Update Mode and Beacon Mode */
+		nicUpdateBss(prAdapter, prBssInfo->ucBssIndex);
+
+		prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T) cnmMemAlloc(prAdapter, RAM_TYPE_MSG,
+						sizeof(P_CMD_RDD_ON_OFF_CTRL_T));
+
+		prCmdRddOnOffCtrl->ucDfsCtrl = RDD_START_TXQ;
+
+		DBGLOG(P2P, INFO, "p2pFuncDfsSwitchCh: Start TXQ - DFS ctrl: %.d\n", prCmdRddOnOffCtrl->ucDfsCtrl);
+
+		wlanSendSetQueryCmd(prAdapter,
+					CMD_ID_RDD_ON_OFF_CTRL,
+					TRUE,
+					FALSE,
+					FALSE,
+					NULL,
+					NULL,
+					sizeof(CMD_RDD_ON_OFF_CTRL_T), (PUINT_8) prCmdRddOnOffCtrl, NULL, 0);
+
+		prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prBssInfo->u4PrivateData);
+
+		prGlueInfo = prAdapter->prGlueInfo;
+
+		DBGLOG(P2P, INFO, "p2pFuncDfsSwitchCh: Update to OS\n");
+		cfg80211_ch_switch_notify(prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->prDevHandler,
+						prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef);
+		DBGLOG(P2P, INFO, "p2pFuncDfsSwitchCh: Update to OS Done\n");
+
+	} while (FALSE);
+}				/* p2pFuncDfsSwitchCh */
+#endif
+
 #if 0
 WLAN_STATUS
 p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter,
diff --git a/mgmt/p2p_role_fsm.c b/mgmt/p2p_role_fsm.c
index 4d93803..74f7bce 100644
--- a/mgmt/p2p_role_fsm.c
+++ b/mgmt/p2p_role_fsm.c
@@ -60,7 +60,13 @@
 	(PUINT_8) DISP_STRING("P2P_ROLE_STATE_SCAN"),
 	(PUINT_8) DISP_STRING("P2P_ROLE_STATE_REQING_CHANNEL"),
 	(PUINT_8) DISP_STRING("P2P_ROLE_STATE_AP_CHNL_DETECTION"),
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	(PUINT_8) DISP_STRING("P2P_ROLE_STATE_GC_JOIN"),
+	(PUINT_8) DISP_STRING("P2P_ROLE_STATE_DFS_CAC"),
+	(PUINT_8) DISP_STRING("P2P_ROLE_STATE_SWITCH_CHANNEL")
+#else
 	(PUINT_8) DISP_STRING("P2P_ROLE_STATE_GC_JOIN")
+#endif
 };
 
 /*lint -restore */
@@ -372,6 +378,29 @@
 							  prP2pRoleFsmInfo, &(prP2pRoleFsmInfo->rJoinInfo), eNextState);
 			}
 			break;
+
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+		case P2P_ROLE_STATE_DFS_CAC:
+			if (!fgIsTransitionOut) {
+				p2pRoleStateInit_DFS_CAC(prAdapter,
+								prP2pRoleFsmInfo->ucBssIndex,
+								&(prP2pRoleFsmInfo->rChnlReqInfo));
+			} else {
+				p2pRoleStateAbort_DFS_CAC(prAdapter, prP2pRoleBssInfo,
+								 prP2pRoleFsmInfo, eNextState);
+			}
+			break;
+		case P2P_ROLE_STATE_SWITCH_CHANNEL:
+			if (!fgIsTransitionOut) {
+				p2pRoleStateInit_SWITCH_CHANNEL(prAdapter,
+								prP2pRoleFsmInfo->ucBssIndex,
+								&(prP2pRoleFsmInfo->rChnlReqInfo));
+			} else {
+				p2pRoleStateAbort_SWITCH_CHANNEL(prAdapter, prP2pRoleBssInfo,
+								 prP2pRoleFsmInfo, eNextState);
+			}
+			break;
+#endif
 		default:
 			ASSERT(FALSE);
 			break;
@@ -408,6 +437,12 @@
 			DBGLOG(P2P, ERROR,
 			       "Current P2P Role State P2P_ROLE_STATE_GC_JOIN is unexpected for FSM timeout event.\n");
 			break;
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+		case P2P_ROLE_STATE_DFS_CAC:
+			p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_IDLE);
+			kalP2PCacFinishedUpdate(prAdapter->prGlueInfo, prP2pRoleFsmInfo->ucRoleIndex);
+			break;
+#endif
 		default:
 			DBGLOG(P2P, ERROR,
 			       "Current P2P Role State %d is unexpected for FSM timeout event.\n",
@@ -1063,6 +1098,184 @@
 
 }				/* p2pRoleFsmRunEventStopAP */
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID p2pRoleFsmRunEventDfsCac(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr)
+{
+	P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
+	P_MSG_P2P_DFS_CAC_T prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T) NULL;
+	P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = (P_P2P_CONNECTION_REQ_INFO_T) NULL;
+	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
+	ENUM_CHANNEL_WIDTH_T rChannelWidth;
+#if CFG_SUPPORT_DBDC
+	CNM_DBDC_CAP_T rDbdcCap;
+#endif /*CFG_SUPPORT_DBDC*/
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL));
+
+		DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsCac\n");
+
+		prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T) prMsgHdr;
+
+		rChannelWidth = prP2pDfsCacMsg->eChannelWidth;
+
+		prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pDfsCacMsg->ucRoleIdx);
+
+		DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsCac with Role(%d)\n", prP2pDfsCacMsg->ucRoleIdx);
+
+		if (!prP2pRoleFsmInfo) {
+			DBGLOG(P2P, ERROR,
+			       "p2pRoleFsmRunEventDfsCac: Corresponding P2P Role FSM empty: %d.\n",
+			       prP2pDfsCacMsg->ucRoleIdx);
+			break;
+		}
+
+		prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex];
+
+		prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo);
+
+		if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings[prP2pDfsCacMsg->ucRoleIdx]))
+			prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_PURE_AP;
+		else
+			prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_GO;
+
+#if CFG_SUPPORT_DBDC
+		cnmDbdcEnableDecision(prAdapter, prP2pBssInfo->ucBssIndex, prP2pConnReqInfo->rChannelInfo.eBand);
+		cnmGetDbdcCapability(prAdapter,
+			prP2pBssInfo->ucBssIndex,
+			prP2pConnReqInfo->rChannelInfo.eBand,
+			prP2pConnReqInfo->rChannelInfo.ucChannelNum,
+			prAdapter->rWifiVar.ucNSS,
+			&rDbdcCap);
+
+		DBGLOG(P2P, INFO,
+			"p2pRoleFsmRunEventDfsCac: Set channel at CH %u.\n",
+			prP2pConnReqInfo->rChannelInfo.ucChannelNum);
+
+		prP2pBssInfo->eDBDCBand = rDbdcCap.ucDbdcBandIndex;
+		prP2pBssInfo->ucNss = rDbdcCap.ucNss;
+		prP2pBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex;
+#endif /*CFG_SUPPORT_DBDC*/
+
+		if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE) {
+			/* Make sure the state is in IDLE state. */
+			p2pRoleFsmRunEventAbort(prAdapter, prP2pRoleFsmInfo);
+		}
+
+		/* Leave IDLE state. */
+		SET_NET_PWR_STATE_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex);
+
+		prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT;
+		prP2pBssInfo->fgIsDfsActive = TRUE;
+
+		if (prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum != 0) {
+			DBGLOG(P2P, INFO, "Role(%d) Set channel at CH(%d)\n",
+				prP2pDfsCacMsg->ucRoleIdx,
+				prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum);
+
+			p2pRoleStatePrepare_To_DFS_CAC_STATE(prAdapter,
+						GET_BSS_INFO_BY_INDEX(prAdapter, prP2pRoleFsmInfo->ucBssIndex),
+						rChannelWidth,
+						&(prP2pRoleFsmInfo->rConnReqInfo),
+						&(prP2pRoleFsmInfo->rChnlReqInfo));
+			p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_DFS_CAC);
+		} else
+			ASSERT(FALSE);
+
+
+	} while (FALSE);
+
+}				/*p2pRoleFsmRunEventDfsCac*/
+
+VOID p2pRoleFsmRunEventRadarDet(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr)
+{
+	P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
+	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
+	P_MSG_P2P_RADAR_DETECT_T prMsgP2pRddDetMsg;
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL));
+
+		DBGLOG(P2P, INFO, "p2pRoleFsmRunEventRadarDet\n");
+
+		prMsgP2pRddDetMsg = (P_MSG_P2P_RADAR_DETECT_T) prMsgHdr;
+
+		prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsgP2pRddDetMsg->ucBssIndex);
+
+		prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData);
+
+		DBGLOG(P2P, INFO, "p2pRoleFsmRunEventRadarDet with Role(%d)\n", prP2pRoleFsmInfo->ucRoleIndex);
+
+		if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_DFS_CAC &&
+				prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE)
+			ASSERT(FALSE);
+
+		if (prP2pRoleFsmInfo->eCurrentState == P2P_ROLE_STATE_DFS_CAC)
+			p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_IDLE);
+
+		kalP2PRddDetectUpdate(prAdapter->prGlueInfo, prP2pRoleFsmInfo->ucRoleIndex);
+
+	} while (FALSE);
+
+}				/*p2pRoleFsmRunEventRadarDet*/
+
+VOID p2pRoleFsmRunEventSetNewChannel(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr)
+{
+	P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
+	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
+	P_MSG_P2P_SET_NEW_CHANNEL_T prMsgP2pSetNewChannelMsg;
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL));
+
+		DBGLOG(P2P, INFO, "p2pRoleFsmRunEventSetNewChannel\n");
+
+		prMsgP2pSetNewChannelMsg = (P_MSG_P2P_SET_NEW_CHANNEL_T) prMsgHdr;
+
+		prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsgP2pSetNewChannelMsg->ucBssIndex);
+
+		prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prMsgP2pSetNewChannelMsg->ucRoleIdx);
+
+		prP2pRoleFsmInfo->rChnlReqInfo.ucReqChnlNum = prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum;
+		prP2pRoleFsmInfo->rChnlReqInfo.eBand = prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.eBand;
+		prP2pRoleFsmInfo->rChnlReqInfo.eChannelWidth = prMsgP2pSetNewChannelMsg->eChannelWidth;
+		prP2pBssInfo->ucPrimaryChannel = prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum;
+
+		prP2pRoleFsmInfo->rChnlReqInfo.ucCenterFreqS1 =
+			nicGetVhtS1(prP2pBssInfo->ucPrimaryChannel, prP2pRoleFsmInfo->rChnlReqInfo.eChannelWidth);
+		prP2pRoleFsmInfo->rChnlReqInfo.ucCenterFreqS2 = 0;
+
+
+	} while (FALSE);
+
+}				/*p2pRoleFsmRunEventCsaDone*/
+
+VOID p2pRoleFsmRunEventCsaDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr)
+{
+	P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
+	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
+	P_MSG_P2P_CSA_DONE_T prMsgP2pCsaDoneMsg;
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL));
+
+		DBGLOG(P2P, INFO, "p2pRoleFsmRunEventCsaDone\n");
+
+		prMsgP2pCsaDoneMsg = (P_MSG_P2P_CSA_DONE_T) prMsgHdr;
+
+		prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsgP2pCsaDoneMsg->ucBssIndex);
+
+		prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData);
+
+		p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_SWITCH_CHANNEL);
+
+
+	} while (FALSE);
+
+}				/*p2pRoleFsmRunEventCsaDone*/
+#endif
+
+
 VOID p2pRoleFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr)
 {
 	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
@@ -1707,6 +1920,9 @@
 {
 	P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T) NULL;
 	P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T) NULL;
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T) NULL;
+#endif
 	UINT_8 ucTokenID = 0;
 
 	do {
@@ -1717,6 +1933,10 @@
 		prMsgChGrant = (P_MSG_CH_GRANT_T) prMsgHdr;
 		ucTokenID = prMsgChGrant->ucTokenID;
 		prChnlReqInfo = &(prP2pRoleFsmInfo->rChnlReqInfo);
+
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+		prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsgChGrant->ucBssIndex);
+#endif
 		if (prChnlReqInfo->u4MaxInterval != prMsgChGrant->u4GrantInterval) {
 			DBGLOG(P2P, WARN,
 			       "P2P Role:%d Request Channel Interval:%d, Grant Interval:%d\n",
@@ -1747,6 +1967,22 @@
 
 				p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, eNextState);
 				break;
+
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+			case P2P_ROLE_STATE_DFS_CAC:
+				p2pFuncStartRdd(prAdapter, prMsgChGrant->ucBssIndex);
+				cnmTimerStartTimer(prAdapter, &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer),
+					prAdapter->prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->cac_time_ms);
+
+				DBGLOG(P2P, INFO, "p2pRoleFsmRunEventChnlGrant: CAC time = %ds\n",
+					prAdapter->prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->
+					cac_time_ms/1000);
+				break;
+			case P2P_ROLE_STATE_SWITCH_CHANNEL:
+				p2pFuncDfsSwitchCh(prAdapter, prP2pBssInfo, prP2pRoleFsmInfo->rChnlReqInfo);
+				p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_IDLE);
+				break;
+#endif
 			default:
 				/* Channel is granted under unexpected state.
 				 * Driver should cancel channel privileagea before leaving the states.
diff --git a/mgmt/p2p_role_state.c b/mgmt/p2p_role_state.c
index bb2a594..a2ca649 100644
--- a/mgmt/p2p_role_state.c
+++ b/mgmt/p2p_role_state.c
@@ -301,6 +301,54 @@
 	} while (FALSE);
 }
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID
+p2pRoleStateInit_DFS_CAC(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo)
+{
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL));
+
+		p2pFuncAcquireCh(prAdapter, ucBssIdx, prChnlReqInfo);
+	} while (FALSE);
+}				/* p2pRoleStateInit_DFS_CAC */
+
+VOID
+p2pRoleStateAbort_DFS_CAC(IN P_ADAPTER_T prAdapter,
+				 IN P_BSS_INFO_T prP2pRoleBssInfo,
+				 IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, IN ENUM_P2P_ROLE_STATE_T eNextState)
+{
+	do {
+		cnmTimerStopTimer(prAdapter, &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer));
+
+		p2pFuncReleaseCh(prAdapter, prP2pRoleFsmInfo->ucBssIndex,
+					&(prP2pRoleFsmInfo->rChnlReqInfo));
+	} while (FALSE);
+}				/* p2pRoleStateAbort_DFS_CAC */
+
+VOID
+p2pRoleStateInit_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIdx, IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo)
+{
+
+	do {
+		ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL));
+
+		p2pFuncAcquireCh(prAdapter, ucBssIdx, prChnlReqInfo);
+	} while (FALSE);
+}				/* p2pRoleStateInit_SWITCH_CHANNEL */
+
+VOID
+p2pRoleStateAbort_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter,
+				 IN P_BSS_INFO_T prP2pRoleBssInfo,
+				 IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, IN ENUM_P2P_ROLE_STATE_T eNextState)
+{
+	do {
+		p2pFuncReleaseCh(prAdapter, prP2pRoleFsmInfo->ucBssIndex,
+					&(prP2pRoleFsmInfo->rChnlReqInfo));
+	} while (FALSE);
+}				/* p2pRoleStateAbort_SWITCH_CHANNEL */
+#endif
+
 VOID
 p2pRoleStatePrepare_To_REQING_CHANNEL_STATE(IN P_ADAPTER_T prAdapter,
 					    IN P_BSS_INFO_T prBssInfo,
@@ -373,3 +421,62 @@
 		prBssInfo->eBssSCO = eSCOBackup;
 	} while (FALSE);
 }
+
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID
+p2pRoleStatePrepare_To_DFS_CAC_STATE(IN P_ADAPTER_T prAdapter,
+					IN P_BSS_INFO_T prBssInfo,
+					IN ENUM_CHANNEL_WIDTH_T rChannelWidth,
+					IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo,
+					OUT P_P2P_CHNL_REQ_INFO_T prChnlReqInfo)
+{
+	ENUM_BAND_T eBand;
+	UINT_8 ucChannel;
+	ENUM_CHNL_EXT_T eSCO;
+	ENUM_BAND_T eBandBackup;
+	UINT_8 ucChannelBackup;
+	ENUM_CHNL_EXT_T eSCOBackup;
+	P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T) NULL;
+
+	do {
+
+		eBandBackup = prBssInfo->eBand;
+		ucChannelBackup = prBssInfo->ucPrimaryChannel;
+		eSCOBackup = prBssInfo->eBssSCO;
+
+		prBssInfo->ucPrimaryChannel = prConnReqInfo->rChannelInfo.ucChannelNum;
+		prBssInfo->eBand = prConnReqInfo->rChannelInfo.eBand;
+
+		if (cnmPreferredChannel(prAdapter, &eBand, &ucChannel, &eSCO) &&
+			eSCO != CHNL_EXT_SCN && ucChannel == prBssInfo->ucPrimaryChannel && eBand == prBssInfo->eBand) {
+			prBssInfo->eBssSCO = eSCO;
+		} else {
+			prBssInfo->eBssSCO = rlmDecideScoForAP(prAdapter, prBssInfo);
+		}
+
+		prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prBssInfo->u4PrivateData);
+
+		ASSERT_BREAK((prAdapter != NULL) && (prConnReqInfo != NULL) && (prChnlReqInfo != NULL));
+		prChnlReqInfo->u8Cookie = 0;
+		prChnlReqInfo->ucReqChnlNum = prConnReqInfo->rChannelInfo.ucChannelNum;
+		prChnlReqInfo->eBand = prConnReqInfo->rChannelInfo.eBand;
+		prChnlReqInfo->eChnlSco = prBssInfo->eBssSCO;
+		prChnlReqInfo->u4MaxInterval =
+				prAdapter->prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->cac_time_ms;
+		prChnlReqInfo->eChnlReqType = CH_REQ_TYPE_DFS_CAC;
+
+		prChnlReqInfo->eChannelWidth = rChannelWidth;
+
+		prChnlReqInfo->ucCenterFreqS1 =
+			nicGetVhtS1(prBssInfo->ucPrimaryChannel, prChnlReqInfo->eChannelWidth);
+		prChnlReqInfo->ucCenterFreqS2 = 0;
+
+		DBGLOG(P2P, TRACE, "p2pRoleStatePrepare_To_REQING_CHANNEL_STATE\n");
+
+		/* Reset */
+		prBssInfo->ucPrimaryChannel = ucChannelBackup;
+		prBssInfo->eBand = eBandBackup;
+		prBssInfo->eBssSCO = eSCOBackup;
+	} while (FALSE);
+}
+#endif
diff --git a/mgmt/rlm.c b/mgmt/rlm.c
index 626d5b5..173b007 100644
--- a/mgmt/rlm.c
+++ b/mgmt/rlm.c
@@ -530,6 +530,42 @@
 * \return none
 */
 /*----------------------------------------------------------------------------*/
+VOID rlmGenerateCsaIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo)
+{
+	P_BSS_INFO_T prBssInfo;
+	PUINT_8 pucBuffer;
+
+	ASSERT(prAdapter);
+	ASSERT(prMsduInfo);
+
+	if (prAdapter->rWifiVar.fgCsaInProgress) {
+		prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex];
+		if (!prBssInfo)
+			return;
+
+		pucBuffer = (PUINT_8) ((ULONG) prMsduInfo->prPacket + (ULONG) prMsduInfo->u2FrameLength);
+
+		CSA_IE(pucBuffer)->ucId = ELEM_ID_CH_SW_ANNOUNCEMENT;
+		CSA_IE(pucBuffer)->ucLength = ELEM_MIN_LEN_CSA;
+		CSA_IE(pucBuffer)->ucChannelSwitchMode = prAdapter->rWifiVar.ucChannelSwitchMode;
+		CSA_IE(pucBuffer)->ucNewChannelNum = prAdapter->rWifiVar.ucNewChannelNumber;
+		CSA_IE(pucBuffer)->ucChannelSwitchCount = prAdapter->rWifiVar.ucChannelSwitchCount;
+
+		prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer);
+		pucBuffer += IE_SIZE(pucBuffer);
+	}
+
+}
+
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief
+*
+* \param[in]
+*
+* \return none
+*/
+/*----------------------------------------------------------------------------*/
 static VOID rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, P_MSDU_INFO_T prMsduInfo)
 {
 	P_IE_HT_CAP_T prHtCap;
diff --git a/mgmt/rlm_domain.c b/mgmt/rlm_domain.c
index 2354990..5f917af 100644
--- a/mgmt/rlm_domain.c
+++ b/mgmt/rlm_domain.c
@@ -2614,11 +2614,12 @@
 	below_ch = primary_ch - CHNL_SPAN_20;
 	above_ch = primary_ch + CHNL_SPAN_20;
 
+	if (rlmDomainIsLegalChannel(prAdapter, band, above_ch))
+		return CHNL_EXT_SCA;
+
 	if (rlmDomainIsLegalChannel(prAdapter, band, below_ch))
 		return CHNL_EXT_SCB;
 
-	if (rlmDomainIsLegalChannel(prAdapter, band, above_ch))
-		return CHNL_EXT_SCA;
 #endif
 
 	return CHNL_EXT_SCN;
diff --git a/nic/nic_rx.c b/nic/nic_rx.c
index 4291e75..e90de10 100644
--- a/nic/nic_rx.c
+++ b/nic/nic_rx.c
@@ -174,7 +174,13 @@
 #endif
 	{EVENT_ID_HIF_CTRL,					nicEventHifCtrl},
 	{EVENT_ID_RDD_SEND_PULSE,			nicEventRddSendPulse},
-	{EVENT_ID_UPDATE_COEX_PHYRATE,		nicEventUpdateCoexPhyrate}
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	{EVENT_ID_UPDATE_COEX_PHYRATE,		nicEventUpdateCoexPhyrate},
+	{EVENT_ID_RDD_REPORT,			cnmRadarDetectEvent},
+	{EVENT_ID_CSA_DONE,			cnmCsaDoneEvent},
+#else
+	{EVENT_ID_UPDATE_COEX_PHYRATE,		nicEventUpdateCoexPhyrate},
+#endif
 };
 
 /*******************************************************************************
diff --git a/os/linux/gl_ate_agent.c b/os/linux/gl_ate_agent.c
index f042e5f..bd4596a 100644
--- a/os/linux/gl_ate_agent.c
+++ b/os/linux/gl_ate_agent.c
@@ -172,6 +172,9 @@
 
 	{"WriteEfuse", WriteEfuse},
 	{"TxPower", SetTxTargetPower},
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	{"RDDReport", SetRddReport},
+#endif
 
 	{NULL,}
 };
@@ -2010,6 +2013,44 @@
 	return i4Status;
 }
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief  This routine is called to Set Tx Power.
+*
+* \param[in] prNetDev		Pointer to the Net Device
+* \param[in] prInBuf		A pointer to the command string buffer
+* \param[out] None
+*
+* \retval 0				On success.
+* \retval -EINVAL			If invalid argument.
+*/
+/*----------------------------------------------------------------------------*/
+int SetRddReport(struct net_device *prNetDev, UINT_8 *prInBuf)
+{
+	INT_32 i4Status;
+	INT_32 rv;
+	int dbdcIdx;
+	UINT_8 ucDbdcIdx;
+
+	DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv Set RDD Report, buf: %s\n", prInBuf);
+
+	/* rv = sscanf(prInBuf, "%u", &addr);*/
+	rv = kstrtoint(prInBuf, 0, &dbdcIdx);
+
+	DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv Set RDD Report, prInBuf: %s\n", prInBuf);
+	DBGLOG(INIT, ERROR, "MT6632 : ATE_AGENT iwpriv Set RDD Report : Band %d\n", dbdcIdx);
+
+	ucDbdcIdx = (UINT_8) dbdcIdx;
+
+	if (rv == 0)
+		i4Status = MT_ATESetRddReport(prNetDev, ucDbdcIdx);
+	else
+		return -EINVAL;
+
+	return i4Status;
+}
+#endif
 
 /*----------------------------------------------------------------------------*/
 /*!
diff --git a/os/linux/gl_hook_api.c b/os/linux/gl_hook_api.c
index 16e0a29..77918c8 100644
--- a/os/linux/gl_hook_api.c
+++ b/os/linux/gl_hook_api.c
@@ -2572,7 +2572,45 @@
 	return i4Status;
 }
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+/*----------------------------------------------------------------------------*/
+/*!
+* \brief  Hook API for Set Rdd Report.
+*
+* \param[in] prNetDev		 Pointer to the Net Device
+* \param[in] ucDbdcIdx         Dbdc Index
+* \param[out] None
+*
+* \retval 0				On success.
+* \retval -EFAULT			If kalIoctl return nonzero.
+* \retval -EINVAL			If invalid argument.
+*/
+/*----------------------------------------------------------------------------*/
+INT_32 MT_ATESetRddReport(struct net_device *prNetDev, UINT_8 ucDbdcIdx)
+{
+	UINT_32 u4BufLen = 0;
+	PARAM_CUSTOM_SET_RDD_REPORT_T rSetRddReport;
+	P_GLUE_INFO_T prGlueInfo = NULL;
+	WLAN_STATUS i4Status = WLAN_STATUS_SUCCESS;
 
+	prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prNetDev));
+	kalMemSet(&rSetRddReport, 0, sizeof(PARAM_CUSTOM_SET_RDD_REPORT_T));
+
+	/* Set Rdd Report */
+	DBGLOG(INIT, INFO, "MT6632 : QA_AGENT Set RDD Report - Band: %d\n", ucDbdcIdx);
+	rSetRddReport.ucDbdcIdx = ucDbdcIdx;
+
+	i4Status = kalIoctl(prGlueInfo,
+				wlanoidQuerySetRddReport,
+				&rSetRddReport,
+				sizeof(PARAM_CUSTOM_SET_RDD_REPORT_T), FALSE, FALSE, TRUE, &u4BufLen);
+
+	if (i4Status != WLAN_STATUS_SUCCESS)
+		return -EFAULT;
+
+	return i4Status;
+}
+#endif
 
 #if CFG_SUPPORT_TX_BF
 INT_32 TxBfProfileTag_InValid(struct net_device *prNetDev, P_PFMU_PROFILE_TAG1 prPfmuTag1, UINT_8 ucInValid)
diff --git a/os/linux/gl_init.c b/os/linux/gl_init.c
index 71d7c81..ce8aea0 100644
--- a/os/linux/gl_init.c
+++ b/os/linux/gl_init.c
@@ -273,6 +273,15 @@
 	.tx_params      = IEEE80211_HT_MCS_TX_DEFINED,      \
 }
 
+#define WLAN_VHT_MCS_INFO                                                   \
+{                                                                           \
+	.rx_mcs_map     = 0xFFFA,                                               \
+	.rx_highest     = cpu_to_le16(867),   \
+	.tx_mcs_map     = 0xFFFA,                                               \
+	.tx_highest     = cpu_to_le16(867),   \
+}
+
+
 #define WLAN_HT_CAP                                   \
 {                                                       \
 	.ht_supported   = true,                             \
@@ -286,6 +295,20 @@
 	.mcs            = WLAN_MCS_INFO,                  \
 }
 
+#define WLAN_VHT_CAP                                    \
+{                                                       \
+	.vht_supported  = true,                             \
+	.cap            = IEEE80211_VHT_CAP_RXLDPC          \
+			| IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK    \
+			| IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454   \
+			| IEEE80211_VHT_CAP_RXLDPC                  \
+			| IEEE80211_VHT_CAP_SHORT_GI_80             \
+			| IEEE80211_VHT_CAP_TXSTBC                  \
+			| IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE   \
+			| IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE,  \
+	.vht_mcs        = WLAN_VHT_MCS_INFO,                \
+}
+
 /* public for both Legacy Wi-Fi / P2P access */
 struct ieee80211_supported_band mtk_band_2ghz = {
 	.band = IEEE80211_BAND_2GHZ,
@@ -304,6 +327,7 @@
 	.bitrates = mtk_a_rates,
 	.n_bitrates = mtk_a_rates_size,
 	.ht_cap = WLAN_HT_CAP,
+	.vht_cap = WLAN_VHT_CAP,
 };
 
 const UINT_32 mtk_cipher_suites[5] = {
@@ -1458,7 +1482,11 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
 	prWiphy->flags = WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 #else
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	prWiphy->flags = WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+#else
 	prWiphy->flags = WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+#endif
 	prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG;
 #endif
 
diff --git a/os/linux/gl_p2p.c b/os/linux/gl_p2p.c
index 3d03dbb..fe42a5c 100644
--- a/os/linux/gl_p2p.c
+++ b/os/linux/gl_p2p.c
@@ -158,6 +158,10 @@
 	.set_tx_power = mtk_p2p_cfg80211_set_txpower,
 	.get_tx_power = mtk_p2p_cfg80211_get_txpower,
 	.set_power_mgmt = mtk_p2p_cfg80211_set_power_mgmt,
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	.start_radar_detection = mtk_p2p_cfg80211_start_radar_detection,
+	.channel_switch = mtk_p2p_cfg80211_channel_switch,
+#endif
 #ifdef CONFIG_NL80211_TESTMODE
 	.testmode_cmd = mtk_p2p_cfg80211_testmode_cmd,
 #endif
@@ -1029,7 +1033,11 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
 	prWiphy->flags = WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME;
 #else
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+#else
 	prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME;
+#endif
 	prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG;
 #endif
 	prWiphy->ap_sme_capa = 1;
@@ -1266,8 +1274,9 @@
 #endif
 
 	/* 2. carrier on & start TX queue */
-	netif_carrier_on(prDev);
-	netif_tx_start_all_queues(prDev);
+	/*Chun todo 20161220_DFS*/
+	/*netif_carrier_on(prDev);*/
+	/*netif_tx_start_all_queues(prDev);*/
 
 	return 0;		/* success */
 }				/* end of p2pOpen() */
diff --git a/os/linux/gl_p2p_cfg80211.c b/os/linux/gl_p2p_cfg80211.c
index 0d7f4e0..5faecf0 100644
--- a/os/linux/gl_p2p_cfg80211.c
+++ b/os/linux/gl_p2p_cfg80211.c
@@ -1090,6 +1090,10 @@
 		DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_start_ap.\n");
 		prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy));
 
+		/*Chun todo 20161220_DFS*/
+		netif_carrier_on(dev);
+		netif_tx_start_all_queues(dev);
+
 		chandef = &settings->chandef;
 
 		if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0)
@@ -1237,6 +1241,261 @@
 	return i4Rslt;
 }				/* mtk_p2p_cfg80211_start_ap */
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+int mtk_p2p_cfg80211_start_radar_detection(struct wiphy *wiphy, struct net_device *dev,
+					struct cfg80211_chan_def *chandef, unsigned int cac_time_ms)
+{
+	P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL;
+	INT_32 i4Rslt = -EINVAL;
+	P_MSG_P2P_DFS_CAC_T prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T) NULL;
+	UINT_8 ucRoleIdx = 0;
+	RF_CHANNEL_INFO_T rRfChnlInfo;
+
+	do {
+		if ((wiphy == NULL) || (chandef == NULL))
+			break;
+
+		DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_start_radar_detection.\n");
+		prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy));
+
+		if (prGlueInfo->prP2PInfo[ucRoleIdx]->chandef == NULL) {
+			prGlueInfo->prP2PInfo[ucRoleIdx]->chandef = (struct cfg80211_chan_def *)
+				cnmMemAlloc(prGlueInfo->prAdapter,
+				RAM_TYPE_BUF, sizeof(struct cfg80211_chan_def));
+
+			prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan = (struct ieee80211_channel *)
+				cnmMemAlloc(prGlueInfo->prAdapter,
+				RAM_TYPE_BUF, sizeof(struct ieee80211_channel));
+		}
+
+		if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0)
+			break;
+
+		/* Copy chan def to local buffer*/
+		prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq1 = chandef->center_freq1;
+		prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq2 = chandef->center_freq2;
+		prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->width = chandef->width;
+		memcpy(prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan, chandef->chan,
+							sizeof(struct ieee80211_channel));
+		prGlueInfo->prP2PInfo[ucRoleIdx]->cac_time_ms = cac_time_ms;
+
+
+		if (chandef) {
+			mtk_p2p_cfg80211func_channel_format_switch(chandef->chan, chandef->width, &rRfChnlInfo, NULL);
+
+			p2pFuncSetChannel(prGlueInfo->prAdapter, ucRoleIdx, &rRfChnlInfo);
+		} else
+			break;
+
+		DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_start_radar_detection.(role %d)\n", ucRoleIdx);
+
+		prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T) cnmMemAlloc(prGlueInfo->prAdapter,
+								RAM_TYPE_MSG, sizeof(MSG_P2P_DFS_CAC_T));
+
+		if (prP2pDfsCacMsg == NULL) {
+			ASSERT(FALSE);
+			i4Rslt = -ENOMEM;
+			break;
+		}
+
+		prP2pDfsCacMsg->rMsgHdr.eMsgId = MID_MNY_P2P_DFS_CAC;
+
+		switch (chandef->width) {
+		case NL80211_CHAN_WIDTH_20_NOHT:
+		case NL80211_CHAN_WIDTH_20:
+		case NL80211_CHAN_WIDTH_40:
+			prP2pDfsCacMsg->eChannelWidth = CW_20_40MHZ;
+			break;
+
+		case NL80211_CHAN_WIDTH_80:
+			prP2pDfsCacMsg->eChannelWidth = CW_80MHZ;
+			break;
+
+		case NL80211_CHAN_WIDTH_80P80:
+			prP2pDfsCacMsg->eChannelWidth = CW_80P80MHZ;
+			break;
+
+		default:
+			DBGLOG(P2P, ERROR,
+				"mtk_p2p_cfg80211_start_radar_detection. !!!Bandwidth do not support!!!\n");
+			ASSERT(FALSE);
+			break;
+		}
+
+		prP2pDfsCacMsg->ucRoleIdx = ucRoleIdx;
+
+		mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pDfsCacMsg, MSG_SEND_METHOD_BUF);
+
+		i4Rslt = 0;
+
+	} while (FALSE);
+
+	return i4Rslt;
+}
+
+int mtk_p2p_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_csa_settings *params)
+{
+	P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL;
+	INT_32 i4Rslt = -EINVAL;
+	P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) NULL;
+	P_MSG_P2P_SET_NEW_CHANNEL_T prP2pSetNewChannelMsg = (P_MSG_P2P_SET_NEW_CHANNEL_T) NULL;
+	PUINT_8 pucBuffer = (PUINT_8) NULL;
+	UINT_8 ucRoleIdx = 0;
+	RF_CHANNEL_INFO_T rRfChnlInfo;
+	P_BSS_INFO_T prBssInfo;
+	UINT_8 ucBssIndex;
+
+	do {
+		if ((wiphy == NULL) || (params == NULL))
+			break;
+
+		DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_channel_switch.\n");
+		prGlueInfo = *((P_GLUE_INFO_T *) wiphy_priv(wiphy));
+
+		/* Todo: 20161220_DFS_Chun */
+		netif_carrier_on(dev);
+		netif_tx_start_all_queues(dev);
+
+		if (prGlueInfo->prP2PInfo[ucRoleIdx]->chandef == NULL) {
+			prGlueInfo->prP2PInfo[ucRoleIdx]->chandef = (struct cfg80211_chan_def *)
+				cnmMemAlloc(prGlueInfo->prAdapter,
+				RAM_TYPE_BUF, sizeof(struct cfg80211_chan_def));
+
+			prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan = (struct ieee80211_channel *)
+				cnmMemAlloc(prGlueInfo->prAdapter,
+				RAM_TYPE_BUF, sizeof(struct ieee80211_channel));
+		}
+		/* Copy chan def to local buffer*/
+		prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq1 = params->chandef.center_freq1;
+		prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq2 = params->chandef.center_freq2;
+		prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->width = params->chandef.width;
+		memcpy(prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan, params->chandef.chan,
+							sizeof(struct ieee80211_channel));
+
+
+		if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0)
+			break;
+
+		if (params) {
+			mtk_p2p_cfg80211func_channel_format_switch(params->chandef.chan,
+								params->chandef.width, &rRfChnlInfo, NULL);
+
+			p2pFuncSetChannel(prGlueInfo->prAdapter, ucRoleIdx, &rRfChnlInfo);
+		} else
+			break;
+
+		DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_channel_switch.(role %d)\n", ucRoleIdx);
+
+		/* Set CSA IE parameters */
+		prGlueInfo->prAdapter->rWifiVar.fgCsaInProgress = TRUE;
+		prGlueInfo->prAdapter->rWifiVar.ucChannelSwitchMode = 1;
+		prGlueInfo->prAdapter->rWifiVar.ucNewChannelNumber =
+							nicFreq2ChannelNum(params->chandef.chan->center_freq * 1000);
+		prGlueInfo->prAdapter->rWifiVar.ucChannelSwitchCount = params->count;
+
+		/* Set new channel parameters */
+		prP2pSetNewChannelMsg = (P_MSG_P2P_SET_NEW_CHANNEL_T) cnmMemAlloc(prGlueInfo->prAdapter,
+								RAM_TYPE_MSG, sizeof(P_MSG_P2P_SET_NEW_CHANNEL_T));
+
+		if (prP2pSetNewChannelMsg == NULL) {
+			ASSERT(FALSE);
+			i4Rslt = -ENOMEM;
+			break;
+		}
+
+		prP2pSetNewChannelMsg->rMsgHdr.eMsgId = MID_MNY_P2P_SET_NEW_CHANNEL;
+
+		switch (params->chandef.width) {
+		case NL80211_CHAN_WIDTH_20_NOHT:
+		case NL80211_CHAN_WIDTH_20:
+		case NL80211_CHAN_WIDTH_40:
+			prP2pSetNewChannelMsg->eChannelWidth = CW_20_40MHZ;
+			break;
+
+		case NL80211_CHAN_WIDTH_80:
+			prP2pSetNewChannelMsg->eChannelWidth = CW_80MHZ;
+			break;
+
+		case NL80211_CHAN_WIDTH_80P80:
+			prP2pSetNewChannelMsg->eChannelWidth = CW_80P80MHZ;
+			break;
+
+		default:
+			DBGLOG(P2P, ERROR,
+				"mtk_p2p_cfg80211_channel_switch. !!!Bandwidth do not support!!!\n");
+			ASSERT(FALSE);
+			break;
+		}
+
+		prP2pSetNewChannelMsg->ucRoleIdx = ucRoleIdx;
+
+		for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) {
+			prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIndex);
+
+			if (prBssInfo && prBssInfo->fgIsDfsActive) {
+				prP2pSetNewChannelMsg->ucBssIndex = ucBssIndex;
+				break;
+			}
+		}
+
+		mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prP2pSetNewChannelMsg, MSG_SEND_METHOD_BUF);
+
+		/* Update beacon */
+		if ((params->beacon_csa.head_len != 0) || (params->beacon_csa.tail_len != 0)) {
+			prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T) cnmMemAlloc(prGlueInfo->prAdapter,
+							RAM_TYPE_MSG, (sizeof(MSG_P2P_BEACON_UPDATE_T)
+							+ params->beacon_csa.head_len + params->beacon_csa.tail_len));
+
+			if (prP2pBcnUpdateMsg == NULL) {
+				ASSERT(FALSE);
+				i4Rslt = -ENOMEM;
+				break;
+			}
+
+			prP2pBcnUpdateMsg->ucRoleIndex = ucRoleIdx;
+			prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE;
+			pucBuffer = prP2pBcnUpdateMsg->aucBuffer;
+
+			if (params->beacon_csa.head_len != 0) {
+				kalMemCopy(pucBuffer, params->beacon_csa.head, params->beacon_csa.head_len);
+
+				prP2pBcnUpdateMsg->u4BcnHdrLen = params->beacon_csa.head_len;
+
+				prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer;
+
+				pucBuffer = (PUINT_8) ((ULONG) pucBuffer + (ULONG) params->beacon_csa.head_len);
+			} else {
+				prP2pBcnUpdateMsg->u4BcnHdrLen = 0;
+
+				prP2pBcnUpdateMsg->pucBcnHdr = NULL;
+			}
+
+			if (params->beacon_csa.tail_len != 0) {
+				UINT_8 ucLen = params->beacon_csa.tail_len;
+
+				prP2pBcnUpdateMsg->pucBcnBody = pucBuffer;
+				kalMemCopy(pucBuffer, params->beacon_csa.tail, params->beacon_csa.tail_len);
+
+				prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen;
+			} else {
+				prP2pBcnUpdateMsg->u4BcnBodyLen = 0;
+				prP2pBcnUpdateMsg->pucBcnBody = NULL;
+			}
+
+			kalP2PSetRole(prGlueInfo, 2, ucRoleIdx);
+
+			mboxSendMsg(prGlueInfo->prAdapter,
+					MBOX_ID_0, (P_MSG_HDR_T) prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF);
+
+			i4Rslt = 0; /* Return Success */
+		}
+
+	} while (FALSE);
+
+	return i4Rslt;
+}
+#endif
+
 #if 0
 struct cfg80211_beacon_data {
 	const u8 *head, *tail;
diff --git a/os/linux/gl_p2p_kal.c b/os/linux/gl_p2p_kal.c
index 38f3b40..ecc8064 100644
--- a/os/linux/gl_p2p_kal.c
+++ b/os/linux/gl_p2p_kal.c
@@ -1278,6 +1278,59 @@
 
 }				/* kalP2PGOStationUpdate */
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID kalP2PRddDetectUpdate(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRoleIndex)
+{
+	DBGLOG(INIT, INFO, "Radar Detection event\n");
+
+	do {
+		if (prGlueInfo == NULL) {
+			ASSERT(FALSE);
+			break;
+		}
+
+		if (prGlueInfo->prP2PInfo[ucRoleIndex]->chandef == NULL) {
+			ASSERT(FALSE);
+			break;
+		}
+
+		/* cac start disable for next cac slot if enable in dfs channel */
+		prGlueInfo->prP2PInfo[ucRoleIndex]->prWdev->cac_started = FALSE;
+		DBGLOG(INIT, INFO, "kalP2PRddDetectUpdate: Update to OS\n");
+		cfg80211_radar_event(prGlueInfo->prP2PInfo[ucRoleIndex]->prWdev->wiphy,
+				prGlueInfo->prP2PInfo[ucRoleIndex]->chandef, GFP_KERNEL);
+		DBGLOG(INIT, INFO, "kalP2PRddDetectUpdate: Update to OS Done\n");
+
+		netif_carrier_off(prGlueInfo->prP2PInfo[ucRoleIndex]->prDevHandler);
+		netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[ucRoleIndex]->prDevHandler);
+
+	} while (FALSE);
+
+}				/* kalP2PRddDetectUpdate */
+
+VOID kalP2PCacFinishedUpdate(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRoleIndex)
+{
+	DBGLOG(INIT, INFO, "CAC Finished event\n");
+
+	do {
+		if (prGlueInfo == NULL)
+			ASSERT(FALSE);
+
+		if (prGlueInfo->prP2PInfo[ucRoleIndex]->chandef == NULL) {
+			ASSERT(FALSE);
+			break;
+		}
+
+		DBGLOG(INIT, INFO, "kalP2PCacFinishedUpdate: Update to OS\n");
+		cfg80211_cac_event(prGlueInfo->prP2PInfo[ucRoleIndex]->prDevHandler,
+				prGlueInfo->prP2PInfo[ucRoleIndex]->chandef, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
+		DBGLOG(INIT, INFO, "kalP2PCacFinishedUpdate: Update to OS Done\n");
+
+	} while (FALSE);
+
+}				/* kalP2PRddDetectUpdate */
+#endif
+
 BOOLEAN kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, OUT enum nl80211_channel_type *channel_type)
 {
 	BOOLEAN fgIsValid = FALSE;
diff --git a/os/linux/include/gl_ate_agent.h b/os/linux/include/gl_ate_agent.h
index e90da51..560820f 100644
--- a/os/linux/include/gl_ate_agent.h
+++ b/os/linux/include/gl_ate_agent.h
@@ -187,6 +187,10 @@
 int WriteEfuse(struct net_device *prNetDev, UINT_8 *prInBuf);
 int SetTxTargetPower(struct net_device *prNetDev, UINT_8 *prInBuf);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+int SetRddReport(struct net_device *prNetDev, UINT_8 *prInBuf);
+#endif
+
 
 int AteCmdSetHandle(struct net_device *prNetDev, UINT_8 *prInBuf, UINT_32 u4InBufLen);
 #endif /*CFG_SUPPORT_QA_TOOL */
diff --git a/os/linux/include/gl_hook_api.h b/os/linux/include/gl_hook_api.h
index a131d1d..b3387d9 100644
--- a/os/linux/include/gl_hook_api.h
+++ b/os/linux/include/gl_hook_api.h
@@ -146,6 +146,9 @@
 
 INT_32 MT_ATEWriteEfuse(struct net_device *prNetDev, UINT_16 u2Offset, UINT_16 u2Content);
 INT_32 MT_ATESetTxTargetPower(struct net_device *prNetDev, UINT_8 ucTxTargetPower);
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+INT_32 MT_ATESetRddReport(struct net_device *prNetDev, UINT_8 ucDbdcIdx);
+#endif
 
 
 #if CFG_SUPPORT_TX_BF
diff --git a/os/linux/include/gl_p2p_ioctl.h b/os/linux/include/gl_p2p_ioctl.h
index 28e846b..04b8edf 100644
--- a/os/linux/include/gl_p2p_ioctl.h
+++ b/os/linux/include/gl_p2p_ioctl.h
@@ -436,6 +436,15 @@
 
 int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+int mtk_p2p_cfg80211_start_radar_detection(struct wiphy *wiphy,
+						struct net_device *dev,
+						struct cfg80211_chan_def *chandef,
+						unsigned int cac_time_ms);
+
+int mtk_p2p_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_csa_settings *params);
+#endif
+
 int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params);
 
 int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req);
diff --git a/os/linux/include/gl_p2p_kal.h b/os/linux/include/gl_p2p_kal.h
index 12080a0..ff8f5e3 100644
--- a/os/linux/include/gl_p2p_kal.h
+++ b/os/linux/include/gl_p2p_kal.h
@@ -249,6 +249,14 @@
 kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo,
 		      IN UINT_8 ucRoleIndex, IN P_STA_RECORD_T prCliStaRec, IN BOOLEAN fgIsNew);
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+VOID
+kalP2PRddDetectUpdate(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRoleIndex);
+
+VOID
+kalP2PCacFinishedUpdate(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucRoleIndex);
+#endif
+
 #if CFG_SUPPORT_HOTSPOT_WPS_MANAGER
 
 BOOLEAN kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, IN BOOLEAN fgIsblock,
diff --git a/os/linux/include/gl_p2p_os.h b/os/linux/include/gl_p2p_os.h
index d219b04..e6cf890 100644
--- a/os/linux/include/gl_p2p_os.h
+++ b/os/linux/include/gl_p2p_os.h
@@ -195,6 +195,11 @@
 	/*UINT_8 aucSecCheckRsp[256];*//* TH3 multiple P2P */
 #endif
 
+#if (CFG_SUPPORT_DFS_MASTER == 1)
+	struct cfg80211_chan_def *chandef;
+	UINT_32 cac_time_ms;
+#endif
+
 #if CFG_SUPPORT_HOTSPOT_WPS_MANAGER
 	/* Hotspot Client Management */
 	/* dependent with  #define P2P_MAXIMUM_CLIENT_COUNT 10,