| /* |
| ************************************************************************* |
| * 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", __func__)); |
| |
| 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", __func__)); |
| 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", __func__)); |
| 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", __func__)); |
| } |
| |
| // 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", __func__)); |
| 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", __func__)); |
| |
| 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", __func__)); |
| 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", __func__)); |
| 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", __func__)); |
| } |
| |
| // 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", __func__)); |
| 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", __func__)); |
| 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", __func__)); |
| 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", __func__)); |
| 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", __func__)); |
| 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", __func__)); |
| 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) |
| { |
| } |
| |
| static VOID StartDFSProcedure( |
| IN PRTMP_ADAPTER pAd, |
| IN UCHAR Channel, |
| IN UINT8 ChSwMode) |
| { |
| // start DFS procedure |
| pAd->CommonCfg.Channel = Channel; |
| |
| N_ChannelCheck(pAd); |
| |
| 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; |
| UCHAR index = 0, Channel = 0, NewChannel = 0; |
| ULONG Bssidx = 0; |
| |
| 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; |
| } |
| |
| 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)); |
| } |
| } |
| } |
| |
| 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) |
| { |
| #ifndef RT30xx |
| DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%zu).\n", __func__, sizeof(MEASURE_RPI_REPORT))); |
| #endif |
| #ifdef RT30xx |
| DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __func__, sizeof(MEASURE_RPI_REPORT))); |
| #endif |
| 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", |
| __func__, 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: |
| { |
| } |
| 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", __func__, 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", __func__, Aid, MeasureReqType, MeasureCh)); |
| if (!VALID_WCID(Aid)) |
| { |
| DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, 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", __func__, Aid)); |
| if (!VALID_WCID(Aid)) |
| { |
| DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid)); |
| return TRUE; |
| } |
| |
| TpcReqInsert(pAd, TpcReqToken); |
| |
| EnqueueTPCReq(pAd, pAd->MacTab.Content[Aid].Addr, TpcReqToken); |
| |
| return TRUE; |
| } |
| |