| /* |
| ************************************************************************* |
| * 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 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}; |
| UCHAR PRE_N_HT_OUI[] = {0x00, 0x90, 0x4c}; |
| |
| 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, |
| }; |
| |
| 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) |
| 0x09, 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, 0x21, 5, 10, 25, |
| 0x06, 0x21, 6, 8, 14, |
| 0x07, 0x21, 7, 8, 14, |
| 0x08, 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) |
| 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, 12, 15, 30, |
| 0x06, 0x20, 13, 8, 20, |
| 0x07, 0x20, 14, 8, 20, |
| 0x08, 0x20, 15, 8, 25, |
| 0x09, 0x22, 15, 8, 25, |
| }; |
| |
| 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) |
| 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, 12, 15, 30, |
| 0x06, 0x20, 13, 8, 20, |
| 0x07, 0x20, 14, 8, 20, |
| 0x08, 0x20, 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) |
| 0x0d, 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,101, //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, 14, |
| 0x0b, 0x21, 7, 8, 14, |
| 0x0c, 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) |
| 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, 15, 50, |
| 0x04, 0x21, 4, 15, 30, |
| 0x05, 0x20, 12, 15, 30, |
| 0x06, 0x20, 13, 8, 20, |
| 0x07, 0x20, 14, 8, 20, |
| 0x08, 0x20, 15, 8, 25, |
| 0x09, 0x22, 15, 8, 25, |
| }; |
| |
| 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, |
| }; |
| |
| PUCHAR ReasonString[] = { |
| /* 0 */ "Reserved", |
| /* 1 */ "Unspecified Reason", |
| /* 2 */ "Previous Auth no longer valid", |
| /* 3 */ "STA is leaving / has left", |
| /* 4 */ "DIS-ASSOC due to inactivity", |
| /* 5 */ "AP unable to hanle all associations", |
| /* 6 */ "class 2 error", |
| /* 7 */ "class 3 error", |
| /* 8 */ "STA is leaving / has left", |
| /* 9 */ "require auth before assoc/re-assoc", |
| /* 10 */ "Reserved", |
| /* 11 */ "Reserved", |
| /* 12 */ "Reserved", |
| /* 13 */ "invalid IE", |
| /* 14 */ "MIC error", |
| /* 15 */ "4-way handshake timeout", |
| /* 16 */ "2-way (group key) handshake timeout", |
| /* 17 */ "4-way handshake IE diff among AssosReq/Rsp/Beacon", |
| /* 18 */ |
| }; |
| |
| 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 MULTICAST_ADDR[MAC_ADDR_LEN] = {0x1, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| 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; |
| UCHAR HtCapIe = IE_HT_CAP; |
| UCHAR AddHtInfoIe = IE_ADD_HT; |
| UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET; |
| 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; |
| |
| 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}; |
| |
| // Reset the RFIC setting to new series |
| RTMP_RF_REGS RF2850RegTable[] = { |
| // ch R1 R2 R3(TX0~4=0) R4 |
| {1, 0x98402ecc, 0x984c0786, 0x9816b455, 0x9800510b}, |
| {2, 0x98402ecc, 0x984c0786, 0x98168a55, 0x9800519f}, |
| {3, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800518b}, |
| {4, 0x98402ecc, 0x984c078a, 0x98168a55, 0x9800519f}, |
| {5, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800518b}, |
| {6, 0x98402ecc, 0x984c078e, 0x98168a55, 0x9800519f}, |
| {7, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800518b}, |
| {8, 0x98402ecc, 0x984c0792, 0x98168a55, 0x9800519f}, |
| {9, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800518b}, |
| {10, 0x98402ecc, 0x984c0796, 0x98168a55, 0x9800519f}, |
| {11, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800518b}, |
| {12, 0x98402ecc, 0x984c079a, 0x98168a55, 0x9800519f}, |
| {13, 0x98402ecc, 0x984c079e, 0x98168a55, 0x9800518b}, |
| {14, 0x98402ecc, 0x984c07a2, 0x98168a55, 0x98005193}, |
| |
| // 802.11 UNI / HyperLan 2 |
| {36, 0x98402ecc, 0x984c099a, 0x98158a55, 0x980ed1a3}, |
| {38, 0x98402ecc, 0x984c099e, 0x98158a55, 0x980ed193}, |
| {40, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed183}, |
| {44, 0x98402ec8, 0x984c0682, 0x98158a55, 0x980ed1a3}, |
| {46, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed18b}, |
| {48, 0x98402ec8, 0x984c0686, 0x98158a55, 0x980ed19b}, |
| {52, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed193}, |
| {54, 0x98402ec8, 0x984c068a, 0x98158a55, 0x980ed1a3}, |
| {56, 0x98402ec8, 0x984c068e, 0x98158a55, 0x980ed18b}, |
| {60, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed183}, |
| {62, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed193}, |
| {64, 0x98402ec8, 0x984c0692, 0x98158a55, 0x980ed1a3}, // Plugfest#4, Day4, change RFR3 left4th 9->5. |
| |
| // 802.11 HyperLan 2 |
| {100, 0x98402ec8, 0x984c06b2, 0x98178a55, 0x980ed783}, |
| |
| // 2008.04.30 modified |
| // The system team has AN to improve the EVM value |
| // for channel 102 to 108 for the RT2850/RT2750 dual band solution. |
| {102, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed793}, |
| {104, 0x98402ec8, 0x985c06b2, 0x98578a55, 0x980ed1a3}, |
| {108, 0x98402ecc, 0x985c0a32, 0x98578a55, 0x980ed193}, |
| |
| {110, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed183}, |
| {112, 0x98402ecc, 0x984c0a36, 0x98178a55, 0x980ed19b}, |
| {116, 0x98402ecc, 0x984c0a3a, 0x98178a55, 0x980ed1a3}, |
| {118, 0x98402ecc, 0x984c0a3e, 0x98178a55, 0x980ed193}, |
| {120, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed183}, |
| {124, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed193}, |
| {126, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed15b}, // 0x980ed1bb->0x980ed15b required by Rory 20070927 |
| {128, 0x98402ec4, 0x984c0382, 0x98178a55, 0x980ed1a3}, |
| {132, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed18b}, |
| {134, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed193}, |
| {136, 0x98402ec4, 0x984c0386, 0x98178a55, 0x980ed19b}, |
| {140, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed183}, |
| |
| // 802.11 UNII |
| {149, 0x98402ec4, 0x984c038a, 0x98178a55, 0x980ed1a7}, |
| {151, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed187}, |
| {153, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed18f}, |
| {157, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed19f}, |
| {159, 0x98402ec4, 0x984c038e, 0x98178a55, 0x980ed1a7}, |
| {161, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed187}, |
| {165, 0x98402ec4, 0x984c0392, 0x98178a55, 0x980ed197}, |
| |
| // Japan |
| {184, 0x95002ccc, 0x9500491e, 0x9509be55, 0x950c0a0b}, |
| {188, 0x95002ccc, 0x95004922, 0x9509be55, 0x950c0a13}, |
| {192, 0x95002ccc, 0x95004926, 0x9509be55, 0x950c0a1b}, |
| {196, 0x95002ccc, 0x9500492a, 0x9509be55, 0x950c0a23}, |
| {208, 0x95002ccc, 0x9500493a, 0x9509be55, 0x950c0a13}, |
| {212, 0x95002ccc, 0x9500493e, 0x9509be55, 0x950c0a1b}, |
| {216, 0x95002ccc, 0x95004982, 0x9509be55, 0x950c0a23}, |
| |
| // still lack of MMAC(Japan) ch 34,38,42,46 |
| }; |
| UCHAR NUM_OF_2850_CHNL = (sizeof(RF2850RegTable) / sizeof(RTMP_RF_REGS)); |
| |
| FREQUENCY_ITEM FreqItems3020[] = |
| { |
| /**************************************************/ |
| // ISM : 2.4 to 2.483 GHz // |
| /**************************************************/ |
| // 11g |
| /**************************************************/ |
| //-CH---N-------R---K----------- |
| {1, 241, 2, 2}, |
| {2, 241, 2, 7}, |
| {3, 242, 2, 2}, |
| {4, 242, 2, 7}, |
| {5, 243, 2, 2}, |
| {6, 243, 2, 7}, |
| {7, 244, 2, 2}, |
| {8, 244, 2, 7}, |
| {9, 245, 2, 2}, |
| {10, 245, 2, 7}, |
| {11, 246, 2, 2}, |
| {12, 246, 2, 7}, |
| {13, 247, 2, 2}, |
| {14, 248, 2, 4}, |
| }; |
| UCHAR NUM_OF_3020_CHNL=(sizeof(FreqItems3020) / sizeof(FREQUENCY_ITEM)); |
| |
| /* |
| ========================================================================== |
| 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); |
| |
| { |
| 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); |
| WpaPskStateMachineInit(pAd, &pAd->Mlme.WpaPskMachine, pAd->Mlme.WpaPskFunc); |
| AironetStateMachineInit(pAd, &pAd->Mlme.AironetMachine, pAd->Mlme.AironetFunc); |
| |
| // 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); |
| } |
| |
| 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 RT2860 |
| { |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_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 |
| } 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; |
| |
| // 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; |
| } |
| |
| //From message type, determine which state machine I should drive |
| if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) |
| { |
| #ifdef RT2870 |
| if (Elem->MsgType == MT2_RESET_CONF) |
| { |
| DBGPRINT_RAW(RT_DEBUG_TRACE, ("!!! reset MLME state machine !!!\n")); |
| MlmeRestartStateMachine(pAd); |
| Elem->Occupied = FALSE; |
| Elem->MsgLen = 0; |
| continue; |
| } |
| #endif // RT2870 // |
| |
| // if dequeue success |
| switch (Elem->Machine) |
| { |
| // STA state machines |
| 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; |
| case AIRONET_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.AironetMachine, Elem); |
| break; |
| case ACTION_STATE_MACHINE: |
| StateMachinePerformAction(pAd, &pAd->Mlme.ActMachine, 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; |
| #ifdef RT3070 |
| UINT32 TxPinCfg = 0x00050F0F; |
| #endif // RT3070 // |
| |
| 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); |
| } |
| |
| { |
| // 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 RT2860 |
| if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) |
| { |
| RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled); |
| } |
| #endif |
| } |
| |
| RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled); |
| RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled); |
| |
| |
| |
| if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) |
| { |
| // Set LED |
| RTMPSetLED(pAd, LED_HALT); |
| RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it. |
| #ifdef RT2870 |
| { |
| LED_CFG_STRUC LedCfg; |
| RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word); |
| LedCfg.field.LedPolar = 0; |
| LedCfg.field.RLedMode = 0; |
| LedCfg.field.GLedMode = 0; |
| LedCfg.field.YLedMode = 0; |
| RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word); |
| } |
| #endif // RT2870 // |
| #ifdef RT3070 |
| // |
| // Turn off LNA_PE |
| // |
| if (IS_RT3070(pAd) || IS_RT3071(pAd)) |
| { |
| TxPinCfg &= 0xFFFFF0F0; |
| RTUSBWriteMACRegister(pAd, TX_PIN_CFG, TxPinCfg); |
| } |
| #endif // RT3070 // |
| } |
| |
| 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; |
| |
| // 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; |
| } |
| |
| unsigned long rx_AMSDU; |
| unsigned long rx_Total; |
| |
| /* |
| ========================================================================== |
| 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; |
| |
| #ifdef RT2860 |
| //Baron 2008/07/10 |
| //printk("Baron_Test:\t%s", RTMPGetRalinkEncryModeStr(pAd->StaCfg.WepStatus)); |
| //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0. |
| //If the STA security setting is WPAPSK or WPA2PSK, pAd->StaCfg.WpaSupplicantUP = 1. |
| if(pAd->StaCfg.WepStatus<2) |
| { |
| pAd->StaCfg.WpaSupplicantUP = 0; |
| } |
| else |
| { |
| pAd->StaCfg.WpaSupplicantUP = 1; |
| } |
| |
| { |
| // 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_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))) |
| { |
| UINT32 data = 0; |
| |
| // Read GPIO pin2 as Hardware controlled radio state |
| RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data); |
| 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 /* RT2860 */ |
| |
| // 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; |
| |
| #ifdef RT2860 |
| { |
| if ((pAd->RalinkCounters.LastReceivedByteCount == pAd->RalinkCounters.ReceivedByteCount) && (pAd->StaCfg.bRadio == TRUE)) |
| { |
| // If ReceiveByteCount doesn't change, increase SameRxByteCount by 1. |
| pAd->SameRxByteCount++; |
| } |
| else |
| pAd->SameRxByteCount = 0; |
| |
| // If after BBP, still not work...need to check to reset PBF&MAC. |
| if (pAd->SameRxByteCount == 702) |
| { |
| pAd->SameRxByteCount = 0; |
| AsicResetPBF(pAd); |
| AsicResetMAC(pAd); |
| } |
| |
| // If SameRxByteCount keeps happens for 2 second in infra mode, or for 60 seconds in idle mode. |
| if (((INFRA_ON(pAd)) && (pAd->SameRxByteCount > 20)) || ((IDLE_ON(pAd)) && (pAd->SameRxByteCount > 600))) |
| { |
| if ((pAd->StaCfg.bRadio == TRUE) && (pAd->SameRxByteCount < 700)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("---> SameRxByteCount = %lu !!!!!!!!!!!!!!! \n", pAd->SameRxByteCount)); |
| pAd->SameRxByteCount = 700; |
| AsicResetBBP(pAd); |
| } |
| } |
| |
| // Update lastReceiveByteCount. |
| pAd->RalinkCounters.LastReceivedByteCount = pAd->RalinkCounters.ReceivedByteCount; |
| |
| if ((pAd->CheckDmaBusyCount > 3) && (IDLE_ON(pAd))) |
| { |
| pAd->CheckDmaBusyCount = 0; |
| AsicResetFromDMABusy(pAd); |
| } |
| } |
| #endif /* RT2860 */ |
| RT28XX_MLME_PRE_SANITY_CHECK(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; |
| } |
| } |
| } |
| |
| pAd->bUpdateBcnCntDone = FALSE; |
| |
| // RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); |
| pAd->Mlme.PeriodicRound ++; |
| |
| #ifdef RT3070 |
| // execute every 100ms, update the Tx FIFO Cnt for update Tx Rate. |
| NICUpdateFifoStaCounters(pAd); |
| #endif // RT3070 // |
| // execute every 500ms |
| if ((pAd->Mlme.PeriodicRound % 5 == 0) && RTMPAutoRateSwitchCheck(pAd)/*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))*/) |
| { |
| // perform dynamic tx rate switching based on past TX history |
| { |
| if ((OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED) |
| ) |
| && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))) |
| MlmeDynamicTxRateSwitching(pAd); |
| } |
| } |
| |
| // Normal 1 second Mlme PeriodicExec. |
| if (pAd->Mlme.PeriodicRound %MLME_TASK_EXEC_MULTIPLE == 0) |
| { |
| pAd->Mlme.OneSecPeriodicRound ++; |
| |
| if (rx_Total) |
| { |
| |
| // reset counters |
| rx_AMSDU = 0; |
| rx_Total = 0; |
| } |
| |
| // 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 RT2870 |
| RT2870_WatchDog(pAd); |
| #endif // RT2870 // |
| |
| // Need statistics after read counter. So put after NICUpdateRawCounters |
| ORIBATimerTimeout(pAd); |
| |
| // The time period for checking antenna is according to traffic |
| 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); |
| } |
| } |
| } |
| |
| STAMlmePeriodicExec(pAd); |
| |
| MlmeResetRalinkCounters(pAd); |
| |
| { |
| #ifdef RT2860 |
| if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST) && (pAd->bPCIclkOff == FALSE)) |
| #endif |
| { |
| // 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")); |
| } |
| } |
| } |
| |
| RT28XX_MLME_HANDLER(pAd); |
| } |
| |
| pAd->bUpdateBcnCntDone = FALSE; |
| } |
| |
| VOID STAMlmePeriodicExec( |
| PRTMP_ADAPTER pAd) |
| { |
| #ifdef RT2860 |
| ULONG TxTotalCnt; |
| #endif |
| #ifdef RT2870 |
| ULONG TxTotalCnt; |
| int i; |
| #endif |
| |
| if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) |
| { |
| // WPA MIC error should block association attempt for 60 seconds |
| if (pAd->StaCfg.bBlockAssoc && (pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ) < pAd->Mlme.Now32)) |
| pAd->StaCfg.bBlockAssoc = FALSE; |
| } |
| |
| #ifdef RT2860 |
| //Baron 2008/07/10 |
| //printk("Baron_Test:\t%s", RTMPGetRalinkEncryModeStr(pAd->StaCfg.WepStatus)); |
| //If the STA security setting is OPEN or WEP, pAd->StaCfg.WpaSupplicantUP = 0. |
| //If the STA security setting is WPAPSK or WPA2PSK, pAd->StaCfg.WpaSupplicantUP = 1. |
| if(pAd->StaCfg.WepStatus<2) |
| { |
| pAd->StaCfg.WpaSupplicantUP = 0; |
| } |
| else |
| { |
| pAd->StaCfg.WpaSupplicantUP = 1; |
| } |
| #endif |
| |
| 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; |
| } |
| |
| #ifdef RT2860 |
| if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd)) && |
| (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)) && |
| (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE) && |
| (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) && |
| (RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_START_UP)) && |
| (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) |
| { |
| RT28xxPciAsicRadioOff(pAd, GUI_IDLE_POWER_SAVE, 0); |
| } |
| #endif |
| |
| |
| |
| 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, 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)) |
| { |
| // 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 ((pAd->StaCfg.LastBeaconRxTime + 1*OS_HZ < pAd->Mlme.Now32) && |
| (!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->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)); |
| pAd->StaCfg.CCXAdjacentAPReportFlag = TRUE; |
| pAd->StaCfg.CCXAdjacentAPLinkDownTime = pAd->StaCfg.LastBeaconRxTime; |
| |
| // Lost AP, send disconnect & link down event |
| LinkDown(pAd, FALSE); |
| |
| { |
| union iwreq_data wrqu; |
| memset(wrqu.ap_addr.sa_data, 0, MAC_ADDR_LEN); |
| wireless_send_event(pAd->net_dev, SIOCGIWAP, &wrqu, NULL); |
| } |
| |
| 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); |
| } |
| |
| // Add auto seamless roaming |
| if (pAd->StaCfg.bFastRoaming) |
| { |
| SHORT dBmToRoam = (SHORT)pAd->StaCfg.dBmToRoam; |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("Rssi=%d, dBmToRoam=%d\n", RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2), (CHAR)dBmToRoam)); |
| |
| if (RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2) <= (CHAR)dBmToRoam) |
| { |
| MlmeCheckForFastRoaming(pAd, pAd->Mlme.Now32); |
| } |
| } |
| } |
| else if (ADHOC_ON(pAd)) |
| { |
| #ifdef RT2860 |
| // 2003-04-17 john. this is a patch that driver forces a BEACON out if ASIC fails |
| // the "TX BEACON competition" for the entire past 1 sec. |
| // So that even when ASIC's BEACONgen engine been blocked |
| // by peer's BEACON due to slower system clock, this STA still can send out |
| // minimum BEACON to tell the peer I'm alive. |
| // drawback is that this BEACON won't be well aligned at TBTT boundary. |
| // EnqueueBeaconFrame(pAd); // software send BEACON |
| |
| // if all 11b peers leave this BSS more than 5 seconds, update Tx rate, |
| // restore outgoing BEACON to support B/G-mixed mode |
| if ((pAd->CommonCfg.Channel <= 14) && |
| (pAd->CommonCfg.MaxTxRate <= RATE_11) && |
| (pAd->CommonCfg.MaxDesiredRate > RATE_11) && |
| ((pAd->StaCfg.Last11bBeaconRxTime + 5*OS_HZ) < pAd->Mlme.Now32)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 11B peer left, update Tx rates\n")); |
| NdisMoveMemory(pAd->StaActive.SupRate, pAd->CommonCfg.SupRate, MAX_LEN_OF_SUPPORTED_RATES); |
| pAd->StaActive.SupRateLen = pAd->CommonCfg.SupRateLen; |
| MlmeUpdateTxRates(pAd, FALSE, 0); |
| MakeIbssBeacon(pAd); // re-build BEACON frame |
| AsicEnableIbssSync(pAd); // copy to on-chip memory |
| pAd->StaCfg.AdhocBOnlyJoined = FALSE; |
| } |
| |
| if (pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) |
| { |
| if ((pAd->StaCfg.AdhocBGJoined) && |
| ((pAd->StaCfg.Last11gBeaconRxTime + 5 * OS_HZ) < pAd->Mlme.Now32)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 11G peer left\n")); |
| pAd->StaCfg.AdhocBGJoined = FALSE; |
| } |
| |
| if ((pAd->StaCfg.Adhoc20NJoined) && |
| ((pAd->StaCfg.Last20NBeaconRxTime + 5 * OS_HZ) < pAd->Mlme.Now32)) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - last 20MHz N peer left\n")); |
| pAd->StaCfg.Adhoc20NJoined = FALSE; |
| } |
| } |
| #endif /* RT2860 */ |
| |
| //radar detect |
| if ((pAd->CommonCfg.Channel > 14) |
| && (pAd->CommonCfg.bIEEE80211H == 1) |
| && RadarChannelCheck(pAd, pAd->CommonCfg.Channel)) |
| { |
| RadarDetectPeriodic(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 ((pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) && |
| 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, 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; |
| } |
| |
| #ifdef RT2870 |
| for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) |
| { |
| MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i]; |
| |
| if (pEntry->ValidAsCLI == FALSE) |
| continue; |
| |
| if (pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME < pAd->Mlme.Now32) |
| MacTableDeleteEntry(pAd, pEntry->Aid, pEntry->Addr); |
| } |
| #endif |
| } |
| else // no INFRA nor ADHOC connection |
| { |
| |
| if (pAd->StaCfg.bScanReqIsFromWebUI && |
| ((pAd->StaCfg.LastScanTime + 30 * OS_HZ) > pAd->Mlme.Now32)) |
| 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 ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) |
| { |
| DBGPRINT(RT_DEBUG_TRACE, ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n", pAd->MlmeAux.AutoReconnectSsid)); |
| ScanParmFill(pAd, &ScanReq, 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 |
| { |
| MlmeAutoReconnectLastSSID(pAd); |
| } |
| } |
| } |
| } |
| |
| SKIP_AUTO_SCAN_CONN: |
| |
| 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); |
| } |
| |
| return; |
| } |
| |
| // Link down report |
| VOID LinkDownExec( |
| IN PVOID SystemSpecific1, |
| IN PVOID FunctionContext, |
| IN PVOID SystemSpecific2, |
| IN PVOID SystemSpecific3) |
| { |
| |
| RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext; |
| |
| 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, |
| 0, |
| NULL); |
| RT28XX_MLME_HANDLER(pAd); |
| } |
| } |
| |
| // IRQL = DISPATCH_LEVEL |
| VOID MlmeAutoReconnectLastSSID( |
| IN PRTMP_ADAPTER pAd) |
| { |
| |
| |
| // check CntlMachine.CurrState to avoid collision with NDIS SetOID request |
| 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); |
| RT28XX_MLME_HANDLER(pAd); |
| } |
| } |
| |
| /* |
| ========================================================================== |
| 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; |
| } |
| |
| if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) |
| { |
| if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && |
| #ifdef RT2860 |
| !pAd->StaCfg.AdhocBOnlyJoined && |
| !pAd->StaCfg.AdhocBGJoined && |
| (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && |
| ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) |
| #endif |
| #ifdef RT2870 |
| (pEntry->HTCapability.MCSSet[0] == 0xff) && |
| ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) |
| #endif |
| {// 11N 1S Adhoc |
| *ppTable = RateSwitchTable11N1S; |
| *pTableSize = RateSwitchTable11N1S[0]; |
| *pInitTxRateIdx = RateSwitchTable11N1S[1]; |
| |
| } |
| else if ((pAd->CommonCfg.PhyMode >= PHY_11ABGN_MIXED) && |
| #ifdef RT2860 |
| !pAd->StaCfg.AdhocBOnlyJoined && |
| !pAd->StaCfg.AdhocBGJoined && |
| (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && |
| (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && |
| #endif |
| #ifdef RT2870 |
| (pEntry->HTCapability.MCSSet[0] == 0xff) && |
| (pEntry->HTCapability.MCSSet[1] == 0xff) && |
| #endif |
| (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 |
| #ifdef RT2860 |
| if (pAd->CommonCfg.PhyMode == PHY_11B) |
| { |
| *ppTable = RateSwitchTable11B; |
| *pTableSize = RateSwitchTable11B[0]; |
| *pInitTxRateIdx = RateSwitchTable11B[1]; |
| |
| } |
| else if((pAd->LatchRfRegs.Channel <= 14) && (pAd->StaCfg.AdhocBOnlyJoined == TRUE)) |
| #endif |
| #ifdef RT2870 |
| if ((pEntry->RateLen == 4) |
| && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) |
| ) |
| #endif |
| { |
| // USe B Table when Only b-only Station in my IBSS . |
| *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; |
| } |
| |
| if ((pEntry->RateLen == 12) && (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; |
| } |
| |
| if ((pEntry->RateLen == 12) && (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; |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| //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) |
| {// 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) |
| && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) |
| ) |
| {// 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) |
| && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) |
| ) |
| {// G only AP |
| *ppTable = RateSwitchTable11G; |
| *pTableSize = RateSwitchTable11G[0]; |
| *pInitTxRateIdx = RateSwitchTable11G[1]; |
| |
| break; |
| } |
| |
| { |
| //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)) |
| { // 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; |
| } |
| |
| 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")); |
| } |
| } |
| |
| 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])); |
| } |
| } while(FALSE); |
| } |
| |
| /* |
| ========================================================================== |
| 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 + BEACON_LOST_TIME) < 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); |
| RT28XX_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: |
| ========================================================================== |
| */ |
| VOID MlmeCheckForFastRoaming( |
| IN PRTMP_ADAPTER pAd, |
| IN ULONG Now) |
| { |
| 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; |
| } |
| |
| 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); |
| RT28XX_MLME_HANDLER(pAd); |
| } |
| } |
| // Maybe site survey required |
| else |
| { |
| if ((pAd->StaCfg.LastScanTime + 10 * 1000) < Now) |
| { |
| // check CntlMachine.CurrState to avoid collision with NDIS SetOID request |
| DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Roaming, No eligable entry, try new scan!\n")); |
| pAd->StaCfg.ScanCnt = 2; |
| pAd->StaCfg.LastScanTime = Now; |
| MlmeAutoScan(pAd); |
| } |
| } |
| |
| DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr)); |
| } |
| |
| /* |
| ========================================================================== |
| 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 ULONG Now32) |
| { |
| ULONG TxOkCnt, TxCnt, TxPER, TxPRR; |
| ULONG RxCnt, RxPER; |
| UCHAR NorRssi; |
| CHAR MaxRssi; |
| ULONG BeaconLostTime = BEACON_LOST_TIME; |
| |
| MaxRssi = RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0, pAd->StaCfg.RssiSample.LastRssi1, pAd->StaCfg.RssiSample.LastRssi2); |
| |
| // |
| // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics |
| // |
| TxOkCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount + pAd->RalinkCounters.OneSecTxRetryOkCount; |
| TxCnt = TxOkCnt + pAd->RalinkCounters.OneSecTxFailCount; |
| if (TxCnt < 5) |
| { |
| TxPER = 0; |
| TxPRR = 0; |
| } |
| else |
| { |
| TxPER = (pAd->RalinkCounters.OneSecTxFailCount * 100) / TxCnt; |
| TxPRR = ((TxCnt - pAd->RalinkCounters.OneSecTxNoRetryOkCount) * 100) / TxCnt; |
| } |
| |
| // |
| // calculate RX PER - don't take RxPER into consideration if too few sample |
| // |
| RxCnt = pAd->RalinkCounters.OneSecRxOkCnt + pAd->RalinkCounters.OneSecRxFcsErrCnt; |
| if (RxCnt < 5) |
| RxPER = 0; |
| else |
| RxPER = (pAd->RalinkCounters.OneSecRxFcsErrCnt * 100) / RxCnt; |
| |
| // |
| // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER |
| // |
| if (INFRA_ON(pAd) && |
| (pAd->RalinkCounters.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)); |
| pAd->Mlme.ChannelQuality = 0; |
| } |
| else |
| { |
| // 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) |
| pAd->Mlme.ChannelQuality = (RSSI_WEIGHTING * NorRssi + |
| TX_WEIGHTING * (100 - TxPRR) + |
| RX_WEIGHTING* (100 - RxPER)) / 100; |
| if (pAd->Mlme.ChannelQuality >= 100) |
| pAd->Mlme.ChannelQuality = 100; |
| } |
| |
| } |
| |
| VOID MlmeSetTxRate( |
| IN PRTMP_ADAPTER pAd, |
| IN PMAC_TABLE_ENTRY pEntry, |
| IN PRTMP_TX_RATE_SWITCH pTxRate) |
| { |
| UCHAR MaxMode = MODE_OFDM; |
| |
| MaxMode = MODE_HTGREENFIELD; |
| |
| if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC) && (pAd->Antenna.field.TxPath == 2)) |
| pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE; |
| else |
| 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; |
| |
| if (pTxRate->ShortGI && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI)) |
| pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400; |
| else |
| pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800; |
| |
| // 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); |
| } |
| |
| 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; |
| |
| if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD) && |
| pAd->WIFItestbed.bGreenField) |
| pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD; |
| } |
| |
| 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, 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; |
| |
| // |
| // 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)) |
| { |
| #ifdef RT2860 |
| Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.RssiSample.AvgRssi0, (CHAR)pAd->StaCfg.RssiSample.AvgRssi1, (CHAR)pAd->StaCfg.RssiSample.AvgRssi2); |
| #endif |
| #ifdef RT2870 |
| Rssi = RTMPMaxRssi(pAd, |
| pAd->StaCfg.RssiSample.AvgRssi0, |
| pAd->StaCfg.RssiSample.AvgRssi1, |
| pAd->StaCfg.RssiSample.AvgRssi2); |
| #endif |
| |
| // 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 |
| { |
| #ifdef RT2860 |
| Rssi = RTMPMaxRssi(pAd, (CHAR)pEntry->RssiSample.AvgRssi0, (CHAR)pEntry->RssiSample.AvgRssi1, (CHAR)pEntry->RssiSample.AvgRssi2); |
| #endif |
| #ifdef RT2870 |
| 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); |
| #endif |
| |
| TxTotalCnt = pEntry->OneSecTxNoRetryOkCount + |
| pEntry->OneSecTxRetryOkCount + |
| pEntry->OneSecTxFailCount; |
| |
| if (TxTotalCnt) |
| TxErrorRatio = ((pEntry->OneSecTxRetryOkCount + pEntry->OneSecTxFailCount) * 100) / TxTotalCnt; |
| } |
| |
| 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]; |
| |
| if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) |
| { |
| TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); |
| TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); |
| } |
| else |
| { |
| 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, MCS7 = 0, MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0; |
| 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, 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; |
| } |
| } |
| |
| /*if (MCS15)*/ |
| if ((pTable == RateSwitchTable11BGN3S) || |
| (pTable == RateSwitchTable11N3S) || |
| (pTable == RateSwitchTable)) |
| {// N mode with 3 stream // 3*3 |
| if (MCS23 && (Rssi >= -70)) |
| TxRateIdx = MCS15; |
| else if (MCS22 && (Rssi >= -72)) |
| TxRateIdx = MCS14; |
| else if (MCS21 && (Rssi >= -76)) |
| TxRateIdx = MCS13; |
| else if (MCS20 && (Rssi >= -78)) |
| TxRateIdx = MCS12; |
| 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)) // 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 |
| {// 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; |
| } |
| |
| { |
| 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; |
| |
| // reset all OneSecTx counters |
| RESET_ONE_SEC_TX_CNT(pEntry); |
| |
| pNextTxRate = (PRTMP_TX_RATE_SWITCH) &pTable[(pEntry->CurrTxRateIndex+1)*5]; |
| if (bTxRateChanged && pNextTxRate) |
| { |
| MlmeSetTxRate(pAd, pEntry, pNextTxRate); |
| } |
| } |
| } |
| |
| /* |
| ======================================================================== |
| 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; |
| #ifdef RT2860 |
| BOOLEAN bTxRateChanged = TRUE; //, bUpgradeQuality = FALSE; |
| #endif |
| #ifdef RT2870 |
| BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE; |
| #endif |
| 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; |
| |
| #ifdef RT2860 |
| //Rssi = RTMPMaxRssi(pAd, (CHAR)pAd->StaCfg.AvgRssi0, (CHAR)pAd->StaCfg.AvgRssi1, (CHAR)pAd->StaCfg.AvgRssi2); |
| if (pAd->Antenna.field.TxPath > 1) |
| Rssi = (pAd->StaCfg.RssiSample.AvgRssi0 + pAd->StaCfg.RssiSample.AvgRssi1) >> 1; |
| else |
| Rssi = pAd->StaCfg.RssiSample.AvgRssi0; |
| #endif |
| #ifdef RT2870 |
| 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); |
| #endif |
| |
| 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]; |
| |
| if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) |
| { |
| TrainUp = (pCurrTxRate->TrainUp + (pCurrTxRate->TrainUp >> 1)); |
| TrainDown = (pCurrTxRate->TrainDown + (pCurrTxRate->TrainDown >> 1)); |
| } |
| else |
| { |
| 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) && ( |