diff options
Diffstat (limited to 'drivers/staging/rt2870/common/spectrum.c')
-rw-r--r-- | drivers/staging/rt2870/common/spectrum.c | 1876 |
1 files changed, 1876 insertions, 0 deletions
diff --git a/drivers/staging/rt2870/common/spectrum.c b/drivers/staging/rt2870/common/spectrum.c new file mode 100644 index 00000000000..abba8405184 --- /dev/null +++ b/drivers/staging/rt2870/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; +} + |