Commit ddaf5575 authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz Committed by Greg Kroah-Hartman

Staging: rt28[67]0: merge rt28[67]0/sta/*.[ch]

Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 5f5d2df8
/* #include "../../rt2860/sta/aironet.c"
*************************************************************************
* 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;
}
}
/* #include "../../rt2860/sta/assoc.c"
*************************************************************************
* 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:
assoc.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John 2004-9-3 porting from RT2500
*/
#include "../rt_config.h"
UCHAR CipherWpaTemplate[] = {
0xdd, // WPA IE
0x16, // Length
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x50, 0xf2, 0x02, // Multicast
0x01, 0x00, // Number of unicast
0x00, 0x50, 0xf2, 0x02, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x50, 0xf2, 0x01 // authentication
};
UCHAR CipherWpa2Template[] = {
0x30, // RSN IE
0x14, // Length
0x01, 0x00, // Version
0x00, 0x0f, 0xac, 0x02, // group cipher, TKIP
0x01, 0x00, // number of pairwise
0x00, 0x0f, 0xac, 0x02, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x0f, 0xac, 0x02, // authentication
0x00, 0x00, // RSN capability
};
UCHAR Ccx2IeInfo[] = { 0x00, 0x40, 0x96, 0x03, 0x02};
/*
==========================================================================
Description:
association state machine init, including state transition and timer init
Parameters:
S - pointer to the association state machine
IRQL = PASSIVE_LEVEL
==========================================================================
*/
VOID AssocStateMachineInit(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *S,
OUT STATE_MACHINE_FUNC Trans[])
{
StateMachineInit(S, Trans, MAX_ASSOC_STATE, MAX_ASSOC_MSG, (STATE_MACHINE_FUNC)Drop, ASSOC_IDLE, ASSOC_MACHINE_BASE);
// first column
StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)MlmeAssocReqAction);
StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)MlmeReassocReqAction);
StateMachineSetAction(S, ASSOC_IDLE, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)MlmeDisassocReqAction);
StateMachineSetAction(S, ASSOC_IDLE, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
// second column
StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc);
StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc);
StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate);
StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction);
//
// Patch 3Com AP MOde:3CRWE454G72
// We send Assoc request frame to this AP, it always send Reassoc Rsp not Associate Rsp.
//
StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerAssocRspAction);
StateMachineSetAction(S, ASSOC_WAIT_RSP, MT2_ASSOC_TIMEOUT, (STATE_MACHINE_FUNC)AssocTimeoutAction);
// third column
StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc);
StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc);
StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate);
StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_REASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction);
//
// Patch, AP doesn't send Reassociate Rsp frame to Station.
//
StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_PEER_ASSOC_RSP, (STATE_MACHINE_FUNC)PeerReassocRspAction);
StateMachineSetAction(S, REASSOC_WAIT_RSP, MT2_REASSOC_TIMEOUT, (STATE_MACHINE_FUNC)ReassocTimeoutAction);
// fourth column
StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_ASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAssoc);
StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_REASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenReassoc);
StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_MLME_DISASSOC_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenDisassociate);
StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_PEER_DISASSOC_REQ, (STATE_MACHINE_FUNC)PeerDisassocAction);
StateMachineSetAction(S, DISASSOC_WAIT_RSP, MT2_DISASSOC_TIMEOUT, (STATE_MACHINE_FUNC)DisassocTimeoutAction);
// initialize the timer
RTMPInitTimer(pAd, &pAd->MlmeAux.AssocTimer, GET_TIMER_FUNCTION(AssocTimeout), pAd, FALSE);
RTMPInitTimer(pAd, &pAd->MlmeAux.ReassocTimer, GET_TIMER_FUNCTION(ReassocTimeout), pAd, FALSE);
RTMPInitTimer(pAd, &pAd->MlmeAux.DisassocTimer, GET_TIMER_FUNCTION(DisassocTimeout), pAd, FALSE);
}
/*
==========================================================================
Description:
Association timeout procedure. After association timeout, this function
will be called and it will put a message into the MLME queue
Parameters:
Standard timer parameters
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID AssocTimeout(IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
return;
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_ASSOC_TIMEOUT, 0, NULL);
RT28XX_MLME_HANDLER(pAd);
}
/*
==========================================================================
Description:
Reassociation timeout procedure. After reassociation timeout, this
function will be called and put a message into the MLME queue
Parameters:
Standard timer parameters
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID ReassocTimeout(IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
return;
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_REASSOC_TIMEOUT, 0, NULL);
RT28XX_MLME_HANDLER(pAd);
}
/*
==========================================================================
Description:
Disassociation timeout procedure. After disassociation timeout, this
function will be called and put a message into the MLME queue
Parameters:
Standard timer parameters
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID DisassocTimeout(IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
return;
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_DISASSOC_TIMEOUT, 0, NULL);
RT28XX_MLME_HANDLER(pAd);
}
/*
==========================================================================
Description:
mlme assoc req handling procedure
Parameters:
Adapter - Adapter pointer
Elem - MLME Queue Element
Pre:
the station has been authenticated and the following information is stored in the config
-# SSID
-# supported rates and their length
-# listen interval (Adapter->StaCfg.default_listen_count)
-# Transmit power (Adapter->StaCfg.tx_power)
Post :
-# An association request frame is generated and sent to the air
-# Association timer starts
-# Association state -> ASSOC_WAIT_RSP
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID MlmeAssocReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR ApAddr[6];
HEADER_802_11 AssocHdr;
UCHAR Ccx2Len = 5;
UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
USHORT ListenIntv;
ULONG Timeout;
USHORT CapabilityInfo;
BOOLEAN TimerCancelled;
PUCHAR pOutBuffer = NULL;
NDIS_STATUS NStatus;
ULONG FrameLen = 0;
ULONG tmp;
USHORT VarIesOffset;
UCHAR CkipFlag;
UCHAR CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH];
UCHAR AironetCkipIe = IE_AIRONET_CKIP;
UCHAR AironetCkipLen = CKIP_NEGOTIATION_LENGTH;
UCHAR AironetIPAddressIE = IE_AIRONET_IPADDRESS;
UCHAR AironetIPAddressLen = AIRONET_IPADDRESS_LENGTH;
UCHAR AironetIPAddressBuffer[AIRONET_IPADDRESS_LENGTH] = {0x00, 0x40, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00};
USHORT Status;
// Block all authentication request durning WPA block period
if (pAd->StaCfg.bBlockAssoc == TRUE)
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block Assoc request durning WPA block period!\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status);
}
// check sanity first
else if (MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv))
{
RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled);
COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr);
// Get an unused nonpaged memory
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if (NStatus != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() allocate memory failed \n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_FAIL_NO_RESOURCE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status);
return;
}
// Add by James 03/06/27
pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
// Association don't need to report MAC address
pAd->StaCfg.AssocInfo.AvailableRequestFixedIEs =
NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_LISTENINTERVAL;
pAd->StaCfg.AssocInfo.RequestFixedIEs.Capabilities = CapabilityInfo;
pAd->StaCfg.AssocInfo.RequestFixedIEs.ListenInterval = ListenIntv;
// Only reassociate need this
//COPY_MAC_ADDR(pAd->StaCfg.AssocInfo.RequestFixedIEs.CurrentAPAddress, ApAddr);
pAd->StaCfg.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
NdisZeroMemory(pAd->StaCfg.ReqVarIEs, MAX_VIE_LEN);
// First add SSID
VarIesOffset = 0;
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SsidIe, 1);
VarIesOffset += 1;
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SsidLen, 1);
VarIesOffset += 1;
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen);
VarIesOffset += pAd->MlmeAux.SsidLen;
// Second add Supported rates
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &SupRateIe, 1);
VarIesOffset += 1;
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->MlmeAux.SupRateLen, 1);
VarIesOffset += 1;
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->MlmeAux.SupRate, pAd->MlmeAux.SupRateLen);
VarIesOffset += pAd->MlmeAux.SupRateLen;
// End Add by James
if ((pAd->CommonCfg.Channel > 14) &&
(pAd->CommonCfg.bIEEE80211H == TRUE))
CapabilityInfo |= 0x0100;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send ASSOC request...\n"));
MgtMacHeaderInit(pAd, &AssocHdr, SUBTYPE_ASSOC_REQ, 0, ApAddr, ApAddr);
// Build basic frame first
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11), &AssocHdr,
2, &CapabilityInfo,
2, &ListenIntv,
1, &SsidIe,
1, &pAd->MlmeAux.SsidLen,
pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid,
1, &SupRateIe,
1, &pAd->MlmeAux.SupRateLen,
pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate,
END_OF_ARGS);
if (pAd->MlmeAux.ExtRateLen != 0)
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
1, &ExtRateIe,
1, &pAd->MlmeAux.ExtRateLen,
pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate,
END_OF_ARGS);
FrameLen += tmp;
}
// HT
if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED))
{
ULONG TmpLen;
UCHAR HtLen;
UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33};
if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE)
{
HtLen = SIZE_HT_CAP_IE + 4;
MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen,
1, &WpaIe,
1, &HtLen,
4, &BROADCOM[0],
pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability,
END_OF_ARGS);
}
else
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen,
1, &HtCapIe,
1, &pAd->MlmeAux.HtCapabilityLen,
pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability,
END_OF_ARGS);
}
FrameLen += TmpLen;
}
// add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION
// Case I: (Aggregation + Piggy-Back)
// 1. user enable aggregation, AND
// 2. Mac support piggy-back
// 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON
// Case II: (Aggregation)
// 1. user enable aggregation, AND
// 2. AP annouces it's AGGREGATION-capable in BEACON
if (pAd->CommonCfg.bAggregationCapable)
{
if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3))
{
ULONG TmpLen;
UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00};
MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen,
9, RalinkIe,
END_OF_ARGS);
FrameLen += TmpLen;
}
else if (pAd->MlmeAux.APRalinkIe & 0x00000001)
{
ULONG TmpLen;
UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00};
MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen,
9, RalinkIe,
END_OF_ARGS);
FrameLen += TmpLen;
}
}
else
{
ULONG TmpLen;
UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x06, 0x00, 0x00, 0x00};
MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen,
9, RalinkIe,
END_OF_ARGS);
FrameLen += TmpLen;
}
if (pAd->MlmeAux.APEdcaParm.bValid)
{
if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable)
{
QBSS_STA_INFO_PARM QosInfo;
NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM));
QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE;
QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK;
QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI;
QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO;
QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength;
WmeIe[8] |= *(PUCHAR)&QosInfo;
}
else
{
// The Parameter Set Count is set to 0 in the association request frames
// WmeIe[8] |= (pAd->MlmeAux.APEdcaParm.EdcaUpdateCount & 0x0f);
}
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
9, &WmeIe[0],
END_OF_ARGS);
FrameLen += tmp;
}
//
// Let WPA(#221) Element ID on the end of this association frame.
// Otherwise some AP will fail on parsing Element ID and set status fail on Assoc Rsp.
// For example: Put Vendor Specific IE on the front of WPA IE.
// This happens on AP (Model No:Linksys WRK54G)
//
if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)
)
)
{
UCHAR RSNIe = IE_WPA;
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2))
{
RSNIe = IE_WPA2;
}
#ifdef RT30xx
#ifdef SIOCSIWGENIE
if (pAd->StaCfg.WpaSupplicantUP != 1)
#endif // SIOCSIWGENIE //
#endif
RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0);
// Check for WPA PMK cache list
if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2)
{
INT idx;
BOOLEAN FoundPMK = FALSE;
// Search chched PMKID, append it if existed
for (idx = 0; idx < PMKID_NO; idx++)
{
if (NdisEqualMemory(ApAddr, &pAd->StaCfg.SavedPMK[idx].BSSID, 6))
{
FoundPMK = TRUE;
break;
}
}
if (FoundPMK)
{
// Set PMK number
*(PUSHORT) &pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len] = 1;
NdisMoveMemory(&pAd->StaCfg.RSN_IE[pAd->StaCfg.RSNIE_Len + 2], &pAd->StaCfg.SavedPMK[idx].PMKID, 16);
pAd->StaCfg.RSNIE_Len += 18;
}
}
#ifdef RT30xx
#ifdef SIOCSIWGENIE
if (pAd->StaCfg.WpaSupplicantUP == 1)
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE,
END_OF_ARGS);
}
else
#endif
#endif
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
1, &RSNIe,
1, &pAd->StaCfg.RSNIE_Len,
pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE,
END_OF_ARGS);
}
FrameLen += tmp;
#ifdef RT30xx
#ifdef SIOCSIWGENIE
if (pAd->StaCfg.WpaSupplicantUP != 1)
#endif
#endif
{
// Append Variable IE
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &RSNIe, 1);
VarIesOffset += 1;
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, &pAd->StaCfg.RSNIE_Len, 1);
VarIesOffset += 1;
}
NdisMoveMemory(pAd->StaCfg.ReqVarIEs + VarIesOffset, pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len);
VarIesOffset += pAd->StaCfg.RSNIE_Len;
// Set Variable IEs Length
pAd->StaCfg.ReqVarIELen = VarIesOffset;
}
// We have update that at PeerBeaconAtJoinRequest()
CkipFlag = pAd->StaCfg.CkipFlag;
if (CkipFlag != 0)
{
NdisZeroMemory(CkipNegotiationBuffer, CKIP_NEGOTIATION_LENGTH);
CkipNegotiationBuffer[2] = 0x66;
// Make it try KP & MIC, since we have to follow the result from AssocRsp
CkipNegotiationBuffer[8] = 0x18;
CkipNegotiationBuffer[CKIP_NEGOTIATION_LENGTH - 1] = 0x22;
CkipFlag = 0x18;
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
1, &AironetCkipIe,
1, &AironetCkipLen,
AironetCkipLen, CkipNegotiationBuffer,
END_OF_ARGS);
FrameLen += tmp;
}
// Add CCX v2 request if CCX2 admin state is on
if (pAd->StaCfg.CCXControl.field.Enable == 1)
{
//
// Add AironetIPAddressIE for Cisco CCX 2.X
// Add CCX Version
//
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
1, &AironetIPAddressIE,
1, &AironetIPAddressLen,
AironetIPAddressLen, AironetIPAddressBuffer,
1, &Ccx2Ie,
1, &Ccx2Len,
Ccx2Len, Ccx2IeInfo,
END_OF_ARGS);
FrameLen += tmp;
// Add by James 03/06/27
// Set Variable IEs Length
pAd->StaCfg.ReqVarIELen = VarIesOffset;
pAd->StaCfg.AssocInfo.RequestIELength = VarIesOffset;
// OffsetResponseIEs follow ReqVarIE
pAd->StaCfg.AssocInfo.OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAd->StaCfg.ReqVarIELen;
// End Add by James
}
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
RTMPSetTimer(&pAd->MlmeAux.AssocTimer, Timeout);
pAd->Mlme.AssocMachine.CurrState = ASSOC_WAIT_RSP;
}
else
{
DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeAssocReqAction() sanity check failed. BUG!!!!!! \n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_INVALID_FORMAT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status);
}
}
/*
==========================================================================
Description:
mlme reassoc req handling procedure
Parameters:
Elem -
Pre:
-# SSID (Adapter->StaCfg.ssid[])
-# BSSID (AP address, Adapter->StaCfg.bssid)
-# Supported rates (Adapter->StaCfg.supported_rates[])
-# Supported rates length (Adapter->StaCfg.supported_rates_len)
-# Tx power (Adapter->StaCfg.tx_power)
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID MlmeReassocReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR ApAddr[6];
HEADER_802_11 ReassocHdr;
UCHAR Ccx2Len = 5;
UCHAR WmeIe[9] = {IE_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
USHORT CapabilityInfo, ListenIntv;
ULONG Timeout;
ULONG FrameLen = 0;
BOOLEAN TimerCancelled;
NDIS_STATUS NStatus;
ULONG tmp;
PUCHAR pOutBuffer = NULL;
USHORT Status;
// Block all authentication request durning WPA block period
if (pAd->StaCfg.bBlockAssoc == TRUE)
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Block ReAssoc request durning WPA block period!\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status);
}
// the parameters are the same as the association
else if(MlmeAssocReqSanity(pAd, Elem->Msg, Elem->MsgLen, ApAddr, &CapabilityInfo, &Timeout, &ListenIntv))
{
RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled);
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() allocate memory failed \n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_FAIL_NO_RESOURCE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status);
return;
}
COPY_MAC_ADDR(pAd->MlmeAux.Bssid, ApAddr);
// make frame, use bssid as the AP address??
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send RE-ASSOC request...\n"));
MgtMacHeaderInit(pAd, &ReassocHdr, SUBTYPE_REASSOC_REQ, 0, ApAddr, ApAddr);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11), &ReassocHdr,
2, &CapabilityInfo,
2, &ListenIntv,
MAC_ADDR_LEN, ApAddr,
1, &SsidIe,
1, &pAd->MlmeAux.SsidLen,
pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid,
1, &SupRateIe,
1, &pAd->MlmeAux.SupRateLen,
pAd->MlmeAux.SupRateLen, pAd->MlmeAux.SupRate,
END_OF_ARGS);
if (pAd->MlmeAux.ExtRateLen != 0)
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
1, &ExtRateIe,
1, &pAd->MlmeAux.ExtRateLen,
pAd->MlmeAux.ExtRateLen, pAd->MlmeAux.ExtRate,
END_OF_ARGS);
FrameLen += tmp;
}
if (pAd->MlmeAux.APEdcaParm.bValid)
{
if (pAd->CommonCfg.bAPSDCapable && pAd->MlmeAux.APEdcaParm.bAPSDCapable)
{
QBSS_STA_INFO_PARM QosInfo;
NdisZeroMemory(&QosInfo, sizeof(QBSS_STA_INFO_PARM));
QosInfo.UAPSD_AC_BE = pAd->CommonCfg.bAPSDAC_BE;
QosInfo.UAPSD_AC_BK = pAd->CommonCfg.bAPSDAC_BK;
QosInfo.UAPSD_AC_VI = pAd->CommonCfg.bAPSDAC_VI;
QosInfo.UAPSD_AC_VO = pAd->CommonCfg.bAPSDAC_VO;
QosInfo.MaxSPLength = pAd->CommonCfg.MaxSPLength;
WmeIe[8] |= *(PUCHAR)&QosInfo;
}
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
9, &WmeIe[0],
END_OF_ARGS);
FrameLen += tmp;
}
// HT
if ((pAd->MlmeAux.HtCapabilityLen > 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED))
{
ULONG TmpLen;
UCHAR HtLen;
UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33};
if (pAd->StaActive.SupportedPhyInfo.bPreNHt == TRUE)
{
HtLen = SIZE_HT_CAP_IE + 4;
MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen,
1, &WpaIe,
1, &HtLen,
4, &BROADCOM[0],
pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability,
END_OF_ARGS);
}
else
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen,
1, &HtCapIe,
1, &pAd->MlmeAux.HtCapabilityLen,
pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability,
END_OF_ARGS);
}
FrameLen += TmpLen;
}
// add Ralink proprietary IE to inform AP this STA is going to use AGGREGATION or PIGGY-BACK+AGGREGATION
// Case I: (Aggregation + Piggy-Back)
// 1. user enable aggregation, AND
// 2. Mac support piggy-back
// 3. AP annouces it's PIGGY-BACK+AGGREGATION-capable in BEACON
// Case II: (Aggregation)
// 1. user enable aggregation, AND
// 2. AP annouces it's AGGREGATION-capable in BEACON
if (pAd->CommonCfg.bAggregationCapable)
{
if ((pAd->CommonCfg.bPiggyBackCapable) && ((pAd->MlmeAux.APRalinkIe & 0x00000003) == 3))
{
ULONG TmpLen;
UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x03, 0x00, 0x00, 0x00};
MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen,
9, RalinkIe,
END_OF_ARGS);
FrameLen += TmpLen;
}
else if (pAd->MlmeAux.APRalinkIe & 0x00000001)
{
ULONG TmpLen;
UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x01, 0x00, 0x00, 0x00};
MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen,
9, RalinkIe,
END_OF_ARGS);
FrameLen += TmpLen;
}
}
else
{
ULONG TmpLen;
UCHAR RalinkIe[9] = {IE_VENDOR_SPECIFIC, 7, 0x00, 0x0c, 0x43, 0x04, 0x00, 0x00, 0x00};
MakeOutgoingFrame(pOutBuffer+FrameLen, &TmpLen,
9, RalinkIe,
END_OF_ARGS);
FrameLen += TmpLen;
}
// Add CCX v2 request if CCX2 admin state is on
if (pAd->StaCfg.CCXControl.field.Enable == 1)
{
//
// Add CCX Version
//
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
1, &Ccx2Ie,
1, &Ccx2Len,
Ccx2Len, Ccx2IeInfo,
END_OF_ARGS);
FrameLen += tmp;
}
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
RTMPSetTimer(&pAd->MlmeAux.ReassocTimer, Timeout); /* in mSec */
pAd->Mlme.AssocMachine.CurrState = REASSOC_WAIT_RSP;
}
else
{
DBGPRINT(RT_DEBUG_TRACE,("ASSOC - MlmeReassocReqAction() sanity check failed. BUG!!!! \n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_INVALID_FORMAT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status);
}
}
/*
==========================================================================
Description:
Upper layer issues disassoc request
Parameters:
Elem -
IRQL = PASSIVE_LEVEL
==========================================================================
*/
VOID MlmeDisassocReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PMLME_DISASSOC_REQ_STRUCT pDisassocReq;
HEADER_802_11 DisassocHdr;
PHEADER_802_11 pDisassocHdr;
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
NDIS_STATUS NStatus;
BOOLEAN TimerCancelled;
ULONG Timeout = 0;
USHORT Status;
// skip sanity check
pDisassocReq = (PMLME_DISASSOC_REQ_STRUCT)(Elem->Msg);
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if (NStatus != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - MlmeDisassocReqAction() allocate memory failed\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_FAIL_NO_RESOURCE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status);
return;
}
RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &TimerCancelled);
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Send DISASSOC request[BSSID::%02x:%02x:%02x:%02x:%02x:%02x (Reason=%d)\n",
pDisassocReq->Addr[0], pDisassocReq->Addr[1], pDisassocReq->Addr[2],
pDisassocReq->Addr[3], pDisassocReq->Addr[4], pDisassocReq->Addr[5], pDisassocReq->Reason));
MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pDisassocReq->Addr, pDisassocReq->Addr); // patch peap ttls switching issue
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11),&DisassocHdr,
2, &pDisassocReq->Reason,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
// To patch Instance and Buffalo(N) AP
// Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine
// Therefore, we send both of them.
pDisassocHdr = (PHEADER_802_11)pOutBuffer;
pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH;
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
pAd->StaCfg.DisassocReason = REASON_DISASSOC_STA_LEAVING;
COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pDisassocReq->Addr);
RTMPSetTimer(&pAd->MlmeAux.DisassocTimer, Timeout); /* in mSec */
pAd->Mlme.AssocMachine.CurrState = DISASSOC_WAIT_RSP;
{
union iwreq_data wrqu;
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
}
/*
==========================================================================
Description:
peer sends assoc rsp back
Parameters:
Elme - MLME message containing the received frame
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerAssocRspAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT CapabilityInfo, Status, Aid;
UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen;
UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen;
UCHAR Addr2[MAC_ADDR_LEN];
BOOLEAN TimerCancelled;
UCHAR CkipFlag;
EDCA_PARM EdcaParm;
HT_CAPABILITY_IE HtCapability;
ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE
UCHAR HtCapabilityLen;
UCHAR AddHtInfoLen;
UCHAR NewExtChannelOffset = 0xff;
if (PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen,
&HtCapability,&AddHtInfo, &HtCapabilityLen,&AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag))
{
// The frame is for me ?
if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid))
{
DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():ASSOC - receive ASSOC_RSP to me (status=%d)\n", Status));
DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspAction():MacTable [%d].AMsduSize = %d. ClientStatusFlags = 0x%lx \n",Elem->Wcid, pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags));
RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &TimerCancelled);
if(Status == MLME_SUCCESS)
{
UCHAR MaxSupportedRateIn500Kbps = 0;
UCHAR idx;
// supported rates array may not be sorted. sort it and find the maximum rate
for (idx=0; idx<SupRateLen; idx++)
{
if (MaxSupportedRateIn500Kbps < (SupRate[idx] & 0x7f))
MaxSupportedRateIn500Kbps = SupRate[idx] & 0x7f;
}
for (idx=0; idx<ExtRateLen; idx++)
{
if (MaxSupportedRateIn500Kbps < (ExtRate[idx] & 0x7f))
MaxSupportedRateIn500Kbps = ExtRate[idx] & 0x7f;
}
// go to procedure listed on page 376
AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen,
&EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo);
StaAddMacTableEntry(pAd, &pAd->MacTab.Content[BSSID_WCID], MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo);
pAd->StaCfg.CkipFlag = CkipFlag;
if (CkipFlag & 0x18)
{
NdisZeroMemory(pAd->StaCfg.TxSEQ, 4);
NdisZeroMemory(pAd->StaCfg.RxSEQ, 4);
NdisZeroMemory(pAd->StaCfg.CKIPMIC, 4);
pAd->StaCfg.GIV[0] = RandomByte(pAd);
pAd->StaCfg.GIV[1] = RandomByte(pAd);
pAd->StaCfg.GIV[2] = RandomByte(pAd);
pAd->StaCfg.bCkipOn = TRUE;
DBGPRINT(RT_DEBUG_TRACE, ("<CCX> pAd->StaCfg.CkipFlag = 0x%02x\n", pAd->StaCfg.CkipFlag));
}
}
else
{
}
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status);
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerAssocRspAction() sanity check fail\n"));
}
}
/*
==========================================================================
Description:
peer sends reassoc rsp
Parametrs:
Elem - MLME message cntaining the received frame
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerReassocRspAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT CapabilityInfo;
USHORT Status;
USHORT Aid;
UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], SupRateLen;
UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRateLen;
UCHAR Addr2[MAC_ADDR_LEN];
UCHAR CkipFlag;
BOOLEAN TimerCancelled;
EDCA_PARM EdcaParm;
HT_CAPABILITY_IE HtCapability;
ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE
UCHAR HtCapabilityLen;
UCHAR AddHtInfoLen;
UCHAR NewExtChannelOffset = 0xff;
if(PeerAssocRspSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &CapabilityInfo, &Status, &Aid, SupRate, &SupRateLen, ExtRate, &ExtRateLen,
&HtCapability, &AddHtInfo, &HtCapabilityLen, &AddHtInfoLen,&NewExtChannelOffset, &EdcaParm, &CkipFlag))
{
if(MAC_ADDR_EQUAL(Addr2, pAd->MlmeAux.Bssid)) // The frame is for me ?
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - receive REASSOC_RSP to me (status=%d)\n", Status));
RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &TimerCancelled);
if(Status == MLME_SUCCESS)
{
// go to procedure listed on page 376
AssocPostProc(pAd, Addr2, CapabilityInfo, Aid, SupRate, SupRateLen, ExtRate, ExtRateLen,
&EdcaParm, &HtCapability, HtCapabilityLen, &AddHtInfo);
{
union iwreq_data wrqu;
wext_notify_event_assoc(pAd);
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
}
{
// CkipFlag is no use for reassociate
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status);
}
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerReassocRspAction() sanity check fail\n"));
}
}
/*
==========================================================================
Description:
procedures on IEEE 802.11/1999 p.376
Parametrs:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID AssocPostProc(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pAddr2,
IN USHORT CapabilityInfo,
IN USHORT Aid,
IN UCHAR SupRate[],
IN UCHAR SupRateLen,
IN UCHAR ExtRate[],
IN UCHAR ExtRateLen,
IN PEDCA_PARM pEdcaParm,
IN HT_CAPABILITY_IE *pHtCapability,
IN UCHAR HtCapabilityLen,
IN ADD_HT_INFO_IE *pAddHtInfo) // AP might use this additional ht info IE
{
ULONG Idx;
pAd->MlmeAux.BssType = BSS_INFRA;
COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pAddr2);
pAd->MlmeAux.Aid = Aid;
pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO;
// Some HT AP might lost WMM IE. We add WMM ourselves. beacuase HT requires QoS on.
if ((HtCapabilityLen > 0) && (pEdcaParm->bValid == FALSE))
{
pEdcaParm->bValid = TRUE;
pEdcaParm->Aifsn[0] = 3;
pEdcaParm->Aifsn[1] = 7;
pEdcaParm->Aifsn[2] = 2;
pEdcaParm->Aifsn[3] = 2;
pEdcaParm->Cwmin[0] = 4;
pEdcaParm->Cwmin[1] = 4;
pEdcaParm->Cwmin[2] = 3;
pEdcaParm->Cwmin[3] = 2;
pEdcaParm->Cwmax[0] = 10;
pEdcaParm->Cwmax[1] = 10;
pEdcaParm->Cwmax[2] = 4;
pEdcaParm->Cwmax[3] = 3;
pEdcaParm->Txop[0] = 0;
pEdcaParm->Txop[1] = 0;
pEdcaParm->Txop[2] = 96;
pEdcaParm->Txop[3] = 48;
}
NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, pEdcaParm, sizeof(EDCA_PARM));
// filter out un-supported rates
pAd->MlmeAux.SupRateLen = SupRateLen;
NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen);
RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen);
// filter out un-supported rates
pAd->MlmeAux.ExtRateLen = ExtRateLen;
NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen);
RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen);
if (HtCapabilityLen > 0)
{
RTMPCheckHt(pAd, BSSID_WCID, pHtCapability, pAddHtInfo);
}
DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> AP.AMsduSize = %d. ClientStatusFlags = 0x%lx \n", pAd->MacTab.Content[BSSID_WCID].AMsduSize, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags));
DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> (Mmps=%d, AmsduSize=%d, )\n",
pAd->MacTab.Content[BSSID_WCID].MmpsMode, pAd->MacTab.Content[BSSID_WCID].AMsduSize));
// Set New WPA information
Idx = BssTableSearch(&pAd->ScanTab, pAddr2, pAd->MlmeAux.Channel);
if (Idx == BSS_NOT_FOUND)
{
DBGPRINT_ERR(("ASSOC - Can't find BSS after receiving Assoc response\n"));
}
else
{
// Init variable
pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = 0;
NdisZeroMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, MAX_LEN_OF_RSNIE);
// Store appropriate RSN_IE for WPA SM negotiation later
if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) && (pAd->ScanTab.BssEntry[Idx].VarIELen != 0))
{
PUCHAR pVIE;
USHORT len;
PEID_STRUCT pEid;
pVIE = pAd->ScanTab.BssEntry[Idx].VarIEs;
len = pAd->ScanTab.BssEntry[Idx].VarIELen;
while (len > 0)
{
pEid = (PEID_STRUCT) pVIE;
// For WPA/WPAPSK
if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))
&& (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
{
NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2));
pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2);
DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA SM negotiation \n"));
}
// For WPA2/WPA2PSK
else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))
&& (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
{
NdisMoveMemory(pAd->MacTab.Content[BSSID_WCID].RSN_IE, pVIE, (pEid->Len + 2));
pAd->MacTab.Content[BSSID_WCID].RSNIE_Len = (pEid->Len + 2);
DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> Store RSN_IE for WPA2 SM negotiation \n"));
}
pVIE += (pEid->Len + 2);
len -= (pEid->Len + 2);
}
}
if (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == 0)
{
DBGPRINT(RT_DEBUG_TRACE, ("AssocPostProc===> no RSN_IE \n"));
}
else
{
hex_dump("RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len);
}
}
}
/*
==========================================================================
Description:
left part of IEEE 802.11/1999 p.374
Parameters:
Elem - MLME message containing the received frame
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerDisassocAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Addr2[MAC_ADDR_LEN];
USHORT Reason;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction()\n"));
if(PeerDisassocSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason))
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() Reason = %d\n", Reason));
if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, Addr2))
{
if (pAd->CommonCfg.bWirelessEvent)
{
RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
}
//
// Get Current System time and Turn on AdjacentAPReport
//
NdisGetSystemUpTime(&pAd->StaCfg.CCXAdjacentAPLinkDownTime);
pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE;
LinkDown(pAd, TRUE);
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
{
union iwreq_data wrqu;
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - PeerDisassocAction() sanity check fail\n"));
}
}
/*
==========================================================================
Description:
what the state machine will do after assoc timeout
Parameters:
Elme -
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID AssocTimeoutAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - AssocTimeoutAction\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_REJ_TIMEOUT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status);
}
/*
==========================================================================
Description:
what the state machine will do after reassoc timeout
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID ReassocTimeoutAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - ReassocTimeoutAction\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_REJ_TIMEOUT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status);
}
/*
==========================================================================
Description:
what the state machine will do after disassoc timeout
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID DisassocTimeoutAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - DisassocTimeoutAction\n"));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_SUCCESS;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status);
}
VOID InvalidStateWhenAssoc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenAssoc(state=%ld), reset ASSOC state machine\n",
pAd->Mlme.AssocMachine.CurrState));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_ASSOC_CONF, 2, &Status);
}
VOID InvalidStateWhenReassoc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenReassoc(state=%ld), reset ASSOC state machine\n",
pAd->Mlme.AssocMachine.CurrState));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_REASSOC_CONF, 2, &Status);
}
VOID InvalidStateWhenDisassociate(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - InvalidStateWhenDisassoc(state=%ld), reset ASSOC state machine\n",
pAd->Mlme.AssocMachine.CurrState));
pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DISASSOC_CONF, 2, &Status);
}
/*
==========================================================================
Description:
right part of IEEE 802.11/1999 page 374
Note:
This event should never cause ASSOC state machine perform state
transition, and has no relationship with CNTL machine. So we separate
this routine as a service outside of ASSOC state transition table.
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID Cls3errAction(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pAddr)
{
HEADER_802_11 DisassocHdr;
PHEADER_802_11 pDisassocHdr;
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
NDIS_STATUS NStatus;
USHORT Reason = REASON_CLS3ERR;
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if (NStatus != NDIS_STATUS_SUCCESS)
return;
DBGPRINT(RT_DEBUG_TRACE, ("ASSOC - Class 3 Error, Send DISASSOC frame\n"));
MgtMacHeaderInit(pAd, &DisassocHdr, SUBTYPE_DISASSOC, 0, pAddr, pAd->CommonCfg.Bssid); // patch peap ttls switching issue
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11),&DisassocHdr,
2, &Reason,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
// To patch Instance and Buffalo(N) AP
// Driver has to send deauth to Instance AP, but Buffalo(N) needs to send disassoc to reset Authenticator's state machine
// Therefore, we send both of them.
pDisassocHdr = (PHEADER_802_11)pOutBuffer;
pDisassocHdr->FC.SubType = SUBTYPE_DEAUTH;
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
pAd->StaCfg.DisassocReason = REASON_CLS3ERR;
COPY_MAC_ADDR(pAd->StaCfg.DisassocSta, pAddr);
}
/*
==========================================================================
Description:
Switch between WEP and CKIP upon new association up.
Parameters:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID SwitchBetweenWepAndCkip(
IN PRTMP_ADAPTER pAd)
{
int i;
SHAREDKEY_MODE_STRUC csr1;
// if KP is required. change the CipherAlg in hardware shard key table from WEP
// to CKIP. else remain as WEP
if (pAd->StaCfg.bCkipOn && (pAd->StaCfg.CkipFlag & 0x10))
{
// modify hardware key table so that MAC use correct algorithm to decrypt RX
RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word);
if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP64)
csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP64;
else if (csr1.field.Bss0Key0CipherAlg == CIPHER_WEP128)
csr1.field.Bss0Key0CipherAlg = CIPHER_CKIP128;
if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP64)
csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP64;
else if (csr1.field.Bss0Key1CipherAlg == CIPHER_WEP128)
csr1.field.Bss0Key1CipherAlg = CIPHER_CKIP128;
if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP64)
csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP64;
else if (csr1.field.Bss0Key2CipherAlg == CIPHER_WEP128)
csr1.field.Bss0Key2CipherAlg = CIPHER_CKIP128;
if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP64)
csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP64;
else if (csr1.field.Bss0Key3CipherAlg == CIPHER_WEP128)
csr1.field.Bss0Key3CipherAlg = CIPHER_CKIP128;
RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word);
DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg]));
// modify software key table so that driver can specify correct algorithm in TXD upon TX
for (i=0; i<SHARE_KEY_NUM; i++)
{
if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_WEP64)
pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP64;
else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_WEP128)
pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_CKIP128;
}
}
// else if KP NOT inused. change the CipherAlg in hardware shard key table from CKIP
// to WEP.
else
{
// modify hardware key table so that MAC use correct algorithm to decrypt RX
RTMP_IO_READ32(pAd, SHARED_KEY_MODE_BASE, &csr1.word);
if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP64)
csr1.field.Bss0Key0CipherAlg = CIPHER_WEP64;
else if (csr1.field.Bss0Key0CipherAlg == CIPHER_CKIP128)
csr1.field.Bss0Key0CipherAlg = CIPHER_WEP128;
if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP64)
csr1.field.Bss0Key1CipherAlg = CIPHER_WEP64;
else if (csr1.field.Bss0Key1CipherAlg == CIPHER_CKIP128)
csr1.field.Bss0Key1CipherAlg = CIPHER_WEP128;
if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP64)
csr1.field.Bss0Key2CipherAlg = CIPHER_WEP64;
else if (csr1.field.Bss0Key2CipherAlg == CIPHER_CKIP128)
csr1.field.Bss0Key2CipherAlg = CIPHER_WEP128;
if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP64)
csr1.field.Bss0Key3CipherAlg = CIPHER_WEP64;
else if (csr1.field.Bss0Key3CipherAlg == CIPHER_CKIP128)
csr1.field.Bss0Key3CipherAlg = CIPHER_WEP128;
// modify software key table so that driver can specify correct algorithm in TXD upon TX
for (i=0; i<SHARE_KEY_NUM; i++)
{
if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_CKIP64)
pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP64;
else if (pAd->SharedKey[BSS0][i].CipherAlg == CIPHER_CKIP128)
pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_WEP128;
}
//
// On WPA-NONE, must update CipherAlg.
// Because the OID_802_11_WEP_STATUS was been set after OID_802_11_ADD_KEY
// and CipherAlg will be CIPHER_NONE by Windows ZeroConfig.
// So we need to update CipherAlg after connect.
//
if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone)
{
for (i = 0; i < SHARE_KEY_NUM; i++)
{
if (pAd->SharedKey[BSS0][i].KeyLen != 0)
{
if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled)
{
pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_TKIP;
}
else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_AES;
}
}
else
{
pAd->SharedKey[BSS0][i].CipherAlg = CIPHER_NONE;
}
}
csr1.field.Bss0Key0CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg;
csr1.field.Bss0Key1CipherAlg = pAd->SharedKey[BSS0][1].CipherAlg;
csr1.field.Bss0Key2CipherAlg = pAd->SharedKey[BSS0][2].CipherAlg;
csr1.field.Bss0Key3CipherAlg = pAd->SharedKey[BSS0][3].CipherAlg;
}
RTMP_IO_WRITE32(pAd, SHARED_KEY_MODE_BASE, csr1.word);
DBGPRINT(RT_DEBUG_TRACE, ("SwitchBetweenWepAndCkip: modify BSS0 cipher to %s\n", CipherName[csr1.field.Bss0Key0CipherAlg]));
}
}
int wext_notify_event_assoc(
IN RTMP_ADAPTER *pAd)
{
union iwreq_data wrqu;
char custom[IW_CUSTOM_MAX] = {0};
#if WIRELESS_EXT > 17
if (pAd->StaCfg.ReqVarIELen <= IW_CUSTOM_MAX)
{
wrqu.data.length = pAd->StaCfg.ReqVarIELen;
memcpy(custom, pAd->StaCfg.ReqVarIEs, pAd->StaCfg.ReqVarIELen);
wireless_send_event(pAd->net_dev, IWEVASSOCREQIE, &wrqu, custom);
}
else
DBGPRINT(RT_DEBUG_TRACE, ("pAd->StaCfg.ReqVarIELen > MAX_CUSTOM_LEN\n"));
#else
if (((pAd->StaCfg.ReqVarIELen*2) + 17) <= IW_CUSTOM_MAX)
{
UCHAR idx;
wrqu.data.length = (pAd->StaCfg.ReqVarIELen*2) + 17;
sprintf(custom, "ASSOCINFO(ReqIEs=");
for (idx=0; idx<pAd->StaCfg.ReqVarIELen; idx++)
sprintf(custom + strlen(custom), "%02x", pAd->StaCfg.ReqVarIEs[idx]);
wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom);
}
else
DBGPRINT(RT_DEBUG_TRACE, ("(pAd->StaCfg.ReqVarIELen*2) + 17 > MAX_CUSTOM_LEN\n"));
#endif
return 0;
}
BOOLEAN StaAddMacTableEntry(
IN PRTMP_ADAPTER pAd,
IN PMAC_TABLE_ENTRY pEntry,
IN UCHAR MaxSupportedRateIn500Kbps,
IN HT_CAPABILITY_IE *pHtCapability,
IN UCHAR HtCapabilityLen,
IN USHORT CapabilityInfo)
{
UCHAR MaxSupportedRate = RATE_11;
if (ADHOC_ON(pAd))
CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE);
switch (MaxSupportedRateIn500Kbps)
{
case 108: MaxSupportedRate = RATE_54; break;
case 96: MaxSupportedRate = RATE_48; break;
case 72: MaxSupportedRate = RATE_36; break;
case 48: MaxSupportedRate = RATE_24; break;
case 36: MaxSupportedRate = RATE_18; break;
case 24: MaxSupportedRate = RATE_12; break;
case 18: MaxSupportedRate = RATE_9; break;
case 12: MaxSupportedRate = RATE_6; break;
case 22: MaxSupportedRate = RATE_11; break;
case 11: MaxSupportedRate = RATE_5_5; break;
case 4: MaxSupportedRate = RATE_2; break;
case 2: MaxSupportedRate = RATE_1; break;
default: MaxSupportedRate = RATE_11; break;
}
if ((pAd->CommonCfg.PhyMode == PHY_11G) && (MaxSupportedRate < RATE_FIRST_OFDM_RATE))
return FALSE;
// 11n only
if (((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))&& (HtCapabilityLen == 0))
return FALSE;
if (!pEntry)
return FALSE;
NdisAcquireSpinLock(&pAd->MacTabLock);
if (pEntry)
{
pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
if ((MaxSupportedRate < RATE_FIRST_OFDM_RATE) ||
(pAd->CommonCfg.PhyMode == PHY_11B))
{
pEntry->RateLen = 4;
if (MaxSupportedRate >= RATE_FIRST_OFDM_RATE)
MaxSupportedRate = RATE_11;
}
else
pEntry->RateLen = 12;
pEntry->MaxHTPhyMode.word = 0;
pEntry->MinHTPhyMode.word = 0;
pEntry->HTPhyMode.word = 0;
pEntry->MaxSupportedRate = MaxSupportedRate;
if (pEntry->MaxSupportedRate < RATE_FIRST_OFDM_RATE)
{
pEntry->MaxHTPhyMode.field.MODE = MODE_CCK;
pEntry->MaxHTPhyMode.field.MCS = pEntry->MaxSupportedRate;
pEntry->MinHTPhyMode.field.MODE = MODE_CCK;
pEntry->MinHTPhyMode.field.MCS = pEntry->MaxSupportedRate;
pEntry->HTPhyMode.field.MODE = MODE_CCK;
pEntry->HTPhyMode.field.MCS = pEntry->MaxSupportedRate;
}
else
{
pEntry->MaxHTPhyMode.field.MODE = MODE_OFDM;
pEntry->MaxHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate];
pEntry->MinHTPhyMode.field.MODE = MODE_OFDM;
pEntry->MinHTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate];
pEntry->HTPhyMode.field.MODE = MODE_OFDM;
pEntry->HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pEntry->MaxSupportedRate];
}
pEntry->CapabilityInfo = CapabilityInfo;
CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_AGGREGATION_CAPABLE);
CLIENT_STATUS_CLEAR_FLAG(pEntry, fCLIENT_STATUS_PIGGYBACK_CAPABLE);
}
// If this Entry supports 802.11n, upgrade to HT rate.
if ((HtCapabilityLen != 0) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED))
{
UCHAR j, bitmask; //k,bitmask;
CHAR i;
if (ADHOC_ON(pAd))
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE);
if ((pHtCapability->HtCapInfo.GF) && (pAd->CommonCfg.DesiredHtPhy.GF))
{
pEntry->MaxHTPhyMode.field.MODE = MODE_HTGREENFIELD;
}
else
{
pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX;
pAd->MacTab.fAnyStationNonGF = TRUE;
pAd->CommonCfg.AddHTInfo.AddHtInfo2.NonGfPresent = 1;
}
if ((pHtCapability->HtCapInfo.ChannelWidth) && (pAd->CommonCfg.DesiredHtPhy.ChannelWidth))
{
pEntry->MaxHTPhyMode.field.BW= BW_40;
pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor40)&(pHtCapability->HtCapInfo.ShortGIfor40));
}
else
{
pEntry->MaxHTPhyMode.field.BW = BW_20;
pEntry->MaxHTPhyMode.field.ShortGI = ((pAd->CommonCfg.DesiredHtPhy.ShortGIfor20)&(pHtCapability->HtCapInfo.ShortGIfor20));
pAd->MacTab.fAnyStation20Only = TRUE;
}
// 3*3
if (pAd->MACVersion >= RALINK_2883_VERSION && pAd->MACVersion < RALINK_3070_VERSION)
pEntry->MaxHTPhyMode.field.TxBF = pAd->CommonCfg.RegTransmitSetting.field.TxBF;
// find max fixed rate
for (i=23; i>=0; i--) // 3*3
{
j = i/8;
bitmask = (1<<(i-(j*8)));
if ((pAd->StaCfg.DesiredHtPhyInfo.MCSSet[j] & bitmask) && (pHtCapability->MCSSet[j] & bitmask))
{
pEntry->MaxHTPhyMode.field.MCS = i;
break;
}
if (i==0)
break;
}
if (pAd->StaCfg.DesiredTransmitSetting.field.MCS != MCS_AUTO)
{
if (pAd->StaCfg.DesiredTransmitSetting.field.MCS == 32)
{
// Fix MCS as HT Duplicated Mode
pEntry->MaxHTPhyMode.field.BW = 1;
pEntry->MaxHTPhyMode.field.MODE = MODE_HTMIX;
pEntry->MaxHTPhyMode.field.STBC = 0;
pEntry->MaxHTPhyMode.field.ShortGI = 0;
pEntry->MaxHTPhyMode.field.MCS = 32;
}
else if (pEntry->MaxHTPhyMode.field.MCS > pAd->StaCfg.HTPhyMode.field.MCS)
{
// STA supports fixed MCS
pEntry->MaxHTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS;
}
}
pEntry->MaxHTPhyMode.field.STBC = (pHtCapability->HtCapInfo.RxSTBC & (pAd->CommonCfg.DesiredHtPhy.TxSTBC));
pEntry->MpduDensity = pHtCapability->HtCapParm.MpduDensity;
pEntry->MaxRAmpduFactor = pHtCapability->HtCapParm.MaxRAmpduFactor;
pEntry->MmpsMode = (UCHAR)pHtCapability->HtCapInfo.MimoPs;
pEntry->AMsduSize = (UCHAR)pHtCapability->HtCapInfo.AMsduSize;
pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word;
if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable && (pAd->CommonCfg.REGBACapability.field.AutoBA == FALSE))
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED);
if (pHtCapability->HtCapInfo.ShortGIfor20)
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE);
if (pHtCapability->HtCapInfo.ShortGIfor40)
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE);
if (pHtCapability->HtCapInfo.TxSTBC)
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_TxSTBC_CAPABLE);
if (pHtCapability->HtCapInfo.RxSTBC)
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RxSTBC_CAPABLE);
if (pHtCapability->ExtHtCapInfo.PlusHTC)
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_HTC_CAPABLE);
if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport)
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_RDG_CAPABLE);
if (pHtCapability->ExtHtCapInfo.MCSFeedback == 0x03)
CLIENT_STATUS_SET_FLAG(pEntry, fCLIENT_STATUS_MCSFEEDBACK_CAPABLE);
}
else
{
pAd->MacTab.fAnyStationIsLegacy = TRUE;
}
NdisMoveMemory(&pEntry->HTCapability, pHtCapability, sizeof(HT_CAPABILITY_IE));
pEntry->HTPhyMode.word = pEntry->MaxHTPhyMode.word;
pEntry->CurrTxRate = pEntry->MaxSupportedRate;
// Set asic auto fall back
if (pAd->StaCfg.bAutoTxRateSwitch == TRUE)
{
PUCHAR pTable;
UCHAR TableSize = 0;
MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &pEntry->CurrTxRateIndex);
pEntry->bAutoTxRateSwitch = TRUE;
}
else
{
pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE;
pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS;
pEntry->bAutoTxRateSwitch = FALSE;
// If the legacy mode is set, overwrite the transmit setting of this entry.
RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry);
}
pEntry->PortSecured = WPA_802_1X_PORT_SECURED;
pEntry->Sst = SST_ASSOC;
pEntry->AuthState = AS_AUTH_OPEN;
pEntry->AuthMode = pAd->StaCfg.AuthMode;
pEntry->WepStatus = pAd->StaCfg.WepStatus;
NdisReleaseSpinLock(&pAd->MacTabLock);
{
union iwreq_data wrqu;
wext_notify_event_assoc(pAd);
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
return TRUE;
}
/* #include "../../rt2860/sta/auth.c"
*************************************************************************
* 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:
auth.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John 2004-9-3 porting from RT2500
*/
#include "../rt_config.h"
/*
==========================================================================
Description:
authenticate state machine init, including state transition and timer init
Parameters:
Sm - pointer to the auth state machine
Note:
The state machine looks like this
AUTH_REQ_IDLE AUTH_WAIT_SEQ2 AUTH_WAIT_SEQ4
MT2_MLME_AUTH_REQ mlme_auth_req_action invalid_state_when_auth invalid_state_when_auth
MT2_PEER_AUTH_EVEN drop peer_auth_even_at_seq2_action peer_auth_even_at_seq4_action
MT2_AUTH_TIMEOUT Drop auth_timeout_action auth_timeout_action
IRQL = PASSIVE_LEVEL
==========================================================================
*/
void AuthStateMachineInit(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *Sm,
OUT STATE_MACHINE_FUNC Trans[])
{
StateMachineInit(Sm, Trans, MAX_AUTH_STATE, MAX_AUTH_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_REQ_IDLE, AUTH_MACHINE_BASE);
// the first column
StateMachineSetAction(Sm, AUTH_REQ_IDLE, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)MlmeAuthReqAction);
// the second column
StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth);
StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq2Action);
StateMachineSetAction(Sm, AUTH_WAIT_SEQ2, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction);
// the third column
StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_MLME_AUTH_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenAuth);
StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_PEER_AUTH_EVEN, (STATE_MACHINE_FUNC)PeerAuthRspAtSeq4Action);
StateMachineSetAction(Sm, AUTH_WAIT_SEQ4, MT2_AUTH_TIMEOUT, (STATE_MACHINE_FUNC)AuthTimeoutAction);
RTMPInitTimer(pAd, &pAd->MlmeAux.AuthTimer, GET_TIMER_FUNCTION(AuthTimeout), pAd, FALSE);
}
/*
==========================================================================
Description:
function to be executed at timer thread when auth timer expires
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID AuthTimeout(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
DBGPRINT(RT_DEBUG_TRACE,("AUTH - AuthTimeout\n"));
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
return;
// send a de-auth to reset AP's state machine (Patch AP-Dir635)
if (pAd->Mlme.AuthMachine.CurrState == AUTH_WAIT_SEQ2)
Cls2errAction(pAd, pAd->MlmeAux.Bssid);
MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_AUTH_TIMEOUT, 0, NULL);
RT28XX_MLME_HANDLER(pAd);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID MlmeAuthReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Addr[6];
USHORT Alg, Seq, Status;
ULONG Timeout;
HEADER_802_11 AuthHdr;
BOOLEAN TimerCancelled;
NDIS_STATUS NStatus;
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
// Block all authentication request durning WPA block period
if (pAd->StaCfg.bBlockAssoc == TRUE)
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Block Auth request durning WPA block period!\n"));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
}
else if(MlmeAuthReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr, &Timeout, &Alg))
{
// reset timer
RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled);
COPY_MAC_ADDR(pAd->MlmeAux.Bssid, Addr);
pAd->MlmeAux.Alg = Alg;
Seq = 1;
Status = MLME_SUCCESS;
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeAuthReqAction(Alg:%d) allocate memory failed\n", Alg));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_FAIL_NO_RESOURCE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
return;
}
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#1 (Alg=%d)...\n", Alg));
MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr, pAd->MlmeAux.Bssid);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11),&AuthHdr,
2, &Alg,
2, &Seq,
2, &Status,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
RTMPSetTimer(&pAd->MlmeAux.AuthTimer, Timeout);
pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ2;
}
else
{
DBGPRINT_ERR(("AUTH - MlmeAuthReqAction() sanity check failed\n"));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_INVALID_FORMAT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerAuthRspAtSeq2Action(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Addr2[MAC_ADDR_LEN];
USHORT Seq, Status, RemoteStatus, Alg;
UCHAR ChlgText[CIPHER_TEXT_LEN];
UCHAR CyperChlgText[CIPHER_TEXT_LEN + 8 + 8];
UCHAR Element[2];
HEADER_802_11 AuthHdr;
BOOLEAN TimerCancelled;
PUCHAR pOutBuffer = NULL;
NDIS_STATUS NStatus;
ULONG FrameLen = 0;
USHORT Status2;
if (PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText))
{
if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 2)
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#2 to me (Alg=%d, Status=%d)\n", Alg, Status));
RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled);
if (Status == MLME_SUCCESS)
{
// Authentication Mode "LEAP" has allow for CCX 1.X
if ((pAd->MlmeAux.Alg == Ndis802_11AuthModeOpen)
)
{
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
}
else
{
// 2. shared key, need to be challenged
Seq++;
RemoteStatus = MLME_SUCCESS;
// Get an unused nonpaged memory
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if(NStatus != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq2Action() allocate memory fail\n"));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status2 = MLME_FAIL_NO_RESOURCE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status2);
return;
}
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send AUTH request seq#3...\n"));
MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, Addr2, pAd->MlmeAux.Bssid);
AuthHdr.FC.Wep = 1;
// Encrypt challenge text & auth information
RTMPInitWepEngine(
pAd,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key,
pAd->StaCfg.DefaultKeyId,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen,
CyperChlgText);
Alg = cpu2le16(*(USHORT *)&Alg);
Seq = cpu2le16(*(USHORT *)&Seq);
RemoteStatus= cpu2le16(*(USHORT *)&RemoteStatus);
RTMPEncryptData(pAd, (PUCHAR) &Alg, CyperChlgText + 4, 2);
RTMPEncryptData(pAd, (PUCHAR) &Seq, CyperChlgText + 6, 2);
RTMPEncryptData(pAd, (PUCHAR) &RemoteStatus, CyperChlgText + 8, 2);
Element[0] = 16;
Element[1] = 128;
RTMPEncryptData(pAd, Element, CyperChlgText + 10, 2);
RTMPEncryptData(pAd, ChlgText, CyperChlgText + 12, 128);
RTMPSetICV(pAd, CyperChlgText + 140);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11), &AuthHdr,
CIPHER_TEXT_LEN + 16, CyperChlgText,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
RTMPSetTimer(&pAd->MlmeAux.AuthTimer, AUTH_TIMEOUT);
pAd->Mlme.AuthMachine.CurrState = AUTH_WAIT_SEQ4;
}
}
else
{
pAd->StaCfg.AuthFailReason = Status;
COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2);
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
}
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthSanity() sanity check fail\n"));
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerAuthRspAtSeq4Action(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Addr2[MAC_ADDR_LEN];
USHORT Alg, Seq, Status;
CHAR ChlgText[CIPHER_TEXT_LEN];
BOOLEAN TimerCancelled;
if(PeerAuthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Alg, &Seq, &Status, ChlgText))
{
if(MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Addr2) && Seq == 4)
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Receive AUTH_RSP seq#4 to me\n"));
RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &TimerCancelled);
if (Status != MLME_SUCCESS)
{
pAd->StaCfg.AuthFailReason = Status;
COPY_MAC_ADDR(pAd->StaCfg.AuthFailSta, Addr2);
}
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - PeerAuthRspAtSeq4Action() sanity check fail\n"));
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID MlmeDeauthReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
MLME_DEAUTH_REQ_STRUCT *pInfo;
HEADER_802_11 DeauthHdr;
PUCHAR pOutBuffer = NULL;
NDIS_STATUS NStatus;
ULONG FrameLen = 0;
USHORT Status;
pInfo = (MLME_DEAUTH_REQ_STRUCT *)Elem->Msg;
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if (NStatus != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - MlmeDeauthReqAction() allocate memory fail\n"));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_FAIL_NO_RESOURCE;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status);
return;
}
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Send DE-AUTH request (Reason=%d)...\n", pInfo->Reason));
MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pInfo->Addr, pAd->MlmeAux.Bssid);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11),&DeauthHdr,
2, &pInfo->Reason,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
pAd->StaCfg.DeauthReason = pInfo->Reason;
COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pInfo->Addr);
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_SUCCESS;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_DEAUTH_CONF, 2, &Status);
// send wireless event - for deauthentication
if (pAd->CommonCfg.bWirelessEvent)
RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID AuthTimeoutAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - AuthTimeoutAction\n"));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_REJ_TIMEOUT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID InvalidStateWhenAuth(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - InvalidStateWhenAuth (state=%ld), reset AUTH state machine\n", pAd->Mlme.AuthMachine.CurrState));
pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_AUTH_CONF, 2, &Status);
}
/*
==========================================================================
Description:
Some STA/AP
Note:
This action should never trigger AUTH state transition, therefore we
separate it from AUTH state machine, and make it as a standalone service
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID Cls2errAction(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pAddr)
{
HEADER_802_11 DeauthHdr;
PUCHAR pOutBuffer = NULL;
NDIS_STATUS NStatus;
ULONG FrameLen = 0;
USHORT Reason = REASON_CLS2ERR;
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if (NStatus != NDIS_STATUS_SUCCESS)
return;
DBGPRINT(RT_DEBUG_TRACE, ("AUTH - Class 2 error, Send DEAUTH frame...\n"));
MgtMacHeaderInit(pAd, &DeauthHdr, SUBTYPE_DEAUTH, 0, pAddr, pAd->MlmeAux.Bssid);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11),&DeauthHdr,
2, &Reason,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
pAd->StaCfg.DeauthReason = Reason;
COPY_MAC_ADDR(pAd->StaCfg.DeauthSta, pAddr);
}
/* #include "../../rt2860/sta/auth_rsp.c"
*************************************************************************
* 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:
auth_rsp.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John 2004-10-1 copy from RT2560
*/
#include "../rt_config.h"
/*
==========================================================================
Description:
authentication state machine init procedure
Parameters:
Sm - the state machine
IRQL = PASSIVE_LEVEL
==========================================================================
*/
VOID AuthRspStateMachineInit(
IN PRTMP_ADAPTER pAd,
IN PSTATE_MACHINE Sm,
IN STATE_MACHINE_FUNC Trans[])
{
StateMachineInit(Sm, Trans, MAX_AUTH_RSP_STATE, MAX_AUTH_RSP_MSG, (STATE_MACHINE_FUNC)Drop, AUTH_RSP_IDLE, AUTH_RSP_MACHINE_BASE);
// column 1
StateMachineSetAction(Sm, AUTH_RSP_IDLE, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction);
// column 2
StateMachineSetAction(Sm, AUTH_RSP_WAIT_CHAL, MT2_PEER_DEAUTH, (STATE_MACHINE_FUNC)PeerDeauthAction);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerAuthSimpleRspGenAndSend(
IN PRTMP_ADAPTER pAd,
IN PHEADER_802_11 pHdr80211,
IN USHORT Alg,
IN USHORT Seq,
IN USHORT Reason,
IN USHORT Status)
{
HEADER_802_11 AuthHdr;
ULONG FrameLen = 0;
PUCHAR pOutBuffer = NULL;
NDIS_STATUS NStatus;
if (Reason != MLME_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("Peer AUTH fail...\n"));
return;
}
//Get an unused nonpaged memory
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if (NStatus != NDIS_STATUS_SUCCESS)
return;
DBGPRINT(RT_DEBUG_TRACE, ("Send AUTH response (seq#2)...\n"));
MgtMacHeaderInit(pAd, &AuthHdr, SUBTYPE_AUTH, 0, pHdr80211->Addr2, pAd->MlmeAux.Bssid);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11), &AuthHdr,
2, &Alg,
2, &Seq,
2, &Reason,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerDeauthAction(
IN PRTMP_ADAPTER pAd,
IN PMLME_QUEUE_ELEM Elem)
{
UCHAR Addr2[MAC_ADDR_LEN];
USHORT Reason;
if (PeerDeauthSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, &Reason))
{
if (INFRA_ON(pAd) && MAC_ADDR_EQUAL(Addr2, pAd->CommonCfg.Bssid))
{
DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - receive DE-AUTH from our AP (Reason=%d)\n", Reason));
{
union iwreq_data wrqu;
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
// send wireless event - for deauthentication
if (pAd->CommonCfg.bWirelessEvent)
RTMPSendWirelessEvent(pAd, IW_DEAUTH_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
LinkDown(pAd, TRUE);
}
}
else
{
DBGPRINT(RT_DEBUG_TRACE,("AUTH_RSP - PeerDeauthAction() sanity check fail\n"));
}
}
/* #include "../../rt2860/sta/connect.c"
*************************************************************************
* 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:
connect.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John 2004-08-08 Major modification from RT2560
*/
#include "../rt_config.h"
UCHAR CipherSuiteWpaNoneTkip[] = {
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x50, 0xf2, 0x02, // Multicast
0x01, 0x00, // Number of unicast
0x00, 0x50, 0xf2, 0x02, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x50, 0xf2, 0x00 // authentication
};
UCHAR CipherSuiteWpaNoneTkipLen = (sizeof(CipherSuiteWpaNoneTkip) / sizeof(UCHAR));
UCHAR CipherSuiteWpaNoneAes[] = {
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x50, 0xf2, 0x04, // Multicast
0x01, 0x00, // Number of unicast
0x00, 0x50, 0xf2, 0x04, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x50, 0xf2, 0x00 // authentication
};
UCHAR CipherSuiteWpaNoneAesLen = (sizeof(CipherSuiteWpaNoneAes) / sizeof(UCHAR));
// The following MACRO is called after 1. starting an new IBSS, 2. succesfully JOIN an IBSS,
// or 3. succesfully ASSOCIATE to a BSS, 4. successfully RE_ASSOCIATE to a BSS
// All settings successfuly negotiated furing MLME state machines become final settings
// and are copied to pAd->StaActive
#define COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(_pAd) \
{ \
(_pAd)->CommonCfg.SsidLen = (_pAd)->MlmeAux.SsidLen; \
NdisMoveMemory((_pAd)->CommonCfg.Ssid, (_pAd)->MlmeAux.Ssid, (_pAd)->MlmeAux.SsidLen); \
COPY_MAC_ADDR((_pAd)->CommonCfg.Bssid, (_pAd)->MlmeAux.Bssid); \
(_pAd)->CommonCfg.Channel = (_pAd)->MlmeAux.Channel; \
(_pAd)->CommonCfg.CentralChannel = (_pAd)->MlmeAux.CentralChannel; \
(_pAd)->StaActive.Aid = (_pAd)->MlmeAux.Aid; \
(_pAd)->StaActive.AtimWin = (_pAd)->MlmeAux.AtimWin; \
(_pAd)->StaActive.CapabilityInfo = (_pAd)->MlmeAux.CapabilityInfo; \
(_pAd)->CommonCfg.BeaconPeriod = (_pAd)->MlmeAux.BeaconPeriod; \
(_pAd)->StaActive.CfpMaxDuration = (_pAd)->MlmeAux.CfpMaxDuration; \
(_pAd)->StaActive.CfpPeriod = (_pAd)->MlmeAux.CfpPeriod; \
(_pAd)->StaActive.SupRateLen = (_pAd)->MlmeAux.SupRateLen; \
NdisMoveMemory((_pAd)->StaActive.SupRate, (_pAd)->MlmeAux.SupRate, (_pAd)->MlmeAux.SupRateLen);\
(_pAd)->StaActive.ExtRateLen = (_pAd)->MlmeAux.ExtRateLen; \
NdisMoveMemory((_pAd)->StaActive.ExtRate, (_pAd)->MlmeAux.ExtRate, (_pAd)->MlmeAux.ExtRateLen);\
NdisMoveMemory(&(_pAd)->CommonCfg.APEdcaParm, &(_pAd)->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));\
NdisMoveMemory(&(_pAd)->CommonCfg.APQosCapability, &(_pAd)->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));\
NdisMoveMemory(&(_pAd)->CommonCfg.APQbssLoad, &(_pAd)->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));\
COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].Addr, (_pAd)->MlmeAux.Bssid); \
(_pAd)->MacTab.Content[BSSID_WCID].Aid = (_pAd)->MlmeAux.Aid; \
(_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.CipherAlg = (_pAd)->StaCfg.PairCipher;\
COPY_MAC_ADDR((_pAd)->MacTab.Content[BSSID_WCID].PairwiseKey.BssId, (_pAd)->MlmeAux.Bssid);\
(_pAd)->MacTab.Content[BSSID_WCID].RateLen = (_pAd)->StaActive.SupRateLen + (_pAd)->StaActive.ExtRateLen;\
}
/*
==========================================================================
Description:
IRQL = PASSIVE_LEVEL
==========================================================================
*/
VOID MlmeCntlInit(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *S,
OUT STATE_MACHINE_FUNC Trans[])
{
// Control state machine differs from other state machines, the interface
// follows the standard interface
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID MlmeCntlMachinePerformAction(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *S,
IN MLME_QUEUE_ELEM *Elem)
{
switch(pAd->Mlme.CntlMachine.CurrState)
{
case CNTL_IDLE:
CntlIdleProc(pAd, Elem);
break;
case CNTL_WAIT_DISASSOC:
CntlWaitDisassocProc(pAd, Elem);
break;
case CNTL_WAIT_JOIN:
CntlWaitJoinProc(pAd, Elem);
break;
// CNTL_WAIT_REASSOC is the only state in CNTL machine that does
// not triggered directly or indirectly by "RTMPSetInformation(OID_xxx)".
// Therefore not protected by NDIS's "only one outstanding OID request"
// rule. Which means NDIS may SET OID in the middle of ROAMing attempts.
// Current approach is to block new SET request at RTMPSetInformation()
// when CntlMachine.CurrState is not CNTL_IDLE
case CNTL_WAIT_REASSOC:
CntlWaitReassocProc(pAd, Elem);
break;
case CNTL_WAIT_START:
CntlWaitStartProc(pAd, Elem);
break;
case CNTL_WAIT_AUTH:
CntlWaitAuthProc(pAd, Elem);
break;
case CNTL_WAIT_AUTH2:
CntlWaitAuthProc2(pAd, Elem);
break;
case CNTL_WAIT_ASSOC:
CntlWaitAssocProc(pAd, Elem);
break;
case CNTL_WAIT_OID_LIST_SCAN:
if(Elem->MsgType == MT2_SCAN_CONF)
{
// Resume TxRing after SCANING complete. We hope the out-of-service time
// won't be too long to let upper layer time-out the waiting frames
RTMPResumeMsduTransmission(pAd);
if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED)
{
// Cisco scan request is finished, prepare beacon report
MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL);
}
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
//
// Set LED status to previous status.
//
if (pAd->bLedOnScanning)
{
pAd->bLedOnScanning = FALSE;
RTMPSetLED(pAd, pAd->LedStatus);
}
}
break;
case CNTL_WAIT_OID_DISASSOC:
if (Elem->MsgType == MT2_DISASSOC_CONF)
{
LinkDown(pAd, FALSE);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
}
break;
#ifdef RT2870
//
// This state is for that we want to connect to an AP but
// it didn't find on BSS List table. So we need to scan the air first,
// after that we can try to connect to the desired AP if available.
//
case CNTL_WAIT_SCAN_FOR_CONNECT:
if(Elem->MsgType == MT2_SCAN_CONF)
{
// Resume TxRing after SCANING complete. We hope the out-of-service time
// won't be too long to let upper layer time-out the waiting frames
RTMPResumeMsduTransmission(pAd);
#ifdef CCX_SUPPORT
if (pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED)
{
// Cisco scan request is finished, prepare beacon report
MlmeEnqueue(pAd, AIRONET_STATE_MACHINE, MT2_AIRONET_SCAN_DONE, 0, NULL);
}
#endif // CCX_SUPPORT //
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
//
// Check if we can connect to.
//
BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen);
if (pAd->MlmeAux.SsidBssTab.BssNr > 0)
{
MlmeAutoReconnectLastSSID(pAd);
}
}
break;
#endif // RT2870 //
default:
DBGPRINT_ERR(("!ERROR! CNTL - Illegal message type(=%ld)", Elem->MsgType));
break;
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlIdleProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
MLME_DISASSOC_REQ_STRUCT DisassocReq;
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
return;
switch(Elem->MsgType)
{
case OID_802_11_SSID:
CntlOidSsidProc(pAd, Elem);
break;
case OID_802_11_BSSID:
CntlOidRTBssidProc(pAd,Elem);
break;
case OID_802_11_BSSID_LIST_SCAN:
CntlOidScanProc(pAd,Elem);
break;
case OID_802_11_DISASSOCIATE:
DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_DISASSOC;
if (pAd->StaCfg.WpaSupplicantUP != WPA_SUPPLICANT_ENABLE_WITH_WEB_UI)
{
// Set the AutoReconnectSsid to prevent it reconnect to old SSID
// Since calling this indicate user don't want to connect to that SSID anymore.
pAd->MlmeAux.AutoReconnectSsidLen= 32;
NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen);
}
break;
case MT2_MLME_ROAMING_REQ:
CntlMlmeRoamingProc(pAd, Elem);
break;
case OID_802_11_MIC_FAILURE_REPORT_FRAME:
WpaMicFailureReportFrame(pAd, Elem);
break;
default:
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Illegal message in CntlIdleProc(MsgType=%ld)\n",Elem->MsgType));
break;
}
}
VOID CntlOidScanProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
MLME_SCAN_REQ_STRUCT ScanReq;
ULONG BssIdx = BSS_NOT_FOUND;
BSS_ENTRY CurrBss;
// record current BSS if network is connected.
// 2003-2-13 do not include current IBSS if this is the only STA in this IBSS.
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
{
BssIdx = BssSsidTableSearch(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->CommonCfg.Channel);
if (BssIdx != BSS_NOT_FOUND)
{
NdisMoveMemory(&CurrBss, &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY));
}
}
// clean up previous SCAN result, add current BSS back to table if any
BssTableInit(&pAd->ScanTab);
if (BssIdx != BSS_NOT_FOUND)
{
// DDK Note: If the NIC is associated with a particular BSSID and SSID
// that are not contained in the list of BSSIDs generated by this scan, the
// BSSID description of the currently associated BSSID and SSID should be
// appended to the list of BSSIDs in the NIC's database.
// To ensure this, we append this BSS as the first entry in SCAN result
NdisMoveMemory(&pAd->ScanTab.BssEntry[0], &CurrBss, sizeof(BSS_ENTRY));
pAd->ScanTab.BssNr = 1;
}
ScanParmFill(pAd, &ScanReq, "", 0, BSS_ANY, SCAN_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;
}
/*
==========================================================================
Description:
Before calling this routine, user desired SSID should already been
recorded in CommonCfg.Ssid[]
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlOidSsidProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM * Elem)
{
PNDIS_802_11_SSID pOidSsid = (NDIS_802_11_SSID *)Elem->Msg;
MLME_DISASSOC_REQ_STRUCT DisassocReq;
ULONG Now;
// Step 1. record the desired user settings to MlmeAux
NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID);
NdisMoveMemory(pAd->MlmeAux.Ssid, pOidSsid->Ssid, pOidSsid->SsidLength);
pAd->MlmeAux.SsidLen = (UCHAR)pOidSsid->SsidLength;
NdisZeroMemory(pAd->MlmeAux.Bssid, MAC_ADDR_LEN);
pAd->MlmeAux.BssType = pAd->StaCfg.BssType;
//
// Update Reconnect Ssid, that user desired to connect.
//
NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID);
NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen);
pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen;
// step 2. find all matching BSS in the lastest SCAN result (inBssTab)
// & log them into MlmeAux.SsidBssTab for later-on iteration. Sort by RSSI order
BssTableSsidSort(pAd, &pAd->MlmeAux.SsidBssTab, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen);
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - %d BSS of %d BSS match the desire (%d)SSID - %s\n",
pAd->MlmeAux.SsidBssTab.BssNr, pAd->ScanTab.BssNr, pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid));
NdisGetSystemUpTime(&Now);
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) &&
(pAd->CommonCfg.SsidLen == pAd->MlmeAux.SsidBssTab.BssEntry[0].SsidLen) &&
NdisEqualMemory(pAd->CommonCfg.Ssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Ssid, pAd->CommonCfg.SsidLen) &&
MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pAd->MlmeAux.SsidBssTab.BssEntry[0].Bssid))
{
// Case 1. already connected with an AP who has the desired SSID
// with highest RSSI
// Add checking Mode "LEAP" for CCX 1.0
if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
) &&
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED))
{
// case 1.1 For WPA, WPA-PSK, if the 1x port is not secured, we have to redo
// connection process
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n"));
DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ,
sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
}
else if (pAd->bConfigChanged == TRUE)
{
// case 1.2 Important Config has changed, we have to reconnect to the same AP
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP Because config changed...\n"));
DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ,
sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
}
else
{
// case 1.3. already connected to the SSID with highest RSSI.
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - already with this BSSID. ignore this SET_SSID request\n"));
//
// (HCT 12.1) 1c_wlan_mediaevents required
// media connect events are indicated when associating with the same AP
//
if (INFRA_ON(pAd))
{
//
// Since MediaState already is NdisMediaStateConnected
// We just indicate the connect event again to meet the WHQL required.
//
pAd->IndicateMediaState = NdisMediaStateConnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up
}
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
{
union iwreq_data wrqu;
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
}
}
else if (INFRA_ON(pAd))
{
//
// For RT61
// [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: )
// RT61 may lost SSID, and not connect to NDTEST_WEP_AP2 and will connect to NDTEST_WEP_AP2 by Autoreconnect
// But media status is connected, so the SSID not report correctly.
//
if (!SSID_EQUAL(pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen))
{
//
// Different SSID means not Roaming case, so we let LinkDown() to Indicate a disconnect event.
//
pAd->MlmeAux.CurrReqIsFromNdis = TRUE;
}
// case 2. active INFRA association existent
// roaming is done within miniport driver, nothing to do with configuration
// utility. so upon a new SET(OID_802_11_SSID) is received, we just
// disassociate with the current associated AP,
// then perform a new association with this new SSID, no matter the
// new/old SSID are the same or not.
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - disassociate with current AP...\n"));
DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ,
sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
}
else
{
if (ADHOC_ON(pAd))
{
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - drop current ADHOC\n"));
LinkDown(pAd, FALSE);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED);
pAd->IndicateMediaState = NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_DOWN;
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():NDIS_STATUS_MEDIA_DISCONNECT Event C!\n"));
}
if ((pAd->MlmeAux.SsidBssTab.BssNr == 0) &&
(pAd->StaCfg.bAutoReconnect == TRUE) &&
(pAd->MlmeAux.BssType == BSS_INFRA) &&
(MlmeValidateSSID(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen) == TRUE)
)
{
MLME_SCAN_REQ_STRUCT ScanReq;
DBGPRINT(RT_DEBUG_TRACE, ("CntlOidSsidProc():CNTL - No matching BSS, start a new scan\n"));
ScanParmFill(pAd, &ScanReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, BSS_ANY, SCAN_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 Missed scan number
pAd->StaCfg.LastScanTime = Now;
}
else
{
pAd->MlmeAux.BssIdx = 0;
IterateOnBssTab(pAd);
}
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlOidRTBssidProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM * Elem)
{
ULONG BssIdx;
PUCHAR pOidBssid = (PUCHAR)Elem->Msg;
MLME_DISASSOC_REQ_STRUCT DisassocReq;
MLME_JOIN_REQ_STRUCT JoinReq;
// record user desired settings
COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pOidBssid);
pAd->MlmeAux.BssType = pAd->StaCfg.BssType;
//
// Update Reconnect Ssid, that user desired to connect.
//
NdisZeroMemory(pAd->MlmeAux.AutoReconnectSsid, MAX_LEN_OF_SSID);
pAd->MlmeAux.AutoReconnectSsidLen = pAd->MlmeAux.SsidLen;
NdisMoveMemory(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen);
// find the desired BSS in the latest SCAN result table
BssIdx = BssTableSearch(&pAd->ScanTab, pOidBssid, pAd->MlmeAux.Channel);
if (BssIdx == BSS_NOT_FOUND)
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - BSSID not found. reply NDIS_STATUS_NOT_ACCEPTED\n"));
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
return;
}
// copy the matched BSS entry from ScanTab to MlmeAux.SsidBssTab. Why?
// Because we need this entry to become the JOIN target in later on SYNC state machine
pAd->MlmeAux.BssIdx = 0;
pAd->MlmeAux.SsidBssTab.BssNr = 1;
NdisMoveMemory(&pAd->MlmeAux.SsidBssTab.BssEntry[0], &pAd->ScanTab.BssEntry[BssIdx], sizeof(BSS_ENTRY));
// 2002-11-26 skip the following checking. i.e. if user wants to re-connect to same AP
// we just follow normal procedure. The reason of user doing this may because he/she changed
// AP to another channel, but we still received BEACON from it thus don't claim Link Down.
// Since user knows he's changed AP channel, he'll re-connect again. By skipping the following
// checking, we'll disassociate then re-do normal association with this AP at the new channel.
// 2003-1-6 Re-enable this feature based on microsoft requirement which prefer not to re-do
// connection when setting the same BSSID.
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) &&
MAC_ADDR_EQUAL(pAd->CommonCfg.Bssid, pOidBssid))
{
// already connected to the same BSSID, go back to idle state directly
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - already in this BSSID. ignore this SET_BSSID request\n"));
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
{
union iwreq_data wrqu;
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
memcpy(wrqu.ap_addr.sa_data, pAd->MlmeAux.Bssid, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
}
else
{
if (INFRA_ON(pAd))
{
// disassoc from current AP first
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - disassociate with current AP ...\n"));
DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ,
sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
}
else
{
if (ADHOC_ON(pAd))
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - drop current ADHOC\n"));
LinkDown(pAd, FALSE);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED);
pAd->IndicateMediaState = NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_DOWN;
DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event C!\n"));
}
// Change the wepstatus to original wepstatus
pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus;
pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus;
pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus;
// Check cipher suite, AP must have more secured cipher than station setting
// Set the Pairwise and Group cipher to match the intended AP setting
// We can only connect to AP with less secured cipher setting
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
{
pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.GroupCipher;
if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher)
pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipher;
else if (pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled)
pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA.PairCipherAux;
else // There is no PairCipher Aux, downgrade our capability to TKIP
pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled;
}
else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
{
pAd->StaCfg.GroupCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.GroupCipher;
if (pAd->StaCfg.WepStatus == pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher)
pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipher;
else if (pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled)
pAd->StaCfg.PairCipher = pAd->ScanTab.BssEntry[BssIdx].WPA2.PairCipherAux;
else // There is no PairCipher Aux, downgrade our capability to TKIP
pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled;
// RSN capability
pAd->StaCfg.RsnCapability = pAd->ScanTab.BssEntry[BssIdx].WPA2.RsnCapability;
}
// Set Mix cipher flag
pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE;
if (pAd->StaCfg.bMixCipher == TRUE)
{
// If mix cipher, re-build RSNIE
RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0);
}
// No active association, join the BSS immediately
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - joining %02x:%02x:%02x:%02x:%02x:%02x ...\n",
pOidBssid[0],pOidBssid[1],pOidBssid[2],pOidBssid[3],pOidBssid[4],pOidBssid[5]));
JoinParmFill(pAd, &JoinReq, pAd->MlmeAux.BssIdx);
MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT), &JoinReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN;
}
}
}
// Roaming is the only external request triggering CNTL state machine
// despite of other "SET OID" operation. All "SET OID" related oerations
// happen in sequence, because no other SET OID will be sent to this device
// until the the previous SET operation is complete (successful o failed).
// So, how do we quarantee this ROAMING request won't corrupt other "SET OID"?
// or been corrupted by other "SET OID"?
//
// IRQL = DISPATCH_LEVEL
VOID CntlMlmeRoamingProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
// TODO:
// AP in different channel may show lower RSSI than actual value??
// should we add a weighting factor to compensate it?
DBGPRINT(RT_DEBUG_TRACE,("CNTL - Roaming in MlmeAux.RoamTab...\n"));
NdisMoveMemory(&pAd->MlmeAux.SsidBssTab, &pAd->MlmeAux.RoamTab, sizeof(pAd->MlmeAux.RoamTab));
pAd->MlmeAux.SsidBssTab.BssNr = pAd->MlmeAux.RoamTab.BssNr;
BssTableSortByRssi(&pAd->MlmeAux.SsidBssTab);
pAd->MlmeAux.BssIdx = 0;
IterateOnBssTab(pAd);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlWaitDisassocProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
MLME_START_REQ_STRUCT StartReq;
if (Elem->MsgType == MT2_DISASSOC_CONF)
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Dis-associate successful\n"));
if (pAd->CommonCfg.bWirelessEvent)
{
RTMPSendWirelessEvent(pAd, IW_DISASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
}
LinkDown(pAd, FALSE);
// case 1. no matching BSS, and user wants ADHOC, so we just start a new one
if ((pAd->MlmeAux.SsidBssTab.BssNr==0) && (pAd->StaCfg.BssType == BSS_ADHOC))
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - No matching BSS, start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid));
StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen);
MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
}
// case 2. try each matched BSS
else
{
pAd->MlmeAux.BssIdx = 0;
IterateOnBssTab(pAd);
}
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlWaitJoinProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Reason;
MLME_AUTH_REQ_STRUCT AuthReq;
if (Elem->MsgType == MT2_JOIN_CONF)
{
NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
if (Reason == MLME_SUCCESS)
{
// 1. joined an IBSS, we are pretty much done here
if (pAd->MlmeAux.BssType == BSS_ADHOC)
{
//
// 5G bands rules of Japan:
// Ad hoc must be disabled in W53(ch52,56,60,64) channels.
//
if ( (pAd->CommonCfg.bIEEE80211H == 1) &&
RadarChannelCheck(pAd, pAd->CommonCfg.Channel)
)
{
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Join adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel));
return;
}
LinkUp(pAd, BSS_ADHOC);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - join the IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n",
pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2],
pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5]));
pAd->IndicateMediaState = NdisMediaStateConnected;
pAd->ExtraInfo = GENERAL_LINK_UP;
}
// 2. joined a new INFRA network, start from authentication
else
{
{
// either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch))
{
AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared);
}
else
{
AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen);
}
}
MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ,
sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH;
}
}
else
{
// 3. failed, try next BSS
pAd->MlmeAux.BssIdx++;
IterateOnBssTab(pAd);
}
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlWaitStartProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Result;
if (Elem->MsgType == MT2_START_CONF)
{
NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT));
if (Result == MLME_SUCCESS)
{
//
// 5G bands rules of Japan:
// Ad hoc must be disabled in W53(ch52,56,60,64) channels.
//
if ( (pAd->CommonCfg.bIEEE80211H == 1) &&
RadarChannelCheck(pAd, pAd->CommonCfg.Channel)
)
{
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Channel=%d, Start adhoc on W53(52,56,60,64) Channels are not accepted\n", pAd->CommonCfg.Channel));
return;
}
if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)
{
N_ChannelCheck(pAd);
SetCommonHT(pAd);
NdisMoveMemory(&pAd->MlmeAux.AddHtInfo, &pAd->CommonCfg.AddHTInfo, sizeof(ADD_HT_INFO_IE));
RTMPCheckHt(pAd, BSSID_WCID, &pAd->CommonCfg.HtCapability, &pAd->CommonCfg.AddHTInfo);
pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE;
NdisZeroMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], 16);
NdisMoveMemory(&pAd->StaActive.SupportedPhyInfo.MCSSet[0], &pAd->CommonCfg.HtCapability.MCSSet[0], 16);
COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd);
if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) &&
(pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE))
{
pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel + 2;
}
else if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) &&
(pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW))
{
pAd->MlmeAux.CentralChannel = pAd->CommonCfg.Channel - 2;
}
}
else
{
pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE;
}
LinkUp(pAd, BSS_ADHOC);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
// Before send beacon, driver need do radar detection
if ((pAd->CommonCfg.Channel > 14 )
&& (pAd->CommonCfg.bIEEE80211H == 1)
&& RadarChannelCheck(pAd, pAd->CommonCfg.Channel))
{
pAd->CommonCfg.RadarDetect.RDMode = RD_SILENCE_MODE;
pAd->CommonCfg.RadarDetect.RDCount = 0;
}
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - start a new IBSS = %02x:%02x:%02x:%02x:%02x:%02x ...\n",
pAd->CommonCfg.Bssid[0],pAd->CommonCfg.Bssid[1],pAd->CommonCfg.Bssid[2],
pAd->CommonCfg.Bssid[3],pAd->CommonCfg.Bssid[4],pAd->CommonCfg.Bssid[5]));
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Start IBSS fail. BUG!!!!!\n"));
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
}
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlWaitAuthProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Reason;
MLME_ASSOC_REQ_STRUCT AssocReq;
MLME_AUTH_REQ_STRUCT AuthReq;
if (Elem->MsgType == MT2_AUTH_CONF)
{
NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
if (Reason == MLME_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n"));
AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo,
ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount);
{
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ,
sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC;
}
}
else
{
// This fail may because of the AP already keep us in its MAC table without
// ageing-out. The previous authentication attempt must have let it remove us.
// so try Authentication again may help. For D-Link DWL-900AP+ compatibility.
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try again...\n"));
{
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeShared) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch))
{
// either Ndis802_11AuthModeShared or Ndis802_11AuthModeAutoSwitch, try shared key first
AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeShared);
}
else
{
AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen);
}
}
MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ,
sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2;
}
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlWaitAuthProc2(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Reason;
MLME_ASSOC_REQ_STRUCT AssocReq;
MLME_AUTH_REQ_STRUCT AuthReq;
if (Elem->MsgType == MT2_AUTH_CONF)
{
NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
if (Reason == MLME_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH OK\n"));
AssocParmFill(pAd, &AssocReq, pAd->MlmeAux.Bssid, pAd->MlmeAux.CapabilityInfo,
ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_ASSOC_REQ,
sizeof(MLME_ASSOC_REQ_STRUCT), &AssocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_ASSOC;
}
else
{
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeAutoSwitch) &&
(pAd->MlmeAux.Alg == Ndis802_11AuthModeShared))
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, try OPEN system...\n"));
AuthParmFill(pAd, &AuthReq, pAd->MlmeAux.Bssid, Ndis802_11AuthModeOpen);
MlmeEnqueue(pAd, AUTH_STATE_MACHINE, MT2_MLME_AUTH_REQ,
sizeof(MLME_AUTH_REQ_STRUCT), &AuthReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_AUTH2;
}
else
{
// not success, try next BSS
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - AUTH FAIL, give up; try next BSS\n"));
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; //???????
pAd->MlmeAux.BssIdx++;
IterateOnBssTab(pAd);
}
}
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlWaitAssocProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Reason;
if (Elem->MsgType == MT2_ASSOC_CONF)
{
NdisMoveMemory(&Reason, Elem->Msg, sizeof(USHORT));
if (Reason == MLME_SUCCESS)
{
LinkUp(pAd, BSS_INFRA);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association successful on BSS #%ld\n",pAd->MlmeAux.BssIdx));
if (pAd->CommonCfg.bWirelessEvent)
{
RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
}
}
else
{
// not success, try next BSS
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Association fails on BSS #%ld\n",pAd->MlmeAux.BssIdx));
pAd->MlmeAux.BssIdx++;
IterateOnBssTab(pAd);
}
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID CntlWaitReassocProc(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Result;
if (Elem->MsgType == MT2_REASSOC_CONF)
{
NdisMoveMemory(&Result, Elem->Msg, sizeof(USHORT));
if (Result == MLME_SUCCESS)
{
//
// NDIS requires a new Link UP indication but no Link Down for RE-ASSOC
//
LinkUp(pAd, BSS_INFRA);
// send wireless event - for association
if (pAd->CommonCfg.bWirelessEvent)
RTMPSendWirelessEvent(pAd, IW_ASSOC_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition successful on BSS #%ld\n", pAd->MlmeAux.RoamIdx));
}
else
{
// reassoc failed, try to pick next BSS in the BSS Table
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - Re-assocition fails on BSS #%ld\n", pAd->MlmeAux.RoamIdx));
pAd->MlmeAux.RoamIdx++;
IterateOnBssTab2(pAd);
}
}
}
VOID AdhocTurnOnQos(
IN PRTMP_ADAPTER pAd)
{
#define AC0_DEF_TXOP 0
#define AC1_DEF_TXOP 0
#define AC2_DEF_TXOP 94
#define AC3_DEF_TXOP 47
// Turn on QOs if use HT rate.
if (pAd->CommonCfg.APEdcaParm.bValid == FALSE)
{
pAd->CommonCfg.APEdcaParm.bValid = TRUE;
pAd->CommonCfg.APEdcaParm.Aifsn[0] = 3;
pAd->CommonCfg.APEdcaParm.Aifsn[1] = 7;
pAd->CommonCfg.APEdcaParm.Aifsn[2] = 1;
pAd->CommonCfg.APEdcaParm.Aifsn[3] = 1;
pAd->CommonCfg.APEdcaParm.Cwmin[0] = 4;
pAd->CommonCfg.APEdcaParm.Cwmin[1] = 4;
pAd->CommonCfg.APEdcaParm.Cwmin[2] = 3;
pAd->CommonCfg.APEdcaParm.Cwmin[3] = 2;
pAd->CommonCfg.APEdcaParm.Cwmax[0] = 10;
pAd->CommonCfg.APEdcaParm.Cwmax[1] = 6;
pAd->CommonCfg.APEdcaParm.Cwmax[2] = 4;
pAd->CommonCfg.APEdcaParm.Cwmax[3] = 3;
pAd->CommonCfg.APEdcaParm.Txop[0] = 0;
pAd->CommonCfg.APEdcaParm.Txop[1] = 0;
pAd->CommonCfg.APEdcaParm.Txop[2] = AC2_DEF_TXOP;
pAd->CommonCfg.APEdcaParm.Txop[3] = AC3_DEF_TXOP;
}
AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID LinkUp(
IN PRTMP_ADAPTER pAd,
IN UCHAR BssType)
{
ULONG Now;
UINT32 Data;
BOOLEAN Cancelled;
UCHAR Value = 0, idx;
MAC_TABLE_ENTRY *pEntry = NULL, *pCurrEntry;
pEntry = &pAd->MacTab.Content[BSSID_WCID];
//
// ASSOC - DisassocTimeoutAction
// CNTL - Dis-associate successful
// !!! LINK DOWN !!!
// [88888] OID_802_11_SSID should have returned NDTEST_WEP_AP2(Returned: )
//
// To prevent DisassocTimeoutAction to call Link down after we link up,
// cancel the DisassocTimer no matter what it start or not.
//
RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled);
COPY_SETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd);
COPY_HTSETTINGS_FROM_MLME_AUX_TO_ACTIVE_CFG(pAd);
// It's quite difficult to tell if a newly added KEY is WEP or CKIP until a new BSS
// is formed (either ASSOC/RE-ASSOC done or IBSS started. LinkUP should be a safe place
// to examine if cipher algorithm switching is required.
//rt2860b. Don't know why need this
SwitchBetweenWepAndCkip(pAd);
if (BssType == BSS_ADHOC)
{
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADHOC_ON);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON);
#ifdef RT30xx
if ((pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) &&
(pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE))
{
pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel + 2;
}
else if ((pAd->CommonCfg.Channel > 2) &&
(pAd->CommonCfg.HtCapability.HtCapInfo.ChannelWidth == BW_40) &&
(pAd->CommonCfg.AddHTInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW))
{
pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel - 2;
}
#endif
if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)
AdhocTurnOnQos(pAd);
DBGPRINT(RT_DEBUG_TRACE, ("!!!Adhoc LINK UP !!! \n" ));
}
else
{
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_INFRA_ON);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON);
DBGPRINT(RT_DEBUG_TRACE, ("!!!Infra LINK UP !!! \n" ));
}
// 3*3
// reset Tx beamforming bit
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value);
Value &= (~0x01);
Value |= pAd->CommonCfg.RegTransmitSetting.field.TxBF;
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value);
// Change to AP channel
if ((pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
// Must using 40MHz.
pAd->CommonCfg.BBPCurrentBW = BW_40;
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value);
Value &= (~0x18);
Value |= 0x10;
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value);
// RX : control channel at lower
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value);
Value &= (~0x20);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value);
RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data);
Data &= 0xfffffffe;
RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data);
if (pAd->MACVersion == 0x28600100)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16);
DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" ));
}
DBGPRINT(RT_DEBUG_TRACE, ("!!!40MHz Lower LINK UP !!! Control Channel at Below. Central = %d \n", pAd->CommonCfg.CentralChannel ));
}
else if ((pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
// Must using 40MHz.
pAd->CommonCfg.BBPCurrentBW = BW_40;
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value);
Value &= (~0x18);
Value |= 0x10;
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value);
RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data);
Data |= 0x1;
RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data);
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value);
Value |= (0x20);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value);
if (pAd->MACVersion == 0x28600100)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x1A);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x0A);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x16);
DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" ));
}
DBGPRINT(RT_DEBUG_TRACE, ("!!! 40MHz Upper LINK UP !!! Control Channel at UpperCentral = %d \n", pAd->CommonCfg.CentralChannel ));
}
else
{
pAd->CommonCfg.BBPCurrentBW = BW_20;
pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel;
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &Value);
Value &= (~0x18);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, Value);
RTMP_IO_READ32(pAd, TX_BAND_CFG, &Data);
Data &= 0xfffffffe;
RTMP_IO_WRITE32(pAd, TX_BAND_CFG, Data);
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &Value);
Value &= (~0x20);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, Value);
if (pAd->MACVersion == 0x28600100)
{
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R69, 0x16);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R70, 0x08);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R73, 0x11);
DBGPRINT(RT_DEBUG_TRACE, ("!!!rt2860C !!! \n" ));
}
DBGPRINT(RT_DEBUG_TRACE, ("!!! 20MHz LINK UP !!! \n" ));
}
RTMPSetAGCInitValue(pAd, pAd->CommonCfg.BBPCurrentBW);
//
// Save BBP_R66 value, it will be used in RTUSBResumeMsduTransmission
//
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &pAd->BbpTuning.R66CurrentValue);
DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (BssType=%d, AID=%d, ssid=%s, Channel=%d, CentralChannel = %d)\n",
BssType, pAd->StaActive.Aid, pAd->CommonCfg.Ssid, pAd->CommonCfg.Channel, pAd->CommonCfg.CentralChannel));
DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! (Density =%d, )\n", pAd->MacTab.Content[BSSID_WCID].MpduDensity));
AsicSetBssid(pAd, pAd->CommonCfg.Bssid);
AsicSetSlotTime(pAd, TRUE);
AsicSetEdcaParm(pAd, &pAd->CommonCfg.APEdcaParm);
// Call this for RTS protectionfor legacy rate, we will always enable RTS threshold, but normally it will not hit
AsicUpdateProtect(pAd, 0, (OFDMSETPROTECT | CCKSETPROTECT), TRUE, FALSE);
if ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE))
{
// Update HT protectionfor based on AP's operating mode.
if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)
{
AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE);
}
else
AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE);
}
NdisZeroMemory(&pAd->DrsCounters, sizeof(COUNTER_DRS));
NdisGetSystemUpTime(&Now);
pAd->StaCfg.LastBeaconRxTime = Now; // last RX timestamp
if ((pAd->CommonCfg.TxPreamble != Rt802_11PreambleLong) &&
CAP_IS_SHORT_PREAMBLE_ON(pAd->StaActive.CapabilityInfo))
{
MlmeSetTxPreamble(pAd, Rt802_11PreambleShort);
}
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED);
if (pAd->CommonCfg.RadarDetect.RDMode == RD_SILENCE_MODE)
{
}
pAd->CommonCfg.RadarDetect.RDMode = RD_NORMAL_MODE;
if (BssType == BSS_ADHOC)
{
MakeIbssBeacon(pAd);
if ((pAd->CommonCfg.Channel > 14)
&& (pAd->CommonCfg.bIEEE80211H == 1)
&& RadarChannelCheck(pAd, pAd->CommonCfg.Channel))
{
; //Do nothing
}
else
{
AsicEnableIbssSync(pAd);
}
// In ad hoc mode, use MAC table from index 1.
// p.s ASIC use all 0xff as termination of WCID table search.To prevent it's 0xff-ff-ff-ff-ff-ff, Write 0 here.
RTMP_IO_WRITE32(pAd, MAC_WCID_BASE, 0x00);
RTMP_IO_WRITE32(pAd, 0x1808, 0x00);
// If WEP is enabled, add key material and cipherAlg into Asic
// Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000)
if (pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)
{
PUCHAR Key;
UCHAR CipherAlg;
for (idx=0; idx < SHARE_KEY_NUM; idx++)
{
CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg;
Key = pAd->SharedKey[BSS0][idx].Key;
if (pAd->SharedKey[BSS0][idx].KeyLen > 0)
{
// Set key material and cipherAlg to Asic
AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL);
if (idx == pAd->StaCfg.DefaultKeyId)
{
// Update WCID attribute table and IVEIV table for this group key table
RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL);
}
}
}
}
// If WPANone is enabled, add key material and cipherAlg into Asic
// Fill in Shared Key Table(offset: 0x6c00) and Shared Key Mode(offset: 0x7000)
else if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone)
{
pAd->StaCfg.DefaultKeyId = 0; // always be zero
NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY));
pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK;
NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, pAd->StaCfg.PMK, LEN_TKIP_EK);
if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
{
NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_RXMICK);
NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PMK[16], LEN_TKIP_TXMICK);
}
// Decide its ChiperAlg
if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP;
else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled)
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES;
else
{
DBGPRINT(RT_DEBUG_TRACE, ("Unknow Cipher (=%d), set Cipher to AES\n", pAd->StaCfg.PairCipher));
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES;
}
// Set key material and cipherAlg to Asic
AsicAddSharedKeyEntry(pAd,
BSS0,
0,
pAd->SharedKey[BSS0][0].CipherAlg,
pAd->SharedKey[BSS0][0].Key,
pAd->SharedKey[BSS0][0].TxMic,
pAd->SharedKey[BSS0][0].RxMic);
// Update WCID attribute table and IVEIV table for this group key table
RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, NULL);
}
}
else // BSS_INFRA
{
// Check the new SSID with last SSID
while (Cancelled == TRUE)
{
if (pAd->CommonCfg.LastSsidLen == pAd->CommonCfg.SsidLen)
{
if (RTMPCompareMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen) == 0)
{
// Link to the old one no linkdown is required.
break;
}
}
// Send link down event before set to link up
pAd->IndicateMediaState = NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_DOWN;
DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event AA!\n"));
break;
}
//
// On WPA mode, Remove All Keys if not connect to the last BSSID
// Key will be set after 4-way handshake.
//
if ((pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA))
{
ULONG IV;
// Remove all WPA keys
RTMPWPARemoveAllKeys(pAd);
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP;
// Fixed connection failed with Range Maximizer - 515 AP (Marvell Chip) when security is WPAPSK/TKIP
// If IV related values are too large in GroupMsg2, AP would ignore this message.
IV = 0;
IV |= (pAd->StaCfg.DefaultKeyId << 30);
AsicUpdateWCIDIVEIV(pAd, BSSID_WCID, IV, 0);
}
// NOTE:
// the decision of using "short slot time" or not may change dynamically due to
// new STA association to the AP. so we have to decide that upon parsing BEACON, not here
// NOTE:
// the decision to use "RTC/CTS" or "CTS-to-self" protection or not may change dynamically
// due to new STA association to the AP. so we have to decide that upon parsing BEACON, not here
ComposePsPoll(pAd);
ComposeNullFrame(pAd);
AsicEnableBssSync(pAd);
// Add BSSID to WCID search table
AsicUpdateRxWCIDTable(pAd, BSSID_WCID, pAd->CommonCfg.Bssid);
NdisAcquireSpinLock(&pAd->MacTabLock);
// add this BSSID entry into HASH table
{
UCHAR HashIdx;
//pEntry = &pAd->MacTab.Content[BSSID_WCID];
HashIdx = MAC_ADDR_HASH_INDEX(pAd->CommonCfg.Bssid);
if (pAd->MacTab.Hash[HashIdx] == NULL)
{
pAd->MacTab.Hash[HashIdx] = pEntry;
}
else
{
pCurrEntry = pAd->MacTab.Hash[HashIdx];
while (pCurrEntry->pNext != NULL)
pCurrEntry = pCurrEntry->pNext;
pCurrEntry->pNext = pEntry;
}
}
NdisReleaseSpinLock(&pAd->MacTabLock);
// If WEP is enabled, add paiewise and shared key
if (((pAd->StaCfg.WpaSupplicantUP)&&
(pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)&&
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_SECURED)) ||
((pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE)&&
(pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled)))
{
PUCHAR Key;
UCHAR CipherAlg;
for (idx=0; idx < SHARE_KEY_NUM; idx++)
{
CipherAlg = pAd->SharedKey[BSS0][idx].CipherAlg;
Key = pAd->SharedKey[BSS0][idx].Key;
if (pAd->SharedKey[BSS0][idx].KeyLen > 0)
{
// Set key material and cipherAlg to Asic
AsicAddSharedKeyEntry(pAd, BSS0, idx, CipherAlg, Key, NULL, NULL);
if (idx == pAd->StaCfg.DefaultKeyId)
{
// Assign group key info
RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, NULL);
// Assign pairwise key info
RTMPAddWcidAttributeEntry(pAd, BSS0, idx, CipherAlg, pEntry);
}
}
}
}
// only INFRASTRUCTURE mode need to indicate connectivity immediately; ADHOC mode
// should wait until at least 2 active nodes in this BSSID.
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED);
// For GUI ++
if (pAd->StaCfg.AuthMode < Ndis802_11AuthModeWPA)
{
pAd->IndicateMediaState = NdisMediaStateConnected;
pAd->ExtraInfo = GENERAL_LINK_UP;
RTMP_IndicateMediaState(pAd);
}
// --
// Add BSSID in my MAC Table.
NdisAcquireSpinLock(&pAd->MacTabLock);
RTMPMoveMemory(pAd->MacTab.Content[BSSID_WCID].Addr, pAd->CommonCfg.Bssid, MAC_ADDR_LEN);
pAd->MacTab.Content[BSSID_WCID].Aid = BSSID_WCID;
pAd->MacTab.Content[BSSID_WCID].pAd = pAd;
pAd->MacTab.Content[BSSID_WCID].ValidAsCLI = TRUE; //Although this is bssid..still set ValidAsCl
pAd->MacTab.Size = 1; // infra mode always set MACtab size =1.
pAd->MacTab.Content[BSSID_WCID].Sst = SST_ASSOC;
pAd->MacTab.Content[BSSID_WCID].AuthState = SST_ASSOC;
#ifdef RT30xx
pAd->MacTab.Content[BSSID_WCID].AuthMode = pAd->StaCfg.AuthMode;
#endif
pAd->MacTab.Content[BSSID_WCID].WepStatus = pAd->StaCfg.WepStatus;
NdisReleaseSpinLock(&pAd->MacTabLock);
DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !!! ClientStatusFlags=%lx)\n",
pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags));
MlmeUpdateTxRates(pAd, TRUE, BSS0);
MlmeUpdateHtTxRates(pAd, BSS0);
DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK UP !! (StaActive.bHtEnable =%d, )\n", pAd->StaActive.SupportedPhyInfo.bHtEnable));
if (pAd->CommonCfg.bAggregationCapable)
{
if ((pAd->CommonCfg.bPiggyBackCapable) && (pAd->MlmeAux.APRalinkIe & 0x00000003) == 3)
{
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED);
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED);
RTMPSetPiggyBack(pAd, TRUE);
DBGPRINT(RT_DEBUG_TRACE, ("Turn on Piggy-Back\n"));
}
else if (pAd->MlmeAux.APRalinkIe & 0x00000001)
{
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED);
}
}
if (pAd->MlmeAux.APRalinkIe != 0x0)
{
if (CLIENT_STATUS_TEST_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RDG_CAPABLE))
{
AsicEnableRDG(pAd);
}
OPSTATUS_SET_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET);
CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET);
}
else
{
OPSTATUS_CLEAR_FLAG(pAd, fCLIENT_STATUS_RALINK_CHIPSET);
CLIENT_STATUS_CLEAR_FLAG(&pAd->MacTab.Content[BSSID_WCID], fCLIENT_STATUS_RALINK_CHIPSET);
}
}
DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_CONNECT Event B!.BACapability = %x. ClientStatusFlags = %lx\n", pAd->CommonCfg.BACapability.word, pAd->MacTab.Content[BSSID_WCID].ClientStatusFlags));
// Set LED
RTMPSetLED(pAd, LED_LINK_UP);
pAd->Mlme.PeriodicRound = 0;
pAd->Mlme.OneSecPeriodicRound = 0;
pAd->bConfigChanged = FALSE; // Reset config flag
pAd->ExtraInfo = GENERAL_LINK_UP; // Update extra information to link is up
// Set asic auto fall back
{
PUCHAR pTable;
UCHAR TableSize = 0;
MlmeSelectTxRateTable(pAd, &pAd->MacTab.Content[BSSID_WCID], &pTable, &TableSize, &pAd->CommonCfg.TxRateIndex);
AsicUpdateAutoFallBackTable(pAd, pTable);
}
NdisAcquireSpinLock(&pAd->MacTabLock);
pEntry->HTPhyMode.word = pAd->StaCfg.HTPhyMode.word;
pEntry->MaxHTPhyMode.word = pAd->StaCfg.HTPhyMode.word;
if (pAd->StaCfg.bAutoTxRateSwitch == FALSE)
{
pEntry->bAutoTxRateSwitch = FALSE;
if (pEntry->HTPhyMode.field.MCS == 32)
pEntry->HTPhyMode.field.ShortGI = GI_800;
if ((pEntry->HTPhyMode.field.MCS > MCS_7) || (pEntry->HTPhyMode.field.MCS == 32))
pEntry->HTPhyMode.field.STBC = STBC_NONE;
// If the legacy mode is set, overwrite the transmit setting of this entry.
if (pEntry->HTPhyMode.field.MODE <= MODE_OFDM)
RTMPUpdateLegacyTxSetting((UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode, pEntry);
}
else
pEntry->bAutoTxRateSwitch = TRUE;
NdisReleaseSpinLock(&pAd->MacTabLock);
// Let Link Status Page display first initial rate.
pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word);
// Select DAC according to HT or Legacy
if (pAd->StaActive.SupportedPhyInfo.MCSSet[0] != 0x00)
{
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value);
Value &= (~0x18);
if (pAd->Antenna.field.TxPath == 2)
{
Value |= 0x10;
}
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value);
}
else
{
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &Value);
Value &= (~0x18);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, Value);
}
if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE)
{
}
else if (pEntry->MaxRAmpduFactor == 0)
{
// If HT AP doesn't support MaxRAmpduFactor = 1, we need to set max PSDU to 0.
// Because our Init value is 1 at MACRegTable.
RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x0fff);
}
// Patch for Marvel AP to gain high throughput
// Need to set as following,
// 1. Set txop in register-EDCA_AC0_CFG as 0x60
// 2. Set EnTXWriteBackDDONE in register-WPDMA_GLO_CFG as zero
// 3. PBF_MAX_PCNT as 0x1F3FBF9F
// 4. kick per two packets when dequeue
//
// Txop can only be modified when RDG is off, WMM is disable and TxBurst is enable
//
// if 1. Legacy AP WMM on, or 2. 11n AP, AMPDU disable. Force turn off burst no matter what bEnableTxBurst is.
#ifdef RT30xx
if (!((pAd->CommonCfg.RxStream == 1)&&(pAd->CommonCfg.TxStream == 1)) &&
(((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED))
|| ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE))))
#endif
#ifndef RT30xx
if (((pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED)))
|| ((pAd->StaActive.SupportedPhyInfo.bHtEnable == TRUE) && (pAd->CommonCfg.BACapability.field.Policy == BA_NOTUSE)))
#endif
{
RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data);
Data &= 0xFFFFFF00;
RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data);
RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F);
DBGPRINT(RT_DEBUG_TRACE, ("Txburst 1\n"));
}
else
if (pAd->CommonCfg.bEnableTxBurst)
{
RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data);
Data &= 0xFFFFFF00;
Data |= 0x60;
RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data);
pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = TRUE;
RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3FBF9F);
DBGPRINT(RT_DEBUG_TRACE, ("Txburst 2\n"));
}
else
{
RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &Data);
Data &= 0xFFFFFF00;
RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, Data);
RTMP_IO_WRITE32(pAd, PBF_MAX_PCNT, 0x1F3F7F9F);
DBGPRINT(RT_DEBUG_TRACE, ("Txburst 3\n"));
}
// Re-check to turn on TX burst or not.
if ((pAd->CommonCfg.IOTestParm.bLastAtheros == TRUE) && ((STA_WEP_ON(pAd))||(STA_TKIP_ON(pAd))))
{
pAd->CommonCfg.IOTestParm.bNextDisableRxBA = TRUE;
if (pAd->CommonCfg.bEnableTxBurst)
{
UINT32 MACValue = 0;
// Force disable TXOP value in this case. The same action in MLMEUpdateProtect too.
// I didn't change PBF_MAX_PCNT setting.
RTMP_IO_READ32(pAd, EDCA_AC0_CFG, &MACValue);
MACValue &= 0xFFFFFF00;
RTMP_IO_WRITE32(pAd, EDCA_AC0_CFG, MACValue);
pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE;
}
}
else
{
pAd->CommonCfg.IOTestParm.bNextDisableRxBA = FALSE;
}
pAd->CommonCfg.IOTestParm.bLastAtheros = FALSE;
COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid);
DBGPRINT(RT_DEBUG_TRACE, ("!!!pAd->bNextDisableRxBA= %d \n", pAd->CommonCfg.IOTestParm.bNextDisableRxBA));
// BSSID add in one MAC entry too. Because in Tx, ASIC need to check Cipher and IV/EIV, BAbitmap
// Pther information in MACTab.Content[BSSID_WCID] is not necessary for driver.
// Note: As STA, The MACTab.Content[BSSID_WCID]. PairwiseKey and Shared Key for BSS0 are the same.
if (pAd->StaCfg.WepStatus <= Ndis802_11WEPDisabled)
{
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilterAcceptAll;
}
NdisAcquireSpinLock(&pAd->MacTabLock);
pEntry->PortSecured = pAd->StaCfg.PortSecured;
NdisReleaseSpinLock(&pAd->MacTabLock);
//
// Patch Atheros AP TX will breakdown issue.
// AP Model: DLink DWL-8200AP
//
if (INFRA_ON(pAd) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) && STA_TKIP_ON(pAd))
{
RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x01);
}
else
{
RTMP_IO_WRITE32(pAd, RX_PARSER_CFG, 0x00);
}
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
}
/*
==========================================================================
Routine Description:
Disconnect current BSSID
Arguments:
pAd - Pointer to our adapter
IsReqFromAP - Request from AP
Return Value:
None
IRQL = DISPATCH_LEVEL
Note:
We need more information to know it's this requst from AP.
If yes! we need to do extra handling, for example, remove the WPA key.
Otherwise on 4-way handshaking will faied, since the WPA key didn't be
remove while auto reconnect.
Disconnect request from AP, it means we will start afresh 4-way handshaking
on WPA mode.
==========================================================================
*/
VOID LinkDown(
IN PRTMP_ADAPTER pAd,
IN BOOLEAN IsReqFromAP)
{
UCHAR i, ByteValue = 0;
// Do nothing if monitor mode is on
if (MONITOR_ON(pAd))
return;
if (pAd->CommonCfg.bWirelessEvent)
{
RTMPSendWirelessEvent(pAd, IW_STA_LINKDOWN_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
}
DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN !!!\n"));
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED);
if (ADHOC_ON(pAd)) // Adhoc mode link down
{
DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 1!!!\n"));
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADHOC_ON);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED);
pAd->IndicateMediaState = NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_DOWN;
BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel);
DBGPRINT(RT_DEBUG_TRACE, ("!!! MacTab.Size=%d !!!\n", pAd->MacTab.Size));
}
else // Infra structure mode
{
DBGPRINT(RT_DEBUG_TRACE, ("!!! LINK DOWN 2!!!\n"));
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_INFRA_ON);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED);
// Saved last SSID for linkup comparison
pAd->CommonCfg.LastSsidLen = pAd->CommonCfg.SsidLen;
NdisMoveMemory(pAd->CommonCfg.LastSsid, pAd->CommonCfg.Ssid, pAd->CommonCfg.LastSsidLen);
COPY_MAC_ADDR(pAd->CommonCfg.LastBssid, pAd->CommonCfg.Bssid);
if (pAd->MlmeAux.CurrReqIsFromNdis == TRUE)
{
pAd->IndicateMediaState = NdisMediaStateDisconnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_DOWN;
DBGPRINT(RT_DEBUG_TRACE, ("NDIS_STATUS_MEDIA_DISCONNECT Event A!\n"));
pAd->MlmeAux.CurrReqIsFromNdis = FALSE;
}
else
{
//
// If disassociation request is from NDIS, then we don't need to delete BSSID from entry.
// Otherwise lost beacon or receive De-Authentication from AP,
// then we should delete BSSID from BssTable.
// If we don't delete from entry, roaming will fail.
//
BssTableDeleteEntry(&pAd->ScanTab, pAd->CommonCfg.Bssid, pAd->CommonCfg.Channel);
}
// restore back to -
// 1. long slot (20 us) or short slot (9 us) time
// 2. turn on/off RTS/CTS and/or CTS-to-self protection
// 3. short preamble
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED);
if (pAd->StaCfg.CCXAdjacentAPReportFlag == TRUE)
{
//
// Record current AP's information.
// for later used reporting Adjacent AP report.
//
pAd->StaCfg.CCXAdjacentAPChannel = pAd->CommonCfg.Channel;
pAd->StaCfg.CCXAdjacentAPSsidLen = pAd->CommonCfg.SsidLen;
NdisMoveMemory(pAd->StaCfg.CCXAdjacentAPSsid, pAd->CommonCfg.Ssid, pAd->StaCfg.CCXAdjacentAPSsidLen);
COPY_MAC_ADDR(pAd->StaCfg.CCXAdjacentAPBssid, pAd->CommonCfg.Bssid);
}
}
for (i=1; i<MAX_LEN_OF_MAC_TABLE; i++)
{
if (pAd->MacTab.Content[i].ValidAsCLI == TRUE)
MacTableDeleteEntry(pAd, pAd->MacTab.Content[i].Aid, pAd->MacTab.Content[i].Addr);
}
pAd->StaCfg.CCXQosECWMin = 4;
pAd->StaCfg.CCXQosECWMax = 10;
AsicSetSlotTime(pAd, TRUE); //FALSE);
AsicSetEdcaParm(pAd, NULL);
// Set LED
RTMPSetLED(pAd, LED_LINK_DOWN);
pAd->LedIndicatorStregth = 0xF0;
RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it.
AsicDisableSync(pAd);
pAd->Mlme.PeriodicRound = 0;
pAd->Mlme.OneSecPeriodicRound = 0;
if (pAd->StaCfg.BssType == BSS_INFRA)
{
// Remove StaCfg Information after link down
NdisZeroMemory(pAd->CommonCfg.Bssid, MAC_ADDR_LEN);
NdisZeroMemory(pAd->CommonCfg.Ssid, MAX_LEN_OF_SSID);
pAd->CommonCfg.SsidLen = 0;
}
NdisZeroMemory(&pAd->MlmeAux.HtCapability, sizeof(HT_CAPABILITY_IE));
NdisZeroMemory(&pAd->MlmeAux.AddHtInfo, sizeof(ADD_HT_INFO_IE));
pAd->MlmeAux.HtCapabilityLen = 0;
pAd->MlmeAux.NewExtChannelOffset = 0xff;
// Reset WPA-PSK state. Only reset when supplicant enabled
if (pAd->StaCfg.WpaState != SS_NOTUSE)
{
pAd->StaCfg.WpaState = SS_START;
// Clear Replay counter
NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8);
}
//
// if link down come from AP, we need to remove all WPA keys on WPA mode.
// otherwise will cause 4-way handshaking failed, since the WPA key not empty.
//
if ((IsReqFromAP) && (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA))
{
// Remove all WPA keys
RTMPWPARemoveAllKeys(pAd);
}
// 802.1x port control
// Prevent clear PortSecured here with static WEP
// NetworkManger set security policy first then set SSID to connect AP.
if (pAd->StaCfg.WpaSupplicantUP &&
(pAd->StaCfg.WepStatus == Ndis802_11WEPEnabled) &&
(pAd->StaCfg.IEEE8021X == FALSE))
{
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
}
else
{
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
pAd->StaCfg.PrivacyFilter = Ndis802_11PrivFilter8021xWEP;
}
NdisAcquireSpinLock(&pAd->MacTabLock);
pAd->MacTab.Content[BSSID_WCID].PortSecured = pAd->StaCfg.PortSecured;
NdisReleaseSpinLock(&pAd->MacTabLock);
pAd->StaCfg.MicErrCnt = 0;
// Turn off Ckip control flag
pAd->StaCfg.bCkipOn = FALSE;
pAd->StaCfg.CCXEnable = FALSE;
pAd->IndicateMediaState = NdisMediaStateDisconnected;
// Update extra information to link is up
pAd->ExtraInfo = GENERAL_LINK_DOWN;
pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE;
// Reset the Current AP's IP address
NdisZeroMemory(pAd->StaCfg.AironetIPAddress, 4);
#ifdef RT2870
pAd->bUsbTxBulkAggre = FALSE;
#endif // RT2870 //
// Clean association information
NdisZeroMemory(&pAd->StaCfg.AssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION));
pAd->StaCfg.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
pAd->StaCfg.ReqVarIELen = 0;
pAd->StaCfg.ResVarIELen = 0;
//
// Reset RSSI value after link down
//
pAd->StaCfg.RssiSample.AvgRssi0 = 0;
pAd->StaCfg.RssiSample.AvgRssi0X8 = 0;
pAd->StaCfg.RssiSample.AvgRssi1 = 0;
pAd->StaCfg.RssiSample.AvgRssi1X8 = 0;
pAd->StaCfg.RssiSample.AvgRssi2 = 0;
pAd->StaCfg.RssiSample.AvgRssi2X8 = 0;
// Restore MlmeRate
pAd->CommonCfg.MlmeRate = pAd->CommonCfg.BasicMlmeRate;
pAd->CommonCfg.RtsRate = pAd->CommonCfg.BasicMlmeRate;
//
// After Link down, reset piggy-back setting in ASIC. Disable RDG.
//
if (pAd->CommonCfg.BBPCurrentBW == BW_40)
{
pAd->CommonCfg.BBPCurrentBW = BW_20;
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &ByteValue);
ByteValue &= (~0x18);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, ByteValue);
}
// Reset DAC
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R1, &ByteValue);
ByteValue &= (~0x18);
if (pAd->Antenna.field.TxPath == 2)
{
ByteValue |= 0x10;
}
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R1, ByteValue);
RTMPSetPiggyBack(pAd,FALSE);
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_PIGGYBACK_INUSED);
pAd->CommonCfg.BACapability.word = pAd->CommonCfg.REGBACapability.word;
// Restore all settings in the following.
AsicUpdateProtect(pAd, 0, (ALLN_SETPROTECT|CCKSETPROTECT|OFDMSETPROTECT), TRUE, FALSE);
AsicDisableRDG(pAd);
pAd->CommonCfg.IOTestParm.bCurrentAtheros = FALSE;
pAd->CommonCfg.IOTestParm.bNowAtherosBurstOn = FALSE;
RTMP_IO_WRITE32(pAd, MAX_LEN_CFG, 0x1fff);
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
{
union iwreq_data wrqu;
memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN);
wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL);
}
#ifdef RT30xx
if (IS_RT3090(pAd))
{
UINT32 macdata;
// disable MMPS BBP control register
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &ByteValue);
ByteValue &= ~(0x04); //bit 2
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, ByteValue);
// disable MMPS MAC control register
RTMP_IO_READ32(pAd, 0x1210, &macdata);
macdata &= ~(0x09); //bit 0, 3
RTMP_IO_WRITE32(pAd, 0x1210, macdata);
}
#endif // RT30xx //
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID IterateOnBssTab(
IN PRTMP_ADAPTER pAd)
{
MLME_START_REQ_STRUCT StartReq;
MLME_JOIN_REQ_STRUCT JoinReq;
ULONG BssIdx;
// Change the wepstatus to original wepstatus
pAd->StaCfg.WepStatus = pAd->StaCfg.OrigWepStatus;
pAd->StaCfg.PairCipher = pAd->StaCfg.OrigWepStatus;
pAd->StaCfg.GroupCipher = pAd->StaCfg.OrigWepStatus;
BssIdx = pAd->MlmeAux.BssIdx;
if (BssIdx < pAd->MlmeAux.SsidBssTab.BssNr)
{
// Check cipher suite, AP must have more secured cipher than station setting
// Set the Pairwise and Group cipher to match the intended AP setting
// We can only connect to AP with less secured cipher setting
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK))
{
pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.GroupCipher;
if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher)
pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipher;
else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux != Ndis802_11WEPDisabled)
pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA.PairCipherAux;
else // There is no PairCipher Aux, downgrade our capability to TKIP
pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled;
}
else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK))
{
pAd->StaCfg.GroupCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.GroupCipher;
if (pAd->StaCfg.WepStatus == pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher)
pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipher;
else if (pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux != Ndis802_11WEPDisabled)
pAd->StaCfg.PairCipher = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.PairCipherAux;
else // There is no PairCipher Aux, downgrade our capability to TKIP
pAd->StaCfg.PairCipher = Ndis802_11Encryption2Enabled;
// RSN capability
pAd->StaCfg.RsnCapability = pAd->MlmeAux.SsidBssTab.BssEntry[BssIdx].WPA2.RsnCapability;
}
// Set Mix cipher flag
pAd->StaCfg.bMixCipher = (pAd->StaCfg.PairCipher == pAd->StaCfg.GroupCipher) ? FALSE : TRUE;
if (pAd->StaCfg.bMixCipher == TRUE)
{
// If mix cipher, re-build RSNIE
RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0);
}
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.SsidBssTab.BssNr));
JoinParmFill(pAd, &JoinReq, BssIdx);
MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_JOIN_REQ, sizeof(MLME_JOIN_REQ_STRUCT),
&JoinReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_JOIN;
}
else if (pAd->StaCfg.BssType == BSS_ADHOC)
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All BSS fail; start a new ADHOC (Ssid=%s)...\n",pAd->MlmeAux.Ssid));
StartParmFill(pAd, &StartReq, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen);
MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
}
else // no more BSS
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All roaming failed, stay @ ch #%d\n", pAd->CommonCfg.Channel));
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
}
}
// for re-association only
// IRQL = DISPATCH_LEVEL
VOID IterateOnBssTab2(
IN PRTMP_ADAPTER pAd)
{
MLME_REASSOC_REQ_STRUCT ReassocReq;
ULONG BssIdx;
BSS_ENTRY *pBss;
BssIdx = pAd->MlmeAux.RoamIdx;
pBss = &pAd->MlmeAux.RoamTab.BssEntry[BssIdx];
if (BssIdx < pAd->MlmeAux.RoamTab.BssNr)
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - iterate BSS %ld of %d\n", BssIdx, pAd->MlmeAux.RoamTab.BssNr));
AsicSwitchChannel(pAd, pBss->Channel, FALSE);
AsicLockChannel(pAd, pBss->Channel);
// reassociate message has the same structure as associate message
AssocParmFill(pAd, &ReassocReq, pBss->Bssid, pBss->CapabilityInfo,
ASSOC_TIMEOUT, pAd->StaCfg.DefaultListenCount);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_REASSOC_REQ,
sizeof(MLME_REASSOC_REQ_STRUCT), &ReassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_REASSOC;
}
else // no more BSS
{
DBGPRINT(RT_DEBUG_TRACE, ("CNTL - All fast roaming failed, back to ch #%d\n",pAd->CommonCfg.Channel));
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
}
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID JoinParmFill(
IN PRTMP_ADAPTER pAd,
IN OUT MLME_JOIN_REQ_STRUCT *JoinReq,
IN ULONG BssIdx)
{
JoinReq->BssIdx = BssIdx;
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID ScanParmFill(
IN PRTMP_ADAPTER pAd,
IN OUT MLME_SCAN_REQ_STRUCT *ScanReq,
IN CHAR Ssid[],
IN UCHAR SsidLen,
IN UCHAR BssType,
IN UCHAR ScanType)
{
NdisZeroMemory(ScanReq->Ssid, MAX_LEN_OF_SSID);
ScanReq->SsidLen = SsidLen;
NdisMoveMemory(ScanReq->Ssid, Ssid, SsidLen);
ScanReq->BssType = BssType;
ScanReq->ScanType = ScanType;
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID StartParmFill(
IN PRTMP_ADAPTER pAd,
IN OUT MLME_START_REQ_STRUCT *StartReq,
IN CHAR Ssid[],
IN UCHAR SsidLen)
{
ASSERT(SsidLen <= MAX_LEN_OF_SSID);
NdisMoveMemory(StartReq->Ssid, Ssid, SsidLen);
StartReq->SsidLen = SsidLen;
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID AuthParmFill(
IN PRTMP_ADAPTER pAd,
IN OUT MLME_AUTH_REQ_STRUCT *AuthReq,
IN PUCHAR pAddr,
IN USHORT Alg)
{
COPY_MAC_ADDR(AuthReq->Addr, pAddr);
AuthReq->Alg = Alg;
AuthReq->Timeout = AUTH_TIMEOUT;
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
#ifdef RT2870
VOID MlmeCntlConfirm(
IN PRTMP_ADAPTER pAd,
IN ULONG MsgType,
IN USHORT Msg)
{
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MsgType, sizeof(USHORT), &Msg);
}
VOID ComposePsPoll(
IN PRTMP_ADAPTER pAd)
{
PTXINFO_STRUC pTxInfo;
PTXWI_STRUC pTxWI;
DBGPRINT(RT_DEBUG_TRACE, ("ComposePsPoll\n"));
NdisZeroMemory(&pAd->PsPollFrame, sizeof(PSPOLL_FRAME));
pAd->PsPollFrame.FC.PwrMgmt = 0;
pAd->PsPollFrame.FC.Type = BTYPE_CNTL;
pAd->PsPollFrame.FC.SubType = SUBTYPE_PS_POLL;
pAd->PsPollFrame.Aid = pAd->StaActive.Aid | 0xC000;
COPY_MAC_ADDR(pAd->PsPollFrame.Bssid, pAd->CommonCfg.Bssid);
COPY_MAC_ADDR(pAd->PsPollFrame.Ta, pAd->CurrentAddress);
RTMPZeroMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0], 100);
pTxInfo = (PTXINFO_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[0];
RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(PSPOLL_FRAME)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE);
pTxWI = (PTXWI_STRUC)&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE];
RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(PSPOLL_FRAME)),
0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit);
RTMPMoveMemory(&pAd->PsPollContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->PsPollFrame, sizeof(PSPOLL_FRAME));
// Append 4 extra zero bytes.
pAd->PsPollContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(PSPOLL_FRAME) + 4;
}
// IRQL = DISPATCH_LEVEL
VOID ComposeNullFrame(
IN PRTMP_ADAPTER pAd)
{
PTXINFO_STRUC pTxInfo;
PTXWI_STRUC pTxWI;
NdisZeroMemory(&pAd->NullFrame, sizeof(HEADER_802_11));
pAd->NullFrame.FC.Type = BTYPE_DATA;
pAd->NullFrame.FC.SubType = SUBTYPE_NULL_FUNC;
pAd->NullFrame.FC.ToDs = 1;
COPY_MAC_ADDR(pAd->NullFrame.Addr1, pAd->CommonCfg.Bssid);
COPY_MAC_ADDR(pAd->NullFrame.Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(pAd->NullFrame.Addr3, pAd->CommonCfg.Bssid);
RTMPZeroMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[0], 100);
pTxInfo = (PTXINFO_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[0];
RTMPWriteTxInfo(pAd, pTxInfo, (USHORT)(sizeof(HEADER_802_11)+TXWI_SIZE), TRUE, EpToQueue[MGMTPIPEIDX], FALSE, FALSE);
pTxWI = (PTXWI_STRUC)&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXINFO_SIZE];
RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 0, BSSID_WCID, (sizeof(HEADER_802_11)),
0, 0, (UCHAR)pAd->CommonCfg.MlmeTransmit.field.MCS, IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit);
RTMPMoveMemory(&pAd->NullContext.TransferBuffer->field.WirelessPacket[TXWI_SIZE+TXINFO_SIZE], &pAd->NullFrame, sizeof(HEADER_802_11));
pAd->NullContext.BulkOutSize = TXINFO_SIZE + TXWI_SIZE + sizeof(pAd->NullFrame) + 4;
}
#endif // RT2870 //
/*
==========================================================================
Description:
Pre-build a BEACON frame in the shared memory
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
==========================================================================
*/
ULONG MakeIbssBeacon(
IN PRTMP_ADAPTER pAd)
{
UCHAR DsLen = 1, IbssLen = 2;
UCHAR LocalErpIe[3] = {IE_ERP, 1, 0x04};
HEADER_802_11 BcnHdr;
USHORT CapabilityInfo;
LARGE_INTEGER FakeTimestamp;
ULONG FrameLen = 0;
PTXWI_STRUC pTxWI = &pAd->BeaconTxWI;
CHAR *pBeaconFrame = pAd->BeaconBuf;
BOOLEAN Privacy;
UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES];
UCHAR SupRateLen = 0;
UCHAR ExtRate[MAX_LEN_OF_SUPPORTED_RATES];
UCHAR ExtRateLen = 0;
UCHAR RSNIe = IE_WPA;
if ((pAd->CommonCfg.PhyMode == PHY_11B) && (pAd->CommonCfg.Channel <= 14))
{
SupRate[0] = 0x82; // 1 mbps
SupRate[1] = 0x84; // 2 mbps
SupRate[2] = 0x8b; // 5.5 mbps
SupRate[3] = 0x96; // 11 mbps
SupRateLen = 4;
ExtRateLen = 0;
}
else if (pAd->CommonCfg.Channel > 14)
{
SupRate[0] = 0x8C; // 6 mbps, in units of 0.5 Mbps, basic rate
SupRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps
SupRate[2] = 0x98; // 12 mbps, in units of 0.5 Mbps, basic rate
SupRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps
SupRate[4] = 0xb0; // 24 mbps, in units of 0.5 Mbps, basic rate
SupRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps
SupRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps
SupRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps
SupRateLen = 8;
ExtRateLen = 0;
//
// Also Update MlmeRate & RtsRate for G only & A only
//
pAd->CommonCfg.MlmeRate = RATE_6;
pAd->CommonCfg.RtsRate = RATE_6;
pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM;
pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
}
else
{
SupRate[0] = 0x82; // 1 mbps
SupRate[1] = 0x84; // 2 mbps
SupRate[2] = 0x8b; // 5.5 mbps
SupRate[3] = 0x96; // 11 mbps
SupRateLen = 4;
ExtRate[0] = 0x0C; // 6 mbps, in units of 0.5 Mbps,
ExtRate[1] = 0x12; // 9 mbps, in units of 0.5 Mbps
ExtRate[2] = 0x18; // 12 mbps, in units of 0.5 Mbps,
ExtRate[3] = 0x24; // 18 mbps, in units of 0.5 Mbps
ExtRate[4] = 0x30; // 24 mbps, in units of 0.5 Mbps,
ExtRate[5] = 0x48; // 36 mbps, in units of 0.5 Mbps
ExtRate[6] = 0x60; // 48 mbps, in units of 0.5 Mbps
ExtRate[7] = 0x6c; // 54 mbps, in units of 0.5 Mbps
ExtRateLen = 8;
}
pAd->StaActive.SupRateLen = SupRateLen;
NdisMoveMemory(pAd->StaActive.SupRate, SupRate, SupRateLen);
pAd->StaActive.ExtRateLen = ExtRateLen;
NdisMoveMemory(pAd->StaActive.ExtRate, ExtRate, ExtRateLen);
// compose IBSS beacon frame
MgtMacHeaderInit(pAd, &BcnHdr, SUBTYPE_BEACON, 0, BROADCAST_ADDR, pAd->CommonCfg.Bssid);
Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) ||
(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ||
(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled);
CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0);
MakeOutgoingFrame(pBeaconFrame, &FrameLen,
sizeof(HEADER_802_11), &BcnHdr,
TIMESTAMP_LEN, &FakeTimestamp,
2, &pAd->CommonCfg.BeaconPeriod,
2, &CapabilityInfo,
1, &SsidIe,
1, &pAd->CommonCfg.SsidLen,
pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid,
1, &SupRateIe,
1, &SupRateLen,
SupRateLen, SupRate,
1, &DsIe,
1, &DsLen,
1, &pAd->CommonCfg.Channel,
1, &IbssIe,
1, &IbssLen,
2, &pAd->StaActive.AtimWin,
END_OF_ARGS);
// add ERP_IE and EXT_RAE IE of in 802.11g
if (ExtRateLen)
{
ULONG tmp;
MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp,
3, LocalErpIe,
1, &ExtRateIe,
1, &ExtRateLen,
ExtRateLen, ExtRate,
END_OF_ARGS);
FrameLen += tmp;
}
// If adhoc secruity is set for WPA-None, append the cipher suite IE
if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone)
{
ULONG tmp;
RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, BSS0);
MakeOutgoingFrame(pBeaconFrame + FrameLen, &tmp,
1, &RSNIe,
1, &pAd->StaCfg.RSNIE_Len,
pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE,
END_OF_ARGS);
FrameLen += tmp;
}
if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED))
{
ULONG TmpLen;
UCHAR HtLen, HtLen1;
// add HT Capability IE
HtLen = sizeof(pAd->CommonCfg.HtCapability);
HtLen1 = sizeof(pAd->CommonCfg.AddHTInfo);
MakeOutgoingFrame(pBeaconFrame+FrameLen, &TmpLen,
1, &HtCapIe,
1, &HtLen,
HtLen, &pAd->CommonCfg.HtCapability,
1, &AddHtInfoIe,
1, &HtLen1,
HtLen1, &pAd->CommonCfg.AddHTInfo,
END_OF_ARGS);
FrameLen += TmpLen;
}
//beacon use reserved WCID 0xff
if (pAd->CommonCfg.Channel > 14)
{
RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen,
PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &pAd->CommonCfg.MlmeTransmit);
}
else
{
// Set to use 1Mbps for Adhoc beacon.
HTTRANSMIT_SETTING Transmit;
Transmit.word = 0;
RTMPWriteTxWI(pAd, pTxWI, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0xff, FrameLen,
PID_MGMT, PID_BEACON, RATE_1, IFS_HTTXOP, FALSE, &Transmit);
}
DBGPRINT(RT_DEBUG_TRACE, ("MakeIbssBeacon (len=%ld), SupRateLen=%d, ExtRateLen=%d, Channel=%d, PhyMode=%d\n",
FrameLen, SupRateLen, ExtRateLen, pAd->CommonCfg.Channel, pAd->CommonCfg.PhyMode));
return FrameLen;
}
/* #include "../../rt2860/sta/rtmp_data.c"
*************************************************************************
* 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:
rtmp_data.c
Abstract:
Data path subroutines
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John Aug/17/04 major modification for RT2561/2661
Jan Lee Mar/17/06 major modification for RT2860 New Ring Design
*/
#include "../rt_config.h"
VOID STARxEAPOLFrameIndicate(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN RX_BLK *pRxBlk,
IN UCHAR FromWhichBSSID)
{
PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD);
PRXWI_STRUC pRxWI = pRxBlk->pRxWI;
UCHAR *pTmpBuf;
if (pAd->StaCfg.WpaSupplicantUP)
{
// All EAPoL frames have to pass to upper layer (ex. WPA_SUPPLICANT daemon)
// TBD : process fragmented EAPol frames
{
// In 802.1x mode, if the received frame is EAP-SUCCESS packet, turn on the PortSecured variable
if ( pAd->StaCfg.IEEE8021X == TRUE &&
(EAP_CODE_SUCCESS == WpaCheckEapCode(pAd, pRxBlk->pData, pRxBlk->DataSize, LENGTH_802_1_H)))
{
PUCHAR Key;
UCHAR CipherAlg;
int idx = 0;
DBGPRINT_RAW(RT_DEBUG_TRACE, ("Receive EAP-SUCCESS Packet\n"));
STA_PORT_SECURED(pAd);
if (pAd->StaCfg.IEEE8021x_required_keys == FALSE)
{
idx = pAd->StaCfg.DesireSharedKeyId;
CipherAlg = pAd->StaCfg.DesireSharedKey[idx].CipherAlg;
Key = pAd->StaCfg.DesireSharedKey[idx].Key;
if (pAd->StaCfg.DesireSharedKey[idx].KeyLen > 0)
{
#ifdef RT2870
union
{
char buf[sizeof(NDIS_802_11_WEP)+MAX_LEN_OF_KEY- 1];
NDIS_802_11_WEP keyinfo;
} WepKey;
int len;
NdisZeroMemory(&WepKey, sizeof(WepKey));
len =pAd->StaCfg.DesireSharedKey[idx].KeyLen;
NdisMoveMemory(WepKey.keyinfo.KeyMaterial,
pAd->StaCfg.DesireSharedKey[idx].Key,
pAd->StaCfg.DesireSharedKey[idx].KeyLen);
WepKey.keyinfo.KeyIndex = 0x80000000 + idx;
WepKey.keyinfo.KeyLength = len;
pAd->SharedKey[BSS0][idx].KeyLen =(UCHAR) (len <= 5 ? 5 : 13);
pAd->IndicateMediaState = NdisMediaStateConnected;
pAd->ExtraInfo = GENERAL_LINK_UP;
// need to enqueue cmd to thread
RTUSBEnqueueCmdFromNdis(pAd, OID_802_11_ADD_WEP, TRUE, &WepKey, sizeof(WepKey.keyinfo) + len - 1);
#endif // RT2870 //
// For Preventing ShardKey Table is cleared by remove key procedure.
pAd->SharedKey[BSS0][idx].CipherAlg = CipherAlg;
pAd->SharedKey[BSS0][idx].KeyLen = pAd->StaCfg.DesireSharedKey[idx].KeyLen;
NdisMoveMemory(pAd->SharedKey[BSS0][idx].Key,
pAd->StaCfg.DesireSharedKey[idx].Key,
pAd->StaCfg.DesireSharedKey[idx].KeyLen);
}
}
}
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
return;
}
}
else
{
// Special DATA frame that has to pass to MLME
// 1. Cisco Aironet frames for CCX2. We need pass it to MLME for special process
// 2. EAPOL handshaking frames when driver supplicant enabled, pass to MLME for special process
{
pTmpBuf = pRxBlk->pData - LENGTH_802_11;
NdisMoveMemory(pTmpBuf, pRxBlk->pHeader, LENGTH_802_11);
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pTmpBuf, pRxBlk->DataSize + LENGTH_802_11, pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal);
DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! report EAPOL/AIRONET DATA to MLME (len=%d) !!!\n", pRxBlk->DataSize));
}
}
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
return;
}
VOID STARxDataFrameAnnounce(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN RX_BLK *pRxBlk,
IN UCHAR FromWhichBSSID)
{
// non-EAP frame
if (!RTMPCheckWPAframe(pAd, pEntry, pRxBlk->pData, pRxBlk->DataSize, FromWhichBSSID))
{
{
// drop all non-EAP DATA frame before
// this client's Port-Access-Control is secured
if (pRxBlk->pHeader->FC.Wep)
{
// unsupported cipher suite
if (pAd->StaCfg.WepStatus == Ndis802_11EncryptionDisabled)
{
// release packet
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
return;
}
}
else
{
// encryption in-use but receive a non-EAPOL clear text frame, drop it
if ((pAd->StaCfg.WepStatus != Ndis802_11EncryptionDisabled) &&
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED))
{
// release packet
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
return;
}
}
}
RX_BLK_CLEAR_FLAG(pRxBlk, fRX_EAP);
if (!RX_BLK_TEST_FLAG(pRxBlk, fRX_ARALINK))
{
// Normal legacy, AMPDU or AMSDU
CmmRxnonRalinkFrameIndicate(pAd, pRxBlk, FromWhichBSSID);
}
else
{
// ARALINK
CmmRxRalinkFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID);
}
}
else
{
RX_BLK_SET_FLAG(pRxBlk, fRX_EAP);
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_AMPDU) && (pAd->CommonCfg.bDisableReordering == 0))
{
Indicate_AMPDU_Packet(pAd, pRxBlk, FromWhichBSSID);
}
else
{
// Determin the destination of the EAP frame
// to WPA state machine or upper layer
STARxEAPOLFrameIndicate(pAd, pEntry, pRxBlk, FromWhichBSSID);
}
}
}
// For TKIP frame, calculate the MIC value
BOOLEAN STACheckTkipMICValue(
IN PRTMP_ADAPTER pAd,
IN MAC_TABLE_ENTRY *pEntry,
IN RX_BLK *pRxBlk)
{
PHEADER_802_11 pHeader = pRxBlk->pHeader;
UCHAR *pData = pRxBlk->pData;
USHORT DataSize = pRxBlk->DataSize;
UCHAR UserPriority = pRxBlk->UserPriority;
PCIPHER_KEY pWpaKey;
UCHAR *pDA, *pSA;
pWpaKey = &pAd->SharedKey[BSS0][pRxBlk->pRxWI->KeyIndex];
pDA = pHeader->Addr1;
if (RX_BLK_TEST_FLAG(pRxBlk, fRX_INFRA))
{
pSA = pHeader->Addr3;
}
else
{
pSA = pHeader->Addr2;
}
if (RTMPTkipCompareMICValue(pAd,
pData,
pDA,
pSA,
pWpaKey->RxMic,
UserPriority,
DataSize) == FALSE)
{
DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error 2\n"));
if (pAd->StaCfg.WpaSupplicantUP)
{
WpaSendMicFailureToWpaSupplicant(pAd, (pWpaKey->Type == PAIRWISEKEY) ? TRUE : FALSE);
}
else
{
RTMPReportMicError(pAd, pWpaKey);
}
// release packet
RELEASE_NDIS_PACKET(pAd, pRxBlk->pRxPacket, NDIS_STATUS_FAILURE);
return FALSE;
}
return TRUE;
}
//
// All Rx routines use RX_BLK structure to hande rx events
// It is very important to build pRxBlk attributes
// 1. pHeader pointer to 802.11 Header
// 2. pData pointer to payload including LLC (just skip Header)
// 3. set payload size including LLC to DataSize
// 4. set some flags with RX_BLK_SET_FLAG()
//
VOID STAHandleRxDataFrame(
IN PRTMP_ADAPTER pAd,
IN RX_BLK *pRxBlk)
{
PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD);
PRXWI_STRUC pRxWI = pRxBlk->pRxWI;
PHEADER_802_11 pHeader = pRxBlk->pHeader;
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
BOOLEAN bFragment = FALSE;
MAC_TABLE_ENTRY *pEntry = NULL;
UCHAR FromWhichBSSID = BSS0;
UCHAR UserPriority = 0;
{
// before LINK UP, all DATA frames are rejected
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
{
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
// Drop not my BSS frames
if (pRxD->MyBss == 0)
{
{
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
}
pAd->RalinkCounters.RxCountSinceLastNULL++;
if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable && (pHeader->FC.SubType & 0x08))
{
UCHAR *pData;
DBGPRINT(RT_DEBUG_TRACE,("bAPSDCapable\n"));
// Qos bit 4
pData = (PUCHAR)pHeader + LENGTH_802_11;
if ((*pData >> 4) & 0x01)
{
DBGPRINT(RT_DEBUG_TRACE,("RxDone- Rcv EOSP frame, driver may fall into sleep\n"));
pAd->CommonCfg.bInServicePeriod = FALSE;
// Force driver to fall into sleep mode when rcv EOSP frame
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
{
USHORT TbttNumToNextWakeUp;
USHORT NextDtim = pAd->StaCfg.DtimPeriod;
ULONG Now;
NdisGetSystemUpTime(&Now);
NextDtim -= (USHORT)(Now - pAd->StaCfg.LastBeaconRxTime)/pAd->CommonCfg.BeaconPeriod;
TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim))
TbttNumToNextWakeUp = NextDtim;
MlmeSetPsmBit(pAd, PWR_SAVE);
// if WMM-APSD is failed, try to disable following line
AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp);
}
}
if ((pHeader->FC.MoreData) && (pAd->CommonCfg.bInServicePeriod))
{
DBGPRINT(RT_DEBUG_TRACE,("Sending another trigger frame when More Data bit is set to 1\n"));
}
}
// Drop NULL, CF-ACK(no data), CF-POLL(no data), and CF-ACK+CF-POLL(no data) data frame
if ((pHeader->FC.SubType & 0x04)) // bit 2 : no DATA
{
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
// Drop not my BSS frame (we can not only check the MyBss bit in RxD)
if (INFRA_ON(pAd))
{
// Infrastructure mode, check address 2 for BSSID
if (!RTMPEqualMemory(&pHeader->Addr2, &pAd->CommonCfg.Bssid, 6))
{
// Receive frame not my BSSID
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
}
else // Ad-Hoc mode or Not associated
{
// Ad-Hoc mode, check address 3 for BSSID
if (!RTMPEqualMemory(&pHeader->Addr3, &pAd->CommonCfg.Bssid, 6))
{
// Receive frame not my BSSID
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
}
//
// find pEntry
//
if (pRxWI->WirelessCliID < MAX_LEN_OF_MAC_TABLE)
{
pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID];
}
else
{
// 1. release packet if infra mode
// 2. new a pEntry if ad-hoc mode
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
// infra or ad-hoc
if (INFRA_ON(pAd))
{
RX_BLK_SET_FLAG(pRxBlk, fRX_INFRA);
ASSERT(pRxWI->WirelessCliID == BSSID_WCID);
}
// check Atheros Client
if ((pEntry->bIAmBadAtheros == FALSE) && (pRxD->AMPDU == 1) && (pHeader->FC.Retry ))
{
pEntry->bIAmBadAtheros = TRUE;
pAd->CommonCfg.IOTestParm.bCurrentAtheros = TRUE;
pAd->CommonCfg.IOTestParm.bLastAtheros = TRUE;
if (!STA_AES_ON(pAd))
{
AsicUpdateProtect(pAd, 8, ALLN_SETPROTECT, TRUE, FALSE);
}
}
}
pRxBlk->pData = (UCHAR *)pHeader;
//
// update RxBlk->pData, DataSize
// 802.11 Header, QOS, HTC, Hw Padding
//
// 1. skip 802.11 HEADER
{
pRxBlk->pData += LENGTH_802_11;
pRxBlk->DataSize -= LENGTH_802_11;
}
// 2. QOS
if (pHeader->FC.SubType & 0x08)
{
RX_BLK_SET_FLAG(pRxBlk, fRX_QOS);
UserPriority = *(pRxBlk->pData) & 0x0f;
// bit 7 in QoS Control field signals the HT A-MSDU format
if ((*pRxBlk->pData) & 0x80)
{
RX_BLK_SET_FLAG(pRxBlk, fRX_AMSDU);
}
// skip QOS contorl field
pRxBlk->pData += 2;
pRxBlk->DataSize -=2;
}
pRxBlk->UserPriority = UserPriority;
// 3. Order bit: A-Ralink or HTC+
if (pHeader->FC.Order)
{
#ifdef AGGREGATION_SUPPORT
if ((pRxWI->PHYMODE <= MODE_OFDM) && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED)))
{
RX_BLK_SET_FLAG(pRxBlk, fRX_ARALINK);
}
else
#endif
{
RX_BLK_SET_FLAG(pRxBlk, fRX_HTC);
// skip HTC contorl field
pRxBlk->pData += 4;
pRxBlk->DataSize -= 4;
}
}
// 4. skip HW padding
if (pRxD->L2PAD)
{
// just move pData pointer
// because DataSize excluding HW padding
RX_BLK_SET_FLAG(pRxBlk, fRX_PAD);
pRxBlk->pData += 2;
}
if (pRxD->BA)
{
RX_BLK_SET_FLAG(pRxBlk, fRX_AMPDU);
}
//
// Case I Process Broadcast & Multicast data frame
//
if (pRxD->Bcast || pRxD->Mcast)
{
INC_COUNTER64(pAd->WlanCounters.MulticastReceivedFrameCount);
// Drop Mcast/Bcast frame with fragment bit on
if (pHeader->FC.MoreFrag)
{
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
// Filter out Bcast frame which AP relayed for us
if (pHeader->FC.FrDs && MAC_ADDR_EQUAL(pHeader->Addr3, pAd->CurrentAddress))
{
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
return;
}
Indicate_Legacy_Packet(pAd, pRxBlk, FromWhichBSSID);
return;
}
else if (pRxD->U2M)
{
pAd->LastRxRate = (USHORT)((pRxWI->MCS) + (pRxWI->BW <<7) + (pRxWI->ShortGI <<8)+ (pRxWI->PHYMODE <<14)) ;
if (ADHOC_ON(pAd))
{
pEntry = MacTableLookup(pAd, pHeader->Addr2);
if (pEntry)
Update_Rssi_Sample(pAd, &pEntry->RssiSample, pRxWI);
}
Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI);
pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0);
pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1);
pAd->RalinkCounters.OneSecRxOkDataCnt++;
if (!((pHeader->Frag == 0) && (pHeader->FC.MoreFrag == 0)))
{
// re-assemble the fragmented packets
// return complete frame (pRxPacket) or NULL
bFragment = TRUE;
pRxPacket = RTMPDeFragmentDataFrame(pAd, pRxBlk);
}
if (pRxPacket)
{
pEntry = &pAd->MacTab.Content[pRxWI->WirelessCliID];
// process complete frame
if (bFragment && (pRxD->Decrypted) && (pEntry->WepStatus == Ndis802_11Encryption2Enabled))
{
// Minus MIC length
pRxBlk->DataSize -= 8;
// For TKIP frame, calculate the MIC value
if (STACheckTkipMICValue(pAd, pEntry, pRxBlk) == FALSE)
{
return;
}
}
STARxDataFrameAnnounce(pAd, pEntry, pRxBlk, FromWhichBSSID);
return;
}
else
{
// just return
// because RTMPDeFragmentDataFrame() will release rx packet,
// if packet is fragmented
return;
}
}
ASSERT(0);
// release packet
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
}
VOID STAHandleRxMgmtFrame(
IN PRTMP_ADAPTER pAd,
IN RX_BLK *pRxBlk)
{
PRT28XX_RXD_STRUC pRxD = &(pRxBlk->RxD);
PRXWI_STRUC pRxWI = pRxBlk->pRxWI;
PHEADER_802_11 pHeader = pRxBlk->pHeader;
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
do
{
// We should collect RSSI not only U2M data but also my beacon
#ifdef RT30xx
if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))
&& (pAd->RxAnt.EvaluatePeriod == 0))
#endif
#ifndef RT30xx
if ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2)))
#endif
{
Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, pRxWI);
pAd->StaCfg.LastSNR0 = (UCHAR)(pRxWI->SNR0);
pAd->StaCfg.LastSNR1 = (UCHAR)(pRxWI->SNR1);
}
#ifdef RT30xx
// collect rssi information for antenna diversity
if (pAd->NicConfig2.field.AntDiversity)
{
if ((pRxD->U2M) || ((pHeader->FC.SubType == SUBTYPE_BEACON) && (MAC_ADDR_EQUAL(&pAd->CommonCfg.Bssid, &pHeader->Addr2))))
{
COLLECT_RX_ANTENNA_AVERAGE_RSSI(pAd, ConvertToRssi(pAd, (UCHAR)pRxWI->RSSI0, RSSI_0), 0); //Note: RSSI2 not used on RT73
pAd->StaCfg.NumOfAvgRssiSample ++;
}
}
#endif // RT30xx //
// First check the size, it MUST not exceed the mlme queue size
if (pRxWI->MPDUtotalByteCount > MGMT_DMA_BUFFER_SIZE)
{
DBGPRINT_ERR(("STAHandleRxMgmtFrame: frame too large, size = %d \n", pRxWI->MPDUtotalByteCount));
break;
}
REPORT_MGMT_FRAME_TO_MLME(pAd, pRxWI->WirelessCliID, pHeader, pRxWI->MPDUtotalByteCount,
pRxWI->RSSI0, pRxWI->RSSI1, pRxWI->RSSI2, pRxD->PlcpSignal);
} while (FALSE);
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_SUCCESS);
}
VOID STAHandleRxControlFrame(
IN PRTMP_ADAPTER pAd,
IN RX_BLK *pRxBlk)
{
PRXWI_STRUC pRxWI = pRxBlk->pRxWI;
PHEADER_802_11 pHeader = pRxBlk->pHeader;
PNDIS_PACKET pRxPacket = pRxBlk->pRxPacket;
switch (pHeader->FC.SubType)
{
case SUBTYPE_BLOCK_ACK_REQ:
{
CntlEnqueueForRecv(pAd, pRxWI->WirelessCliID, (pRxWI->MPDUtotalByteCount), (PFRAME_BA_REQ)pHeader);
}
break;
case SUBTYPE_BLOCK_ACK:
case SUBTYPE_ACK:
default:
break;
}
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
}
/*
========================================================================
Routine Description:
Process RxDone interrupt, running in DPC level
Arguments:
pAd Pointer to our adapter
Return Value:
None
IRQL = DISPATCH_LEVEL
Note:
This routine has to maintain Rx ring read pointer.
Need to consider QOS DATA format when converting to 802.3
========================================================================
*/
BOOLEAN STARxDoneInterruptHandle(
IN PRTMP_ADAPTER pAd,
IN BOOLEAN argc)
{
NDIS_STATUS Status;
UINT32 RxProcessed, RxPending;
BOOLEAN bReschedule = FALSE;
RT28XX_RXD_STRUC *pRxD;
UCHAR *pData;
PRXWI_STRUC pRxWI;
PNDIS_PACKET pRxPacket;
PHEADER_802_11 pHeader;
RX_BLK RxCell;
RxProcessed = RxPending = 0;
// process whole rx ring
while (1)
{
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF |
fRTMP_ADAPTER_RESET_IN_PROGRESS |
fRTMP_ADAPTER_HALT_IN_PROGRESS |
fRTMP_ADAPTER_NIC_NOT_EXIST) ||
!RTMP_TEST_FLAG(pAd,fRTMP_ADAPTER_START_UP))
{
break;
}
RxProcessed ++; // test
// 1. allocate a new data packet into rx ring to replace received packet
// then processing the received packet
// 2. the callee must take charge of release of packet
// 3. As far as driver is concerned ,
// the rx packet must
// a. be indicated to upper layer or
// b. be released if it is discarded
pRxPacket = GetPacketFromRxRing(pAd, &(RxCell.RxD), &bReschedule, &RxPending);
if (pRxPacket == NULL)
{
// no more packet to process
break;
}
// get rx ring descriptor
pRxD = &(RxCell.RxD);
// get rx data buffer
pData = GET_OS_PKT_DATAPTR(pRxPacket);
pRxWI = (PRXWI_STRUC) pData;
pHeader = (PHEADER_802_11) (pData+RXWI_SIZE) ;
// build RxCell
RxCell.pRxWI = pRxWI;
RxCell.pHeader = pHeader;
RxCell.pRxPacket = pRxPacket;
RxCell.pData = (UCHAR *) pHeader;
RxCell.DataSize = pRxWI->MPDUtotalByteCount;
RxCell.Flags = 0;
// Increase Total receive byte counter after real data received no mater any error or not
pAd->RalinkCounters.ReceivedByteCount += pRxWI->MPDUtotalByteCount;
pAd->RalinkCounters.RxCount ++;
INC_COUNTER64(pAd->WlanCounters.ReceivedFragmentCount);
if (pRxWI->MPDUtotalByteCount < 14)
Status = NDIS_STATUS_FAILURE;
if (MONITOR_ON(pAd))
{
send_monitor_packets(pAd, &RxCell);
break;
}
/* RT2870 invokes STARxDoneInterruptHandle() in rtusb_bulk.c */
// Check for all RxD errors
Status = RTMPCheckRxError(pAd, pHeader, pRxWI, pRxD);
// Handle the received frame
if (Status == NDIS_STATUS_SUCCESS)
{
switch (pHeader->FC.Type)
{
// CASE I, receive a DATA frame
case BTYPE_DATA:
{
// process DATA frame
STAHandleRxDataFrame(pAd, &RxCell);
}
break;
// CASE II, receive a MGMT frame
case BTYPE_MGMT:
{
STAHandleRxMgmtFrame(pAd, &RxCell);
}
break;
// CASE III. receive a CNTL frame
case BTYPE_CNTL:
{
STAHandleRxControlFrame(pAd, &RxCell);
}
break;
// discard other type
default:
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
break;
}
}
else
{
pAd->Counters8023.RxErrors++;
// discard this frame
RELEASE_NDIS_PACKET(pAd, pRxPacket, NDIS_STATUS_FAILURE);
}
}
return bReschedule;
}
/*
========================================================================
Routine Description:
Arguments:
pAd Pointer to our adapter
IRQL = DISPATCH_LEVEL
========================================================================
*/
VOID RTMPHandleTwakeupInterrupt(
IN PRTMP_ADAPTER pAd)
{
AsicForceWakeup(pAd, FALSE);
}
/*
========================================================================
Routine Description:
Early checking and OS-depened parsing for Tx packet send to our STA driver.
Arguments:
NDIS_HANDLE MiniportAdapterContext Pointer refer to the device handle, i.e., the pAd.
PPNDIS_PACKET ppPacketArray The packet array need to do transmission.
UINT NumberOfPackets Number of packet in packet array.
Return Value:
NONE
Note:
This function do early checking and classification for send-out packet.
You only can put OS-depened & STA related code in here.
========================================================================
*/
VOID STASendPackets(
IN NDIS_HANDLE MiniportAdapterContext,
IN PPNDIS_PACKET ppPacketArray,
IN UINT NumberOfPackets)
{
UINT Index;
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) MiniportAdapterContext;
PNDIS_PACKET pPacket;
BOOLEAN allowToSend = FALSE;
for (Index = 0; Index < NumberOfPackets; Index++)
{
pPacket = ppPacketArray[Index];
do
{
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) ||
RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
{
// Drop send request since hardware is in reset state
break;
}
else if (!INFRA_ON(pAd) && !ADHOC_ON(pAd))
{
// Drop send request since there are no physical connection yet
break;
}
else
{
// Record that orignal packet source is from NDIS layer,so that
// later on driver knows how to release this NDIS PACKET
RTMP_SET_PACKET_WCID(pPacket, 0); // this field is useless when in STA mode
RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
NDIS_SET_PACKET_STATUS(pPacket, NDIS_STATUS_PENDING);
pAd->RalinkCounters.PendingNdisPacketCount++;
allowToSend = TRUE;
}
} while(FALSE);
if (allowToSend == TRUE)
STASendPacket(pAd, pPacket);
else
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
}
// Dequeue outgoing frames from TxSwQueue[] and process it
RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS);
}
/*
========================================================================
Routine Description:
This routine is used to do packet parsing and classification for Tx packet
to STA device, and it will en-queue packets to our TxSwQueue depends on AC
class.
Arguments:
pAd Pointer to our adapter
pPacket Pointer to send packet
Return Value:
NDIS_STATUS_SUCCESS If succes to queue the packet into TxSwQueue.
NDIS_STATUS_FAILURE If failed to do en-queue.
Note:
You only can put OS-indepened & STA related code in here.
========================================================================
*/
NDIS_STATUS STASendPacket(
IN PRTMP_ADAPTER pAd,
IN PNDIS_PACKET pPacket)
{
PACKET_INFO PacketInfo;
PUCHAR pSrcBufVA;
UINT SrcBufLen;
UINT AllowFragSize;
UCHAR NumberOfFrag;
UCHAR QueIdx, UserPriority;
MAC_TABLE_ENTRY *pEntry = NULL;
unsigned int IrqFlags;
UCHAR FlgIsIP = 0;
UCHAR Rate;
// Prepare packet information structure for buffer descriptor
// chained within a single NDIS packet.
RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen);
if (pSrcBufVA == NULL)
{
DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> pSrcBufVA == NULL !!!SrcBufLen=%x\n",SrcBufLen));
// Resourece is low, system did not allocate virtual address
// return NDIS_STATUS_FAILURE directly to upper layer
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
}
if (SrcBufLen < 14)
{
DBGPRINT(RT_DEBUG_ERROR,("STASendPacket --> Ndis Packet buffer error !!!\n"));
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return (NDIS_STATUS_FAILURE);
}
// In HT rate adhoc mode, A-MPDU is often used. So need to lookup BA Table and MAC Entry.
// Note multicast packets in adhoc also use BSSID_WCID index.
{
if(INFRA_ON(pAd))
{
{
pEntry = &pAd->MacTab.Content[BSSID_WCID];
RTMP_SET_PACKET_WCID(pPacket, BSSID_WCID);
Rate = pAd->CommonCfg.TxRate;
}
}
else if (ADHOC_ON(pAd))
{
if (*pSrcBufVA & 0x01)
{
RTMP_SET_PACKET_WCID(pPacket, MCAST_WCID);
pEntry = &pAd->MacTab.Content[MCAST_WCID];
}
else
{
pEntry = MacTableLookup(pAd, pSrcBufVA);
}
Rate = pAd->CommonCfg.TxRate;
}
}
if (!pEntry)
{
DBGPRINT(RT_DEBUG_ERROR,("STASendPacket->Cannot find pEntry(%2x:%2x:%2x:%2x:%2x:%2x) in MacTab!\n", PRINT_MAC(pSrcBufVA)));
// Resourece is low, system did not allocate virtual address
// return NDIS_STATUS_FAILURE directly to upper layer
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
}
if (ADHOC_ON(pAd)
)
{
RTMP_SET_PACKET_WCID(pPacket, (UCHAR)pEntry->Aid);
}
//
// Check the Ethernet Frame type of this packet, and set the RTMP_SET_PACKET_SPECIFIC flags.
// Here we set the PACKET_SPECIFIC flags(LLC, VLAN, DHCP/ARP, EAPOL).
RTMPCheckEtherType(pAd, pPacket);
//
// WPA 802.1x secured port control - drop all non-802.1x frame before port secured
//
if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
|| (pAd->StaCfg.IEEE8021X == TRUE)
)
&& ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) || (pAd->StaCfg.MicErrCnt >= 2))
&& (RTMP_GET_PACKET_EAPOL(pPacket)== FALSE)
)
{
DBGPRINT(RT_DEBUG_TRACE,("STASendPacket --> Drop packet before port secured !!!\n"));
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return (NDIS_STATUS_FAILURE);
}
// STEP 1. Decide number of fragments required to deliver this MSDU.
// The estimation here is not very accurate because difficult to
// take encryption overhead into consideration here. The result
// "NumberOfFrag" is then just used to pre-check if enough free
// TXD are available to hold this MSDU.
if (*pSrcBufVA & 0x01) // fragmentation not allowed on multicast & broadcast
NumberOfFrag = 1;
else if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_AGGREGATION_INUSED))
NumberOfFrag = 1; // Aggregation overwhelms fragmentation
else if (CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_AMSDU_INUSED))
NumberOfFrag = 1; // Aggregation overwhelms fragmentation
else if ((pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTMIX) || (pAd->StaCfg.HTPhyMode.field.MODE == MODE_HTGREENFIELD))
NumberOfFrag = 1; // MIMO RATE overwhelms fragmentation
else
{
// The calculated "NumberOfFrag" is a rough estimation because of various
// encryption/encapsulation overhead not taken into consideration. This number is just
// used to make sure enough free TXD are available before fragmentation takes place.
// In case the actual required number of fragments of an NDIS packet
// excceeds "NumberOfFrag"caculated here and not enough free TXD available, the
// last fragment (i.e. last MPDU) will be dropped in RTMPHardTransmit() due to out of
// resource, and the NDIS packet will be indicated NDIS_STATUS_FAILURE. This should
// rarely happen and the penalty is just like a TX RETRY fail. Affordable.
AllowFragSize = (pAd->CommonCfg.FragmentThreshold) - LENGTH_802_11 - LENGTH_CRC;
NumberOfFrag = ((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) / AllowFragSize) + 1;
// To get accurate number of fragmentation, Minus 1 if the size just match to allowable fragment size
if (((PacketInfo.TotalPacketLength - LENGTH_802_3 + LENGTH_802_1_H) % AllowFragSize) == 0)
{
NumberOfFrag--;
}
}
// Save fragment number to Ndis packet reserved field
RTMP_SET_PACKET_FRAGMENTS(pPacket, NumberOfFrag);
// STEP 2. Check the requirement of RTS:
// If multiple fragment required, RTS is required only for the first fragment
// if the fragment size large than RTS threshold
// For RT28xx, Let ASIC send RTS/CTS
RTMP_SET_PACKET_RTS(pPacket, 0);
RTMP_SET_PACKET_TXRATE(pPacket, pAd->CommonCfg.TxRate);
//
// STEP 3. Traffic classification. outcome = <UserPriority, QueIdx>
//
UserPriority = 0;
QueIdx = QID_AC_BE;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) &&
CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_WMM_CAPABLE))
{
USHORT Protocol;
UCHAR LlcSnapLen = 0, Byte0, Byte1;
do
{
// get Ethernet protocol field
Protocol = (USHORT)((pSrcBufVA[12] << 8) + pSrcBufVA[13]);
if (Protocol <= 1500)
{
// get Ethernet protocol field from LLC/SNAP
if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + 6, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS)
break;
Protocol = (USHORT)((Byte0 << 8) + Byte1);
LlcSnapLen = 8;
}
// always AC_BE for non-IP packet
if (Protocol != 0x0800)
break;
// get IP header
if (Sniff2BytesFromNdisBuffer(PacketInfo.pFirstBuffer, LENGTH_802_3 + LlcSnapLen, &Byte0, &Byte1) != NDIS_STATUS_SUCCESS)
break;
// return AC_BE if packet is not IPv4
if ((Byte0 & 0xf0) != 0x40)
break;
FlgIsIP = 1;
UserPriority = (Byte1 & 0xe0) >> 5;
QueIdx = MapUserPriorityToAccessCategory[UserPriority];
// TODO: have to check ACM bit. apply TSPEC if ACM is ON
// TODO: downgrade UP & QueIdx before passing ACM
if (pAd->CommonCfg.APEdcaParm.bACM[QueIdx])
{
UserPriority = 0;
QueIdx = QID_AC_BE;
}
} while (FALSE);
}
RTMP_SET_PACKET_UP(pPacket, UserPriority);
// Make sure SendTxWait queue resource won't be used by other threads
RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
if (pAd->TxSwQueue[QueIdx].Number >= MAX_PACKETS_IN_QUEUE)
{
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
}
else
{
InsertTailQueue(&pAd->TxSwQueue[QueIdx], PACKET_TO_QUEUE_ENTRY(pPacket));
}
RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
if ((pAd->CommonCfg.BACapability.field.AutoBA == TRUE)&&
IS_HT_STA(pEntry))
{
if (((pEntry->TXBAbitmap & (1<<UserPriority)) == 0) &&
((pEntry->BADeclineBitmap & (1<<UserPriority)) == 0) &&
(pEntry->PortSecured == WPA_802_1X_PORT_SECURED)
// For IOT compatibility, if
// 1. It is Ralink chip or
// 2. It is OPEN or AES mode,
// then BA session can be bulit.
&& ((pEntry->ValidAsCLI && pAd->MlmeAux.APRalinkIe != 0x0) ||
(pEntry->WepStatus == Ndis802_11WEPDisabled || pEntry->WepStatus == Ndis802_11Encryption3Enabled))
)
{
BAOriSessionSetUp(pAd, pEntry, 0, 0, 10, FALSE);
}
}
pAd->RalinkCounters.OneSecOsTxCount[QueIdx]++; // TODO: for debug only. to be removed
return NDIS_STATUS_SUCCESS;
}
/*
========================================================================
Routine Description:
This subroutine will scan through releative ring descriptor to find
out avaliable free ring descriptor and compare with request size.
Arguments:
pAd Pointer to our adapter
QueIdx Selected TX Ring
Return Value:
NDIS_STATUS_FAILURE Not enough free descriptor
NDIS_STATUS_SUCCESS Enough free descriptor
IRQL = PASSIVE_LEVEL
IRQL = DISPATCH_LEVEL
Note:
========================================================================
*/
#ifdef RT2870
/*
Actually, this function used to check if the TxHardware Queue still has frame need to send.
If no frame need to send, go to sleep, else, still wake up.
*/
NDIS_STATUS RTMPFreeTXDRequest(
IN PRTMP_ADAPTER pAd,
IN UCHAR QueIdx,
IN UCHAR NumberRequired,
IN PUCHAR FreeNumberIs)
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
unsigned long IrqFlags;
HT_TX_CONTEXT *pHTTXContext;
switch (QueIdx)
{
case QID_AC_BK:
case QID_AC_BE:
case QID_AC_VI:
case QID_AC_VO:
case QID_HCCA:
{
pHTTXContext = &pAd->TxContext[QueIdx];
RTMP_IRQ_LOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
if ((pHTTXContext->CurWritePosition != pHTTXContext->ENextBulkOutPosition) ||
(pHTTXContext->IRPPending == TRUE))
{
Status = NDIS_STATUS_FAILURE;
}
else
{
Status = NDIS_STATUS_SUCCESS;
}
RTMP_IRQ_UNLOCK(&pAd->TxContextQueueLock[QueIdx], IrqFlags);
}
break;
case QID_MGMT:
if (pAd->MgmtRing.TxSwFreeIdx != MGMT_RING_SIZE)
Status = NDIS_STATUS_FAILURE;
else
Status = NDIS_STATUS_SUCCESS;
break;
default:
DBGPRINT(RT_DEBUG_ERROR,("RTMPFreeTXDRequest::Invalid QueIdx(=%d)\n", QueIdx));
break;
}
return (Status);
}
#endif // RT2870 //
VOID RTMPSendDisassociationFrame(
IN PRTMP_ADAPTER pAd)
{
}
VOID RTMPSendNullFrame(
IN PRTMP_ADAPTER pAd,
IN UCHAR TxRate,
IN BOOLEAN bQosNull)
{
UCHAR NullFrame[48];
ULONG Length;
PHEADER_802_11 pHeader_802_11;
// WPA 802.1x secured port control
if (((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) ||
(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
|| (pAd->StaCfg.IEEE8021X == TRUE)
) &&
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED))
{
return;
}
NdisZeroMemory(NullFrame, 48);
Length = sizeof(HEADER_802_11);
pHeader_802_11 = (PHEADER_802_11) NullFrame;
pHeader_802_11->FC.Type = BTYPE_DATA;
pHeader_802_11->FC.SubType = SUBTYPE_NULL_FUNC;
pHeader_802_11->FC.ToDs = 1;
COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid);
COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid);
if (pAd->CommonCfg.bAPSDForcePowerSave)
{
pHeader_802_11->FC.PwrMgmt = PWR_SAVE;
}
else
{
pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE) ? 1: 0;
}
pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + RTMPCalcDuration(pAd, TxRate, 14);
pAd->Sequence++;
pHeader_802_11->Sequence = pAd->Sequence;
// Prepare QosNull function frame
if (bQosNull)
{
pHeader_802_11->FC.SubType = SUBTYPE_QOS_NULL;
// copy QOS control bytes
NullFrame[Length] = 0;
NullFrame[Length+1] = 0;
Length += 2;// if pad with 2 bytes for alignment, APSD will fail
}
HAL_KickOutNullFrameTx(pAd, 0, NullFrame, Length);
}
// IRQL = DISPATCH_LEVEL
VOID RTMPSendRTSFrame(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pDA,
IN unsigned int NextMpduSize,
IN UCHAR TxRate,
IN UCHAR RTSRate,
IN USHORT AckDuration,
IN UCHAR QueIdx,
IN UCHAR FrameGap)
{
}
// --------------------------------------------------------
// FIND ENCRYPT KEY AND DECIDE CIPHER ALGORITHM
// Find the WPA key, either Group or Pairwise Key
// LEAP + TKIP also use WPA key.
// --------------------------------------------------------
// Decide WEP bit and cipher suite to be used. Same cipher suite should be used for whole fragment burst
// In Cisco CCX 2.0 Leap Authentication
// WepStatus is Ndis802_11Encryption1Enabled but the key will use PairwiseKey
// Instead of the SharedKey, SharedKey Length may be Zero.
VOID STAFindCipherAlgorithm(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
NDIS_802_11_ENCRYPTION_STATUS Cipher; // To indicate cipher used for this packet
UCHAR CipherAlg = CIPHER_NONE; // cipher alogrithm
UCHAR KeyIdx = 0xff;
PUCHAR pSrcBufVA;
PCIPHER_KEY pKey = NULL;
pSrcBufVA = GET_OS_PKT_DATAPTR(pTxBlk->pPacket);
{
// Select Cipher
if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd)))
Cipher = pAd->StaCfg.GroupCipher; // Cipher for Multicast or Broadcast
else
Cipher = pAd->StaCfg.PairCipher; // Cipher for Unicast
if (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket))
{
ASSERT(pAd->SharedKey[BSS0][0].CipherAlg <= CIPHER_CKIP128);
// 4-way handshaking frame must be clear
if (!(TX_BLK_TEST_FLAG(pTxBlk, fTX_bClearEAPFrame)) && (pAd->SharedKey[BSS0][0].CipherAlg) &&
(pAd->SharedKey[BSS0][0].KeyLen))
{
CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg;
KeyIdx = 0;
}
}
else if (Cipher == Ndis802_11Encryption1Enabled)
{
KeyIdx = pAd->StaCfg.DefaultKeyId;
}
else if ((Cipher == Ndis802_11Encryption2Enabled) ||
(Cipher == Ndis802_11Encryption3Enabled))
{
if ((*pSrcBufVA & 0x01) && (ADHOC_ON(pAd))) // multicast
KeyIdx = pAd->StaCfg.DefaultKeyId;
else if (pAd->SharedKey[BSS0][0].KeyLen)
KeyIdx = 0;
else
KeyIdx = pAd->StaCfg.DefaultKeyId;
}
if (KeyIdx == 0xff)
CipherAlg = CIPHER_NONE;
else if ((Cipher == Ndis802_11EncryptionDisabled) || (pAd->SharedKey[BSS0][KeyIdx].KeyLen == 0))
CipherAlg = CIPHER_NONE;
else if ( pAd->StaCfg.WpaSupplicantUP &&
(Cipher == Ndis802_11Encryption1Enabled) &&
(pAd->StaCfg.IEEE8021X == TRUE) &&
(pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED))
CipherAlg = CIPHER_NONE;
else
{
//Header_802_11.FC.Wep = 1;
CipherAlg = pAd->SharedKey[BSS0][KeyIdx].CipherAlg;
pKey = &pAd->SharedKey[BSS0][KeyIdx];
}
}
pTxBlk->CipherAlg = CipherAlg;
pTxBlk->pKey = pKey;
}
VOID STABuildCommon802_11Header(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
HEADER_802_11 *pHeader_802_11;
//
// MAKE A COMMON 802.11 HEADER
//
// normal wlan header size : 24 octets
pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11);
pHeader_802_11 = (HEADER_802_11 *) &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE];
NdisZeroMemory(pHeader_802_11, sizeof(HEADER_802_11));
pHeader_802_11->FC.FrDs = 0;
pHeader_802_11->FC.Type = BTYPE_DATA;
pHeader_802_11->FC.SubType = ((TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM)) ? SUBTYPE_QDATA : SUBTYPE_DATA);
if (pTxBlk->pMacEntry)
{
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bForceNonQoS))
{
pHeader_802_11->Sequence = pTxBlk->pMacEntry->NonQosDataSeq;
pTxBlk->pMacEntry->NonQosDataSeq = (pTxBlk->pMacEntry->NonQosDataSeq+1) & MAXSEQ;
}
else
{
pHeader_802_11->Sequence = pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority];
pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority] = (pTxBlk->pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ;
}
}
else
{
pHeader_802_11->Sequence = pAd->Sequence;
pAd->Sequence = (pAd->Sequence+1) & MAXSEQ; // next sequence
}
pHeader_802_11->Frag = 0;
pHeader_802_11->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData);
{
if (INFRA_ON(pAd))
{
{
COPY_MAC_ADDR(pHeader_802_11->Addr1, pAd->CommonCfg.Bssid);
COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(pHeader_802_11->Addr3, pTxBlk->pSrcBufHeader);
pHeader_802_11->FC.ToDs = 1;
}
}
else if (ADHOC_ON(pAd))
{
COPY_MAC_ADDR(pHeader_802_11->Addr1, pTxBlk->pSrcBufHeader);
COPY_MAC_ADDR(pHeader_802_11->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(pHeader_802_11->Addr3, pAd->CommonCfg.Bssid);
pHeader_802_11->FC.ToDs = 0;
}
}
if (pTxBlk->CipherAlg != CIPHER_NONE)
pHeader_802_11->FC.Wep = 1;
// -----------------------------------------------------------------
// STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later.
// -----------------------------------------------------------------
if (pAd->CommonCfg.bAPSDForcePowerSave)
pHeader_802_11->FC.PwrMgmt = PWR_SAVE;
else
pHeader_802_11->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE);
}
VOID STABuildCache802_11Header(
IN RTMP_ADAPTER *pAd,
IN TX_BLK *pTxBlk,
IN UCHAR *pHeader)
{
MAC_TABLE_ENTRY *pMacEntry;
PHEADER_802_11 pHeader80211;
pHeader80211 = (PHEADER_802_11)pHeader;
pMacEntry = pTxBlk->pMacEntry;
//
// Update the cached 802.11 HEADER
//
// normal wlan header size : 24 octets
pTxBlk->MpduHeaderLen = sizeof(HEADER_802_11);
// More Bit
pHeader80211->FC.MoreData = TX_BLK_TEST_FLAG(pTxBlk, fTX_bMoreData);
// Sequence
pHeader80211->Sequence = pMacEntry->TxSeq[pTxBlk->UserPriority];
pMacEntry->TxSeq[pTxBlk->UserPriority] = (pMacEntry->TxSeq[pTxBlk->UserPriority]+1) & MAXSEQ;
{
// The addr3 of normal packet send from DS is Dest Mac address.
if (ADHOC_ON(pAd))
COPY_MAC_ADDR(pHeader80211->Addr3, pAd->CommonCfg.Bssid);
else
COPY_MAC_ADDR(pHeader80211->Addr3, pTxBlk->pSrcBufHeader);
}
// -----------------------------------------------------------------
// STEP 2. MAKE A COMMON 802.11 HEADER SHARED BY ENTIRE FRAGMENT BURST. Fill sequence later.
// -----------------------------------------------------------------
if (pAd->CommonCfg.bAPSDForcePowerSave)
pHeader80211->FC.PwrMgmt = PWR_SAVE;
else
pHeader80211->FC.PwrMgmt = (pAd->StaCfg.Psm == PWR_SAVE);
}
static inline PUCHAR STA_Build_ARalink_Frame_Header(
IN RTMP_ADAPTER *pAd,
IN TX_BLK *pTxBlk)
{
PUCHAR pHeaderBufPtr;
HEADER_802_11 *pHeader_802_11;
PNDIS_PACKET pNextPacket;
UINT32 nextBufLen;
PQUEUE_ENTRY pQEntry;
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE];
pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr;
// steal "order" bit to mark "aggregation"
pHeader_802_11->FC.Order = 1;
// skip common header
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM))
{
//
// build QOS Control bytes
//
*pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F);
*(pHeaderBufPtr+1) = 0;
pHeaderBufPtr +=2;
pTxBlk->MpduHeaderLen += 2;
}
// padding at front of LLC header. LLC header should at 4-bytes aligment.
pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr;
pHeaderBufPtr = (PCHAR)ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen);
// For RA Aggregation,
// put the 2nd MSDU length(extra 2-byte field) after QOS_CONTROL in little endian format
pQEntry = pTxBlk->TxPacketList.Head;
pNextPacket = QUEUE_ENTRY_TO_PKT(pQEntry);
nextBufLen = GET_OS_PKT_LEN(pNextPacket);
if (RTMP_GET_PACKET_VLAN(pNextPacket))
nextBufLen -= LENGTH_802_1Q;
*pHeaderBufPtr = (UCHAR)nextBufLen & 0xff;
*(pHeaderBufPtr+1) = (UCHAR)(nextBufLen >> 8);
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += 2;
return pHeaderBufPtr;
}
static inline PUCHAR STA_Build_AMSDU_Frame_Header(
IN RTMP_ADAPTER *pAd,
IN TX_BLK *pTxBlk)
{
PUCHAR pHeaderBufPtr;//, pSaveBufPtr;
HEADER_802_11 *pHeader_802_11;
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE];
pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr;
// skip common header
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
//
// build QOS Control bytes
//
*pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F);
//
// A-MSDU packet
//
*pHeaderBufPtr |= 0x80;
*(pHeaderBufPtr+1) = 0;
pHeaderBufPtr +=2;
pTxBlk->MpduHeaderLen += 2;
//pSaveBufPtr = pHeaderBufPtr;
//
// padding at front of LLC header
// LLC header should locate at 4-octets aligment
//
// @@@ MpduHeaderLen excluding padding @@@
//
pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr;
pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen);
return pHeaderBufPtr;
}
VOID STA_AMPDU_Frame_Tx(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
HEADER_802_11 *pHeader_802_11;
PUCHAR pHeaderBufPtr;
USHORT FreeNumber;
MAC_TABLE_ENTRY *pMacEntry;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
ASSERT(pTxBlk);
while(pTxBlk->TxPacketList.Head)
{
pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList);
pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry);
if ( RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE)
{
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE);
continue;
}
bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE);
pMacEntry = pTxBlk->pMacEntry;
if (pMacEntry->isCached)
{
// NOTE: Please make sure the size of pMacEntry->CachedBuf[] is smaller than pTxBlk->HeaderBuf[]!!!!
NdisMoveMemory((PUCHAR)&pTxBlk->HeaderBuf[TXINFO_SIZE], (PUCHAR)&pMacEntry->CachedBuf[0], TXWI_SIZE + sizeof(HEADER_802_11));
pHeaderBufPtr = (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE]);
STABuildCache802_11Header(pAd, pTxBlk, pHeaderBufPtr);
}
else
{
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE];
}
pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr;
// skip common header
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
//
// build QOS Control bytes
//
*pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F);
*(pHeaderBufPtr+1) = 0;
pHeaderBufPtr +=2;
pTxBlk->MpduHeaderLen += 2;
//
// build HTC+
// HTC control filed following QoS field
//
if ((pAd->CommonCfg.bRdg == TRUE) && CLIENT_STATUS_TEST_FLAG(pTxBlk->pMacEntry, fCLIENT_STATUS_RDG_CAPABLE))
{
if (pMacEntry->isCached == FALSE)
{
// mark HTC bit
pHeader_802_11->FC.Order = 1;
NdisZeroMemory(pHeaderBufPtr, 4);
*(pHeaderBufPtr+3) |= 0x80;
}
pHeaderBufPtr += 4;
pTxBlk->MpduHeaderLen += 4;
}
//pTxBlk->MpduHeaderLen = pHeaderBufPtr - pTxBlk->HeaderBuf - TXWI_SIZE - TXINFO_SIZE;
ASSERT(pTxBlk->MpduHeaderLen >= 24);
// skip 802.3 header
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3;
pTxBlk->SrcBufLen -= LENGTH_802_3;
// skip vlan tag
if (bVLANPkt)
{
pTxBlk->pSrcBufData += LENGTH_802_1Q;
pTxBlk->SrcBufLen -= LENGTH_802_1Q;
}
//
// padding at front of LLC header
// LLC header should locate at 4-octets aligment
//
// @@@ MpduHeaderLen excluding padding @@@
//
pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr;
pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen);
{
//
// Insert LLC-SNAP encapsulation - 8 octets
//
EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap);
if (pTxBlk->pExtraLlcSnapEncap)
{
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6);
pHeaderBufPtr += 6;
// get 2 octets (TypeofLen)
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2);
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += LENGTH_802_1_H;
}
}
if (pMacEntry->isCached)
{
RTMPWriteTxWI_Cache(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
}
else
{
RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
NdisZeroMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), sizeof(pMacEntry->CachedBuf));
NdisMoveMemory((PUCHAR)(&pMacEntry->CachedBuf[0]), (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), (pHeaderBufPtr - (PUCHAR)(&pTxBlk->HeaderBuf[TXINFO_SIZE])));
pMacEntry->isCached = TRUE;
}
// calculate Transmitted AMPDU count and ByteCount
{
pAd->RalinkCounters.TransmittedMPDUsInAMPDUCount.u.LowPart ++;
pAd->RalinkCounters.TransmittedOctetsInAMPDUCount.QuadPart += pTxBlk->SrcBufLen;
}
//FreeNumber = GET_TXRING_FREENO(pAd, QueIdx);
HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber);
//
// Kick out Tx
//
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
}
}
VOID STA_AMSDU_Frame_Tx(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
PUCHAR pHeaderBufPtr;
USHORT FreeNumber;
USHORT subFramePayloadLen = 0; // AMSDU Subframe length without AMSDU-Header / Padding.
USHORT totalMPDUSize=0;
UCHAR *subFrameHeader;
UCHAR padding = 0;
USHORT FirstTx = 0, LastTxIdx = 0;
BOOLEAN bVLANPkt;
int frameNum = 0;
PQUEUE_ENTRY pQEntry;
ASSERT(pTxBlk);
ASSERT((pTxBlk->TxPacketList.Number > 1));
while(pTxBlk->TxPacketList.Head)
{
pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList);
pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry);
if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE)
{
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE);
continue;
}
bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE);
// skip 802.3 header
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3;
pTxBlk->SrcBufLen -= LENGTH_802_3;
// skip vlan tag
if (bVLANPkt)
{
pTxBlk->pSrcBufData += LENGTH_802_1Q;
pTxBlk->SrcBufLen -= LENGTH_802_1Q;
}
if (frameNum == 0)
{
pHeaderBufPtr = STA_Build_AMSDU_Frame_Header(pAd, pTxBlk);
// NOTE: TxWI->MPDUtotalByteCount will be updated after final frame was handled.
RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
}
else
{
pHeaderBufPtr = &pTxBlk->HeaderBuf[0];
padding = ROUND_UP(LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen, 4) - (LENGTH_AMSDU_SUBFRAMEHEAD + subFramePayloadLen);
NdisZeroMemory(pHeaderBufPtr, padding + LENGTH_AMSDU_SUBFRAMEHEAD);
pHeaderBufPtr += padding;
pTxBlk->MpduHeaderLen = padding;
}
//
// A-MSDU subframe
// DA(6)+SA(6)+Length(2) + LLC/SNAP Encap
//
subFrameHeader = pHeaderBufPtr;
subFramePayloadLen = pTxBlk->SrcBufLen;
NdisMoveMemory(subFrameHeader, pTxBlk->pSrcBufHeader, 12);
pHeaderBufPtr += LENGTH_AMSDU_SUBFRAMEHEAD;
pTxBlk->MpduHeaderLen += LENGTH_AMSDU_SUBFRAMEHEAD;
//
// Insert LLC-SNAP encapsulation - 8 octets
//
EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap);
subFramePayloadLen = pTxBlk->SrcBufLen;
if (pTxBlk->pExtraLlcSnapEncap)
{
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6);
pHeaderBufPtr += 6;
// get 2 octets (TypeofLen)
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2);
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += LENGTH_802_1_H;
subFramePayloadLen += LENGTH_802_1_H;
}
// update subFrame Length field
subFrameHeader[12] = (subFramePayloadLen & 0xFF00) >> 8;
subFrameHeader[13] = subFramePayloadLen & 0xFF;
totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen;
if (frameNum ==0)
FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber);
else
LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber);
frameNum++;
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
// calculate Transmitted AMSDU Count and ByteCount
{
pAd->RalinkCounters.TransmittedAMSDUCount.u.LowPart ++;
pAd->RalinkCounters.TransmittedOctetsInAMSDU.QuadPart += totalMPDUSize;
}
}
HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx);
HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx);
//
// Kick out Tx
//
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
}
VOID STA_Legacy_Frame_Tx(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
HEADER_802_11 *pHeader_802_11;
PUCHAR pHeaderBufPtr;
USHORT FreeNumber;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
ASSERT(pTxBlk);
pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList);
pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry);
if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE)
{
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE);
return;
}
if (pTxBlk->TxFrameType == TX_MCAST_FRAME)
{
INC_COUNTER64(pAd->WlanCounters.MulticastTransmittedFrameCount);
}
if (RTMP_GET_PACKET_RTS(pTxBlk->pPacket))
TX_BLK_SET_FLAG(pTxBlk, fTX_bRtsRequired);
else
TX_BLK_CLEAR_FLAG(pTxBlk, fTX_bRtsRequired);
bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE);
if (pTxBlk->TxRate < pAd->CommonCfg.MinTxRate)
pTxBlk->TxRate = pAd->CommonCfg.MinTxRate;
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
// skip 802.3 header
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3;
pTxBlk->SrcBufLen -= LENGTH_802_3;
// skip vlan tag
if (bVLANPkt)
{
pTxBlk->pSrcBufData += LENGTH_802_1Q;
pTxBlk->SrcBufLen -= LENGTH_802_1Q;
}
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE];
pHeader_802_11 = (HEADER_802_11 *) pHeaderBufPtr;
// skip common header
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM))
{
//
// build QOS Control bytes
//
*pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F);
*(pHeaderBufPtr+1) = 0;
pHeaderBufPtr +=2;
pTxBlk->MpduHeaderLen += 2;
}
// The remaining content of MPDU header should locate at 4-octets aligment
pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr;
pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen);
{
//
// Insert LLC-SNAP encapsulation - 8 octets
//
//
// if original Ethernet frame contains no LLC/SNAP,
// then an extra LLC/SNAP encap is required
//
EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap);
if (pTxBlk->pExtraLlcSnapEncap)
{
UCHAR vlan_size;
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6);
pHeaderBufPtr += 6;
// skip vlan tag
vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0;
// get 2 octets (TypeofLen)
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2);
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += LENGTH_802_1_H;
}
}
//
// prepare for TXWI
// use Wcid as Key Index
//
RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
//FreeNumber = GET_TXRING_FREENO(pAd, QueIdx);
HAL_WriteTxResource(pAd, pTxBlk, TRUE, &FreeNumber);
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
//
// Kick out Tx
//
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
}
VOID STA_ARalink_Frame_Tx(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk)
{
PUCHAR pHeaderBufPtr;
USHORT FreeNumber;
USHORT totalMPDUSize=0;
USHORT FirstTx, LastTxIdx;
int frameNum = 0;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
ASSERT(pTxBlk);
ASSERT((pTxBlk->TxPacketList.Number== 2));
FirstTx = LastTxIdx = 0; // Is it ok init they as 0?
while(pTxBlk->TxPacketList.Head)
{
pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList);
pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry);
if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE)
{
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE);
continue;
}
bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE);
// skip 802.3 header
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3;
pTxBlk->SrcBufLen -= LENGTH_802_3;
// skip vlan tag
if (bVLANPkt)
{
pTxBlk->pSrcBufData += LENGTH_802_1Q;
pTxBlk->SrcBufLen -= LENGTH_802_1Q;
}
if (frameNum == 0)
{ // For first frame, we need to create the 802.11 header + padding(optional) + RA-AGG-LEN + SNAP Header
pHeaderBufPtr = STA_Build_ARalink_Frame_Header(pAd, pTxBlk);
// It's ok write the TxWI here, because the TxWI->MPDUtotalByteCount
// will be updated after final frame was handled.
RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
//
// Insert LLC-SNAP encapsulation - 8 octets
//
EXTRA_LLCSNAP_ENCAP_FROM_PKT_OFFSET(pTxBlk->pSrcBufData-2, pTxBlk->pExtraLlcSnapEncap);
if (pTxBlk->pExtraLlcSnapEncap)
{
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6);
pHeaderBufPtr += 6;
// get 2 octets (TypeofLen)
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2);
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += LENGTH_802_1_H;
}
}
else
{ // For second aggregated frame, we need create the 802.3 header to headerBuf, because PCI will copy it to SDPtr0.
pHeaderBufPtr = &pTxBlk->HeaderBuf[0];
pTxBlk->MpduHeaderLen = 0;
// A-Ralink sub-sequent frame header is the same as 802.3 header.
// DA(6)+SA(6)+FrameType(2)
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader, 12);
pHeaderBufPtr += 12;
// get 2 octets (TypeofLen)
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufData-2, 2);
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen = LENGTH_ARALINK_SUBFRAMEHEAD;
}
totalMPDUSize += pTxBlk->MpduHeaderLen + pTxBlk->SrcBufLen;
//FreeNumber = GET_TXRING_FREENO(pAd, QueIdx);
if (frameNum ==0)
FirstTx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber);
else
LastTxIdx = HAL_WriteMultiTxResource(pAd, pTxBlk, frameNum, &FreeNumber);
frameNum++;
pAd->RalinkCounters.OneSecTxAggregationCount++;
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
}
HAL_FinalWriteTxResource(pAd, pTxBlk, totalMPDUSize, FirstTx);
HAL_LastTxIdx(pAd, pTxBlk->QueIdx, LastTxIdx);
//
// Kick out Tx
//
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
}
VOID STA_Fragment_Frame_Tx(
IN RTMP_ADAPTER *pAd,
IN TX_BLK *pTxBlk)
{
HEADER_802_11 *pHeader_802_11;
PUCHAR pHeaderBufPtr;
USHORT FreeNumber;
UCHAR fragNum = 0;
PACKET_INFO PacketInfo;
USHORT EncryptionOverhead = 0;
UINT32 FreeMpduSize, SrcRemainingBytes;
USHORT AckDuration;
UINT NextMpduSize;
BOOLEAN bVLANPkt;
PQUEUE_ENTRY pQEntry;
ASSERT(pTxBlk);
pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList);
pTxBlk->pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry);
if (RTMP_FillTxBlkInfo(pAd, pTxBlk) != TRUE)
{
RELEASE_NDIS_PACKET(pAd, pTxBlk->pPacket, NDIS_STATUS_FAILURE);
return;
}
ASSERT(TX_BLK_TEST_FLAG(pTxBlk, fTX_bAllowFrag));
bVLANPkt = (RTMP_GET_PACKET_VLAN(pTxBlk->pPacket) ? TRUE : FALSE);
STAFindCipherAlgorithm(pAd, pTxBlk);
STABuildCommon802_11Header(pAd, pTxBlk);
if (pTxBlk->CipherAlg == CIPHER_TKIP)
{
pTxBlk->pPacket = duplicate_pkt_with_TKIP_MIC(pAd, pTxBlk->pPacket);
if (pTxBlk->pPacket == NULL)
return;
RTMP_QueryPacketInfo(pTxBlk->pPacket, &PacketInfo, &pTxBlk->pSrcBufHeader, &pTxBlk->SrcBufLen);
}
// skip 802.3 header
pTxBlk->pSrcBufData = pTxBlk->pSrcBufHeader + LENGTH_802_3;
pTxBlk->SrcBufLen -= LENGTH_802_3;
// skip vlan tag
if (bVLANPkt)
{
pTxBlk->pSrcBufData += LENGTH_802_1Q;
pTxBlk->SrcBufLen -= LENGTH_802_1Q;
}
pHeaderBufPtr = &pTxBlk->HeaderBuf[TXINFO_SIZE + TXWI_SIZE];
pHeader_802_11 = (HEADER_802_11 *)pHeaderBufPtr;
// skip common header
pHeaderBufPtr += pTxBlk->MpduHeaderLen;
if (TX_BLK_TEST_FLAG(pTxBlk, fTX_bWMM))
{
//
// build QOS Control bytes
//
*pHeaderBufPtr = (pTxBlk->UserPriority & 0x0F);
*(pHeaderBufPtr+1) = 0;
pHeaderBufPtr +=2;
pTxBlk->MpduHeaderLen += 2;
}
//
// padding at front of LLC header
// LLC header should locate at 4-octets aligment
//
pTxBlk->HdrPadLen = (ULONG)pHeaderBufPtr;
pHeaderBufPtr = (PCHAR) ROUND_UP(pHeaderBufPtr, 4);
pTxBlk->HdrPadLen = (ULONG)(pHeaderBufPtr - pTxBlk->HdrPadLen);
//
// Insert LLC-SNAP encapsulation - 8 octets
//
//
// if original Ethernet frame contains no LLC/SNAP,
// then an extra LLC/SNAP encap is required
//
EXTRA_LLCSNAP_ENCAP_FROM_PKT_START(pTxBlk->pSrcBufHeader, pTxBlk->pExtraLlcSnapEncap);
if (pTxBlk->pExtraLlcSnapEncap)
{
UCHAR vlan_size;
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pExtraLlcSnapEncap, 6);
pHeaderBufPtr += 6;
// skip vlan tag
vlan_size = (bVLANPkt) ? LENGTH_802_1Q : 0;
// get 2 octets (TypeofLen)
NdisMoveMemory(pHeaderBufPtr, pTxBlk->pSrcBufHeader+12+vlan_size, 2);
pHeaderBufPtr += 2;
pTxBlk->MpduHeaderLen += LENGTH_802_1_H;
}
// If TKIP is used and fragmentation is required. Driver has to
// append TKIP MIC at tail of the scatter buffer
// MAC ASIC will only perform IV/EIV/ICV insertion but no TKIP MIC
if (pTxBlk->CipherAlg == CIPHER_TKIP)
{
// NOTE: DON'T refer the skb->len directly after following copy. Becasue the length is not adjust
// to correct lenght, refer to pTxBlk->SrcBufLen for the packet length in following progress.
NdisMoveMemory(pTxBlk->pSrcBufData + pTxBlk->SrcBufLen, &pAd->PrivateInfo.Tx.MIC[0], 8);
//skb_put((RTPKT_TO_OSPKT(pTxBlk->pPacket))->tail, 8);
pTxBlk->SrcBufLen += 8;
pTxBlk->TotalFrameLen += 8;
pTxBlk->CipherAlg = CIPHER_TKIP_NO_MIC;
}
//
// calcuate the overhead bytes that encryption algorithm may add. This
// affects the calculate of "duration" field
//
if ((pTxBlk->CipherAlg == CIPHER_WEP64) || (pTxBlk->CipherAlg == CIPHER_WEP128))
EncryptionOverhead = 8; //WEP: IV[4] + ICV[4];
else if (pTxBlk->CipherAlg == CIPHER_TKIP_NO_MIC)
EncryptionOverhead = 12;//TKIP: IV[4] + EIV[4] + ICV[4], MIC will be added to TotalPacketLength
else if (pTxBlk->CipherAlg == CIPHER_TKIP)
EncryptionOverhead = 20;//TKIP: IV[4] + EIV[4] + ICV[4] + MIC[8]
else if (pTxBlk->CipherAlg == CIPHER_AES)
EncryptionOverhead = 16; // AES: IV[4] + EIV[4] + MIC[8]
else
EncryptionOverhead = 0;
// decide how much time an ACK/CTS frame will consume in the air
AckDuration = RTMPCalcDuration(pAd, pAd->CommonCfg.ExpectedACKRate[pTxBlk->TxRate], 14);
// Init the total payload length of this frame.
SrcRemainingBytes = pTxBlk->SrcBufLen;
pTxBlk->TotalFragNum = 0xff;
do {
FreeMpduSize = pAd->CommonCfg.FragmentThreshold - LENGTH_CRC;
FreeMpduSize -= pTxBlk->MpduHeaderLen;
if (SrcRemainingBytes <= FreeMpduSize)
{ // this is the last or only fragment
pTxBlk->SrcBufLen = SrcRemainingBytes;
pHeader_802_11->FC.MoreFrag = 0;
pHeader_802_11->Duration = pAd->CommonCfg.Dsifs + AckDuration;
// Indicate the lower layer that this's the last fragment.
pTxBlk->TotalFragNum = fragNum;
}
else
{ // more fragment is required
pTxBlk->SrcBufLen = FreeMpduSize;
NextMpduSize = min(((UINT)SrcRemainingBytes - pTxBlk->SrcBufLen), ((UINT)pAd->CommonCfg.FragmentThreshold));
pHeader_802_11->FC.MoreFrag = 1;
pHeader_802_11->Duration = (3 * pAd->CommonCfg.Dsifs) + (2 * AckDuration) + RTMPCalcDuration(pAd, pTxBlk->TxRate, NextMpduSize + EncryptionOverhead);
}
if (fragNum == 0)
pTxBlk->FrameGap = IFS_HTTXOP;
else
pTxBlk->FrameGap = IFS_SIFS;
RTMPWriteTxWI_Data(pAd, (PTXWI_STRUC)(&pTxBlk->HeaderBuf[TXINFO_SIZE]), pTxBlk);
HAL_WriteFragTxResource(pAd, pTxBlk, fragNum, &FreeNumber);
pAd->RalinkCounters.KickTxCount++;
pAd->RalinkCounters.OneSecTxDoneCount++;
// Update the frame number, remaining size of the NDIS packet payload.
// space for 802.11 header.
if (fragNum == 0 && pTxBlk->pExtraLlcSnapEncap)
pTxBlk->MpduHeaderLen -= LENGTH_802_1_H;
fragNum++;
SrcRemainingBytes -= pTxBlk->SrcBufLen;
pTxBlk->pSrcBufData += pTxBlk->SrcBufLen;
pHeader_802_11->Frag++; // increase Frag #
}while(SrcRemainingBytes > 0);
//
// Kick out Tx
//
HAL_KickOutTx(pAd, pTxBlk, pTxBlk->QueIdx);
}
#define RELEASE_FRAMES_OF_TXBLK(_pAd, _pTxBlk, _pQEntry, _Status) \
while(_pTxBlk->TxPacketList.Head) \
{ \
_pQEntry = RemoveHeadQueue(&_pTxBlk->TxPacketList); \
RELEASE_NDIS_PACKET(_pAd, QUEUE_ENTRY_TO_PACKET(_pQEntry), _Status); \
}
/*
========================================================================
Routine Description:
Copy frame from waiting queue into relative ring buffer and set
appropriate ASIC register to kick hardware encryption before really
sent out to air.
Arguments:
pAd Pointer to our adapter
PNDIS_PACKET Pointer to outgoing Ndis frame
NumberOfFrag Number of fragment required
Return Value:
None
IRQL = DISPATCH_LEVEL
Note:
========================================================================
*/
NDIS_STATUS STAHardTransmit(
IN PRTMP_ADAPTER pAd,
IN TX_BLK *pTxBlk,
IN UCHAR QueIdx)
{
NDIS_PACKET *pPacket;
PQUEUE_ENTRY pQEntry;
// ---------------------------------------------
// STEP 0. DO SANITY CHECK AND SOME EARLY PREPARATION.
// ---------------------------------------------
//
ASSERT(pTxBlk->TxPacketList.Number);
if (pTxBlk->TxPacketList.Head == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("pTxBlk->TotalFrameNum == %ld!\n", pTxBlk->TxPacketList.Number));
return NDIS_STATUS_FAILURE;
}
pPacket = QUEUE_ENTRY_TO_PACKET(pTxBlk->TxPacketList.Head);
// ------------------------------------------------------------------
// STEP 1. WAKE UP PHY
// outgoing frame always wakeup PHY to prevent frame lost and
// turn off PSM bit to improve performance
// ------------------------------------------------------------------
// not to change PSM bit, just send this frame out?
if ((pAd->StaCfg.Psm == PWR_SAVE) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
{
DBGPRINT_RAW(RT_DEBUG_TRACE, ("AsicForceWakeup At HardTx\n"));
AsicForceWakeup(pAd, TRUE);
}
// It should not change PSM bit, when APSD turn on.
if ((!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) && (pAd->CommonCfg.bAPSDForcePowerSave == FALSE))
|| (RTMP_GET_PACKET_EAPOL(pTxBlk->pPacket))
|| (RTMP_GET_PACKET_WAI(pTxBlk->pPacket)))
{
if ((pAd->StaCfg.Psm == PWR_SAVE) &&
(pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeFast_PSP))
MlmeSetPsmBit(pAd, PWR_ACTIVE);
}
switch (pTxBlk->TxFrameType)
{
case TX_AMPDU_FRAME:
STA_AMPDU_Frame_Tx(pAd, pTxBlk);
break;
case TX_AMSDU_FRAME:
STA_AMSDU_Frame_Tx(pAd, pTxBlk);
break;
case TX_LEGACY_FRAME:
STA_Legacy_Frame_Tx(pAd, pTxBlk);
break;
case TX_MCAST_FRAME:
STA_Legacy_Frame_Tx(pAd, pTxBlk);
break;
case TX_RALINK_FRAME:
STA_ARalink_Frame_Tx(pAd, pTxBlk);
break;
case TX_FRAG_FRAME:
STA_Fragment_Frame_Tx(pAd, pTxBlk);
break;
default:
{
// It should not happened!
DBGPRINT(RT_DEBUG_ERROR, ("Send a pacekt was not classified!! It should not happen!\n"));
while(pTxBlk->TxPacketList.Number)
{
pQEntry = RemoveHeadQueue(&pTxBlk->TxPacketList);
pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry);
if (pPacket)
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
}
}
break;
}
return (NDIS_STATUS_SUCCESS);
}
ULONG HashBytesPolynomial(UCHAR *value, unsigned int len)
{
unsigned char *word = value;
unsigned int ret = 0;
unsigned int i;
for(i=0; i < len; i++)
{
int mod = i % 32;
ret ^=(unsigned int) (word[i]) << mod;
ret ^=(unsigned int) (word[i]) >> (32 - mod);
}
return ret;
}
VOID Sta_Announce_or_Forward_802_3_Packet(
IN PRTMP_ADAPTER pAd,
IN PNDIS_PACKET pPacket,
IN UCHAR FromWhichBSSID)
{
if (TRUE
)
{
announce_802_3_packet(pAd, pPacket);
}
else
{
// release packet
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
}
}
/* #include "../../rt2860/sta/sanity.c"
*************************************************************************
* 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:
sanity.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John Chang 2004-09-01 add WMM support
*/
#include "../rt_config.h"
extern UCHAR CISCO_OUI[];
extern UCHAR WPA_OUI[];
extern UCHAR RSN_OUI[];
extern UCHAR WME_INFO_ELEM[];
extern UCHAR WME_PARM_ELEM[];
extern UCHAR Ccx2QosInfo[];
extern UCHAR RALINK_OUI[];
extern UCHAR BROADCOM_OUI[];
/*
==========================================================================
Description:
MLME message sanity check
Return:
TRUE if all parameters are OK, FALSE otherwise
==========================================================================
*/
BOOLEAN MlmeStartReqSanity(
IN PRTMP_ADAPTER pAd,
IN VOID *Msg,
IN ULONG MsgLen,
OUT CHAR Ssid[],
OUT UCHAR *pSsidLen)
{
MLME_START_REQ_STRUCT *Info;
Info = (MLME_START_REQ_STRUCT *)(Msg);
if (Info->SsidLen > MAX_LEN_OF_SSID)
{
DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqSanity fail - wrong SSID length\n"));
return FALSE;
}
*pSsidLen = Info->SsidLen;
NdisMoveMemory(Ssid, Info->Ssid, *pSsidLen);
return TRUE;
}
/*
==========================================================================
Description:
MLME message sanity check
Return:
TRUE if all parameters are OK, FALSE otherwise
IRQL = DISPATCH_LEVEL
==========================================================================
*/
BOOLEAN PeerAssocRspSanity(
IN PRTMP_ADAPTER pAd,
IN VOID *pMsg,
IN ULONG MsgLen,
OUT PUCHAR pAddr2,
OUT USHORT *pCapabilityInfo,
OUT USHORT *pStatus,
OUT USHORT *pAid,
OUT UCHAR SupRate[],
OUT UCHAR *pSupRateLen,
OUT UCHAR ExtRate[],
OUT UCHAR *pExtRateLen,
OUT HT_CAPABILITY_IE *pHtCapability,
OUT ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE
OUT UCHAR *pHtCapabilityLen,
OUT UCHAR *pAddHtInfoLen,
OUT UCHAR *pNewExtChannelOffset,
OUT PEDCA_PARM pEdcaParm,
OUT UCHAR *pCkipFlag)
{
CHAR IeType, *Ptr;
PFRAME_802_11 pFrame = (PFRAME_802_11)pMsg;
PEID_STRUCT pEid;
ULONG Length = 0;
*pNewExtChannelOffset = 0xff;
*pHtCapabilityLen = 0;
*pAddHtInfoLen = 0;
COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2);
Ptr = pFrame->Octet;
Length += LENGTH_802_11;
NdisMoveMemory(pCapabilityInfo, &pFrame->Octet[0], 2);
Length += 2;
NdisMoveMemory(pStatus, &pFrame->Octet[2], 2);
Length += 2;
*pCkipFlag = 0;
*pExtRateLen = 0;
pEdcaParm->bValid = FALSE;
if (*pStatus != MLME_SUCCESS)
return TRUE;
NdisMoveMemory(pAid, &pFrame->Octet[4], 2);
Length += 2;
// Aid already swaped byte order in RTMPFrameEndianChange() for big endian platform
*pAid = (*pAid) & 0x3fff; // AID is low 14-bit
// -- get supported rates from payload and advance the pointer
IeType = pFrame->Octet[6];
*pSupRateLen = pFrame->Octet[7];
if ((IeType != IE_SUPP_RATES) || (*pSupRateLen > MAX_LEN_OF_SUPPORTED_RATES))
{
DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity fail - wrong SupportedRates IE\n"));
return FALSE;
}
else
NdisMoveMemory(SupRate, &pFrame->Octet[8], *pSupRateLen);
Length = Length + 2 + *pSupRateLen;
// many AP implement proprietary IEs in non-standard order, we'd better
// tolerate mis-ordered IEs to get best compatibility
pEid = (PEID_STRUCT) &pFrame->Octet[8 + (*pSupRateLen)];
// get variable fields from payload and advance the pointer
while ((Length + 2 + pEid->Len) <= MsgLen)
{
switch (pEid->Eid)
{
case IE_EXT_SUPP_RATES:
if (pEid->Len <= MAX_LEN_OF_SUPPORTED_RATES)
{
NdisMoveMemory(ExtRate, pEid->Octet, pEid->Len);
*pExtRateLen = pEid->Len;
}
break;
case IE_HT_CAP:
case IE_HT_CAP2:
if (pEid->Len >= SIZE_HT_CAP_IE) //Note: allow extension.!!
{
NdisMoveMemory(pHtCapability, pEid->Octet, SIZE_HT_CAP_IE);
*(USHORT *)(&pHtCapability->HtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->HtCapInfo));
*(USHORT *)(&pHtCapability->ExtHtCapInfo) = cpu2le16(*(USHORT *)(&pHtCapability->ExtHtCapInfo));
*pHtCapabilityLen = SIZE_HT_CAP_IE;
}
else
{
DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_HT_CAP. \n"));
}
break;
case IE_ADD_HT:
case IE_ADD_HT2:
if (pEid->Len >= sizeof(ADD_HT_INFO_IE))
{
// This IE allows extension, but we can ignore extra bytes beyond our knowledge , so only
// copy first sizeof(ADD_HT_INFO_IE)
NdisMoveMemory(pAddHtInfo, pEid->Octet, sizeof(ADD_HT_INFO_IE));
*(USHORT *)(&pAddHtInfo->AddHtInfo2) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo2));
*(USHORT *)(&pAddHtInfo->AddHtInfo3) = cpu2le16(*(USHORT *)(&pAddHtInfo->AddHtInfo3));
*pAddHtInfoLen = SIZE_ADD_HT_INFO_IE;
}
else
{
DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_ADD_HT. \n"));
}
break;
case IE_SECONDARY_CH_OFFSET:
if (pEid->Len == 1)
{
*pNewExtChannelOffset = pEid->Octet[0];
}
else
{
DBGPRINT(RT_DEBUG_WARN, ("PeerAssocRspSanity - wrong IE_SECONDARY_CH_OFFSET. \n"));
}
break;
case IE_AIRONET_CKIP:
// 0. Check Aironet IE length, it must be larger or equal to 28
// Cisco's AP VxWork version(will not be supported) used this IE length as 28
// Cisco's AP IOS version used this IE length as 30
if (pEid->Len < (CKIP_NEGOTIATION_LENGTH - 2))
break;
// 1. Copy CKIP flag byte to buffer for process
*pCkipFlag = *(pEid->Octet + 8);
break;
case IE_AIRONET_IPADDRESS:
if (pEid->Len != 0x0A)
break;
// Get Cisco Aironet IP information
if (NdisEqualMemory(pEid->Octet, CISCO_OUI, 3) == 1)
NdisMoveMemory(pAd->StaCfg.AironetIPAddress, pEid->Octet + 4, 4);
break;
// CCX2, WMM use the same IE value
// case IE_CCX_V2:
case IE_VENDOR_SPECIFIC:
// handle WME PARAMTER ELEMENT
if (NdisEqualMemory(pEid->Octet, WME_PARM_ELEM, 6) && (pEid->Len == 24))
{
PUCHAR ptr;
int i;
// parsing EDCA parameters
pEdcaParm->bValid = TRUE;
pEdcaParm->bQAck = FALSE; // pEid->Octet[0] & 0x10;
pEdcaParm->bQueueRequest = FALSE; // pEid->Octet[0] & 0x20;
pEdcaParm->bTxopRequest = FALSE; // pEid->Octet[0] & 0x40;
//pEdcaParm->bMoreDataAck = FALSE; // pEid->Octet[0] & 0x80;
pEdcaParm->EdcaUpdateCount = pEid->Octet[6] & 0x0f;
pEdcaParm->bAPSDCapable = (pEid->Octet[6] & 0x80) ? 1 : 0;
ptr = &pEid->Octet[8];
for (i=0; i<4; i++)
{
UCHAR aci = (*ptr & 0x60) >> 5; // b5~6 is AC INDEX
pEdcaParm->bACM[aci] = (((*ptr) & 0x10) == 0x10); // b5 is ACM
pEdcaParm->Aifsn[aci] = (*ptr) & 0x0f; // b0~3 is AIFSN
pEdcaParm->Cwmin[aci] = *(ptr+1) & 0x0f; // b0~4 is Cwmin
pEdcaParm->Cwmax[aci] = *(ptr+1) >> 4; // b5~8 is Cwmax
pEdcaParm->Txop[aci] = *(ptr+2) + 256 * (*(ptr+3)); // in unit of 32-us
ptr += 4; // point to next AC
}
}
// handle CCX IE
else
{
// 0. Check the size and CCX admin control
if (pAd->StaCfg.CCXControl.field.Enable == 0)
break;
if (pEid->Len != 5)
break;
// Turn CCX2 if matched
if (NdisEqualMemory(pEid->Octet, Ccx2IeInfo, 5) == 1)
pAd->StaCfg.CCXEnable = TRUE;
break;
}
break;
default:
DBGPRINT(RT_DEBUG_TRACE, ("PeerAssocRspSanity - ignore unrecognized EID = %d\n", pEid->Eid));
break;
}
Length = Length + 2 + pEid->Len;
pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len);
}
// Force CCX2 enable to TRUE for those AP didn't replay CCX v2 IE, we still force it to be on
if (pAd->StaCfg.CCXControl.field.Enable == 1)
pAd->StaCfg.CCXEnable = TRUE;
return TRUE;
}
/*
==========================================================================
Description:
MLME message sanity check
Return:
TRUE if all parameters are OK, FALSE otherwise
IRQL = DISPATCH_LEVEL
==========================================================================
*/
BOOLEAN PeerProbeReqSanity(
IN PRTMP_ADAPTER pAd,
IN VOID *Msg,
IN ULONG MsgLen,
OUT PUCHAR pAddr2,
OUT CHAR Ssid[],
OUT UCHAR *pSsidLen)
{
UCHAR Idx;
UCHAR RateLen;
CHAR IeType;
PFRAME_802_11 pFrame = (PFRAME_802_11)Msg;
COPY_MAC_ADDR(pAddr2, pFrame->Hdr.Addr2);
if ((pFrame->Octet[0] != IE_SSID) || (pFrame->Octet[1] > MAX_LEN_OF_SSID))
{
DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SSID IE(Type=%d,Len=%d)\n",pFrame->Octet[0],pFrame->Octet[1]));
return FALSE;
}
*pSsidLen = pFrame->Octet[1];
NdisMoveMemory(Ssid, &pFrame->Octet[2], *pSsidLen);
Idx = *pSsidLen + 2;
// -- get supported rates from payload and advance the pointer
IeType = pFrame->Octet[Idx];
RateLen = pFrame->Octet[Idx + 1];
if (IeType != IE_SUPP_RATES)
{
DBGPRINT(RT_DEBUG_TRACE, ("PeerProbeReqSanity fail - wrong SupportRates IE(Type=%d,Len=%d)\n",pFrame->Octet[Idx],pFrame->Octet[Idx+1]));
return FALSE;
}
else
{
if ((pAd->CommonCfg.PhyMode == PHY_11G) && (RateLen < 8))
return (FALSE);
}
return TRUE;
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
BOOLEAN GetTimBit(
IN CHAR *Ptr,
IN USHORT Aid,
OUT UCHAR *TimLen,
OUT UCHAR *BcastFlag,
OUT UCHAR *DtimCount,
OUT UCHAR *DtimPeriod,
OUT UCHAR *MessageToMe)
{
UCHAR BitCntl, N1, N2, MyByte, MyBit;
CHAR *IdxPtr;
IdxPtr = Ptr;
IdxPtr ++;
*TimLen = *IdxPtr;
// get DTIM Count from TIM element
IdxPtr ++;
*DtimCount = *IdxPtr;
// get DTIM Period from TIM element
IdxPtr++;
*DtimPeriod = *IdxPtr;
// get Bitmap Control from TIM element
IdxPtr++;
BitCntl = *IdxPtr;
if ((*DtimCount == 0) && (BitCntl & 0x01))
*BcastFlag = TRUE;
else
*BcastFlag = FALSE;
// Parse Partial Virtual Bitmap from TIM element
N1 = BitCntl & 0xfe; // N1 is the first bitmap byte#
N2 = *TimLen - 4 + N1; // N2 is the last bitmap byte#
if ((Aid < (N1 << 3)) || (Aid >= ((N2 + 1) << 3)))
*MessageToMe = FALSE;
else
{
MyByte = (Aid >> 3) - N1; // my byte position in the bitmap byte-stream
MyBit = Aid % 16 - ((MyByte & 0x01)? 8:0);
IdxPtr += (MyByte + 1);
//if (*IdxPtr)
// DBGPRINT(RT_DEBUG_WARN, ("TIM bitmap = 0x%02x\n", *IdxPtr));
if (*IdxPtr & (0x01 << MyBit))
*MessageToMe = TRUE;
else
*MessageToMe = FALSE;
}
return TRUE;
}
/* #include "../../rt2860/sta/sync.c"
*************************************************************************
* 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:
sync.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
John Chang 2004-09-01 modified for rt2561/2661
Jan Lee 2006-08-01 modified for rt2860 for 802.11n
*/
#include "../rt_config.h"
#define ADHOC_ENTRY_BEACON_LOST_TIME (2*OS_HZ) // 2 sec
/*
==========================================================================
Description:
The sync state machine,
Parameters:
Sm - pointer to the state machine
Note:
the state machine looks like the following
==========================================================================
*/
VOID SyncStateMachineInit(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *Sm,
OUT STATE_MACHINE_FUNC Trans[])
{
StateMachineInit(Sm, Trans, MAX_SYNC_STATE, MAX_SYNC_MSG, (STATE_MACHINE_FUNC)Drop, SYNC_IDLE, SYNC_MACHINE_BASE);
// column 1
StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)MlmeScanReqAction);
StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)MlmeJoinReqAction);
StateMachineSetAction(Sm, SYNC_IDLE, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)MlmeStartReqAction);
StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeacon);
StateMachineSetAction(Sm, SYNC_IDLE, MT2_PEER_PROBE_REQ, (STATE_MACHINE_FUNC)PeerProbeReqAction);
//column 2
StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan);
StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin);
StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart);
StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtJoinAction);
StateMachineSetAction(Sm, JOIN_WAIT_BEACON, MT2_BEACON_TIMEOUT, (STATE_MACHINE_FUNC)BeaconTimeoutAtJoinAction);
// column 3
StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_SCAN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenScan);
StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_JOIN_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenJoin);
StateMachineSetAction(Sm, SCAN_LISTEN, MT2_MLME_START_REQ, (STATE_MACHINE_FUNC)InvalidStateWhenStart);
StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_BEACON, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction);
StateMachineSetAction(Sm, SCAN_LISTEN, MT2_PEER_PROBE_RSP, (STATE_MACHINE_FUNC)PeerBeaconAtScanAction);
StateMachineSetAction(Sm, SCAN_LISTEN, MT2_SCAN_TIMEOUT, (STATE_MACHINE_FUNC)ScanTimeoutAction);
// timer init
RTMPInitTimer(pAd, &pAd->MlmeAux.BeaconTimer, GET_TIMER_FUNCTION(BeaconTimeout), pAd, FALSE);
RTMPInitTimer(pAd, &pAd->MlmeAux.ScanTimer, GET_TIMER_FUNCTION(ScanTimeout), pAd, FALSE);
}
/*
==========================================================================
Description:
Beacon timeout handler, executed in timer thread
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID BeaconTimeout(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
DBGPRINT(RT_DEBUG_TRACE,("SYNC - BeaconTimeout\n"));
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))
return;
if ((pAd->CommonCfg.BBPCurrentBW == BW_40)
)
{
UCHAR BBPValue = 0;
AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue);
BBPValue &= (~0x18);
BBPValue |= 0x10;
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - End of SCAN, restore to 40MHz channel %d, Total BSS[%02d]\n",pAd->CommonCfg.CentralChannel, pAd->ScanTab.BssNr));
}
MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_BEACON_TIMEOUT, 0, NULL);
RT28XX_MLME_HANDLER(pAd);
}
/*
==========================================================================
Description:
Scan timeout handler, executed in timer thread
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID ScanTimeout(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))
return;
if (MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_SCAN_TIMEOUT, 0, NULL))
{
RT28XX_MLME_HANDLER(pAd);
}
else
{
// To prevent SyncMachine.CurrState is SCAN_LISTEN forever.
pAd->MlmeAux.Channel = 0;
ScanNextChannel(pAd);
if (pAd->CommonCfg.bWirelessEvent)
{
RTMPSendWirelessEvent(pAd, IW_SCAN_ENQUEUE_FAIL_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
}
}
}
/*
==========================================================================
Description:
MLME SCAN req state machine procedure
==========================================================================
*/
VOID MlmeScanReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, ScanType, BssType, BBPValue = 0;
BOOLEAN TimerCancelled;
ULONG Now;
USHORT Status;
PHEADER_802_11 pHdr80211;
PUCHAR pOutBuffer = NULL;
NDIS_STATUS NStatus;
// Check the total scan tries for one single OID command
// If this is the CCX 2.0 Case, skip that!
if ( !RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP))
{
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeScanReqAction before Startup\n"));
return;
}
// Increase the scan retry counters.
pAd->StaCfg.ScanCnt++;
// first check the parameter sanity
if (MlmeScanReqSanity(pAd,
Elem->Msg,
Elem->MsgLen,
&BssType,
Ssid,
&SsidLen,
&ScanType))
{
// Check for channel load and noise hist request
// Suspend MSDU only at scan request, not the last two mentioned
if ((ScanType == SCAN_CISCO_NOISE) || (ScanType == SCAN_CISCO_CHANNEL_LOAD))
{
if (pAd->StaCfg.CCXScanChannel != pAd->CommonCfg.Channel)
RTMPSuspendMsduTransmission(pAd); // Suspend MSDU transmission here
}
else
{
// Suspend MSDU transmission here
RTMPSuspendMsduTransmission(pAd);
}
//
// To prevent data lost.
// Send an NULL data with turned PSM bit on to current associated AP before SCAN progress.
// And should send an NULL data with turned PSM bit off to AP, when scan progress done
//
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) && (INFRA_ON(pAd)))
{
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer);
if (NStatus == NDIS_STATUS_SUCCESS)
{
pHdr80211 = (PHEADER_802_11) pOutBuffer;
MgtMacHeaderInit(pAd, pHdr80211, SUBTYPE_NULL_FUNC, 1, pAd->CommonCfg.Bssid, pAd->CommonCfg.Bssid);
pHdr80211->Duration = 0;
pHdr80211->FC.Type = BTYPE_DATA;
pHdr80211->FC.PwrMgmt = PWR_SAVE;
// Send using priority queue
MiniportMMRequest(pAd, 0, pOutBuffer, sizeof(HEADER_802_11));
DBGPRINT(RT_DEBUG_TRACE, ("MlmeScanReqAction -- Send PSM Data frame for off channel RM\n"));
MlmeFreeMemory(pAd, pOutBuffer);
RTMPusecDelay(5000);
}
}
NdisGetSystemUpTime(&Now);
pAd->StaCfg.LastScanTime = Now;
// reset all the timers
RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled);
RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled);
// record desired BSS parameters
pAd->MlmeAux.BssType = BssType;
pAd->MlmeAux.ScanType = ScanType;
pAd->MlmeAux.SsidLen = SsidLen;
NdisZeroMemory(pAd->MlmeAux.Ssid, MAX_LEN_OF_SSID);
NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen);
// start from the first channel
pAd->MlmeAux.Channel = FirstChannel(pAd);
// Change the scan channel when dealing with CCX beacon report
if ((ScanType == SCAN_CISCO_PASSIVE) || (ScanType == SCAN_CISCO_ACTIVE) ||
(ScanType == SCAN_CISCO_CHANNEL_LOAD) || (ScanType == SCAN_CISCO_NOISE))
pAd->MlmeAux.Channel = pAd->StaCfg.CCXScanChannel;
// Let BBP register at 20MHz to do scan
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue);
BBPValue &= (~0x18);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n"));
ScanNextChannel(pAd);
}
else
{
DBGPRINT_ERR(("SYNC - MlmeScanReqAction() sanity check fail\n"));
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_INVALID_FORMAT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status);
}
}
/*
==========================================================================
Description:
MLME JOIN req state machine procedure
==========================================================================
*/
VOID MlmeJoinReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR BBPValue = 0;
BSS_ENTRY *pBss;
BOOLEAN TimerCancelled;
HEADER_802_11 Hdr80211;
NDIS_STATUS NStatus;
ULONG FrameLen = 0;
PUCHAR pOutBuffer = NULL;
PUCHAR pSupRate = NULL;
UCHAR SupRateLen;
PUCHAR pExtRate = NULL;
UCHAR ExtRateLen;
UCHAR ASupRate[] = {0x8C, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6C};
UCHAR ASupRateLen = sizeof(ASupRate)/sizeof(UCHAR);
MLME_JOIN_REQ_STRUCT *pInfo = (MLME_JOIN_REQ_STRUCT *)(Elem->Msg);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeJoinReqAction(BSS #%ld)\n", pInfo->BssIdx));
// reset all the timers
RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled);
RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled);
pBss = &pAd->MlmeAux.SsidBssTab.BssEntry[pInfo->BssIdx];
// record the desired SSID & BSSID we're waiting for
COPY_MAC_ADDR(pAd->MlmeAux.Bssid, pBss->Bssid);
// If AP's SSID is not hidden, it is OK for updating ssid to MlmeAux again.
if (pBss->Hidden == 0)
{
NdisMoveMemory(pAd->MlmeAux.Ssid, pBss->Ssid, pBss->SsidLen);
pAd->MlmeAux.SsidLen = pBss->SsidLen;
}
pAd->MlmeAux.BssType = pBss->BssType;
pAd->MlmeAux.Channel = pBss->Channel;
pAd->MlmeAux.CentralChannel = pBss->CentralChannel;
// Let BBP register at 20MHz to do scan
RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R4, &BBPValue);
BBPValue &= (~0x18);
RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R4, BBPValue);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BBP R4 to 20MHz.l\n"));
// switch channel and waiting for beacon timer
AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE);
AsicLockChannel(pAd, pAd->MlmeAux.Channel);
RTMPSetTimer(&pAd->MlmeAux.BeaconTimer, JOIN_TIMEOUT);
do
{
if (((pAd->CommonCfg.bIEEE80211H == 1) &&
(pAd->MlmeAux.Channel > 14) &&
RadarChannelCheck(pAd, pAd->MlmeAux.Channel))
)
{
//
// We can't send any Probe request frame to meet 802.11h.
//
if (pBss->Hidden == 0)
break;
}
//
// send probe request
//
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer);
if (NStatus == NDIS_STATUS_SUCCESS)
{
if (pAd->MlmeAux.Channel <= 14)
{
pSupRate = pAd->CommonCfg.SupRate;
SupRateLen = pAd->CommonCfg.SupRateLen;
pExtRate = pAd->CommonCfg.ExtRate;
ExtRateLen = pAd->CommonCfg.ExtRateLen;
}
else
{
//
// Overwrite Support Rate, CCK rate are not allowed
//
pSupRate = ASupRate;
SupRateLen = ASupRateLen;
ExtRateLen = 0;
}
if (pAd->MlmeAux.BssType == BSS_INFRA)
MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, pAd->MlmeAux.Bssid, pAd->MlmeAux.Bssid);
else
MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11), &Hdr80211,
1, &SsidIe,
1, &pAd->MlmeAux.SsidLen,
pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid,
1, &SupRateIe,
1, &SupRateLen,
SupRateLen, pSupRate,
END_OF_ARGS);
if (ExtRateLen)
{
ULONG Tmp;
MakeOutgoingFrame(pOutBuffer + FrameLen, &Tmp,
1, &ExtRateIe,
1, &ExtRateLen,
ExtRateLen, pExtRate,
END_OF_ARGS);
FrameLen += Tmp;
}
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
}
} while (FALSE);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Switch to ch %d, Wait BEACON from %02x:%02x:%02x:%02x:%02x:%02x\n",
pBss->Channel, pBss->Bssid[0], pBss->Bssid[1], pBss->Bssid[2], pBss->Bssid[3], pBss->Bssid[4], pBss->Bssid[5]));
pAd->Mlme.SyncMachine.CurrState = JOIN_WAIT_BEACON;
}
/*
==========================================================================
Description:
MLME START Request state machine procedure, starting an IBSS
==========================================================================
*/
VOID MlmeStartReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen;
BOOLEAN TimerCancelled;
// New for WPA security suites
UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5
NDIS_802_11_VARIABLE_IEs *pVIE = NULL;
LARGE_INTEGER TimeStamp;
BOOLEAN Privacy;
USHORT Status;
// Init Variable IE structure
pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE;
pVIE->Length = 0;
TimeStamp.u.LowPart = 0;
TimeStamp.u.HighPart = 0;
if (MlmeStartReqSanity(pAd, Elem->Msg, Elem->MsgLen, Ssid, &SsidLen))
{
// reset all the timers
RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &TimerCancelled);
RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled);
//
// Start a new IBSS. All IBSS parameters are decided now....
//
DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - Start a new IBSS. All IBSS parameters are decided now.... \n"));
pAd->MlmeAux.BssType = BSS_ADHOC;
NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen);
pAd->MlmeAux.SsidLen = SsidLen;
// generate a radom number as BSSID
MacAddrRandomBssid(pAd, pAd->MlmeAux.Bssid);
DBGPRINT(RT_DEBUG_TRACE, ("MlmeStartReqAction - generate a radom number as BSSID \n"));
Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) ||
(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ||
(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled);
pAd->MlmeAux.CapabilityInfo = CAP_GENERATE(0,1,Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 1, 0);
pAd->MlmeAux.BeaconPeriod = pAd->CommonCfg.BeaconPeriod;
pAd->MlmeAux.AtimWin = pAd->StaCfg.AtimWin;
pAd->MlmeAux.Channel = pAd->CommonCfg.Channel;
pAd->CommonCfg.CentralChannel = pAd->CommonCfg.Channel;
pAd->MlmeAux.CentralChannel = pAd->CommonCfg.CentralChannel;
pAd->MlmeAux.SupRateLen= pAd->CommonCfg.SupRateLen;
NdisMoveMemory(pAd->MlmeAux.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES);
RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen);
pAd->MlmeAux.ExtRateLen = pAd->CommonCfg.ExtRateLen;
NdisMoveMemory(pAd->MlmeAux.ExtRate, pAd->CommonCfg.ExtRate, MAX_LEN_OF_SUPPORTED_RATES);
RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen);
if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)
{
RTMPUpdateHTIE(&pAd->CommonCfg.DesiredHtPhy, &pAd->StaCfg.DesiredHtPhyInfo.MCSSet[0], &pAd->MlmeAux.HtCapability, &pAd->MlmeAux.AddHtInfo);
pAd->MlmeAux.HtCapabilityLen = sizeof(HT_CAPABILITY_IE);
// Not turn pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE here.
DBGPRINT(RT_DEBUG_TRACE, ("SYNC -pAd->StaActive.SupportedHtPhy.bHtEnable = TRUE\n"));
}
else
{
pAd->MlmeAux.HtCapabilityLen = 0;
pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE;
}
// temporarily not support QOS in IBSS
NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));
NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));
NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));
AsicSwitchChannel(pAd, pAd->MlmeAux.Channel, FALSE);
AsicLockChannel(pAd, pAd->MlmeAux.Channel);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - MlmeStartReqAction(ch= %d,sup rates= %d, ext rates=%d)\n",
pAd->MlmeAux.Channel, pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen));
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_SUCCESS;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status);
}
else
{
DBGPRINT_ERR(("SYNC - MlmeStartReqAction() sanity check fail.\n"));
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_INVALID_FORMAT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status);
}
}
/*
==========================================================================
Description:
peer sends beacon back when scanning
==========================================================================
*/
VOID PeerBeaconAtScanAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN];
UCHAR Ssid[MAX_LEN_OF_SSID], BssType, Channel, NewChannel,
SsidLen, DtimCount, DtimPeriod, BcastFlag, MessageToMe;
CF_PARM CfParm;
USHORT BeaconPeriod, AtimWin, CapabilityInfo;
PFRAME_802_11 pFrame;
LARGE_INTEGER TimeStamp;
UCHAR Erp;
UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES];
UCHAR SupRateLen, ExtRateLen;
USHORT LenVIE;
UCHAR CkipFlag;
UCHAR AironetCellPowerLimit;
EDCA_PARM EdcaParm;
QBSS_LOAD_PARM QbssLoad;
QOS_CAPABILITY_PARM QosCapability;
ULONG RalinkIe;
UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5
NDIS_802_11_VARIABLE_IEs *pVIE = NULL;
HT_CAPABILITY_IE HtCapability;
ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE
UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0;
UCHAR AddHtInfoLen;
UCHAR NewExtChannelOffset = 0xff;
pFrame = (PFRAME_802_11) Elem->Msg;
// Init Variable IE structure
pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE;
pVIE->Length = 0;
RTMPZeroMemory(&HtCapability, sizeof(HtCapability));
RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE));
if (PeerBeaconAndProbeRspSanity(pAd,
Elem->Msg,
Elem->MsgLen,
Elem->Channel,
Addr2,
Bssid,
Ssid,
&SsidLen,
&BssType,
&BeaconPeriod,
&Channel,
&NewChannel,
&TimeStamp,
&CfParm,
&AtimWin,
&CapabilityInfo,
&Erp,
&DtimCount,
&DtimPeriod,
&BcastFlag,
&MessageToMe,
SupRate,
&SupRateLen,
ExtRate,
&ExtRateLen,
&CkipFlag,
&AironetCellPowerLimit,
&EdcaParm,
&QbssLoad,
&QosCapability,
&RalinkIe,
&HtCapabilityLen,
&PreNHtCapabilityLen,
&HtCapability,
&AddHtInfoLen,
&AddHtInfo,
&NewExtChannelOffset,
&LenVIE,
pVIE))
{
ULONG Idx;
CHAR Rssi = 0;
Idx = BssTableSearch(&pAd->ScanTab, Bssid, Channel);
if (Idx != BSS_NOT_FOUND)
Rssi = pAd->ScanTab.BssEntry[Idx].Rssi;
Rssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2));
if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0))
HtCapabilityLen = SIZE_HT_CAP_IE;
if ((pAd->StaCfg.CCXReqType != MSRN_TYPE_UNUSED) && (Channel == pAd->StaCfg.CCXScanChannel))
{
Idx = BssTableSetEntry(pAd, &pAd->StaCfg.CCXBssTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
&CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen,ExtRate, ExtRateLen, &HtCapability,
&AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag,
&EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE);
if (Idx != BSS_NOT_FOUND)
{
NdisMoveMemory(pAd->StaCfg.CCXBssTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4);
NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4);
NdisMoveMemory(&pAd->StaCfg.CCXBssTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4);
if (pAd->StaCfg.CCXReqType == MSRN_TYPE_BEACON_REQ)
AironetAddBeaconReport(pAd, Idx, Elem);
}
}
else
{
Idx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
&CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability,
&AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, Rssi, TimeStamp, CkipFlag,
&EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE);
if (Idx != BSS_NOT_FOUND)
{
NdisMoveMemory(pAd->ScanTab.BssEntry[Idx].PTSF, &Elem->Msg[24], 4);
NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4);
NdisMoveMemory(&pAd->ScanTab.BssEntry[Idx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4);
}
}
}
// sanity check fail, ignored
}
/*
==========================================================================
Description:
When waiting joining the (I)BSS, beacon received from external
==========================================================================
*/
VOID PeerBeaconAtJoinAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN];
UCHAR Ssid[MAX_LEN_OF_SSID], SsidLen, BssType, Channel, MessageToMe,
DtimCount, DtimPeriod, BcastFlag, NewChannel;
LARGE_INTEGER TimeStamp;
USHORT BeaconPeriod, AtimWin, CapabilityInfo;
CF_PARM Cf;
BOOLEAN TimerCancelled;
UCHAR Erp;
UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES];
UCHAR SupRateLen, ExtRateLen;
UCHAR CkipFlag;
USHORT LenVIE;
UCHAR AironetCellPowerLimit;
EDCA_PARM EdcaParm;
QBSS_LOAD_PARM QbssLoad;
QOS_CAPABILITY_PARM QosCapability;
USHORT Status;
UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5
NDIS_802_11_VARIABLE_IEs *pVIE = NULL;
ULONG RalinkIe;
ULONG Idx;
HT_CAPABILITY_IE HtCapability;
ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE
UCHAR HtCapabilityLen = 0, PreNHtCapabilityLen = 0;
UCHAR AddHtInfoLen;
UCHAR NewExtChannelOffset = 0xff;
UCHAR CentralChannel;
// Init Variable IE structure
pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE;
pVIE->Length = 0;
RTMPZeroMemory(&HtCapability, sizeof(HtCapability));
RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE));
if (PeerBeaconAndProbeRspSanity(pAd,
Elem->Msg,
Elem->MsgLen,
Elem->Channel,
Addr2,
Bssid,
Ssid,
&SsidLen,
&BssType,
&BeaconPeriod,
&Channel,
&NewChannel,
&TimeStamp,
&Cf,
&AtimWin,
&CapabilityInfo,
&Erp,
&DtimCount,
&DtimPeriod,
&BcastFlag,
&MessageToMe,
SupRate,
&SupRateLen,
ExtRate,
&ExtRateLen,
&CkipFlag,
&AironetCellPowerLimit,
&EdcaParm,
&QbssLoad,
&QosCapability,
&RalinkIe,
&HtCapabilityLen,
&PreNHtCapabilityLen,
&HtCapability,
&AddHtInfoLen,
&AddHtInfo,
&NewExtChannelOffset,
&LenVIE,
pVIE))
{
// Disqualify 11b only adhoc when we are in 11g only adhoc mode
if ((BssType == BSS_ADHOC) && (pAd->CommonCfg.PhyMode == PHY_11G) && ((SupRateLen+ExtRateLen)< 12))
return;
// BEACON from desired BSS/IBSS found. We should be able to decide most
// BSS parameters here.
// Q. But what happen if this JOIN doesn't conclude a successful ASSOCIATEION?
// Do we need to receover back all parameters belonging to previous BSS?
// A. Should be not. There's no back-door recover to previous AP. It still need
// a new JOIN-AUTH-ASSOC sequence.
if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, Bssid))
{
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - receive desired BEACON at JoinWaitBeacon... Channel = %d\n", Channel));
RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &TimerCancelled);
// Update RSSI to prevent No signal display when cards first initialized
pAd->StaCfg.RssiSample.LastRssi0 = ConvertToRssi(pAd, Elem->Rssi0, RSSI_0);
pAd->StaCfg.RssiSample.LastRssi1 = ConvertToRssi(pAd, Elem->Rssi1, RSSI_1);
pAd->StaCfg.RssiSample.LastRssi2 = ConvertToRssi(pAd, Elem->Rssi2, RSSI_2);
pAd->StaCfg.RssiSample.AvgRssi0 = pAd->StaCfg.RssiSample.LastRssi0;
pAd->StaCfg.RssiSample.AvgRssi0X8 = pAd->StaCfg.RssiSample.AvgRssi0 << 3;
pAd->StaCfg.RssiSample.AvgRssi1 = pAd->StaCfg.RssiSample.LastRssi1;
pAd->StaCfg.RssiSample.AvgRssi1X8 = pAd->StaCfg.RssiSample.AvgRssi1 << 3;
pAd->StaCfg.RssiSample.AvgRssi2 = pAd->StaCfg.RssiSample.LastRssi2;
pAd->StaCfg.RssiSample.AvgRssi2X8 = pAd->StaCfg.RssiSample.AvgRssi2 << 3;
//
// We need to check if SSID only set to any, then we can record the current SSID.
// Otherwise will cause hidden SSID association failed.
//
if (pAd->MlmeAux.SsidLen == 0)
{
NdisMoveMemory(pAd->MlmeAux.Ssid, Ssid, SsidLen);
pAd->MlmeAux.SsidLen = SsidLen;
}
else
{
Idx = BssSsidTableSearch(&pAd->ScanTab, Bssid, pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Channel);
if (Idx != BSS_NOT_FOUND)
{
//
// Multiple SSID case, used correct CapabilityInfo
//
CapabilityInfo = pAd->ScanTab.BssEntry[Idx].CapabilityInfo;
}
}
NdisMoveMemory(pAd->MlmeAux.Bssid, Bssid, MAC_ADDR_LEN);
pAd->MlmeAux.CapabilityInfo = CapabilityInfo & SUPPORTED_CAPABILITY_INFO;
pAd->MlmeAux.BssType = BssType;
pAd->MlmeAux.BeaconPeriod = BeaconPeriod;
pAd->MlmeAux.Channel = Channel;
pAd->MlmeAux.AtimWin = AtimWin;
pAd->MlmeAux.CfpPeriod = Cf.CfpPeriod;
pAd->MlmeAux.CfpMaxDuration = Cf.CfpMaxDuration;
pAd->MlmeAux.APRalinkIe = RalinkIe;
// Copy AP's supported rate to MlmeAux for creating assoication request
// Also filter out not supported rate
pAd->MlmeAux.SupRateLen = SupRateLen;
NdisMoveMemory(pAd->MlmeAux.SupRate, SupRate, SupRateLen);
RTMPCheckRates(pAd, pAd->MlmeAux.SupRate, &pAd->MlmeAux.SupRateLen);
pAd->MlmeAux.ExtRateLen = ExtRateLen;
NdisMoveMemory(pAd->MlmeAux.ExtRate, ExtRate, ExtRateLen);
RTMPCheckRates(pAd, pAd->MlmeAux.ExtRate, &pAd->MlmeAux.ExtRateLen);
NdisZeroMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, 16);
pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset;
pAd->MlmeAux.HtCapabilityLen = HtCapabilityLen;
// filter out un-supported ht rates
if (((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0)) && (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED))
{
RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE);
RTMPMoveMemory(&pAd->MlmeAux.AddHtInfo, &AddHtInfo, SIZE_ADD_HT_INFO_IE);
// StaActive.SupportedHtPhy.MCSSet stores Peer AP's 11n Rx capability
NdisMoveMemory(pAd->StaActive.SupportedPhyInfo.MCSSet, HtCapability.MCSSet, 16);
pAd->MlmeAux.NewExtChannelOffset = NewExtChannelOffset;
pAd->MlmeAux.HtCapabilityLen = SIZE_HT_CAP_IE;
pAd->StaActive.SupportedPhyInfo.bHtEnable = TRUE;
if (PreNHtCapabilityLen > 0)
pAd->StaActive.SupportedPhyInfo.bPreNHt = TRUE;
RTMPCheckHt(pAd, BSSID_WCID, &HtCapability, &AddHtInfo);
// Copy AP Parameter to StaActive. This is also in LinkUp.
DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction! (MpduDensity=%d, MaxRAmpduFactor=%d, BW=%d)\n",
pAd->StaActive.SupportedHtPhy.MpduDensity, pAd->StaActive.SupportedHtPhy.MaxRAmpduFactor, HtCapability.HtCapInfo.ChannelWidth));
if (AddHtInfoLen > 0)
{
CentralChannel = AddHtInfo.ControlChan;
// Check again the Bandwidth capability of this AP.
if ((AddHtInfo.ControlChan > 2)&& (AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
CentralChannel = AddHtInfo.ControlChan - 2;
}
else if ((AddHtInfo.AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (HtCapability.HtCapInfo.ChannelWidth == BW_40))
{
CentralChannel = AddHtInfo.ControlChan + 2;
}
// Check Error .
if (pAd->MlmeAux.CentralChannel != CentralChannel)
DBGPRINT(RT_DEBUG_ERROR, ("PeerBeaconAtJoinAction HT===>Beacon Central Channel = %d, Control Channel = %d. Mlmeaux CentralChannel = %d\n", CentralChannel, AddHtInfo.ControlChan, pAd->MlmeAux.CentralChannel));
DBGPRINT(RT_DEBUG_TRACE, ("PeerBeaconAtJoinAction HT===>Central Channel = %d, Control Channel = %d, .\n", CentralChannel, AddHtInfo.ControlChan));
}
}
else
{
// To prevent error, let legacy AP must have same CentralChannel and Channel.
if ((HtCapabilityLen == 0) && (PreNHtCapabilityLen == 0))
pAd->MlmeAux.CentralChannel = pAd->MlmeAux.Channel;
pAd->StaActive.SupportedPhyInfo.bHtEnable = FALSE;
RTMPZeroMemory(&pAd->MlmeAux.HtCapability, SIZE_HT_CAP_IE);
RTMPZeroMemory(&pAd->MlmeAux.AddHtInfo, SIZE_ADD_HT_INFO_IE);
}
RTMPUpdateMlmeRate(pAd);
// copy QOS related information
if ((pAd->CommonCfg.bWmmCapable)
|| (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)
)
{
NdisMoveMemory(&pAd->MlmeAux.APEdcaParm, &EdcaParm, sizeof(EDCA_PARM));
NdisMoveMemory(&pAd->MlmeAux.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM));
NdisMoveMemory(&pAd->MlmeAux.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM));
}
else
{
NdisZeroMemory(&pAd->MlmeAux.APEdcaParm, sizeof(EDCA_PARM));
NdisZeroMemory(&pAd->MlmeAux.APQbssLoad, sizeof(QBSS_LOAD_PARM));
NdisZeroMemory(&pAd->MlmeAux.APQosCapability, sizeof(QOS_CAPABILITY_PARM));
}
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - after JOIN, SupRateLen=%d, ExtRateLen=%d\n",
pAd->MlmeAux.SupRateLen, pAd->MlmeAux.ExtRateLen));
if (AironetCellPowerLimit != 0xFF)
{
//We need to change our TxPower for CCX 2.0 AP Control of Client Transmit Power
ChangeToCellPowerLimit(pAd, AironetCellPowerLimit);
}
else //Used the default TX Power Percentage.
pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault;
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_SUCCESS;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status);
}
// not to me BEACON, ignored
}
// sanity check fail, ignore this frame
}
/*
==========================================================================
Description:
receive BEACON from peer
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID PeerBeacon(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Bssid[MAC_ADDR_LEN], Addr2[MAC_ADDR_LEN];
CHAR Ssid[MAX_LEN_OF_SSID];
CF_PARM CfParm;
UCHAR SsidLen, MessageToMe=0, BssType, Channel, NewChannel, index=0;
UCHAR DtimCount=0, DtimPeriod=0, BcastFlag=0;
USHORT CapabilityInfo, AtimWin, BeaconPeriod;
LARGE_INTEGER TimeStamp;
USHORT TbttNumToNextWakeUp;
UCHAR Erp;
UCHAR SupRate[MAX_LEN_OF_SUPPORTED_RATES], ExtRate[MAX_LEN_OF_SUPPORTED_RATES];
UCHAR SupRateLen, ExtRateLen;
UCHAR CkipFlag;
USHORT LenVIE;
UCHAR AironetCellPowerLimit;
EDCA_PARM EdcaParm;
QBSS_LOAD_PARM QbssLoad;
QOS_CAPABILITY_PARM QosCapability;
ULONG RalinkIe;
// New for WPA security suites
UCHAR VarIE[MAX_VIE_LEN]; // Total VIE length = MAX_VIE_LEN - -5
NDIS_802_11_VARIABLE_IEs *pVIE = NULL;
HT_CAPABILITY_IE HtCapability;
ADD_HT_INFO_IE AddHtInfo; // AP might use this additional ht info IE
UCHAR HtCapabilityLen, PreNHtCapabilityLen;
UCHAR AddHtInfoLen;
UCHAR NewExtChannelOffset = 0xff;
if (!(INFRA_ON(pAd) || ADHOC_ON(pAd)
))
return;
// Init Variable IE structure
pVIE = (PNDIS_802_11_VARIABLE_IEs) VarIE;
pVIE->Length = 0;
RTMPZeroMemory(&HtCapability, sizeof(HtCapability));
RTMPZeroMemory(&AddHtInfo, sizeof(ADD_HT_INFO_IE));
if (PeerBeaconAndProbeRspSanity(pAd,
Elem->Msg,
Elem->MsgLen,
Elem->Channel,
Addr2,
Bssid,
Ssid,
&SsidLen,
&BssType,
&BeaconPeriod,
&Channel,
&NewChannel,
&TimeStamp,
&CfParm,
&AtimWin,
&CapabilityInfo,
&Erp,
&DtimCount,
&DtimPeriod,
&BcastFlag,
&MessageToMe,
SupRate,
&SupRateLen,
ExtRate,
&ExtRateLen,
&CkipFlag,
&AironetCellPowerLimit,
&EdcaParm,
&QbssLoad,
&QosCapability,
&RalinkIe,
&HtCapabilityLen,
&PreNHtCapabilityLen,
&HtCapability,
&AddHtInfoLen,
&AddHtInfo,
&NewExtChannelOffset,
&LenVIE,
pVIE))
{
BOOLEAN is_my_bssid, is_my_ssid;
ULONG Bssidx, Now;
BSS_ENTRY *pBss;
CHAR RealRssi = RTMPMaxRssi(pAd, ConvertToRssi(pAd, Elem->Rssi0, RSSI_0), ConvertToRssi(pAd, Elem->Rssi1, RSSI_1), ConvertToRssi(pAd, Elem->Rssi2, RSSI_2));
is_my_bssid = MAC_ADDR_EQUAL(Bssid, pAd->CommonCfg.Bssid)? TRUE : FALSE;
is_my_ssid = SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)? TRUE:FALSE;
// ignore BEACON not for my SSID
if ((! is_my_ssid) && (! is_my_bssid))
return;
// It means STA waits disassoc completely from this AP, ignores this beacon.
if (pAd->Mlme.CntlMachine.CurrState == CNTL_WAIT_DISASSOC)
return;
// Copy Control channel for this BSSID.
if (AddHtInfoLen != 0)
Channel = AddHtInfo.ControlChan;
if ((HtCapabilityLen > 0) || (PreNHtCapabilityLen > 0))
HtCapabilityLen = SIZE_HT_CAP_IE;
//
// Housekeeping "SsidBssTab" table for later-on ROAMing usage.
//
Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel);
if (Bssidx == BSS_NOT_FOUND)
{
// discover new AP of this network, create BSS entry
Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
&CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,
&HtCapability, &AddHtInfo,HtCapabilityLen,AddHtInfoLen,NewExtChannelOffset, Channel,
RealRssi, TimeStamp, CkipFlag, &EdcaParm, &QosCapability,
&QbssLoad, LenVIE, pVIE);
if (Bssidx == BSS_NOT_FOUND) // return if BSS table full
return;
NdisMoveMemory(pAd->ScanTab.BssEntry[Bssidx].PTSF, &Elem->Msg[24], 4);
NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[0], &Elem->TimeStamp.u.LowPart, 4);
NdisMoveMemory(&pAd->ScanTab.BssEntry[Bssidx].TTSF[4], &Elem->TimeStamp.u.LowPart, 4);
}
if ((pAd->CommonCfg.bIEEE80211H == 1) && (NewChannel != 0) && (Channel != NewChannel))
{
// Switching to channel 1 can prevent from rescanning the current channel immediately (by auto reconnection).
// In addition, clear the MLME queue and the scan table to discard the RX packets and previous scanning results.
AsicSwitchChannel(pAd, 1, FALSE);
AsicLockChannel(pAd, 1);
LinkDown(pAd, FALSE);
MlmeQueueInit(&pAd->Mlme.Queue);
BssTableInit(&pAd->ScanTab);
RTMPusecDelay(1000000); // use delay to prevent STA do reassoc
// channel sanity check
for (index = 0 ; index < pAd->ChannelListNum; index++)
{
if (pAd->ChannelList[index].Channel == NewChannel)
{
pAd->ScanTab.BssEntry[Bssidx].Channel = NewChannel;
pAd->CommonCfg.Channel = NewChannel;
AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
AsicLockChannel(pAd, pAd->CommonCfg.Channel);
DBGPRINT(RT_DEBUG_TRACE, ("PeerBeacon - STA receive channel switch announcement IE (New Channel =%d)\n", NewChannel));
break;
}
}
if (index >= pAd->ChannelListNum)
{
DBGPRINT_ERR(("PeerBeacon(can not find New Channel=%d in ChannelList[%d]\n", pAd->CommonCfg.Channel, pAd->ChannelListNum));
}
}
// if the ssid matched & bssid unmatched, we should select the bssid with large value.
// This might happened when two STA start at the same time
if ((! is_my_bssid) && ADHOC_ON(pAd))
{
INT i;
// Add the safeguard against the mismatch of adhoc wep status
if (pAd->StaCfg.WepStatus != pAd->ScanTab.BssEntry[Bssidx].WepStatus)
{
#ifdef RT30xx
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - Not matched wep status %d %d\n", pAd->StaCfg.WepStatus, pAd->ScanTab.BssEntry[Bssidx].WepStatus));
DBGPRINT(RT_DEBUG_TRACE, ("bssid=%s\n", pAd->ScanTab.BssEntry[Bssidx].Bssid));
#endif
return;
}
// collapse into the ADHOC network which has bigger BSSID value.
for (i = 0; i < 6; i++)
{
if (Bssid[i] > pAd->CommonCfg.Bssid[i])
{
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - merge to the IBSS with bigger BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n",
Bssid[0], Bssid[1], Bssid[2], Bssid[3], Bssid[4], Bssid[5]));
AsicDisableSync(pAd);
COPY_MAC_ADDR(pAd->CommonCfg.Bssid, Bssid);
AsicSetBssid(pAd, pAd->CommonCfg.Bssid);
MakeIbssBeacon(pAd); // re-build BEACON frame
AsicEnableIbssSync(pAd); // copy BEACON frame to on-chip memory
is_my_bssid = TRUE;
break;
}
else if (Bssid[i] < pAd->CommonCfg.Bssid[i])
break;
}
}
NdisGetSystemUpTime(&Now);
pBss = &pAd->ScanTab.BssEntry[Bssidx];
pBss->Rssi = RealRssi; // lastest RSSI
pBss->LastBeaconRxTime = Now; // last RX timestamp
//
// BEACON from my BSSID - either IBSS or INFRA network
//
if (is_my_bssid)
{
RXWI_STRUC RxWI;
pAd->StaCfg.DtimCount = DtimCount;
pAd->StaCfg.DtimPeriod = DtimPeriod;
pAd->StaCfg.LastBeaconRxTime = Now;
RxWI.RSSI0 = Elem->Rssi0;
RxWI.RSSI1 = Elem->Rssi1;
RxWI.RSSI2 = Elem->Rssi2;
Update_Rssi_Sample(pAd, &pAd->StaCfg.RssiSample, &RxWI);
if (AironetCellPowerLimit != 0xFF)
{
//
// We get the Cisco (ccx) "TxPower Limit" required
// Changed to appropriate TxPower Limit for Ciso Compatible Extensions
//
ChangeToCellPowerLimit(pAd, AironetCellPowerLimit);
}
else
{
//
// AironetCellPowerLimit equal to 0xFF means the Cisco (ccx) "TxPower Limit" not exist.
// Used the default TX Power Percentage, that set from UI.
//
pAd->CommonCfg.TxPowerPercentage = pAd->CommonCfg.TxPowerDefault;
}
if (ADHOC_ON(pAd) && (CAP_IS_IBSS_ON(CapabilityInfo)))
{
UCHAR MaxSupportedRateIn500Kbps = 0;
UCHAR idx;
MAC_TABLE_ENTRY *pEntry;
// supported rates array may not be sorted. sort it and find the maximum rate
for (idx=0; idx<SupRateLen; idx++)
{
if (MaxSupportedRateIn500Kbps < (SupRate[idx] & 0x7f))
MaxSupportedRateIn500Kbps = SupRate[idx] & 0x7f;
}
for (idx=0; idx<ExtRateLen; idx++)
{
if (MaxSupportedRateIn500Kbps < (ExtRate[idx] & 0x7f))
MaxSupportedRateIn500Kbps = ExtRate[idx] & 0x7f;
}
// look up the existing table
pEntry = MacTableLookup(pAd, Addr2);
// Ad-hoc mode is using MAC address as BA session. So we need to continuously find newly joined adhoc station by receiving beacon.
// To prevent always check this, we use wcid == RESERVED_WCID to recognize it as newly joined adhoc station.
if ((ADHOC_ON(pAd) && (Elem->Wcid == RESERVED_WCID)) ||
(pEntry && ((pEntry->LastBeaconRxTime + ADHOC_ENTRY_BEACON_LOST_TIME) < Now)))
{
if (pEntry == NULL)
// Another adhoc joining, add to our MAC table.
pEntry = MacTableInsertEntry(pAd, Addr2, BSS0, FALSE);
if (StaAddMacTableEntry(pAd, pEntry, MaxSupportedRateIn500Kbps, &HtCapability, HtCapabilityLen, CapabilityInfo) == FALSE)
{
DBGPRINT(RT_DEBUG_TRACE, ("ADHOC - Add Entry failed.\n"));
return;
}
if (pEntry &&
(Elem->Wcid == RESERVED_WCID))
{
idx = pAd->StaCfg.DefaultKeyId;
RT28XX_STA_SECURITY_INFO_ADD(pAd, BSS0, idx, pEntry);
}
}
if (pEntry && pEntry->ValidAsCLI)
pEntry->LastBeaconRxTime = Now;
// At least another peer in this IBSS, declare MediaState as CONNECTED
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
{
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED);
pAd->IndicateMediaState = NdisMediaStateConnected;
RTMP_IndicateMediaState(pAd);
pAd->ExtraInfo = GENERAL_LINK_UP;
AsicSetBssid(pAd, pAd->CommonCfg.Bssid);
// 2003/03/12 - john
// Make sure this entry in "ScanTab" table, thus complies to Microsoft's policy that
// "site survey" result should always include the current connected network.
//
Bssidx = BssTableSearch(&pAd->ScanTab, Bssid, Channel);
if (Bssidx == BSS_NOT_FOUND)
{
Bssidx = BssTableSetEntry(pAd, &pAd->ScanTab, Bssid, Ssid, SsidLen, BssType, BeaconPeriod,
&CfParm, AtimWin, CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen, &HtCapability,
&AddHtInfo, HtCapabilityLen, AddHtInfoLen, NewExtChannelOffset, Channel, RealRssi, TimeStamp, 0,
&EdcaParm, &QosCapability, &QbssLoad, LenVIE, pVIE);
}
DBGPRINT(RT_DEBUG_TRACE, ("ADHOC fOP_STATUS_MEDIA_STATE_CONNECTED.\n"));
}
}
if (INFRA_ON(pAd))
{
BOOLEAN bUseShortSlot, bUseBGProtection;
// decide to use/change to -
// 1. long slot (20 us) or short slot (9 us) time
// 2. turn on/off RTS/CTS and/or CTS-to-self protection
// 3. short preamble
//bUseShortSlot = pAd->CommonCfg.bUseShortSlotTime && CAP_IS_SHORT_SLOT(CapabilityInfo);
bUseShortSlot = CAP_IS_SHORT_SLOT(CapabilityInfo);
if (bUseShortSlot != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_SLOT_INUSED))
AsicSetSlotTime(pAd, bUseShortSlot);
bUseBGProtection = (pAd->CommonCfg.UseBGProtection == 1) || // always use
((pAd->CommonCfg.UseBGProtection == 0) && ERP_IS_USE_PROTECTION(Erp));
if (pAd->CommonCfg.Channel > 14) // always no BG protection in A-band. falsely happened when switching A/G band to a dual-band AP
bUseBGProtection = FALSE;
if (bUseBGProtection != OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED))
{
if (bUseBGProtection)
{
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED);
AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),FALSE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1));
}
else
{
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_BG_PROTECTION_INUSED);
AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, (OFDMSETPROTECT|CCKSETPROTECT|ALLN_SETPROTECT),TRUE,(pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1));
}
DBGPRINT(RT_DEBUG_WARN, ("SYNC - AP changed B/G protection to %d\n", bUseBGProtection));
}
// check Ht protection mode. and adhere to the Non-GF device indication by AP.
if ((AddHtInfoLen != 0) &&
((AddHtInfo.AddHtInfo2.OperaionMode != pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode) ||
(AddHtInfo.AddHtInfo2.NonGfPresent != pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent)))
{
pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent = AddHtInfo.AddHtInfo2.NonGfPresent;
pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode = AddHtInfo.AddHtInfo2.OperaionMode;
if (pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent == 1)
{
AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, TRUE);
}
else
AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP changed N OperaionMode to %d\n", pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode));
}
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED) &&
ERP_IS_USE_BARKER_PREAMBLE(Erp))
{
MlmeSetTxPreamble(pAd, Rt802_11PreambleLong);
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP forced to use LONG preamble\n"));
}
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WMM_INUSED) &&
(EdcaParm.bValid == TRUE) &&
(EdcaParm.EdcaUpdateCount != pAd->CommonCfg.APEdcaParm.EdcaUpdateCount))
{
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - AP change EDCA parameters(from %d to %d)\n",
pAd->CommonCfg.APEdcaParm.EdcaUpdateCount,
EdcaParm.EdcaUpdateCount));
AsicSetEdcaParm(pAd, &EdcaParm);
}
// copy QOS related information
NdisMoveMemory(&pAd->CommonCfg.APQbssLoad, &QbssLoad, sizeof(QBSS_LOAD_PARM));
NdisMoveMemory(&pAd->CommonCfg.APQosCapability, &QosCapability, sizeof(QOS_CAPABILITY_PARM));
}
// only INFRASTRUCTURE mode support power-saving feature
if ((INFRA_ON(pAd) && (pAd->StaCfg.Psm == PWR_SAVE)) || (pAd->CommonCfg.bAPSDForcePowerSave))
{
UCHAR FreeNumber;
// 1. AP has backlogged unicast-to-me frame, stay AWAKE, send PSPOLL
// 2. AP has backlogged broadcast/multicast frame and we want those frames, stay AWAKE
// 3. we have outgoing frames in TxRing or MgmtRing, better stay AWAKE
// 4. Psm change to PWR_SAVE, but AP not been informed yet, we better stay AWAKE
// 5. otherwise, put PHY back to sleep to save battery.
if (MessageToMe)
{
if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable &&
pAd->CommonCfg.bAPSDAC_BE && pAd->CommonCfg.bAPSDAC_BK && pAd->CommonCfg.bAPSDAC_VI && pAd->CommonCfg.bAPSDAC_VO)
{
pAd->CommonCfg.bNeedSendTriggerFrame = TRUE;
}
else
RT28XX_PS_POLL_ENQUEUE(pAd);
}
else if (BcastFlag && (DtimCount == 0) && OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM))
{
}
else if ((pAd->TxSwQueue[QID_AC_BK].Number != 0) ||
(pAd->TxSwQueue[QID_AC_BE].Number != 0) ||
(pAd->TxSwQueue[QID_AC_VI].Number != 0) ||
(pAd->TxSwQueue[QID_AC_VO].Number != 0) ||
(RTMPFreeTXDRequest(pAd, QID_AC_BK, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) ||
(RTMPFreeTXDRequest(pAd, QID_AC_BE, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) ||
(RTMPFreeTXDRequest(pAd, QID_AC_VI, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) ||
(RTMPFreeTXDRequest(pAd, QID_AC_VO, TX_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS) ||
(RTMPFreeTXDRequest(pAd, QID_MGMT, MGMT_RING_SIZE - 1, &FreeNumber) != NDIS_STATUS_SUCCESS))
{
// TODO: consider scheduled HCCA. might not be proper to use traditional DTIM-based power-saving scheme
// can we cheat here (i.e. just check MGMT & AC_BE) for better performance?
}
else
{
USHORT NextDtim = DtimCount;
if (NextDtim == 0)
NextDtim = DtimPeriod;
TbttNumToNextWakeUp = pAd->StaCfg.DefaultListenCount;
if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM) && (TbttNumToNextWakeUp > NextDtim))
TbttNumToNextWakeUp = NextDtim;
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
{
AsicSleepThenAutoWakeup(pAd, TbttNumToNextWakeUp);
}
}
}
}
// not my BSSID, ignore it
}
// sanity check fail, ignore this frame
}
/*
==========================================================================
Description:
Receive PROBE REQ from remote peer when operating in IBSS mode
==========================================================================
*/
VOID PeerProbeReqAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
UCHAR Addr2[MAC_ADDR_LEN];
CHAR Ssid[MAX_LEN_OF_SSID];
UCHAR SsidLen;
UCHAR HtLen, AddHtLen, NewExtLen;
HEADER_802_11 ProbeRspHdr;
NDIS_STATUS NStatus;
PUCHAR pOutBuffer = NULL;
ULONG FrameLen = 0;
LARGE_INTEGER FakeTimestamp;
UCHAR DsLen = 1, IbssLen = 2;
UCHAR LocalErpIe[3] = {IE_ERP, 1, 0};
BOOLEAN Privacy;
USHORT CapabilityInfo;
UCHAR RSNIe = IE_WPA;
if (! ADHOC_ON(pAd))
return;
if (PeerProbeReqSanity(pAd, Elem->Msg, Elem->MsgLen, Addr2, Ssid, &SsidLen))
{
if ((SsidLen == 0) || SSID_EQUAL(Ssid, SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen))
{
// allocate and send out ProbeRsp frame
NStatus = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if (NStatus != NDIS_STATUS_SUCCESS)
return;
//pAd->StaCfg.AtimWin = 0; // ??????
Privacy = (pAd->StaCfg.WepStatus == Ndis802_11Encryption1Enabled) ||
(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) ||
(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled);
CapabilityInfo = CAP_GENERATE(0, 1, Privacy, (pAd->CommonCfg.TxPreamble == Rt802_11PreambleShort), 0, 0);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11), &ProbeRspHdr,
TIMESTAMP_LEN, &FakeTimestamp,
2, &pAd->CommonCfg.BeaconPeriod,
2, &CapabilityInfo,
1, &SsidIe,
1, &pAd->CommonCfg.SsidLen,
pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid,
1, &SupRateIe,
1, &pAd->StaActive.SupRateLen,
pAd->StaActive.SupRateLen, pAd->StaActive.SupRate,
1, &DsIe,
1, &DsLen,
1, &pAd->CommonCfg.Channel,
1, &IbssIe,
1, &IbssLen,
2, &pAd->StaActive.AtimWin,
END_OF_ARGS);
if (pAd->StaActive.ExtRateLen)
{
ULONG tmp;
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
3, LocalErpIe,
1, &ExtRateIe,
1, &pAd->StaActive.ExtRateLen,
pAd->StaActive.ExtRateLen, &pAd->StaActive.ExtRate,
END_OF_ARGS);
FrameLen += tmp;
}
// If adhoc secruity is set for WPA-None, append the cipher suite IE
if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPANone)
{
ULONG tmp;
MakeOutgoingFrame(pOutBuffer + FrameLen, &tmp,
1, &RSNIe,
1, &pAd->StaCfg.RSNIE_Len,
pAd->StaCfg.RSNIE_Len, pAd->StaCfg.RSN_IE,
END_OF_ARGS);
FrameLen += tmp;
}
if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED)
{
ULONG TmpLen;
UCHAR BROADCOM[4] = {0x0, 0x90, 0x4c, 0x33};
HtLen = sizeof(pAd->CommonCfg.HtCapability);
AddHtLen = sizeof(pAd->CommonCfg.AddHTInfo);
NewExtLen = 1;
//New extension channel offset IE is included in Beacon, Probe Rsp or channel Switch Announcement Frame
if (pAd->bBroadComHT == TRUE)
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen,
1, &WpaIe,
4, &BROADCOM[0],
pAd->MlmeAux.HtCapabilityLen, &pAd->MlmeAux.HtCapability,
END_OF_ARGS);
}
else
{
MakeOutgoingFrame(pOutBuffer + FrameLen, &TmpLen,
1, &HtCapIe,
1, &HtLen,
sizeof(HT_CAPABILITY_IE), &pAd->CommonCfg.HtCapability,
1, &AddHtInfoIe,
1, &AddHtLen,
sizeof(ADD_HT_INFO_IE), &pAd->CommonCfg.AddHTInfo,
1, &NewExtChanIe,
1, &NewExtLen,
sizeof(NEW_EXT_CHAN_IE), &pAd->CommonCfg.NewExtChanOffset,
END_OF_ARGS);
}
FrameLen += TmpLen;
}
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
}
}
}
VOID BeaconTimeoutAtJoinAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("SYNC - BeaconTimeoutAtJoinAction\n"));
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_REJ_TIMEOUT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status);
}
/*
==========================================================================
Description:
Scan timeout procedure. basically add channel index by 1 and rescan
==========================================================================
*/
VOID ScanTimeoutAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
pAd->MlmeAux.Channel = NextChannel(pAd, pAd->MlmeAux.Channel);
// Only one channel scanned for CISCO beacon request
if ((pAd->MlmeAux.ScanType == SCAN_CISCO_ACTIVE) ||
(pAd->MlmeAux.ScanType == SCAN_CISCO_PASSIVE) ||
(pAd->MlmeAux.ScanType == SCAN_CISCO_NOISE) ||
(pAd->MlmeAux.ScanType == SCAN_CISCO_CHANNEL_LOAD))
pAd->MlmeAux.Channel = 0;
// this routine will stop if pAd->MlmeAux.Channel == 0
ScanNextChannel(pAd);
}
/*
==========================================================================
Description:
==========================================================================
*/
VOID InvalidStateWhenScan(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("AYNC - InvalidStateWhenScan(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState));
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_SCAN_CONF, 2, &Status);
}
/*
==========================================================================
Description:
==========================================================================
*/
VOID InvalidStateWhenJoin(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenJoin(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState));
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_JOIN_CONF, 2, &Status);
}
/*
==========================================================================
Description:
==========================================================================
*/
VOID InvalidStateWhenStart(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
USHORT Status;
DBGPRINT(RT_DEBUG_TRACE, ("InvalidStateWhenStart(state=%ld). Reset SYNC machine\n", pAd->Mlme.SyncMachine.CurrState));
pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
Status = MLME_STATE_MACHINE_REJECT;
MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_START_CONF, 2, &Status);
}
/*
==========================================================================
Description:
IRQL = DISPATCH_LEVEL
==========================================================================
*/
VOID EnqueuePsPoll(
IN PRTMP_ADAPTER pAd)
{
if (pAd->StaCfg.WindowsPowerMode == Ndis802_11PowerModeLegacy_PSP)
pAd->PsPollFrame.FC.PwrMgmt = PWR_SAVE;
MiniportMMRequest(pAd, 0, (PUCHAR)&pAd->PsPollFrame, sizeof(PSPOLL_FRAME));
}
/*
==========================================================================
Description:
==========================================================================
*/
VOID EnqueueProbeRequest(
IN PRTMP_ADAPTER pAd)
{
NDIS_STATUS NState;
PUCHAR pOutBuffer;
ULONG FrameLen = 0;
HEADER_802_11 Hdr80211;
DBGPRINT(RT_DEBUG_TRACE, ("force out a ProbeRequest ...\n"));
NState = MlmeAllocateMemory(pAd, &pOutBuffer); //Get an unused nonpaged memory
if (NState == NDIS_STATUS_SUCCESS)
{
MgtMacHeaderInit(pAd, &Hdr80211, SUBTYPE_PROBE_REQ, 0, BROADCAST_ADDR, BROADCAST_ADDR);
// this ProbeRequest explicitly specify SSID to reduce unwanted ProbeResponse
MakeOutgoingFrame(pOutBuffer, &FrameLen,
sizeof(HEADER_802_11), &Hdr80211,
1, &SsidIe,
1, &pAd->CommonCfg.SsidLen,
pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid,
1, &SupRateIe,
1, &pAd->StaActive.SupRateLen,
pAd->StaActive.SupRateLen, pAd->StaActive.SupRate,
END_OF_ARGS);
MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
}
}
BOOLEAN ScanRunning(
IN PRTMP_ADAPTER pAd)
{
return (pAd->Mlme.SyncMachine.CurrState == SCAN_LISTEN) ? TRUE : FALSE;
}
/* #include "../../rt2860/sta/wpa.c"
*************************************************************************
* 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:
wpa.c
Abstract:
Revision History:
Who When What
-------- ---------- ----------------------------------------------
Jan Lee 03-07-22 Initial
Paul Lin 03-11-28 Modify for supplicant
*/
#include "../rt_config.h"
#define WPARSNIE 0xdd
#define WPA2RSNIE 0x30
//extern UCHAR BIT8[];
UCHAR CipherWpaPskTkip[] = {
0xDD, 0x16, // RSN IE
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x50, 0xf2, 0x02, // Multicast
0x01, 0x00, // Number of unicast
0x00, 0x50, 0xf2, 0x02, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x50, 0xf2, 0x02 // authentication
};
UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR));
UCHAR CipherWpaPskAes[] = {
0xDD, 0x16, // RSN IE
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x50, 0xf2, 0x04, // Multicast
0x01, 0x00, // Number of unicast
0x00, 0x50, 0xf2, 0x04, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x50, 0xf2, 0x02 // authentication
};
UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR));
UCHAR CipherSuiteCiscoCCKM[] = {
0xDD, 0x16, // RSN IE
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x40, 0x96, 0x01, // Multicast
0x01, 0x00, // Number of uicast
0x00, 0x40, 0x96, 0x01, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x40, 0x96, 0x00 // Authentication
};
UCHAR CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR));
UCHAR CipherSuiteCiscoCCKM24[] = {
0xDD, 0x18, // RSN IE
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x40, 0x96, 0x01, // Multicast
0x01, 0x00, // Number of uicast
0x00, 0x40, 0x96, 0x01, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x40, 0x96, 0x00,
0x28, 0x00// Authentication
};
UCHAR CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR));
UCHAR CipherSuiteCCXTkip[] = {
0xDD, 0x16, // RSN IE
0x00, 0x50, 0xf2, 0x01, // oui
0x01, 0x00, // Version
0x00, 0x50, 0xf2, 0x02, // Multicast
0x01, 0x00, // Number of unicast
0x00, 0x50, 0xf2, 0x02, // unicast
0x01, 0x00, // number of authentication method
0x00, 0x50, 0xf2, 0x01 // authentication
};
UCHAR CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR));
UCHAR CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02};
UCHAR LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
UCHAR EAPOL_FRAME[] = {0x88, 0x8E};
BOOLEAN CheckRSNIE(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pData,
IN UCHAR DataLen,
OUT UCHAR *Offset);
void inc_byte_array(UCHAR *counter, int len);
/*
========================================================================
Routine Description:
Classify WPA EAP message type
Arguments:
EAPType Value of EAP message type
MsgType Internal Message definition for MLME state machine
Return Value:
TRUE Found appropriate message type
FALSE No appropriate message type
IRQL = DISPATCH_LEVEL
Note:
All these constants are defined in wpa.h
For supplicant, there is only EAPOL Key message avaliable
========================================================================
*/
BOOLEAN WpaMsgTypeSubst(
IN UCHAR EAPType,
OUT INT *MsgType)
{
switch (EAPType)
{
case EAPPacket:
*MsgType = MT2_EAPPacket;
break;
case EAPOLStart:
*MsgType = MT2_EAPOLStart;
break;
case EAPOLLogoff:
*MsgType = MT2_EAPOLLogoff;
break;
case EAPOLKey:
*MsgType = MT2_EAPOLKey;
break;
case EAPOLASFAlert:
*MsgType = MT2_EAPOLASFAlert;
break;
default:
return FALSE;
}
return TRUE;
}
/*
==========================================================================
Description:
association state machine init, including state transition and timer init
Parameters:
S - pointer to the association state machine
==========================================================================
*/
VOID WpaPskStateMachineInit(
IN PRTMP_ADAPTER pAd,
IN STATE_MACHINE *S,
OUT STATE_MACHINE_FUNC Trans[])
{
StateMachineInit(S, Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE);
StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction);
}
/*
==========================================================================
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 WpaEAPOLKeyAction(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
INT MsgType = EAPOL_MSG_INVALID;
PKEY_DESCRIPTER pKeyDesc;
PHEADER_802_11 pHeader; //red
UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY];
UCHAR EapolVr;
KEY_INFO peerKeyInfo;
DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n"));
// Get 802.11 header first
pHeader = (PHEADER_802_11) Elem->Msg;
// Get EAPoL-Key Descriptor
pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)];
NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO));
*((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo));
// 1. Check EAPOL frame version and type
EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H];
if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC)))
{
DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n"));
return;
}
// First validate replay counter, only accept message with larger replay counter
// Let equal pass, some AP start with all zero replay counter
NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY);
if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) &&
(RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0))
{
DBGPRINT(RT_DEBUG_ERROR, (" ReplayCounter not match \n"));
return;
}
// Process WPA2PSK frame
if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
{
if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
(peerKeyInfo.EKD_DL == 0) &&
(peerKeyInfo.KeyAck == 1) &&
(peerKeyInfo.KeyMic == 0) &&
(peerKeyInfo.Secure == 0) &&
(peerKeyInfo.Error == 0) &&
(peerKeyInfo.Request == 0))
{
MsgType = EAPOL_PAIR_MSG_1;
DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n"));
} else if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
(peerKeyInfo.EKD_DL == 1) &&
(peerKeyInfo.KeyAck == 1) &&
(peerKeyInfo.KeyMic == 1) &&
(peerKeyInfo.Secure == 1) &&
(peerKeyInfo.Error == 0) &&
(peerKeyInfo.Request == 0))
{
MsgType = EAPOL_PAIR_MSG_3;
DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n"));
} else if((peerKeyInfo.KeyType == GROUPKEY) &&
(peerKeyInfo.EKD_DL == 1) &&
(peerKeyInfo.KeyAck == 1) &&
(peerKeyInfo.KeyMic == 1) &&
(peerKeyInfo.Secure == 1) &&
(peerKeyInfo.Error == 0) &&
(peerKeyInfo.Request == 0))
{
MsgType = EAPOL_GROUP_MSG_1;
DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n"));
}
// We will assume link is up (assoc suceess and port not secured).
// All state has to be able to process message from previous state
switch(pAd->StaCfg.WpaState)
{
case SS_START:
if(MsgType == EAPOL_PAIR_MSG_1)
{
Wpa2PairMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
}
break;
case SS_WAIT_MSG_3:
if(MsgType == EAPOL_PAIR_MSG_1)
{
Wpa2PairMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
}
else if(MsgType == EAPOL_PAIR_MSG_3)
{
Wpa2PairMsg3Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_GROUP;
}
break;
case SS_WAIT_GROUP: // When doing group key exchange
case SS_FINISH: // This happened when update group key
if(MsgType == EAPOL_PAIR_MSG_1)
{
// Reset port secured variable
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
Wpa2PairMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
}
else if(MsgType == EAPOL_PAIR_MSG_3)
{
// Reset port secured variable
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
Wpa2PairMsg3Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_GROUP;
}
else if(MsgType == EAPOL_GROUP_MSG_1)
{
WpaGroupMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_FINISH;
}
break;
default:
break;
}
}
// Process WPAPSK Frame
// Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant
else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)
{
if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
(peerKeyInfo.KeyIndex == 0) &&
(peerKeyInfo.KeyAck == 1) &&
(peerKeyInfo.KeyMic == 0) &&
(peerKeyInfo.Secure == 0) &&
(peerKeyInfo.Error == 0) &&
(peerKeyInfo.Request == 0))
{
MsgType = EAPOL_PAIR_MSG_1;
DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n"));
}
else if((peerKeyInfo.KeyType == PAIRWISEKEY) &&
(peerKeyInfo.KeyIndex == 0) &&
(peerKeyInfo.KeyAck == 1) &&
(peerKeyInfo.KeyMic == 1) &&
(peerKeyInfo.Secure == 0) &&
(peerKeyInfo.Error == 0) &&
(peerKeyInfo.Request == 0))
{
MsgType = EAPOL_PAIR_MSG_3;
DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n"));
}
else if((peerKeyInfo.KeyType == GROUPKEY) &&
(peerKeyInfo.KeyIndex != 0) &&
(peerKeyInfo.KeyAck == 1) &&
(peerKeyInfo.KeyMic == 1) &&
(peerKeyInfo.Secure == 1) &&
(peerKeyInfo.Error == 0) &&
(peerKeyInfo.Request == 0))
{
MsgType = EAPOL_GROUP_MSG_1;
DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n"));
}
// We will assume link is up (assoc suceess and port not secured).
// All state has to be able to process message from previous state
switch(pAd->StaCfg.WpaState)
{
case SS_START:
if(MsgType == EAPOL_PAIR_MSG_1)
{
WpaPairMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
}
break;
case SS_WAIT_MSG_3:
if(MsgType == EAPOL_PAIR_MSG_1)
{
WpaPairMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
}
else if(MsgType == EAPOL_PAIR_MSG_3)
{
WpaPairMsg3Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_GROUP;
}
break;
case SS_WAIT_GROUP: // When doing group key exchange
case SS_FINISH: // This happened when update group key
if(MsgType == EAPOL_PAIR_MSG_1)
{
WpaPairMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_MSG_3;
// Reset port secured variable
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
}
else if(MsgType == EAPOL_PAIR_MSG_3)
{
WpaPairMsg3Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_WAIT_GROUP;
// Reset port secured variable
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
}
else if(MsgType == EAPOL_GROUP_MSG_1)
{
WpaGroupMsg1Action(pAd, Elem);
pAd->StaCfg.WpaState = SS_FINISH;
}
break;
default:
break;
}
}
DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n"));
}
/*
========================================================================
Routine Description:
Process Pairwise key 4-way handshaking
Arguments:
pAd Pointer to our adapter
Elem Message body
Return Value:
None
Note:
========================================================================
*/
VOID WpaPairMsg1Action(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PHEADER_802_11 pHeader;
UCHAR *mpool, *PTK, *digest;
PUCHAR pOutBuffer = NULL;
UCHAR Header802_3[14];
ULONG FrameLen = 0;
PEAPOL_PACKET pMsg1;
EAPOL_PACKET Packet;
UCHAR Mic[16];
DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n"));
// allocate memory pool
os_alloc_mem(pAd, (PUCHAR *)&mpool, 256);
if (mpool == NULL)
return;
// PTK Len = 80.
PTK = (UCHAR *) ROUND_UP(mpool, 4);
// digest Len = 80.
digest = (UCHAR *) ROUND_UP(PTK + 80, 4);
pHeader = (PHEADER_802_11) Elem->Msg;
// Process message 1 from authenticator
pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
// 1. Save Replay counter, it will use to verify message 3 and construct message 2
NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// 2. Save ANonce
NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE);
// Generate random SNonce
GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce);
// Calc PTK(ANonce, SNonce)
WpaCountPTK(pAd,
pAd->StaCfg.PMK,
pAd->StaCfg.ANonce,
pAd->CommonCfg.Bssid,
pAd->StaCfg.SNonce,
pAd->CurrentAddress,
PTK,
LEN_PTK);
// Save key to PTK entry
NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK);
// init 802.3 header and Fill Packet
MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
// Zero Message 2 body
NdisZeroMemory(&Packet, sizeof(Packet));
Packet.ProVer = EAPOL_VER;
Packet.ProType = EAPOLKey;
//
// Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE)
//
Packet.KeyDesc.Type = WPA1_KEY_DESC;
// 1. Key descriptor version and appropriate RSN IE
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
Packet.KeyDesc.KeyInfo.KeyDescVer = 2;
}
else // TKIP
{
Packet.KeyDesc.KeyInfo.KeyDescVer = 1;
}
// fill in Data Material and its length
Packet.KeyDesc.KeyData[0] = IE_WPA;
Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len;
Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2;
NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len);
// Update packet length after decide Key data payload
Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1];
// Update Key length
Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0];
Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1];
// 2. Key Type PeerKey
Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
// 3. KeyMic field presented
Packet.KeyDesc.KeyInfo.KeyMic = 1;
//Convert to little-endian format.
*((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
// 4. Fill SNonce
NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE);
// 5. Key Replay Count
NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY);
// Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE)
// Out buffer for transmitting message 2
MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory
if(pOutBuffer == NULL)
{
os_free_mem(pAd, mpool);
return;
}
// Prepare EAPOL frame for MIC calculation
// Be careful, only EAPOL frame is counted for MIC calculation
MakeOutgoingFrame(pOutBuffer, &FrameLen,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// 6. Prepare and Fill MIC value
NdisZeroMemory(Mic, sizeof(Mic));
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{ // AES
HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{ // TKIP
hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
}
NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
//hex_dump("MIC", Mic, LEN_KEY_DESC_MIC);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
LENGTH_802_3, &Header802_3,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// 5. Copy frame to Tx ring and send Msg 2 to authenticator
RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
os_free_mem(pAd, (PUCHAR)mpool);
DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n"));
}
VOID Wpa2PairMsg1Action(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PHEADER_802_11 pHeader;
UCHAR *mpool, *PTK, *digest;
PUCHAR pOutBuffer = NULL;
UCHAR Header802_3[14];
ULONG FrameLen = 0;
PEAPOL_PACKET pMsg1;
EAPOL_PACKET Packet;
UCHAR Mic[16];
DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n"));
// allocate memory pool
os_alloc_mem(pAd, (PUCHAR *)&mpool, 256);
if (mpool == NULL)
return;
// PTK Len = 80.
PTK = (UCHAR *) ROUND_UP(mpool, 4);
// digest Len = 80.
digest = (UCHAR *) ROUND_UP(PTK + 80, 4);
pHeader = (PHEADER_802_11) Elem->Msg;
// Process message 1 from authenticator
pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
// 1. Save Replay counter, it will use to verify message 3 and construct message 2
NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// 2. Save ANonce
NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE);
// Generate random SNonce
GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce);
if(pMsg1->KeyDesc.KeyDataLen[1] > 0 )
{
// cached PMKID
}
// Calc PTK(ANonce, SNonce)
WpaCountPTK(pAd,
pAd->StaCfg.PMK,
pAd->StaCfg.ANonce,
pAd->CommonCfg.Bssid,
pAd->StaCfg.SNonce,
pAd->CurrentAddress,
PTK,
LEN_PTK);
// Save key to PTK entry
NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK);
// init 802.3 header and Fill Packet
MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
// Zero message 2 body
NdisZeroMemory(&Packet, sizeof(Packet));
Packet.ProVer = EAPOL_VER;
Packet.ProType = EAPOLKey;
//
// Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE)
//
Packet.KeyDesc.Type = WPA2_KEY_DESC;
// 1. Key descriptor version and appropriate RSN IE
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
Packet.KeyDesc.KeyInfo.KeyDescVer = 2;
}
else // TKIP
{
Packet.KeyDesc.KeyInfo.KeyDescVer = 1;
}
// fill in Data Material and its length
Packet.KeyDesc.KeyData[0] = IE_WPA2;
Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len;
Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2;
NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len);
// Update packet length after decide Key data payload
Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1];
// 2. Key Type PeerKey
Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
// 3. KeyMic field presented
Packet.KeyDesc.KeyInfo.KeyMic = 1;
// Update Key Length
Packet.KeyDesc.KeyLength[0] = 0;
Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1];
// 4. Fill SNonce
NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE);
// 5. Key Replay Count
NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY);
// Convert to little-endian format.
*((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
// Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE)
// Out buffer for transmitting message 2
MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory
if(pOutBuffer == NULL)
{
os_free_mem(pAd, mpool);
return;
}
// Prepare EAPOL frame for MIC calculation
// Be careful, only EAPOL frame is counted for MIC calculation
MakeOutgoingFrame(pOutBuffer, &FrameLen,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// 6. Prepare and Fill MIC value
NdisZeroMemory(Mic, sizeof(Mic));
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// AES
HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{
hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
}
NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
// Make Transmitting frame
MakeOutgoingFrame(pOutBuffer, &FrameLen,
LENGTH_802_3, &Header802_3,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// 5. Copy frame to Tx ring
RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
MlmeFreeMemory(pAd, pOutBuffer);
os_free_mem(pAd, mpool);
DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n"));
}
/*
========================================================================
Routine Description:
Process Pairwise key 4-way handshaking
Arguments:
pAd Pointer to our adapter
Elem Message body
Return Value:
None
Note:
========================================================================
*/
VOID WpaPairMsg3Action(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PHEADER_802_11 pHeader;
PUCHAR pOutBuffer = NULL;
UCHAR Header802_3[14];
ULONG FrameLen = 0;
EAPOL_PACKET Packet;
PEAPOL_PACKET pMsg3;
UCHAR Mic[16], OldMic[16];
MAC_TABLE_ENTRY *pEntry = NULL;
UCHAR skip_offset;
KEY_INFO peerKeyInfo;
DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n"));
// Record 802.11 header & the received EAPOL packet Msg3
pHeader = (PHEADER_802_11) Elem->Msg;
pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO));
*((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo));
// 1. Verify cipher type match
if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2))
{
return;
}
else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1))
{
return;
}
// Verify RSN IE
//if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len))
if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset))
{
DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n"));
hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len);
hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]);
return;
}
else
DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n"));
// 2. Check MIC value
// Save the MIC and replace with zero
NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// AES
UCHAR digest[80];
HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else // TKIP
{
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic);
}
if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC))
{
DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n"));
return;
}
else
DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n"));
// 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger
if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1)
return;
// Update new replay counter
NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// 4. Double check ANonce
if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE))
return;
// init 802.3 header and Fill Packet
MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
// Zero Message 4 body
NdisZeroMemory(&Packet, sizeof(Packet));
Packet.ProVer = EAPOL_VER;
Packet.ProType = EAPOLKey;
Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field
//
// Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0)
//
Packet.KeyDesc.Type = WPA1_KEY_DESC;
// Key descriptor version and appropriate RSN IE
Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer;
// Update Key Length
Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0];
Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1];
// Key Type PeerKey
Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
// KeyMic field presented
Packet.KeyDesc.KeyInfo.KeyMic = 1;
// In Msg3, KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS
// Station sends Msg4 KeyInfo.secure should be the same as that in Msg.3
Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure;
// Convert to little-endian format.
*((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
// Key Replay count
NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// Out buffer for transmitting message 4
MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory
if(pOutBuffer == NULL)
return;
// Prepare EAPOL frame for MIC calculation
// Be careful, only EAPOL frame is counted for MIC calculation
MakeOutgoingFrame(pOutBuffer, &FrameLen,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// Prepare and Fill MIC value
NdisZeroMemory(Mic, sizeof(Mic));
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// AES
UCHAR digest[80];
HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
}
NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
// Update PTK
// Prepare pair-wise key information into shared key table
NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY));
pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK;
NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
// Decide its ChiperAlg
if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP;
else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled)
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES;
else
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE;
// Update these related information to MAC_TABLE_ENTRY
pEntry = &pAd->MacTab.Content[BSSID_WCID];
NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg;
// Update pairwise key information to ASIC Shared Key Table
AsicAddSharedKeyEntry(pAd,
BSS0,
0,
pAd->SharedKey[BSS0][0].CipherAlg,
pAd->SharedKey[BSS0][0].Key,
pAd->SharedKey[BSS0][0].TxMic,
pAd->SharedKey[BSS0][0].RxMic);
// Update ASIC WCID attribute table and IVEIV table
RTMPAddWcidAttributeEntry(pAd,
BSS0,
0,
pAd->SharedKey[BSS0][0].CipherAlg,
pEntry);
// Make transmitting frame
MakeOutgoingFrame(pOutBuffer, &FrameLen,
LENGTH_802_3, &Header802_3,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// Copy frame to Tx ring and Send Message 4 to authenticator
RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n"));
}
VOID Wpa2PairMsg3Action(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PHEADER_802_11 pHeader;
PUCHAR pOutBuffer = NULL;
UCHAR Header802_3[14];
ULONG FrameLen = 0;
EAPOL_PACKET Packet;
PEAPOL_PACKET pMsg3;
UCHAR Mic[16], OldMic[16];
UCHAR *mpool, *KEYDATA, *digest;
UCHAR Key[32];
MAC_TABLE_ENTRY *pEntry = NULL;
KEY_INFO peerKeyInfo;
// allocate memory
os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024);
if(mpool == NULL)
return;
// KEYDATA Len = 512.
KEYDATA = (UCHAR *) ROUND_UP(mpool, 4);
// digest Len = 80.
digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4);
DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n"));
pHeader = (PHEADER_802_11) Elem->Msg;
// Process message 3 frame.
pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO));
*((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo));
// 1. Verify cipher type match
if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2))
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1))
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
// 2. Check MIC value
// Save the MIC and replace with zero
NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// AES
HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic);
}
if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC))
{
DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n"));
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
else
DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n"));
// 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger
if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1)
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
// Update new replay counter
NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// 4. Double check ANonce
if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE))
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
// Obtain GTK
// 5. Decrypt GTK from Key Data
DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL));
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// Decrypt AES GTK
AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData);
}
else // TKIP
{
INT i;
// Decrypt TKIP GTK
// Construct 32 bytes RC4 Key
NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16);
NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16);
ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32);
//discard first 256 bytes
for(i = 0; i < 256; i++)
ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT);
// Decrypt GTK. Becareful, there is no ICV to check the result is correct or not
ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]);
}
if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1))
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
// Update GTK to ASIC
// Update group key information to ASIC Shared Key Table
AsicAddSharedKeyEntry(pAd,
BSS0,
pAd->StaCfg.DefaultKeyId,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic);
// Update ASIC WCID attribute table and IVEIV table
RTMPAddWcidAttributeEntry(pAd,
BSS0,
pAd->StaCfg.DefaultKeyId,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
NULL);
// init 802.3 header and Fill Packet
MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
// Zero message 4 body
NdisZeroMemory(&Packet, sizeof(Packet));
Packet.ProVer = EAPOL_VER;
Packet.ProType = EAPOLKey;
Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field
//
// Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0)
//
Packet.KeyDesc.Type = WPA2_KEY_DESC;
// Key descriptor version and appropriate RSN IE
Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer;
// Update Key Length
Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0];
Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1];
// Key Type PeerKey
Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY;
// KeyMic field presented
Packet.KeyDesc.KeyInfo.KeyMic = 1;
Packet.KeyDesc.KeyInfo.Secure = 1;
// Convert to little-endian format.
*((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
// Key Replay count
NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// Out buffer for transmitting message 4
MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory
if(pOutBuffer == NULL)
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
// Prepare EAPOL frame for MIC calculation
// Be careful, only EAPOL frame is counted for MIC calculation
MakeOutgoingFrame(pOutBuffer, &FrameLen,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// Prepare and Fill MIC value
NdisZeroMemory(Mic, sizeof(Mic));
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// AES
HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
}
NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
// Update PTK
// Prepare pair-wise key information into shared key table
NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY));
pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK;
NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
// Decide its ChiperAlg
if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled)
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP;
else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled)
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES;
else
pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE;
// Update these related information to MAC_TABLE_ENTRY
pEntry = &pAd->MacTab.Content[BSSID_WCID];
NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK);
NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK);
NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK);
pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg;
// Update pairwise key information to ASIC Shared Key Table
AsicAddSharedKeyEntry(pAd,
BSS0,
0,
pAd->SharedKey[BSS0][0].CipherAlg,
pAd->SharedKey[BSS0][0].Key,
pAd->SharedKey[BSS0][0].TxMic,
pAd->SharedKey[BSS0][0].RxMic);
// Update ASIC WCID attribute table and IVEIV table
RTMPAddWcidAttributeEntry(pAd,
BSS0,
0,
pAd->SharedKey[BSS0][0].CipherAlg,
pEntry);
// Make Transmitting frame
MakeOutgoingFrame(pOutBuffer, &FrameLen,
LENGTH_802_3, &Header802_3,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// Copy frame to Tx ring and Send Message 4 to authenticator
RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE);
// set 802.1x port control
STA_PORT_SECURED(pAd);
// Indicate Connected for GUI
pAd->IndicateMediaState = NdisMediaStateConnected;
MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
os_free_mem(pAd, (PUCHAR)mpool);
// send wireless event - for set key done WPA2
if (pAd->CommonCfg.bWirelessEvent)
RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0);
DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n"));
}
/*
========================================================================
Routine Description:
Process Group key 2-way handshaking
Arguments:
pAd Pointer to our adapter
Elem Message body
Return Value:
None
Note:
========================================================================
*/
VOID WpaGroupMsg1Action(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PUCHAR pOutBuffer = NULL;
UCHAR Header802_3[14];
ULONG FrameLen = 0;
EAPOL_PACKET Packet;
PEAPOL_PACKET pGroup;
UCHAR *mpool, *digest, *KEYDATA;
UCHAR Mic[16], OldMic[16];
UCHAR GTK[32], Key[32];
KEY_INFO peerKeyInfo;
// allocate memory
os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024);
if(mpool == NULL)
return;
// digest Len = 80.
digest = (UCHAR *) ROUND_UP(mpool, 4);
// KEYDATA Len = 512.
KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4);
DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n"));
// Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8)
pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H];
NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo));
NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO));
*((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo));
// 0. Check cipher type match
if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2))
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1))
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
// 1. Verify Replay counter
// Check Replay Counter, it has to be larger than last one. No need to be exact one larger
if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1)
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
// Update new replay counter
NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// 2. Verify MIC is valid
// Save the MIC and replace with zero
NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC);
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{ // AES
HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{ // TKIP
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic);
}
if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC))
{
DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n"));
MlmeFreeMemory(pAd, (PUCHAR)mpool);
return;
}
else
DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n"));
// 3. Decrypt GTK from Key Data
if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// Decrypt AES GTK
AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData);
}
else // TKIP
{
INT i;
// Decrypt TKIP GTK
// Construct 32 bytes RC4 Key
NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16);
NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16);
ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32);
//discard first 256 bytes
for(i = 0; i < 256; i++)
ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT);
// Decrypt GTK. Becareful, there is no ICV to check the result is correct or not
ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]);
}
// Process decrypted key data material
// Parse keyData to handle KDE format for WPA2PSK
if (peerKeyInfo.EKD_DL)
{
if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0))
{
os_free_mem(pAd, (PUCHAR)mpool);
return;
}
}
else // WPAPSK
{
// set key material, TxMic and RxMic for WPAPSK
NdisMoveMemory(GTK, KEYDATA, 32);
NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32);
pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex;
// Prepare pair-wise key information into shared key table
NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY));
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK;
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK);
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &GTK[16], LEN_TKIP_RXMICK);
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &GTK[24], LEN_TKIP_TXMICK);
// Update Shared Key CipherAlg
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE;
if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP;
else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES;
#ifndef RT30xx
else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64;
else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128;
#endif
//hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK);
}
// Update group key information to ASIC Shared Key Table
AsicAddSharedKeyEntry(pAd,
BSS0,
pAd->StaCfg.DefaultKeyId,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic);
// Update ASIC WCID attribute table and IVEIV table
RTMPAddWcidAttributeEntry(pAd,
BSS0,
pAd->StaCfg.DefaultKeyId,
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg,
NULL);
// set 802.1x port control
STA_PORT_SECURED(pAd);
// Indicate Connected for GUI
pAd->IndicateMediaState = NdisMediaStateConnected;
// init header and Fill Packet
MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
// Zero Group message 1 body
NdisZeroMemory(&Packet, sizeof(Packet));
Packet.ProVer = EAPOL_VER;
Packet.ProType = EAPOLKey;
Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field
//
// Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0)
//
if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)
{
Packet.KeyDesc.Type = WPA2_KEY_DESC;
}
else
{
Packet.KeyDesc.Type = WPA1_KEY_DESC;
}
// Key descriptor version and appropriate RSN IE
Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer;
// Update Key Length
Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0];
Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1];
// Key Index as G-Msg 1
if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)
Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex;
// Key Type Group key
Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY;
// KeyMic field presented
Packet.KeyDesc.KeyInfo.KeyMic = 1;
// Secure bit
Packet.KeyDesc.KeyInfo.Secure = 1;
// Convert to little-endian format.
*((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
// Key Replay count
NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY);
// Out buffer for transmitting group message 2
MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory
if(pOutBuffer == NULL)
{
MlmeFreeMemory(pAd, (PUCHAR)mpool);
return;
}
// Prepare EAPOL frame for MIC calculation
// Be careful, only EAPOL frame is counted for MIC calculation
MakeOutgoingFrame(pOutBuffer, &FrameLen,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// Prepare and Fill MIC value
NdisZeroMemory(Mic, sizeof(Mic));
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
// AES
HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
}
NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
LENGTH_802_3, &Header802_3,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// 5. Copy frame to Tx ring and prepare for encryption
RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE);
// 6 Free allocated memory
MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
os_free_mem(pAd, (PUCHAR)mpool);
// send wireless event - for set key done WPA2
if (pAd->CommonCfg.bWirelessEvent)
RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n"));
}
/*
========================================================================
Routine Description:
Init WPA MAC header
Arguments:
pAd Pointer to our adapter
Return Value:
None
Note:
========================================================================
*/
VOID WpaMacHeaderInit(
IN PRTMP_ADAPTER pAd,
IN OUT PHEADER_802_11 pHdr80211,
IN UCHAR wep,
IN PUCHAR pAddr1)
{
NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11));
pHdr80211->FC.Type = BTYPE_DATA;
pHdr80211->FC.ToDs = 1;
if (wep == 1)
pHdr80211->FC.Wep = 1;
// Addr1: BSSID, Addr2: SA, Addr3: DA
COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1);
COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);
COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid);
pHdr80211->Sequence = pAd->Sequence;
}
/*
========================================================================
Routine Description:
Copy frame from waiting queue into relative ring buffer and set
appropriate ASIC register to kick hardware encryption before really
sent out to air.
Arguments:
pAd Pointer to our adapter
PNDIS_PACKET Pointer to outgoing Ndis frame
NumberOfFrag Number of fragment required
Return Value:
None
Note:
========================================================================
*/
VOID RTMPToWirelessSta(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pHeader802_3,
IN UINT HdrLen,
IN PUCHAR pData,
IN UINT DataLen,
IN BOOLEAN is4wayFrame)
{
NDIS_STATUS Status;
PNDIS_PACKET pPacket;
UCHAR Index;
do
{
// 1. build a NDIS packet and call RTMPSendPacket();
// be careful about how/when to release this internal allocated NDIS PACKET buffer
Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen);
if (Status != NDIS_STATUS_SUCCESS)
break;
if (is4wayFrame)
RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1);
else
RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0);
// 2. send out the packet
Status = STASendPacket(pAd, pPacket);
if(Status == NDIS_STATUS_SUCCESS)
{
// Dequeue one frame from TxSwQueue0..3 queue and process it
// There are three place calling dequeue for TX ring.
// 1. Here, right after queueing the frame.
// 2. At the end of TxRingTxDone service routine.
// 3. Upon NDIS call RTMPSendPackets
if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) &&
(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)))
{
for(Index = 0; Index < 5; Index ++)
if(pAd->TxSwQueue[Index].Number > 0)
RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS);
}
}
} while(FALSE);
}
/*
========================================================================
Routine Description:
Check Sanity RSN IE form AP
Arguments:
Return Value:
========================================================================
*/
BOOLEAN CheckRSNIE(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pData,
IN UCHAR DataLen,
OUT UCHAR *Offset)
{
PUCHAR pVIE;
UCHAR len;
PEID_STRUCT pEid;
BOOLEAN result = FALSE;
pVIE = pData;
len = DataLen;
*Offset = 0;
while (len > sizeof(RSNIE2))
{
pEid = (PEID_STRUCT) pVIE;
// WPA RSN IE
if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)))
{
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) &&
(NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) &&
(pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2)))
{
DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2)));
result = TRUE;
}
*Offset += (pEid->Len + 2);
}
// WPA2 RSN IE
else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)))
{
if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) &&
(NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) &&
(pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2)))
{
DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2)));
result = TRUE;
}
*Offset += (pEid->Len + 2);
}
else
{
break;
}
pVIE += (pEid->Len + 2);
len -= (pEid->Len + 2);
}
DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset));
return result;
}
/*
========================================================================
Routine Description:
Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK.
GTK is encaptulated in KDE format at p.83 802.11i D10
Arguments:
Return Value:
Note:
802.11i D10
========================================================================
*/
BOOLEAN ParseKeyData(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pKeyData,
IN UCHAR KeyDataLen,
IN UCHAR bPairewise)
{
PKDE_ENCAP pKDE = NULL;
PUCHAR pMyKeyData = pKeyData;
UCHAR KeyDataLength = KeyDataLen;
UCHAR GTKLEN;
UCHAR skip_offset;
// Verify The RSN IE contained in Pairewise-Msg 3 and skip it
if (bPairewise)
{
// Check RSN IE whether it is WPA2/WPA2PSK
if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset))
{
DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n"));
hex_dump("Get KEYDATA :", pKeyData, KeyDataLen);
return FALSE;
}
else
{
// skip RSN IE
pMyKeyData += skip_offset;
KeyDataLength -= skip_offset;
//DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset));
}
}
DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength));
// Parse EKD format
if (KeyDataLength >= 8)
{
pKDE = (PKDE_ENCAP) pMyKeyData;
}
else
{
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n"));
return FALSE;
}
// Sanity check - shared key index should not be 0
if (pKDE->GTKEncap.Kid == 0)
{
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n"));
return FALSE;
}
// Sanity check - KED length
if (KeyDataLength < (pKDE->Len + 2))
{
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n"));
return FALSE;
}
// Get GTK length - refer to IEEE 802.11i-2004 p.82
GTKLEN = pKDE->Len -6;
#ifdef RT30xx
if (GTKLEN < LEN_AES_KEY)
#endif
#ifndef RT30xx
if (GTKLEN < MIN_LEN_OF_GTK)
#endif
{
DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN));
return FALSE;
}
else
DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN));
// Update GTK
// set key material, TxMic and RxMic for WPAPSK
NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32);
pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid;
// Update shared key table
NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY));
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK;
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK);
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK);
NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK);
// Update Shared Key CipherAlg
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE;
if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP;
else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES;
#ifndef RT30xx
else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP40Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP64;
else if (pAd->StaCfg.GroupCipher == Ndis802_11GroupWEP104Enabled)
pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_WEP128;
#endif
return TRUE;
}
/*
========================================================================
Routine Description:
Cisco CCKM PRF function
Arguments:
key Cisco Base Transient Key (BTK)
key_len The key length of the BTK
data Ruquest Number(RN) + BSSID
data_len The length of the data
output Store for PTK(Pairwise transient keys)
len The length of the output
Return Value:
None
Note:
802.1i Annex F.9
========================================================================
*/
VOID CCKMPRF(
IN UCHAR *key,
IN INT key_len,
IN UCHAR *data,
IN INT data_len,
OUT UCHAR *output,
IN INT len)
{
INT i;
UCHAR input[1024];
INT currentindex = 0;
INT total_len;
NdisMoveMemory(input, data, data_len);
total_len = data_len;
input[total_len] = 0;
total_len++;
for (i = 0; i < (len + 19) / 20; i++)
{
HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]);
currentindex += 20;
input[total_len - 1]++;
}
}
/*
========================================================================
Routine Description:
Process MIC error indication and record MIC error timer.
Arguments:
pAd Pointer to our adapter
pWpaKey Pointer to the WPA key structure
Return Value:
None
IRQL = DISPATCH_LEVEL
Note:
========================================================================
*/
VOID RTMPReportMicError(
IN PRTMP_ADAPTER pAd,
IN PCIPHER_KEY pWpaKey)
{
ULONG Now;
UCHAR unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0);
// Record Last MIC error time and count
Now = jiffies;
if (pAd->StaCfg.MicErrCnt == 0)
{
pAd->StaCfg.MicErrCnt++;
pAd->StaCfg.LastMicErrorTime = Now;
NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8);
}
else if (pAd->StaCfg.MicErrCnt == 1)
{
if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now)
{
// Update Last MIC error time, this did not violate two MIC errors within 60 seconds
pAd->StaCfg.LastMicErrorTime = Now;
}
else
{
if (pAd->CommonCfg.bWirelessEvent)
RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
pAd->StaCfg.LastMicErrorTime = Now;
// Violate MIC error counts, MIC countermeasures kicks in
pAd->StaCfg.MicErrCnt++;
}
}
else
{
// MIC error count >= 2
// This should not happen
;
}
MlmeEnqueue(pAd,
MLME_CNTL_STATE_MACHINE,
OID_802_11_MIC_FAILURE_REPORT_FRAME,
1,
&unicastKey);
if (pAd->StaCfg.MicErrCnt == 2)
{
RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100);
}
}
#define LENGTH_EAP_H 4
// If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)).
INT WpaCheckEapCode(
IN PRTMP_ADAPTER pAd,
IN PUCHAR pFrame,
IN USHORT FrameLen,
IN USHORT OffSet)
{
PUCHAR pData;
INT result = 0;
if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H )
return result;
pData = pFrame + OffSet; // skip offset bytes
if(*(pData+1) == EAPPacket) // 802.1x header - Packet Type
{
result = *(pData+4); // EAP header - Code
}
return result;
}
VOID WpaSendMicFailureToWpaSupplicant(
IN PRTMP_ADAPTER pAd,
IN BOOLEAN bUnicast)
{
union iwreq_data wrqu;
char custom[IW_CUSTOM_MAX] = {0};
sprintf(custom, "MLME-MICHAELMICFAILURE.indication");
if (bUnicast)
sprintf(custom, "%s unicast", custom);
wrqu.data.length = strlen(custom);
wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom);
return;
}
VOID WpaMicFailureReportFrame(
IN PRTMP_ADAPTER pAd,
IN MLME_QUEUE_ELEM *Elem)
{
PUCHAR pOutBuffer = NULL;
UCHAR Header802_3[14];
ULONG FrameLen = 0;
EAPOL_PACKET Packet;
UCHAR Mic[16];
BOOLEAN bUnicast;
DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n"));
bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE);
pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER);
// init 802.3 header and Fill Packet
MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL);
NdisZeroMemory(&Packet, sizeof(Packet));
Packet.ProVer = EAPOL_VER;
Packet.ProType = EAPOLKey;
Packet.KeyDesc.Type = WPA1_KEY_DESC;
// Request field presented
Packet.KeyDesc.KeyInfo.Request = 1;
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{
Packet.KeyDesc.KeyInfo.KeyDescVer = 2;
}
else // TKIP
{
Packet.KeyDesc.KeyInfo.KeyDescVer = 1;
}
Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY);
// KeyMic field presented
Packet.KeyDesc.KeyInfo.KeyMic = 1;
// Error field presented
Packet.KeyDesc.KeyInfo.Error = 1;
// Update packet length after decide Key data payload
Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE;
// Key Replay Count
NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY);
inc_byte_array(pAd->StaCfg.ReplayCounter, 8);
// Convert to little-endian format.
*((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo));
MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory
if(pOutBuffer == NULL)
{
return;
}
// Prepare EAPOL frame for MIC calculation
// Be careful, only EAPOL frame is counted for MIC calculation
MakeOutgoingFrame(pOutBuffer, &FrameLen,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// Prepare and Fill MIC value
NdisZeroMemory(Mic, sizeof(Mic));
if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled)
{ // AES
UCHAR digest[20] = {0};
HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest);
NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC);
}
else
{ // TKIP
hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic);
}
NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC);
MakeOutgoingFrame(pOutBuffer, &FrameLen,
LENGTH_802_3, &Header802_3,
Packet.Body_Len[1] + 4, &Packet,
END_OF_ARGS);
// opy frame to Tx ring and send MIC failure report frame to authenticator
RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE);
MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer);
DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n"));
}
/** from wpa_supplicant
* inc_byte_array - Increment arbitrary length byte array by one
* @counter: Pointer to byte array
* @len: Length of the counter in bytes
*
* This function increments the last byte of the counter by one and continues
* rolling over to more significant bytes if the byte was incremented from
* 0xff to 0x00.
*/
void inc_byte_array(UCHAR *counter, int len)
{
int pos = len - 1;
while (pos >= 0) {
counter[pos]++;
if (counter[pos] != 0)
break;
pos--;
}
}
VOID WpaDisassocApAndBlockAssoc(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
{
RTMP_ADAPTER *pAd = (PRTMP_ADAPTER)FunctionContext;
MLME_DISASSOC_REQ_STRUCT DisassocReq;
// disassoc from current AP first
DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n"));
DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE);
MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq);
pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
pAd->StaCfg.bBlockAssoc = TRUE;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment