]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/staging/rt3070/sta/aironet.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / staging / rt3070 / sta / aironet.c
diff --git a/drivers/staging/rt3070/sta/aironet.c b/drivers/staging/rt3070/sta/aironet.c
new file mode 100644 (file)
index 0000000..4af4a19
--- /dev/null
@@ -0,0 +1,1312 @@
+/*
+ *************************************************************************
+ * 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:
+       aironet.c
+
+       Abstract:
+
+       Revision History:
+       Who                     When                    What
+       --------        ----------              ----------------------------------------------
+       Paul Lin        04-06-15                Initial
+*/
+#include "../rt_config.h"
+
+/*
+       ==========================================================================
+       Description:
+               association     state machine init,     including state transition and timer init
+       Parameters:
+               S -     pointer to the association state machine
+       ==========================================================================
+ */
+VOID   AironetStateMachineInit(
+       IN      PRTMP_ADAPTER           pAd,
+       IN      STATE_MACHINE           *S,
+       OUT     STATE_MACHINE_FUNC      Trans[])
+{
+       StateMachineInit(S,     Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE);
+       StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction);
+       StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction);
+       StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction);
+}
+
+/*
+       ==========================================================================
+       Description:
+               This is state machine function.
+               When receiving EAPOL packets which is  for 802.1x key management.
+               Use     both in WPA, and WPAPSK case.
+               In this function, further dispatch to different functions according     to the received packet.  3 categories are :
+                 1.  normal 4-way pairwisekey and 2-way groupkey handshake
+                 2.  MIC error (Countermeasures attack)  report packet from STA.
+                 3.  Request for pairwise/group key update     from STA
+       Return:
+       ==========================================================================
+*/
+VOID   AironetMsgAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      MLME_QUEUE_ELEM *Elem)
+{
+       USHORT                                                  Length;
+       UCHAR                                                   Index, i;
+       PUCHAR                                                  pData;
+       PAIRONET_RM_REQUEST_FRAME               pRMReq;
+       PRM_REQUEST_ACTION                              pReqElem;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n"));
+
+       // 0. Get Aironet IAPP header first
+       pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11];
+       pData  = (PUCHAR) &Elem->Msg[LENGTH_802_11];
+
+       // 1. Change endian format form network to little endian
+       Length = be2cpu16(pRMReq->IAPP.Length);
+
+       // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled
+       if (pAd->StaCfg.CCXEnable != TRUE)
+               return;
+
+       // 2.1 Radio measurement must be on
+       if (pAd->StaCfg.CCXControl.field.RMEnable != 1)
+               return;
+
+       // 2.2. Debug print all bit information
+       DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length));
+       DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type));
+       DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType));
+       DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token));
+       DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay));
+       DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset));
+
+       // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension
+       if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n"));
+               return;
+       }
+
+       // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request.
+       //    Since we are acting as client only, we will disregards reply subtype.
+       if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST)
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n"));
+               return;
+       }
+
+       // 5. Verify Destination MAC and Source MAC, both should be all zeros.
+       if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n"));
+               return;
+       }
+
+       if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR))
+       {
+               DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n"));
+               return;
+       }
+
+       // 6. Reinit all report related fields
+       NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048);
+       NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE);
+       NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4);
+
+       // 7. Point to the start of first element report element
+       pAd->StaCfg.FrameReportLen   = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER);
+       DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen));
+       pAd->StaCfg.LastBssIndex     = 0xff;
+       pAd->StaCfg.RMReqCnt         = 0;
+       pAd->StaCfg.ParallelReq      = FALSE;
+       pAd->StaCfg.ParallelDuration = 0;
+       pAd->StaCfg.ParallelChannel  = 0;
+       pAd->StaCfg.IAPPToken        = pRMReq->IAPP.Token;
+       pAd->StaCfg.CurrentRMReqIdx  = 0;
+       pAd->StaCfg.CLBusyBytes      = 0;
+       // Reset the statistics
+       for (i = 0; i < 8; i++)
+               pAd->StaCfg.RPIDensity[i] = 0;
+
+       Index = 0;
+
+       // 8. Save dialog token for report
+       pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token;
+
+       // Save Activation delay & measurement offset, Not really needed
+
+       // 9. Point to the first request element
+       pData += sizeof(AIRONET_RM_REQUEST_FRAME);
+       //    Length should exclude the CISCO Aironet SNAP header
+       Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H);
+
+       // 10. Start Parsing the Measurement elements.
+       //    Be careful about multiple MR elements within one frames.
+       while (Length > 0)
+       {
+               pReqElem = (PRM_REQUEST_ACTION) pData;
+               switch (pReqElem->ReqElem.Eid)
+               {
+                       case IE_MEASUREMENT_REQUEST:
+                               // From the example, it seems we only need to support one request in one frame
+                               // There is no multiple request in one frame.
+                               // Besides, looks like we need to take care the measurement request only.
+                               // The measurement request is always 4 bytes.
+
+                               // Start parsing this type of request.
+                               // 0. Eid is IE_MEASUREMENT_REQUEST
+                               // 1. Length didn't include Eid and Length field, it always be 8.
+                               // 2. Measurement Token, we nned to save it for the corresponding report.
+                               // 3. Measurement Mode, Although there are definitions, but we din't see value other than
+                               //    0 from test specs examples.
+                               // 4. Measurement Type, this is what we need to do.
+                               switch (pReqElem->ReqElem.Type)
+                               {
+                                       case MSRN_TYPE_CHANNEL_LOAD_REQ:
+                                       case MSRN_TYPE_NOISE_HIST_REQ:
+                                       case MSRN_TYPE_BEACON_REQ:
+                                               // Check the Enable non-serving channel measurement control
+                                               if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0)
+                                               {
+                                                       // Check channel before enqueue the action
+                                                       if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel)
+                                                               break;
+                                               }
+                                               else
+                                               {
+                                                       // If off channel measurement, check the TU duration limit
+                                                       if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel)
+                                                               if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit)
+                                                                       break;
+                                               }
+
+                                               // Save requests and execute actions later
+                                               NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION));
+                                               Index += 1;
+                                               break;
+
+                                       case MSRN_TYPE_FRAME_REQ:
+                                               // Since it's option, we will support later
+                                               // FrameRequestAction(pAd, pData);
+                                               break;
+
+                                       default:
+                                               break;
+                               }
+
+                               // Point to next Measurement request
+                               pData  += sizeof(RM_REQUEST_ACTION);
+                               Length -= sizeof(RM_REQUEST_ACTION);
+                               break;
+
+                       // We accept request only, all others are dropped
+                       case IE_MEASUREMENT_REPORT:
+                       case IE_AP_TX_POWER:
+                       case IE_MEASUREMENT_CAPABILITY:
+                       default:
+                               return;
+               }
+       }
+
+       // 11. Update some flags and index
+       pAd->StaCfg.RMReqCnt = Index;
+
+       if (Index)
+       {
+               MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL);
+               RT28XX_MLME_HANDLER(pAd);
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+
+       Arguments:
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   AironetRequestAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      MLME_QUEUE_ELEM *Elem)
+{
+       PRM_REQUEST_ACTION      pReq;
+
+       // 1. Point to next request element
+       pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
+
+       // 2. Parse measurement type and call appropriate functions
+       if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
+               // Channel Load measurement request
+               ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+       else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
+               // Noise Histogram measurement request
+               NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+       else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ)
+               // Beacon measurement request
+               BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+       else
+               // Unknown. Do nothing and return, this should never happen
+               return;
+
+       // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one
+       if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt)
+       {
+               pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1];
+               // Check for parallel bit
+               if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel))
+               {
+                       // Update parallel mode request information
+                       pAd->StaCfg.ParallelReq = TRUE;
+                       pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ?
+                       (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime));
+               }
+       }
+
+       // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used
+       RT28XX_MLME_HANDLER(pAd);
+
+}
+
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Prepare channel load report action, special scan operation added
+               to support
+
+       Arguments:
+               pAd     Pointer to our adapter
+               pData           Start from element ID
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   ChannelLoadRequestAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   Index)
+{
+       PRM_REQUEST_ACTION                              pReq;
+       MLME_SCAN_REQ_STRUCT                    ScanReq;
+       UCHAR                                                   ZeroSsid[32];
+       NDIS_STATUS                                             NStatus;
+       PUCHAR                                                  pOutBuffer = NULL;
+       PHEADER_802_11                                  pNullFrame;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n"));
+
+       pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
+       NdisZeroMemory(ZeroSsid, 32);
+
+       // Prepare for special scan request
+       // The scan definition is different with our Active, Passive scan definition.
+       // For CCX2, Active means send out probe request with broadcast BSSID.
+       // Passive means no probe request sent, only listen to the beacons.
+       // The channel scanned is fixed as specified, no need to scan all channels.
+       // The scan wait time is specified in the request too.
+       // Passive scan Mode
+
+       // Control state machine is not idle, reject the request
+       if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
+               return;
+
+       // Fill out stuff for scan request
+       ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD);
+       MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
+       pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
+
+       // Reset some internal control flags to make sure this scan works.
+       BssTableInit(&pAd->StaCfg.CCXBssTab);
+       pAd->StaCfg.ScanCnt        = 0;
+       pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
+       pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel));
+
+       // If it's non serving channel scan, send out a null frame with PSM bit on.
+       if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
+       {
+               // Use MLME enqueue method
+               NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+               if (NStatus     != NDIS_STATUS_SUCCESS)
+                       return;
+
+               pNullFrame = (PHEADER_802_11) pOutBuffer;;
+               // Make the power save Null frame with PSM bit on
+               MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
+               pNullFrame->Duration    = 0;
+               pNullFrame->FC.Type     = BTYPE_DATA;
+               pNullFrame->FC.PwrMgmt  = PWR_SAVE;
+
+               // Send using priority queue
+               MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
+               MlmeFreeMemory(pAd, pOutBuffer);
+               DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
+               RTMPusecDelay(5000);
+       }
+
+       pAd->StaCfg.CCXReqType     = MSRN_TYPE_CHANNEL_LOAD_REQ;
+       pAd->StaCfg.CLBusyBytes    = 0;
+       // Enable Rx with promiscuous reception
+       RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010);
+
+       // Set channel load measurement flag
+       RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
+
+       pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Prepare noise histogram report action, special scan operation added
+               to support
+
+       Arguments:
+               pAd     Pointer to our adapter
+               pData           Start from element ID
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   NoiseHistRequestAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   Index)
+{
+       PRM_REQUEST_ACTION                              pReq;
+       MLME_SCAN_REQ_STRUCT                    ScanReq;
+       UCHAR                                                   ZeroSsid[32], i;
+       NDIS_STATUS                                             NStatus;
+       PUCHAR                                                  pOutBuffer = NULL;
+       PHEADER_802_11                                  pNullFrame;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n"));
+
+       pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
+       NdisZeroMemory(ZeroSsid, 32);
+
+       // Prepare for special scan request
+       // The scan definition is different with our Active, Passive scan definition.
+       // For CCX2, Active means send out probe request with broadcast BSSID.
+       // Passive means no probe request sent, only listen to the beacons.
+       // The channel scanned is fixed as specified, no need to scan all channels.
+       // The scan wait time is specified in the request too.
+       // Passive scan Mode
+
+       // Control state machine is not idle, reject the request
+       if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
+               return;
+
+       // Fill out stuff for scan request
+       ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE);
+       MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
+       pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
+
+       // Reset some internal control flags to make sure this scan works.
+       BssTableInit(&pAd->StaCfg.CCXBssTab);
+       pAd->StaCfg.ScanCnt        = 0;
+       pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
+       pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
+       pAd->StaCfg.CCXReqType     = MSRN_TYPE_NOISE_HIST_REQ;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel));
+
+       // If it's non serving channel scan, send out a null frame with PSM bit on.
+       if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
+       {
+               // Use MLME enqueue method
+               NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+               if (NStatus     != NDIS_STATUS_SUCCESS)
+                       return;
+
+               pNullFrame = (PHEADER_802_11) pOutBuffer;
+               // Make the power save Null frame with PSM bit on
+               MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
+               pNullFrame->Duration    = 0;
+               pNullFrame->FC.Type     = BTYPE_DATA;
+               pNullFrame->FC.PwrMgmt  = PWR_SAVE;
+
+               // Send using priority queue
+               MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
+               MlmeFreeMemory(pAd, pOutBuffer);
+               DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
+               RTMPusecDelay(5000);
+       }
+
+       // Reset the statistics
+       for (i = 0; i < 8; i++)
+               pAd->StaCfg.RPIDensity[i] = 0;
+
+       // Enable Rx with promiscuous reception
+       RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010);
+
+       // Set channel load measurement flag
+       RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
+
+       pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Prepare Beacon report action, special scan operation added
+               to support
+
+       Arguments:
+               pAd     Pointer to our adapter
+               pData           Start from element ID
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   BeaconRequestAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   Index)
+{
+       PRM_REQUEST_ACTION                              pReq;
+       NDIS_STATUS                                             NStatus;
+       PUCHAR                                                  pOutBuffer = NULL;
+       PHEADER_802_11                                  pNullFrame;
+       MLME_SCAN_REQ_STRUCT                    ScanReq;
+       UCHAR                                                   ZeroSsid[32];
+
+       DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n"));
+
+       pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
+       NdisZeroMemory(ZeroSsid, 32);
+
+       // Prepare for special scan request
+       // The scan definition is different with our Active, Passive scan definition.
+       // For CCX2, Active means send out probe request with broadcast BSSID.
+       // Passive means no probe request sent, only listen to the beacons.
+       // The channel scanned is fixed as specified, no need to scan all channels.
+       // The scan wait time is specified in the request too.
+       if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE)
+       {
+               // Passive scan Mode
+               DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n"));
+
+               // Control state machine is not idle, reject the request
+               if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
+                       return;
+
+               // Fill out stuff for scan request
+               ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE);
+               MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
+               pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
+
+               // Reset some internal control flags to make sure this scan works.
+               BssTableInit(&pAd->StaCfg.CCXBssTab);
+               pAd->StaCfg.ScanCnt        = 0;
+               pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
+               pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
+               pAd->StaCfg.CCXReqType     = MSRN_TYPE_BEACON_REQ;
+               DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration));
+
+               // If it's non serving channel scan, send out a null frame with PSM bit on.
+               if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
+               {
+                       // Use MLME enqueue method
+                       NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+                       if (NStatus     != NDIS_STATUS_SUCCESS)
+                               return;
+
+                       pNullFrame = (PHEADER_802_11) pOutBuffer;
+                       // Make the power save Null frame with PSM bit on
+                       MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
+                       pNullFrame->Duration    = 0;
+                       pNullFrame->FC.Type     = BTYPE_DATA;
+                       pNullFrame->FC.PwrMgmt  = PWR_SAVE;
+
+                       // Send using priority queue
+                       MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
+                       MlmeFreeMemory(pAd, pOutBuffer);
+                       DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
+                       RTMPusecDelay(5000);
+               }
+
+               pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
+       }
+       else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE)
+       {
+               // Active scan Mode
+               DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n"));
+
+               // Control state machine is not idle, reject the request
+               if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE)
+                       return;
+
+               // Fill out stuff for scan request
+               ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE);
+               MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
+               pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
+
+               // Reset some internal control flags to make sure this scan works.
+               BssTableInit(&pAd->StaCfg.CCXBssTab);
+               pAd->StaCfg.ScanCnt        = 0;
+               pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
+               pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
+               pAd->StaCfg.CCXReqType     = MSRN_TYPE_BEACON_REQ;
+               DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration));
+
+               // If it's non serving channel scan, send out a null frame with PSM bit on.
+               if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
+               {
+                       // Use MLME enqueue method
+                       NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
+                       if (NStatus     != NDIS_STATUS_SUCCESS)
+                               return;
+
+                       pNullFrame = (PHEADER_802_11) pOutBuffer;
+                       // Make the power save Null frame with PSM bit on
+                       MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
+                       pNullFrame->Duration    = 0;
+                       pNullFrame->FC.Type     = BTYPE_DATA;
+                       pNullFrame->FC.PwrMgmt  = PWR_SAVE;
+
+                       // Send using priority queue
+                       MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
+                       MlmeFreeMemory(pAd, pOutBuffer);
+                       DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
+                       RTMPusecDelay(5000);
+               }
+
+               pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
+       }
+       else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE)
+       {
+               // Beacon report Mode, report all the APS in current bss table
+               DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n"));
+
+               // Copy current BSS table to CCX table, we can omit this step later on.
+               NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE));
+
+               // Create beacon report from Bss table
+               AironetCreateBeaconReportFromBssTable(pAd);
+
+               // Set state to scanning
+               pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
+
+               // Enqueue report request
+               // Cisco scan request is finished, prepare beacon report
+               MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL);
+       }
+       else
+       {
+               // Wrong scan Mode
+               DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n"));
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+
+       Arguments:
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   AironetReportAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      MLME_QUEUE_ELEM *Elem)
+{
+       PRM_REQUEST_ACTION      pReq;
+       ULONG                           Now32;
+
+    NdisGetSystemUpTime(&Now32);
+       pAd->StaCfg.LastBeaconRxTime = Now32;
+
+       pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
+
+       DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n"));
+
+       // 1. Parse measurement type and call appropriate functions
+       if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
+               // Channel Load measurement request
+               ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+       else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
+               // Noise Histogram measurement request
+               NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+       else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ)
+               // Beacon measurement request
+               BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+       else
+               // Unknown. Do nothing and return
+               ;
+
+       // 2. Point to the correct index of action element, start from 0
+       pAd->StaCfg.CurrentRMReqIdx++;
+
+       // 3. Check for parallel actions
+       if (pAd->StaCfg.ParallelReq == TRUE)
+       {
+               pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
+
+               // Process next action right away
+               if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
+                       // Channel Load measurement request
+                       ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+               else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
+                       // Noise Histogram measurement request
+                       NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
+
+               pAd->StaCfg.ParallelReq = FALSE;
+               pAd->StaCfg.CurrentRMReqIdx++;
+       }
+
+       if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt)
+       {
+               // 4. There is no more unprocessed measurement request, go for transmit this report
+               AironetFinalReportAction(pAd);
+               pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
+       }
+       else
+       {
+               pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
+
+               if (pReq->Measurement.Channel != pAd->CommonCfg.Channel)
+               {
+                       RTMPusecDelay(100000);
+               }
+
+               // 5. There are more requests to be measure
+               MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL);
+               RT28XX_MLME_HANDLER(pAd);
+       }
+
+       DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+
+       Arguments:
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   AironetFinalReportAction(
+       IN      PRTMP_ADAPTER   pAd)
+{
+       PUCHAR                                  pDest;
+       PAIRONET_IAPP_HEADER    pIAPP;
+       PHEADER_802_11                  pHeader;
+       UCHAR                                   AckRate = RATE_2;
+       USHORT                                  AckDuration = 0;
+       NDIS_STATUS                             NStatus;
+       PUCHAR                                  pOutBuffer = NULL;
+       ULONG                                   FrameLen = 0;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n"));
+
+       // 0. Set up the frame pointer, Frame was inited at the end of message action
+       pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11];
+
+       // 1. Update report IAPP fields
+       pIAPP = (PAIRONET_IAPP_HEADER) pDest;
+
+       // 2. Copy Cisco SNAP header
+       NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H);
+
+       // 3. network order for this 16bit length
+       pIAPP->Length  = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H);
+
+       // 3.1 sanity check the report length, ignore it if there is nothing to report
+       if (be2cpu16(pIAPP->Length) <= 18)
+               return;
+
+       // 4. Type must be 0x32
+       pIAPP->Type    = AIRONET_IAPP_TYPE;
+
+       // 5. SubType for report must be 0x81
+       pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT;
+
+       // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function
+       //    We will do it again here. We can use BSSID instead
+       COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid);
+
+       // 7. SA is the client reporting which must be our MAC
+       COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress);
+
+       // 8. Copy the saved dialog token
+       pIAPP->Token = pAd->StaCfg.IAPPToken;
+
+       // 9. Make the Report frame 802.11 header
+       //    Reuse function in wpa.c
+       pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf;
+       pAd->Sequence ++;
+       WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid);
+
+       // ACK size     is 14 include CRC, and its rate is based on real time information
+       AckRate     = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate];
+       AckDuration = RTMPCalcDuration(pAd, AckRate, 14);
+       pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration;
+
+       // Use MLME enqueue method
+       NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
+       if (NStatus     != NDIS_STATUS_SUCCESS)
+               return;
+
+       // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything.
+       MakeOutgoingFrame(pOutBuffer,                       &FrameLen,
+                         pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf,
+                             END_OF_ARGS);
+
+       // 11. Send using priority queue
+       MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
+       MlmeFreeMemory(pAd, pOutBuffer);
+
+       pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+
+       Arguments:
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   ChannelLoadReportAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   Index)
+{
+       PMEASUREMENT_REPORT_ELEMENT     pReport;
+       PCHANNEL_LOAD_REPORT            pLoad;
+       PUCHAR                                          pDest;
+       UCHAR                                           CCABusyFraction;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n"));
+
+       // Disable Rx with promiscuous reception, make it back to normal
+       RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification.
+
+       // 0. Setup pointer for processing beacon & probe response
+       pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
+       pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
+
+       // 1. Fill Measurement report element field.
+       pReport->Eid    = IE_MEASUREMENT_REPORT;
+       // Fixed Length at 9, not include Eid and length fields
+       pReport->Length = 9;
+       pReport->Token  = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token;
+       pReport->Mode   = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode;
+       pReport->Type   = MSRN_TYPE_CHANNEL_LOAD_REQ;
+
+       // 2. Fill channel report measurement data
+       pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
+       pLoad  = (PCHANNEL_LOAD_REPORT) pDest;
+       pLoad->Channel  = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel;
+       pLoad->Spare    = 0;
+       pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration;
+
+       // 3. Calculate the CCA Busy Fraction
+       //    (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed
+       //     =  (Bytes + ACK) / 12 / duration
+       //     9 is the good value for pAd->StaCfg.CLFactor
+       // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration);
+       CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration);
+       if (CCABusyFraction < 10)
+                       CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1;
+
+       pLoad->CCABusy = CCABusyFraction;
+       DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction));
+
+       DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen));
+       pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT));
+       DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen));
+
+       // 4. Clear channel load measurement flag
+       RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
+
+       // 5. reset to idle state
+       pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+
+       Arguments:
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   NoiseHistReportAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   Index)
+{
+       PMEASUREMENT_REPORT_ELEMENT     pReport;
+       PNOISE_HIST_REPORT                      pNoise;
+       PUCHAR                                          pDest;
+       UCHAR                                           i,NoiseCnt;
+       USHORT                                          TotalRPICnt, TotalRPISum;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n"));
+
+       // 0. Disable Rx with promiscuous reception, make it back to normal
+       RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification.
+       // 1. Setup pointer for processing beacon & probe response
+       pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
+       pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
+
+       // 2. Fill Measurement report element field.
+       pReport->Eid    = IE_MEASUREMENT_REPORT;
+       // Fixed Length at 16, not include Eid and length fields
+       pReport->Length = 16;
+       pReport->Token  = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token;
+       pReport->Mode   = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode;
+       pReport->Type   = MSRN_TYPE_NOISE_HIST_REQ;
+
+       // 3. Fill noise histogram report measurement data
+       pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
+       pNoise  = (PNOISE_HIST_REPORT) pDest;
+       pNoise->Channel  = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel;
+       pNoise->Spare    = 0;
+       pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration;
+       // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU
+       //    We estimate 4000 normal packets received durning 10 seconds test.
+       //    Adjust it if required.
+       // 3 is a good value for pAd->StaCfg.NHFactor
+       // TotalRPICnt = pNoise->Duration * 3 / 10;
+       TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10;
+       TotalRPISum = 0;
+
+       for (i = 0; i < 8; i++)
+       {
+               TotalRPISum += pAd->StaCfg.RPIDensity[i];
+               DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i]));
+       }
+
+       // Double check if the counter is larger than our expectation.
+       // We will replace it with the total number plus a fraction.
+       if (TotalRPISum > TotalRPICnt)
+               TotalRPICnt = TotalRPISum + pNoise->Duration / 20;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt));
+
+       // 5. Initialize noise count for the total summation of 0xff
+       NoiseCnt = 0;
+       for (i = 1; i < 8; i++)
+       {
+               pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt);
+               if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0))
+                       pNoise->Density[i]++;
+               NoiseCnt += pNoise->Density[i];
+               DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d]  = 0x%02x\n", i, pNoise->Density[i]));
+       }
+
+       // 6. RPI[0] represents the rest of counts
+       pNoise->Density[0] = 0xff - NoiseCnt;
+       DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0]  = 0x%02x\n", pNoise->Density[0]));
+
+       pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT));
+
+       // 7. Clear channel load measurement flag
+       RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
+
+       // 8. reset to idle state
+       pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+               Prepare Beacon report action,
+
+       Arguments:
+               pAd     Pointer to our adapter
+
+       Return Value:
+               None
+
+       Note:
+
+       ========================================================================
+*/
+VOID   BeaconReportAction(
+       IN      PRTMP_ADAPTER   pAd,
+       IN      UCHAR                   Index)
+{
+       DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n"));
+
+       // Looks like we don't have anything thing need to do here.
+       // All measurement report already finished in AddBeaconReport
+       // The length is in the FrameReportLen
+
+       // reset Beacon index for next beacon request
+       pAd->StaCfg.LastBssIndex = 0xff;
+
+       // reset to idle state
+       pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n"));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+
+       Arguments:
+               Index           Current BSSID in CCXBsstab entry index
+
+       Return Value:
+
+       Note:
+
+       ========================================================================
+*/
+VOID   AironetAddBeaconReport(
+       IN      PRTMP_ADAPTER           pAd,
+       IN      ULONG                           Index,
+       IN      PMLME_QUEUE_ELEM        pElem)
+{
+       PVOID                                           pMsg;
+       PUCHAR                                          pSrc, pDest;
+       UCHAR                                           ReqIdx;
+       ULONG                                           MsgLen;
+       USHORT                                          Length;
+       PFRAME_802_11                           pFrame;
+       PMEASUREMENT_REPORT_ELEMENT     pReport;
+       PEID_STRUCT                             pEid;
+       PBEACON_REPORT                          pBeaconReport;
+       PBSS_ENTRY                                      pBss;
+
+       // 0. Setup pointer for processing beacon & probe response
+       pMsg   = pElem->Msg;
+       MsgLen = pElem->MsgLen;
+       pFrame = (PFRAME_802_11) pMsg;
+       pSrc   = pFrame->Octet;                         // Start from AP TSF
+       pBss   = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index];
+       ReqIdx = pAd->StaCfg.CurrentRMReqIdx;
+
+       // 1 Check the Index, if we already create this entry, only update the average RSSI
+       if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff))
+       {
+               pDest  = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]];
+               // Point to bss report information
+               pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
+               pBeaconReport = (PBEACON_REPORT) pDest;
+
+               // Update Rx power, in dBm
+               // Get the original RSSI readback from BBP
+               pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta;
+               // Average the Rssi reading
+               pBeaconReport->RxPower  = (pBeaconReport->RxPower + pBss->Rssi) / 2;
+               // Get to dBm format
+               pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta;
+
+               DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ",
+                       pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2],
+                       pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]));
+               DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256));
+               DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index]));
+
+               // Update other information here
+
+               // Done
+               return;
+       }
+
+       // 2. Update reported Index
+       pAd->StaCfg.LastBssIndex = Index;
+
+       // 3. Setup the buffer address for copying this BSSID into reporting frame
+       //    The offset should start after 802.11 header and report frame header.
+       pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
+
+       // 4. Save the start offset of each Bss in report frame
+       pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen;
+
+       // 5. Fill Measurement report fields
+       pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
+       pReport->Eid = IE_MEASUREMENT_REPORT;
+       pReport->Length = 0;
+       pReport->Token  = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token;
+       pReport->Mode   = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode;
+       pReport->Type   = MSRN_TYPE_BEACON_REQ;
+       Length          = sizeof(MEASUREMENT_REPORT_ELEMENT);
+       pDest          += sizeof(MEASUREMENT_REPORT_ELEMENT);
+
+       // 6. Start thebeacon report format
+       pBeaconReport = (PBEACON_REPORT) pDest;
+       pDest        += sizeof(BEACON_REPORT);
+       Length       += sizeof(BEACON_REPORT);
+
+       // 7. Copy Channel number
+       pBeaconReport->Channel        = pBss->Channel;
+       pBeaconReport->Spare          = 0;
+       pBeaconReport->Duration       = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration;
+       pBeaconReport->PhyType        = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS);
+       // 8. Rx power, in dBm
+       pBeaconReport->RxPower        = pBss->Rssi - pAd->BbpRssiToDbmDelta;
+
+       DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ",
+               pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2],
+               pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]));
+       DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256));
+       DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen));
+
+       pBeaconReport->BeaconInterval = pBss->BeaconPeriod;
+       COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3);
+       NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4);
+       NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4);
+       NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4);
+
+       // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo
+       pSrc += (TIMESTAMP_LEN + 2);
+       pBeaconReport->CapabilityInfo = *(USHORT *)pSrc;
+
+       // 10. Point to start of element ID
+       pSrc += 2;
+       pEid = (PEID_STRUCT) pSrc;
+
+       // 11. Start process all variable Eid oayload and add the appropriate to the frame report
+       while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen))
+       {
+               // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate,
+               // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set,
+               // TIM (report first 4 bytes only, radio measurement capability
+               switch (pEid->Eid)
+               {
+                       case IE_SSID:
+                       case IE_SUPP_RATES:
+                       case IE_FH_PARM:
+                       case IE_DS_PARM:
+                       case IE_CF_PARM:
+                       case IE_IBSS_PARM:
+                               NdisMoveMemory(pDest, pEid, pEid->Len + 2);
+                               pDest  += (pEid->Len + 2);
+                               Length += (pEid->Len + 2);
+                               break;
+
+                       case IE_MEASUREMENT_CAPABILITY:
+                               // Since this IE is duplicated with WPA security IE, we has to do sanity check before
+                               // recognize it.
+                               // 1. It also has fixed 6 bytes IE length.
+                               if (pEid->Len != 6)
+                                       break;
+                               // 2. Check the Cisco Aironet OUI
+                               if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3))
+                               {
+                                       // Matched, this is what we want
+                                       NdisMoveMemory(pDest, pEid, pEid->Len + 2);
+                                       pDest  += (pEid->Len + 2);
+                                       Length += (pEid->Len + 2);
+                               }
+                               break;
+
+                       case IE_TIM:
+                               if (pEid->Len > 4)
+                               {
+                                       // May truncate and report the first 4 bytes only, with the eid & len, total should be 6
+                                       NdisMoveMemory(pDest, pEid, 6);
+                                       pDest  += 6;
+                                       Length += 6;
+                               }
+                               else
+                               {
+                                       NdisMoveMemory(pDest, pEid, pEid->Len + 2);
+                                       pDest  += (pEid->Len + 2);
+                                       Length += (pEid->Len + 2);
+                               }
+                               break;
+
+                       default:
+                               break;
+               }
+               // 12. Move to next element ID
+               pSrc += (2 + pEid->Len);
+               pEid = (PEID_STRUCT) pSrc;
+       }
+
+       // 13. Update the length in the header, not include EID and length
+       pReport->Length = Length - 4;
+
+       // 14. Update the frame report buffer data length
+       pAd->StaCfg.FrameReportLen += Length;
+       DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen));
+}
+
+/*
+       ========================================================================
+
+       Routine Description:
+
+       Arguments:
+               Index           Current BSSID in CCXBsstab entry index
+
+       Return Value:
+
+       Note:
+
+       ========================================================================
+*/
+VOID   AironetCreateBeaconReportFromBssTable(
+       IN      PRTMP_ADAPTER           pAd)
+{
+       PMEASUREMENT_REPORT_ELEMENT     pReport;
+       PBEACON_REPORT                          pBeaconReport;
+       UCHAR                                           Index, ReqIdx;
+       USHORT                                          Length;
+       PUCHAR                                          pDest;
+       PBSS_ENTRY                                      pBss;
+
+       // 0. setup base pointer
+       ReqIdx = pAd->StaCfg.CurrentRMReqIdx;
+
+       for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++)
+       {
+               // 1. Setup the buffer address for copying this BSSID into reporting frame
+               //    The offset should start after 802.11 header and report frame header.
+               pDest  = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
+               pBss   = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index];
+               Length = 0;
+
+               // 2. Fill Measurement report fields
+               pReport         = (PMEASUREMENT_REPORT_ELEMENT) pDest;
+               pReport->Eid    = IE_MEASUREMENT_REPORT;
+               pReport->Length = 0;
+               pReport->Token  = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token;
+               pReport->Mode   = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode;
+               pReport->Type   = MSRN_TYPE_BEACON_REQ;
+               Length          = sizeof(MEASUREMENT_REPORT_ELEMENT);
+               pDest          += sizeof(MEASUREMENT_REPORT_ELEMENT);
+
+               // 3. Start the beacon report format
+               pBeaconReport = (PBEACON_REPORT) pDest;
+               pDest        += sizeof(BEACON_REPORT);
+               Length       += sizeof(BEACON_REPORT);
+
+               // 4. Copy Channel number
+               pBeaconReport->Channel        = pBss->Channel;
+               pBeaconReport->Spare          = 0;
+               pBeaconReport->Duration       = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration;
+               pBeaconReport->PhyType        = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS);
+               pBeaconReport->RxPower        = pBss->Rssi - pAd->BbpRssiToDbmDelta;
+               pBeaconReport->BeaconInterval = pBss->BeaconPeriod;
+               pBeaconReport->CapabilityInfo = pBss->CapabilityInfo;
+               COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid);
+               NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4);
+               NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8);
+
+               // 5. Create SSID
+               *pDest++ = 0x00;
+               *pDest++ = pBss->SsidLen;
+               NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen);
+               pDest  += pBss->SsidLen;
+               Length += (2 + pBss->SsidLen);
+
+               // 6. Create SupportRates
+               *pDest++ = 0x01;
+               *pDest++ = pBss->SupRateLen;
+               NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen);
+               pDest  += pBss->SupRateLen;
+               Length += (2 + pBss->SupRateLen);
+
+               // 7. DS Parameter
+               *pDest++ = 0x03;
+               *pDest++ = 1;
+               *pDest++ = pBss->Channel;
+               Length  += 3;
+
+               // 8. IBSS parameter if presents
+               if (pBss->BssType == BSS_ADHOC)
+               {
+                       *pDest++ = 0x06;
+                       *pDest++ = 2;
+                       *(PUSHORT) pDest = pBss->AtimWin;
+                       pDest   += 2;
+                       Length  += 4;
+               }
+
+               // 9. Update length field, not include EID and length
+               pReport->Length = Length - 4;
+
+               // 10. Update total frame size
+               pAd->StaCfg.FrameReportLen += Length;
+       }
+}