]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/staging/rt3070/common/spectrum.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / staging / rt3070 / common / spectrum.c
diff --git a/drivers/staging/rt3070/common/spectrum.c b/drivers/staging/rt3070/common/spectrum.c
new file mode 100644 (file)
index 0000000..da57b12
--- /dev/null
@@ -0,0 +1,1876 @@
+/*
+ *************************************************************************
+ * Ralink Tech Inc.
+ * 5F., No.36, Taiyuan St., Jhubei City,
+ * Hsinchu County 302,
+ * Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2007, Ralink Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify  *
+ * it under the terms of the GNU General Public License as published by  *
+ * the Free Software Foundation; either version 2 of the License, or     *
+ * (at your option) any later version.                                   *
+ *                                                                       *
+ * This program is distributed in the hope that it will be useful,       *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ * GNU General Public License for more details.                          *
+ *                                                                       *
+ * You should have received a copy of the GNU General Public License     *
+ * along with this program; if not, write to the                         *
+ * Free Software Foundation, Inc.,                                       *
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *                                                                       *
+ *************************************************************************
+
+    Module Name:
+       action.c
+
+    Abstract:
+    Handle association related requests either from WSTA or from local MLME
+
+    Revision History:
+    Who          When          What
+    ---------    ----------    ----------------------------------------------
+       Fonchi Wu    2008                  created for 802.11h
+ */
+
+#include "../rt_config.h"
+#include "../action.h"
+
+VOID MeasureReqTabInit(
+       IN PRTMP_ADAPTER pAd)
+{
+       NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock);
+
+       pAd->CommonCfg.pMeasureReqTab = kmalloc(sizeof(MEASURE_REQ_TAB), GFP_ATOMIC);
+       if (pAd->CommonCfg.pMeasureReqTab)
+               NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB));
+       else
+               DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__));
+
+       return;
+}
+
+VOID MeasureReqTabExit(
+       IN PRTMP_ADAPTER pAd)
+{
+       NdisFreeSpinLock(pAd->CommonCfg.MeasureReqTabLock);
+
+       if (pAd->CommonCfg.pMeasureReqTab)
+               kfree(pAd->CommonCfg.pMeasureReqTab);
+       pAd->CommonCfg.pMeasureReqTab = NULL;
+
+       return;
+}
+
+static PMEASURE_REQ_ENTRY MeasureReqLookUp(
+       IN PRTMP_ADAPTER        pAd,
+       IN UINT8                        DialogToken)
+{
+       UINT HashIdx;
+       PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab;
+       PMEASURE_REQ_ENTRY pEntry = NULL;
+       PMEASURE_REQ_ENTRY pPrevEntry = NULL;
+
+       if (pTab == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+               return NULL;
+       }
+
+       RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock);
+
+       HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken);
+       pEntry = pTab->Hash[HashIdx];
+
+       while (pEntry)
+       {
+               if (pEntry->DialogToken == DialogToken)
+                       break;
+               else
+               {
+                       pPrevEntry = pEntry;
+                       pEntry = pEntry->pNext;
+               }
+       }
+
+       RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock);
+
+       return pEntry;
+}
+
+static PMEASURE_REQ_ENTRY MeasureReqInsert(
+       IN PRTMP_ADAPTER        pAd,
+       IN UINT8                        DialogToken)
+{
+       INT i;
+       ULONG HashIdx;
+       PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab;
+       PMEASURE_REQ_ENTRY pEntry = NULL, pCurrEntry;
+       ULONG Now;
+
+       if(pTab == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+               return NULL;
+       }
+
+       pEntry = MeasureReqLookUp(pAd, DialogToken);
+       if (pEntry == NULL)
+       {
+               RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock);
+               for (i = 0; i < MAX_MEASURE_REQ_TAB_SIZE; i++)
+               {
+                       NdisGetSystemUpTime(&Now);
+                       pEntry = &pTab->Content[i];
+
+                       if ((pEntry->Valid == TRUE)
+                               && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + MQ_REQ_AGE_OUT)))
+                       {
+                               PMEASURE_REQ_ENTRY pPrevEntry = NULL;
+                               ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
+                               PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
+
+                               // update Hash list
+                               do
+                               {
+                                       if (pProbeEntry == pEntry)
+                                       {
+                                               if (pPrevEntry == NULL)
+                                               {
+                                                       pTab->Hash[HashIdx] = pEntry->pNext;
+                                               }
+                                               else
+                                               {
+                                                       pPrevEntry->pNext = pEntry->pNext;
+                                               }
+                                               break;
+                                       }
+
+                                       pPrevEntry = pProbeEntry;
+                                       pProbeEntry = pProbeEntry->pNext;
+                               } while (pProbeEntry);
+
+                               NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY));
+                               pTab->Size--;
+
+                               break;
+                       }
+
+                       if (pEntry->Valid == FALSE)
+                               break;
+               }
+
+               if (i < MAX_MEASURE_REQ_TAB_SIZE)
+               {
+                       NdisGetSystemUpTime(&Now);
+                       pEntry->lastTime = Now;
+                       pEntry->Valid = TRUE;
+                       pEntry->DialogToken = DialogToken;
+                       pTab->Size++;
+               }
+               else
+               {
+                       pEntry = NULL;
+                       DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__));
+               }
+
+               // add this Neighbor entry into HASH table
+               if (pEntry)
+               {
+                       HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(DialogToken);
+                       if (pTab->Hash[HashIdx] == NULL)
+                       {
+                               pTab->Hash[HashIdx] = pEntry;
+                       }
+                       else
+                       {
+                               pCurrEntry = pTab->Hash[HashIdx];
+                               while (pCurrEntry->pNext != NULL)
+                                       pCurrEntry = pCurrEntry->pNext;
+                               pCurrEntry->pNext = pEntry;
+                       }
+               }
+
+               RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock);
+       }
+
+       return pEntry;
+}
+
+static VOID MeasureReqDelete(
+       IN PRTMP_ADAPTER        pAd,
+       IN UINT8                        DialogToken)
+{
+       PMEASURE_REQ_TAB pTab = pAd->CommonCfg.pMeasureReqTab;
+       PMEASURE_REQ_ENTRY pEntry = NULL;
+
+       if(pTab == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+               return;
+       }
+
+       // if empty, return
+       if (pTab->Size == 0)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("pMeasureReqTab empty.\n"));
+               return;
+       }
+
+       pEntry = MeasureReqLookUp(pAd, DialogToken);
+       if (pEntry != NULL)
+       {
+               PMEASURE_REQ_ENTRY pPrevEntry = NULL;
+               ULONG HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
+               PMEASURE_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
+
+               RTMP_SEM_LOCK(&pAd->CommonCfg.MeasureReqTabLock);
+               // update Hash list
+               do
+               {
+                       if (pProbeEntry == pEntry)
+                       {
+                               if (pPrevEntry == NULL)
+                               {
+                                       pTab->Hash[HashIdx] = pEntry->pNext;
+                               }
+                               else
+                               {
+                                       pPrevEntry->pNext = pEntry->pNext;
+                               }
+                               break;
+                       }
+
+                       pPrevEntry = pProbeEntry;
+                       pProbeEntry = pProbeEntry->pNext;
+               } while (pProbeEntry);
+
+               NdisZeroMemory(pEntry, sizeof(MEASURE_REQ_ENTRY));
+               pTab->Size--;
+
+               RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock);
+       }
+
+       return;
+}
+
+VOID TpcReqTabInit(
+       IN PRTMP_ADAPTER pAd)
+{
+       NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock);
+
+       pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(TPC_REQ_TAB), GFP_ATOMIC);
+       if (pAd->CommonCfg.pTpcReqTab)
+               NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB));
+       else
+               DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__));
+
+       return;
+}
+
+VOID TpcReqTabExit(
+       IN PRTMP_ADAPTER pAd)
+{
+       NdisFreeSpinLock(pAd->CommonCfg.TpcReqTabLock);
+
+       if (pAd->CommonCfg.pTpcReqTab)
+               kfree(pAd->CommonCfg.pTpcReqTab);
+       pAd->CommonCfg.pTpcReqTab = NULL;
+
+       return;
+}
+
+static PTPC_REQ_ENTRY TpcReqLookUp(
+       IN PRTMP_ADAPTER        pAd,
+       IN UINT8                        DialogToken)
+{
+       UINT HashIdx;
+       PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab;
+       PTPC_REQ_ENTRY pEntry = NULL;
+       PTPC_REQ_ENTRY pPrevEntry = NULL;
+
+       if (pTab == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+               return NULL;
+       }
+
+       RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock);
+
+       HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken);
+       pEntry = pTab->Hash[HashIdx];
+
+       while (pEntry)
+       {
+               if (pEntry->DialogToken == DialogToken)
+                       break;
+               else
+               {
+                       pPrevEntry = pEntry;
+                       pEntry = pEntry->pNext;
+               }
+       }
+
+       RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock);
+
+       return pEntry;
+}
+
+
+static PTPC_REQ_ENTRY TpcReqInsert(
+       IN PRTMP_ADAPTER        pAd,
+       IN UINT8                        DialogToken)
+{
+       INT i;
+       ULONG HashIdx;
+       PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab;
+       PTPC_REQ_ENTRY pEntry = NULL, pCurrEntry;
+       ULONG Now;
+
+       if(pTab == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+               return NULL;
+       }
+
+       pEntry = TpcReqLookUp(pAd, DialogToken);
+       if (pEntry == NULL)
+       {
+               RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock);
+               for (i = 0; i < MAX_TPC_REQ_TAB_SIZE; i++)
+               {
+                       NdisGetSystemUpTime(&Now);
+                       pEntry = &pTab->Content[i];
+
+                       if ((pEntry->Valid == TRUE)
+                               && RTMP_TIME_AFTER((unsigned long)Now, (unsigned long)(pEntry->lastTime + TPC_REQ_AGE_OUT)))
+                       {
+                               PTPC_REQ_ENTRY pPrevEntry = NULL;
+                               ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
+                               PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
+
+                               // update Hash list
+                               do
+                               {
+                                       if (pProbeEntry == pEntry)
+                                       {
+                                               if (pPrevEntry == NULL)
+                                               {
+                                                       pTab->Hash[HashIdx] = pEntry->pNext;
+                                               }
+                                               else
+                                               {
+                                                       pPrevEntry->pNext = pEntry->pNext;
+                                               }
+                                               break;
+                                       }
+
+                                       pPrevEntry = pProbeEntry;
+                                       pProbeEntry = pProbeEntry->pNext;
+                               } while (pProbeEntry);
+
+                               NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY));
+                               pTab->Size--;
+
+                               break;
+                       }
+
+                       if (pEntry->Valid == FALSE)
+                               break;
+               }
+
+               if (i < MAX_TPC_REQ_TAB_SIZE)
+               {
+                       NdisGetSystemUpTime(&Now);
+                       pEntry->lastTime = Now;
+                       pEntry->Valid = TRUE;
+                       pEntry->DialogToken = DialogToken;
+                       pTab->Size++;
+               }
+               else
+               {
+                       pEntry = NULL;
+                       DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__));
+               }
+
+               // add this Neighbor entry into HASH table
+               if (pEntry)
+               {
+                       HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(DialogToken);
+                       if (pTab->Hash[HashIdx] == NULL)
+                       {
+                               pTab->Hash[HashIdx] = pEntry;
+                       }
+                       else
+                       {
+                               pCurrEntry = pTab->Hash[HashIdx];
+                               while (pCurrEntry->pNext != NULL)
+                                       pCurrEntry = pCurrEntry->pNext;
+                               pCurrEntry->pNext = pEntry;
+                       }
+               }
+
+               RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock);
+       }
+
+       return pEntry;
+}
+
+static VOID TpcReqDelete(
+       IN PRTMP_ADAPTER        pAd,
+       IN UINT8                        DialogToken)
+{
+       PTPC_REQ_TAB pTab = pAd->CommonCfg.pTpcReqTab;
+       PTPC_REQ_ENTRY pEntry = NULL;
+
+       if(pTab == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+               return;
+       }
+
+       // if empty, return
+       if (pTab->Size == 0)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("pTpcReqTab empty.\n"));
+               return;
+       }
+
+       pEntry = TpcReqLookUp(pAd, DialogToken);
+       if (pEntry != NULL)
+       {
+               PTPC_REQ_ENTRY pPrevEntry = NULL;
+               ULONG HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken);
+               PTPC_REQ_ENTRY pProbeEntry = pTab->Hash[HashIdx];
+
+               RTMP_SEM_LOCK(&pAd->CommonCfg.TpcReqTabLock);
+               // update Hash list
+               do
+               {
+                       if (pProbeEntry == pEntry)
+                       {
+                               if (pPrevEntry == NULL)
+                               {
+                                       pTab->Hash[HashIdx] = pEntry->pNext;
+                               }
+                               else
+                               {
+                                       pPrevEntry->pNext = pEntry->pNext;
+                               }
+                               break;
+                       }
+
+                       pPrevEntry = pProbeEntry;
+                       pProbeEntry = pProbeEntry->pNext;
+               } while (pProbeEntry);
+
+               NdisZeroMemory(pEntry, sizeof(TPC_REQ_ENTRY));
+               pTab->Size--;
+
+               RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock);
+       }
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Get Current TimeS tamp.
+
+       Parametrs:
+
+       Return  : Current Time Stamp.
+       ==========================================================================
+ */
+static UINT64 GetCurrentTimeStamp(
+       IN PRTMP_ADAPTER pAd)
+{
+       // get current time stamp.
+       return 0;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Get Current Transmit Power.
+
+       Parametrs:
+
+       Return  : Current Time Stamp.
+       ==========================================================================
+ */
+static UINT8 GetCurTxPwr(
+       IN PRTMP_ADAPTER pAd,
+       IN UINT8 Wcid)
+{
+       return 16; /* 16 dBm */
+}
+
+/*
+       ==========================================================================
+       Description:
+               Insert Dialog Token into frame.
+
+       Parametrs:
+               1. frame buffer pointer.
+               2. frame length.
+               3. Dialog token.
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID InsertDialogToken(
+       IN PRTMP_ADAPTER pAd,
+       OUT PUCHAR pFrameBuf,
+       OUT PULONG pFrameLen,
+       IN UINT8 DialogToken)
+{
+       ULONG TempLen;
+       MakeOutgoingFrame(pFrameBuf,    &TempLen,
+                                       1,                              &DialogToken,
+                                       END_OF_ARGS);
+
+       *pFrameLen = *pFrameLen + TempLen;
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Insert TPC Request IE into frame.
+
+       Parametrs:
+               1. frame buffer pointer.
+               2. frame length.
+
+       Return  : None.
+       ==========================================================================
+ */
+ static VOID InsertTpcReqIE(
+       IN PRTMP_ADAPTER pAd,
+       OUT PUCHAR pFrameBuf,
+       OUT PULONG pFrameLen)
+{
+       ULONG TempLen;
+       ULONG Len = 0;
+       UINT8 ElementID = IE_TPC_REQUEST;
+
+       MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
+                                               1,                                                      &ElementID,
+                                               1,                                                      &Len,
+                                               END_OF_ARGS);
+
+       *pFrameLen = *pFrameLen + TempLen;
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Insert TPC Report IE into frame.
+
+       Parametrs:
+               1. frame buffer pointer.
+               2. frame length.
+               3. Transmit Power.
+               4. Link Margin.
+
+       Return  : None.
+       ==========================================================================
+ */
+ static VOID InsertTpcReportIE(
+       IN PRTMP_ADAPTER pAd,
+       OUT PUCHAR pFrameBuf,
+       OUT PULONG pFrameLen,
+       IN UINT8 TxPwr,
+       IN UINT8 LinkMargin)
+{
+       ULONG TempLen;
+       ULONG Len = sizeof(TPC_REPORT_INFO);
+       UINT8 ElementID = IE_TPC_REPORT;
+       TPC_REPORT_INFO TpcReportIE;
+
+       TpcReportIE.TxPwr = TxPwr;
+       TpcReportIE.LinkMargin = LinkMargin;
+
+       MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
+                                               1,                                                      &ElementID,
+                                               1,                                                      &Len,
+                                               Len,                                            &TpcReportIE,
+                                               END_OF_ARGS);
+
+       *pFrameLen = *pFrameLen + TempLen;
+
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Insert Channel Switch Announcement IE into frame.
+
+       Parametrs:
+               1. frame buffer pointer.
+               2. frame length.
+               3. channel switch announcement mode.
+               4. new selected channel.
+               5. channel switch announcement count.
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID InsertChSwAnnIE(
+       IN PRTMP_ADAPTER pAd,
+       OUT PUCHAR pFrameBuf,
+       OUT PULONG pFrameLen,
+       IN UINT8 ChSwMode,
+       IN UINT8 NewChannel,
+       IN UINT8 ChSwCnt)
+{
+       ULONG TempLen;
+       ULONG Len = sizeof(CH_SW_ANN_INFO);
+       UINT8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT;
+       CH_SW_ANN_INFO ChSwAnnIE;
+
+       ChSwAnnIE.ChSwMode = ChSwMode;
+       ChSwAnnIE.Channel = NewChannel;
+       ChSwAnnIE.ChSwCnt = ChSwCnt;
+
+       MakeOutgoingFrame(pFrameBuf,                            &TempLen,
+                                               1,                                              &ElementID,
+                                               1,                                              &Len,
+                                               Len,                                    &ChSwAnnIE,
+                                               END_OF_ARGS);
+
+       *pFrameLen = *pFrameLen + TempLen;
+
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Insert Measure Request IE into frame.
+
+       Parametrs:
+               1. frame buffer pointer.
+               2. frame length.
+               3. Measure Token.
+               4. Measure Request Mode.
+               5. Measure Request Type.
+               6. Measure Channel.
+               7. Measure Start time.
+               8. Measure Duration.
+
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID InsertMeasureReqIE(
+       IN PRTMP_ADAPTER pAd,
+       OUT PUCHAR pFrameBuf,
+       OUT PULONG pFrameLen,
+       IN PMEASURE_REQ_INFO pMeasureReqIE)
+{
+       ULONG TempLen;
+       UINT8 Len = sizeof(MEASURE_REQ_INFO);
+       UINT8 ElementID = IE_MEASUREMENT_REQUEST;
+
+       MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
+                                               1,                                                      &ElementID,
+                                               1,                                                      &Len,
+                                               Len,                                            pMeasureReqIE,
+                                               END_OF_ARGS);
+
+       *pFrameLen = *pFrameLen + TempLen;
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Insert Measure Report IE into frame.
+
+       Parametrs:
+               1. frame buffer pointer.
+               2. frame length.
+               3. Measure Token.
+               4. Measure Request Mode.
+               5. Measure Request Type.
+               6. Length of Report Infomation
+               7. Pointer of Report Infomation Buffer.
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID InsertMeasureReportIE(
+       IN PRTMP_ADAPTER pAd,
+       OUT PUCHAR pFrameBuf,
+       OUT PULONG pFrameLen,
+       IN PMEASURE_REPORT_INFO pMeasureReportIE,
+       IN UINT8 ReportLnfoLen,
+       IN PUINT8 pReportInfo)
+{
+       ULONG TempLen;
+       ULONG Len;
+       UINT8 ElementID = IE_MEASUREMENT_REPORT;
+
+       Len = sizeof(MEASURE_REPORT_INFO) + ReportLnfoLen;
+
+       MakeOutgoingFrame(pFrameBuf,                                    &TempLen,
+                                               1,                                                      &ElementID,
+                                               1,                                                      &Len,
+                                               Len,                                            pMeasureReportIE,
+                                               END_OF_ARGS);
+
+       *pFrameLen = *pFrameLen + TempLen;
+
+       if ((ReportLnfoLen > 0) && (pReportInfo != NULL))
+       {
+               MakeOutgoingFrame(pFrameBuf + *pFrameLen,               &TempLen,
+                                                       ReportLnfoLen,                          pReportInfo,
+                                                       END_OF_ARGS);
+
+               *pFrameLen = *pFrameLen + TempLen;
+       }
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Prepare Measurement request action frame and enqueue it into
+               management queue waiting for transmition.
+
+       Parametrs:
+               1. the destination mac address of the frame.
+
+       Return  : None.
+       ==========================================================================
+ */
+VOID EnqueueMeasurementReq(
+       IN PRTMP_ADAPTER pAd,
+       IN PUCHAR pDA,
+       IN UINT8 MeasureToken,
+       IN UINT8 MeasureReqMode,
+       IN UINT8 MeasureReqType,
+       IN UINT8 MeasureCh,
+       IN UINT16 MeasureDuration)
+{
+       PUCHAR pOutBuffer = NULL;
+       NDIS_STATUS NStatus;
+       ULONG FrameLen;
+       HEADER_802_11 ActHdr;
+       MEASURE_REQ_INFO MeasureReqIE;
+       UINT8 RmReqDailogToken = RandomByte(pAd);
+       UINT64 MeasureStartTime = GetCurrentTimeStamp(pAd);
+
+       // build action frame header.
+       MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
+                                               pAd->CurrentAddress);
+
+       NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+       if(NStatus != NDIS_STATUS_SUCCESS)
+       {
+               DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+               return;
+       }
+       NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
+       FrameLen = sizeof(HEADER_802_11);
+
+       InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRQ);
+
+       // fill Dialog Token
+       InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, MeasureToken);
+
+       // prepare Measurement IE.
+       NdisZeroMemory(&MeasureReqIE, sizeof(MEASURE_REQ_INFO));
+       MeasureReqIE.Token = RmReqDailogToken;
+       MeasureReqIE.ReqMode.word = MeasureReqMode;
+       MeasureReqIE.ReqType = MeasureReqType;
+       MeasureReqIE.MeasureReq.ChNum = MeasureCh;
+       MeasureReqIE.MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime);
+       MeasureReqIE.MeasureReq.MeasureDuration = cpu2le16(MeasureDuration);
+       InsertMeasureReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureReqIE);
+
+       MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Prepare Measurement report action frame and enqueue it into
+               management queue waiting for transmition.
+
+       Parametrs:
+               1. the destination mac address of the frame.
+
+       Return  : None.
+       ==========================================================================
+ */
+VOID EnqueueMeasurementRep(
+       IN PRTMP_ADAPTER pAd,
+       IN PUCHAR pDA,
+       IN UINT8 DialogToken,
+       IN UINT8 MeasureToken,
+       IN UINT8 MeasureReqMode,
+       IN UINT8 MeasureReqType,
+       IN UINT8 ReportInfoLen,
+       IN PUINT8 pReportInfo)
+{
+       PUCHAR pOutBuffer = NULL;
+       NDIS_STATUS NStatus;
+       ULONG FrameLen;
+       HEADER_802_11 ActHdr;
+       MEASURE_REPORT_INFO MeasureRepIE;
+
+       // build action frame header.
+       MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
+                                               pAd->CurrentAddress);
+
+       NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+       if(NStatus != NDIS_STATUS_SUCCESS)
+       {
+               DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+               return;
+       }
+       NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
+       FrameLen = sizeof(HEADER_802_11);
+
+       InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_MRP);
+
+       // fill Dialog Token
+       InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken);
+
+       // prepare Measurement IE.
+       NdisZeroMemory(&MeasureRepIE, sizeof(MEASURE_REPORT_INFO));
+       MeasureRepIE.Token = MeasureToken;
+       MeasureRepIE.ReportMode.word = MeasureReqMode;
+       MeasureRepIE.ReportType = MeasureReqType;
+       InsertMeasureReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, &MeasureRepIE, ReportInfoLen, pReportInfo);
+
+       MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Prepare TPC Request action frame and enqueue it into
+               management queue waiting for transmition.
+
+       Parametrs:
+               1. the destination mac address of the frame.
+
+       Return  : None.
+       ==========================================================================
+ */
+VOID EnqueueTPCReq(
+       IN PRTMP_ADAPTER pAd,
+       IN PUCHAR pDA,
+       IN UCHAR DialogToken)
+{
+       PUCHAR pOutBuffer = NULL;
+       NDIS_STATUS NStatus;
+       ULONG FrameLen;
+
+       HEADER_802_11 ActHdr;
+
+       // build action frame header.
+       MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
+                                               pAd->CurrentAddress);
+
+       NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+       if(NStatus != NDIS_STATUS_SUCCESS)
+       {
+               DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+               return;
+       }
+       NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
+       FrameLen = sizeof(HEADER_802_11);
+
+       InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRQ);
+
+       // fill Dialog Token
+       InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken);
+
+       // Insert TPC Request IE.
+       InsertTpcReqIE(pAd, (pOutBuffer + FrameLen), &FrameLen);
+
+       MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Prepare TPC Report action frame and enqueue it into
+               management queue waiting for transmition.
+
+       Parametrs:
+               1. the destination mac address of the frame.
+
+       Return  : None.
+       ==========================================================================
+ */
+VOID EnqueueTPCRep(
+       IN PRTMP_ADAPTER pAd,
+       IN PUCHAR pDA,
+       IN UINT8 DialogToken,
+       IN UINT8 TxPwr,
+       IN UINT8 LinkMargin)
+{
+       PUCHAR pOutBuffer = NULL;
+       NDIS_STATUS NStatus;
+       ULONG FrameLen;
+
+       HEADER_802_11 ActHdr;
+
+       // build action frame header.
+       MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
+                                               pAd->CurrentAddress);
+
+       NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+       if(NStatus != NDIS_STATUS_SUCCESS)
+       {
+               DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+               return;
+       }
+       NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
+       FrameLen = sizeof(HEADER_802_11);
+
+       InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_TPCRP);
+
+       // fill Dialog Token
+       InsertDialogToken(pAd, (pOutBuffer + FrameLen), &FrameLen, DialogToken);
+
+       // Insert TPC Request IE.
+       InsertTpcReportIE(pAd, (pOutBuffer + FrameLen), &FrameLen, TxPwr, LinkMargin);
+
+       MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Prepare Channel Switch Announcement action frame and enqueue it into
+               management queue waiting for transmition.
+
+       Parametrs:
+               1. the destination mac address of the frame.
+               2. Channel switch announcement mode.
+               2. a New selected channel.
+
+       Return  : None.
+       ==========================================================================
+ */
+VOID EnqueueChSwAnn(
+       IN PRTMP_ADAPTER pAd,
+       IN PUCHAR pDA,
+       IN UINT8 ChSwMode,
+       IN UINT8 NewCh)
+{
+       PUCHAR pOutBuffer = NULL;
+       NDIS_STATUS NStatus;
+       ULONG FrameLen;
+
+       HEADER_802_11 ActHdr;
+
+       // build action frame header.
+       MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA,
+                                               pAd->CurrentAddress);
+
+       NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+       if(NStatus != NDIS_STATUS_SUCCESS)
+       {
+               DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+               return;
+       }
+       NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
+       FrameLen = sizeof(HEADER_802_11);
+
+       InsertActField(pAd, (pOutBuffer + FrameLen), &FrameLen, CATEGORY_SPECTRUM, SPEC_CHANNEL_SWITCH);
+
+       InsertChSwAnnIE(pAd, (pOutBuffer + FrameLen), &FrameLen, ChSwMode, NewCh, 0);
+
+       MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+
+       return;
+}
+
+static BOOLEAN DfsRequirementCheck(
+       IN PRTMP_ADAPTER pAd,
+       IN UINT8 Channel)
+{
+       BOOLEAN Result = FALSE;
+       INT i;
+
+       do
+       {
+               // check DFS procedure is running.
+               // make sure DFS procedure won't start twice.
+               if (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)
+               {
+                       Result = FALSE;
+                       break;
+               }
+
+               // check the new channel carried from Channel Switch Announcemnet is valid.
+               for (i=0; i<pAd->ChannelListNum; i++)
+               {
+                       if ((Channel == pAd->ChannelList[i].Channel)
+                               &&(pAd->ChannelList[i].RemainingTimeForUse == 0))
+                       {
+                               // found radar signal in the channel. the channel can't use at least for 30 minutes.
+                               pAd->ChannelList[i].RemainingTimeForUse = 1800;//30 min = 1800 sec
+                               Result = TRUE;
+                               break;
+                       }
+               }
+       } while(FALSE);
+
+       return Result;
+}
+
+VOID NotifyChSwAnnToPeerAPs(
+       IN PRTMP_ADAPTER pAd,
+       IN PUCHAR pRA,
+       IN PUCHAR pTA,
+       IN UINT8 ChSwMode,
+       IN UINT8 Channel)
+{
+#ifdef WDS_SUPPORT
+       if (!((pRA[0] & 0xff) == 0xff)) // is pRA a broadcase address.
+       {
+               INT i;
+               // info neighbor APs that Radar signal found throgh WDS link.
+               for (i = 0; i < MAX_WDS_ENTRY; i++)
+               {
+                       if (ValidWdsEntry(pAd, i))
+                       {
+                               PUCHAR pDA = pAd->WdsTab.WdsEntry[i].PeerWdsAddr;
+
+                               // DA equal to SA. have no necessary orignal AP which found Radar signal.
+                               if (MAC_ADDR_EQUAL(pTA, pDA))
+                                       continue;
+
+                               // send Channel Switch Action frame to info Neighbro APs.
+                               EnqueueChSwAnn(pAd, pDA, ChSwMode, Channel);
+                       }
+               }
+       }
+#endif // WDS_SUPPORT //
+}
+
+static VOID StartDFSProcedure(
+       IN PRTMP_ADAPTER pAd,
+       IN UCHAR Channel,
+       IN UINT8 ChSwMode)
+{
+       // start DFS procedure
+       pAd->CommonCfg.Channel = Channel;
+#ifdef DOT11_N_SUPPORT
+       N_ChannelCheck(pAd);
+#endif // DOT11_N_SUPPORT //
+       pAd->CommonCfg.RadarDetect.RDMode = RD_SWITCHING_MODE;
+       pAd->CommonCfg.RadarDetect.CSCount = 0;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Channel Switch Announcement action frame sanity check.
+
+       Parametrs:
+               1. MLME message containing the received frame
+               2. message length.
+               3. Channel switch announcement infomation buffer.
+
+
+       Return  : None.
+       ==========================================================================
+ */
+
+/*
+  Channel Switch Announcement IE.
+  +----+-----+-----------+------------+-----------+
+  | ID | Len |Ch Sw Mode | New Ch Num | Ch Sw Cnt |
+  +----+-----+-----------+------------+-----------+
+    1    1        1           1            1
+*/
+static BOOLEAN PeerChSwAnnSanity(
+       IN PRTMP_ADAPTER pAd,
+       IN VOID *pMsg,
+       IN ULONG MsgLen,
+       OUT PCH_SW_ANN_INFO pChSwAnnInfo)
+{
+       PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
+       PUCHAR pFramePtr = Fr->Octet;
+       BOOLEAN result = FALSE;
+       PEID_STRUCT eid_ptr;
+
+       // skip 802.11 header.
+       MsgLen -= sizeof(HEADER_802_11);
+
+       // skip category and action code.
+       pFramePtr += 2;
+       MsgLen -= 2;
+
+       if (pChSwAnnInfo == NULL)
+               return result;
+
+       eid_ptr = (PEID_STRUCT)pFramePtr;
+       while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
+       {
+               switch(eid_ptr->Eid)
+               {
+                       case IE_CHANNEL_SWITCH_ANNOUNCEMENT:
+                               NdisMoveMemory(&pChSwAnnInfo->ChSwMode, eid_ptr->Octet, 1);
+                               NdisMoveMemory(&pChSwAnnInfo->Channel, eid_ptr->Octet + 1, 1);
+                               NdisMoveMemory(&pChSwAnnInfo->ChSwCnt, eid_ptr->Octet + 2, 1);
+
+                               result = TRUE;
+                break;
+
+                       default:
+                               break;
+               }
+               eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
+       }
+
+       return result;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Measurement request action frame sanity check.
+
+       Parametrs:
+               1. MLME message containing the received frame
+               2. message length.
+               3. Measurement request infomation buffer.
+
+       Return  : None.
+       ==========================================================================
+ */
+static BOOLEAN PeerMeasureReqSanity(
+       IN PRTMP_ADAPTER pAd,
+       IN VOID *pMsg,
+       IN ULONG MsgLen,
+       OUT PUINT8 pDialogToken,
+       OUT PMEASURE_REQ_INFO pMeasureReqInfo)
+{
+       PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
+       PUCHAR pFramePtr = Fr->Octet;
+       BOOLEAN result = FALSE;
+       PEID_STRUCT eid_ptr;
+       PUCHAR ptr;
+       UINT64 MeasureStartTime;
+       UINT16 MeasureDuration;
+
+       // skip 802.11 header.
+       MsgLen -= sizeof(HEADER_802_11);
+
+       // skip category and action code.
+       pFramePtr += 2;
+       MsgLen -= 2;
+
+       if (pMeasureReqInfo == NULL)
+               return result;
+
+       NdisMoveMemory(pDialogToken, pFramePtr, 1);
+       pFramePtr += 1;
+       MsgLen -= 1;
+
+       eid_ptr = (PEID_STRUCT)pFramePtr;
+       while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
+       {
+               switch(eid_ptr->Eid)
+               {
+                       case IE_MEASUREMENT_REQUEST:
+                               NdisMoveMemory(&pMeasureReqInfo->Token, eid_ptr->Octet, 1);
+                               NdisMoveMemory(&pMeasureReqInfo->ReqMode.word, eid_ptr->Octet + 1, 1);
+                               NdisMoveMemory(&pMeasureReqInfo->ReqType, eid_ptr->Octet + 2, 1);
+                               ptr = eid_ptr->Octet + 3;
+                               NdisMoveMemory(&pMeasureReqInfo->MeasureReq.ChNum, ptr, 1);
+                               NdisMoveMemory(&MeasureStartTime, ptr + 1, 8);
+                               pMeasureReqInfo->MeasureReq.MeasureStartTime = SWAP64(MeasureStartTime);
+                               NdisMoveMemory(&MeasureDuration, ptr + 9, 2);
+                               pMeasureReqInfo->MeasureReq.MeasureDuration = SWAP16(MeasureDuration);
+
+                               result = TRUE;
+                               break;
+
+                       default:
+                               break;
+               }
+               eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
+       }
+
+       return result;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Measurement report action frame sanity check.
+
+       Parametrs:
+               1. MLME message containing the received frame
+               2. message length.
+               3. Measurement report infomation buffer.
+               4. basic report infomation buffer.
+
+       Return  : None.
+       ==========================================================================
+ */
+
+/*
+  Measurement Report IE.
+  +----+-----+-------+-------------+--------------+----------------+
+  | ID | Len | Token | Report Mode | Measure Type | Measure Report |
+  +----+-----+-------+-------------+--------------+----------------+
+    1     1      1          1             1            variable
+
+  Basic Report.
+  +--------+------------+----------+-----+
+  | Ch Num | Start Time | Duration | Map |
+  +--------+------------+----------+-----+
+      1          8           2        1
+
+  Map Field Bit Format.
+  +-----+---------------+---------------------+-------+------------+----------+
+  | Bss | OFDM Preamble | Unidentified signal | Radar | Unmeasured | Reserved |
+  +-----+---------------+---------------------+-------+------------+----------+
+     0          1                  2              3         4          5-7
+*/
+static BOOLEAN PeerMeasureReportSanity(
+       IN PRTMP_ADAPTER pAd,
+       IN VOID *pMsg,
+       IN ULONG MsgLen,
+       OUT PUINT8 pDialogToken,
+       OUT PMEASURE_REPORT_INFO pMeasureReportInfo,
+       OUT PUINT8 pReportBuf)
+{
+       PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
+       PUCHAR pFramePtr = Fr->Octet;
+       BOOLEAN result = FALSE;
+       PEID_STRUCT eid_ptr;
+       PUCHAR ptr;
+
+       // skip 802.11 header.
+       MsgLen -= sizeof(HEADER_802_11);
+
+       // skip category and action code.
+       pFramePtr += 2;
+       MsgLen -= 2;
+
+       if (pMeasureReportInfo == NULL)
+               return result;
+
+       NdisMoveMemory(pDialogToken, pFramePtr, 1);
+       pFramePtr += 1;
+       MsgLen -= 1;
+
+       eid_ptr = (PEID_STRUCT)pFramePtr;
+       while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
+       {
+               switch(eid_ptr->Eid)
+               {
+                       case IE_MEASUREMENT_REPORT:
+                               NdisMoveMemory(&pMeasureReportInfo->Token, eid_ptr->Octet, 1);
+                               NdisMoveMemory(&pMeasureReportInfo->ReportMode, eid_ptr->Octet + 1, 1);
+                               NdisMoveMemory(&pMeasureReportInfo->ReportType, eid_ptr->Octet + 2, 1);
+                               if (pMeasureReportInfo->ReportType == RM_BASIC)
+                               {
+                                       PMEASURE_BASIC_REPORT pReport = (PMEASURE_BASIC_REPORT)pReportBuf;
+                                       ptr = eid_ptr->Octet + 3;
+                                       NdisMoveMemory(&pReport->ChNum, ptr, 1);
+                                       NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
+                                       NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
+                                       NdisMoveMemory(&pReport->Map, ptr + 11, 1);
+
+                               }
+                               else if (pMeasureReportInfo->ReportType == RM_CCA)
+                               {
+                                       PMEASURE_CCA_REPORT pReport = (PMEASURE_CCA_REPORT)pReportBuf;
+                                       ptr = eid_ptr->Octet + 3;
+                                       NdisMoveMemory(&pReport->ChNum, ptr, 1);
+                                       NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
+                                       NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
+                                       NdisMoveMemory(&pReport->CCA_Busy_Fraction, ptr + 11, 1);
+
+                               }
+                               else if (pMeasureReportInfo->ReportType == RM_RPI_HISTOGRAM)
+                               {
+                                       PMEASURE_RPI_REPORT pReport = (PMEASURE_RPI_REPORT)pReportBuf;
+                                       ptr = eid_ptr->Octet + 3;
+                                       NdisMoveMemory(&pReport->ChNum, ptr, 1);
+                                       NdisMoveMemory(&pReport->MeasureStartTime, ptr + 1, 8);
+                                       NdisMoveMemory(&pReport->MeasureDuration, ptr + 9, 2);
+                                       NdisMoveMemory(&pReport->RPI_Density, ptr + 11, 8);
+                               }
+                               result = TRUE;
+                break;
+
+                       default:
+                               break;
+               }
+               eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
+       }
+
+       return result;
+}
+
+/*
+       ==========================================================================
+       Description:
+               TPC Request action frame sanity check.
+
+       Parametrs:
+               1. MLME message containing the received frame
+               2. message length.
+               3. Dialog Token.
+
+       Return  : None.
+       ==========================================================================
+ */
+static BOOLEAN PeerTpcReqSanity(
+       IN PRTMP_ADAPTER pAd,
+       IN VOID *pMsg,
+       IN ULONG MsgLen,
+       OUT PUINT8 pDialogToken)
+{
+       PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
+       PUCHAR pFramePtr = Fr->Octet;
+       BOOLEAN result = FALSE;
+       PEID_STRUCT eid_ptr;
+
+       MsgLen -= sizeof(HEADER_802_11);
+
+       // skip category and action code.
+       pFramePtr += 2;
+       MsgLen -= 2;
+
+       if (pDialogToken == NULL)
+               return result;
+
+       NdisMoveMemory(pDialogToken, pFramePtr, 1);
+       pFramePtr += 1;
+       MsgLen -= 1;
+
+       eid_ptr = (PEID_STRUCT)pFramePtr;
+       while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
+       {
+               switch(eid_ptr->Eid)
+               {
+                       case IE_TPC_REQUEST:
+                               result = TRUE;
+                break;
+
+                       default:
+                               break;
+               }
+               eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
+       }
+
+       return result;
+}
+
+/*
+       ==========================================================================
+       Description:
+               TPC Report action frame sanity check.
+
+       Parametrs:
+               1. MLME message containing the received frame
+               2. message length.
+               3. Dialog Token.
+               4. TPC Report IE.
+
+       Return  : None.
+       ==========================================================================
+ */
+static BOOLEAN PeerTpcRepSanity(
+       IN PRTMP_ADAPTER pAd,
+       IN VOID *pMsg,
+       IN ULONG MsgLen,
+       OUT PUINT8 pDialogToken,
+       OUT PTPC_REPORT_INFO pTpcRepInfo)
+{
+       PFRAME_802_11 Fr = (PFRAME_802_11)pMsg;
+       PUCHAR pFramePtr = Fr->Octet;
+       BOOLEAN result = FALSE;
+       PEID_STRUCT eid_ptr;
+
+       MsgLen -= sizeof(HEADER_802_11);
+
+       // skip category and action code.
+       pFramePtr += 2;
+       MsgLen -= 2;
+
+       if (pDialogToken == NULL)
+               return result;
+
+       NdisMoveMemory(pDialogToken, pFramePtr, 1);
+       pFramePtr += 1;
+       MsgLen -= 1;
+
+       eid_ptr = (PEID_STRUCT)pFramePtr;
+       while (((UCHAR*)eid_ptr + eid_ptr->Len + 1) < ((PUCHAR)pFramePtr + MsgLen))
+       {
+               switch(eid_ptr->Eid)
+               {
+                       case IE_TPC_REPORT:
+                               NdisMoveMemory(&pTpcRepInfo->TxPwr, eid_ptr->Octet, 1);
+                               NdisMoveMemory(&pTpcRepInfo->LinkMargin, eid_ptr->Octet + 1, 1);
+                               result = TRUE;
+                break;
+
+                       default:
+                               break;
+               }
+               eid_ptr = (PEID_STRUCT)((UCHAR*)eid_ptr + 2 + eid_ptr->Len);
+       }
+
+       return result;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Channel Switch Announcement action frame handler.
+
+       Parametrs:
+               Elme - MLME message containing the received frame
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID PeerChSwAnnAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+{
+       CH_SW_ANN_INFO ChSwAnnInfo;
+       PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
+#ifdef CONFIG_STA_SUPPORT
+       UCHAR index = 0, Channel = 0, NewChannel = 0;
+       ULONG Bssidx = 0;
+#endif // CONFIG_STA_SUPPORT //
+
+       NdisZeroMemory(&ChSwAnnInfo, sizeof(CH_SW_ANN_INFO));
+       if (! PeerChSwAnnSanity(pAd, Elem->Msg, Elem->MsgLen, &ChSwAnnInfo))
+       {
+               DBGPRINT(RT_DEBUG_TRACE, ("Invalid Channel Switch Action Frame.\n"));
+               return;
+       }
+
+
+#ifdef CONFIG_STA_SUPPORT
+       if (pAd->OpMode == OPMODE_STA)
+       {
+               Bssidx = BssTableSearch(&pAd->ScanTab, pFr->Hdr.Addr3, pAd->CommonCfg.Channel);
+               if (Bssidx == BSS_NOT_FOUND)
+               {
+                       DBGPRINT(RT_DEBUG_TRACE, ("PeerChSwAnnAction - Bssidx is not found\n"));
+                       return;
+               }
+
+               DBGPRINT(RT_DEBUG_TRACE, ("\n****Bssidx is %d, Channel = %d\n", index, pAd->ScanTab.BssEntry[Bssidx].Channel));
+               hex_dump("SSID",pAd->ScanTab.BssEntry[Bssidx].Bssid ,6);
+
+               Channel = pAd->CommonCfg.Channel;
+               NewChannel = ChSwAnnInfo.Channel;
+
+               if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel))
+               {
+                       // Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection).
+                       // In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results.
+                       AsicSwitchChannel(pAd, 1, FALSE);
+                       AsicLockChannel(pAd, 1);
+                   LinkDown(pAd, FALSE);
+                       MlmeQueueInit(&pAd->Mlme.Queue);
+                       BssTableInit(&pAd->ScanTab);
+                   RTMPusecDelay(1000000);             // use delay to prevent STA do reassoc
+
+                       // channel sanity check
+                       for (index = 0 ; index < pAd->ChannelListNum; index++)
+                       {
+                               if (pAd->ChannelList[index].Channel == NewChannel)
+                               {
+                                       pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel;
+                                       pAd->CommonCfg.Channel = NewChannel;
+                                       AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
+                                       AsicLockChannel(pAd, pAd->CommonCfg.Channel);
+                                       DBGPRINT(RT_DEBUG_TRACE, ("&&&&&&&&&&&&&&&&PeerChSwAnnAction - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel));
+                                       break;
+                               }
+                       }
+
+                       if (index >= pAd->ChannelListNum)
+                       {
+                               DBGPRINT_ERR(("&&&&&&&&&&&&&&&&&&&&&&&&&&PeerChSwAnnAction(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum));
+                       }
+               }
+       }
+#endif // CONFIG_STA_SUPPORT //
+
+       return;
+}
+
+
+/*
+       ==========================================================================
+       Description:
+               Measurement Request action frame handler.
+
+       Parametrs:
+               Elme - MLME message containing the received frame
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID PeerMeasureReqAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+{
+       PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
+       UINT8 DialogToken;
+       MEASURE_REQ_INFO MeasureReqInfo;
+       MEASURE_REPORT_MODE ReportMode;
+
+       if(PeerMeasureReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo))
+       {
+               ReportMode.word = 0;
+               ReportMode.field.Incapable = 1;
+               EnqueueMeasurementRep(pAd, pFr->Hdr.Addr2, DialogToken, MeasureReqInfo.Token, ReportMode.word, MeasureReqInfo.ReqType, 0, NULL);
+       }
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Measurement Report action frame handler.
+
+       Parametrs:
+               Elme - MLME message containing the received frame
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID PeerMeasureReportAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+{
+       MEASURE_REPORT_INFO MeasureReportInfo;
+       PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
+       UINT8 DialogToken;
+       PUINT8 pMeasureReportInfo;
+
+//     if (pAd->CommonCfg.bIEEE80211H != TRUE)
+//             return;
+
+       if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT)));
+               return;
+       }
+
+       NdisZeroMemory(&MeasureReportInfo, sizeof(MEASURE_REPORT_INFO));
+       NdisZeroMemory(pMeasureReportInfo, sizeof(MEASURE_RPI_REPORT));
+       if (PeerMeasureReportSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, pMeasureReportInfo))
+       {
+               do {
+                       PMEASURE_REQ_ENTRY pEntry = NULL;
+
+                       // Not a autonomous measure report.
+                       // check the dialog token field. drop it if the dialog token doesn't match.
+                       if ((DialogToken != 0)
+                               && ((pEntry = MeasureReqLookUp(pAd, DialogToken)) == NULL))
+                               break;
+
+                       if (pEntry != NULL)
+                               MeasureReqDelete(pAd, pEntry->DialogToken);
+
+                       if (MeasureReportInfo.ReportType == RM_BASIC)
+                       {
+                               PMEASURE_BASIC_REPORT pBasicReport = (PMEASURE_BASIC_REPORT)pMeasureReportInfo;
+                               if ((pBasicReport->Map.field.Radar)
+                                       && (DfsRequirementCheck(pAd, pBasicReport->ChNum) == TRUE))
+                               {
+                                       NotifyChSwAnnToPeerAPs(pAd, pFr->Hdr.Addr1, pFr->Hdr.Addr2, 1, pBasicReport->ChNum);
+                                       StartDFSProcedure(pAd, pBasicReport->ChNum, 1);
+                               }
+                       }
+               } while (FALSE);
+       }
+       else
+               DBGPRINT(RT_DEBUG_TRACE, ("Invalid Measurement Report Frame.\n"));
+
+       kfree(pMeasureReportInfo);
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               TPC Request action frame handler.
+
+       Parametrs:
+               Elme - MLME message containing the received frame
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID PeerTpcReqAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+{
+       PFRAME_802_11 pFr = (PFRAME_802_11)Elem->Msg;
+       PUCHAR pFramePtr = pFr->Octet;
+       UINT8 DialogToken;
+       UINT8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid);
+       UINT8 LinkMargin = 0;
+       CHAR RealRssi;
+
+       // link margin: Ratio of the received signal power to the minimum desired by the station (STA). The
+       //                              STA may incorporate rate information and channel conditions, including interference, into its computation
+       //                              of link margin.
+
+       RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0),
+                                                               ConvertToRssi(pAd, Elem->Rssi1, RSSI_1),
+                                                               ConvertToRssi(pAd, Elem->Rssi2, RSSI_2));
+
+       // skip Category and action code.
+       pFramePtr += 2;
+
+       // Dialog token.
+       NdisMoveMemory(&DialogToken, pFramePtr, 1);
+
+       LinkMargin = (RealRssi / MIN_RCV_PWR);
+       if (PeerTpcReqSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken))
+               EnqueueTPCRep(pAd, pFr->Hdr.Addr2, DialogToken, TxPwr, LinkMargin);
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               TPC Report action frame handler.
+
+       Parametrs:
+               Elme - MLME message containing the received frame
+
+       Return  : None.
+       ==========================================================================
+ */
+static VOID PeerTpcRepAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+{
+       UINT8 DialogToken;
+       TPC_REPORT_INFO TpcRepInfo;
+       PTPC_REQ_ENTRY pEntry = NULL;
+
+       NdisZeroMemory(&TpcRepInfo, sizeof(TPC_REPORT_INFO));
+       if (PeerTpcRepSanity(pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo))
+       {
+               if ((pEntry = TpcReqLookUp(pAd, DialogToken)) != NULL)
+               {
+                       TpcReqDelete(pAd, pEntry->DialogToken);
+                       DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n",
+                               __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin));
+               }
+       }
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+               Spectrun action frames Handler such as channel switch annoucement,
+               measurement report, measurement request actions frames.
+
+       Parametrs:
+               Elme - MLME message containing the received frame
+
+       Return  : None.
+       ==========================================================================
+ */
+VOID PeerSpectrumAction(
+       IN PRTMP_ADAPTER pAd,
+       IN MLME_QUEUE_ELEM *Elem)
+{
+
+       UCHAR   Action = Elem->Msg[LENGTH_802_11+1];
+
+       if (pAd->CommonCfg.bIEEE80211H != TRUE)
+               return;
+
+       switch(Action)
+       {
+               case SPEC_MRQ:
+                       // current rt2860 unable do such measure specified in Measurement Request.
+                       // reject all measurement request.
+                       PeerMeasureReqAction(pAd, Elem);
+                       break;
+
+               case SPEC_MRP:
+                       PeerMeasureReportAction(pAd, Elem);
+                       break;
+
+               case SPEC_TPCRQ:
+                       PeerTpcReqAction(pAd, Elem);
+                       break;
+
+               case SPEC_TPCRP:
+                       PeerTpcRepAction(pAd, Elem);
+                       break;
+
+               case SPEC_CHANNEL_SWITCH:
+{
+#ifdef DOT11N_DRAFT3
+                               SEC_CHA_OFFSET_IE       Secondary;
+                               CHA_SWITCH_ANNOUNCE_IE  ChannelSwitch;
+
+                               // 802.11h only has Channel Switch Announcement IE.
+                               RTMPMoveMemory(&ChannelSwitch, &Elem->Msg[LENGTH_802_11+4], sizeof (CHA_SWITCH_ANNOUNCE_IE));
+
+                               // 802.11n D3.03 adds secondary channel offset element in the end.
+                               if (Elem->MsgLen ==  (LENGTH_802_11 + 2 + sizeof (CHA_SWITCH_ANNOUNCE_IE) + sizeof (SEC_CHA_OFFSET_IE)))
+                               {
+                                       RTMPMoveMemory(&Secondary, &Elem->Msg[LENGTH_802_11+9], sizeof (SEC_CHA_OFFSET_IE));
+                               }
+                               else
+                               {
+                                       Secondary.SecondaryChannelOffset = 0;
+                               }
+
+                               if ((Elem->Msg[LENGTH_802_11+2] == IE_CHANNEL_SWITCH_ANNOUNCEMENT) && (Elem->Msg[LENGTH_802_11+3] == 3))
+                               {
+                                       ChannelSwitchAction(pAd, Elem->Wcid, ChannelSwitch.NewChannel, Secondary.SecondaryChannelOffset);
+                               }
+#endif // DOT11N_DRAFT3 //
+}
+                       PeerChSwAnnAction(pAd, Elem);
+                       break;
+       }
+
+       return;
+}
+
+/*
+       ==========================================================================
+       Description:
+
+       Parametrs:
+
+       Return  : None.
+       ==========================================================================
+ */
+INT Set_MeasureReq_Proc(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      PUCHAR                  arg)
+{
+       UINT Aid = 1;
+       UINT ArgIdx;
+       PUCHAR thisChar;
+
+       MEASURE_REQ_MODE MeasureReqMode;
+       UINT8 MeasureReqToken = RandomByte(pAd);
+       UINT8 MeasureReqType = RM_BASIC;
+       UINT8 MeasureCh = 1;
+
+       ArgIdx = 1;
+       while ((thisChar = strsep((char **)&arg, "-")) != NULL)
+       {
+               switch(ArgIdx)
+               {
+                       case 1: // Aid.
+                               Aid = simple_strtol(thisChar, 0, 16);
+                               break;
+
+                       case 2: // Measurement Request Type.
+                               MeasureReqType = simple_strtol(thisChar, 0, 16);
+                               if (MeasureReqType > 3)
+                               {
+                                       DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType));
+                                       return TRUE;
+                               }
+                               break;
+
+                       case 3: // Measurement channel.
+                               MeasureCh = simple_strtol(thisChar, 0, 16);
+                               break;
+               }
+               ArgIdx++;
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh));
+       if (!VALID_WCID(Aid))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid));
+               return TRUE;
+       }
+
+       MeasureReqMode.word = 0;
+       MeasureReqMode.field.Enable = 1;
+
+       MeasureReqInsert(pAd, MeasureReqToken);
+
+       EnqueueMeasurementReq(pAd, pAd->MacTab.Content[Aid].Addr,
+               MeasureReqToken, MeasureReqMode.word, MeasureReqType, MeasureCh, 2000);
+
+       return TRUE;
+}
+
+INT Set_TpcReq_Proc(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      PUCHAR                  arg)
+{
+       UINT Aid;
+
+       UINT8 TpcReqToken = RandomByte(pAd);
+
+       Aid = simple_strtol(arg, 0, 16);
+
+       DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid));
+       if (!VALID_WCID(Aid))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid));
+               return TRUE;
+       }
+
+       TpcReqInsert(pAd, TpcReqToken);
+
+       EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken);
+
+       return TRUE;
+}
+