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