| /* |
| ************************************************************************* |
| * 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: |
| mlme.c |
| |
| Abstract: |
| |
| Revision History: |
| Who When What |
| -------- ---------- ---------------------------------------------- |
| John Chang 2004-08-25 Modify from RT2500 code base |
| John Chang 2004-09-06 modified for RT2600 |
| */ |
| |
| #include "../rt_config.h" |
| #include <stdarg.h> |
| |
| UCHAR CISCO_OUI[] = {0x00, 0x40, 0x96}; |
| |
| UCHAR WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; |
| UCHAR RSN_OUI[] = {0x00, 0x0f, 0xac}; |
| UCHAR WAPI_OUI[] = {0x00, 0x14, 0x72}; |
| UCHAR WME_INFO_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; |
| UCHAR WME_PARM_ELEM[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; |
| UCHAR Ccx2QosInfo[] = {0x00, 0x40, 0x96, 0x04}; |
| UCHAR RALINK_OUI[] = {0x00, 0x0c, 0x43}; |
| UCHAR BROADCOM_OUI[] = {0x00, 0x90, 0x4c}; |
| UCHAR WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; |
| #ifdef CONFIG_STA_SUPPORT |
| #ifdef DOT11_N_SUPPORT |
| UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; |
| #endif // DOT11_N_SUPPORT // |
| #endif // CONFIG_STA_SUPPORT // |
| |
| UCHAR RateSwitchTable[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x11, 0x00, 0, 0, 0, // Initial used item after association |
| 0x00, 0x00, 0, 40, 101, |
| 0x01, 0x00, 1, 40, 50, |
| 0x02, 0x00, 2, 35, 45, |
| 0x03, 0x00, 3, 20, 45, |
| 0x04, 0x21, 0, 30, 50, |
| 0x05, 0x21, 1, 20, 50, |
| 0x06, 0x21, 2, 20, 50, |
| 0x07, 0x21, 3, 15, 50, |
| 0x08, 0x21, 4, 15, 30, |
| 0x09, 0x21, 5, 10, 25, |
| 0x0a, 0x21, 6, 8, 25, |
| 0x0b, 0x21, 7, 8, 25, |
| 0x0c, 0x20, 12, 15, 30, |
| 0x0d, 0x20, 13, 8, 20, |
| 0x0e, 0x20, 14, 8, 20, |
| 0x0f, 0x20, 15, 8, 25, |
| 0x10, 0x22, 15, 8, 25, |
| 0x11, 0x00, 0, 0, 0, |
| 0x12, 0x00, 0, 0, 0, |
| 0x13, 0x00, 0, 0, 0, |
| 0x14, 0x00, 0, 0, 0, |
| 0x15, 0x00, 0, 0, 0, |
| 0x16, 0x00, 0, 0, 0, |
| 0x17, 0x00, 0, 0, 0, |
| 0x18, 0x00, 0, 0, 0, |
| 0x19, 0x00, 0, 0, 0, |
| 0x1a, 0x00, 0, 0, 0, |
| 0x1b, 0x00, 0, 0, 0, |
| 0x1c, 0x00, 0, 0, 0, |
| 0x1d, 0x00, 0, 0, 0, |
| 0x1e, 0x00, 0, 0, 0, |
| 0x1f, 0x00, 0, 0, 0, |
| }; |
| |
| UCHAR RateSwitchTable11B[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x04, 0x03, 0, 0, 0, // Initial used item after association |
| 0x00, 0x00, 0, 40, 101, |
| 0x01, 0x00, 1, 40, 50, |
| 0x02, 0x00, 2, 35, 45, |
| 0x03, 0x00, 3, 20, 45, |
| }; |
| |
| UCHAR RateSwitchTable11BG[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0a, 0x00, 0, 0, 0, // Initial used item after association |
| 0x00, 0x00, 0, 40, 101, |
| 0x01, 0x00, 1, 40, 50, |
| 0x02, 0x00, 2, 35, 45, |
| 0x03, 0x00, 3, 20, 45, |
| 0x04, 0x10, 2, 20, 35, |
| 0x05, 0x10, 3, 16, 35, |
| 0x06, 0x10, 4, 10, 25, |
| 0x07, 0x10, 5, 16, 25, |
| 0x08, 0x10, 6, 10, 25, |
| 0x09, 0x10, 7, 10, 13, |
| }; |
| |
| UCHAR RateSwitchTable11G[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x08, 0x00, 0, 0, 0, // Initial used item after association |
| 0x00, 0x10, 0, 20, 101, |
| 0x01, 0x10, 1, 20, 35, |
| 0x02, 0x10, 2, 20, 35, |
| 0x03, 0x10, 3, 16, 35, |
| 0x04, 0x10, 4, 10, 25, |
| 0x05, 0x10, 5, 16, 25, |
| 0x06, 0x10, 6, 10, 25, |
| 0x07, 0x10, 7, 10, 13, |
| }; |
| |
| #ifdef DOT11_N_SUPPORT |
| UCHAR RateSwitchTable11N1S[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0c, 0x0a, 0, 0, 0, // Initial used item after association |
| 0x00, 0x00, 0, 40, 101, |
| 0x01, 0x00, 1, 40, 50, |
| 0x02, 0x00, 2, 25, 45, |
| 0x03, 0x21, 0, 20, 35, |
| 0x04, 0x21, 1, 20, 35, |
| 0x05, 0x21, 2, 20, 35, |
| 0x06, 0x21, 3, 15, 35, |
| 0x07, 0x21, 4, 15, 30, |
| 0x08, 0x21, 5, 10, 25, |
| 0x09, 0x21, 6, 8, 14, |
| 0x0a, 0x21, 7, 8, 14, |
| 0x0b, 0x23, 7, 8, 14, |
| }; |
| |
| UCHAR RateSwitchTable11N2S[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0e, 0x0c, 0, 0, 0, // Initial used item after association |
| 0x00, 0x00, 0, 40, 101, |
| 0x01, 0x00, 1, 40, 50, |
| 0x02, 0x00, 2, 25, 45, |
| 0x03, 0x21, 0, 20, 35, |
| 0x04, 0x21, 1, 20, 35, |
| 0x05, 0x21, 2, 20, 35, |
| 0x06, 0x21, 3, 15, 35, |
| 0x07, 0x21, 4, 15, 30, |
| 0x08, 0x20, 11, 15, 30, |
| 0x09, 0x20, 12, 15, 30, |
| 0x0a, 0x20, 13, 8, 20, |
| 0x0b, 0x20, 14, 8, 20, |
| 0x0c, 0x20, 15, 8, 25, |
| 0x0d, 0x22, 15, 8, 15, |
| }; |
| |
| UCHAR RateSwitchTable11N3S[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0b, 0x00, 0, 0, 0, // 0x0a, 0x00, 0, 0, 0, // Initial used item after association |
| 0x00, 0x21, 0, 30, 101, |
| 0x01, 0x21, 1, 20, 50, |
| 0x02, 0x21, 2, 20, 50, |
| 0x03, 0x21, 3, 15, 50, |
| 0x04, 0x21, 4, 15, 30, |
| 0x05, 0x20, 11, 15, 30, // Required by System-Alan @ 20080812 |
| 0x06, 0x20, 12, 15, 30, // 0x05, 0x20, 12, 15, 30, |
| 0x07, 0x20, 13, 8, 20, // 0x06, 0x20, 13, 8, 20, |
| 0x08, 0x20, 14, 8, 20, // 0x07, 0x20, 14, 8, 20, |
| 0x09, 0x20, 15, 8, 25, // 0x08, 0x20, 15, 8, 25, |
| 0x0a, 0x22, 15, 8, 25, // 0x09, 0x22, 15, 8, 25, |
| }; |
| |
| UCHAR RateSwitchTable11N2SForABand[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0b, 0x09, 0, 0, 0, // Initial used item after association |
| 0x00, 0x21, 0, 30, 101, |
| 0x01, 0x21, 1, 20, 50, |
| 0x02, 0x21, 2, 20, 50, |
| 0x03, 0x21, 3, 15, 50, |
| 0x04, 0x21, 4, 15, 30, |
| 0x05, 0x21, 5, 15, 30, |
| 0x06, 0x20, 12, 15, 30, |
| 0x07, 0x20, 13, 8, 20, |
| 0x08, 0x20, 14, 8, 20, |
| 0x09, 0x20, 15, 8, 25, |
| 0x0a, 0x22, 15, 8, 25, |
| }; |
| |
| UCHAR RateSwitchTable11N3SForABand[] = { // 3*3 |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0b, 0x09, 0, 0, 0, // Initial used item after association |
| 0x00, 0x21, 0, 30, 101, |
| 0x01, 0x21, 1, 20, 50, |
| 0x02, 0x21, 2, 20, 50, |
| 0x03, 0x21, 3, 15, 50, |
| 0x04, 0x21, 4, 15, 30, |
| 0x05, 0x21, 5, 15, 30, |
| 0x06, 0x20, 12, 15, 30, |
| 0x07, 0x20, 13, 8, 20, |
| 0x08, 0x20, 14, 8, 20, |
| 0x09, 0x20, 15, 8, 25, |
| 0x0a, 0x22, 15, 8, 25, |
| }; |
| |
| UCHAR RateSwitchTable11BGN1S[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0c, 0x0a, 0, 0, 0, // Initial used item after association |
| 0x00, 0x00, 0, 40, 101, |
| 0x01, 0x00, 1, 40, 50, |
| 0x02, 0x00, 2, 25, 45, |
| 0x03, 0x21, 0, 20, 35, |
| 0x04, 0x21, 1, 20, 35, |
| 0x05, 0x21, 2, 20, 35, |
| 0x06, 0x21, 3, 15, 35, |
| 0x07, 0x21, 4, 15, 30, |
| 0x08, 0x21, 5, 10, 25, |
| 0x09, 0x21, 6, 8, 14, |
| 0x0a, 0x21, 7, 8, 14, |
| 0x0b, 0x23, 7, 8, 14, |
| }; |
| |
| UCHAR RateSwitchTable11BGN2S[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0e, 0x0c, 0, 0, 0, // Initial used item after association |
| 0x00, 0x00, 0, 40, 101, |
| 0x01, 0x00, 1, 40, 50, |
| 0x02, 0x00, 2, 25, 45, |
| 0x03, 0x21, 0, 20, 35, |
| 0x04, 0x21, 1, 20, 35, |
| 0x05, 0x21, 2, 20, 35, |
| 0x06, 0x21, 3, 15, 35, |
| 0x07, 0x21, 4, 15, 30, |
| 0x08, 0x20, 11, 15, 30, |
| 0x09, 0x20, 12, 15, 30, |
| 0x0a, 0x20, 13, 8, 20, |
| 0x0b, 0x20, 14, 8, 20, |
| 0x0c, 0x20, 15, 8, 25, |
| 0x0d, 0x22, 15, 8, 15, |
| }; |
| |
| UCHAR RateSwitchTable11BGN3S[] = { // 3*3 |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0a, 0x00, 0, 0, 0, // Initial used item after association |
| 0x00, 0x21, 0, 30,101, //50 |
| 0x01, 0x21, 1, 20, 50, |
| 0x02, 0x21, 2, 20, 50, |
| 0x03, 0x21, 3, 20, 50, |
| 0x04, 0x21, 4, 15, 50, |
| 0x05, 0x20, 20, 15, 30, |
| 0x06, 0x20, 21, 8, 20, |
| 0x07, 0x20, 22, 8, 20, |
| 0x08, 0x20, 23, 8, 25, |
| 0x09, 0x22, 23, 8, 25, |
| }; |
| |
| UCHAR RateSwitchTable11BGN2SForABand[] = { |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0b, 0x09, 0, 0, 0, // Initial used item after association |
| 0x00, 0x21, 0, 30,101, //50 |
| 0x01, 0x21, 1, 20, 50, |
| 0x02, 0x21, 2, 20, 50, |
| 0x03, 0x21, 3, 15, 50, |
| 0x04, 0x21, 4, 15, 30, |
| 0x05, 0x21, 5, 15, 30, |
| 0x06, 0x20, 12, 15, 30, |
| 0x07, 0x20, 13, 8, 20, |
| 0x08, 0x20, 14, 8, 20, |
| 0x09, 0x20, 15, 8, 25, |
| 0x0a, 0x22, 15, 8, 25, |
| }; |
| |
| UCHAR RateSwitchTable11BGN3SForABand[] = { // 3*3 |
| // Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) |
| 0x0c, 0x09, 0, 0, 0, // Initial used item after association |
| 0x00, 0x21, 0, 30,101, //50 |
| 0x01, 0x21, 1, 20, 50, |
| 0x02, 0x21, 2, 20, 50, |
| 0x03, 0x21, 3, 15, 50, |
| 0x04, 0x21, 4, 15, 30, |
| 0x05, 0x21, 5, 15, 30, |
| 0x06, 0x21, 12, 15, 30, |
| 0x07, 0x20, 20, 15, 30, |
| 0x08, 0x20, 21, 8, 20, |
| 0x09, 0x20, 22, 8, 20, |
| 0x0a, 0x20, 23, 8, 25, |
| 0x0b, 0x22, 23, 8, 25, |
| }; |
| #endif // DOT11_N_SUPPORT // |
| |
| |
| extern UCHAR OfdmRateToRxwiMCS[]; |
| // since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. |
| // otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate |
| ULONG BasicRateMask[12] = {0xfffff001 /* 1-Mbps */, 0xfffff003 /* 2 Mbps */, 0xfffff007 /* 5.5 */, 0xfffff00f /* 11 */, |
| 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ , 0xfffff0ff /* 18 */, |
| 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ , 0xffffffff /* 54 */}; |
| |
| UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
| UCHAR ZERO_MAC_ADDR[MAC_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| |
| // e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than |
| // this value, then it's quaranteed capable of operating in 36 mbps TX rate in |
| // clean environment. |
| // TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 |
| CHAR RssiSafeLevelForTxRate[] ={ -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 }; |
| |
| UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100}; |
| USHORT RateIdTo500Kbps[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200}; |
| |
| UCHAR SsidIe = IE_SSID; |
| UCHAR SupRateIe = IE_SUPP_RATES; |
| UCHAR ExtRateIe = IE_EXT_SUPP_RATES; |
| #ifdef DOT11_N_SUPPORT |
| UCHAR HtCapIe = IE_HT_CAP; |
| UCHAR AddHtInfoIe = IE_ADD_HT; |
| UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; |
| #ifdef DOT11N_DRAFT3 |
| UCHAR ExtHtCapIe = IE_EXT_CAPABILITY; |
| #endif // DOT11N_DRAFT3 // |
| #endif // DOT11_N_SUPPORT // |
| UCHAR ErpIe = IE_ERP; |
| UCHAR DsIe = IE_DS_PARM; |
| UCHAR TimIe = IE_TIM; |
| UCHAR WpaIe = IE_WPA; |
| UCHAR Wpa2Ie = IE_WPA2; |
| UCHAR IbssIe = IE_IBSS_PARM; |
| UCHAR Ccx2Ie = IE_CCX_V2; |
| UCHAR WapiIe = IE_WAPI; |
| |
| extern UCHAR WPA_OUI[]; |
| |
| UCHAR SES_OUI[] = {0x00, 0x90, 0x4c}; |
| |
| UCHAR ZeroSsid[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; |
| |
| |
| /* |
| ========================================================================== |
| Description: |
| initialize the MLME task and its data structure (queue, spinlock, |
| timer, state machines). |
| |
| IRQL = PASSIVE_LEVEL |
| |
| Return: |
| always return NDIS_STATUS_SUCCESS |
| |
| ========================================================================== |
| */ |
| NDIS_STATUS MlmeInit( |
| IN PRTMP_ADAPTER pAd) |
| { |
| NDIS_STATUS Status = NDIS_STATUS_SUCCESS; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n")); |
| |
| do |
| { |
| Status = MlmeQueueInit(&pAd->Mlme.Queue); |
| if(Status != NDIS_STATUS_SUCCESS) |
| break; |
| |
| pAd->Mlme.bRunning = FALSE; |
| NdisAllocateSpinLock(&pAd->Mlme.TaskLock); |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| BssTableInit(&pAd->ScanTab); |
| |
| // init STA state machines |
| AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine, pAd->Mlme.AssocFunc); |
| AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine, pAd->Mlme.AuthFunc); |
| AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine, pAd->Mlme.AuthRspFunc); |
| SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine, pAd->Mlme.SyncFunc); |
| |
| #ifdef QOS_DLS_SUPPORT |
| DlsStateMachineInit(pAd, &pAd->Mlme.DlsMachine, pAd->Mlme.DlsFunc); |
| #endif // QOS_DLS_SUPPORT // |
| |
| |
| |
| // Since we are using switch/case to implement it, the init is different from the above |
| // state machine init |
| MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL); |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| |
| WpaStateMachineInit(pAd, &pAd->Mlme.WpaMachine, pAd->Mlme.WpaFunc); |
| |
| |
| ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine, pAd->Mlme.ActFunc); |
| |
| // Init mlme periodic timer |
| RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer, GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE); |
| |
| // Set mlme periodic timer |
| RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV); |
| |
| // software-based RX Antenna diversity |
| RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer, GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd, FALSE); |
| |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| #ifdef RTMP_PCI_SUPPORT |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) |
| { |
| // only PCIe cards need these two timers |
| RTMPInitTimer(pAd, &pAd->Mlme.PsPollTimer, GET_TIMER_FUNCTION(PsPollWakeExec), pAd, FALSE); |
| RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer, GET_TIMER_FUNCTION(RadioOnExec), pAd, FALSE); |
| } |
| #endif // RTMP_PCI_SUPPORT // |
| |
| RTMPInitTimer(pAd, &pAd->Mlme.LinkDownTimer, GET_TIMER_FUNCTION(LinkDownExec), pAd, FALSE); |
| |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| } while (FALSE); |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n")); |
| |
| return Status; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| main loop of the MLME |
| Pre: |
| Mlme has to be initialized, and there are something inside the queue |
| Note: |
| This function is invoked from MPSetInformation and MPReceive; |
| This task guarantee only one MlmeHandler will run. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID MlmeHandler( |
| IN PRTMP_ADAPTER pAd) |
| { |
| MLME_QUEUE_ELEM *Elem = NULL; |
| #ifdef APCLI_SUPPORT |
| SHORT apcliIfIndex; |
| #endif // APCLI_SUPPORT // |
| |
| // Only accept MLME and Frame from peer side, no other (control/data) frame should |
| // get into this state machine |
| |
| NdisAcquireSpinLock(&pAd->Mlme.TaskLock); |
| if(pAd->Mlme.bRunning) |
| { |
| NdisReleaseSpinLock(&pAd->Mlme.TaskLock); |
| return; |
| } |
| else |
| { |
| pAd->Mlme.bRunning = TRUE; |
| } |
| NdisReleaseSpinLock(&pAd->Mlme.TaskLock); |
| |
| while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) |
| { |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) || |
| RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) || |
| RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n", pAd->Mlme.Queue.Num)); |
| break; |
| } |
| |
| #ifdef RALINK_ATE |
| if(ATE_ON(pAd)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("The driver is in ATE mode now in MlmeHandler\n")); |
| break; |
| } |
| #endif // RALINK_ATE // |
| |
| //From message type, determine which state machine I should drive |
| if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) |
| { |
| |
| // if dequeue success |
| switch (Elem->Machine) |
| { |
| // STA state machines |
| #ifdef CONFIG_STA_SUPPORT |
| case ASSOC_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.AssocMachine, Elem); |
| break; |
| case AUTH_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.AuthMachine, Elem); |
| break; |
| case AUTH_RSP_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.AuthRspMachine, Elem); |
| break; |
| case SYNC_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.SyncMachine, Elem); |
| break; |
| case MLME_CNTL_STATE_MACHINE: |
| MlmeCntlMachinePerformAction(pAd, &pAd->Mlme.CntlMachine, Elem); |
| break; |
| case WPA_PSK_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.WpaPskMachine, Elem); |
| break; |
| |
| #ifdef QOS_DLS_SUPPORT |
| case DLS_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.DlsMachine, Elem); |
| break; |
| #endif // QOS_DLS_SUPPORT // |
| |
| #endif // CONFIG_STA_SUPPORT // |
| |
| case ACTION_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, Elem); |
| break; |
| |
| case WPA_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.WpaMachine, Elem); |
| break; |
| |
| |
| default: |
| DBGPRINT(RT_DEBUG_TRACE, ("ERROR: Illegal machine %ld in MlmeHandler()\n", Elem->Machine)); |
| break; |
| } // end of switch |
| |
| // free MLME element |
| Elem->Occupied = FALSE; |
| Elem->MsgLen = 0; |
| |
| } |
| else { |
| DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n")); |
| } |
| } |
| |
| NdisAcquireSpinLock(&pAd->Mlme.TaskLock); |
| pAd->Mlme.bRunning = FALSE; |
| NdisReleaseSpinLock(&pAd->Mlme.TaskLock); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Destructor of MLME (Destroy queue, state machine, spin lock and timer) |
| Parameters: |
| Adapter - NIC Adapter pointer |
| Post: |
| The MLME task will no longer work properly |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID MlmeHalt( |
| IN PRTMP_ADAPTER pAd) |
| { |
| BOOLEAN Cancelled; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n")); |
| |
| if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) |
| { |
| // disable BEACON generation and other BEACON related hardware timers |
| AsicDisableSync(pAd); |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| #ifdef QOS_DLS_SUPPORT |
| UCHAR i; |
| #endif // QOS_DLS_SUPPORT // |
| // Cancel pending timers |
| RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); |
| |
| |
| #ifdef RTMP_MAC_PCI |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE) |
| &&(pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) |
| { |
| RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); |
| } |
| #endif // RTMP_MAC_PCI // |
| |
| #ifdef QOS_DLS_SUPPORT |
| for (i=0; i<MAX_NUM_OF_DLS_ENTRY; i++) |
| { |
| RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &Cancelled); |
| } |
| #endif // QOS_DLS_SUPPORT // |
| RTMPCancelTimer(&pAd->Mlme.LinkDownTimer, &Cancelled); |
| |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); |
| |
| |
| |
| if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) |
| { |
| RTMP_CHIP_OP *pChipOps = &pAd->chipOps; |
| |
| // Set LED |
| RTMPSetLED(pAd, LED_HALT); |
| RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. |
| |
| if (pChipOps->AsicHaltAction) |
| pChipOps->AsicHaltAction(pAd); |
| } |
| |
| RTMPusecDelay(5000); // 5 msec to gurantee Ant Diversity timer canceled |
| |
| MlmeQueueDestroy(&pAd->Mlme.Queue); |
| NdisFreeSpinLock(&pAd->Mlme.TaskLock); |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n")); |
| } |
| |
| VOID MlmeResetRalinkCounters( |
| IN PRTMP_ADAPTER pAd) |
| { |
| pAd->RalinkCounters.LastOneSecRxOkDataCnt = pAd->RalinkCounters.OneSecRxOkDataCnt; |
| // clear all OneSecxxx counters. |
| pAd->RalinkCounters.OneSecBeaconSentCnt = 0; |
| pAd->RalinkCounters.OneSecFalseCCACnt = 0; |
| pAd->RalinkCounters.OneSecRxFcsErrCnt = 0; |
| pAd->RalinkCounters.OneSecRxOkCnt = 0; |
| pAd->RalinkCounters.OneSecTxFailCount = 0; |
| pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0; |
| pAd->RalinkCounters.OneSecTxRetryOkCount = 0; |
| pAd->RalinkCounters.OneSecRxOkDataCnt = 0; |
| pAd->RalinkCounters.OneSecReceivedByteCount = 0; |
| pAd->RalinkCounters.OneSecTransmittedByteCount = 0; |
| |
| // TODO: for debug only. to be removed |
| pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0; |
| pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0; |
| pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0; |
| pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0; |
| pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0; |
| pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0; |
| pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0; |
| pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0; |
| pAd->RalinkCounters.OneSecTxDoneCount = 0; |
| pAd->RalinkCounters.OneSecRxCount = 0; |
| pAd->RalinkCounters.OneSecTxAggregationCount = 0; |
| pAd->RalinkCounters.OneSecRxAggregationCount = 0; |
| |
| return; |
| } |
| |
| |
| /* |
| ========================================================================== |
| Description: |
| This routine is executed periodically to - |
| 1. Decide if it's a right time to turn on PwrMgmt bit of all |
| outgoiing frames |
| 2. Calculate ChannelQuality based on statistics of the last |
| period, so that TX rate won't toggling very frequently between a |
| successful TX and a failed TX. |
| 3. If the calculated ChannelQuality indicated current connection not |
| healthy, then a ROAMing attempt is tried here. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| #define ADHOC_BEACON_LOST_TIME (8*OS_HZ) // 8 sec |
| VOID MlmePeriodicExec( |
| IN PVOID SystemSpecific1, |
| IN PVOID FunctionContext, |
| IN PVOID SystemSpecific2, |
| IN PVOID SystemSpecific3) |
| { |
| ULONG TxTotalCnt; |
| PRTMP_ADAPTER pAd = (RTMP_ADAPTER *)FunctionContext; |
| SHORT realavgrssi; |
| |
| #ifdef CONFIG_STA_SUPPORT |
| #ifdef RTMP_MAC_PCI |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| // If Hardware controlled Radio enabled, we have to check GPIO pin2 every 2 second. |
| // Move code to here, because following code will return when radio is off |
| if ((pAd->Mlme.PeriodicRound % (MLME_TASK_EXEC_MULTIPLE * 2) == 0) && (pAd->StaCfg.bHardwareRadio == TRUE) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) |
| /*&&(pAd->bPCIclkOff == FALSE)*/) |
| { |
| UINT32 data = 0; |
| |
| // Read GPIO pin2 as Hardware controlled radio state |
| #ifndef RT3090 |
| RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data); |
| #endif // RT3090 // |
| //KH(PCIE PS):Added based on Jane<-- |
| #ifdef RT3090 |
| // Read GPIO pin2 as Hardware controlled radio state |
| // We need to Read GPIO if HW said so no mater what advance power saving |
| if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd)) |
| && (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)) |
| && (pAd->StaCfg.PSControl.field.EnablePSinIdle == TRUE)) |
| { |
| // Want to make sure device goes to L0 state before reading register. |
| RTMPPCIeLinkCtrlValueRestore(pAd, 0); |
| RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data); |
| RTMPPCIeLinkCtrlSetting(pAd, 3); |
| } |
| else |
| RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data); |
| #endif // RT3090 // |
| //KH(PCIE PS):Added based on Jane--> |
| |
| if (data & 0x04) |
| { |
| pAd->StaCfg.bHwRadio = TRUE; |
| } |
| else |
| { |
| pAd->StaCfg.bHwRadio = FALSE; |
| } |
| if (pAd->StaCfg.bRadio != (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) |
| { |
| pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio); |
| if (pAd->StaCfg.bRadio == TRUE) |
| { |
| MlmeRadioOn(pAd); |
| // Update extra information |
| pAd->ExtraInfo = EXTRA_INFO_CLEAR; |
| } |
| else |
| { |
| MlmeRadioOff(pAd); |
| // Update extra information |
| pAd->ExtraInfo = HW_RADIO_OFF; |
| } |
| } |
| } |
| } |
| #endif // RTMP_MAC_PCI // |
| #endif // CONFIG_STA_SUPPORT // |
| |
| // Do nothing if the driver is starting halt state. |
| // This might happen when timer already been fired before cancel timer with mlmehalt |
| if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_RADIO_OFF | |
| fRTMP_ADAPTER_RADIO_MEASUREMENT | |
| fRTMP_ADAPTER_RESET_IN_PROGRESS)))) |
| return; |
| |
| RTMP_MLME_PRE_SANITY_CHECK(pAd); |
| |
| #ifdef RALINK_ATE |
| /* Do not show RSSI until "Normal 1 second Mlme PeriodicExec". */ |
| if (ATE_ON(pAd)) |
| { |
| if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE != (MLME_TASK_EXEC_MULTIPLE - 1)) |
| { |
| pAd->Mlme.PeriodicRound ++; |
| return; |
| } |
| } |
| #endif // RALINK_ATE // |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| // Do nothing if monitor mode is on |
| if (MONITOR_ON(pAd)) |
| return; |
| |
| if (pAd->Mlme.PeriodicRound & 0x1) |
| { |
| // This is the fix for wifi 11n extension channel overlapping test case. for 2860D |
| if (((pAd->MACVersion & 0xffff) == 0x0101) && |
| (STA_TGN_WIFI_ON(pAd)) && |
| (pAd->CommonCfg.IOTestParm.bToggle == FALSE)) |
| |
| { |
| RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf); |
| pAd->CommonCfg.IOTestParm.bToggle = TRUE; |
| } |
| else if ((STA_TGN_WIFI_ON(pAd)) && |
| ((pAd->MACVersion & 0xffff) == 0x0101)) |
| { |
| RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f); |
| pAd->CommonCfg.IOTestParm.bToggle = FALSE; |
| } |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| pAd->bUpdateBcnCntDone = FALSE; |
| |
| // RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); |
| pAd->Mlme.PeriodicRound ++; |
| |
| |
| // execute every 500ms |
| if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) |
| { |
| #ifdef CONFIG_STA_SUPPORT |
| // perform dynamic tx rate switching based on past TX history |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) |
| ) |
| && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) |
| MlmeDynamicTxRateSwitching(pAd); |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| } |
| |
| // Normal 1 second Mlme PeriodicExec. |
| if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0) |
| { |
| pAd->Mlme.OneSecPeriodicRound ++; |
| |
| #ifdef RALINK_ATE |
| if (ATE_ON(pAd)) |
| { |
| /* request from Baron : move this routine from later to here */ |
| /* for showing Rx error count in ATE RXFRAME */ |
| NICUpdateRawCounters(pAd); |
| if (pAd->ate.bRxFER == 1) |
| { |
| pAd->ate.RxTotalCnt += pAd->ate.RxCntPerSec; |
| ate_print(KERN_EMERG "MlmePeriodicExec: Rx packet cnt = %d/%d\n", pAd->ate.RxCntPerSec, pAd->ate.RxTotalCnt); |
| pAd->ate.RxCntPerSec = 0; |
| |
| if (pAd->ate.RxAntennaSel == 0) |
| ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi0=%d, AvgRssi1=%d, AvgRssi2=%d\n\n", |
| pAd->ate.AvgRssi0, pAd->ate.AvgRssi1, pAd->ate.AvgRssi2); |
| else |
| ate_print(KERN_EMERG "MlmePeriodicExec: Rx AvgRssi=%d\n\n", pAd->ate.AvgRssi0); |
| } |
| MlmeResetRalinkCounters(pAd); |
| |
| |
| |
| return; |
| } |
| #endif // RALINK_ATE // |
| |
| |
| |
| //ORIBATimerTimeout(pAd); |
| |
| // Media status changed, report to NDIS |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) |
| { |
| RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE); |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) |
| { |
| pAd->IndicateMediaState = NdisMediaStateConnected; |
| RTMP_IndicateMediaState(pAd); |
| } |
| else |
| { |
| pAd->IndicateMediaState = NdisMediaStateDisconnected; |
| RTMP_IndicateMediaState(pAd); |
| } |
| } |
| |
| NdisGetSystemUpTime(&pAd->Mlme.Now32); |
| |
| // add the most up-to-date h/w raw counters into software variable, so that |
| // the dynamic tuning mechanism below are based on most up-to-date information |
| NICUpdateRawCounters(pAd); |
| |
| |
| #ifdef DOT11_N_SUPPORT |
| // Need statistics after read counter. So put after NICUpdateRawCounters |
| ORIBATimerTimeout(pAd); |
| #endif // DOT11_N_SUPPORT // |
| |
| // if MGMT RING is full more than twice within 1 second, we consider there's |
| // a hardware problem stucking the TX path. In this case, try a hardware reset |
| // to recover the system |
| // if (pAd->RalinkCounters.MgmtRingFullCount >= 2) |
| // RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR); |
| // else |
| // pAd->RalinkCounters.MgmtRingFullCount = 0; |
| |
| // The time period for checking antenna is according to traffic |
| #ifdef ANT_DIVERSITY_SUPPORT |
| if ((pAd->NicConfig2.field.AntDiversity) && |
| (pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_ENABLE) && |
| (!pAd->EepromAccess)) |
| AsicAntennaSelect(pAd, pAd->MlmeAux.Channel); |
| else if(pAd->CommonCfg.bRxAntDiversity == ANT_FIX_ANT1 || pAd->CommonCfg.bRxAntDiversity == ANT_FIX_ANT2) |
| { |
| #ifdef CONFIG_STA_SUPPORT |
| realavgrssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt] >> 3); |
| #endif // CONFIG_STA_SUPPORT // |
| DBGPRINT(RT_DEBUG_TRACE,("Ant-realrssi0(%d), Lastrssi0(%d), EvaluateStableCnt=%d\n", realavgrssi, pAd->RxAnt.Pair1LastAvgRssi, pAd->RxAnt.EvaluateStableCnt)); |
| } |
| else |
| #endif // ANT_DIVERSITY_SUPPORT // |
| { |
| if (pAd->Mlme.bEnableAutoAntennaCheck) |
| { |
| TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + |
| pAd->RalinkCounters.OneSecTxRetryOkCount + |
| pAd->RalinkCounters.OneSecTxFailCount; |
| |
| // dynamic adjust antenna evaluation period according to the traffic |
| if (TxTotalCnt > 50) |
| { |
| if (pAd->Mlme.OneSecPeriodicRound % 10 == 0) |
| { |
| AsicEvaluateRxAnt(pAd); |
| } |
| } |
| else |
| { |
| if (pAd->Mlme.OneSecPeriodicRound % 3 == 0) |
| { |
| AsicEvaluateRxAnt(pAd); |
| } |
| } |
| } |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| STAMlmePeriodicExec(pAd); |
| #endif // CONFIG_STA_SUPPORT // |
| |
| MlmeResetRalinkCounters(pAd); |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| #ifdef RTMP_MAC_PCI |
| if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->bPCIclkOff == FALSE)) |
| #endif // RTMP_MAC_PCI // |
| { |
| // When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock |
| // and sending CTS-to-self over and over. |
| // Software Patch Solution: |
| // 1. Polling debug state register 0x10F4 every one second. |
| // 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. |
| // 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. |
| |
| UINT32 MacReg = 0; |
| |
| RTMP_IO_READ32(pAd, 0x10F4, &MacReg); |
| if (((MacReg & 0x20000000) && (MacReg & 0x80)) || ((MacReg & 0x20000000) && (MacReg & 0x20))) |
| { |
| RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1); |
| RTMPusecDelay(1); |
| RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC); |
| |
| DBGPRINT(RT_DEBUG_WARN,("Warning, MAC specific condition occurs \n")); |
| } |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| RTMP_MLME_HANDLER(pAd); |
| } |
| |
| |
| pAd->bUpdateBcnCntDone = FALSE; |
| } |
| |
| |
| /* |
| ========================================================================== |
| Validate SSID for connection try and rescan purpose |
| Valid SSID will have visible chars only. |
| The valid length is from 0 to 32. |
| IRQL = DISPATCH_LEVEL |
| ========================================================================== |
| */ |
| BOOLEAN MlmeValidateSSID( |
| IN PUCHAR pSsid, |
| IN UCHAR SsidLen) |
| { |
| int index; |
| |
| if (SsidLen > MAX_LEN_OF_SSID) |
| return (FALSE); |
| |
| // Check each character value |
| for (index = 0; index < SsidLen; index++) |
| { |
| if (pSsid[index] < 0x20) |
| return (FALSE); |
| } |
| |
| // All checked |
| return (TRUE); |
| } |
| |
| VOID MlmeSelectTxRateTable( |
| IN PRTMP_ADAPTER pAd, |
| IN PMAC_TABLE_ENTRY pEntry, |
| IN PUCHAR *ppTable, |
| IN PUCHAR pTableSize, |
| IN PUCHAR pInitTxRateIdx) |
| { |
| do |
| { |
| // decide the rate table for tuning |
| if (pAd->CommonCfg.TxRateTableSize > 0) |
| { |
| *ppTable = RateSwitchTable; |
| *pTableSize = RateSwitchTable[0]; |
| *pInitTxRateIdx = RateSwitchTable[1]; |
| |
| break; |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) |
| { |
| #ifdef DOT11_N_SUPPORT |
| if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && |
| (pEntry->HTCapability.MCSSet[0] == 0xff) && |
| ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) |
| {// 11N 1S Adhoc |
| *ppTable = RateSwitchTable11N1S; |
| *pTableSize = RateSwitchTable11N1S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N1S[1]; |
| |
| } |
| else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && |
| (pEntry->HTCapability.MCSSet[0] == 0xff) && |
| (pEntry->HTCapability.MCSSet[1] == 0xff) && |
| (pAd->Antenna.field.TxPath == 2)) |
| {// 11N 2S Adhoc |
| if (pAd->LatchRfRegs.Channel <= 14) |
| { |
| *ppTable = RateSwitchTable11N2S; |
| *pTableSize = RateSwitchTable11N2S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N2S[1]; |
| } |
| else |
| { |
| *ppTable = RateSwitchTable11N2SForABand; |
| *pTableSize = RateSwitchTable11N2SForABand[0]; |
| *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; |
| } |
| |
| } |
| else |
| #endif // DOT11_N_SUPPORT // |
| if ((pEntry->RateLen == 4) |
| #ifdef DOT11_N_SUPPORT |
| && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) |
| #endif // DOT11_N_SUPPORT // |
| ) |
| { |
| *ppTable = RateSwitchTable11B; |
| *pTableSize = RateSwitchTable11B[0]; |
| *pInitTxRateIdx = RateSwitchTable11B[1]; |
| |
| } |
| else if (pAd->LatchRfRegs.Channel <= 14) |
| { |
| *ppTable = RateSwitchTable11BG; |
| *pTableSize = RateSwitchTable11BG[0]; |
| *pInitTxRateIdx = RateSwitchTable11BG[1]; |
| |
| } |
| else |
| { |
| *ppTable = RateSwitchTable11G; |
| *pTableSize = RateSwitchTable11G[0]; |
| *pInitTxRateIdx = RateSwitchTable11G[1]; |
| |
| } |
| break; |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| #ifdef DOT11_N_SUPPORT |
| //if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && |
| // ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) |
| if (((pEntry->RateLen == 12) || (pAd->OpMode == OPMODE_STA)) && (pEntry->HTCapability.MCSSet[0] == 0xff) && |
| ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) |
| {// 11BGN 1S AP |
| *ppTable = RateSwitchTable11BGN1S; |
| *pTableSize = RateSwitchTable11BGN1S[0]; |
| *pInitTxRateIdx = RateSwitchTable11BGN1S[1]; |
| |
| break; |
| } |
| |
| //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && |
| // (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) |
| if (((pEntry->RateLen == 12) || (pAd->OpMode == OPMODE_STA)) && (pEntry->HTCapability.MCSSet[0] == 0xff) && |
| (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) |
| {// 11BGN 2S AP |
| if (pAd->LatchRfRegs.Channel <= 14) |
| { |
| *ppTable = RateSwitchTable11BGN2S; |
| *pTableSize = RateSwitchTable11BGN2S[0]; |
| *pInitTxRateIdx = RateSwitchTable11BGN2S[1]; |
| |
| } |
| else |
| { |
| *ppTable = RateSwitchTable11BGN2SForABand; |
| *pTableSize = RateSwitchTable11BGN2SForABand[0]; |
| *pInitTxRateIdx = RateSwitchTable11BGN2SForABand[1]; |
| |
| } |
| break; |
| } |
| |
| //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) |
| if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) |
| {// 11N 1S AP |
| *ppTable = RateSwitchTable11N1S; |
| *pTableSize = RateSwitchTable11N1S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N1S[1]; |
| |
| break; |
| } |
| |
| //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) |
| if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) |
| {// 11N 2S AP |
| if (pAd->LatchRfRegs.Channel <= 14) |
| { |
| *ppTable = RateSwitchTable11N2S; |
| *pTableSize = RateSwitchTable11N2S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N2S[1]; |
| } |
| else |
| { |
| *ppTable = RateSwitchTable11N2SForABand; |
| *pTableSize = RateSwitchTable11N2SForABand[0]; |
| *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; |
| } |
| |
| break; |
| } |
| #endif // DOT11_N_SUPPORT // |
| //else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) |
| if ((pEntry->RateLen == 4 || pAd->CommonCfg.PhyMode==PHY_11B) |
| #ifdef DOT11_N_SUPPORT |
| //Iverson mark for Adhoc b mode,sta will use rate 54 Mbps when connect with sta b/g/n mode |
| /* && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)*/ |
| #endif // DOT11_N_SUPPORT // |
| ) |
| {// B only AP |
| *ppTable = RateSwitchTable11B; |
| *pTableSize = RateSwitchTable11B[0]; |
| *pInitTxRateIdx = RateSwitchTable11B[1]; |
| |
| break; |
| } |
| |
| //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) |
| if ((pEntry->RateLen > 8) |
| #ifdef DOT11_N_SUPPORT |
| && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) |
| #endif // DOT11_N_SUPPORT // |
| ) |
| {// B/G mixed AP |
| *ppTable = RateSwitchTable11BG; |
| *pTableSize = RateSwitchTable11BG[0]; |
| *pInitTxRateIdx = RateSwitchTable11BG[1]; |
| |
| break; |
| } |
| |
| //else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) |
| if ((pEntry->RateLen == 8) |
| #ifdef DOT11_N_SUPPORT |
| && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) |
| #endif // DOT11_N_SUPPORT // |
| ) |
| {// G only AP |
| *ppTable = RateSwitchTable11G; |
| *pTableSize = RateSwitchTable11G[0]; |
| *pInitTxRateIdx = RateSwitchTable11G[1]; |
| |
| break; |
| } |
| #ifdef DOT11_N_SUPPORT |
| #endif // DOT11_N_SUPPORT // |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| #ifdef DOT11_N_SUPPORT |
| //else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) |
| if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) |
| #endif // DOT11_N_SUPPORT // |
| { // Legacy mode |
| if (pAd->CommonCfg.MaxTxRate <= RATE_11) |
| { |
| *ppTable = RateSwitchTable11B; |
| *pTableSize = RateSwitchTable11B[0]; |
| *pInitTxRateIdx = RateSwitchTable11B[1]; |
| } |
| else if ((pAd->CommonCfg.MaxTxRate > RATE_11) && (pAd->CommonCfg.MinTxRate > RATE_11)) |
| { |
| *ppTable = RateSwitchTable11G; |
| *pTableSize = RateSwitchTable11G[0]; |
| *pInitTxRateIdx = RateSwitchTable11G[1]; |
| |
| } |
| else |
| { |
| *ppTable = RateSwitchTable11BG; |
| *pTableSize = RateSwitchTable11BG[0]; |
| *pInitTxRateIdx = RateSwitchTable11BG[1]; |
| } |
| break; |
| } |
| #ifdef DOT11_N_SUPPORT |
| if (pAd->LatchRfRegs.Channel <= 14) |
| { |
| if (pAd->CommonCfg.TxStream == 1) |
| { |
| *ppTable = RateSwitchTable11N1S; |
| *pTableSize = RateSwitchTable11N1S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N1S[1]; |
| DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); |
| } |
| else |
| { |
| *ppTable = RateSwitchTable11N2S; |
| *pTableSize = RateSwitchTable11N2S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N2S[1]; |
| DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); |
| } |
| } |
| else |
| { |
| if (pAd->CommonCfg.TxStream == 1) |
| { |
| *ppTable = RateSwitchTable11N1S; |
| *pTableSize = RateSwitchTable11N1S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N1S[1]; |
| DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 1S AP \n")); |
| } |
| else |
| { |
| *ppTable = RateSwitchTable11N2SForABand; |
| *pTableSize = RateSwitchTable11N2SForABand[0]; |
| *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; |
| DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode,default use 11N 2S AP \n")); |
| } |
| } |
| #endif // DOT11_N_SUPPORT // |
| DBGPRINT_RAW(RT_DEBUG_ERROR,("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", |
| pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], pAd->StaActive.SupportedPhyInfo.MCSSet[1])); |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| } while(FALSE); |
| } |
| |
| |
| #ifdef CONFIG_STA_SUPPORT |
| VOID STAMlmePeriodicExec( |
| PRTMP_ADAPTER pAd) |
| { |
| ULONG TxTotalCnt; |
| int i; |
| |
| |
| |
| |
| /* |
| We return here in ATE mode, because the statistics |
| that ATE need are not collected via this routine. |
| */ |
| #ifdef RALINK_ATE |
| if (ATE_ON(pAd)) |
| return; |
| #endif // RALINK_ATE // |
| |
| #ifdef RALINK_ATE |
| // It is supposed that we will never reach here in ATE mode. |
| ASSERT(!(ATE_ON(pAd))); |
| if (ATE_ON(pAd)) |
| return; |
| #endif // RALINK_ATE // |
| |
| #ifdef PCIE_PS_SUPPORT |
| // don't perform idle-power-save mechanism within 3 min after driver initialization. |
| // This can make rebooter test more robust |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) |
| { |
| if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd)) |
| && (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE) |
| && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) |
| && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) |
| { |
| if (IS_RT3090(pAd)|| IS_RT3572(pAd) || IS_RT3390(pAd)) |
| { |
| if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("%s::%d\n",__FUNCTION__,__LINE__)); |
| |
| RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0); |
| } |
| else |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("%s::%d\n",__FUNCTION__,__LINE__)); |
| AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x2); |
| // Wait command success |
| AsicCheckCommanOk(pAd, PowerSafeCID); |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF); |
| DBGPRINT(RT_DEBUG_TRACE, ("PSM - rt30xx Issue Sleep command)\n")); |
| } |
| } |
| else if (pAd->Mlme.OneSecPeriodicRound > 180) |
| { |
| if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("%s::%d\n",__FUNCTION__,__LINE__)); |
| RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0); |
| } |
| else |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("%s::%d\n",__FUNCTION__,__LINE__)); |
| AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x02); |
| // Wait command success |
| AsicCheckCommanOk(pAd, PowerSafeCID); |
| RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF); |
| DBGPRINT(RT_DEBUG_TRACE, ("PSM - rt28xx Issue Sleep command)\n")); |
| } |
| } |
| } |
| else |
| { |
| DBGPRINT(RT_DEBUG_TRACE,("STAMlmePeriodicExec MMCHK - CommonCfg.Ssid[%d]=%c%c%c%c... MlmeAux.Ssid[%d]=%c%c%c%c...\n", |
| pAd->CommonCfg.SsidLen, pAd->CommonCfg.Ssid[0], pAd->CommonCfg.Ssid[1], pAd->CommonCfg.Ssid[2], pAd->CommonCfg.Ssid[3], |
| pAd->MlmeAux.SsidLen, pAd->MlmeAux.Ssid[0], pAd->MlmeAux.Ssid[1], pAd->MlmeAux.Ssid[2], pAd->MlmeAux.Ssid[3])); |
| } |
| } |
| #endif // PCIE_PS_SUPPORT // |
| |
| |
| #ifdef WPA_SUPPLICANT_SUPPORT |
| if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) |
| #endif // WPA_SUPPLICANT_SUPPORT // |
| { |
| // WPA MIC error should block association attempt for 60 seconds |
| if (pAd->StaCfg.bBlockAssoc && |
| RTMP_TIME_AFTER(pAd->Mlme.Now32, pAd->StaCfg.LastMicErrorTime + (60*OS_HZ))) |
| pAd->StaCfg.bBlockAssoc = FALSE; |
| } |
| |
| if ((pAd->PreMediaState != pAd->IndicateMediaState) && (pAd->CommonCfg.bWirelessEvent)) |
| { |
| if (pAd->IndicateMediaState == NdisMediaStateConnected) |
| { |
| RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); |
| } |
| pAd->PreMediaState = pAd->IndicateMediaState; |
| } |
| |
| |
| |
| |
| if (pAd->CommonCfg.PSPXlink && ADHOC_ON(pAd)) |
| { |
| } |
| else |
| { |
| AsicStaBbpTuning(pAd); |
| } |
| |
| TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + |
| pAd->RalinkCounters.OneSecTxRetryOkCount + |
| pAd->RalinkCounters.OneSecTxFailCount; |
| |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) |
| { |
| // update channel quality for Roaming and UI LinkQuality display |
| MlmeCalculateChannelQuality(pAd, NULL, pAd->Mlme.Now32); |
| } |
| |
| // must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if |
| // Radio is currently in noisy environment |
| if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) |
| AsicAdjustTxPower(pAd); |
| |
| if (INFRA_ON(pAd)) |
| { |
| #ifdef QOS_DLS_SUPPORT |
| // Check DLS time out, then tear down those session |
| RTMPCheckDLSTimeOut(pAd); |
| #endif // QOS_DLS_SUPPORT // |
| |
| // Is PSM bit consistent with user power management policy? |
| // This is the only place that will set PSM bit ON. |
| if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) |
| MlmeCheckPsmChange(pAd, pAd->Mlme.Now32); |
| |
| pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt; |
| |
| if ((RTMP_TIME_AFTER(pAd->Mlme.Now32, pAd->StaCfg.LastBeaconRxTime + (1*OS_HZ))) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && |
| (((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt) < 600))) |
| { |
| RTMPSetAGCInitValue(pAd, BW_20); |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n", (0x2E + GET_LNA_GAIN(pAd)))); |
| } |
| |
| //if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && |
| // (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) |
| { |
| if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable) |
| { |
| // When APSD is enabled, the period changes as 20 sec |
| if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8) |
| RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); |
| } |
| else |
| { |
| // Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) |
| if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) |
| { |
| if (pAd->CommonCfg.bWmmCapable) |
| RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); |
| else |
| RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); |
| } |
| } |
| } |
| |
| if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); |
| |
| // Lost AP, send disconnect & link down event |
| LinkDown(pAd, FALSE); |
| |
| #ifdef WPA_SUPPLICANT_SUPPORT |
| #ifndef NATIVE_WPA_SUPPLICANT_SUPPORT |
| //send disassociate event to wpa_supplicant |
| if (pAd->StaCfg.WpaSupplicantUP) { |
| RtmpOSWrielessEventSend(pAd, IWEVCUSTOM, RT_DISASSOC_EVENT_FLAG, NULL, NULL, 0); |
| } |
| #endif // NATIVE_WPA_SUPPLICANT_SUPPORT // |
| #endif // WPA_SUPPLICANT_SUPPORT // |
| |
| #ifdef NATIVE_WPA_SUPPLICANT_SUPPORT |
| RtmpOSWrielessEventSend(pAd, SIOCGIWAP, -1, NULL, NULL, 0); |
| #endif // NATIVE_WPA_SUPPLICANT_SUPPORT // |
| |
| // RTMPPatchMacBbpBug(pAd); |
| MlmeAutoReconnectLastSSID(pAd); |
| } |
| else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) |
| { |
| pAd->RalinkCounters.BadCQIAutoRecoveryCount ++; |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n", pAd->RalinkCounters.BadCQIAutoRecoveryCount)); |
| MlmeAutoReconnectLastSSID(pAd); |
| } |
| |
| if (pAd->StaCfg.bAutoRoaming) |
| { |
| BOOLEAN rv = FALSE; |
| CHAR dBmToRoam = pAd->StaCfg.dBmToRoam; |
| CHAR MaxRssi = RTMPMaxRssi(pAd, |
| pAd->StaCfg.RssiSample.LastRssi0, |
| pAd->StaCfg.RssiSample.LastRssi1, |
| pAd->StaCfg.RssiSample.LastRssi2); |
| |
| // Scanning, ignore Roaming |
| if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) && |
| (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE) && |
| (MaxRssi <= dBmToRoam)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", MaxRssi, (CHAR)dBmToRoam)); |
| |
| |
| // Add auto seamless roaming |
| if (rv == FALSE) |
| rv = MlmeCheckForFastRoaming(pAd); |
| |
| if (rv == FALSE) |
| { |
| if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n")); |
| pAd->StaCfg.ScanCnt = 2; |
| pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; |
| MlmeAutoScan(pAd); |
| } |
| } |
| } |
| } |
| } |
| else if (ADHOC_ON(pAd)) |
| { |
| |
| // If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState |
| // to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can |
| // join later. |
| if (RTMP_TIME_AFTER(pAd->Mlme.Now32, pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME) && |
| OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) |
| { |
| MLME_START_REQ_STRUCT StartReq; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n")); |
| LinkDown(pAd, FALSE); |
| |
| StartParmFill(pAd, &StartReq, (CHAR *)pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen); |
| MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ, sizeof(MLME_START_REQ_STRUCT), &StartReq); |
| pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START; |
| } |
| |
| for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) |
| { |
| MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; |
| |
| if (pEntry->ValidAsCLI == FALSE) |
| continue; |
| |
| if (RTMP_TIME_AFTER(pAd->Mlme.Now32, pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME)) |
| MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr); |
| } |
| } |
| else // no INFRA nor ADHOC connection |
| { |
| |
| if (pAd->StaCfg.bScanReqIsFromWebUI && |
| RTMP_TIME_BEFORE(pAd->Mlme.Now32, pAd->StaCfg.LastScanTime + (30 * OS_HZ))) |
| goto SKIP_AUTO_SCAN_CONN; |
| else |
| pAd->StaCfg.bScanReqIsFromWebUI = FALSE; |
| |
| if ((pAd->StaCfg.bAutoReconnect == TRUE) |
| && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP) |
| && (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) |
| { |
| if ((pAd->ScanTab.BssNr==0) && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) |
| { |
| MLME_SCAN_REQ_STRUCT ScanReq; |
| |
| if (RTMP_TIME_AFTER(pAd->Mlme.Now32, pAd->StaCfg.LastScanTime + (10 * OS_HZ))) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid)); |
| ScanParmFill(pAd, &ScanReq, (PSTRING) pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen, BSS_ANY, SCAN_ACTIVE); |
| MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_SCAN_REQ, sizeof(MLME_SCAN_REQ_STRUCT), &ScanReq); |
| pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_OID_LIST_SCAN; |
| // Reset Missed scan number |
| pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; |
| } |
| else if (pAd->StaCfg.BssType == BSS_ADHOC) // Quit the forever scan when in a very clean room |
| MlmeAutoReconnectLastSSID(pAd); |
| } |
| else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) |
| { |
| if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) |
| { |
| MlmeAutoScan(pAd); |
| pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; |
| } |
| else |
| { |
| #ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier |
| if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) |
| { |
| if ((pAd->Mlme.OneSecPeriodicRound % 5) == 1) |
| MlmeAutoReconnectLastSSID(pAd); |
| } |
| else |
| #endif // CARRIER_DETECTION_SUPPORT // |
| MlmeAutoReconnectLastSSID(pAd); |
| } |
| } |
| } |
| } |
| |
| SKIP_AUTO_SCAN_CONN: |
| |
| #ifdef DOT11_N_SUPPORT |
| if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap !=0) && (pAd->MacTab.fAnyBASession == FALSE)) |
| { |
| pAd->MacTab.fAnyBASession = TRUE; |
| AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE, FALSE); |
| } |
| else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap ==0) && (pAd->MacTab.fAnyBASession == TRUE)) |
| { |
| pAd->MacTab.fAnyBASession = FALSE; |
| AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, FALSE, FALSE); |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| |
| #ifdef DOT11_N_SUPPORT |
| #ifdef DOT11N_DRAFT3 |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_SCAN_2040)) |
| TriEventCounterMaintenance(pAd); |
| #endif // DOT11N_DRAFT3 // |
| #endif // DOT11_N_SUPPORT // |
| |
| return; |
| } |
| |
| // Link down report |
| VOID LinkDownExec( |
| IN PVOID SystemSpecific1, |
| IN PVOID FunctionContext, |
| IN PVOID SystemSpecific2, |
| IN PVOID SystemSpecific3) |
| { |
| RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; |
| |
| if (pAd != NULL) |
| { |
| MLME_DISASSOC_REQ_STRUCT DisassocReq; |
| |
| if ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) && |
| (INFRA_ON(pAd))) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("LinkDownExec(): disassociate with current AP...\n")); |
| DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_DISASSOC_STA_LEAVING); |
| MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, |
| sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); |
| pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; |
| |
| pAd->IndicateMediaState = NdisMediaStateDisconnected; |
| RTMP_IndicateMediaState(pAd); |
| pAd->ExtraInfo = GENERAL_LINK_DOWN; |
| } |
| } |
| } |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeAutoScan( |
| IN PRTMP_ADAPTER pAd) |
| { |
| // check CntlMachine.CurrState to avoid collision with NDIS SetOID request |
| if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n")); |
| MlmeEnqueue(pAd, |
| MLME_CNTL_STATE_MACHINE, |
| OID_802_11_BSSID_LIST_SCAN, |
| pAd->MlmeAux.AutoReconnectSsidLen, |
| pAd->MlmeAux.AutoReconnectSsid); |
| RTMP_MLME_HANDLER(pAd); |
| } |
| } |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeAutoReconnectLastSSID( |
| IN PRTMP_ADAPTER pAd) |
| { |
| if (pAd->StaCfg.bAutoConnectByBssid) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_BSSID setting - %02X:%02X:%02X:%02X:%02X:%02X\n", |
| pAd->MlmeAux.Bssid[0], |
| pAd->MlmeAux.Bssid[1], |
| pAd->MlmeAux.Bssid[2], |
| pAd->MlmeAux.Bssid[3], |
| pAd->MlmeAux.Bssid[4], |
| pAd->MlmeAux.Bssid[5])); |
| |
| pAd->MlmeAux.Channel = pAd->CommonCfg.Channel; |
| MlmeEnqueue(pAd, |
| MLME_CNTL_STATE_MACHINE, |
| OID_802_11_BSSID, |
| MAC_ADDR_LEN, |
| pAd->MlmeAux.Bssid); |
| |
| pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; |
| |
| RTMP_MLME_HANDLER(pAd); |
| } |
| // check CntlMachine.CurrState to avoid collision with NDIS SetOID request |
| else if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && |
| (MlmeValidateSSID(pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) |
| { |
| NDIS_802_11_SSID OidSsid; |
| OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen; |
| NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen); |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n", pAd->MlmeAux.AutoReconnectSsid, pAd->MlmeAux.AutoReconnectSsidLen)); |
| MlmeEnqueue(pAd, |
| MLME_CNTL_STATE_MACHINE, |
| OID_802_11_SSID, |
| sizeof(NDIS_802_11_SSID), |
| &OidSsid); |
| RTMP_MLME_HANDLER(pAd); |
| } |
| } |
| |
| |
| /* |
| ========================================================================== |
| Description: |
| This routine checks if there're other APs out there capable for |
| roaming. Caller should call this routine only when Link up in INFRA mode |
| and channel quality is below CQI_GOOD_THRESHOLD. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Output: |
| ========================================================================== |
| */ |
| VOID MlmeCheckForRoaming( |
| IN PRTMP_ADAPTER pAd, |
| IN ULONG Now32) |
| { |
| USHORT i; |
| BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; |
| BSS_ENTRY *pBss; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n")); |
| // put all roaming candidates into RoamTab, and sort in RSSI order |
| BssTableInit(pRoamTab); |
| for (i = 0; i < pAd->ScanTab.BssNr; i++) |
| { |
| pBss = &pAd->ScanTab.BssEntry[i]; |
| |
| if ((pBss->LastBeaconRxTime + pAd->StaCfg.BeaconLostTime) < Now32) |
| continue; // AP disappear |
| if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING) |
| continue; // RSSI too weak. forget it. |
| if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) |
| continue; // skip current AP |
| if (pBss->Rssi < (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA)) |
| continue; // only AP with stronger RSSI is eligible for roaming |
| |
| // AP passing all above rules is put into roaming candidate table |
| NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); |
| pRoamTab->BssNr += 1; |
| } |
| |
| if (pRoamTab->BssNr > 0) |
| { |
| // check CntlMachine.CurrState to avoid collision with NDIS SetOID request |
| if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) |
| { |
| pAd->RalinkCounters.PoorCQIRoamingCount ++; |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); |
| RTMP_MLME_HANDLER(pAd); |
| } |
| } |
| DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForRoaming(# of candidate= %d)\n",pRoamTab->BssNr)); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| This routine checks if there're other APs out there capable for |
| roaming. Caller should call this routine only when link up in INFRA mode |
| and channel quality is below CQI_GOOD_THRESHOLD. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| Output: |
| ========================================================================== |
| */ |
| BOOLEAN MlmeCheckForFastRoaming( |
| IN PRTMP_ADAPTER pAd) |
| { |
| USHORT i; |
| BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab; |
| BSS_ENTRY *pBss; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n")); |
| // put all roaming candidates into RoamTab, and sort in RSSI order |
| BssTableInit(pRoamTab); |
| for (i = 0; i < pAd->ScanTab.BssNr; i++) |
| { |
| pBss = &pAd->ScanTab.BssEntry[i]; |
| |
| if ((pBss->Rssi <= -50) && (pBss->Channel == pAd->CommonCfg.Channel)) |
| continue; // RSSI too weak. forget it. |
| if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid)) |
| continue; // skip current AP |
| if (!SSID_EQUAL(pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid, pAd->CommonCfg.SsidLen)) |
| continue; // skip different SSID |
| if (pBss->Rssi < (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA)) |
| continue; // skip AP without better RSSI |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("LastRssi0 = %d, pBss->Rssi = %d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), pBss->Rssi)); |
| // AP passing all above rules is put into roaming candidate table |
| NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss, sizeof(BSS_ENTRY)); |
| pRoamTab->BssNr += 1; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr)); |
| if (pRoamTab->BssNr > 0) |
| { |
| // check CntlMachine.CurrState to avoid collision with NDIS SetOID request |
| if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) |
| { |
| pAd->RalinkCounters.PoorCQIRoamingCount ++; |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming attempt #%ld\n", pAd->RalinkCounters.PoorCQIRoamingCount)); |
| MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, MT2_MLME_ROAMING_REQ, 0, NULL); |
| RTMP_MLME_HANDLER(pAd); |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| VOID MlmeSetTxRate( |
| IN PRTMP_ADAPTER pAd, |
| IN PMAC_TABLE_ENTRY pEntry, |
| IN PRTMP_TX_RATE_SWITCH pTxRate) |
| { |
| UCHAR MaxMode = MODE_OFDM; |
| |
| #ifdef DOT11_N_SUPPORT |
| MaxMode = MODE_HTGREENFIELD; |
| |
| if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) |
| pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; |
| else |
| #endif // DOT11_N_SUPPORT // |
| pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; |
| |
| if (pTxRate->CurrMCS < MCS_AUTO) |
| pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS; |
| |
| if (pAd->StaCfg.HTPhyMode.field.MCS > 7) |
| pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE; |
| |
| if (ADHOC_ON(pAd)) |
| { |
| // If peer adhoc is b-only mode, we can't send 11g rate. |
| pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; |
| pEntry->HTPhyMode.field.STBC = STBC_NONE; |
| |
| // |
| // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary |
| // |
| pEntry->HTPhyMode.field.MODE = pTxRate->Mode; |
| pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; |
| pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; |
| |
| // Patch speed error in status page |
| pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE; |
| } |
| else |
| { |
| if (pTxRate->Mode <= MaxMode) |
| pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode; |
| |
| #ifdef DOT11_N_SUPPORT |
| if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) |
| pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; |
| else |
| #endif // DOT11_N_SUPPORT // |
| pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; |
| |
| #ifdef DOT11_N_SUPPORT |
| // Reexam each bandwidth's SGI support. |
| if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) |
| { |
| if ((pEntry->HTPhyMode.field.BW == BW_20) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI20_CAPABLE))) |
| pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; |
| if ((pEntry->HTPhyMode.field.BW == BW_40) && (!CLIENT_STATUS_TEST_FLAG(pEntry, fCLIENT_STATUS_SGI40_CAPABLE))) |
| pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; |
| } |
| |
| // Turn RTS/CTS rate to 6Mbps. |
| if ((pEntry->HTPhyMode.field.MCS == 0) && (pAd->StaCfg.HTPhyMode.field.MCS != 0)) |
| { |
| pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; |
| if (pAd->MacTab.fAnyBASession) |
| { |
| AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); |
| } |
| else |
| { |
| AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); |
| } |
| } |
| else if ((pEntry->HTPhyMode.field.MCS == 8) && (pAd->StaCfg.HTPhyMode.field.MCS != 8)) |
| { |
| pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; |
| if (pAd->MacTab.fAnyBASession) |
| { |
| AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); |
| } |
| else |
| { |
| AsicUpdateProtect(pAd, pAd->MlmeAux.AddHtInfo.AddHtInfo2.OperaionMode, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); |
| } |
| } |
| else if ((pEntry->HTPhyMode.field.MCS != 0) && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) |
| { |
| AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); |
| |
| } |
| else if ((pEntry->HTPhyMode.field.MCS != 8) && (pAd->StaCfg.HTPhyMode.field.MCS == 8)) |
| { |
| AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT, TRUE, (BOOLEAN)pAd->MlmeAux.AddHtInfo.AddHtInfo2.NonGfPresent); |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC; |
| pEntry->HTPhyMode.field.ShortGI = pAd->StaCfg.HTPhyMode.field.ShortGI; |
| pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS; |
| pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE; |
| #ifdef DOT11_N_SUPPORT |
| if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && |
| pAd->WIFItestbed.bGreenField) |
| pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; |
| #endif // DOT11_N_SUPPORT // |
| } |
| |
| pAd->LastTxRate = (USHORT)(pEntry->HTPhyMode.word); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| This routine calculates the acumulated TxPER of eaxh TxRate. And |
| according to the calculation result, change CommonCfg.TxRate which |
| is the stable TX Rate we expect the Radio situation could sustained. |
| |
| CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate} |
| Output: |
| CommonCfg.TxRate - |
| |
| IRQL = DISPATCH_LEVEL |
| |
| NOTE: |
| call this routine every second |
| ========================================================================== |
| */ |
| VOID MlmeDynamicTxRateSwitching( |
| IN PRTMP_ADAPTER pAd) |
| { |
| UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx; |
| ULONG i, AccuTxTotalCnt = 0, TxTotalCnt; |
| ULONG TxErrorRatio = 0; |
| BOOLEAN bTxRateChanged = FALSE, bUpgradeQuality = FALSE; |
| PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; |
| PUCHAR pTable; |
| UCHAR TableSize = 0; |
| UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; |
| CHAR Rssi, RssiOffset = 0; |
| TX_STA_CNT1_STRUC StaTx1; |
| TX_STA_CNT0_STRUC TxStaCnt0; |
| ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; |
| MAC_TABLE_ENTRY *pEntry; |
| RSSI_SAMPLE *pRssi = &pAd->StaCfg.RssiSample; |
| |
| #ifdef RALINK_ATE |
| if (ATE_ON(pAd)) |
| { |
| return; |
| } |
| #endif // RALINK_ATE // |
| |
| // |
| // walk through MAC table, see if need to change AP's TX rate toward each entry |
| // |
| for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) |
| { |
| pEntry = &pAd->MacTab.Content[i]; |
| |
| // check if this entry need to switch rate automatically |
| if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) |
| continue; |
| |
| if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) |
| { |
| Rssi = RTMPMaxRssi(pAd, |
| pRssi->AvgRssi0, |
| pRssi->AvgRssi1, |
| pRssi->AvgRssi2); |
| |
| // Update statistic counter |
| RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); |
| RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); |
| pAd->bUpdateBcnCntDone = TRUE; |
| TxRetransmit = StaTx1.field.TxRetransmit; |
| TxSuccess = StaTx1.field.TxSuccess; |
| TxFailCount = TxStaCnt0.field.TxFailCount; |
| TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; |
| |
| pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; |
| pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; |
| pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; |
| pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; |
| pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; |
| pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; |
| |
| // if no traffic in the past 1-sec period, don't change TX rate, |
| // but clear all bad history. because the bad history may affect the next |
| // Chariot throughput test |
| AccuTxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + |
| pAd->RalinkCounters.OneSecTxRetryOkCount + |
| pAd->RalinkCounters.OneSecTxFailCount; |
| |
| if (TxTotalCnt) |
| TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; |
| } |
| else |
| { |
| if (INFRA_ON(pAd) && (i == 1)) |
| Rssi = RTMPMaxRssi(pAd, |
| pRssi->AvgRssi0, |
| pRssi->AvgRssi1, |
| pRssi->AvgRssi2); |
| else |
| Rssi = RTMPMaxRssi(pAd, |
| pEntry->RssiSample.AvgRssi0, |
| pEntry->RssiSample.AvgRssi1, |
| pEntry->RssiSample.AvgRssi2); |
| |
| TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + |
| pEntry->OneSecTxRetryOkCount + |
| pEntry->OneSecTxFailCount; |
| |
| if (TxTotalCnt) |
| TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; |
| } |
| |
| if (TxTotalCnt) |
| { |
| /* |
| Three AdHoc connections can not work normally if one AdHoc connection is disappeared from a heavy traffic environment generated by ping tool |
| We force to set LongRtyLimit and ShortRtyLimit to 0 to stop retransmitting packet, after a while, resoring original settings |
| */ |
| if (TxErrorRatio == 100) |
| { |
| TX_RTY_CFG_STRUC TxRtyCfg,TxRtyCfgtmp; |
| ULONG Index; |
| ULONG MACValue; |
| |
| RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word); |
| TxRtyCfgtmp.word = TxRtyCfg.word; |
| TxRtyCfg.field.LongRtyLimit = 0x0; |
| TxRtyCfg.field.ShortRtyLimit = 0x0; |
| RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word); |
| |
| RTMPusecDelay(1); |
| |
| Index = 0; |
| MACValue = 0; |
| do |
| { |
| RTMP_IO_READ32(pAd, TXRXQ_PCNT, &MACValue); |
| if ((MACValue & 0xffffff) == 0) |
| break; |
| Index++; |
| RTMPusecDelay(1000); |
| }while((Index < 330)&&(!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))); |
| |
| RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word); |
| TxRtyCfg.field.LongRtyLimit = TxRtyCfgtmp.field.LongRtyLimit; |
| TxRtyCfg.field.ShortRtyLimit = TxRtyCfgtmp.field.ShortRtyLimit; |
| RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word); |
| } |
| } |
| |
| CurrRateIdx = pEntry->CurrTxRateIndex; |
| |
| MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); |
| |
| if (CurrRateIdx >= TableSize) |
| { |
| CurrRateIdx = TableSize - 1; |
| } |
| |
| // When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. |
| // So need to sync here. |
| pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; |
| if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS) |
| //&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) |
| ) |
| { |
| |
| // Need to sync Real Tx rate and our record. |
| // Then return for next DRS. |
| pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(InitTxRateIdx+1)*5]; |
| pEntry->CurrTxRateIndex = InitTxRateIdx; |
| MlmeSetTxRate(pAd, pEntry, pCurrTxRate); |
| |
| // reset all OneSecTx counters |
| RESET_ONE_SEC_TX_CNT(pEntry); |
| continue; |
| } |
| |
| // decide the next upgrade rate and downgrade rate, if any |
| if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) |
| { |
| UpRateIdx = CurrRateIdx + 1; |
| DownRateIdx = CurrRateIdx -1; |
| } |
| else if (CurrRateIdx == 0) |
| { |
| UpRateIdx = CurrRateIdx + 1; |
| DownRateIdx = CurrRateIdx; |
| } |
| else if (CurrRateIdx == (TableSize - 1)) |
| { |
| UpRateIdx = CurrRateIdx; |
| DownRateIdx = CurrRateIdx - 1; |
| } |
| |
| pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; |
| |
| #ifdef DOT11_N_SUPPORT |
| if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) |
| { |
| TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); |
| TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); |
| } |
| else |
| #endif // DOT11_N_SUPPORT // |
| { |
| TrainUp = pCurrTxRate->TrainUp; |
| TrainDown = pCurrTxRate->TrainDown; |
| } |
| |
| //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; |
| |
| // |
| // Keep the last time TxRateChangeAction status. |
| // |
| pEntry->LastTimeTxRateChangeAction = pEntry->LastSecTxRateChangeAction; |
| |
| |
| |
| // |
| // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI |
| // (criteria copied from RT2500 for Netopia case) |
| // |
| if (TxTotalCnt <= 15) |
| { |
| CHAR idx = 0; |
| UCHAR TxRateIdx; |
| UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 = 0, MCS5 =0, MCS6 = 0, MCS7 = 0; |
| UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; |
| UCHAR MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; // 3*3 |
| |
| // check the existence and index of each needed MCS |
| while (idx < pTable[0]) |
| { |
| pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(idx+1)*5]; |
| |
| if (pCurrTxRate->CurrMCS == MCS_0) |
| { |
| MCS0 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_1) |
| { |
| MCS1 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_2) |
| { |
| MCS2 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_3) |
| { |
| MCS3 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_4) |
| { |
| MCS4 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_5) |
| { |
| MCS5 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_6) |
| { |
| MCS6 = idx; |
| } |
| //else if (pCurrTxRate->CurrMCS == MCS_7) |
| else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800)) // prevent the highest MCS using short GI when 1T and low throughput |
| { |
| MCS7 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_12) |
| { |
| MCS12 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_13) |
| { |
| MCS13 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_14) |
| { |
| MCS14 = idx; |
| } |
| //else if ((pCurrTxRate->CurrMCS == MCS_15)/* && (pCurrTxRate->ShortGI == GI_800)*/) //we hope to use ShortGI as initial rate |
| else if ((pCurrTxRate->CurrMCS == MCS_15) && (pCurrTxRate->ShortGI == GI_800)) //we hope to use ShortGI as initial rate, however Atheros's chip has bugs when short GI |
| { |
| MCS15 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3 |
| { |
| MCS20 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_21) |
| { |
| MCS21 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_22) |
| { |
| MCS22 = idx; |
| } |
| else if (pCurrTxRate->CurrMCS == MCS_23) |
| { |
| MCS23 = idx; |
| } |
| idx ++; |
| } |
| |
| if (pAd->LatchRfRegs.Channel <= 14) |
| { |
| if (pAd->NicConfig2.field.ExternalLNAForG) |
| { |
| RssiOffset = 2; |
| } |
| else |
| { |
| RssiOffset = 5; |
| } |
| } |
| else |
| { |
| if (pAd->NicConfig2.field.ExternalLNAForA) |
| { |
| RssiOffset = 5; |
| } |
| else |
| { |
| RssiOffset = 8; |
| } |
| } |
| #ifdef DOT11_N_SUPPORT |
| /*if (MCS15)*/ |
| if ((pTable == RateSwitchTable11BGN3S) || |
| (pTable == RateSwitchTable11N3S) || |
| (pTable == RateSwitchTable)) |
| {// N mode with 3 stream // 3*3 |
| if (MCS23 && (Rssi >= -70)) |
| TxRateIdx = MCS23; |
| else if (MCS22 && (Rssi >= -72)) |
| TxRateIdx = MCS22; |
| else if (MCS21 && (Rssi >= -76)) |
| TxRateIdx = MCS21; |
| else if (MCS20 && (Rssi >= -78)) |
| TxRateIdx = MCS20; |
| else if (MCS4 && (Rssi >= -82)) |
| TxRateIdx = MCS4; |
| else if (MCS3 && (Rssi >= -84)) |
| TxRateIdx = MCS3; |
| else if (MCS2 && (Rssi >= -86)) |
| TxRateIdx = MCS2; |
| else if (MCS1 && (Rssi >= -88)) |
| TxRateIdx = MCS1; |
| else |
| TxRateIdx = MCS0; |
| } |
| // else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) |
| else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand)) // 3*3 |
| {// N mode with 2 stream |
| if (MCS15 && (Rssi >= (-70+RssiOffset))) |
| TxRateIdx = MCS15; |
| else if (MCS14 && (Rssi >= (-72+RssiOffset))) |
| TxRateIdx = MCS14; |
| else if (MCS13 && (Rssi >= (-76+RssiOffset))) |
| TxRateIdx = MCS13; |
| else if (MCS12 && (Rssi >= (-78+RssiOffset))) |
| TxRateIdx = MCS12; |
| else if (MCS4 && (Rssi >= (-82+RssiOffset))) |
| TxRateIdx = MCS4; |
| else if (MCS3 && (Rssi >= (-84+RssiOffset))) |
| TxRateIdx = MCS3; |
| else if (MCS2 && (Rssi >= (-86+RssiOffset))) |
| TxRateIdx = MCS2; |
| else if (MCS1 && (Rssi >= (-88+RssiOffset))) |
| TxRateIdx = MCS1; |
| else |
| TxRateIdx = MCS0; |
| } |
| else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) |
| {// N mode with 1 stream |
| if (MCS7 && (Rssi > (-72+RssiOffset))) |
| TxRateIdx = MCS7; |
| else if (MCS6 && (Rssi > (-74+RssiOffset))) |
| TxRateIdx = MCS6; |
| else if (MCS5 && (Rssi > (-77+RssiOffset))) |
| TxRateIdx = MCS5; |
| else if (MCS4 && (Rssi > (-79+RssiOffset))) |
| TxRateIdx = MCS4; |
| else if (MCS3 && (Rssi > (-81+RssiOffset))) |
| TxRateIdx = MCS3; |
| else if (MCS2 && (Rssi > (-83+RssiOffset))) |
| TxRateIdx = MCS2; |
| else if (MCS1 && (Rssi > (-86+RssiOffset))) |
| TxRateIdx = MCS1; |
| else |
| TxRateIdx = MCS0; |
| } |
| else |
| #endif // DOT11_N_SUPPORT // |
| {// Legacy mode |
| if (MCS7 && (Rssi > -70)) |
| TxRateIdx = MCS7; |
| else if (MCS6 && (Rssi > -74)) |
| TxRateIdx = MCS6; |
| else if (MCS5 && (Rssi > -78)) |
| TxRateIdx = MCS5; |
| else if (MCS4 && (Rssi > -82)) |
| TxRateIdx = MCS4; |
| else if (MCS4 == 0) // for B-only mode |
| TxRateIdx = MCS3; |
| else if (MCS3 && (Rssi > -85)) |
| TxRateIdx = MCS3; |
| else if (MCS2 && (Rssi > -87)) |
| TxRateIdx = MCS2; |
| else if (MCS1 && (Rssi > -90)) |
| TxRateIdx = MCS1; |
| else |
| TxRateIdx = MCS0; |
| } |
| |
| // if (TxRateIdx != pAd->CommonCfg.TxRateIndex) |
| { |
| pEntry->CurrTxRateIndex = TxRateIdx; |
| pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; |
| MlmeSetTxRate(pAd, pEntry, pNextTxRate); |
| } |
| |
| NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); |
| NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); |
| pEntry->fLastSecAccordingRSSI = TRUE; |
| // reset all OneSecTx counters |
| RESET_ONE_SEC_TX_CNT(pEntry); |
| |
| continue; |
| } |
| |
| if (pEntry->fLastSecAccordingRSSI == TRUE) |
| { |
| pEntry->fLastSecAccordingRSSI = FALSE; |
| pEntry->LastSecTxRateChangeAction = 0; |
| // reset all OneSecTx counters |
| RESET_ONE_SEC_TX_CNT(pEntry); |
| |
| continue; |
| } |
| |
| do |
| { |
| BOOLEAN bTrainUpDown = FALSE; |
| |
| pEntry->CurrTxRateStableTime ++; |
| |
| // downgrade TX quality if PER >= Rate-Down threshold |
| if (TxErrorRatio >= TrainDown) |
| { |
| bTrainUpDown = TRUE; |
| pEntry->TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; |
| } |
| // upgrade TX quality if PER <= Rate-Up threshold |
| else if (TxErrorRatio <= TrainUp) |
| { |
| bTrainUpDown = TRUE; |
| bUpgradeQuality = TRUE; |
| if (pEntry->TxQuality[CurrRateIdx]) |
| pEntry->TxQuality[CurrRateIdx] --; // quality very good in CurrRate |
| |
| if (pEntry->TxRateUpPenalty) |
| pEntry->TxRateUpPenalty --; |
| else if (pEntry->TxQuality[UpRateIdx]) |
| pEntry->TxQuality[UpRateIdx] --; // may improve next UP rate's quality |
| } |
| |
| pEntry->PER[CurrRateIdx] = (UCHAR)TxErrorRatio; |
| |
| if (bTrainUpDown) |
| { |
| // perform DRS - consider TxRate Down first, then rate up. |
| if ((CurrRateIdx != DownRateIdx) && (pEntry->TxQuality[CurrRateIdx] >= DRS_TX_QUALITY_WORST_BOUND)) |
| { |
| pEntry->CurrTxRateIndex = DownRateIdx; |
| } |
| else if ((CurrRateIdx != UpRateIdx) && (pEntry->TxQuality[UpRateIdx] <= 0)) |
| { |
| pEntry->CurrTxRateIndex = UpRateIdx; |
| } |
| } |
| } while (FALSE); |
| |
| // if rate-up happen, clear all bad history of all TX rates |
| if (pEntry->CurrTxRateIndex > CurrRateIdx) |
| { |
| pEntry->CurrTxRateStableTime = 0; |
| pEntry->TxRateUpPenalty = 0; |
| pEntry->LastSecTxRateChangeAction = 1; // rate UP |
| NdisZeroMemory(pEntry->TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); |
| NdisZeroMemory(pEntry->PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); |
| |
| // |
| // For TxRate fast train up |
| // |
| if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) |
| { |
| RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); |
| |
| pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; |
| } |
| bTxRateChanged = TRUE; |
| } |
| // if rate-down happen, only clear DownRate's bad history |
| else if (pEntry->CurrTxRateIndex < CurrRateIdx) |
| { |
| pEntry->CurrTxRateStableTime = 0; |
| pEntry->TxRateUpPenalty = 0; // no penalty |
| pEntry->LastSecTxRateChangeAction = 2; // rate DOWN |
| pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0; |
| pEntry->PER[pEntry->CurrTxRateIndex] = 0; |
| |
| // |
| // For TxRate fast train down |
| // |
| if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) |
| { |
| RTMPSetTimer(&pAd->StaCfg.StaQuickResponeForRateUpTimer, 100); |
| |
| pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = TRUE; |
| } |
| bTxRateChanged = TRUE; |
| } |
| else |
| { |
| pEntry->LastSecTxRateChangeAction = 0; // rate no change |
| bTxRateChanged = FALSE; |
| } |
| |
| pEntry->LastTxOkCount = TxSuccess; |
| |
| { |
| UCHAR tmpTxRate; |
| |
| // to fix tcp ack issue |
| if (!bTxRateChanged && (pAd->RalinkCounters.OneSecReceivedByteCount > (pAd->RalinkCounters.OneSecTransmittedByteCount * 5))) |
| { |
| tmpTxRate = DownRateIdx; |
| DBGPRINT_RAW(RT_DEBUG_TRACE,("DRS: Rx(%d) is 5 times larger than Tx(%d), use low rate (curr=%d, tmp=%d)\n", |
| pAd->RalinkCounters.OneSecReceivedByteCount, pAd->RalinkCounters.OneSecTransmittedByteCount, pEntry->CurrTxRateIndex, tmpTxRate)); |
| } |
| else |
| { |
| tmpTxRate = pEntry->CurrTxRateIndex; |
| } |
| |
| pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(tmpTxRate+1)*5]; |
| if (bTxRateChanged && pNextTxRate) |
| { |
| MlmeSetTxRate(pAd, pEntry, pNextTxRate); |
| } |
| } |
| // reset all OneSecTx counters |
| RESET_ONE_SEC_TX_CNT(pEntry); |
| } |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Station side, Auto TxRate faster train up timer call back function. |
| |
| Arguments: |
| SystemSpecific1 - Not used. |
| FunctionContext - Pointer to our Adapter context. |
| SystemSpecific2 - Not used. |
| SystemSpecific3 - Not used. |
| |
| Return Value: |
| None |
| |
| ======================================================================== |
| */ |
| VOID StaQuickResponeForRateUpExec( |
| IN PVOID SystemSpecific1, |
| IN PVOID FunctionContext, |
| IN PVOID SystemSpecific2, |
| IN PVOID SystemSpecific3) |
| { |
| PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)FunctionContext; |
| UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0; |
| ULONG TxTotalCnt; |
| ULONG TxErrorRatio = 0; |
| BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE; |
| PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL; |
| PUCHAR pTable; |
| UCHAR TableSize = 0; |
| UCHAR InitTxRateIdx = 0, TrainUp, TrainDown; |
| TX_STA_CNT1_STRUC StaTx1; |
| TX_STA_CNT0_STRUC TxStaCnt0; |
| CHAR Rssi, ratio; |
| ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0; |
| MAC_TABLE_ENTRY *pEntry; |
| ULONG i; |
| |
| pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE; |
| |
| // |
| // walk through MAC table, see if need to change AP's TX rate toward each entry |
| // |
| for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) |
| { |
| pEntry = &pAd->MacTab.Content[i]; |
| |
| // check if this entry need to switch rate automatically |
| if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE) |
| continue; |
| |
| if (INFRA_ON(pAd) && (i == 1)) |
| Rssi = RTMPMaxRssi(pAd, |
| pAd->StaCfg.RssiSample.AvgRssi0, |
| pAd->StaCfg.RssiSample.AvgRssi1, |
| pAd->StaCfg.RssiSample.AvgRssi2); |
| else |
| Rssi = RTMPMaxRssi(pAd, |
| pEntry->RssiSample.AvgRssi0, |
| pEntry->RssiSample.AvgRssi1, |
| pEntry->RssiSample.AvgRssi2); |
| |
| CurrRateIdx = pAd->CommonCfg.TxRateIndex; |
| |
| MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize, &InitTxRateIdx); |
| |
| // decide the next upgrade rate and downgrade rate, if any |
| if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) |
| { |
| UpRateIdx = CurrRateIdx + 1; |
| DownRateIdx = CurrRateIdx -1; |
| } |
| else if (CurrRateIdx == 0) |
| { |
| UpRateIdx = CurrRateIdx + 1; |
| DownRateIdx = CurrRateIdx; |
| } |
| else if (CurrRateIdx == (TableSize - 1)) |
| { |
| UpRateIdx = CurrRateIdx; |
| DownRateIdx = CurrRateIdx - 1; |
| } |
| |
| pCurrTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(CurrRateIdx+1)*5]; |
| |
| #ifdef DOT11_N_SUPPORT |
| if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) |
| { |
| TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); |
| TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); |
| } |
| else |
| #endif // DOT11_N_SUPPORT // |
| { |
| TrainUp = pCurrTxRate->TrainUp; |
| TrainDown = pCurrTxRate->TrainDown; |
| } |
| |
| if (pAd->MacTab.Size == 1) |
| { |
| // Update statistic counter |
| RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word); |
| RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word); |
| |
| TxRetransmit = StaTx1.field.TxRetransmit; |
| TxSuccess = StaTx1.field.TxSuccess; |
| TxFailCount = TxStaCnt0.field.TxFailCount; |
| TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount; |
| |
| pAd->RalinkCounters.OneSecTxRetryOkCount += StaTx1.field.TxRetransmit; |
| pAd->RalinkCounters.OneSecTxNoRetryOkCount += StaTx1.field.TxSuccess; |
| pAd->RalinkCounters.OneSecTxFailCount += TxStaCnt0.field.TxFailCount; |
| pAd->WlanCounters.TransmittedFragmentCount.u.LowPart += StaTx1.field.TxSuccess; |
| pAd->WlanCounters.RetryCount.u.LowPart += StaTx1.field.TxRetransmit; |
| pAd->WlanCounters.FailedCount.u.LowPart += TxStaCnt0.field.TxFailCount; |
| |
| if (TxTotalCnt) |
| TxErrorRatio = ((TxRetransmit + TxFailCount) * 100) / TxTotalCnt; |
| } |
| else |
| { |
| TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + |
| pEntry->OneSecTxRetryOkCount + |
| pEntry->OneSecTxFailCount; |
| |
| if (TxTotalCnt) |
| TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; |
| } |
| |
| |
| // |
| // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI |
| // (criteria copied from RT2500 for Netopia case) |
| // |
| if (TxTotalCnt <= 12) |
| { |
| NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); |
| NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); |
| |
| if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) |
| { |
| pAd->CommonCfg.TxRateIndex = DownRateIdx; |
| pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; |
| } |
| else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) |
| { |
| pAd->CommonCfg.TxRateIndex = UpRateIdx; |
| } |
| |
| DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: TxTotalCnt <= 15, train back to original rate \n")); |
| return; |
| } |
| |
| do |
| { |
| ULONG OneSecTxNoRetryOKRationCount; |
| |
| if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0) |
| ratio = 5; |
| else |
| ratio = 4; |
| |
| // downgrade TX quality if PER >= Rate-Down threshold |
| if (TxErrorRatio >= TrainDown) |
| { |
| pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; |
| } |
| |
| pAd->DrsCounters.PER[CurrRateIdx] = (UCHAR)TxErrorRatio; |
| |
| OneSecTxNoRetryOKRationCount = (TxSuccess * ratio); |
| |
| // perform DRS - consider TxRate Down first, then rate up. |
| if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1) && (CurrRateIdx != DownRateIdx)) |
| { |
| if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) |
| { |
| pAd->CommonCfg.TxRateIndex = DownRateIdx; |
| pAd->DrsCounters.TxQuality[CurrRateIdx] = DRS_TX_QUALITY_WORST_BOUND; |
| |
| } |
| |
| } |
| else if ((pAd->DrsCounters.LastSecTxRateChangeAction == 2) && (CurrRateIdx != UpRateIdx)) |
| { |
| if ((TxErrorRatio >= 50) || (TxErrorRatio >= TrainDown)) |
| { |
| |
| } |
| else if ((pAd->DrsCounters.LastTxOkCount + 2) >= OneSecTxNoRetryOKRationCount) |
| { |
| pAd->CommonCfg.TxRateIndex = UpRateIdx; |
| } |
| } |
| }while (FALSE); |
| |
| // if rate-up happen, clear all bad history of all TX rates |
| if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) |
| { |
| pAd->DrsCounters.TxRateUpPenalty = 0; |
| NdisZeroMemory(pAd->DrsCounters.TxQuality, sizeof(USHORT) * MAX_STEP_OF_TX_RATE_SWITCH); |
| NdisZeroMemory(pAd->DrsCounters.PER, sizeof(UCHAR) * MAX_STEP_OF_TX_RATE_SWITCH); |
| bTxRateChanged = TRUE; |
| } |
| // if rate-down happen, only clear DownRate's bad history |
| else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) |
| { |
| DBGPRINT_RAW(RT_DEBUG_TRACE,("QuickDRS: --TX rate from %d to %d \n", CurrRateIdx, pAd->CommonCfg.TxRateIndex)); |
| |
| pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty |
| pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] = 0; |
| pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0; |
| bTxRateChanged = TRUE; |
| } |
| else |
| { |
| bTxRateChanged = FALSE; |
| } |
| |
| pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pAd->CommonCfg.TxRateIndex+1)*5]; |
| if (bTxRateChanged && pNextTxRate) |
| { |
| MlmeSetTxRate(pAd, pEntry, pNextTxRate); |
| } |
| } |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| This routine is executed periodically inside MlmePeriodicExec() after |
| association with an AP. |
| It checks if StaCfg.Psm is consistent with user policy (recorded in |
| StaCfg.WindowsPowerMode). If not, enforce user policy. However, |
| there're some conditions to consider: |
| 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all |
| the time when Mibss==TRUE |
| 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE |
| if outgoing traffic available in TxRing or MgmtRing. |
| Output: |
| 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID MlmeCheckPsmChange( |
| IN PRTMP_ADAPTER pAd, |
| IN ULONG Now32) |
| { |
| ULONG PowerMode; |
| |
| // condition - |
| // 1. Psm maybe ON only happen in INFRASTRUCTURE mode |
| // 2. user wants either MAX_PSP or FAST_PSP |
| // 3. but current psm is not in PWR_SAVE |
| // 4. CNTL state machine is not doing SCANning |
| // 5. no TX SUCCESS event for the past 1-sec period |
| PowerMode = pAd->StaCfg.WindowsPowerMode; |
| |
| if (INFRA_ON(pAd) && |
| (PowerMode != Ndis802_11PowerModeCAM) && |
| (pAd->StaCfg.Psm == PWR_ACTIVE) && |
| // (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) |
| (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)&& |
| RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP) |
| /*&& |
| (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && |
| (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)*/) |
| { |
| NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime); |
| pAd->RalinkCounters.RxCountSinceLastNULL = 0; |
| RTMP_SET_PSM_BIT(pAd, PWR_SAVE); |
| if (!(pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) |
| { |
| RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE); |
| } |
| else |
| { |
| RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); |
| } |
| } |
| } |
| |
| // IRQL = PASSIVE_LEVEL |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeSetPsmBit( |
| IN PRTMP_ADAPTER pAd, |
| IN USHORT psm) |
| { |
| AUTO_RSP_CFG_STRUC csr4; |
| |
| pAd->StaCfg.Psm = psm; |
| RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); |
| csr4.field.AckCtsPsmBit = (psm == PWR_SAVE)? 1:0; |
| RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); |
| DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm)); |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| /* |
| ========================================================================== |
| Description: |
| This routine calculates TxPER, RxPER of the past N-sec period. And |
| according to the calculation result, ChannelQuality is calculated here |
| to decide if current AP is still doing the job. |
| |
| If ChannelQuality is not good, a ROAMing attempt may be tried later. |
| Output: |
| StaCfg.ChannelQuality - 0..100 |
| |
| IRQL = DISPATCH_LEVEL |
| |
| NOTE: This routine decide channle quality based on RX CRC error ratio. |
| Caller should make sure a function call to NICUpdateRawCounters(pAd) |
| is performed right before this routine, so that this routine can decide |
| channel quality based on the most up-to-date information |
| ========================================================================== |
| */ |
| VOID MlmeCalculateChannelQuality( |
| IN PRTMP_ADAPTER pAd, |
| IN PMAC_TABLE_ENTRY pMacEntry, |
| IN ULONG Now32) |
| { |
| ULONG TxOkCnt, TxCnt, TxPER, TxPRR; |
| ULONG RxCnt, RxPER; |
| UCHAR NorRssi; |
| CHAR MaxRssi; |
| RSSI_SAMPLE *pRssiSample = NULL; |
| UINT32 OneSecTxNoRetryOkCount = 0; |
| UINT32 OneSecTxRetryOkCount = 0; |
| UINT32 OneSecTxFailCount = 0; |
| UINT32 OneSecRxOkCnt = 0; |
| UINT32 OneSecRxFcsErrCnt = 0; |
| ULONG ChannelQuality = 0; // 0..100, Channel Quality Indication for Roaming |
| #ifdef CONFIG_STA_SUPPORT |
| ULONG BeaconLostTime = pAd->StaCfg.BeaconLostTime; |
| #endif // CONFIG_STA_SUPPORT // |
| |
| #ifdef CONFIG_STA_SUPPORT |
| #ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier |
| // longer beacon lost time when carrier detection enabled |
| if (pAd->CommonCfg.CarrierDetect.Enable == TRUE) |
| { |
| BeaconLostTime = pAd->StaCfg.BeaconLostTime + (pAd->StaCfg.BeaconLostTime/2); |
| } |
| #endif // CARRIER_DETECTION_SUPPORT // |
| #endif // CONFIG_STA_SUPPORT // |
| |
| #ifdef CONFIG_STA_SUPPORT |
| if (pAd->OpMode == OPMODE_STA) |
| { |
| pRssiSample = &pAd->StaCfg.RssiSample; |
| OneSecTxNoRetryOkCount = pAd->RalinkCounters.OneSecTxNoRetryOkCount; |
| OneSecTxRetryOkCount = pAd->RalinkCounters.OneSecTxRetryOkCount; |
| OneSecTxFailCount = pAd->RalinkCounters.OneSecTxFailCount; |
| OneSecRxOkCnt = pAd->RalinkCounters.OneSecRxOkCnt; |
| OneSecRxFcsErrCnt = pAd->RalinkCounters.OneSecRxFcsErrCnt; |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| MaxRssi = RTMPMaxRssi(pAd, pRssiSample->LastRssi0, |
| pRssiSample->LastRssi1, |
| pRssiSample->LastRssi2); |
| |
| // |
| // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics |
| // |
| TxOkCnt = OneSecTxNoRetryOkCount + OneSecTxRetryOkCount; |
| TxCnt = TxOkCnt + OneSecTxFailCount; |
| if (TxCnt < 5) |
| { |
| TxPER = 0; |
| TxPRR = 0; |
| } |
| else |
| { |
| TxPER = (OneSecTxFailCount * 100) / TxCnt; |
| TxPRR = ((TxCnt - OneSecTxNoRetryOkCount) * 100) / TxCnt; |
| } |
| |
| // |
| // calculate RX PER - don't take RxPER into consideration if too few sample |
| // |
| RxCnt = OneSecRxOkCnt + OneSecRxFcsErrCnt; |
| if (RxCnt < 5) |
| RxPER = 0; |
| else |
| RxPER = (OneSecRxFcsErrCnt * 100) / RxCnt; |
| |
| // |
| // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER |
| // |
| #ifdef CONFIG_STA_SUPPORT |
| if ((pAd->OpMode == OPMODE_STA) && |
| INFRA_ON(pAd) && |
| (OneSecTxNoRetryOkCount < 2) && // no heavy traffic |
| ((pAd->StaCfg.LastBeaconRxTime + BeaconLostTime) < Now32)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n", BeaconLostTime, TxOkCnt)); |
| ChannelQuality = 0; |
| } |
| else |
| #endif // CONFIG_STA_SUPPORT // |
| { |
| // Normalize Rssi |
| if (MaxRssi > -40) |
| NorRssi = 100; |
| else if (MaxRssi < -90) |
| NorRssi = 0; |
| else |
| NorRssi = (MaxRssi + 90) * 2; |
| |
| // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) |
| ChannelQuality = (RSSI_WEIGHTING * NorRssi + |
| TX_WEIGHTING * (100 - TxPRR) + |
| RX_WEIGHTING* (100 - RxPER)) / 100; |
| } |
| |
| |
| #ifdef CONFIG_STA_SUPPORT |
| if (pAd->OpMode == OPMODE_STA) |
| pAd->Mlme.ChannelQuality = (ChannelQuality > 100) ? 100 : ChannelQuality; |
| #endif // CONFIG_STA_SUPPORT // |
| |
| |
| } |
| |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeSetTxPreamble( |
| IN PRTMP_ADAPTER pAd, |
| IN USHORT TxPreamble) |
| { |
| AUTO_RSP_CFG_STRUC csr4; |
| |
| // |
| // Always use Long preamble before verifiation short preamble functionality works well. |
| // Todo: remove the following line if short preamble functionality works |
| // |
| //TxPreamble = Rt802_11PreambleLong; |
| |
| RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word); |
| if (TxPreamble == Rt802_11PreambleLong) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= LONG PREAMBLE)\n")); |
| OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); |
| csr4.field.AutoResponderPreamble = 0; |
| } |
| else |
| { |
| // NOTE: 1Mbps should always use long preamble |
| DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n")); |
| OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED); |
| csr4.field.AutoResponderPreamble = 1; |
| } |
| |
| RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| Update basic rate bitmap |
| ========================================================================== |
| */ |
| |
| VOID UpdateBasicRateBitmap( |
| IN PRTMP_ADAPTER pAdapter) |
| { |
| INT i, j; |
| /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */ |
| UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; |
| UCHAR *sup_p = pAdapter->CommonCfg.SupRate; |
| UCHAR *ext_p = pAdapter->CommonCfg.ExtRate; |
| ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap; |
| |
| |
| /* if A mode, always use fix BasicRateBitMap */ |
| //if (pAdapter->CommonCfg.Channel == PHY_11A) |
| if (pAdapter->CommonCfg.Channel > 14) |
| pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */ |
| /* End of if */ |
| |
| if (pAdapter->CommonCfg.BasicRateBitmap > 4095) |
| { |
| /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */ |
| return; |
| } /* End of if */ |
| |
| for(i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++) |
| { |
| sup_p[i] &= 0x7f; |
| ext_p[i] &= 0x7f; |
| } /* End of for */ |
| |
| for(i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++) |
| { |
| if (bitmap & (1 << i)) |
| { |
| for(j=0; j<MAX_LEN_OF_SUPPORTED_RATES; j++) |
| { |
| if (sup_p[j] == rate[i]) |
| sup_p[j] |= 0x80; |
| /* End of if */ |
| } /* End of for */ |
| |
| for(j=0; j<MAX_LEN_OF_SUPPORTED_RATES; j++) |
| { |
| if (ext_p[j] == rate[i]) |
| ext_p[j] |= 0x80; |
| /* End of if */ |
| } /* End of for */ |
| } /* End of if */ |
| } /* End of for */ |
| } /* End of UpdateBasicRateBitmap */ |
| |
| // IRQL = PASSIVE_LEVEL |
| // IRQL = DISPATCH_LEVEL |
| // bLinkUp is to identify the inital link speed. |
| // TRUE indicates the rate update at linkup, we should not try to set the rate at 54Mbps. |
| VOID MlmeUpdateTxRates( |
| IN PRTMP_ADAPTER pAd, |
| IN BOOLEAN bLinkUp, |
| IN UCHAR apidx) |
| { |
| int i, num; |
| UCHAR Rate = RATE_6, MaxDesire = RATE_1, MaxSupport = RATE_1; |
| UCHAR MinSupport = RATE_54; |
| ULONG BasicRateBitmap = 0; |
| UCHAR CurrBasicRate = RATE_1; |
| UCHAR *pSupRate, SupRateLen, *pExtRate, ExtRateLen; |
| PHTTRANSMIT_SETTING pHtPhy = NULL; |
| PHTTRANSMIT_SETTING pMaxHtPhy = NULL; |
| PHTTRANSMIT_SETTING pMinHtPhy = NULL; |
| BOOLEAN *auto_rate_cur_p; |
| UCHAR HtMcs = MCS_AUTO; |
| |
| // find max desired rate |
| UpdateBasicRateBitmap(pAd); |
| |
| num = 0; |
| auto_rate_cur_p = NULL; |
| for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++) |
| { |
| switch (pAd->CommonCfg.DesireRate[i] & 0x7f) |
| { |
| case 2: Rate = RATE_1; num++; break; |
| case 4: Rate = RATE_2; num++; break; |
| case 11: Rate = RATE_5_5; num++; break; |
| case 22: Rate = RATE_11; num++; break; |
| case 12: Rate = RATE_6; num++; break; |
| case 18: Rate = RATE_9; num++; break; |
| case 24: Rate = RATE_12; num++; break; |
| case 36: Rate = RATE_18; num++; break; |
| case 48: Rate = RATE_24; num++; break; |
| case 72: Rate = RATE_36; num++; break; |
| case 96: Rate = RATE_48; num++; break; |
| case 108: Rate = RATE_54; num++; break; |
| //default: Rate = RATE_1; break; |
| } |
| if (MaxDesire < Rate) MaxDesire = Rate; |
| } |
| |
| //=========================================================================== |
| //=========================================================================== |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| pHtPhy = &pAd->StaCfg.HTPhyMode; |
| pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; |
| pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; |
| |
| auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; |
| HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS; |
| |
| if ((pAd->StaCfg.BssType == BSS_ADHOC) && |
| (pAd->CommonCfg.PhyMode == PHY_11B) && |
| (MaxDesire > RATE_11)) |
| { |
| MaxDesire = RATE_11; |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| pAd->CommonCfg.MaxDesiredRate = MaxDesire; |
| pMinHtPhy->word = 0; |
| pMaxHtPhy->word = 0; |
| pHtPhy->word = 0; |
| |
| // Auto rate switching is enabled only if more than one DESIRED RATES are |
| // specified; otherwise disabled |
| if (num <= 1) |
| { |
| //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); |
| //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; |
| *auto_rate_cur_p = FALSE; |
| } |
| else |
| { |
| //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); |
| //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; |
| *auto_rate_cur_p = TRUE; |
| } |
| |
| if (HtMcs != MCS_AUTO) |
| { |
| //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); |
| //pAd->CommonCfg.bAutoTxRateSwitch = FALSE; |
| *auto_rate_cur_p = FALSE; |
| } |
| else |
| { |
| //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); |
| //pAd->CommonCfg.bAutoTxRateSwitch = TRUE; |
| *auto_rate_cur_p = TRUE; |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) |
| { |
| pSupRate = &pAd->StaActive.SupRate[0]; |
| pExtRate = &pAd->StaActive.ExtRate[0]; |
| SupRateLen = pAd->StaActive.SupRateLen; |
| ExtRateLen = pAd->StaActive.ExtRateLen; |
| } |
| else |
| #endif // CONFIG_STA_SUPPORT // |
| { |
| pSupRate = &pAd->CommonCfg.SupRate[0]; |
| pExtRate = &pAd->CommonCfg.ExtRate[0]; |
| SupRateLen = pAd->CommonCfg.SupRateLen; |
| ExtRateLen = pAd->CommonCfg.ExtRateLen; |
| } |
| |
| // find max supported rate |
| for (i=0; i<SupRateLen; i++) |
| { |
| switch (pSupRate[i] & 0x7f) |
| { |
| case 2: Rate = RATE_1; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0001; break; |
| case 4: Rate = RATE_2; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0002; break; |
| case 11: Rate = RATE_5_5; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0004; break; |
| case 22: Rate = RATE_11; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0008; break; |
| case 12: Rate = RATE_6; /*if (pSupRate[i] & 0x80)*/ BasicRateBitmap |= 0x0010; break; |
| case 18: Rate = RATE_9; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0020; break; |
| case 24: Rate = RATE_12; /*if (pSupRate[i] & 0x80)*/ BasicRateBitmap |= 0x0040; break; |
| case 36: Rate = RATE_18; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0080; break; |
| case 48: Rate = RATE_24; /*if (pSupRate[i] & 0x80)*/ BasicRateBitmap |= 0x0100; break; |
| case 72: Rate = RATE_36; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0200; break; |
| case 96: Rate = RATE_48; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0400; break; |
| case 108: Rate = RATE_54; if (pSupRate[i] & 0x80) BasicRateBitmap |= 0x0800; break; |
| default: Rate = RATE_1; break; |
| } |
| if (MaxSupport < Rate) MaxSupport = Rate; |
| |
| if (MinSupport > Rate) MinSupport = Rate; |
| } |
| |
| for (i=0; i<ExtRateLen; i++) |
| { |
| switch (pExtRate[i] & 0x7f) |
| { |
| case 2: Rate = RATE_1; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0001; break; |
| case 4: Rate = RATE_2; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0002; break; |
| case 11: Rate = RATE_5_5; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0004; break; |
| case 22: Rate = RATE_11; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0008; break; |
| case 12: Rate = RATE_6; /*if (pExtRate[i] & 0x80)*/ BasicRateBitmap |= 0x0010; break; |
| case 18: Rate = RATE_9; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0020; break; |
| case 24: Rate = RATE_12; /*if (pExtRate[i] & 0x80)*/ BasicRateBitmap |= 0x0040; break; |
| case 36: Rate = RATE_18; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0080; break; |
| case 48: Rate = RATE_24; /*if (pExtRate[i] & 0x80)*/ BasicRateBitmap |= 0x0100; break; |
| case 72: Rate = RATE_36; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0200; break; |
| case 96: Rate = RATE_48; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0400; break; |
| case 108: Rate = RATE_54; if (pExtRate[i] & 0x80) BasicRateBitmap |= 0x0800; break; |
| default: Rate = RATE_1; break; |
| } |
| if (MaxSupport < Rate) MaxSupport = Rate; |
| |
| if (MinSupport > Rate) MinSupport = Rate; |
| } |
| |
| RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap); |
| |
| // bug fix |
| // pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap; |
| |
| // calculate the exptected ACK rate for each TX rate. This info is used to caculate |
| // the DURATION field of outgoing uniicast DATA/MGMT frame |
| for (i=0; i<MAX_LEN_OF_SUPPORTED_RATES; i++) |
| { |
| if (BasicRateBitmap & (0x01 << i)) |
| CurrBasicRate = (UCHAR)i; |
| pAd->CommonCfg.ExpectedACKRate[i] = CurrBasicRate; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n", RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire])); |
| // max tx rate = min {max desire rate, max supported rate} |
| if (MaxSupport < MaxDesire) |
| pAd->CommonCfg.MaxTxRate = MaxSupport; |
| else |
| pAd->CommonCfg.MaxTxRate = MaxDesire; |
| |
| pAd->CommonCfg.MinTxRate = MinSupport; |
| // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success |
| // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending |
| // on average RSSI |
| // 1. RSSI >= -70db, start at 54 Mbps (short distance) |
| // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) |
| // 3. -75 > RSSI, start at 11 Mbps (long distance) |
| //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)/* && |
| // OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)*/) |
| if (*auto_rate_cur_p) |
| { |
| short dbm = 0; |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta; |
| #endif // CONFIG_STA_SUPPORT // |
| if (bLinkUp == TRUE) |
| pAd->CommonCfg.TxRate = RATE_24; |
| else |
| pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; |
| |
| if (dbm < -75) |
| pAd->CommonCfg.TxRate = RATE_11; |
| else if (dbm < -70) |
| pAd->CommonCfg.TxRate = RATE_24; |
| |
| // should never exceed MaxTxRate (consider 11B-only mode) |
| if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate) |
| pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; |
| |
| pAd->CommonCfg.TxRateIndex = 0; |
| } |
| else |
| { |
| pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate; |
| pHtPhy->field.MCS = (pAd->CommonCfg.MaxTxRate > 3) ? (pAd->CommonCfg.MaxTxRate - 4) : pAd->CommonCfg.MaxTxRate; |
| pHtPhy->field.MODE = (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK; |
| |
| pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC = pHtPhy->field.STBC; |
| pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI = pHtPhy->field.ShortGI; |
| pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS = pHtPhy->field.MCS; |
| pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE = pHtPhy->field.MODE; |
| } |
| |
| if (pAd->CommonCfg.TxRate <= RATE_11) |
| { |
| pMaxHtPhy->field.MODE = MODE_CCK; |
| pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate; |
| pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate; |
| } |
| else |
| { |
| pMaxHtPhy->field.MODE = MODE_OFDM; |
| pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate]; |
| if (pAd->CommonCfg.MinTxRate >= RATE_6 && (pAd->CommonCfg.MinTxRate <= RATE_54)) |
| {pMinHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];} |
| else |
| {pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;} |
| } |
| |
| pHtPhy->word = (pMaxHtPhy->word); |
| if (bLinkUp && (pAd->OpMode == OPMODE_STA)) |
| { |
| pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word; |
| pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word = pMaxHtPhy->word; |
| pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word = pMinHtPhy->word; |
| } |
| else |
| { |
| switch (pAd->CommonCfg.PhyMode) |
| { |
| case PHY_11BG_MIXED: |
| case PHY_11B: |
| #ifdef DOT11_N_SUPPORT |
| case PHY_11BGN_MIXED: |
| #endif // DOT11_N_SUPPORT // |
| pAd->CommonCfg.MlmeRate = RATE_1; |
| pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; |
| pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; |
| |
| //#ifdef WIFI_TEST |
| pAd->CommonCfg.RtsRate = RATE_11; |
| //#else |
| // pAd->CommonCfg.RtsRate = RATE_1; |
| //#endif |
| break; |
| case PHY_11G: |
| case PHY_11A: |
| #ifdef DOT11_N_SUPPORT |
| case PHY_11AGN_MIXED: |
| case PHY_11GN_MIXED: |
| case PHY_11N_2_4G: |
| case PHY_11AN_MIXED: |
| case PHY_11N_5G: |
| #endif // DOT11_N_SUPPORT // |
| pAd->CommonCfg.MlmeRate = RATE_6; |
| pAd->CommonCfg.RtsRate = RATE_6; |
| pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; |
| pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; |
| break; |
| case PHY_11ABG_MIXED: |
| #ifdef DOT11_N_SUPPORT |
| case PHY_11ABGN_MIXED: |
| #endif // DOT11_N_SUPPORT // |
| if (pAd->CommonCfg.Channel <= 14) |
| { |
| pAd->CommonCfg.MlmeRate = RATE_1; |
| pAd->CommonCfg.RtsRate = RATE_1; |
| pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; |
| pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1; |
| } |
| else |
| { |
| pAd->CommonCfg.MlmeRate = RATE_6; |
| pAd->CommonCfg.RtsRate = RATE_6; |
| pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; |
| pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; |
| } |
| break; |
| default: // error |
| pAd->CommonCfg.MlmeRate = RATE_6; |
| pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; |
| pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; |
| pAd->CommonCfg.RtsRate = RATE_1; |
| break; |
| } |
| // |
| // Keep Basic Mlme Rate. |
| // |
| pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word = pAd->CommonCfg.MlmeTransmit.word; |
| if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM) |
| pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[RATE_24]; |
| else |
| pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS = RATE_1; |
| pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n", |
| RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport], RateIdToMbps[pAd->CommonCfg.MaxTxRate], RateIdToMbps[pAd->CommonCfg.MinTxRate], |
| /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)*/*auto_rate_cur_p)); |
| DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n", |
| RateIdToMbps[pAd->CommonCfg.TxRate], RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap)); |
| DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n", |
| pAd->CommonCfg.MlmeTransmit.word, pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word ,pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word )); |
| } |
| |
| #ifdef DOT11_N_SUPPORT |
| /* |
| ========================================================================== |
| Description: |
| This function update HT Rate setting. |
| Input Wcid value is valid for 2 case : |
| 1. it's used for Station in infra mode that copy AP rate to Mactable. |
| 2. OR Station in adhoc mode to copy peer's HT rate to Mactable. |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID MlmeUpdateHtTxRates( |
| IN PRTMP_ADAPTER pAd, |
| IN UCHAR apidx) |
| { |
| UCHAR StbcMcs; //j, StbcMcs, bitmask; |
| CHAR i; // 3*3 |
| RT_HT_CAPABILITY *pRtHtCap = NULL; |
| RT_HT_PHY_INFO *pActiveHtPhy = NULL; |
| ULONG BasicMCS; |
| UCHAR j, bitmask; |
| PRT_HT_PHY_INFO pDesireHtPhy = NULL; |
| PHTTRANSMIT_SETTING pHtPhy = NULL; |
| PHTTRANSMIT_SETTING pMaxHtPhy = NULL; |
| PHTTRANSMIT_SETTING pMinHtPhy = NULL; |
| BOOLEAN *auto_rate_cur_p; |
| |
| DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates===> \n")); |
| |
| auto_rate_cur_p = NULL; |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; |
| pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo; |
| pHtPhy = &pAd->StaCfg.HTPhyMode; |
| pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode; |
| pMinHtPhy = &pAd->StaCfg.MinHTPhyMode; |
| |
| auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch; |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| #ifdef CONFIG_STA_SUPPORT |
| if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) |
| { |
| if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE) |
| return; |
| |
| pRtHtCap = &pAd->StaActive.SupportedHtPhy; |
| pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo; |
| StbcMcs = (UCHAR)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs; |
| BasicMCS =pAd->MlmeAux.AddHtInfo.MCSSet[0]+(pAd->MlmeAux.AddHtInfo.MCSSet[1]<<8)+(StbcMcs<<16); |
| if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) |
| pMaxHtPhy->field.STBC = STBC_USE; |
| else |
| pMaxHtPhy->field.STBC = STBC_NONE; |
| } |
| else |
| #endif // CONFIG_STA_SUPPORT // |
| { |
| if (pDesireHtPhy->bHtEnable == FALSE) |
| return; |
| |
| pRtHtCap = &pAd->CommonCfg.DesiredHtPhy; |
| StbcMcs = (UCHAR)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs; |
| BasicMCS = pAd->CommonCfg.AddHTInfo.MCSSet[0]+(pAd->CommonCfg.AddHTInfo.MCSSet[1]<<8)+(StbcMcs<<16); |
| if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC) && (pAd->Antenna.field.TxPath == 2)) |
| pMaxHtPhy->field.STBC = STBC_USE; |
| else |
| pMaxHtPhy->field.STBC = STBC_NONE; |
| } |
| |
| // Decide MAX ht rate. |
| if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF)) |
| pMaxHtPhy->field.MODE = MODE_HTGREENFIELD; |
| else |
| pMaxHtPhy->field.MODE = MODE_HTMIX; |
| |
| if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth) && (pRtHtCap->ChannelWidth)) |
| pMaxHtPhy->field.BW = BW_40; |
| else |
| pMaxHtPhy->field.BW = BW_20; |
| |
| if (pMaxHtPhy->field.BW == BW_20) |
| pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->ShortGIfor20); |
| else |
| pMaxHtPhy->field.ShortGI = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->ShortGIfor40); |
| |
| if (pDesireHtPhy->MCSSet[4] != 0) |
| { |
| pMaxHtPhy->field.MCS = 32; |
| } |
| |
| for (i=23; i>=0; i--) // 3*3 |
| { |
| j = i/8; |
| bitmask = (1<<(i-(j*8))); |
| |
| if ((pActiveHtPhy->MCSSet[j] & bitmask) && (pDesireHtPhy->MCSSet[j] & bitmask)) |
| { |
| pMaxHtPhy->field.MCS = i; |
| break; |
| } |
| |
| if (i==0) |
| break; |
| } |
| |
| // Copy MIN ht rate. rt2860??? |
| pMinHtPhy->field.BW = BW_20; |
| pMinHtPhy->field.MCS = 0; |
| pMinHtPhy->field.STBC = 0; |
| pMinHtPhy->field.ShortGI = 0; |
| //If STA assigns fixed rate. update to fixed here. |
| #ifdef CONFIG_STA_SUPPORT |
| if ( (pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) |
| { |
| if (pDesireHtPhy->MCSSet[4] != 0) |
| { |
| pMaxHtPhy->field.MCS = 32; |
| pMinHtPhy->field.MCS = 32; |
| DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",pMinHtPhy->field.MCS)); |
| } |
| |
| for (i=23; (CHAR)i >= 0; i--) // 3*3 |
| { |
| j = i/8; |
| bitmask = (1<<(i-(j*8))); |
| if ( (pDesireHtPhy->MCSSet[j] & bitmask) && (pActiveHtPhy->MCSSet[j] & bitmask)) |
| { |
| pMaxHtPhy->field.MCS = i; |
| pMinHtPhy->field.MCS = i; |
| break; |
| } |
| if (i==0) |
| break; |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| |
| // Decide ht rate |
| pHtPhy->field.STBC = pMaxHtPhy->field.STBC; |
| pHtPhy->field.BW = pMaxHtPhy->field.BW; |
| pHtPhy->field.MODE = pMaxHtPhy->field.MODE; |
| pHtPhy->field.MCS = pMaxHtPhy->field.MCS; |
| pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI; |
| |
| // use default now. rt2860 |
| if (pDesireHtPhy->MCSSet[0] != 0xff) |
| *auto_rate_cur_p = FALSE; |
| else |
| *auto_rate_cur_p = TRUE; |
| |
| DBGPRINT(RT_DEBUG_TRACE, (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n", pAd->CommonCfg.DesiredHtPhy.AmsduSize )); |
| DBGPRINT(RT_DEBUG_TRACE,("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n", pActiveHtPhy->MCSSet[0],pHtPhy->field.MCS, |
| pHtPhy->field.BW, pHtPhy->field.ShortGI, pHtPhy->field.MODE)); |
| DBGPRINT(RT_DEBUG_TRACE,("MlmeUpdateHtTxRates<=== \n")); |
| } |
| |
| |
| VOID BATableInit( |
| IN PRTMP_ADAPTER pAd, |
| IN BA_TABLE *Tab) |
| { |
| int i; |
| |
| Tab->numAsOriginator = 0; |
| Tab->numAsRecipient = 0; |
| Tab->numDoneOriginator = 0; |
| NdisAllocateSpinLock(&pAd->BATabLock); |
| for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) |
| { |
| Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE; |
| NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock)); |
| } |
| for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) |
| { |
| Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE; |
| } |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeRadioOff( |
| IN PRTMP_ADAPTER pAd) |
| { |
| RTMP_MLME_RADIO_OFF(pAd); |
| } |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeRadioOn( |
| IN PRTMP_ADAPTER pAd) |
| { |
| RTMP_MLME_RADIO_ON(pAd); |
| } |
| |
| // =========================================================================================== |
| // bss_table.c |
| // =========================================================================================== |
| |
| |
| /*! \brief initialize BSS table |
| * \param p_tab pointer to the table |
| * \return none |
| * \pre |
| * \post |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| VOID BssTableInit( |
| IN BSS_TABLE *Tab) |
| { |
| int i; |
| |
| Tab->BssNr = 0; |
| Tab->BssOverlapNr = 0; |
| for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) |
| { |
| NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY)); |
| Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value |
| } |
| } |
| |
| |
| /*! \brief search the BSS table by SSID |
| * \param p_tab pointer to the bss table |
| * \param ssid SSID string |
| * \return index of the table, BSS_NOT_FOUND if not in the table |
| * \pre |
| * \post |
| * \note search by sequential search |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| ULONG BssTableSearch( |
| IN BSS_TABLE *Tab, |
| IN PUCHAR pBssid, |
| IN UCHAR Channel) |
| { |
| UCHAR i; |
| |
| for (i = 0; i < Tab->BssNr; i++) |
| { |
| // |
| // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. |
| // We should distinguish this case. |
| // |
| if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || |
| ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && |
| MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) |
| { |
| return i; |
| } |
| } |
| return (ULONG)BSS_NOT_FOUND; |
| } |
| |
| ULONG BssSsidTableSearch( |
| IN BSS_TABLE *Tab, |
| IN PUCHAR pBssid, |
| IN PUCHAR pSsid, |
| IN UCHAR SsidLen, |
| IN UCHAR Channel) |
| { |
| UCHAR i; |
| |
| for (i = 0; i < Tab->BssNr; i++) |
| { |
| // |
| // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. |
| // We should distinguish this case. |
| // |
| if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || |
| ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && |
| MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) && |
| SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen)) |
| { |
| return i; |
| } |
| } |
| return (ULONG)BSS_NOT_FOUND; |
| } |
| |
| ULONG BssTableSearchWithSSID( |
| IN BSS_TABLE *Tab, |
| IN PUCHAR Bssid, |
| IN PUCHAR pSsid, |
| IN UCHAR SsidLen, |
| IN UCHAR Channel) |
| { |
| UCHAR i; |
| |
| for (i = 0; i < Tab->BssNr; i++) |
| { |
| if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) || |
| ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) && |
| MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) && |
| (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen) || |
| (NdisEqualMemory(pSsid, ZeroSsid, SsidLen)) || |
| (NdisEqualMemory(Tab->BssEntry[i].Ssid, ZeroSsid, Tab->BssEntry[i].SsidLen)))) |
| { |
| return i; |
| } |
| } |
| return (ULONG)BSS_NOT_FOUND; |
| } |
| |
| |
| ULONG BssSsidTableSearchBySSID( |
| IN BSS_TABLE *Tab, |
| IN PUCHAR pSsid, |
| IN UCHAR SsidLen) |
| { |
| UCHAR i; |
| |
| for (i = 0; i < Tab->BssNr; i++) |
| { |
| if (SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid, Tab->BssEntry[i].SsidLen)) |
| { |
| return i; |
| } |
| } |
| return (ULONG)BSS_NOT_FOUND; |
| } |
| |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID BssTableDeleteEntry( |
| IN OUT BSS_TABLE *Tab, |
| IN PUCHAR pBssid, |
| IN UCHAR Channel) |
| { |
| UCHAR i, j; |
| |
| for (i = 0; i < Tab->BssNr; i++) |
| { |
| if ((Tab->BssEntry[i].Channel == Channel) && |
| (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) |
| { |
| for (j = i; j < Tab->BssNr - 1; j++) |
| { |
| NdisMoveMemory(&(Tab->BssEntry[j]), &(Tab->BssEntry[j + 1]), sizeof(BSS_ENTRY)); |
| } |
| NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]), sizeof(BSS_ENTRY)); |
| Tab->BssNr -= 1; |
| return; |
| } |
| } |
| } |
| |
| #ifdef DOT11_N_SUPPORT |
| /* |
| ======================================================================== |
| Routine Description: |
| Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed. |
| |
| Arguments: |
| // IRQL = DISPATCH_LEVEL |
| ======================================================================== |
| */ |
| VOID BATableDeleteORIEntry( |
| IN OUT PRTMP_ADAPTER pAd, |
| IN BA_ORI_ENTRY *pBAORIEntry) |
| { |
| |
| if (pBAORIEntry->ORI_BA_Status != Originator_NONE) |
| { |
| NdisAcquireSpinLock(&pAd->BATabLock); |
| if (pBAORIEntry->ORI_BA_Status == Originator_Done) |
| { |
| pAd->BATable.numAsOriginator -= 1; |
| DBGPRINT(RT_DEBUG_TRACE, ("BATableDeleteORIEntry numAsOriginator= %ld\n", pAd->BATable.numAsRecipient)); |
| // Erase Bitmap flag. |
| } |
| pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1<<(pBAORIEntry->TID) )); // If STA mode, erase flag here |
| pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here |
| pBAORIEntry->ORI_BA_Status = Originator_NONE; |
| pBAORIEntry->Token = 1; |
| // Not clear Sequence here. |
| NdisReleaseSpinLock(&pAd->BATabLock); |
| } |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| /*! \brief |
| * \param |
| * \return |
| * \pre |
| * \post |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| VOID BssEntrySet( |
| IN PRTMP_ADAPTER pAd, |
| OUT BSS_ENTRY *pBss, |
| IN PUCHAR pBssid, |
| IN CHAR Ssid[], |
| IN UCHAR SsidLen, |
| IN UCHAR BssType, |
| IN USHORT BeaconPeriod, |
| IN PCF_PARM pCfParm, |
| IN USHORT AtimWin, |
| IN USHORT CapabilityInfo, |
| IN UCHAR SupRate[], |
| IN UCHAR SupRateLen, |
| IN UCHAR ExtRate[], |
| IN UCHAR ExtRateLen, |
| IN HT_CAPABILITY_IE *pHtCapability, |
| IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE |
| IN UCHAR HtCapabilityLen, |
| IN UCHAR AddHtInfoLen, |
| IN UCHAR NewExtChanOffset, |
| IN UCHAR Channel, |
| IN CHAR Rssi, |
| IN LARGE_INTEGER TimeStamp, |
| IN UCHAR CkipFlag, |
| IN PEDCA_PARM pEdcaParm, |
| IN PQOS_CAPABILITY_PARM pQosCapability, |
| IN PQBSS_LOAD_PARM pQbssLoad, |
| IN USHORT LengthVIE, |
| IN PNDIS_802_11_VARIABLE_IEs pVIE) |
| { |
| COPY_MAC_ADDR(pBss->Bssid, pBssid); |
| // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID |
| pBss->Hidden = 1; |
| if (SsidLen > 0) |
| { |
| // For hidden SSID AP, it might send beacon with SSID len equal to 0 |
| // Or send beacon /probe response with SSID len matching real SSID length, |
| // but SSID is all zero. such as "00-00-00-00" with length 4. |
| // We have to prevent this case overwrite correct table |
| if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) |
| { |
| NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID); |
| NdisMoveMemory(pBss->Ssid, Ssid, SsidLen); |
| pBss->SsidLen = SsidLen; |
| pBss->Hidden = 0; |
| } |
| } |
| else |
| pBss->SsidLen = 0; |
| pBss->BssType = BssType; |
| pBss->BeaconPeriod = BeaconPeriod; |
| if (BssType == BSS_INFRA) |
| { |
| if (pCfParm->bValid) |
| { |
| pBss->CfpCount = pCfParm->CfpCount; |
| pBss->CfpPeriod = pCfParm->CfpPeriod; |
| pBss->CfpMaxDuration = pCfParm->CfpMaxDuration; |
| pBss->CfpDurRemaining = pCfParm->CfpDurRemaining; |
| } |
| } |
| else |
| { |
| pBss->AtimWin = AtimWin; |
| } |
| |
| pBss->CapabilityInfo = CapabilityInfo; |
| // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES |
| // Combine with AuthMode, they will decide the connection methods. |
| pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo); |
| ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES); |
| if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES) |
| NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen); |
| else |
| NdisMoveMemory(pBss->SupRate, SupRate, MAX_LEN_OF_SUPPORTED_RATES); |
| pBss->SupRateLen = SupRateLen; |
| ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES); |
| NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen); |
| pBss->NewExtChanOffset = NewExtChanOffset; |
| pBss->ExtRateLen = ExtRateLen; |
| pBss->Channel = Channel; |
| pBss->CentralChannel = Channel; |
| pBss->Rssi = Rssi; |
| // Update CkipFlag. if not exists, the value is 0x0 |
| pBss->CkipFlag = CkipFlag; |
| |
| // New for microsoft Fixed IEs |
| NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8); |
| pBss->FixIEs.BeaconInterval = BeaconPeriod; |
| pBss->FixIEs.Capabilities = CapabilityInfo; |
| |
| // New for microsoft Variable IEs |
| if (LengthVIE != 0) |
| { |
| pBss->VarIELen = LengthVIE; |
| NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen); |
| } |
| else |
| { |
| pBss->VarIELen = 0; |
| } |
| |
| pBss->AddHtInfoLen = 0; |
| pBss->HtCapabilityLen = 0; |
| #ifdef DOT11_N_SUPPORT |
| if (HtCapabilityLen> 0) |
| { |
| pBss->HtCapabilityLen = HtCapabilityLen; |
| NdisMoveMemory(&pBss->HtCapability, pHtCapability, HtCapabilityLen); |
| if (AddHtInfoLen > 0) |
| { |
| pBss->AddHtInfoLen = AddHtInfoLen; |
| NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo, AddHtInfoLen); |
| |
| if ((pAddHtInfo->ControlChan > 2)&& (pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_BELOW) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) |
| { |
| pBss->CentralChannel = pAddHtInfo->ControlChan - 2; |
| } |
| else if ((pAddHtInfo->AddHtInfo.ExtChanOffset == EXTCHA_ABOVE) && (pHtCapability->HtCapInfo.ChannelWidth == BW_40)) |
| { |
| pBss->CentralChannel = pAddHtInfo->ControlChan + 2; |
| } |
| } |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| BssCipherParse(pBss); |
| |
| // new for QOS |
| if (pEdcaParm) |
| NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM)); |
| else |
| pBss->EdcaParm.bValid = FALSE; |
| if (pQosCapability) |
| NdisMoveMemory(&pBss->QosCapability, pQosCapability, sizeof(QOS_CAPABILITY_PARM)); |
| else |
| pBss->QosCapability.bValid = FALSE; |
| if (pQbssLoad) |
| NdisMoveMemory(&pBss->QbssLoad, pQbssLoad, sizeof(QBSS_LOAD_PARM)); |
| else |
| pBss->QbssLoad.bValid = FALSE; |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| PEID_STRUCT pEid; |
| USHORT Length = 0; |
| |
| |
| NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN); |
| NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN); |
| #ifdef EXT_BUILD_CHANNEL_LIST |
| NdisZeroMemory(&pBss->CountryString[0], 3); |
| pBss->bHasCountryIE = FALSE; |
| #endif // EXT_BUILD_CHANNEL_LIST // |
| pEid = (PEID_STRUCT) pVIE; |
| while ((Length + 2 + (USHORT)pEid->Len) <= LengthVIE) |
| { |
| switch(pEid->Eid) |
| { |
| case IE_WPA: |
| if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) |
| { |
| if ((pEid->Len + 2) > MAX_CUSTOM_LEN) |
| { |
| pBss->WpaIE.IELen = 0; |
| break; |
| } |
| pBss->WpaIE.IELen = pEid->Len + 2; |
| NdisMoveMemory(pBss->WpaIE.IE, pEid, pBss->WpaIE.IELen); |
| } |
| break; |
| case IE_RSN: |
| if (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3)) |
| { |
| if ((pEid->Len + 2) > MAX_CUSTOM_LEN) |
| { |
| pBss->RsnIE.IELen = 0; |
| break; |
| } |
| pBss->RsnIE.IELen = pEid->Len + 2; |
| NdisMoveMemory(pBss->RsnIE.IE, pEid, pBss->RsnIE.IELen); |
| } |
| break; |
| #ifdef EXT_BUILD_CHANNEL_LIST |
| case IE_COUNTRY: |
| NdisMoveMemory(&pBss->CountryString[0], pEid->Octet, 3); |
| pBss->bHasCountryIE = TRUE; |
| break; |
| #endif // EXT_BUILD_CHANNEL_LIST // |
| } |
| Length = Length + 2 + (USHORT)pEid->Len; // Eid[1] + Len[1]+ content[Len] |
| pEid = (PEID_STRUCT)((UCHAR*)pEid + 2 + pEid->Len); |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| } |
| |
| /*! |
| * \brief insert an entry into the bss table |
| * \param p_tab The BSS table |
| * \param Bssid BSSID |
| * \param ssid SSID |
| * \param ssid_len Length of SSID |
| * \param bss_type |
| * \param beacon_period |
| * \param timestamp |
| * \param p_cf |
| * \param atim_win |
| * \param cap |
| * \param rates |
| * \param rates_len |
| * \param channel_idx |
| * \return none |
| * \pre |
| * \post |
| * \note If SSID is identical, the old entry will be replaced by the new one |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| ULONG BssTableSetEntry( |
| IN PRTMP_ADAPTER pAd, |
| OUT BSS_TABLE *Tab, |
| IN PUCHAR pBssid, |
| IN CHAR Ssid[], |
| IN UCHAR SsidLen, |
| IN UCHAR BssType, |
| IN USHORT BeaconPeriod, |
| IN CF_PARM *CfParm, |
| IN USHORT AtimWin, |
| IN USHORT CapabilityInfo, |
| IN UCHAR SupRate[], |
| IN UCHAR SupRateLen, |
| IN UCHAR ExtRate[], |
| IN UCHAR ExtRateLen, |
| IN HT_CAPABILITY_IE *pHtCapability, |
| IN ADD_HT_INFO_IE *pAddHtInfo, // AP might use this additional ht info IE |
| IN UCHAR HtCapabilityLen, |
| IN UCHAR AddHtInfoLen, |
| IN UCHAR NewExtChanOffset, |
| IN UCHAR ChannelNo, |
| IN CHAR Rssi, |
| IN LARGE_INTEGER TimeStamp, |
| IN UCHAR CkipFlag, |
| IN PEDCA_PARM pEdcaParm, |
| IN PQOS_CAPABILITY_PARM pQosCapability, |
| IN PQBSS_LOAD_PARM pQbssLoad, |
| IN USHORT LengthVIE, |
| IN PNDIS_802_11_VARIABLE_IEs pVIE) |
| { |
| ULONG Idx; |
| |
| Idx = BssTableSearchWithSSID(Tab, pBssid, (UCHAR *)Ssid, SsidLen, ChannelNo); |
| if (Idx == BSS_NOT_FOUND) |
| { |
| if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) |
| { |
| // |
| // It may happen when BSS Table was full. |
| // The desired AP will not be added into BSS Table |
| // In this case, if we found the desired AP then overwrite BSS Table. |
| // |
| if(!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) |
| { |
| if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid) || |
| SSID_EQUAL(pAd->MlmeAux.Ssid, pAd->MlmeAux.SsidLen, Ssid, SsidLen)) |
| { |
| Idx = Tab->BssOverlapNr; |
| BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, |
| CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, |
| NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); |
| Tab->BssOverlapNr = (Tab->BssOverlapNr++) % MAX_LEN_OF_BSS_TABLE; |
| } |
| return Idx; |
| } |
| else |
| { |
| return BSS_NOT_FOUND; |
| } |
| } |
| Idx = Tab->BssNr; |
| BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod, CfParm, AtimWin, |
| CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, |
| NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); |
| Tab->BssNr++; |
| } |
| else |
| { |
| /* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */ |
| if ((SSID_EQUAL(Ssid, SsidLen, Tab->BssEntry[Idx].Ssid, Tab->BssEntry[Idx].SsidLen)) || |
| (NdisEqualMemory(Tab->BssEntry[Idx].Ssid, ZeroSsid, Tab->BssEntry[Idx].SsidLen))) |
| { |
| BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen, BssType, BeaconPeriod,CfParm, AtimWin, |
| CapabilityInfo, SupRate, SupRateLen, ExtRate, ExtRateLen,pHtCapability, pAddHtInfo,HtCapabilityLen, AddHtInfoLen, |
| NewExtChanOffset, ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm, pQosCapability, pQbssLoad, LengthVIE, pVIE); |
| } |
| } |
| |
| return Idx; |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| #ifdef DOT11_N_SUPPORT |
| #ifdef DOT11N_DRAFT3 |
| VOID TriEventInit( |
| IN PRTMP_ADAPTER pAd) |
| { |
| UCHAR i; |
| |
| for (i = 0;i < MAX_TRIGGER_EVENT;i++) |
| pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; |
| |
| pAd->CommonCfg.TriggerEventTab.EventANo = 0; |
| pAd->CommonCfg.TriggerEventTab.EventBCountDown = 0; |
| } |
| |
| ULONG TriEventTableSetEntry( |
| IN PRTMP_ADAPTER pAd, |
| OUT TRIGGER_EVENT_TAB *Tab, |
| IN PUCHAR pBssid, |
| IN HT_CAPABILITY_IE *pHtCapability, |
| IN UCHAR HtCapabilityLen, |
| IN UCHAR RegClass, |
| IN UCHAR ChannelNo) |
| { |
| // Event A |
| if (HtCapabilityLen == 0) |
| { |
| if (Tab->EventANo < MAX_TRIGGER_EVENT) |
| { |
| RTMPMoveMemory(Tab->EventA[Tab->EventANo].BSSID, pBssid, 6); |
| Tab->EventA[Tab->EventANo].bValid = TRUE; |
| Tab->EventA[Tab->EventANo].Channel = ChannelNo; |
| Tab->EventA[Tab->EventANo].CDCounter = pAd->CommonCfg.Dot11BssWidthChanTranDelay; |
| if (RegClass != 0) |
| { |
| // Beacon has Regulatory class IE. So use beacon's |
| Tab->EventA[Tab->EventANo].RegClass = RegClass; |
| } |
| else |
| { |
| // Use Station's Regulatory class instead. |
| if (pAd->StaActive.SupportedHtPhy.bHtEnable == TRUE) |
| { |
| if (pAd->CommonCfg.CentralChannel > pAd->CommonCfg.Channel) |
| { |
| Tab->EventA[Tab->EventANo].RegClass = 32; |
| } |
| else if (pAd->CommonCfg.CentralChannel < pAd->CommonCfg.Channel) |
| Tab->EventA[Tab->EventANo].RegClass = 33; |
| } |
| else |
| Tab->EventA[Tab->EventANo].RegClass = ??; |
| |
| } |
| |
| Tab->EventANo ++; |
| } |
| } |
| else if (pHtCapability->HtCapInfo.Intolerant40) |
| { |
| Tab->EventBCountDown = pAd->CommonCfg.Dot11BssWidthChanTranDelay; |
| } |
| |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Trigger Event table Maintainence called once every second. |
| |
| Arguments: |
| // IRQL = DISPATCH_LEVEL |
| ======================================================================== |
| */ |
| VOID TriEventCounterMaintenance( |
| IN PRTMP_ADAPTER pAd) |
| { |
| UCHAR i; |
| BOOLEAN bNotify = FALSE; |
| for (i = 0;i < MAX_TRIGGER_EVENT;i++) |
| { |
| if (pAd->CommonCfg.TriggerEventTab.EventA[i].bValid && (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter > 0)) |
| { |
| pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter--; |
| if (pAd->CommonCfg.TriggerEventTab.EventA[i].CDCounter == 0) |
| { |
| pAd->CommonCfg.TriggerEventTab.EventA[i].bValid = FALSE; |
| pAd->CommonCfg.TriggerEventTab.EventANo --; |
| // Need to send 20/40 Coexistence Notify frame if has status change. |
| bNotify = TRUE; |
| } |
| } |
| } |
| if (pAd->CommonCfg.TriggerEventTab.EventBCountDown > 0) |
| { |
| pAd->CommonCfg.TriggerEventTab.EventBCountDown--; |
| if (pAd->CommonCfg.TriggerEventTab.EventBCountDown == 0) |
| bNotify = TRUE; |
| } |
| |
| if (bNotify == TRUE) |
| Update2040CoexistFrameAndNotify(pAd, BSSID_WCID, TRUE); |
| } |
| #endif // DOT11N_DRAFT3 // |
| #endif // DOT11_N_SUPPORT // |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID BssTableSsidSort( |
| IN PRTMP_ADAPTER pAd, |
| OUT BSS_TABLE *OutTab, |
| IN CHAR Ssid[], |
| IN UCHAR SsidLen) |
| { |
| INT i; |
| BssTableInit(OutTab); |
| |
| for (i = 0; i < pAd->ScanTab.BssNr; i++) |
| { |
| BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i]; |
| BOOLEAN bIsHiddenApIncluded = FALSE; |
| |
| if (((pAd->CommonCfg.bIEEE80211H == 1) && |
| (pAd->MlmeAux.Channel > 14) && |
| RadarChannelCheck(pAd, pInBss->Channel)) |
| #ifdef CARRIER_DETECTION_SUPPORT // Roger sync Carrier |
| || (pAd->CommonCfg.CarrierDetect.Enable == TRUE) |
| #endif // CARRIER_DETECTION_SUPPORT // |
| ) |
| { |
| if (pInBss->Hidden) |
| bIsHiddenApIncluded = TRUE; |
| } |
| |
| if ((pInBss->BssType == pAd->StaCfg.BssType) && |
| (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen) || bIsHiddenApIncluded)) |
| { |
| BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; |
| |
| |
| #ifdef EXT_BUILD_CHANNEL_LIST |
| // If no Country IE exists no Connection will be established when IEEE80211dClientMode is strict. |
| if ((pAd->StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict) && |
| (pInBss->bHasCountryIE == FALSE)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE,("StaCfg.IEEE80211dClientMode == Rt802_11_D_Strict, but this AP doesn't have country IE.\n")); |
| continue; |
| } |
| #endif // EXT_BUILD_CHANNEL_LIST // |
| |
| #ifdef DOT11_N_SUPPORT |
| // 2.4G/5G N only mode |
| if ((pInBss->HtCapabilityLen == 0) && |
| ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) |
| { |
| DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); |
| continue; |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| // New for WPA2 |
| // Check the Authmode first |
| if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) |
| { |
| // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode |
| if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) |
| // None matched |
| continue; |
| |
| // Check cipher suite, AP must have more secured cipher than station setting |
| if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) |
| { |
| // If it's not mixed mode, we should only let BSS pass with the same encryption |
| if (pInBss->WPA.bMixMode == FALSE) |
| if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) |
| continue; |
| |
| // check group cipher |
| if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && |
| (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP40Enabled) && |
| (pInBss->WPA.GroupCipher != Ndis802_11GroupWEP104Enabled)) |
| continue; |
| |
| // check pairwise cipher, skip if none matched |
| // If profile set to AES, let it pass without question. |
| // If profile set to TKIP, we must find one mateched |
| if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) |
| continue; |
| } |
| else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) |
| { |
| // If it's not mixed mode, we should only let BSS pass with the same encryption |
| if (pInBss->WPA2.bMixMode == FALSE) |
| if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) |
| continue; |
| |
| // check group cipher |
| if ((pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) && |
| (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP40Enabled) && |
| (pInBss->WPA2.GroupCipher != Ndis802_11GroupWEP104Enabled)) |
| continue; |
| |
| // check pairwise cipher, skip if none matched |
| // If profile set to AES, let it pass without question. |
| // If profile set to TKIP, we must find one mateched |
| if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) |
| continue; |
| } |
| } |
| // Bss Type matched, SSID matched. |
| // We will check wepstatus for qualification Bss |
| else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) |
| { |
| DBGPRINT(RT_DEBUG_TRACE,("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n", pAd->StaCfg.WepStatus, pInBss->WepStatus)); |
| // |
| // For the SESv2 case, we will not qualify WepStatus. |
| // |
| if (!pInBss->bSES) |
| continue; |
| } |
| |
| // Since the AP is using hidden SSID, and we are trying to connect to ANY |
| // It definitely will fail. So, skip it. |
| // CCX also require not even try to connect it!! |
| if (SsidLen == 0) |
| continue; |
| |
| #ifdef DOT11_N_SUPPORT |
| // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region |
| // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, |
| if ((pInBss->CentralChannel != pInBss->Channel) && |
| (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) |
| { |
| if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) |
| { |
| pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; |
| SetCommonHT(pAd); |
| pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; |
| } |
| else |
| { |
| if (pAd->CommonCfg.DesiredHtPhy.ChannelWidth == BAND_WIDTH_20) |
| { |
| SetCommonHT(pAd); |
| } |
| } |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| // copy matching BSS from InTab to OutTab |
| NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); |
| |
| OutTab->BssNr++; |
| } |
| else if ((pInBss->BssType == pAd->StaCfg.BssType) && (SsidLen == 0)) |
| { |
| BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr]; |
| |
| |
| #ifdef DOT11_N_SUPPORT |
| // 2.4G/5G N only mode |
| if ((pInBss->HtCapabilityLen == 0) && |
| ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G) || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) |
| { |
| DBGPRINT(RT_DEBUG_TRACE,("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n")); |
| continue; |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| // New for WPA2 |
| // Check the Authmode first |
| if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) |
| { |
| // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode |
| if ((pAd->StaCfg.AuthMode != pInBss->AuthMode) && (pAd->StaCfg.AuthMode != pInBss->AuthModeAux)) |
| // None matched |
| continue; |
| |
| // Check cipher suite, AP must have more secured cipher than station setting |
| if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK)) |
| { |
| // If it's not mixed mode, we should only let BSS pass with the same encryption |
| if (pInBss->WPA.bMixMode == FALSE) |
| if (pAd->StaCfg.WepStatus != pInBss->WPA.GroupCipher) |
| continue; |
| |
| // check group cipher |
| if (pAd->StaCfg.WepStatus < pInBss->WPA.GroupCipher) |
| continue; |
| |
| // check pairwise cipher, skip if none matched |
| // If profile set to AES, let it pass without question. |
| // If profile set to TKIP, we must find one mateched |
| if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipher) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA.PairCipherAux)) |
| continue; |
| } |
| else if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2) || (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK)) |
| { |
| // If it's not mixed mode, we should only let BSS pass with the same encryption |
| if (pInBss->WPA2.bMixMode == FALSE) |
| if (pAd->StaCfg.WepStatus != pInBss->WPA2.GroupCipher) |
| continue; |
| |
| // check group cipher |
| if (pAd->StaCfg.WepStatus < pInBss->WPA2.GroupCipher) |
| continue; |
| |
| // check pairwise cipher, skip if none matched |
| // If profile set to AES, let it pass without question. |
| // If profile set to TKIP, we must find one mateched |
| if ((pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipher) && |
| (pAd->StaCfg.WepStatus != pInBss->WPA2.PairCipherAux)) |
| continue; |
| } |
| } |
| // Bss Type matched, SSID matched. |
| // We will check wepstatus for qualification Bss |
| else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) |
| continue; |
| |
| #ifdef DOT11_N_SUPPORT |
| // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region |
| // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, |
| if ((pInBss->CentralChannel != pInBss->Channel) && |
| (pAd->CommonCfg.RegTransmitSetting.field.BW == BW_40)) |
| { |
| if (RTMPCheckChannel(pAd, pInBss->CentralChannel, pInBss->Channel) == FALSE) |
| { |
| pAd->CommonCfg.RegTransmitSetting.field.BW = BW_20; |
| SetCommonHT(pAd); |
| pAd->CommonCfg.RegTransmitSetting.field.BW = BW_40; |
| } |
| } |
| #endif // DOT11_N_SUPPORT // |
| |
| // copy matching BSS from InTab to OutTab |
| NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY)); |
| |
| OutTab->BssNr++; |
| } |
| |
| if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE) |
| break; |
| } |
| |
| BssTableSortByRssi(OutTab); |
| } |
| |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID BssTableSortByRssi( |
| IN OUT BSS_TABLE *OutTab) |
| { |
| INT i, j; |
| BSS_ENTRY TmpBss; |
| |
| for (i = 0; i < OutTab->BssNr - 1; i++) |
| { |
| for (j = i+1; j < OutTab->BssNr; j++) |
| { |
| if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) |
| { |
| NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j], sizeof(BSS_ENTRY)); |
| NdisMoveMemory(&OutTab->BssEntry[j], &OutTab->BssEntry[i], sizeof(BSS_ENTRY)); |
| NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss, sizeof(BSS_ENTRY)); |
| } |
| } |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| |
| VOID BssCipherParse( |
| IN OUT PBSS_ENTRY pBss) |
| { |
| PEID_STRUCT pEid; |
| PUCHAR pTmp; |
| PRSN_IE_HEADER_STRUCT pRsnHeader; |
| PCIPHER_SUITE_STRUCT pCipher; |
| PAKM_SUITE_STRUCT pAKM; |
| USHORT Count; |
| INT Length; |
| NDIS_802_11_ENCRYPTION_STATUS TmpCipher; |
| |
| // |
| // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. |
| // |
| if (pBss->Privacy) |
| { |
| pBss->WepStatus = Ndis802_11WEPEnabled; |
| } |
| else |
| { |
| pBss->WepStatus = Ndis802_11WEPDisabled; |
| } |
| // Set default to disable & open authentication before parsing variable IE |
| pBss->AuthMode = Ndis802_11AuthModeOpen; |
| pBss->AuthModeAux = Ndis802_11AuthModeOpen; |
| |
| // Init WPA setting |
| pBss->WPA.PairCipher = Ndis802_11WEPDisabled; |
| pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled; |
| pBss->WPA.GroupCipher = Ndis802_11WEPDisabled; |
| pBss->WPA.RsnCapability = 0; |
| pBss->WPA.bMixMode = FALSE; |
| |
| // Init WPA2 setting |
| pBss->WPA2.PairCipher = Ndis802_11WEPDisabled; |
| pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled; |
| pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled; |
| pBss->WPA2.RsnCapability = 0; |
| pBss->WPA2.bMixMode = FALSE; |
| |
| |
| Length = (INT) pBss->VarIELen; |
| |
| while (Length > 0) |
| { |
| // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently |
| pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length; |
| pEid = (PEID_STRUCT) pTmp; |
| switch (pEid->Eid) |
| { |
| case IE_WPA: |
| if (NdisEqualMemory(pEid->Octet, SES_OUI, 3) && (pEid->Len == 7)) |
| { |
| pBss->bSES = TRUE; |
| break; |
| } |
| else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) != 1) |
| { |
| // if unsupported vendor specific IE |
| break; |
| } |
| // Skip OUI, version, and multicast suite |
| // This part should be improved in the future when AP supported multiple cipher suite. |
| // For now, it's OK since almost all APs have fixed cipher suite supported. |
| // pTmp = (PUCHAR) pEid->Octet; |
| pTmp += 11; |
| |
| // Cipher Suite Selectors from Spec P802.11i/D3.2 P26. |
| // Value Meaning |
| // 0 None |
| // 1 WEP-40 |
| // 2 Tkip |
| // 3 WRAP |
| // 4 AES |
| // 5 WEP-104 |
| // Parse group cipher |
| switch (*pTmp) |
| { |
| case 1: |
| pBss->WPA.GroupCipher = Ndis802_11GroupWEP40Enabled; |
| break; |
| case 5: |
| pBss->WPA.GroupCipher = Ndis802_11GroupWEP104Enabled; |
| break; |
| case 2: |
| pBss->WPA.GroupCipher = Ndis802_11Encryption2Enabled; |
| break; |
| case 4: |
| pBss->WPA.GroupCipher = Ndis802_11Encryption3Enabled; |
| break; |
| default: |
| break; |
| } |
| // number of unicast suite |
| pTmp += 1; |
| |
| // skip all unicast cipher suites |
| //Count = *(PUSHORT) pTmp; |
| Count = (pTmp[1]<<8) + pTmp[0]; |
| pTmp += sizeof(USHORT); |
| |
| // Parsing all unicast cipher suite |
| while (Count > 0) |
| { |
| // Skip OUI |
| pTmp += 3; |
| TmpCipher = Ndis802_11WEPDisabled; |
| switch (*pTmp) |
| { |
| case 1: |
| case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway |
| TmpCipher = Ndis802_11Encryption1Enabled; |
| break; |
| case 2: |
| TmpCipher = Ndis802_11Encryption2Enabled; |
| break; |
| case 4: |
| TmpCipher = Ndis802_11Encryption3Enabled; |
| break; |
| default: |
| break; |
| } |
| if (TmpCipher > pBss->WPA.PairCipher) |
| { |
| // Move the lower cipher suite to PairCipherAux |
| pBss->WPA.PairCipherAux = pBss->WPA.PairCipher; |
| pBss->WPA.PairCipher = TmpCipher; |
| } |
| else |
| { |
| pBss->WPA.PairCipherAux = TmpCipher; |
| } |
| pTmp++; |
| Count--; |
| } |
| |
| // 4. get AKM suite counts |
| //Count = *(PUSHORT) pTmp; |
| Count = (pTmp[1]<<8) + pTmp[0]; |
| pTmp += sizeof(USHORT); |
| pTmp += 3; |
| |
| switch (*pTmp) |
| { |
| case 1: |
| // Set AP support WPA-enterprise mode |
| if (pBss->AuthMode == Ndis802_11AuthModeOpen) |
| pBss->AuthMode = Ndis802_11AuthModeWPA; |
| else |
| pBss->AuthModeAux = Ndis802_11AuthModeWPA; |
| break; |
| case 2: |
| // Set AP support WPA-PSK mode |
| if (pBss->AuthMode == Ndis802_11AuthModeOpen) |
| pBss->AuthMode = Ndis802_11AuthModeWPAPSK; |
| else |
| pBss->AuthModeAux = Ndis802_11AuthModeWPAPSK; |
| break; |
| default: |
| break; |
| } |
| pTmp += 1; |
| |
| // Fixed for WPA-None |
| if (pBss->BssType == BSS_ADHOC) |
| { |
| pBss->AuthMode = Ndis802_11AuthModeWPANone; |
| pBss->AuthModeAux = Ndis802_11AuthModeWPANone; |
| pBss->WepStatus = pBss->WPA.GroupCipher; |
| // Patched bugs for old driver |
| if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) |
| pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; |
| } |
| else |
| pBss->WepStatus = pBss->WPA.PairCipher; |
| |
| // Check the Pair & Group, if different, turn on mixed mode flag |
| if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher) |
| pBss->WPA.bMixMode = TRUE; |
| |
| break; |
| |
| case IE_RSN: |
| pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp; |
| |
| // 0. Version must be 1 |
| if (le2cpu16(pRsnHeader->Version) != 1) |
| break; |
| pTmp += sizeof(RSN_IE_HEADER_STRUCT); |
| |
| // 1. Check group cipher |
| pCipher = (PCIPHER_SUITE_STRUCT) pTmp; |
| if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) |
| break; |
| |
| // Parse group cipher |
| switch (pCipher->Type) |
| { |
| case 1: |
| pBss->WPA2.GroupCipher = Ndis802_11GroupWEP40Enabled; |
| break; |
| case 5: |
| pBss->WPA2.GroupCipher = Ndis802_11GroupWEP104Enabled; |
| break; |
| case 2: |
| pBss->WPA2.GroupCipher = Ndis802_11Encryption2Enabled; |
| break; |
| case 4: |
| pBss->WPA2.GroupCipher = Ndis802_11Encryption3Enabled; |
| break; |
| default: |
| break; |
| } |
| // set to correct offset for next parsing |
| pTmp += sizeof(CIPHER_SUITE_STRUCT); |
| |
| // 2. Get pairwise cipher counts |
| //Count = *(PUSHORT) pTmp; |
| Count = (pTmp[1]<<8) + pTmp[0]; |
| pTmp += sizeof(USHORT); |
| |
| // 3. Get pairwise cipher |
| // Parsing all unicast cipher suite |
| while (Count > 0) |
| { |
| // Skip OUI |
| pCipher = (PCIPHER_SUITE_STRUCT) pTmp; |
| TmpCipher = Ndis802_11WEPDisabled; |
| switch (pCipher->Type) |
| { |
| case 1: |
| case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway |
| TmpCipher = Ndis802_11Encryption1Enabled; |
| break; |
| case 2: |
| TmpCipher = Ndis802_11Encryption2Enabled; |
| break; |
| case 4: |
| TmpCipher = Ndis802_11Encryption3Enabled; |
| break; |
| default: |
| break; |
| } |
| if (TmpCipher > pBss->WPA2.PairCipher) |
| { |
| // Move the lower cipher suite to PairCipherAux |
| pBss->WPA2.PairCipherAux = pBss->WPA2.PairCipher; |
| pBss->WPA2.PairCipher = TmpCipher; |
| } |
| else |
| { |
| pBss->WPA2.PairCipherAux = TmpCipher; |
| } |
| pTmp += sizeof(CIPHER_SUITE_STRUCT); |
| Count--; |
| } |
| |
| // 4. get AKM suite counts |
| //Count = *(PUSHORT) pTmp; |
| Count = (pTmp[1]<<8) + pTmp[0]; |
| pTmp += sizeof(USHORT); |
| |
| // 5. Get AKM ciphers |
| // Parsing all AKM ciphers |
| while (Count > 0) |
| { |
| pAKM = (PAKM_SUITE_STRUCT) pTmp; |
| if (!RTMPEqualMemory(pTmp, RSN_OUI, 3)) |
| break; |
| |
| switch (pAKM->Type) |
| { |
| case 1: |
| // Set AP support WPA-enterprise mode |
| if (pBss->AuthMode == Ndis802_11AuthModeOpen) |
| pBss->AuthMode = Ndis802_11AuthModeWPA2; |
| else |
| pBss->AuthModeAux = Ndis802_11AuthModeWPA2; |
| break; |
| case 2: |
| // Set AP support WPA-PSK mode |
| if (pBss->AuthMode == Ndis802_11AuthModeOpen) |
| pBss->AuthMode = Ndis802_11AuthModeWPA2PSK; |
| else |
| pBss->AuthModeAux = Ndis802_11AuthModeWPA2PSK; |
| break; |
| default: |
| if (pBss->AuthMode == Ndis802_11AuthModeOpen) |
| pBss->AuthMode = Ndis802_11AuthModeMax; |
| else |
| pBss->AuthModeAux = Ndis802_11AuthModeMax; |
| break; |
| } |
| pTmp += (Count * sizeof(AKM_SUITE_STRUCT)); |
| Count--; |
| } |
| |
| // Fixed for WPA-None |
| if (pBss->BssType == BSS_ADHOC) |
| { |
| pBss->AuthMode = Ndis802_11AuthModeWPANone; |
| pBss->AuthModeAux = Ndis802_11AuthModeWPANone; |
| pBss->WPA.PairCipherAux = pBss->WPA2.PairCipherAux; |
| pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher; |
| pBss->WepStatus = pBss->WPA.GroupCipher; |
| // Patched bugs for old driver |
| if (pBss->WPA.PairCipherAux == Ndis802_11WEPDisabled) |
| pBss->WPA.PairCipherAux = pBss->WPA.GroupCipher; |
| } |
| pBss->WepStatus = pBss->WPA2.PairCipher; |
| |
| // 6. Get RSN capability |
| //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp; |
| pBss->WPA2.RsnCapability = (pTmp[1]<<8) + pTmp[0]; |
| pTmp += sizeof(USHORT); |
| |
| // Check the Pair & Group, if different, turn on mixed mode flag |
| if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher) |
| pBss->WPA2.bMixMode = TRUE; |
| |
| break; |
| default: |
| break; |
| } |
| Length -= (pEid->Len + 2); |
| } |
| } |
| |
| // =========================================================================================== |
| // mac_table.c |
| // =========================================================================================== |
| |
| /*! \brief generates a random mac address value for IBSS BSSID |
| * \param Addr the bssid location |
| * \return none |
| * \pre |
| * \post |
| */ |
| VOID MacAddrRandomBssid( |
| IN PRTMP_ADAPTER pAd, |
| OUT PUCHAR pAddr) |
| { |
| INT i; |
| |
| for (i = 0; i < MAC_ADDR_LEN; i++) |
| { |
| pAddr[i] = RandomByte(pAd); |
| } |
| |
| pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx |
| } |
| |
| /*! \brief init the management mac frame header |
| * \param p_hdr mac header |
| * \param subtype subtype of the frame |
| * \param p_ds destination address, don't care if it is a broadcast address |
| * \return none |
| * \pre the station has the following information in the pAd->StaCfg |
| * - bssid |
| * - station address |
| * \post |
| * \note this function initializes the following field |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| VOID MgtMacHeaderInit( |
| IN PRTMP_ADAPTER pAd, |
| IN OUT PHEADER_802_11 pHdr80211, |
| IN UCHAR SubType, |
| IN UCHAR ToDs, |
| IN PUCHAR pDA, |
| IN PUCHAR pBssid) |
| { |
| NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); |
| |
| pHdr80211->FC.Type = BTYPE_MGMT; |
| pHdr80211->FC.SubType = SubType; |
| // if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type |
| // pHdr80211->FC.Type = BTYPE_CNTL; |
| pHdr80211->FC.ToDs = ToDs; |
| COPY_MAC_ADDR(pHdr80211->Addr1, pDA); |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); |
| #endif // CONFIG_STA_SUPPORT // |
| COPY_MAC_ADDR(pHdr80211->Addr3, pBssid); |
| } |
| |
| // =========================================================================================== |
| // mem_mgmt.c |
| // =========================================================================================== |
| |
| /*!*************************************************************************** |
| * This routine build an outgoing frame, and fill all information specified |
| * in argument list to the frame body. The actual frame size is the summation |
| * of all arguments. |
| * input params: |
| * Buffer - pointer to a pre-allocated memory segment |
| * args - a list of <int arg_size, arg> pairs. |
| * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this |
| * function will FAIL!!! |
| * return: |
| * Size of the buffer |
| * usage: |
| * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS); |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| ****************************************************************************/ |
| ULONG MakeOutgoingFrame( |
| OUT UCHAR *Buffer, |
| OUT ULONG *FrameLen, ...) |
| { |
| UCHAR *p; |
| int leng; |
| ULONG TotLeng; |
| va_list Args; |
| |
| // calculates the total length |
| TotLeng = 0; |
| va_start(Args, FrameLen); |
| do |
| { |
| leng = va_arg(Args, int); |
| if (leng == END_OF_ARGS) |
| { |
| break; |
| } |
| p = va_arg(Args, PVOID); |
| NdisMoveMemory(&Buffer[TotLeng], p, leng); |
| TotLeng = TotLeng + leng; |
| } while(TRUE); |
| |
| va_end(Args); /* clean up */ |
| *FrameLen = TotLeng; |
| return TotLeng; |
| } |
| |
| // =========================================================================================== |
| // mlme_queue.c |
| // =========================================================================================== |
| |
| /*! \brief Initialize The MLME Queue, used by MLME Functions |
| * \param *Queue The MLME Queue |
| * \return Always Return NDIS_STATE_SUCCESS in this implementation |
| * \pre |
| * \post |
| * \note Because this is done only once (at the init stage), no need to be locked |
| |
| IRQL = PASSIVE_LEVEL |
| |
| */ |
| NDIS_STATUS MlmeQueueInit( |
| IN MLME_QUEUE *Queue) |
| { |
| INT i; |
| |
| NdisAllocateSpinLock(&Queue->Lock); |
| |
| Queue->Num = 0; |
| Queue->Head = 0; |
| Queue->Tail = 0; |
| |
| for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) |
| { |
| Queue->Entry[i].Occupied = FALSE; |
| Queue->Entry[i].MsgLen = 0; |
| NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE); |
| } |
| |
| return NDIS_STATUS_SUCCESS; |
| } |
| |
| /*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread |
| * \param *Queue The MLME Queue |
| * \param Machine The State Machine Id |
| * \param MsgType The Message Type |
| * \param MsgLen The Message length |
| * \param *Msg The message pointer |
| * \return TRUE if enqueue is successful, FALSE if the queue is full |
| * \pre |
| * \post |
| * \note The message has to be initialized |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| BOOLEAN MlmeEnqueue( |
| IN PRTMP_ADAPTER pAd, |
| IN ULONG Machine, |
| IN ULONG MsgType, |
| IN ULONG MsgLen, |
| IN VOID *Msg) |
| { |
| INT Tail; |
| MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; |
| |
| // Do nothing if the driver is starting halt state. |
| // This might happen when timer already been fired before cancel timer with mlmehalt |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) |
| return FALSE; |
| |
| // First check the size, it MUST not exceed the mlme queue size |
| if (MsgLen > MGMT_DMA_BUFFER_SIZE) |
| { |
| DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n", MsgLen)); |
| return FALSE; |
| } |
| |
| if (MlmeQueueFull(Queue)) |
| { |
| return FALSE; |
| } |
| |
| NdisAcquireSpinLock(&(Queue->Lock)); |
| Tail = Queue->Tail; |
| Queue->Tail++; |
| Queue->Num++; |
| if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) |
| { |
| Queue->Tail = 0; |
| } |
| |
| Queue->Entry[Tail].Wcid = RESERVED_WCID; |
| Queue->Entry[Tail].Occupied = TRUE; |
| Queue->Entry[Tail].Machine = Machine; |
| Queue->Entry[Tail].MsgType = MsgType; |
| Queue->Entry[Tail].MsgLen = MsgLen; |
| |
| if (Msg != NULL) |
| { |
| NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); |
| } |
| |
| NdisReleaseSpinLock(&(Queue->Lock)); |
| return TRUE; |
| } |
| |
| /*! \brief This function is used when Recv gets a MLME message |
| * \param *Queue The MLME Queue |
| * \param TimeStampHigh The upper 32 bit of timestamp |
| * \param TimeStampLow The lower 32 bit of timestamp |
| * \param Rssi The receiving RSSI strength |
| * \param MsgLen The length of the message |
| * \param *Msg The message pointer |
| * \return TRUE if everything ok, FALSE otherwise (like Queue Full) |
| * \pre |
| * \post |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| BOOLEAN MlmeEnqueueForRecv( |
| IN PRTMP_ADAPTER pAd, |
| IN ULONG Wcid, |
| IN ULONG TimeStampHigh, |
| IN ULONG TimeStampLow, |
| IN UCHAR Rssi0, |
| IN UCHAR Rssi1, |
| IN UCHAR Rssi2, |
| IN ULONG MsgLen, |
| IN VOID *Msg, |
| IN UCHAR Signal) |
| { |
| INT Tail, Machine; |
| PFRAME_802_11 pFrame = (PFRAME_802_11)Msg; |
| INT MsgType; |
| MLME_QUEUE *Queue = (MLME_QUEUE *)&pAd->Mlme.Queue; |
| |
| #ifdef RALINK_ATE |
| /* Nothing to do in ATE mode */ |
| if(ATE_ON(pAd)) |
| return FALSE; |
| #endif // RALINK_ATE // |
| |
| // Do nothing if the driver is starting halt state. |
| // This might happen when timer already been fired before cancel timer with mlmehalt |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) |
| { |
| DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n")); |
| return FALSE; |
| } |
| |
| // First check the size, it MUST not exceed the mlme queue size |
| if (MsgLen > MGMT_DMA_BUFFER_SIZE) |
| { |
| DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen)); |
| return FALSE; |
| } |
| |
| if (MlmeQueueFull(Queue)) |
| { |
| return FALSE; |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) |
| { |
| DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n",pFrame->Hdr.FC.SubType)); |
| return FALSE; |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| // OK, we got all the informations, it is time to put things into queue |
| NdisAcquireSpinLock(&(Queue->Lock)); |
| Tail = Queue->Tail; |
| Queue->Tail++; |
| Queue->Num++; |
| if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) |
| { |
| Queue->Tail = 0; |
| } |
| Queue->Entry[Tail].Occupied = TRUE; |
| Queue->Entry[Tail].Machine = Machine; |
| Queue->Entry[Tail].MsgType = MsgType; |
| Queue->Entry[Tail].MsgLen = MsgLen; |
| Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow; |
| Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh; |
| Queue->Entry[Tail].Rssi0 = Rssi0; |
| Queue->Entry[Tail].Rssi1 = Rssi1; |
| Queue->Entry[Tail].Rssi2 = Rssi2; |
| Queue->Entry[Tail].Signal = Signal; |
| Queue->Entry[Tail].Wcid = (UCHAR)Wcid; |
| |
| Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel; |
| |
| if (Msg != NULL) |
| { |
| NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen); |
| } |
| |
| NdisReleaseSpinLock(&(Queue->Lock)); |
| |
| RTMP_MLME_HANDLER(pAd); |
| |
| return TRUE; |
| } |
| |
| |
| /*! \brief Dequeue a message from the MLME Queue |
| * \param *Queue The MLME Queue |
| * \param *Elem The message dequeued from MLME Queue |
| * \return TRUE if the Elem contains something, FALSE otherwise |
| * \pre |
| * \post |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| BOOLEAN MlmeDequeue( |
| IN MLME_QUEUE *Queue, |
| OUT MLME_QUEUE_ELEM **Elem) |
| { |
| NdisAcquireSpinLock(&(Queue->Lock)); |
| *Elem = &(Queue->Entry[Queue->Head]); |
| Queue->Num--; |
| Queue->Head++; |
| if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) |
| { |
| Queue->Head = 0; |
| } |
| NdisReleaseSpinLock(&(Queue->Lock)); |
| return TRUE; |
| } |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeRestartStateMachine( |
| IN PRTMP_ADAPTER pAd) |
| { |
| #ifdef RTMP_MAC_PCI |
| MLME_QUEUE_ELEM *Elem = NULL; |
| #endif // RTMP_MAC_PCI // |
| #ifdef CONFIG_STA_SUPPORT |
| BOOLEAN Cancelled; |
| #endif // CONFIG_STA_SUPPORT // |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n")); |
| |
| #ifdef RTMP_MAC_PCI |
| NdisAcquireSpinLock(&pAd->Mlme.TaskLock); |
| if(pAd->Mlme.bRunning) |
| { |
| NdisReleaseSpinLock(&pAd->Mlme.TaskLock); |
| return; |
| } |
| else |
| { |
| pAd->Mlme.bRunning = TRUE; |
| } |
| NdisReleaseSpinLock(&pAd->Mlme.TaskLock); |
| |
| // Remove all Mlme queues elements |
| while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) |
| { |
| //From message type, determine which state machine I should drive |
| if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) |
| { |
| // free MLME element |
| Elem->Occupied = FALSE; |
| Elem->MsgLen = 0; |
| |
| } |
| else { |
| DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n")); |
| } |
| } |
| #endif // RTMP_MAC_PCI // |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| #ifdef QOS_DLS_SUPPORT |
| UCHAR i; |
| #endif // QOS_DLS_SUPPORT // |
| // Cancel all timer events |
| // Be careful to cancel new added timer |
| RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled); |
| |
| #ifdef QOS_DLS_SUPPORT |
| for (i=0; i<MAX_NUM_OF_DLS_ENTRY; i++) |
| { |
| RTMPCancelTimer(&pAd->StaCfg.DLSEntry[i].Timer, &Cancelled); |
| } |
| #endif // QOS_DLS_SUPPORT // |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| // Change back to original channel in case of doing scan |
| AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE); |
| AsicLockChannel(pAd, pAd->CommonCfg.Channel); |
| |
| // Resume MSDU which is turned off durning scan |
| RTMPResumeMsduTransmission(pAd); |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| // Set all state machines back IDLE |
| pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE; |
| pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE; |
| pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE; |
| pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE; |
| pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE; |
| pAd->Mlme.ActMachine.CurrState = ACT_IDLE; |
| #ifdef QOS_DLS_SUPPORT |
| pAd->Mlme.DlsMachine.CurrState = DLS_IDLE; |
| #endif // QOS_DLS_SUPPORT // |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| #ifdef RTMP_MAC_PCI |
| // Remove running state |
| NdisAcquireSpinLock(&pAd->Mlme.TaskLock); |
| pAd->Mlme.bRunning = FALSE; |
| NdisReleaseSpinLock(&pAd->Mlme.TaskLock); |
| #endif // RTMP_MAC_PCI // |
| } |
| |
| /*! \brief test if the MLME Queue is empty |
| * \param *Queue The MLME Queue |
| * \return TRUE if the Queue is empty, FALSE otherwise |
| * \pre |
| * \post |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| BOOLEAN MlmeQueueEmpty( |
| IN MLME_QUEUE *Queue) |
| { |
| BOOLEAN Ans; |
| |
| NdisAcquireSpinLock(&(Queue->Lock)); |
| Ans = (Queue->Num == 0); |
| NdisReleaseSpinLock(&(Queue->Lock)); |
| |
| return Ans; |
| } |
| |
| /*! \brief test if the MLME Queue is full |
| * \param *Queue The MLME Queue |
| * \return TRUE if the Queue is empty, FALSE otherwise |
| * \pre |
| * \post |
| |
| IRQL = PASSIVE_LEVEL |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| BOOLEAN MlmeQueueFull( |
| IN MLME_QUEUE *Queue) |
| { |
| BOOLEAN Ans; |
| |
| NdisAcquireSpinLock(&(Queue->Lock)); |
| Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE || Queue->Entry[Queue->Tail].Occupied); |
| NdisReleaseSpinLock(&(Queue->Lock)); |
| |
| return Ans; |
| } |
| |
| /*! \brief The destructor of MLME Queue |
| * \param |
| * \return |
| * \pre |
| * \post |
| * \note Clear Mlme Queue, Set Queue->Num to Zero. |
| |
| IRQL = PASSIVE_LEVEL |
| |
| */ |
| VOID MlmeQueueDestroy( |
| IN MLME_QUEUE *pQueue) |
| { |
| NdisAcquireSpinLock(&(pQueue->Lock)); |
| pQueue->Num = 0; |
| pQueue->Head = 0; |
| pQueue->Tail = 0; |
| NdisReleaseSpinLock(&(pQueue->Lock)); |
| NdisFreeSpinLock(&(pQueue->Lock)); |
| } |
| |
| |
| /*! \brief To substitute the message type if the message is coming from external |
| * \param pFrame The frame received |
| * \param *Machine The state machine |
| * \param *MsgType the message type for the state machine |
| * \return TRUE if the substitution is successful, FALSE otherwise |
| * \pre |
| * \post |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| #ifdef CONFIG_STA_SUPPORT |
| BOOLEAN MsgTypeSubst( |
| IN PRTMP_ADAPTER pAd, |
| IN PFRAME_802_11 pFrame, |
| OUT INT *Machine, |
| OUT INT *MsgType) |
| { |
| USHORT Seq, Alg; |
| UCHAR EAPType; |
| PUCHAR pData; |
| |
| // Pointer to start of data frames including SNAP header |
| pData = (PUCHAR) pFrame + LENGTH_802_11; |
| |
| // The only data type will pass to this function is EAPOL frame |
| if (pFrame->Hdr.FC.Type == BTYPE_DATA) |
| { |
| { |
| *Machine = WPA_STATE_MACHINE; |
| EAPType = *((UCHAR*)pFrame + LENGTH_802_11 + LENGTH_802_1_H + 1); |
| return (WpaMsgTypeSubst(EAPType, (INT *) MsgType)); |
| } |
| } |
| |
| switch (pFrame->Hdr.FC.SubType) |
| { |
| case SUBTYPE_ASSOC_REQ: |
| *Machine = ASSOC_STATE_MACHINE; |
| *MsgType = MT2_PEER_ASSOC_REQ; |
| break; |
| case SUBTYPE_ASSOC_RSP: |
| *Machine = ASSOC_STATE_MACHINE; |
| *MsgType = MT2_PEER_ASSOC_RSP; |
| break; |
| case SUBTYPE_REASSOC_REQ: |
| *Machine = ASSOC_STATE_MACHINE; |
| *MsgType = MT2_PEER_REASSOC_REQ; |
| break; |
| case SUBTYPE_REASSOC_RSP: |
| *Machine = ASSOC_STATE_MACHINE; |
| *MsgType = MT2_PEER_REASSOC_RSP; |
| break; |
| case SUBTYPE_PROBE_REQ: |
| *Machine = SYNC_STATE_MACHINE; |
| *MsgType = MT2_PEER_PROBE_REQ; |
| break; |
| case SUBTYPE_PROBE_RSP: |
| *Machine = SYNC_STATE_MACHINE; |
| *MsgType = MT2_PEER_PROBE_RSP; |
| break; |
| case SUBTYPE_BEACON: |
| *Machine = SYNC_STATE_MACHINE; |
| *MsgType = MT2_PEER_BEACON; |
| break; |
| case SUBTYPE_ATIM: |
| *Machine = SYNC_STATE_MACHINE; |
| *MsgType = MT2_PEER_ATIM; |
| break; |
| case SUBTYPE_DISASSOC: |
| *Machine = ASSOC_STATE_MACHINE; |
| *MsgType = MT2_PEER_DISASSOC_REQ; |
| break; |
| case SUBTYPE_AUTH: |
| // get the sequence number from payload 24 Mac Header + 2 bytes algorithm |
| NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT)); |
| NdisMoveMemory(&Alg, &pFrame->Octet[0], sizeof(USHORT)); |
| if (Seq == 1 || Seq == 3) |
| { |
| *Machine = AUTH_RSP_STATE_MACHINE; |
| *MsgType = MT2_PEER_AUTH_ODD; |
| } |
| else if (Seq == 2 || Seq == 4) |
| { |
| if (Alg == AUTH_MODE_OPEN || Alg == AUTH_MODE_KEY) |
| { |
| *Machine = AUTH_STATE_MACHINE; |
| *MsgType = MT2_PEER_AUTH_EVEN; |
| } |
| } |
| else |
| { |
| return FALSE; |
| } |
| break; |
| case SUBTYPE_DEAUTH: |
| *Machine = AUTH_RSP_STATE_MACHINE; |
| *MsgType = MT2_PEER_DEAUTH; |
| break; |
| case SUBTYPE_ACTION: |
| *Machine = ACTION_STATE_MACHINE; |
| // Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support |
| if ((pFrame->Octet[0]&0x7F) > MAX_PEER_CATE_MSG) |
| { |
| *MsgType = MT2_ACT_INVALID; |
| } |
| else |
| { |
| *MsgType = (pFrame->Octet[0]&0x7F); |
| } |
| break; |
| default: |
| return FALSE; |
| break; |
| } |
| |
| return TRUE; |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| // =========================================================================================== |
| // state_machine.c |
| // =========================================================================================== |
| |
| /*! \brief Initialize the state machine. |
| * \param *S pointer to the state machine |
| * \param Trans State machine transition function |
| * \param StNr number of states |
| * \param MsgNr number of messages |
| * \param DefFunc default function, when there is invalid state/message combination |
| * \param InitState initial state of the state machine |
| * \param Base StateMachine base, internal use only |
| * \pre p_sm should be a legal pointer |
| * \post |
| |
| IRQL = PASSIVE_LEVEL |
| |
| */ |
| VOID StateMachineInit( |
| IN STATE_MACHINE *S, |
| IN STATE_MACHINE_FUNC Trans[], |
| IN ULONG StNr, |
| IN ULONG MsgNr, |
| IN STATE_MACHINE_FUNC DefFunc, |
| IN ULONG InitState, |
| IN ULONG Base) |
| { |
| ULONG i, j; |
| |
| // set number of states and messages |
| S->NrState = StNr; |
| S->NrMsg = MsgNr; |
| S->Base = Base; |
| |
| S->TransFunc = Trans; |
| |
| // init all state transition to default function |
| for (i = 0; i < StNr; i++) |
| { |
| for (j = 0; j < MsgNr; j++) |
| { |
| S->TransFunc[i * MsgNr + j] = DefFunc; |
| } |
| } |
| |
| // set the starting state |
| S->CurrState = InitState; |
| } |
| |
| /*! \brief This function fills in the function pointer into the cell in the state machine |
| * \param *S pointer to the state machine |
| * \param St state |
| * \param Msg incoming message |
| * \param f the function to be executed when (state, message) combination occurs at the state machine |
| * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state |
| * \post |
| |
| IRQL = PASSIVE_LEVEL |
| |
| */ |
| VOID StateMachineSetAction( |
| IN STATE_MACHINE *S, |
| IN ULONG St, |
| IN ULONG Msg, |
| IN STATE_MACHINE_FUNC Func) |
| { |
| ULONG MsgIdx; |
| |
| MsgIdx = Msg - S->Base; |
| |
| if (St < S->NrState && MsgIdx < S->NrMsg) |
| { |
| // boundary checking before setting the action |
| S->TransFunc[St * S->NrMsg + MsgIdx] = Func; |
| } |
| } |
| |
| /*! \brief This function does the state transition |
| * \param *Adapter the NIC adapter pointer |
| * \param *S the state machine |
| * \param *Elem the message to be executed |
| * \return None |
| |
| IRQL = DISPATCH_LEVEL |
| |
| */ |
| VOID StateMachinePerformAction( |
| IN PRTMP_ADAPTER pAd, |
| IN STATE_MACHINE *S, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))(pAd, Elem); |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| The drop function, when machine executes this, the message is simply |
| ignored. This function does nothing, the message is freed in |
| StateMachinePerformAction() |
| ========================================================================== |
| */ |
| VOID Drop( |
| IN PRTMP_ADAPTER pAd, |
| IN MLME_QUEUE_ELEM *Elem) |
| { |
| } |
| |
| // =========================================================================================== |
| // lfsr.c |
| // =========================================================================================== |
| |
| /* |
| ========================================================================== |
| Description: |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID LfsrInit( |
| IN PRTMP_ADAPTER pAd, |
| IN ULONG Seed) |
| { |
| if (Seed == 0) |
| pAd->Mlme.ShiftReg = 1; |
| else |
| pAd->Mlme.ShiftReg = Seed; |
| } |
| |
| /* |
| ========================================================================== |
| Description: |
| ========================================================================== |
| */ |
| UCHAR RandomByte( |
| IN PRTMP_ADAPTER pAd) |
| { |
| ULONG i; |
| UCHAR R, Result; |
| |
| R = 0; |
| |
| if (pAd->Mlme.ShiftReg == 0) |
| NdisGetSystemUpTime((ULONG *)&pAd->Mlme.ShiftReg); |
| |
| for (i = 0; i < 8; i++) |
| { |
| if (pAd->Mlme.ShiftReg & 0x00000001) |
| { |
| pAd->Mlme.ShiftReg = ((pAd->Mlme.ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000; |
| Result = 1; |
| } |
| else |
| { |
| pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1; |
| Result = 0; |
| } |
| R = (R << 1) | Result; |
| } |
| |
| return R; |
| } |
| |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Verify the support rate for different PHY type |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| None |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ======================================================================== |
| */ |
| VOID RTMPCheckRates( |
| IN PRTMP_ADAPTER pAd, |
| IN OUT UCHAR SupRate[], |
| IN OUT UCHAR *SupRateLen) |
| { |
| UCHAR RateIdx, i, j; |
| UCHAR NewRate[12], NewRateLen; |
| |
| NewRateLen = 0; |
| |
| if (pAd->CommonCfg.PhyMode == PHY_11B) |
| RateIdx = 4; |
| else |
| RateIdx = 12; |
| |
| // Check for support rates exclude basic rate bit |
| for (i = 0; i < *SupRateLen; i++) |
| for (j = 0; j < RateIdx; j++) |
| if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) |
| NewRate[NewRateLen++] = SupRate[i]; |
| |
| *SupRateLen = NewRateLen; |
| NdisMoveMemory(SupRate, NewRate, NewRateLen); |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| #ifdef DOT11_N_SUPPORT |
| BOOLEAN RTMPCheckChannel( |
| IN PRTMP_ADAPTER pAd, |
| IN UCHAR CentralChannel, |
| IN UCHAR Channel) |
| { |
| UCHAR k; |
| UCHAR UpperChannel = 0, LowerChannel = 0; |
| UCHAR NoEffectChannelinList = 0; |
| |
| // Find upper and lower channel according to 40MHz current operation. |
| if (CentralChannel < Channel) |
| { |
| UpperChannel = Channel; |
| if (CentralChannel > 2) |
| LowerChannel = CentralChannel - 2; |
| else |
| return FALSE; |
| } |
| else if (CentralChannel > Channel) |
| { |
| UpperChannel = CentralChannel + 2; |
| LowerChannel = Channel; |
| } |
| |
| for (k = 0;k < pAd->ChannelListNum;k++) |
| { |
| if (pAd->ChannelList[k].Channel == UpperChannel) |
| { |
| NoEffectChannelinList ++; |
| } |
| if (pAd->ChannelList[k].Channel == LowerChannel) |
| { |
| NoEffectChannelinList ++; |
| } |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE,("Total Channel in Channel List = [%d]\n", NoEffectChannelinList)); |
| if (NoEffectChannelinList == 2) |
| return TRUE; |
| else |
| return FALSE; |
| } |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Verify the support rate for HT phy type |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode) |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ======================================================================== |
| */ |
| BOOLEAN RTMPCheckHt( |
| IN PRTMP_ADAPTER pAd, |
| IN UCHAR Wcid, |
| IN HT_CAPABILITY_IE *pHtCapability, |
| IN ADD_HT_INFO_IE *pAddHtInfo) |
| { |
| if (Wcid >= MAX_LEN_OF_MAC_TABLE) |
| return FALSE; |
| |
| // If use AMSDU, set flag. |
| if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable) |
| CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_AMSDU_INUSED); |
| // Save Peer Capability |
| if (pHtCapability->HtCapInfo.ShortGIfor20) |
| CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI20_CAPABLE); |
| if (pHtCapability->HtCapInfo.ShortGIfor40) |
| CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_SGI40_CAPABLE); |
| if (pHtCapability->HtCapInfo.TxSTBC) |
| CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_TxSTBC_CAPABLE); |
| if (pHtCapability->HtCapInfo.RxSTBC) |
| CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RxSTBC_CAPABLE); |
| if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) |
| { |
| CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid], fCLIENT_STATUS_RDG_CAPABLE); |
| } |
| |
| if (Wcid < MAX_LEN_OF_MAC_TABLE) |
| { |
| pAd->MacTab.Content[Wcid].MpduDensity = pHtCapability->HtCapParm.MpduDensity; |
| } |
| |
| // Will check ChannelWidth for MCSSet[4] below |
| pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1; |
| switch (pAd->CommonCfg.RxStream) |
| { |
| case 1: |
| pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; |
| pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00; |
| pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; |
| pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; |
| break; |
| case 2: |
| pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; |
| pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; |
| pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00; |
| pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; |
| break; |
| case 3: |
| pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff; |
| pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff; |
| pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff; |
| pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00; |
| break; |
| } |
| |
| pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth = pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.ChannelWidth; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n", |
| pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth, pAddHtInfo->AddHtInfo.RecomWidth, pAd->CommonCfg.DesiredHtPhy.ChannelWidth, |
| pAd->NicConfig2.field.BW40MAvailForA, pAd->NicConfig2.field.BW40MAvailForG, pAd->CommonCfg.PhyMode)); |
| |
| pAd->MlmeAux.HtCapability.HtCapInfo.GF = pHtCapability->HtCapInfo.GF &pAd->CommonCfg.DesiredHtPhy.GF; |
| |
| // Send Assoc Req with my HT capability. |
| pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize = pAd->CommonCfg.DesiredHtPhy.AmsduSize; |
| pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs = pAd->CommonCfg.DesiredHtPhy.MimoPs; |
| pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->HtCapInfo.ShortGIfor20); |
| pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 = (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->HtCapInfo.ShortGIfor40); |
| pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC = (pAd->CommonCfg.DesiredHtPhy.TxSTBC)&(pHtCapability->HtCapInfo.RxSTBC); |
| pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC = (pAd->CommonCfg.DesiredHtPhy.RxSTBC)&(pHtCapability->HtCapInfo.TxSTBC); |
| pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor = pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor; |
| pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity = pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity; |
| pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; |
| pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC = pHtCapability->ExtHtCapInfo.PlusHTC; |
| if (pAd->CommonCfg.bRdg) |
| { |
| pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport = pHtCapability->ExtHtCapInfo.RDGSupport; |
| pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1; |
| } |
| |
| if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20) |
| pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32 |
| |
| COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability); |
| return TRUE; |
| } |
| #endif // DOT11_N_SUPPORT // |
| #endif // CONFIG_STA_SUPPORT // |
| |
| /* |
| ======================================================================== |
| |
| Routine Description: |
| Verify the support rate for different PHY type |
| |
| Arguments: |
| pAd Pointer to our adapter |
| |
| Return Value: |
| None |
| |
| IRQL = PASSIVE_LEVEL |
| |
| ======================================================================== |
| */ |
| VOID RTMPUpdateMlmeRate( |
| IN PRTMP_ADAPTER pAd) |
| { |
| UCHAR MinimumRate; |
| UCHAR ProperMlmeRate; //= RATE_54; |
| UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 |
| BOOLEAN bMatch = FALSE; |
| |
| switch (pAd->CommonCfg.PhyMode) |
| { |
| case PHY_11B: |
| ProperMlmeRate = RATE_11; |
| MinimumRate = RATE_1; |
| break; |
| case PHY_11BG_MIXED: |
| #ifdef DOT11_N_SUPPORT |
| case PHY_11ABGN_MIXED: |
| case PHY_11BGN_MIXED: |
| #endif // DOT11_N_SUPPORT // |
| if ((pAd->MlmeAux.SupRateLen == 4) && |
| (pAd->MlmeAux.ExtRateLen == 0)) |
| // B only AP |
| ProperMlmeRate = RATE_11; |
| else |
| ProperMlmeRate = RATE_24; |
| |
| if (pAd->MlmeAux.Channel <= 14) |
| MinimumRate = RATE_1; |
| else |
| MinimumRate = RATE_6; |
| break; |
| case PHY_11A: |
| #ifdef DOT11_N_SUPPORT |
| case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n |
| case PHY_11GN_MIXED: |
| case PHY_11AGN_MIXED: |
| case PHY_11AN_MIXED: |
| case PHY_11N_5G: |
| #endif // DOT11_N_SUPPORT // |
| ProperMlmeRate = RATE_24; |
| MinimumRate = RATE_6; |
| break; |
| case PHY_11ABG_MIXED: |
| ProperMlmeRate = RATE_24; |
| if (pAd->MlmeAux.Channel <= 14) |
| MinimumRate = RATE_1; |
| else |
| MinimumRate = RATE_6; |
| break; |
| default: // error |
| ProperMlmeRate = RATE_1; |
| MinimumRate = RATE_1; |
| break; |
| } |
| |
| for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) |
| { |
| for (j = 0; j < RateIdx; j++) |
| { |
| if ((pAd->MlmeAux.SupRate[i] & 0x7f) == RateIdTo500Kbps[j]) |
| { |
| if (j == ProperMlmeRate) |
| { |
| bMatch = TRUE; |
| break; |
| } |
| } |
| } |
| |
| if (bMatch) |
| break; |
| } |
| |
| if (bMatch == FALSE) |
| { |
| for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) |
| { |
| for (j = 0; j < RateIdx; j++) |
| { |
| if ((pAd->MlmeAux.ExtRate[i] & 0x7f) == RateIdTo500Kbps[j]) |
| { |
| if (j == ProperMlmeRate) |
| { |
| bMatch = TRUE; |
| break; |
| } |
| } |
| } |
| |
| if (bMatch) |
| break; |
| } |
| } |
| |
| if (bMatch == FALSE) |
| { |
| ProperMlmeRate = MinimumRate; |
| } |
| |
| pAd->CommonCfg.MlmeRate = MinimumRate; |
| pAd->CommonCfg.RtsRate = ProperMlmeRate; |
| if (pAd->CommonCfg.MlmeRate >= RATE_6) |
| { |
| pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM; |
| pAd->CommonCfg.MlmeTransmit.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; |
| pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_OFDM; |
| pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate]; |
| } |
| else |
| { |
| pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK; |
| pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate; |
| pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE = MODE_CCK; |
| pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS = pAd->CommonCfg.MlmeRate; |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n" , pAd->CommonCfg.MlmeTransmit.word)); |
| } |
| |
| CHAR RTMPMaxRssi( |
| IN PRTMP_ADAPTER pAd, |
| IN CHAR Rssi0, |
| IN CHAR Rssi1, |
| IN CHAR Rssi2) |
| { |
| CHAR larger = -127; |
| |
| if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) |
| { |
| larger = Rssi0; |
| } |
| |
| if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) |
| { |
| larger = max(Rssi0, Rssi1); |
| } |
| |
| if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) |
| { |
| larger = max(larger, Rssi2); |
| } |
| |
| if (larger == -127) |
| larger = 0; |
| |
| return larger; |
| } |
| |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Periodic evaluate antenna link status |
| |
| Arguments: |
| pAd - Adapter pointer |
| |
| Return Value: |
| None |
| |
| ======================================================================== |
| */ |
| VOID AsicEvaluateRxAnt( |
| IN PRTMP_ADAPTER pAd) |
| { |
| #ifdef CONFIG_STA_SUPPORT |
| UCHAR BBPR3 = 0; |
| #endif // CONFIG_STA_SUPPORT // |
| |
| #ifdef RALINK_ATE |
| if (ATE_ON(pAd)) |
| return; |
| #endif // RALINK_ATE // |
| |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_RADIO_OFF | |
| fRTMP_ADAPTER_NIC_NOT_EXIST | |
| fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) || |
| OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) |
| #ifdef RT3090 |
| || (pAd->bPCIclkOff == TRUE) |
| #endif // RT3090 // |
| #ifdef ANT_DIVERSITY_SUPPORT |
| || (pAd->EepromAccess) |
| #endif // ANT_DIVERSITY_SUPPORT // |
| ) |
| return; |
| |
| #ifdef ANT_DIVERSITY_SUPPORT |
| if ((pAd->NicConfig2.field.AntDiversity) && (pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_ENABLE)) |
| { |
| // two antenna selection mechanism- one is antenna diversity, the other is failed antenna remove |
| // one is antenna diversity:there is only one antenna can rx and tx |
| // the other is failed antenna remove:two physical antenna can rx and tx |
| DBGPRINT(RT_DEBUG_TRACE,("AntDiv - before evaluate Pair1-Ant (%d,%d)\n", |
| pAd->RxAnt.Pair1PrimaryRxAnt, pAd->RxAnt.Pair1SecondaryRxAnt)); |
| |
| AsicSetRxAnt(pAd, pAd->RxAnt.Pair1SecondaryRxAnt); |
| |
| pAd->RxAnt.EvaluatePeriod = 1; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt |
| pAd->RxAnt.FirstPktArrivedWhenEvaluate = FALSE; |
| pAd->RxAnt.RcvPktNumWhenEvaluate = 0; |
| |
| // a one-shot timer to end the evalution |
| // dynamic adjust antenna evaluation period according to the traffic |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) |
| RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 100); |
| else |
| RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); |
| } |
| else |
| #endif // ANT_DIVERSITY_SUPPORT // |
| { |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| |
| if (pAd->StaCfg.Psm == PWR_SAVE) |
| return; |
| |
| RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); |
| BBPR3 &= (~0x18); |
| if(pAd->Antenna.field.RxPath == 3) |
| { |
| BBPR3 |= (0x10); |
| } |
| else if(pAd->Antenna.field.RxPath == 2) |
| { |
| BBPR3 |= (0x8); |
| } |
| else if(pAd->Antenna.field.RxPath == 1) |
| { |
| BBPR3 |= (0x0); |
| } |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); |
| #ifdef RTMP_MAC_PCI |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| pAd->StaCfg.BBPR3 = BBPR3; |
| #endif // RTMP_MAC_PCI // |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) |
| ) |
| { |
| ULONG TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + |
| pAd->RalinkCounters.OneSecTxRetryOkCount + |
| pAd->RalinkCounters.OneSecTxFailCount; |
| |
| // dynamic adjust antenna evaluation period according to the traffic |
| if (TxTotalCnt > 50) |
| { |
| RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 20); |
| pAd->Mlme.bLowThroughput = FALSE; |
| } |
| else |
| { |
| RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer, 300); |
| pAd->Mlme.bLowThroughput = TRUE; |
| } |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| } |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| After evaluation, check antenna link status |
| |
| Arguments: |
| pAd - Adapter pointer |
| |
| Return Value: |
| None |
| |
| ======================================================================== |
| */ |
| VOID AsicRxAntEvalTimeout( |
| IN PVOID SystemSpecific1, |
| IN PVOID FunctionContext, |
| IN PVOID SystemSpecific2, |
| IN PVOID SystemSpecific3) |
| { |
| RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; |
| BOOLEAN bSwapAnt = FALSE; |
| #ifdef CONFIG_STA_SUPPORT |
| UCHAR BBPR3 = 0; |
| CHAR larger = -127, rssi0, rssi1, rssi2; |
| #endif // CONFIG_STA_SUPPORT // |
| |
| #ifdef RALINK_ATE |
| if (ATE_ON(pAd)) |
| return; |
| #endif // RALINK_ATE // |
| |
| if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS | |
| fRTMP_ADAPTER_HALT_IN_PROGRESS | |
| fRTMP_ADAPTER_RADIO_OFF | |
| fRTMP_ADAPTER_NIC_NOT_EXIST) || |
| OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE) |
| #ifdef RT3090 |
| || (pAd->bPCIclkOff == TRUE) |
| #endif // RT3090 // |
| #ifdef ANT_DIVERSITY_SUPPORT |
| || (pAd->EepromAccess) |
| #endif // ANT_DIVERSITY_SUPPORT // |
| ) |
| return; |
| |
| #ifdef ANT_DIVERSITY_SUPPORT |
| if ((pAd->NicConfig2.field.AntDiversity) && (pAd->CommonCfg.bRxAntDiversity == ANT_DIVERSITY_ENABLE)) |
| { |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| if ((pAd->RxAnt.RcvPktNumWhenEvaluate != 0) && (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >= pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1PrimaryRxAnt])) |
| bSwapAnt = TRUE; |
| #endif // CONFIG_STA_SUPPORT // |
| if (bSwapAnt == TRUE) |
| { |
| UCHAR temp; |
| |
| // |
| // select PrimaryRxAntPair |
| // Role change, Used Pair1SecondaryRxAnt as PrimaryRxAntPair. |
| // Since Pair1SecondaryRxAnt Quality good than Pair1PrimaryRxAnt |
| // |
| temp = pAd->RxAnt.Pair1PrimaryRxAnt; |
| pAd->RxAnt.Pair1PrimaryRxAnt = pAd->RxAnt.Pair1SecondaryRxAnt; |
| pAd->RxAnt.Pair1SecondaryRxAnt = temp; |
| |
| #ifdef CONFIG_STA_SUPPORT |
| pAd->RxAnt.Pair1LastAvgRssi = (pAd->RxAnt.Pair1AvgRssi[pAd->RxAnt.Pair1SecondaryRxAnt] >> 3); |
| #endif // CONFIG_STA_SUPPORT // |
| // pAd->RxAnt.EvaluateStableCnt = 0; |
| } |
| else |
| { |
| // if the evaluated antenna is not better than original, switch back to original antenna |
| AsicSetRxAnt(pAd, pAd->RxAnt.Pair1PrimaryRxAnt); |
| pAd->RxAnt.EvaluateStableCnt ++; |
| } |
| |
| pAd->RxAnt.EvaluatePeriod = 0; // 1:Means switch to SecondaryRxAnt, 0:Means switch to Pair1PrimaryRxAnt |
| |
| #ifdef CONFIG_STA_SUPPORT |
| DBGPRINT(RT_DEBUG_TRACE,("AsicRxAntEvalAction::After Eval(fix in #%d), <%d, %d>, RcvPktNumWhenEvaluate=%ld\n", |
| pAd->RxAnt.Pair1PrimaryRxAnt, (pAd->RxAnt.Pair1AvgRssi[0] >> 3), (pAd->RxAnt.Pair1AvgRssi[1] >> 3), pAd->RxAnt.RcvPktNumWhenEvaluate)); |
| #endif // CONFIG_STA_SUPPORT // |
| } |
| else |
| #endif // ANT_DIVERSITY_SUPPORT // |
| { |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| if (pAd->StaCfg.Psm == PWR_SAVE) |
| return; |
| |
| |
| // if the traffic is low, use average rssi as the criteria |
| if (pAd->Mlme.bLowThroughput == TRUE) |
| { |
| rssi0 = pAd->StaCfg.RssiSample.LastRssi0; |
| rssi1 = pAd->StaCfg.RssiSample.LastRssi1; |
| rssi2 = pAd->StaCfg.RssiSample.LastRssi2; |
| } |
| else |
| { |
| rssi0 = pAd->StaCfg.RssiSample.AvgRssi0; |
| rssi1 = pAd->StaCfg.RssiSample.AvgRssi1; |
| rssi2 = pAd->StaCfg.RssiSample.AvgRssi2; |
| } |
| |
| if(pAd->Antenna.field.RxPath == 3) |
| { |
| larger = max(rssi0, rssi1); |
| |
| if (larger > (rssi2 + 20)) |
| pAd->Mlme.RealRxPath = 2; |
| else |
| pAd->Mlme.RealRxPath = 3; |
| } |
| else if(pAd->Antenna.field.RxPath == 2) |
| { |
| if (rssi0 > (rssi1 + 20)) |
| pAd->Mlme.RealRxPath = 1; |
| else |
| pAd->Mlme.RealRxPath = 2; |
| } |
| |
| RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3); |
| BBPR3 &= (~0x18); |
| if(pAd->Mlme.RealRxPath == 3) |
| { |
| BBPR3 |= (0x10); |
| } |
| else if(pAd->Mlme.RealRxPath == 2) |
| { |
| BBPR3 |= (0x8); |
| } |
| else if(pAd->Mlme.RealRxPath == 1) |
| { |
| BBPR3 |= (0x0); |
| } |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3); |
| #ifdef RTMP_MAC_PCI |
| pAd->StaCfg.BBPR3 = BBPR3; |
| #endif // RTMP_MAC_PCI // |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| } |
| } |
| |
| |
| VOID APSDPeriodicExec( |
| IN PVOID SystemSpecific1, |
| IN PVOID FunctionContext, |
| IN PVOID SystemSpecific2, |
| IN PVOID SystemSpecific3) |
| { |
| RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; |
| |
| if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) |
| return; |
| |
| pAd->CommonCfg.TriggerTimerCount++; |
| |
| // Driver should not send trigger frame, it should be send by application layer |
| /* |
| if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable |
| && (pAd->CommonCfg.bNeedSendTriggerFrame || |
| (((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO)))) |
| { |
| DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n")); |
| RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE); |
| pAd->CommonCfg.bNeedSendTriggerFrame = FALSE; |
| pAd->CommonCfg.TriggerTimerCount = 0; |
| pAd->CommonCfg.bInServicePeriod = TRUE; |
| }*/ |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Set/reset MAC registers according to bPiggyBack parameter |
| |
| Arguments: |
| pAd - Adapter pointer |
| bPiggyBack - Enable / Disable Piggy-Back |
| |
| Return Value: |
| None |
| |
| ======================================================================== |
| */ |
| VOID RTMPSetPiggyBack( |
| IN PRTMP_ADAPTER pAd, |
| IN BOOLEAN bPiggyBack) |
| { |
| TX_LINK_CFG_STRUC TxLinkCfg; |
| |
| RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word); |
| |
| TxLinkCfg.field.TxCFAckEn = bPiggyBack; |
| RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word); |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| check if this entry need to switch rate automatically |
| |
| Arguments: |
| pAd |
| pEntry |
| |
| Return Value: |
| TURE |
| FALSE |
| |
| ======================================================================== |
| */ |
| BOOLEAN RTMPCheckEntryEnableAutoRateSwitch( |
| IN PRTMP_ADAPTER pAd, |
| IN PMAC_TABLE_ENTRY pEntry) |
| { |
| BOOLEAN result = TRUE; |
| |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| // only associated STA counts |
| if (pEntry && (pEntry->ValidAsCLI) && (pEntry->Sst == SST_ASSOC)) |
| { |
| result = pAd->StaCfg.bAutoTxRateSwitch; |
| } |
| else |
| result = FALSE; |
| |
| #ifdef QOS_DLS_SUPPORT |
| if (pEntry && (pEntry->ValidAsDls)) |
| result = pAd->StaCfg.bAutoTxRateSwitch; |
| #endif // QOS_DLS_SUPPORT // |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| |
| |
| return result; |
| } |
| |
| |
| BOOLEAN RTMPAutoRateSwitchCheck( |
| IN PRTMP_ADAPTER pAd) |
| { |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| if (pAd->StaCfg.bAutoTxRateSwitch) |
| return TRUE; |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| return FALSE; |
| } |
| |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| check if this entry need to fix tx legacy rate |
| |
| Arguments: |
| pAd |
| pEntry |
| |
| Return Value: |
| TURE |
| FALSE |
| |
| ======================================================================== |
| */ |
| UCHAR RTMPStaFixedTxMode( |
| IN PRTMP_ADAPTER pAd, |
| IN PMAC_TABLE_ENTRY pEntry) |
| { |
| UCHAR tx_mode = FIXED_TXMODE_HT; |
| |
| |
| #ifdef CONFIG_STA_SUPPORT |
| IF_DEV_CONFIG_OPMODE_ON_STA(pAd) |
| { |
| tx_mode = (UCHAR)pAd->StaCfg.DesiredTransmitSetting.field.FixedTxMode; |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| return tx_mode; |
| } |
| |
| /* |
| ======================================================================== |
| Routine Description: |
| Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified. |
| |
| Arguments: |
| pAd |
| pEntry |
| |
| Return Value: |
| TURE |
| FALSE |
| |
| ======================================================================== |
| */ |
| VOID RTMPUpdateLegacyTxSetting( |
| UCHAR fixed_tx_mode, |
| PMAC_TABLE_ENTRY pEntry) |
| { |
| HTTRANSMIT_SETTING TransmitSetting; |
| |
| if (fixed_tx_mode == FIXED_TXMODE_HT) |
| return; |
| |
| TransmitSetting.word = 0; |
| |
| TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE; |
| TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS; |
| |
| if (fixed_tx_mode == FIXED_TXMODE_CCK) |
| { |
| TransmitSetting.field.MODE = MODE_CCK; |
| // CCK mode allow MCS 0~3 |
| if (TransmitSetting.field.MCS > MCS_3) |
| TransmitSetting.field.MCS = MCS_3; |
| } |
| else |
| { |
| TransmitSetting.field.MODE = MODE_OFDM; |
| // OFDM mode allow MCS 0~7 |
| if (TransmitSetting.field.MCS > MCS_7) |
| TransmitSetting.field.MCS = MCS_7; |
| } |
| |
| if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) |
| { |
| pEntry->HTPhyMode.word = TransmitSetting.word; |
| DBGPRINT(RT_DEBUG_TRACE, ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n", |
| pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE), pEntry->HTPhyMode.field.MCS)); |
| } |
| } |
| |
| #ifdef CONFIG_STA_SUPPORT |
| /* |
| ========================================================================== |
| Description: |
| dynamic tune BBP R66 to find a balance between sensibility and |
| noise isolation |
| |
| IRQL = DISPATCH_LEVEL |
| |
| ========================================================================== |
| */ |
| VOID AsicStaBbpTuning( |
| IN PRTMP_ADAPTER pAd) |
| { |
| UCHAR OrigR66Value = 0, R66;//, R66UpperBound = 0x30, R66LowerBound = 0x30; |
| CHAR Rssi; |
| |
| // 2860C did not support Fase CCA, therefore can't tune |
| if (pAd->MACVersion == 0x28600100) |
| return; |
| |
| // |
| // work as a STA |
| // |
| if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING |
| return; |
| |
| if ((pAd->OpMode == OPMODE_STA) |
| && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) |
| ) |
| && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) |
| #ifdef RTMP_MAC_PCI |
| && (pAd->bPCIclkOff == FALSE) |
| #endif // RTMP_MAC_PCI // |
| ) |
| { |
| RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value); |
| R66 = OrigR66Value; |
| |
| if (pAd->Antenna.field.RxPath > 1) |
| Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; |
| else |
| Rssi = pAd->StaCfg.RssiSample.AvgRssi0; |
| |
| if (pAd->LatchRfRegs.Channel <= 14) |
| { //BG band |
| #ifdef RT30xx |
| // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control |
| // Otherwise, it will have some throughput side effect when low RSSI |
| |
| if (IS_RT3070(pAd)||IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
| { |
| if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) |
| { |
| R66 = 0x1C + 2*GET_LNA_GAIN(pAd) + 0x20; |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| else |
| { |
| R66 = 0x1C + 2*GET_LNA_GAIN(pAd); |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| } |
| else |
| #endif // RT30xx // |
| { |
| if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) |
| { |
| R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10; |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| else |
| { |
| R66 = 0x2E + GET_LNA_GAIN(pAd); |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| } |
| } |
| else |
| { //A band |
| if (pAd->CommonCfg.BBPCurrentBW == BW_20) |
| { |
| if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) |
| { |
| R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| else |
| { |
| R66 = 0x32 + (GET_LNA_GAIN(pAd)*5)/3; |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| } |
| else |
| { |
| if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) |
| { |
| R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3 + 0x10; |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| else |
| { |
| R66 = 0x3A + (GET_LNA_GAIN(pAd)*5)/3; |
| if (OrigR66Value != R66) |
| { |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| } |
| } |
| |
| |
| } |
| } |
| #endif // CONFIG_STA_SUPPORT // |
| |
| VOID RTMPSetAGCInitValue( |
| IN PRTMP_ADAPTER pAd, |
| IN UCHAR BandWidth) |
| { |
| UCHAR R66 = 0x30; |
| |
| if (pAd->LatchRfRegs.Channel <= 14) |
| { // BG band |
| #ifdef RT30xx |
| /* Gary was verified Amazon AP and find that RT307x has BBP_R66 invalid default value */ |
| |
| if (IS_RT3070(pAd)||IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) |
| { |
| R66 = 0x1C + 2*GET_LNA_GAIN(pAd); |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| else |
| #endif // RT30xx // |
| { |
| R66 = 0x2E + GET_LNA_GAIN(pAd); |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| } |
| else |
| { //A band |
| { |
| if (BandWidth == BW_20) |
| { |
| R66 = (UCHAR)(0x32 + (GET_LNA_GAIN(pAd)*5)/3); |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| #ifdef DOT11_N_SUPPORT |
| else |
| { |
| R66 = (UCHAR)(0x3A + (GET_LNA_GAIN(pAd)*5)/3); |
| RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66); |
| } |
| #endif // DOT11_N_SUPPORT // |
| } |
| } |
| |
| } |