| /* |
| ************************************************************************* |
| * 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" |
| |
| /* The regulatory information in the USA (US) */ |
| struct rt_dot11_regulatory_information USARegulatoryInfo[] = { |
| /* "regulatory class" "number of channels" "Max Tx Pwr" "channel list" */ |
| {0, {0, 0, {0} |
| } |
| } |
| , /* Invlid entry */ |
| {1, {4, 16, {36, 40, 44, 48} |
| } |
| } |
| , |
| {2, {4, 23, {52, 56, 60, 64} |
| } |
| } |
| , |
| {3, {4, 29, {149, 153, 157, 161} |
| } |
| } |
| , |
| {4, {11, 23, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} |
| } |
| } |
| , |
| {5, {5, 30, {149, 153, 157, 161, 165} |
| } |
| } |
| , |
| {6, {10, 14, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} |
| } |
| } |
| , |
| {7, {10, 27, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} |
| } |
| } |
| , |
| {8, {5, 17, {11, 13, 15, 17, 19} |
| } |
| } |
| , |
| {9, {5, 30, {11, 13, 15, 17, 19} |
| } |
| } |
| , |
| {10, {2, 20, {21, 25} |
| } |
| } |
| , |
| {11, {2, 33, {21, 25} |
| } |
| } |
| , |
| {12, {11, 30, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} |
| } |
| } |
| }; |
| |
| #define USA_REGULATORY_INFO_SIZE (sizeof(USARegulatoryInfo) / sizeof(struct rt_dot11_regulatory_information)) |
| |
| /* The regulatory information in Europe */ |
| struct rt_dot11_regulatory_information EuropeRegulatoryInfo[] = { |
| /* "regulatory class" "number of channels" "Max Tx Pwr" "channel list" */ |
| {0, {0, 0, {0} |
| } |
| } |
| , /* Invalid entry */ |
| {1, {4, 20, {36, 40, 44, 48} |
| } |
| } |
| , |
| {2, {4, 20, {52, 56, 60, 64} |
| } |
| } |
| , |
| {3, {11, 30, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} |
| } |
| } |
| , |
| {4, {13, 20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} |
| } |
| } |
| }; |
| |
| #define EU_REGULATORY_INFO_SIZE (sizeof(EuropeRegulatoryInfo) / sizeof(struct rt_dot11_regulatory_information)) |
| |
| /* The regulatory information in Japan */ |
| struct rt_dot11_regulatory_information JapanRegulatoryInfo[] = { |
| /* "regulatory class" "number of channels" "Max Tx Pwr" "channel list" */ |
| {0, {0, 0, {0} |
| } |
| } |
| , /* Invalid entry */ |
| {1, {4, 22, {34, 38, 42, 46} |
| } |
| } |
| , |
| {2, {3, 24, {8, 12, 16} |
| } |
| } |
| , |
| {3, {3, 24, {8, 12, 16} |
| } |
| } |
| , |
| {4, {3, 24, {8, 12, 16} |
| } |
| } |
| , |
| {5, {3, 24, {8, 12, 16} |
| } |
| } |
| , |
| {6, {3, 22, {8, 12, 16} |
| } |
| } |
| , |
| {7, {4, 24, {184, 188, 192, 196} |
| } |
| } |
| , |
| {8, {4, 24, {184, 188, 192, 196} |
| } |
| } |
| , |
| {9, {4, 24, {184, 188, 192, 196} |
| } |
| } |
| , |
| {10, {4, 24, {184, 188, 192, 196} |
| } |
| } |
| , |
| {11, {4, 22, {184, 188, 192, 196} |
| } |
| } |
| , |
| {12, {4, 24, {7, 8, 9, 11} |
| } |
| } |
| , |
| {13, {4, 24, {7, 8, 9, 11} |
| } |
| } |
| , |
| {14, {4, 24, {7, 8, 9, 11} |
| } |
| } |
| , |
| {15, {4, 24, {7, 8, 9, 11} |
| } |
| } |
| , |
| {16, {6, 24, {183, 184, 185, 187, 188, 189} |
| } |
| } |
| , |
| {17, {6, 24, {183, 184, 185, 187, 188, 189} |
| } |
| } |
| , |
| {18, {6, 24, {183, 184, 185, 187, 188, 189} |
| } |
| } |
| , |
| {19, {6, 24, {183, 184, 185, 187, 188, 189} |
| } |
| } |
| , |
| {20, {6, 17, {183, 184, 185, 187, 188, 189} |
| } |
| } |
| , |
| {21, {6, 24, {6, 7, 8, 9, 10, 11} |
| } |
| } |
| , |
| {22, {6, 24, {6, 7, 8, 9, 10, 11} |
| } |
| } |
| , |
| {23, {6, 24, {6, 7, 8, 9, 10, 11} |
| } |
| } |
| , |
| {24, {6, 24, {6, 7, 8, 9, 10, 11} |
| } |
| } |
| , |
| {25, {8, 24, {182, 183, 184, 185, 186, 187, 188, 189} |
| } |
| } |
| , |
| {26, {8, 24, {182, 183, 184, 185, 186, 187, 188, 189} |
| } |
| } |
| , |
| {27, {8, 24, {182, 183, 184, 185, 186, 187, 188, 189} |
| } |
| } |
| , |
| {28, {8, 24, {182, 183, 184, 185, 186, 187, 188, 189} |
| } |
| } |
| , |
| {29, {8, 17, {182, 183, 184, 185, 186, 187, 188, 189} |
| } |
| } |
| , |
| {30, {13, 23, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} |
| } |
| } |
| , |
| {31, {1, 23, {14} |
| } |
| } |
| , |
| {32, {4, 22, {52, 56, 60, 64} |
| } |
| } |
| }; |
| |
| #define JP_REGULATORY_INFO_SIZE (sizeof(JapanRegulatoryInfo) / sizeof(struct rt_dot11_regulatory_information)) |
| |
| char RTMP_GetTxPwr(struct rt_rtmp_adapter *pAd, IN HTTRANSMIT_SETTING HTTxMode) |
| { |
| struct tx_pwr_cfg { |
| u8 Mode; |
| u8 MCS; |
| u16 req; |
| u8 shift; |
| u32 BitMask; |
| }; |
| |
| u32 Value; |
| int Idx; |
| u8 PhyMode; |
| char CurTxPwr; |
| u8 TxPwrRef = 0; |
| char DaltaPwr; |
| unsigned long TxPwr[5]; |
| |
| struct tx_pwr_cfg TxPwrCfg[] = { |
| {MODE_CCK, 0, 0, 4, 0x000000f0}, |
| {MODE_CCK, 1, 0, 0, 0x0000000f}, |
| {MODE_CCK, 2, 0, 12, 0x0000f000}, |
| {MODE_CCK, 3, 0, 8, 0x00000f00}, |
| |
| {MODE_OFDM, 0, 0, 20, 0x00f00000}, |
| {MODE_OFDM, 1, 0, 16, 0x000f0000}, |
| {MODE_OFDM, 2, 0, 28, 0xf0000000}, |
| {MODE_OFDM, 3, 0, 24, 0x0f000000}, |
| {MODE_OFDM, 4, 1, 4, 0x000000f0}, |
| {MODE_OFDM, 5, 1, 0, 0x0000000f}, |
| {MODE_OFDM, 6, 1, 12, 0x0000f000}, |
| {MODE_OFDM, 7, 1, 8, 0x00000f00} |
| , {MODE_HTMIX, 0, 1, 20, 0x00f00000}, |
| {MODE_HTMIX, 1, 1, 16, 0x000f0000}, |
| {MODE_HTMIX, 2, 1, 28, 0xf0000000}, |
| {MODE_HTMIX, 3, 1, 24, 0x0f000000}, |
| {MODE_HTMIX, 4, 2, 4, 0x000000f0}, |
| {MODE_HTMIX, 5, 2, 0, 0x0000000f}, |
| {MODE_HTMIX, 6, 2, 12, 0x0000f000}, |
| {MODE_HTMIX, 7, 2, 8, 0x00000f00}, |
| {MODE_HTMIX, 8, 2, 20, 0x00f00000}, |
| {MODE_HTMIX, 9, 2, 16, 0x000f0000}, |
| {MODE_HTMIX, 10, 2, 28, 0xf0000000}, |
| {MODE_HTMIX, 11, 2, 24, 0x0f000000}, |
| {MODE_HTMIX, 12, 3, 4, 0x000000f0}, |
| {MODE_HTMIX, 13, 3, 0, 0x0000000f}, |
| {MODE_HTMIX, 14, 3, 12, 0x0000f000}, |
| {MODE_HTMIX, 15, 3, 8, 0x00000f00} |
| }; |
| #define MAX_TXPWR_TAB_SIZE (sizeof(TxPwrCfg) / sizeof(struct tx_pwr_cfg)) |
| |
| CurTxPwr = 19; |
| |
| /* check Tx Power setting from UI. */ |
| if (pAd->CommonCfg.TxPowerPercentage > 90) ; |
| else if (pAd->CommonCfg.TxPowerPercentage > 60) /* reduce Pwr for 1 dB. */ |
| CurTxPwr -= 1; |
| else if (pAd->CommonCfg.TxPowerPercentage > 30) /* reduce Pwr for 3 dB. */ |
| CurTxPwr -= 3; |
| else if (pAd->CommonCfg.TxPowerPercentage > 15) /* reduce Pwr for 6 dB. */ |
| CurTxPwr -= 6; |
| else if (pAd->CommonCfg.TxPowerPercentage > 9) /* reduce Pwr for 9 dB. */ |
| CurTxPwr -= 9; |
| else /* reduce Pwr for 12 dB. */ |
| CurTxPwr -= 12; |
| |
| if (pAd->CommonCfg.BBPCurrentBW == BW_40) { |
| if (pAd->CommonCfg.CentralChannel > 14) { |
| TxPwr[0] = pAd->Tx40MPwrCfgABand[0]; |
| TxPwr[1] = pAd->Tx40MPwrCfgABand[1]; |
| TxPwr[2] = pAd->Tx40MPwrCfgABand[2]; |
| TxPwr[3] = pAd->Tx40MPwrCfgABand[3]; |
| TxPwr[4] = pAd->Tx40MPwrCfgABand[4]; |
| } else { |
| TxPwr[0] = pAd->Tx40MPwrCfgGBand[0]; |
| TxPwr[1] = pAd->Tx40MPwrCfgGBand[1]; |
| TxPwr[2] = pAd->Tx40MPwrCfgGBand[2]; |
| TxPwr[3] = pAd->Tx40MPwrCfgGBand[3]; |
| TxPwr[4] = pAd->Tx40MPwrCfgGBand[4]; |
| } |
| } else { |
| if (pAd->CommonCfg.Channel > 14) { |
| TxPwr[0] = pAd->Tx20MPwrCfgABand[0]; |
| TxPwr[1] = pAd->Tx20MPwrCfgABand[1]; |
| TxPwr[2] = pAd->Tx20MPwrCfgABand[2]; |
| TxPwr[3] = pAd->Tx20MPwrCfgABand[3]; |
| TxPwr[4] = pAd->Tx20MPwrCfgABand[4]; |
| } else { |
| TxPwr[0] = pAd->Tx20MPwrCfgGBand[0]; |
| TxPwr[1] = pAd->Tx20MPwrCfgGBand[1]; |
| TxPwr[2] = pAd->Tx20MPwrCfgGBand[2]; |
| TxPwr[3] = pAd->Tx20MPwrCfgGBand[3]; |
| TxPwr[4] = pAd->Tx20MPwrCfgGBand[4]; |
| } |
| } |
| |
| switch (HTTxMode.field.MODE) { |
| case MODE_CCK: |
| case MODE_OFDM: |
| Value = TxPwr[1]; |
| TxPwrRef = (Value & 0x00000f00) >> 8; |
| |
| break; |
| |
| case MODE_HTMIX: |
| case MODE_HTGREENFIELD: |
| if (pAd->CommonCfg.TxStream == 1) { |
| Value = TxPwr[2]; |
| TxPwrRef = (Value & 0x00000f00) >> 8; |
| } else if (pAd->CommonCfg.TxStream == 2) { |
| Value = TxPwr[3]; |
| TxPwrRef = (Value & 0x00000f00) >> 8; |
| } |
| break; |
| } |
| |
| PhyMode = (HTTxMode.field.MODE == MODE_HTGREENFIELD) |
| ? MODE_HTMIX : HTTxMode.field.MODE; |
| |
| for (Idx = 0; Idx < MAX_TXPWR_TAB_SIZE; Idx++) { |
| if ((TxPwrCfg[Idx].Mode == PhyMode) |
| && (TxPwrCfg[Idx].MCS == HTTxMode.field.MCS)) { |
| Value = TxPwr[TxPwrCfg[Idx].req]; |
| DaltaPwr = |
| TxPwrRef - (char)((Value & TxPwrCfg[Idx].BitMask) |
| >> TxPwrCfg[Idx].shift); |
| CurTxPwr -= DaltaPwr; |
| break; |
| } |
| } |
| |
| return CurTxPwr; |
| } |
| |
| void MeasureReqTabInit(struct rt_rtmp_adapter *pAd) |
| { |
| NdisAllocateSpinLock(&pAd->CommonCfg.MeasureReqTabLock); |
| |
| pAd->CommonCfg.pMeasureReqTab = |
| kmalloc(sizeof(struct rt_measure_req_tab), GFP_ATOMIC); |
| if (pAd->CommonCfg.pMeasureReqTab) |
| NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, |
| sizeof(struct rt_measure_req_tab)); |
| else |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", |
| __func__)); |
| |
| return; |
| } |
| |
| void MeasureReqTabExit(struct rt_rtmp_adapter *pAd) |
| { |
| NdisFreeSpinLock(&pAd->CommonCfg.MeasureReqTabLock); |
| |
| if (pAd->CommonCfg.pMeasureReqTab) |
| kfree(pAd->CommonCfg.pMeasureReqTab); |
| pAd->CommonCfg.pMeasureReqTab = NULL; |
| |
| return; |
| } |
| |
| struct rt_measure_req_entry *MeasureReqLookUp(struct rt_rtmp_adapter *pAd, u8 DialogToken) |
| { |
| u32 HashIdx; |
| struct rt_measure_req_tab *pTab = pAd->CommonCfg.pMeasureReqTab; |
| struct rt_measure_req_entry *pEntry = NULL; |
| struct rt_measure_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; |
| } |
| |
| struct rt_measure_req_entry *MeasureReqInsert(struct rt_rtmp_adapter *pAd, u8 DialogToken) |
| { |
| int i; |
| unsigned long HashIdx; |
| struct rt_measure_req_tab *pTab = pAd->CommonCfg.pMeasureReqTab; |
| struct rt_measure_req_entry *pEntry = NULL, *pCurrEntry; |
| unsigned long 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))) |
| { |
| struct rt_measure_req_entry *pPrevEntry = NULL; |
| unsigned long HashIdx = |
| MQ_DIALOGTOKEN_HASH_INDEX(pEntry-> |
| DialogToken); |
| struct rt_measure_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(struct rt_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; |
| } |
| |
| void MeasureReqDelete(struct rt_rtmp_adapter *pAd, u8 DialogToken) |
| { |
| struct rt_measure_req_tab *pTab = pAd->CommonCfg.pMeasureReqTab; |
| struct rt_measure_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) { |
| struct rt_measure_req_entry *pPrevEntry = NULL; |
| unsigned long HashIdx = MQ_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); |
| struct rt_measure_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(struct rt_measure_req_entry)); |
| pTab->Size--; |
| |
| RTMP_SEM_UNLOCK(&pAd->CommonCfg.MeasureReqTabLock); |
| } |
| |
| return; |
| } |
| |
| void TpcReqTabInit(struct rt_rtmp_adapter *pAd) |
| { |
| NdisAllocateSpinLock(&pAd->CommonCfg.TpcReqTabLock); |
| |
| pAd->CommonCfg.pTpcReqTab = kmalloc(sizeof(struct rt_tpc_req_tab), GFP_ATOMIC); |
| if (pAd->CommonCfg.pTpcReqTab) |
| NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(struct rt_tpc_req_tab)); |
| else |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", |
| __func__)); |
| |
| return; |
| } |
| |
| void TpcReqTabExit(struct rt_rtmp_adapter *pAd) |
| { |
| NdisFreeSpinLock(&pAd->CommonCfg.TpcReqTabLock); |
| |
| if (pAd->CommonCfg.pTpcReqTab) |
| kfree(pAd->CommonCfg.pTpcReqTab); |
| pAd->CommonCfg.pTpcReqTab = NULL; |
| |
| return; |
| } |
| |
| static struct rt_tpc_req_entry *TpcReqLookUp(struct rt_rtmp_adapter *pAd, u8 DialogToken) |
| { |
| u32 HashIdx; |
| struct rt_tpc_req_tab *pTab = pAd->CommonCfg.pTpcReqTab; |
| struct rt_tpc_req_entry *pEntry = NULL; |
| struct rt_tpc_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 struct rt_tpc_req_entry *TpcReqInsert(struct rt_rtmp_adapter *pAd, u8 DialogToken) |
| { |
| int i; |
| unsigned long HashIdx; |
| struct rt_tpc_req_tab *pTab = pAd->CommonCfg.pTpcReqTab; |
| struct rt_tpc_req_entry *pEntry = NULL, *pCurrEntry; |
| unsigned long 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))) |
| { |
| struct rt_tpc_req_entry *pPrevEntry = NULL; |
| unsigned long HashIdx = |
| TPC_DIALOGTOKEN_HASH_INDEX(pEntry-> |
| DialogToken); |
| struct rt_tpc_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(struct rt_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(struct rt_rtmp_adapter *pAd, u8 DialogToken) |
| { |
| struct rt_tpc_req_tab *pTab = pAd->CommonCfg.pTpcReqTab; |
| struct rt_tpc_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) { |
| struct rt_tpc_req_entry *pPrevEntry = NULL; |
| unsigned long HashIdx = TPC_DIALOGTOKEN_HASH_INDEX(pEntry->DialogToken); |
| struct rt_tpc_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(struct rt_tpc_req_entry)); |
| pTab->Size--; |
| |
| RTMP_SEM_UNLOCK(&pAd->CommonCfg.TpcReqTabLock); |
| } |
| |
| return; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Get Current TimeS tamp. |
| |
| Parametrs: |
| |
| Return : Current Time Stamp. |
| ========================================================================== |
| */ |
| static u64 GetCurrentTimeStamp(struct rt_rtmp_adapter *pAd) |
| { |
| /* get current time stamp. */ |
| return 0; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Get Current Transmit Power. |
| |
| Parametrs: |
| |
| Return : Current Time Stamp. |
| ========================================================================== |
| */ |
| static u8 GetCurTxPwr(struct rt_rtmp_adapter *pAd, u8 Wcid) |
| { |
| return 16; /* 16 dBm */ |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Get Current Transmit Power. |
| |
| Parametrs: |
| |
| Return : Current Time Stamp. |
| ========================================================================== |
| */ |
| void InsertChannelRepIE(struct rt_rtmp_adapter *pAd, |
| u8 *pFrameBuf, |
| unsigned long *pFrameLen, |
| char *pCountry, u8 RegulatoryClass) |
| { |
| unsigned long TempLen; |
| u8 Len; |
| u8 IEId = IE_AP_CHANNEL_REPORT; |
| u8 *pChListPtr = NULL; |
| |
| Len = 1; |
| if (strncmp(pCountry, "US", 2) == 0) { |
| if (RegulatoryClass >= USA_REGULATORY_INFO_SIZE) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("%s: USA Unknow Requlatory class (%d)\n", |
| __func__, RegulatoryClass)); |
| return; |
| } |
| |
| Len += |
| USARegulatoryInfo[RegulatoryClass].ChannelSet. |
| NumberOfChannels; |
| pChListPtr = |
| USARegulatoryInfo[RegulatoryClass].ChannelSet.ChannelList; |
| } else if (strncmp(pCountry, "JP", 2) == 0) { |
| if (RegulatoryClass >= JP_REGULATORY_INFO_SIZE) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("%s: JP Unknow Requlatory class (%d)\n", |
| __func__, RegulatoryClass)); |
| return; |
| } |
| |
| Len += |
| JapanRegulatoryInfo[RegulatoryClass].ChannelSet. |
| NumberOfChannels; |
| pChListPtr = |
| JapanRegulatoryInfo[RegulatoryClass].ChannelSet.ChannelList; |
| } else { |
| DBGPRINT(RT_DEBUG_ERROR, ("%s: Unknow Country (%s)\n", |
| __func__, pCountry)); |
| return; |
| } |
| |
| MakeOutgoingFrame(pFrameBuf, &TempLen, |
| 1, &IEId, |
| 1, &Len, |
| 1, &RegulatoryClass, |
| Len - 1, pChListPtr, END_OF_ARGS); |
| |
| *pFrameLen = *pFrameLen + TempLen; |
| |
| return; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Insert Dialog Token into frame. |
| |
| Parametrs: |
| 1. frame buffer pointer. |
| 2. frame length. |
| 3. Dialog token. |
| |
| Return : None. |
| ========================================================================== |
| */ |
| void InsertDialogToken(struct rt_rtmp_adapter *pAd, |
| u8 *pFrameBuf, |
| unsigned long *pFrameLen, u8 DialogToken) |
| { |
| unsigned long 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(struct rt_rtmp_adapter *pAd, |
| u8 *pFrameBuf, unsigned long *pFrameLen) |
| { |
| unsigned long TempLen; |
| unsigned long Len = 0; |
| u8 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. |
| ========================================================================== |
| */ |
| void InsertTpcReportIE(struct rt_rtmp_adapter *pAd, |
| u8 *pFrameBuf, |
| unsigned long *pFrameLen, |
| u8 TxPwr, u8 LinkMargin) |
| { |
| unsigned long TempLen; |
| unsigned long Len = sizeof(struct rt_tpc_report_info); |
| u8 ElementID = IE_TPC_REPORT; |
| struct rt_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(struct rt_rtmp_adapter *pAd, |
| u8 *pFrameBuf, |
| unsigned long *pFrameLen, |
| u8 ChSwMode, |
| u8 NewChannel, u8 ChSwCnt) |
| { |
| unsigned long TempLen; |
| unsigned long Len = sizeof(struct rt_ch_sw_ann_info); |
| u8 ElementID = IE_CHANNEL_SWITCH_ANNOUNCEMENT; |
| struct rt_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(struct rt_rtmp_adapter *pAd, |
| u8 *pFrameBuf, |
| unsigned long *pFrameLen, |
| u8 Len, struct rt_measure_req_info * pMeasureReqIE) |
| { |
| unsigned long TempLen; |
| u8 ElementID = IE_MEASUREMENT_REQUEST; |
| |
| MakeOutgoingFrame(pFrameBuf, &TempLen, |
| 1, &ElementID, |
| 1, &Len, |
| sizeof(struct rt_measure_req_info), 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(struct rt_rtmp_adapter *pAd, |
| u8 *pFrameBuf, |
| unsigned long *pFrameLen, |
| struct rt_measure_report_info * pMeasureReportIE, |
| u8 ReportLnfoLen, u8 *pReportInfo) |
| { |
| unsigned long TempLen; |
| unsigned long Len; |
| u8 ElementID = IE_MEASUREMENT_REPORT; |
| |
| Len = sizeof(struct rt_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 MakeMeasurementReqFrame(struct rt_rtmp_adapter *pAd, |
| u8 *pOutBuffer, |
| unsigned long *pFrameLen, |
| u8 TotalLen, |
| u8 Category, |
| u8 Action, |
| u8 MeasureToken, |
| u8 MeasureReqMode, |
| u8 MeasureReqType, u8 NumOfRepetitions) |
| { |
| unsigned long TempLen; |
| struct rt_measure_req_info MeasureReqIE; |
| |
| InsertActField(pAd, (pOutBuffer + *pFrameLen), pFrameLen, Category, |
| Action); |
| |
| /* fill Dialog Token */ |
| InsertDialogToken(pAd, (pOutBuffer + *pFrameLen), pFrameLen, |
| MeasureToken); |
| |
| /* fill Number of repetitions. */ |
| if (Category == CATEGORY_RM) { |
| MakeOutgoingFrame((pOutBuffer + *pFrameLen), &TempLen, |
| 2, &NumOfRepetitions, END_OF_ARGS); |
| |
| *pFrameLen += TempLen; |
| } |
| /* prepare Measurement IE. */ |
| NdisZeroMemory(&MeasureReqIE, sizeof(struct rt_measure_req_info)); |
| MeasureReqIE.Token = MeasureToken; |
| MeasureReqIE.ReqMode.word = MeasureReqMode; |
| MeasureReqIE.ReqType = MeasureReqType; |
| InsertMeasureReqIE(pAd, (pOutBuffer + *pFrameLen), pFrameLen, |
| TotalLen, &MeasureReqIE); |
| |
| 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(struct rt_rtmp_adapter *pAd, |
| u8 *pDA, |
| u8 DialogToken, |
| u8 MeasureToken, |
| u8 MeasureReqMode, |
| u8 MeasureReqType, |
| u8 ReportInfoLen, u8 *pReportInfo) |
| { |
| u8 *pOutBuffer = NULL; |
| int NStatus; |
| unsigned long FrameLen; |
| struct rt_header_802_11 ActHdr; |
| struct rt_measure_report_info MeasureRepIE; |
| |
| /* build action frame header. */ |
| MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, |
| pAd->CurrentAddress); |
| |
| NStatus = MlmeAllocateMemory(pAd, (void *)& pOutBuffer); /*Get an unused nonpaged memory */ |
| if (NStatus != NDIS_STATUS_SUCCESS) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("%s() allocate memory failed \n", __func__)); |
| return; |
| } |
| NdisMoveMemory(pOutBuffer, (char *)& ActHdr, sizeof(struct rt_header_802_11)); |
| FrameLen = sizeof(struct rt_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(struct rt_measure_report_info)); |
| MeasureRepIE.Token = MeasureToken; |
| MeasureRepIE.ReportMode = 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(struct rt_rtmp_adapter *pAd, u8 *pDA, u8 DialogToken) |
| { |
| u8 *pOutBuffer = NULL; |
| int NStatus; |
| unsigned long FrameLen; |
| |
| struct rt_header_802_11 ActHdr; |
| |
| /* build action frame header. */ |
| MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, |
| pAd->CurrentAddress); |
| |
| NStatus = MlmeAllocateMemory(pAd, (void *)& pOutBuffer); /*Get an unused nonpaged memory */ |
| if (NStatus != NDIS_STATUS_SUCCESS) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("%s() allocate memory failed \n", __func__)); |
| return; |
| } |
| NdisMoveMemory(pOutBuffer, (char *)& ActHdr, sizeof(struct rt_header_802_11)); |
| FrameLen = sizeof(struct rt_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(struct rt_rtmp_adapter *pAd, |
| u8 *pDA, |
| u8 DialogToken, u8 TxPwr, u8 LinkMargin) |
| { |
| u8 *pOutBuffer = NULL; |
| int NStatus; |
| unsigned long FrameLen; |
| |
| struct rt_header_802_11 ActHdr; |
| |
| /* build action frame header. */ |
| MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, |
| pAd->CurrentAddress); |
| |
| NStatus = MlmeAllocateMemory(pAd, (void *)& pOutBuffer); /*Get an unused nonpaged memory */ |
| if (NStatus != NDIS_STATUS_SUCCESS) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("%s() allocate memory failed \n", __func__)); |
| return; |
| } |
| NdisMoveMemory(pOutBuffer, (char *)& ActHdr, sizeof(struct rt_header_802_11)); |
| FrameLen = sizeof(struct rt_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(struct rt_rtmp_adapter *pAd, |
| u8 *pDA, u8 ChSwMode, u8 NewCh) |
| { |
| u8 *pOutBuffer = NULL; |
| int NStatus; |
| unsigned long FrameLen; |
| |
| struct rt_header_802_11 ActHdr; |
| |
| /* build action frame header. */ |
| MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, pDA, |
| pAd->CurrentAddress); |
| |
| NStatus = MlmeAllocateMemory(pAd, (void *)& pOutBuffer); /*Get an unused nonpaged memory */ |
| if (NStatus != NDIS_STATUS_SUCCESS) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("%s() allocate memory failed \n", __func__)); |
| return; |
| } |
| NdisMoveMemory(pOutBuffer, (char *)& ActHdr, sizeof(struct rt_header_802_11)); |
| FrameLen = sizeof(struct rt_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(struct rt_rtmp_adapter *pAd, u8 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(struct rt_rtmp_adapter *pAd, |
| u8 *pRA, |
| u8 *pTA, u8 ChSwMode, u8 Channel) |
| { |
| } |
| |
| static void StartDFSProcedure(struct rt_rtmp_adapter *pAd, |
| u8 Channel, u8 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(struct rt_rtmp_adapter *pAd, |
| void * pMsg, |
| unsigned long MsgLen, |
| struct rt_ch_sw_ann_info * pChSwAnnInfo) |
| { |
| struct rt_frame_802_11 * Fr = (struct rt_frame_802_11 *) pMsg; |
| u8 *pFramePtr = Fr->Octet; |
| BOOLEAN result = FALSE; |
| struct rt_eid * eid_ptr; |
| |
| /* skip 802.11 header. */ |
| MsgLen -= sizeof(struct rt_header_802_11); |
| |
| /* skip category and action code. */ |
| pFramePtr += 2; |
| MsgLen -= 2; |
| |
| if (pChSwAnnInfo == NULL) |
| return result; |
| |
| eid_ptr = (struct rt_eid *) pFramePtr; |
| while (((u8 *) eid_ptr + eid_ptr->Len + 1) < |
| ((u8 *)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 = (struct rt_eid *) ((u8 *) 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(struct rt_rtmp_adapter *pAd, |
| void * pMsg, |
| unsigned long MsgLen, |
| u8 *pDialogToken, |
| struct rt_measure_req_info * pMeasureReqInfo, |
| struct rt_measure_req * pMeasureReq) |
| { |
| struct rt_frame_802_11 * Fr = (struct rt_frame_802_11 *) pMsg; |
| u8 *pFramePtr = Fr->Octet; |
| BOOLEAN result = FALSE; |
| struct rt_eid * eid_ptr; |
| u8 *ptr; |
| u64 MeasureStartTime; |
| u16 MeasureDuration; |
| |
| /* skip 802.11 header. */ |
| MsgLen -= sizeof(struct rt_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 = (struct rt_eid *) pFramePtr; |
| while (((u8 *) eid_ptr + eid_ptr->Len + 1) < |
| ((u8 *)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 = (u8 *)(eid_ptr->Octet + 3); |
| NdisMoveMemory(&pMeasureReq->ChNum, ptr, 1); |
| NdisMoveMemory(&MeasureStartTime, ptr + 1, 8); |
| pMeasureReq->MeasureStartTime = |
| SWAP64(MeasureStartTime); |
| NdisMoveMemory(&MeasureDuration, ptr + 9, 2); |
| pMeasureReq->MeasureDuration = SWAP16(MeasureDuration); |
| |
| result = TRUE; |
| break; |
| |
| default: |
| break; |
| } |
| eid_ptr = (struct rt_eid *) ((u8 *) 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(struct rt_rtmp_adapter *pAd, |
| void * pMsg, |
| unsigned long MsgLen, |
| u8 *pDialogToken, |
| struct rt_measure_report_info * |
| pMeasureReportInfo, |
| u8 *pReportBuf) |
| { |
| struct rt_frame_802_11 * Fr = (struct rt_frame_802_11 *) pMsg; |
| u8 *pFramePtr = Fr->Octet; |
| BOOLEAN result = FALSE; |
| struct rt_eid * eid_ptr; |
| u8 *ptr; |
| |
| /* skip 802.11 header. */ |
| MsgLen -= sizeof(struct rt_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 = (struct rt_eid *) pFramePtr; |
| while (((u8 *) eid_ptr + eid_ptr->Len + 1) < |
| ((u8 *)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) { |
| struct rt_measure_basic_report * pReport = |
| (struct rt_measure_basic_report *) pReportBuf; |
| ptr = (u8 *)(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) { |
| struct rt_measure_cca_report * pReport = |
| (struct rt_measure_cca_report *) pReportBuf; |
| ptr = (u8 *)(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) { |
| struct rt_measure_rpi_report * pReport = |
| (struct rt_measure_rpi_report *) pReportBuf; |
| ptr = (u8 *)(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 = (struct rt_eid *) ((u8 *) 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(struct rt_rtmp_adapter *pAd, |
| void * pMsg, |
| unsigned long MsgLen, u8 *pDialogToken) |
| { |
| struct rt_frame_802_11 * Fr = (struct rt_frame_802_11 *) pMsg; |
| u8 *pFramePtr = Fr->Octet; |
| BOOLEAN result = FALSE; |
| struct rt_eid * eid_ptr; |
| |
| MsgLen -= sizeof(struct rt_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 = (struct rt_eid *) pFramePtr; |
| while (((u8 *) eid_ptr + eid_ptr->Len + 1) < |
| ((u8 *)pFramePtr + MsgLen)) { |
| switch (eid_ptr->Eid) { |
| case IE_TPC_REQUEST: |
| result = TRUE; |
| break; |
| |
| default: |
| break; |
| } |
| eid_ptr = (struct rt_eid *) ((u8 *) 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(struct rt_rtmp_adapter *pAd, |
| void * pMsg, |
| unsigned long MsgLen, |
| u8 *pDialogToken, |
| struct rt_tpc_report_info * pTpcRepInfo) |
| { |
| struct rt_frame_802_11 * Fr = (struct rt_frame_802_11 *) pMsg; |
| u8 *pFramePtr = Fr->Octet; |
| BOOLEAN result = FALSE; |
| struct rt_eid * eid_ptr; |
| |
| MsgLen -= sizeof(struct rt_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 = (struct rt_eid *) pFramePtr; |
| while (((u8 *) eid_ptr + eid_ptr->Len + 1) < |
| ((u8 *)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 = (struct rt_eid *) ((u8 *) 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(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem) |
| { |
| struct rt_ch_sw_ann_info ChSwAnnInfo; |
| struct rt_frame_802_11 * pFr = (struct rt_frame_802_11 *) Elem->Msg; |
| u8 index = 0, Channel = 0, NewChannel = 0; |
| unsigned long Bssidx = 0; |
| |
| NdisZeroMemory(&ChSwAnnInfo, sizeof(struct rt_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(struct rt_rtmp_adapter *pAd, |
| struct rt_mlme_queue_elem *Elem) |
| { |
| struct rt_frame_802_11 * pFr = (struct rt_frame_802_11 *) Elem->Msg; |
| u8 DialogToken; |
| struct rt_measure_req_info MeasureReqInfo; |
| struct rt_measure_req MeasureReq; |
| MEASURE_REPORT_MODE ReportMode; |
| |
| if (PeerMeasureReqSanity |
| (pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReqInfo, |
| &MeasureReq)) { |
| 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(struct rt_rtmp_adapter *pAd, |
| struct rt_mlme_queue_elem *Elem) |
| { |
| struct rt_measure_report_info MeasureReportInfo; |
| struct rt_frame_802_11 * pFr = (struct rt_frame_802_11 *) Elem->Msg; |
| u8 DialogToken; |
| u8 *pMeasureReportInfo; |
| |
| /* if (pAd->CommonCfg.bIEEE80211H != TRUE) */ |
| /* return; */ |
| |
| pMeasureReportInfo = kmalloc(sizeof(struct rt_measure_rpi_report), GFP_ATOMIC); |
| if (pMeasureReportInfo == NULL) { |
| DBGPRINT(RT_DEBUG_ERROR, |
| ("%s unable to alloc memory for measure report buffer (size=%zu).\n", |
| __func__, sizeof(struct rt_measure_rpi_report))); |
| return; |
| } |
| |
| NdisZeroMemory(&MeasureReportInfo, sizeof(struct rt_measure_report_info)); |
| NdisZeroMemory(pMeasureReportInfo, sizeof(struct rt_measure_rpi_report)); |
| if (PeerMeasureReportSanity |
| (pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &MeasureReportInfo, |
| pMeasureReportInfo)) { |
| do { |
| struct rt_measure_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) { |
| struct rt_measure_basic_report * pBasicReport = |
| (struct rt_measure_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(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem) |
| { |
| struct rt_frame_802_11 * pFr = (struct rt_frame_802_11 *) Elem->Msg; |
| u8 *pFramePtr = pFr->Octet; |
| u8 DialogToken; |
| u8 TxPwr = GetCurTxPwr(pAd, Elem->Wcid); |
| u8 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(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem) |
| { |
| u8 DialogToken; |
| struct rt_tpc_report_info TpcRepInfo; |
| struct rt_tpc_req_entry *pEntry = NULL; |
| |
| NdisZeroMemory(&TpcRepInfo, sizeof(struct rt_tpc_report_info)); |
| if (PeerTpcRepSanity |
| (pAd, Elem->Msg, Elem->MsgLen, &DialogToken, &TpcRepInfo)) { |
| pEntry = TpcReqLookUp(pAd, DialogToken); |
| if (pEntry != 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(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem) |
| { |
| |
| u8 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(struct rt_rtmp_adapter *pAd, char *arg) |
| { |
| u32 Aid = 1; |
| u32 ArgIdx; |
| char *thisChar; |
| |
| MEASURE_REQ_MODE MeasureReqMode; |
| u8 MeasureReqToken = RandomByte(pAd); |
| u8 MeasureReqType = RM_BASIC; |
| u8 MeasureCh = 1; |
| u64 MeasureStartTime = GetCurrentTimeStamp(pAd); |
| struct rt_measure_req MeasureReq; |
| u8 TotalLen; |
| |
| struct rt_header_802_11 ActHdr; |
| u8 *pOutBuffer = NULL; |
| int NStatus; |
| unsigned long FrameLen; |
| |
| NStatus = MlmeAllocateMemory(pAd, (void *)& pOutBuffer); /*Get an unused nonpaged memory */ |
| if (NStatus != NDIS_STATUS_SUCCESS) { |
| DBGPRINT(RT_DEBUG_TRACE, |
| ("%s() allocate memory failed \n", __func__)); |
| goto END_OF_MEASURE_REQ; |
| } |
| |
| ArgIdx = 1; |
| while ((thisChar = strsep((char **)&arg, "-")) != NULL) { |
| switch (ArgIdx) { |
| case 1: /* Aid. */ |
| Aid = (u8)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)); |
| goto END_OF_MEASURE_REQ; |
| } |
| break; |
| |
| case 3: /* Measurement channel. */ |
| MeasureCh = (u8)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)); |
| goto END_OF_MEASURE_REQ; |
| } |
| |
| MeasureReqMode.word = 0; |
| MeasureReqMode.field.Enable = 1; |
| |
| MeasureReqInsert(pAd, MeasureReqToken); |
| |
| /* build action frame header. */ |
| MgtMacHeaderInit(pAd, &ActHdr, SUBTYPE_ACTION, 0, |
| pAd->MacTab.Content[Aid].Addr, pAd->CurrentAddress); |
| |
| NdisMoveMemory(pOutBuffer, (char *)& ActHdr, sizeof(struct rt_header_802_11)); |
| FrameLen = sizeof(struct rt_header_802_11); |
| |
| TotalLen = sizeof(struct rt_measure_req_info) + sizeof(struct rt_measure_req); |
| |
| MakeMeasurementReqFrame(pAd, pOutBuffer, &FrameLen, |
| sizeof(struct rt_measure_req_info), CATEGORY_RM, RM_BASIC, |
| MeasureReqToken, MeasureReqMode.word, |
| MeasureReqType, 0); |
| |
| MeasureReq.ChNum = MeasureCh; |
| MeasureReq.MeasureStartTime = cpu2le64(MeasureStartTime); |
| MeasureReq.MeasureDuration = cpu2le16(2000); |
| |
| { |
| unsigned long TempLen; |
| MakeOutgoingFrame(pOutBuffer + FrameLen, &TempLen, |
| sizeof(struct rt_measure_req), &MeasureReq, |
| END_OF_ARGS); |
| FrameLen += TempLen; |
| } |
| |
| MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, (u32)FrameLen); |
| |
| END_OF_MEASURE_REQ: |
| MlmeFreeMemory(pAd, pOutBuffer); |
| |
| return TRUE; |
| } |
| |
| int Set_TpcReq_Proc(struct rt_rtmp_adapter *pAd, char *arg) |
| { |
| u32 Aid; |
| |
| u8 TpcReqToken = RandomByte(pAd); |
| |
| Aid = (u32)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; |
| } |