linux/drivers/staging/rt2860/sta/aironet.c
<<
>>
Prefs
   1/*
   2 *************************************************************************
   3 * Ralink Tech Inc.
   4 * 5F., No.36, Taiyuan St., Jhubei City,
   5 * Hsinchu County 302,
   6 * Taiwan, R.O.C.
   7 *
   8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
   9 *
  10 * This program is free software; you can redistribute it and/or modify  *
  11 * it under the terms of the GNU General Public License as published by  *
  12 * the Free Software Foundation; either version 2 of the License, or     *
  13 * (at your option) any later version.                                   *
  14 *                                                                       *
  15 * This program is distributed in the hope that it will be useful,       *
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
  18 * GNU General Public License for more details.                          *
  19 *                                                                       *
  20 * You should have received a copy of the GNU General Public License     *
  21 * along with this program; if not, write to the                         *
  22 * Free Software Foundation, Inc.,                                       *
  23 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  24 *                                                                       *
  25 *************************************************************************
  26
  27        Module Name:
  28        aironet.c
  29
  30        Abstract:
  31
  32        Revision History:
  33        Who                     When                    What
  34        --------        ----------              ----------------------------------------------
  35        Paul Lin        04-06-15                Initial
  36*/
  37#include "../rt_config.h"
  38
  39/*
  40        ==========================================================================
  41        Description:
  42                association     state machine init,     including state transition and timer init
  43        Parameters:
  44                S -     pointer to the association state machine
  45        ==========================================================================
  46 */
  47VOID    AironetStateMachineInit(
  48        IN      PRTMP_ADAPTER           pAd,
  49        IN      STATE_MACHINE           *S,
  50        OUT     STATE_MACHINE_FUNC      Trans[])
  51{
  52        StateMachineInit(S,     Trans, MAX_AIRONET_STATE, MAX_AIRONET_MSG, (STATE_MACHINE_FUNC)Drop, AIRONET_IDLE, AIRONET_MACHINE_BASE);
  53        StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_MSG, (STATE_MACHINE_FUNC)AironetMsgAction);
  54        StateMachineSetAction(S, AIRONET_IDLE, MT2_AIRONET_SCAN_REQ, (STATE_MACHINE_FUNC)AironetRequestAction);
  55        StateMachineSetAction(S, AIRONET_SCANNING, MT2_AIRONET_SCAN_DONE, (STATE_MACHINE_FUNC)AironetReportAction);
  56}
  57
  58/*
  59        ==========================================================================
  60        Description:
  61                This is state machine function.
  62                When receiving EAPOL packets which is  for 802.1x key management.
  63                Use     both in WPA, and WPAPSK case.
  64                In this function, further dispatch to different functions according     to the received packet.  3 categories are :
  65                  1.  normal 4-way pairwisekey and 2-way groupkey handshake
  66                  2.  MIC error (Countermeasures attack)  report packet from STA.
  67                  3.  Request for pairwise/group key update     from STA
  68        Return:
  69        ==========================================================================
  70*/
  71VOID    AironetMsgAction(
  72        IN      PRTMP_ADAPTER   pAd,
  73        IN      MLME_QUEUE_ELEM *Elem)
  74{
  75        USHORT                                                  Length;
  76        UCHAR                                                   Index, i;
  77        PUCHAR                                                  pData;
  78        PAIRONET_RM_REQUEST_FRAME               pRMReq;
  79        PRM_REQUEST_ACTION                              pReqElem;
  80
  81        DBGPRINT(RT_DEBUG_TRACE, ("-----> AironetMsgAction\n"));
  82
  83        // 0. Get Aironet IAPP header first
  84        pRMReq = (PAIRONET_RM_REQUEST_FRAME) &Elem->Msg[LENGTH_802_11];
  85        pData  = (PUCHAR) &Elem->Msg[LENGTH_802_11];
  86
  87        // 1. Change endian format form network to little endian
  88        Length = be2cpu16(pRMReq->IAPP.Length);
  89
  90        // 2.0 Sanity check, this should only happen when CCX 2.0 support is enabled
  91        if (pAd->StaCfg.CCXEnable != TRUE)
  92                return;
  93
  94        // 2.1 Radio measurement must be on
  95        if (pAd->StaCfg.CCXControl.field.RMEnable != 1)
  96                return;
  97
  98        // 2.2. Debug print all bit information
  99        DBGPRINT(RT_DEBUG_TRACE, ("IAPP ID & Length %d\n", Length));
 100        DBGPRINT(RT_DEBUG_TRACE, ("IAPP Type %x\n", pRMReq->IAPP.Type));
 101        DBGPRINT(RT_DEBUG_TRACE, ("IAPP SubType %x\n", pRMReq->IAPP.SubType));
 102        DBGPRINT(RT_DEBUG_TRACE, ("IAPP Dialog Token %x\n", pRMReq->IAPP.Token));
 103        DBGPRINT(RT_DEBUG_TRACE, ("IAPP Activation Delay %x\n", pRMReq->Delay));
 104        DBGPRINT(RT_DEBUG_TRACE, ("IAPP Measurement Offset %x\n", pRMReq->Offset));
 105
 106        // 3. Check IAPP frame type, it must be 0x32 for Cisco Aironet extension
 107        if (pRMReq->IAPP.Type != AIRONET_IAPP_TYPE)
 108        {
 109                DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP type for Cisco Aironet extension\n"));
 110                return;
 111        }
 112
 113        // 4. Check IAPP frame subtype, it must be 0x01 for Cisco Aironet extension request.
 114        //    Since we are acting as client only, we will disregards reply subtype.
 115        if (pRMReq->IAPP.SubType != AIRONET_IAPP_SUBTYPE_REQUEST)
 116        {
 117                DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP subtype for Cisco Aironet extension\n"));
 118                return;
 119        }
 120
 121        // 5. Verify Destination MAC and Source MAC, both should be all zeros.
 122        if (! MAC_ADDR_EQUAL(pRMReq->IAPP.DA, ZERO_MAC_ADDR))
 123        {
 124                DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP DA for Cisco Aironet extension, it's not Zero\n"));
 125                return;
 126        }
 127
 128        if (! MAC_ADDR_EQUAL(pRMReq->IAPP.SA, ZERO_MAC_ADDR))
 129        {
 130                DBGPRINT(RT_DEBUG_ERROR, ("Wrong IAPP SA for Cisco Aironet extension, it's not Zero\n"));
 131                return;
 132        }
 133
 134        // 6. Reinit all report related fields
 135        NdisZeroMemory(pAd->StaCfg.FrameReportBuf, 2048);
 136        NdisZeroMemory(pAd->StaCfg.BssReportOffset, sizeof(USHORT) * MAX_LEN_OF_BSS_TABLE);
 137        NdisZeroMemory(pAd->StaCfg.MeasurementRequest, sizeof(RM_REQUEST_ACTION) * 4);
 138
 139        // 7. Point to the start of first element report element
 140        pAd->StaCfg.FrameReportLen   = LENGTH_802_11 + sizeof(AIRONET_IAPP_HEADER);
 141        DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen));
 142        pAd->StaCfg.LastBssIndex     = 0xff;
 143        pAd->StaCfg.RMReqCnt         = 0;
 144        pAd->StaCfg.ParallelReq      = FALSE;
 145        pAd->StaCfg.ParallelDuration = 0;
 146        pAd->StaCfg.ParallelChannel  = 0;
 147        pAd->StaCfg.IAPPToken        = pRMReq->IAPP.Token;
 148        pAd->StaCfg.CurrentRMReqIdx  = 0;
 149        pAd->StaCfg.CLBusyBytes      = 0;
 150        // Reset the statistics
 151        for (i = 0; i < 8; i++)
 152                pAd->StaCfg.RPIDensity[i] = 0;
 153
 154        Index = 0;
 155
 156        // 8. Save dialog token for report
 157        pAd->StaCfg.IAPPToken = pRMReq->IAPP.Token;
 158
 159        // Save Activation delay & measurement offset, Not really needed
 160
 161        // 9. Point to the first request element
 162        pData += sizeof(AIRONET_RM_REQUEST_FRAME);
 163        //    Length should exclude the CISCO Aironet SNAP header
 164        Length -= (sizeof(AIRONET_RM_REQUEST_FRAME) - LENGTH_802_1_H);
 165
 166        // 10. Start Parsing the Measurement elements.
 167        //    Be careful about multiple MR elements within one frames.
 168        while (Length > 0)
 169        {
 170                pReqElem = (PRM_REQUEST_ACTION) pData;
 171                switch (pReqElem->ReqElem.Eid)
 172                {
 173                        case IE_MEASUREMENT_REQUEST:
 174                                // From the example, it seems we only need to support one request in one frame
 175                                // There is no multiple request in one frame.
 176                                // Besides, looks like we need to take care the measurement request only.
 177                                // The measurement request is always 4 bytes.
 178
 179                                // Start parsing this type of request.
 180                                // 0. Eid is IE_MEASUREMENT_REQUEST
 181                                // 1. Length didn't include Eid and Length field, it always be 8.
 182                                // 2. Measurement Token, we nned to save it for the corresponding report.
 183                                // 3. Measurement Mode, Although there are definitions, but we din't see value other than
 184                                //    0 from test specs examples.
 185                                // 4. Measurement Type, this is what we need to do.
 186                                switch (pReqElem->ReqElem.Type)
 187                                {
 188                                        case MSRN_TYPE_CHANNEL_LOAD_REQ:
 189                                        case MSRN_TYPE_NOISE_HIST_REQ:
 190                                        case MSRN_TYPE_BEACON_REQ:
 191                                                // Check the Enable non-serving channel measurement control
 192                                                if (pAd->StaCfg.CCXControl.field.DCRMEnable == 0)
 193                                                {
 194                                                        // Check channel before enqueue the action
 195                                                        if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel)
 196                                                                break;
 197                                                }
 198                                                else
 199                                                {
 200                                                        // If off channel measurement, check the TU duration limit
 201                                                        if (pReqElem->Measurement.Channel != pAd->CommonCfg.Channel)
 202                                                                if (pReqElem->Measurement.Duration > pAd->StaCfg.CCXControl.field.TuLimit)
 203                                                                        break;
 204                                                }
 205
 206                                                // Save requests and execute actions later
 207                                                NdisMoveMemory(&pAd->StaCfg.MeasurementRequest[Index], pReqElem, sizeof(RM_REQUEST_ACTION));
 208                                                Index += 1;
 209                                                break;
 210
 211                                        case MSRN_TYPE_FRAME_REQ:
 212                                                // Since it's option, we will support later
 213                                                // FrameRequestAction(pAd, pData);
 214                                                break;
 215
 216                                        default:
 217                                                break;
 218                                }
 219
 220                                // Point to next Measurement request
 221                                pData  += sizeof(RM_REQUEST_ACTION);
 222                                Length -= sizeof(RM_REQUEST_ACTION);
 223                                break;
 224
 225                        // We accept request only, all others are dropped
 226                        case IE_MEASUREMENT_REPORT:
 227                        case IE_AP_TX_POWER:
 228                        case IE_MEASUREMENT_CAPABILITY:
 229                        default:
 230                                return;
 231                }
 232        }
 233
 234        // 11. Update some flags and index
 235        pAd->StaCfg.RMReqCnt = Index;
 236
 237        if (Index)
 238        {
 239                MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL);
 240                RT28XX_MLME_HANDLER(pAd);
 241        }
 242
 243        DBGPRINT(RT_DEBUG_TRACE, ("<----- AironetMsgAction\n"));
 244}
 245
 246/*
 247        ========================================================================
 248
 249        Routine Description:
 250
 251        Arguments:
 252
 253        Return Value:
 254                None
 255
 256        Note:
 257
 258        ========================================================================
 259*/
 260VOID    AironetRequestAction(
 261        IN      PRTMP_ADAPTER   pAd,
 262        IN      MLME_QUEUE_ELEM *Elem)
 263{
 264        PRM_REQUEST_ACTION      pReq;
 265
 266        // 1. Point to next request element
 267        pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
 268
 269        // 2. Parse measurement type and call appropriate functions
 270        if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
 271                // Channel Load measurement request
 272                ChannelLoadRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 273        else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
 274                // Noise Histogram measurement request
 275                NoiseHistRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 276        else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ)
 277                // Beacon measurement request
 278                BeaconRequestAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 279        else
 280                // Unknown. Do nothing and return, this should never happen
 281                return;
 282
 283        // 3. Peek into the next request, if it's parallel, we will update the scan time to the largest one
 284        if ((pAd->StaCfg.CurrentRMReqIdx + 1) < pAd->StaCfg.RMReqCnt)
 285        {
 286                pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx + 1];
 287                // Check for parallel bit
 288                if ((pReq->ReqElem.Mode & 0x01) && (pReq->Measurement.Channel == pAd->StaCfg.CCXScanChannel))
 289                {
 290                        // Update parallel mode request information
 291                        pAd->StaCfg.ParallelReq = TRUE;
 292                        pAd->StaCfg.CCXScanTime = ((pReq->Measurement.Duration > pAd->StaCfg.CCXScanTime) ?
 293                        (pReq->Measurement.Duration) : (pAd->StaCfg.CCXScanTime));
 294                }
 295        }
 296
 297        // 4. Call RT28XX_MLME_HANDLER to execute the request mlme commands, Scan request is the only one used
 298        RT28XX_MLME_HANDLER(pAd);
 299
 300}
 301
 302
 303/*
 304        ========================================================================
 305
 306        Routine Description:
 307                Prepare channel load report action, special scan operation added
 308                to support
 309
 310        Arguments:
 311                pAd     Pointer to our adapter
 312                pData           Start from element ID
 313
 314        Return Value:
 315                None
 316
 317        Note:
 318
 319        ========================================================================
 320*/
 321VOID    ChannelLoadRequestAction(
 322        IN      PRTMP_ADAPTER   pAd,
 323        IN      UCHAR                   Index)
 324{
 325        PRM_REQUEST_ACTION                              pReq;
 326        MLME_SCAN_REQ_STRUCT                    ScanReq;
 327        UCHAR                                                   ZeroSsid[32];
 328        NDIS_STATUS                                             NStatus;
 329        PUCHAR                                                  pOutBuffer = NULL;
 330        PHEADER_802_11                                  pNullFrame;
 331
 332        DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction ----->\n"));
 333
 334        pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
 335        NdisZeroMemory(ZeroSsid, 32);
 336
 337        // Prepare for special scan request
 338        // The scan definition is different with our Active, Passive scan definition.
 339        // For CCX2, Active means send out probe request with broadcast BSSID.
 340        // Passive means no probe request sent, only listen to the beacons.
 341        // The channel scanned is fixed as specified, no need to scan all channels.
 342        // The scan wait time is specified in the request too.
 343        // Passive scan Mode
 344
 345        // Control state machine is not idle, reject the request
 346        if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
 347                return;
 348
 349        // Fill out stuff for scan request
 350        ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_CHANNEL_LOAD);
 351        MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
 352        pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
 353
 354        // Reset some internal control flags to make sure this scan works.
 355        BssTableInit(&pAd->StaCfg.CCXBssTab);
 356        pAd->StaCfg.ScanCnt        = 0;
 357        pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
 358        pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
 359
 360        DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel));
 361
 362        // If it's non serving channel scan, send out a null frame with PSM bit on.
 363        if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
 364        {
 365                // Use MLME enqueue method
 366                NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
 367                if (NStatus     != NDIS_STATUS_SUCCESS)
 368                        return;
 369
 370                pNullFrame = (PHEADER_802_11) pOutBuffer;;
 371                // Make the power save Null frame with PSM bit on
 372                MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
 373                pNullFrame->Duration    = 0;
 374                pNullFrame->FC.Type     = BTYPE_DATA;
 375                pNullFrame->FC.PwrMgmt  = PWR_SAVE;
 376
 377                // Send using priority queue
 378                MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
 379                MlmeFreeMemory(pAd, pOutBuffer);
 380                DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
 381                RTMPusecDelay(5000);
 382        }
 383
 384        pAd->StaCfg.CCXReqType     = MSRN_TYPE_CHANNEL_LOAD_REQ;
 385        pAd->StaCfg.CLBusyBytes    = 0;
 386        // Enable Rx with promiscuous reception
 387        RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010);
 388
 389        // Set channel load measurement flag
 390        RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
 391
 392        pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
 393
 394        DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadRequestAction <-----\n"));
 395}
 396
 397/*
 398        ========================================================================
 399
 400        Routine Description:
 401                Prepare noise histogram report action, special scan operation added
 402                to support
 403
 404        Arguments:
 405                pAd     Pointer to our adapter
 406                pData           Start from element ID
 407
 408        Return Value:
 409                None
 410
 411        Note:
 412
 413        ========================================================================
 414*/
 415VOID    NoiseHistRequestAction(
 416        IN      PRTMP_ADAPTER   pAd,
 417        IN      UCHAR                   Index)
 418{
 419        PRM_REQUEST_ACTION                              pReq;
 420        MLME_SCAN_REQ_STRUCT                    ScanReq;
 421        UCHAR                                                   ZeroSsid[32], i;
 422        NDIS_STATUS                                             NStatus;
 423        PUCHAR                                                  pOutBuffer = NULL;
 424        PHEADER_802_11                                  pNullFrame;
 425
 426        DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction ----->\n"));
 427
 428        pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
 429        NdisZeroMemory(ZeroSsid, 32);
 430
 431        // Prepare for special scan request
 432        // The scan definition is different with our Active, Passive scan definition.
 433        // For CCX2, Active means send out probe request with broadcast BSSID.
 434        // Passive means no probe request sent, only listen to the beacons.
 435        // The channel scanned is fixed as specified, no need to scan all channels.
 436        // The scan wait time is specified in the request too.
 437        // Passive scan Mode
 438
 439        // Control state machine is not idle, reject the request
 440        if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
 441                return;
 442
 443        // Fill out stuff for scan request
 444        ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_NOISE);
 445        MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
 446        pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
 447
 448        // Reset some internal control flags to make sure this scan works.
 449        BssTableInit(&pAd->StaCfg.CCXBssTab);
 450        pAd->StaCfg.ScanCnt        = 0;
 451        pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
 452        pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
 453        pAd->StaCfg.CCXReqType     = MSRN_TYPE_NOISE_HIST_REQ;
 454
 455        DBGPRINT(RT_DEBUG_TRACE, ("Duration %d, Channel %d!\n", pReq->Measurement.Duration, pReq->Measurement.Channel));
 456
 457        // If it's non serving channel scan, send out a null frame with PSM bit on.
 458        if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
 459        {
 460                // Use MLME enqueue method
 461                NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
 462                if (NStatus     != NDIS_STATUS_SUCCESS)
 463                        return;
 464
 465                pNullFrame = (PHEADER_802_11) pOutBuffer;
 466                // Make the power save Null frame with PSM bit on
 467                MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
 468                pNullFrame->Duration    = 0;
 469                pNullFrame->FC.Type     = BTYPE_DATA;
 470                pNullFrame->FC.PwrMgmt  = PWR_SAVE;
 471
 472                // Send using priority queue
 473                MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
 474                MlmeFreeMemory(pAd, pOutBuffer);
 475                DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
 476                RTMPusecDelay(5000);
 477        }
 478
 479        // Reset the statistics
 480        for (i = 0; i < 8; i++)
 481                pAd->StaCfg.RPIDensity[i] = 0;
 482
 483        // Enable Rx with promiscuous reception
 484        RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, 0x1010);
 485
 486        // Set channel load measurement flag
 487        RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
 488
 489        pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
 490
 491        DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistRequestAction <-----\n"));
 492}
 493
 494/*
 495        ========================================================================
 496
 497        Routine Description:
 498                Prepare Beacon report action, special scan operation added
 499                to support
 500
 501        Arguments:
 502                pAd     Pointer to our adapter
 503                pData           Start from element ID
 504
 505        Return Value:
 506                None
 507
 508        Note:
 509
 510        ========================================================================
 511*/
 512VOID    BeaconRequestAction(
 513        IN      PRTMP_ADAPTER   pAd,
 514        IN      UCHAR                   Index)
 515{
 516        PRM_REQUEST_ACTION                              pReq;
 517        NDIS_STATUS                                             NStatus;
 518        PUCHAR                                                  pOutBuffer = NULL;
 519        PHEADER_802_11                                  pNullFrame;
 520        MLME_SCAN_REQ_STRUCT                    ScanReq;
 521        UCHAR                                                   ZeroSsid[32];
 522
 523        DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction ----->\n"));
 524
 525        pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[Index];
 526        NdisZeroMemory(ZeroSsid, 32);
 527
 528        // Prepare for special scan request
 529        // The scan definition is different with our Active, Passive scan definition.
 530        // For CCX2, Active means send out probe request with broadcast BSSID.
 531        // Passive means no probe request sent, only listen to the beacons.
 532        // The channel scanned is fixed as specified, no need to scan all channels.
 533        // The scan wait time is specified in the request too.
 534        if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_PASSIVE)
 535        {
 536                // Passive scan Mode
 537                DBGPRINT(RT_DEBUG_TRACE, ("Passive Scan Mode!\n"));
 538
 539                // Control state machine is not idle, reject the request
 540                if ((pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) && (Index == 0))
 541                        return;
 542
 543                // Fill out stuff for scan request
 544                ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_PASSIVE);
 545                MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
 546                pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
 547
 548                // Reset some internal control flags to make sure this scan works.
 549                BssTableInit(&pAd->StaCfg.CCXBssTab);
 550                pAd->StaCfg.ScanCnt        = 0;
 551                pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
 552                pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
 553                pAd->StaCfg.CCXReqType     = MSRN_TYPE_BEACON_REQ;
 554                DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration));
 555
 556                // If it's non serving channel scan, send out a null frame with PSM bit on.
 557                if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
 558                {
 559                        // Use MLME enqueue method
 560                        NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
 561                        if (NStatus     != NDIS_STATUS_SUCCESS)
 562                                return;
 563
 564                        pNullFrame = (PHEADER_802_11) pOutBuffer;
 565                        // Make the power save Null frame with PSM bit on
 566                        MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
 567                        pNullFrame->Duration    = 0;
 568                        pNullFrame->FC.Type     = BTYPE_DATA;
 569                        pNullFrame->FC.PwrMgmt  = PWR_SAVE;
 570
 571                        // Send using priority queue
 572                        MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
 573                        MlmeFreeMemory(pAd, pOutBuffer);
 574                        DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
 575                        RTMPusecDelay(5000);
 576                }
 577
 578                pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
 579        }
 580        else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_ACTIVE)
 581        {
 582                // Active scan Mode
 583                DBGPRINT(RT_DEBUG_TRACE, ("Active Scan Mode!\n"));
 584
 585                // Control state machine is not idle, reject the request
 586                if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE)
 587                        return;
 588
 589                // Fill out stuff for scan request
 590                ScanParmFill(pAd, &ScanReq, ZeroSsid, 0, BSS_ANY, SCAN_CISCO_ACTIVE);
 591                MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq);
 592                pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN;
 593
 594                // Reset some internal control flags to make sure this scan works.
 595                BssTableInit(&pAd->StaCfg.CCXBssTab);
 596                pAd->StaCfg.ScanCnt        = 0;
 597                pAd->StaCfg.CCXScanChannel = pReq->Measurement.Channel;
 598                pAd->StaCfg.CCXScanTime    = pReq->Measurement.Duration;
 599                pAd->StaCfg.CCXReqType     = MSRN_TYPE_BEACON_REQ;
 600                DBGPRINT(RT_DEBUG_TRACE, ("Duration %d!\n", pReq->Measurement.Duration));
 601
 602                // If it's non serving channel scan, send out a null frame with PSM bit on.
 603                if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
 604                {
 605                        // Use MLME enqueue method
 606                        NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);  //Get an unused nonpaged memory
 607                        if (NStatus     != NDIS_STATUS_SUCCESS)
 608                                return;
 609
 610                        pNullFrame = (PHEADER_802_11) pOutBuffer;
 611                        // Make the power save Null frame with PSM bit on
 612                        MgtMacHeaderInit(pAd, pNullFrame, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
 613                        pNullFrame->Duration    = 0;
 614                        pNullFrame->FC.Type     = BTYPE_DATA;
 615                        pNullFrame->FC.PwrMgmt  = PWR_SAVE;
 616
 617                        // Send using priority queue
 618                        MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
 619                        MlmeFreeMemory(pAd, pOutBuffer);
 620                        DBGPRINT(RT_DEBUG_TRACE, ("Send PSM Data frame for off channel RM\n"));
 621                        RTMPusecDelay(5000);
 622                }
 623
 624                pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
 625        }
 626        else if (pReq->Measurement.ScanMode == MSRN_SCAN_MODE_BEACON_TABLE)
 627        {
 628                // Beacon report Mode, report all the APS in current bss table
 629                DBGPRINT(RT_DEBUG_TRACE, ("Beacon Report Mode!\n"));
 630
 631                // Copy current BSS table to CCX table, we can omit this step later on.
 632                NdisMoveMemory(&pAd->StaCfg.CCXBssTab, &pAd->ScanTab, sizeof(BSS_TABLE));
 633
 634                // Create beacon report from Bss table
 635                AironetCreateBeaconReportFromBssTable(pAd);
 636
 637                // Set state to scanning
 638                pAd->Mlme.AironetMachine.CurrState = AIRONET_SCANNING;
 639
 640                // Enqueue report request
 641                // Cisco scan request is finished, prepare beacon report
 642                MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL);
 643        }
 644        else
 645        {
 646                // Wrong scan Mode
 647                DBGPRINT(RT_DEBUG_TRACE, ("Wrong Scan Mode!\n"));
 648        }
 649
 650        DBGPRINT(RT_DEBUG_TRACE, ("BeaconRequestAction <-----\n"));
 651}
 652
 653/*
 654        ========================================================================
 655
 656        Routine Description:
 657
 658        Arguments:
 659
 660        Return Value:
 661                None
 662
 663        Note:
 664
 665        ========================================================================
 666*/
 667VOID    AironetReportAction(
 668        IN      PRTMP_ADAPTER   pAd,
 669        IN      MLME_QUEUE_ELEM *Elem)
 670{
 671        PRM_REQUEST_ACTION      pReq;
 672        ULONG                           Now32;
 673
 674    NdisGetSystemUpTime(&Now32);
 675        pAd->StaCfg.LastBeaconRxTime = Now32;
 676
 677        pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
 678
 679        DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction ----->\n"));
 680
 681        // 1. Parse measurement type and call appropriate functions
 682        if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
 683                // Channel Load measurement request
 684                ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 685        else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
 686                // Noise Histogram measurement request
 687                NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 688        else if (pReq->ReqElem.Type == MSRN_TYPE_BEACON_REQ)
 689                // Beacon measurement request
 690                BeaconReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 691        else
 692                // Unknown. Do nothing and return
 693                ;
 694
 695        // 2. Point to the correct index of action element, start from 0
 696        pAd->StaCfg.CurrentRMReqIdx++;
 697
 698        // 3. Check for parallel actions
 699        if (pAd->StaCfg.ParallelReq == TRUE)
 700        {
 701                pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
 702
 703                // Process next action right away
 704                if (pReq->ReqElem.Type == MSRN_TYPE_CHANNEL_LOAD_REQ)
 705                        // Channel Load measurement request
 706                        ChannelLoadReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 707                else if (pReq->ReqElem.Type == MSRN_TYPE_NOISE_HIST_REQ)
 708                        // Noise Histogram measurement request
 709                        NoiseHistReportAction(pAd, pAd->StaCfg.CurrentRMReqIdx);
 710
 711                pAd->StaCfg.ParallelReq = FALSE;
 712                pAd->StaCfg.CurrentRMReqIdx++;
 713        }
 714
 715        if (pAd->StaCfg.CurrentRMReqIdx >= pAd->StaCfg.RMReqCnt)
 716        {
 717                // 4. There is no more unprocessed measurement request, go for transmit this report
 718                AironetFinalReportAction(pAd);
 719                pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
 720        }
 721        else
 722        {
 723                pReq = (PRM_REQUEST_ACTION) &pAd->StaCfg.MeasurementRequest[pAd->StaCfg.CurrentRMReqIdx];
 724
 725                if (pReq->Measurement.Channel != pAd->CommonCfg.Channel)
 726                {
 727                        RTMPusecDelay(100000);
 728                }
 729
 730                // 5. There are more requests to be measure
 731                MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_REQ, 0, NULL);
 732                RT28XX_MLME_HANDLER(pAd);
 733        }
 734
 735        DBGPRINT(RT_DEBUG_TRACE, ("AironetReportAction <-----\n"));
 736}
 737
 738/*
 739        ========================================================================
 740
 741        Routine Description:
 742
 743        Arguments:
 744
 745        Return Value:
 746                None
 747
 748        Note:
 749
 750        ========================================================================
 751*/
 752VOID    AironetFinalReportAction(
 753        IN      PRTMP_ADAPTER   pAd)
 754{
 755        PUCHAR                                  pDest;
 756        PAIRONET_IAPP_HEADER    pIAPP;
 757        PHEADER_802_11                  pHeader;
 758        UCHAR                                   AckRate = RATE_2;
 759        USHORT                                  AckDuration = 0;
 760        NDIS_STATUS                             NStatus;
 761        PUCHAR                                  pOutBuffer = NULL;
 762        ULONG                                   FrameLen = 0;
 763
 764        DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction ----->\n"));
 765
 766        // 0. Set up the frame pointer, Frame was inited at the end of message action
 767        pDest = &pAd->StaCfg.FrameReportBuf[LENGTH_802_11];
 768
 769        // 1. Update report IAPP fields
 770        pIAPP = (PAIRONET_IAPP_HEADER) pDest;
 771
 772        // 2. Copy Cisco SNAP header
 773        NdisMoveMemory(pIAPP->CiscoSnapHeader, SNAP_AIRONET, LENGTH_802_1_H);
 774
 775        // 3. network order for this 16bit length
 776        pIAPP->Length  = cpu2be16(pAd->StaCfg.FrameReportLen - LENGTH_802_11 - LENGTH_802_1_H);
 777
 778        // 3.1 sanity check the report length, ignore it if there is nothing to report
 779        if (be2cpu16(pIAPP->Length) <= 18)
 780                return;
 781
 782        // 4. Type must be 0x32
 783        pIAPP->Type    = AIRONET_IAPP_TYPE;
 784
 785        // 5. SubType for report must be 0x81
 786        pIAPP->SubType = AIRONET_IAPP_SUBTYPE_REPORT;
 787
 788        // 6. DA is not used and must be zero, although the whole frame was cleared at the start of function
 789        //    We will do it again here. We can use BSSID instead
 790        COPY_MAC_ADDR(pIAPP->DA, pAd->CommonCfg.Bssid);
 791
 792        // 7. SA is the client reporting which must be our MAC
 793        COPY_MAC_ADDR(pIAPP->SA, pAd->CurrentAddress);
 794
 795        // 8. Copy the saved dialog token
 796        pIAPP->Token = pAd->StaCfg.IAPPToken;
 797
 798        // 9. Make the Report frame 802.11 header
 799        //    Reuse function in wpa.c
 800        pHeader = (PHEADER_802_11) pAd->StaCfg.FrameReportBuf;
 801        pAd->Sequence ++;
 802        WpaMacHeaderInit(pAd, pHeader, 0, pAd->CommonCfg.Bssid);
 803
 804        // ACK size     is 14 include CRC, and its rate is based on real time information
 805        AckRate     = pAd->CommonCfg.ExpectedACKRate[pAd->CommonCfg.MlmeRate];
 806        AckDuration = RTMPCalcDuration(pAd, AckRate, 14);
 807        pHeader->Duration = pAd->CommonCfg.Dsifs + AckDuration;
 808
 809        // Use MLME enqueue method
 810        NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);  //Get an unused nonpaged memory
 811        if (NStatus     != NDIS_STATUS_SUCCESS)
 812                return;
 813
 814        // 10. Prepare report frame with dynamic outbuffer. Just simply copy everything.
 815        MakeOutgoingFrame(pOutBuffer,                       &FrameLen,
 816                          pAd->StaCfg.FrameReportLen, pAd->StaCfg.FrameReportBuf,
 817                              END_OF_ARGS);
 818
 819        // 11. Send using priority queue
 820        MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
 821        MlmeFreeMemory(pAd, pOutBuffer);
 822
 823        pAd->StaCfg.CCXReqType = MSRN_TYPE_UNUSED;
 824
 825        DBGPRINT(RT_DEBUG_TRACE, ("AironetFinalReportAction <-----\n"));
 826}
 827
 828/*
 829        ========================================================================
 830
 831        Routine Description:
 832
 833        Arguments:
 834
 835        Return Value:
 836                None
 837
 838        Note:
 839
 840        ========================================================================
 841*/
 842VOID    ChannelLoadReportAction(
 843        IN      PRTMP_ADAPTER   pAd,
 844        IN      UCHAR                   Index)
 845{
 846        PMEASUREMENT_REPORT_ELEMENT     pReport;
 847        PCHANNEL_LOAD_REPORT            pLoad;
 848        PUCHAR                                          pDest;
 849        UCHAR                                           CCABusyFraction;
 850
 851        DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction ----->\n"));
 852
 853        // Disable Rx with promiscuous reception, make it back to normal
 854        RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification.
 855
 856        // 0. Setup pointer for processing beacon & probe response
 857        pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
 858        pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
 859
 860        // 1. Fill Measurement report element field.
 861        pReport->Eid    = IE_MEASUREMENT_REPORT;
 862        // Fixed Length at 9, not include Eid and length fields
 863        pReport->Length = 9;
 864        pReport->Token  = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token;
 865        pReport->Mode   = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode;
 866        pReport->Type   = MSRN_TYPE_CHANNEL_LOAD_REQ;
 867
 868        // 2. Fill channel report measurement data
 869        pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
 870        pLoad  = (PCHANNEL_LOAD_REPORT) pDest;
 871        pLoad->Channel  = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel;
 872        pLoad->Spare    = 0;
 873        pLoad->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration;
 874
 875        // 3. Calculate the CCA Busy Fraction
 876        //    (Bytes + ACK size) * 8 / Tx speed * 255 / 1000 / measurement duration, use 24 us Tx speed
 877        //     =  (Bytes + ACK) / 12 / duration
 878        //     9 is the good value for pAd->StaCfg.CLFactor
 879        // CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 9 / pLoad->Duration);
 880        CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / pAd->StaCfg.CLFactor / pLoad->Duration);
 881        if (CCABusyFraction < 10)
 882                        CCABusyFraction = (UCHAR) (pAd->StaCfg.CLBusyBytes / 3 / pLoad->Duration) + 1;
 883
 884        pLoad->CCABusy = CCABusyFraction;
 885        DBGPRINT(RT_DEBUG_TRACE, ("CLBusyByte %ld, Duration %d, Result, %d\n", pAd->StaCfg.CLBusyBytes, pLoad->Duration, CCABusyFraction));
 886
 887        DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen));
 888        pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(CHANNEL_LOAD_REPORT));
 889        DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen %d\n", pAd->StaCfg.FrameReportLen));
 890
 891        // 4. Clear channel load measurement flag
 892        RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
 893
 894        // 5. reset to idle state
 895        pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
 896
 897        DBGPRINT(RT_DEBUG_TRACE, ("ChannelLoadReportAction <-----\n"));
 898}
 899
 900/*
 901        ========================================================================
 902
 903        Routine Description:
 904
 905        Arguments:
 906
 907        Return Value:
 908                None
 909
 910        Note:
 911
 912        ========================================================================
 913*/
 914VOID    NoiseHistReportAction(
 915        IN      PRTMP_ADAPTER   pAd,
 916        IN      UCHAR                   Index)
 917{
 918        PMEASUREMENT_REPORT_ELEMENT     pReport;
 919        PNOISE_HIST_REPORT                      pNoise;
 920        PUCHAR                                          pDest;
 921        UCHAR                                           i,NoiseCnt;
 922        USHORT                                          TotalRPICnt, TotalRPISum;
 923
 924        DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction ----->\n"));
 925
 926        // 0. Disable Rx with promiscuous reception, make it back to normal
 927        RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, STANORMAL); // Staion not drop control frame will fail WiFi Certification.
 928        // 1. Setup pointer for processing beacon & probe response
 929        pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
 930        pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
 931
 932        // 2. Fill Measurement report element field.
 933        pReport->Eid    = IE_MEASUREMENT_REPORT;
 934        // Fixed Length at 16, not include Eid and length fields
 935        pReport->Length = 16;
 936        pReport->Token  = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Token;
 937        pReport->Mode   = pAd->StaCfg.MeasurementRequest[Index].ReqElem.Mode;
 938        pReport->Type   = MSRN_TYPE_NOISE_HIST_REQ;
 939
 940        // 3. Fill noise histogram report measurement data
 941        pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
 942        pNoise  = (PNOISE_HIST_REPORT) pDest;
 943        pNoise->Channel  = pAd->StaCfg.MeasurementRequest[Index].Measurement.Channel;
 944        pNoise->Spare    = 0;
 945        pNoise->Duration = pAd->StaCfg.MeasurementRequest[Index].Measurement.Duration;
 946        // 4. Fill Noise histogram, the total RPI counts should be 0.4 * TU
 947        //    We estimate 4000 normal packets received durning 10 seconds test.
 948        //    Adjust it if required.
 949        // 3 is a good value for pAd->StaCfg.NHFactor
 950        // TotalRPICnt = pNoise->Duration * 3 / 10;
 951        TotalRPICnt = pNoise->Duration * pAd->StaCfg.NHFactor / 10;
 952        TotalRPISum = 0;
 953
 954        for (i = 0; i < 8; i++)
 955        {
 956                TotalRPISum += pAd->StaCfg.RPIDensity[i];
 957                DBGPRINT(RT_DEBUG_TRACE, ("RPI %d Conuts %d\n", i, pAd->StaCfg.RPIDensity[i]));
 958        }
 959
 960        // Double check if the counter is larger than our expectation.
 961        // We will replace it with the total number plus a fraction.
 962        if (TotalRPISum > TotalRPICnt)
 963                TotalRPICnt = TotalRPISum + pNoise->Duration / 20;
 964
 965        DBGPRINT(RT_DEBUG_TRACE, ("Total RPI Conuts %d\n", TotalRPICnt));
 966
 967        // 5. Initialize noise count for the total summation of 0xff
 968        NoiseCnt = 0;
 969        for (i = 1; i < 8; i++)
 970        {
 971                pNoise->Density[i] = (UCHAR) (pAd->StaCfg.RPIDensity[i] * 255 / TotalRPICnt);
 972                if ((pNoise->Density[i] == 0) && (pAd->StaCfg.RPIDensity[i] != 0))
 973                        pNoise->Density[i]++;
 974                NoiseCnt += pNoise->Density[i];
 975                DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[%d]  = 0x%02x\n", i, pNoise->Density[i]));
 976        }
 977
 978        // 6. RPI[0] represents the rest of counts
 979        pNoise->Density[0] = 0xff - NoiseCnt;
 980        DBGPRINT(RT_DEBUG_TRACE, ("Reported RPI[0]  = 0x%02x\n", pNoise->Density[0]));
 981
 982        pAd->StaCfg.FrameReportLen += (sizeof(MEASUREMENT_REPORT_ELEMENT) + sizeof(NOISE_HIST_REPORT));
 983
 984        // 7. Clear channel load measurement flag
 985        RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_MEASUREMENT);
 986
 987        // 8. reset to idle state
 988        pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
 989
 990        DBGPRINT(RT_DEBUG_TRACE, ("NoiseHistReportAction <-----\n"));
 991}
 992
 993/*
 994        ========================================================================
 995
 996        Routine Description:
 997                Prepare Beacon report action,
 998
 999        Arguments:
1000                pAd     Pointer to our adapter
1001
1002        Return Value:
1003                None
1004
1005        Note:
1006
1007        ========================================================================
1008*/
1009VOID    BeaconReportAction(
1010        IN      PRTMP_ADAPTER   pAd,
1011        IN      UCHAR                   Index)
1012{
1013        DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction ----->\n"));
1014
1015        // Looks like we don't have anything thing need to do here.
1016        // All measurement report already finished in AddBeaconReport
1017        // The length is in the FrameReportLen
1018
1019        // reset Beacon index for next beacon request
1020        pAd->StaCfg.LastBssIndex = 0xff;
1021
1022        // reset to idle state
1023        pAd->Mlme.AironetMachine.CurrState = AIRONET_IDLE;
1024
1025        DBGPRINT(RT_DEBUG_TRACE, ("BeaconReportAction <-----\n"));
1026}
1027
1028/*
1029        ========================================================================
1030
1031        Routine Description:
1032
1033        Arguments:
1034                Index           Current BSSID in CCXBsstab entry index
1035
1036        Return Value:
1037
1038        Note:
1039
1040        ========================================================================
1041*/
1042VOID    AironetAddBeaconReport(
1043        IN      PRTMP_ADAPTER           pAd,
1044        IN      ULONG                           Index,
1045        IN      PMLME_QUEUE_ELEM        pElem)
1046{
1047        PVOID                                           pMsg;
1048        PUCHAR                                          pSrc, pDest;
1049        UCHAR                                           ReqIdx;
1050        ULONG                                           MsgLen;
1051        USHORT                                          Length;
1052        PFRAME_802_11                           pFrame;
1053        PMEASUREMENT_REPORT_ELEMENT     pReport;
1054        PEID_STRUCT                             pEid;
1055        PBEACON_REPORT                          pBeaconReport;
1056        PBSS_ENTRY                                      pBss;
1057
1058        // 0. Setup pointer for processing beacon & probe response
1059        pMsg   = pElem->Msg;
1060        MsgLen = pElem->MsgLen;
1061        pFrame = (PFRAME_802_11) pMsg;
1062        pSrc   = pFrame->Octet;                         // Start from AP TSF
1063        pBss   = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index];
1064        ReqIdx = pAd->StaCfg.CurrentRMReqIdx;
1065
1066        // 1 Check the Index, if we already create this entry, only update the average RSSI
1067        if ((Index <= pAd->StaCfg.LastBssIndex) && (pAd->StaCfg.LastBssIndex != 0xff))
1068        {
1069                pDest  = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.BssReportOffset[Index]];
1070                // Point to bss report information
1071                pDest += sizeof(MEASUREMENT_REPORT_ELEMENT);
1072                pBeaconReport = (PBEACON_REPORT) pDest;
1073
1074                // Update Rx power, in dBm
1075                // Get the original RSSI readback from BBP
1076                pBeaconReport->RxPower += pAd->BbpRssiToDbmDelta;
1077                // Average the Rssi reading
1078                pBeaconReport->RxPower  = (pBeaconReport->RxPower + pBss->Rssi) / 2;
1079                // Get to dBm format
1080                pBeaconReport->RxPower -= pAd->BbpRssiToDbmDelta;
1081
1082                DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ",
1083                        pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2],
1084                        pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]));
1085                DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld] Rssi %d, Avg Rssi %d\n", Index, (pBss->Rssi - pAd->BbpRssiToDbmDelta), pBeaconReport->RxPower - 256));
1086                DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.BssReportOffset[Index]));
1087
1088                // Update other information here
1089
1090                // Done
1091                return;
1092        }
1093
1094        // 2. Update reported Index
1095        pAd->StaCfg.LastBssIndex = Index;
1096
1097        // 3. Setup the buffer address for copying this BSSID into reporting frame
1098        //    The offset should start after 802.11 header and report frame header.
1099        pDest = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
1100
1101        // 4. Save the start offset of each Bss in report frame
1102        pAd->StaCfg.BssReportOffset[Index] = pAd->StaCfg.FrameReportLen;
1103
1104        // 5. Fill Measurement report fields
1105        pReport = (PMEASUREMENT_REPORT_ELEMENT) pDest;
1106        pReport->Eid = IE_MEASUREMENT_REPORT;
1107        pReport->Length = 0;
1108        pReport->Token  = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token;
1109        pReport->Mode   = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode;
1110        pReport->Type   = MSRN_TYPE_BEACON_REQ;
1111        Length          = sizeof(MEASUREMENT_REPORT_ELEMENT);
1112        pDest          += sizeof(MEASUREMENT_REPORT_ELEMENT);
1113
1114        // 6. Start thebeacon report format
1115        pBeaconReport = (PBEACON_REPORT) pDest;
1116        pDest        += sizeof(BEACON_REPORT);
1117        Length       += sizeof(BEACON_REPORT);
1118
1119        // 7. Copy Channel number
1120        pBeaconReport->Channel        = pBss->Channel;
1121        pBeaconReport->Spare          = 0;
1122        pBeaconReport->Duration       = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration;
1123        pBeaconReport->PhyType        = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS);
1124        // 8. Rx power, in dBm
1125        pBeaconReport->RxPower        = pBss->Rssi - pAd->BbpRssiToDbmDelta;
1126
1127        DBGPRINT(RT_DEBUG_TRACE, ("Bssid %02x:%02x:%02x:%02x:%02x:%02x ",
1128                pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2],
1129                pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]));
1130        DBGPRINT(RT_DEBUG_TRACE, ("RxPower[%ld], Rssi %d\n", Index, pBeaconReport->RxPower - 256));
1131        DBGPRINT(RT_DEBUG_TRACE, ("FrameReportLen = %d\n", pAd->StaCfg.FrameReportLen));
1132
1133        pBeaconReport->BeaconInterval = pBss->BeaconPeriod;
1134        COPY_MAC_ADDR(pBeaconReport->BSSID, pFrame->Hdr.Addr3);
1135        NdisMoveMemory(pBeaconReport->ParentTSF, pSrc, 4);
1136        NdisMoveMemory(pBeaconReport->TargetTSF, &pElem->TimeStamp.u.LowPart, 4);
1137        NdisMoveMemory(&pBeaconReport->TargetTSF[4], &pElem->TimeStamp.u.HighPart, 4);
1138
1139        // 9. Skip the beacon frame and offset to start of capabilityinfo since we already processed capabilityinfo
1140        pSrc += (TIMESTAMP_LEN + 2);
1141        pBeaconReport->CapabilityInfo = *(USHORT *)pSrc;
1142
1143        // 10. Point to start of element ID
1144        pSrc += 2;
1145        pEid = (PEID_STRUCT) pSrc;
1146
1147        // 11. Start process all variable Eid oayload and add the appropriate to the frame report
1148        while (((PUCHAR) pEid + pEid->Len + 1) < ((PUCHAR) pFrame + MsgLen))
1149        {
1150                // Only limited EID are required to report for CCX 2. It includes SSID, Supported rate,
1151                // FH paramenter set, DS parameter set, CF parameter set, IBSS parameter set,
1152                // TIM (report first 4 bytes only, radio measurement capability
1153                switch (pEid->Eid)
1154                {
1155                        case IE_SSID:
1156                        case IE_SUPP_RATES:
1157                        case IE_FH_PARM:
1158                        case IE_DS_PARM:
1159                        case IE_CF_PARM:
1160                        case IE_IBSS_PARM:
1161                                NdisMoveMemory(pDest, pEid, pEid->Len + 2);
1162                                pDest  += (pEid->Len + 2);
1163                                Length += (pEid->Len + 2);
1164                                break;
1165
1166                        case IE_MEASUREMENT_CAPABILITY:
1167                                // Since this IE is duplicated with WPA security IE, we has to do sanity check before
1168                                // recognize it.
1169                                // 1. It also has fixed 6 bytes IE length.
1170                                if (pEid->Len != 6)
1171                                        break;
1172                                // 2. Check the Cisco Aironet OUI
1173                                if (NdisEqualMemory(CISCO_OUI, (pSrc + 2), 3))
1174                                {
1175                                        // Matched, this is what we want
1176                                        NdisMoveMemory(pDest, pEid, pEid->Len + 2);
1177                                        pDest  += (pEid->Len + 2);
1178                                        Length += (pEid->Len + 2);
1179                                }
1180                                break;
1181
1182                        case IE_TIM:
1183                                if (pEid->Len > 4)
1184                                {
1185                                        // May truncate and report the first 4 bytes only, with the eid & len, total should be 6
1186                                        NdisMoveMemory(pDest, pEid, 6);
1187                                        pDest  += 6;
1188                                        Length += 6;
1189                                }
1190                                else
1191                                {
1192                                        NdisMoveMemory(pDest, pEid, pEid->Len + 2);
1193                                        pDest  += (pEid->Len + 2);
1194                                        Length += (pEid->Len + 2);
1195                                }
1196                                break;
1197
1198                        default:
1199                                break;
1200                }
1201                // 12. Move to next element ID
1202                pSrc += (2 + pEid->Len);
1203                pEid = (PEID_STRUCT) pSrc;
1204        }
1205
1206        // 13. Update the length in the header, not include EID and length
1207        pReport->Length = Length - 4;
1208
1209        // 14. Update the frame report buffer data length
1210        pAd->StaCfg.FrameReportLen += Length;
1211        DBGPRINT(RT_DEBUG_TRACE, ("FR len = %d\n", pAd->StaCfg.FrameReportLen));
1212}
1213
1214/*
1215        ========================================================================
1216
1217        Routine Description:
1218
1219        Arguments:
1220                Index           Current BSSID in CCXBsstab entry index
1221
1222        Return Value:
1223
1224        Note:
1225
1226        ========================================================================
1227*/
1228VOID    AironetCreateBeaconReportFromBssTable(
1229        IN      PRTMP_ADAPTER           pAd)
1230{
1231        PMEASUREMENT_REPORT_ELEMENT     pReport;
1232        PBEACON_REPORT                          pBeaconReport;
1233        UCHAR                                           Index, ReqIdx;
1234        USHORT                                          Length;
1235        PUCHAR                                          pDest;
1236        PBSS_ENTRY                                      pBss;
1237
1238        // 0. setup base pointer
1239        ReqIdx = pAd->StaCfg.CurrentRMReqIdx;
1240
1241        for (Index = 0; Index < pAd->StaCfg.CCXBssTab.BssNr; Index++)
1242        {
1243                // 1. Setup the buffer address for copying this BSSID into reporting frame
1244                //    The offset should start after 802.11 header and report frame header.
1245                pDest  = (PUCHAR) &pAd->StaCfg.FrameReportBuf[pAd->StaCfg.FrameReportLen];
1246                pBss   = (PBSS_ENTRY) &pAd->StaCfg.CCXBssTab.BssEntry[Index];
1247                Length = 0;
1248
1249                // 2. Fill Measurement report fields
1250                pReport         = (PMEASUREMENT_REPORT_ELEMENT) pDest;
1251                pReport->Eid    = IE_MEASUREMENT_REPORT;
1252                pReport->Length = 0;
1253                pReport->Token  = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Token;
1254                pReport->Mode   = pAd->StaCfg.MeasurementRequest[ReqIdx].ReqElem.Mode;
1255                pReport->Type   = MSRN_TYPE_BEACON_REQ;
1256                Length          = sizeof(MEASUREMENT_REPORT_ELEMENT);
1257                pDest          += sizeof(MEASUREMENT_REPORT_ELEMENT);
1258
1259                // 3. Start the beacon report format
1260                pBeaconReport = (PBEACON_REPORT) pDest;
1261                pDest        += sizeof(BEACON_REPORT);
1262                Length       += sizeof(BEACON_REPORT);
1263
1264                // 4. Copy Channel number
1265                pBeaconReport->Channel        = pBss->Channel;
1266                pBeaconReport->Spare          = 0;
1267                pBeaconReport->Duration       = pAd->StaCfg.MeasurementRequest[ReqIdx].Measurement.Duration;
1268                pBeaconReport->PhyType        = ((pBss->SupRateLen+pBss->ExtRateLen > 4) ? PHY_ERP : PHY_DSS);
1269                pBeaconReport->RxPower        = pBss->Rssi - pAd->BbpRssiToDbmDelta;
1270                pBeaconReport->BeaconInterval = pBss->BeaconPeriod;
1271                pBeaconReport->CapabilityInfo = pBss->CapabilityInfo;
1272                COPY_MAC_ADDR(pBeaconReport->BSSID, pBss->Bssid);
1273                NdisMoveMemory(pBeaconReport->ParentTSF, pBss->PTSF, 4);
1274                NdisMoveMemory(pBeaconReport->TargetTSF, pBss->TTSF, 8);
1275
1276                // 5. Create SSID
1277                *pDest++ = 0x00;
1278                *pDest++ = pBss->SsidLen;
1279                NdisMoveMemory(pDest, pBss->Ssid, pBss->SsidLen);
1280                pDest  += pBss->SsidLen;
1281                Length += (2 + pBss->SsidLen);
1282
1283                // 6. Create SupportRates
1284                *pDest++ = 0x01;
1285                *pDest++ = pBss->SupRateLen;
1286                NdisMoveMemory(pDest, pBss->SupRate, pBss->SupRateLen);
1287                pDest  += pBss->SupRateLen;
1288                Length += (2 + pBss->SupRateLen);
1289
1290                // 7. DS Parameter
1291                *pDest++ = 0x03;
1292                *pDest++ = 1;
1293                *pDest++ = pBss->Channel;
1294                Length  += 3;
1295
1296                // 8. IBSS parameter if presents
1297                if (pBss->BssType == BSS_ADHOC)
1298                {
1299                        *pDest++ = 0x06;
1300                        *pDest++ = 2;
1301                        *(PUSHORT) pDest = pBss->AtimWin;
1302                        pDest   += 2;
1303                        Length  += 4;
1304                }
1305
1306                // 9. Update length field, not include EID and length
1307                pReport->Length = Length - 4;
1308
1309                // 10. Update total frame size
1310                pAd->StaCfg.FrameReportLen += Length;
1311        }
1312}
1313