| /* |
| ************************************************************************* |
| * 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; |
| } |
| } |