6551 lines
189 KiB
C
6551 lines
189 KiB
C
|
/*
|
||
|
*************************************************************************
|
||
|
* 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 //
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|