• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/rt2860/common/
1/*
2 *************************************************************************
3 * Ralink Tech Inc.
4 * 5F., No.36, Taiyuan St., Jhubei City,
5 * Hsinchu County 302,
6 * Taiwan, R.O.C.
7 *
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify  *
11 * it under the terms of the GNU General Public License as published by  *
12 * the Free Software Foundation; either version 2 of the License, or     *
13 * (at your option) any later version.                                   *
14 *                                                                       *
15 * This program is distributed in the hope that it will be useful,       *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18 * GNU General Public License for more details.                          *
19 *                                                                       *
20 * You should have received a copy of the GNU General Public License     *
21 * along with this program; if not, write to the                         *
22 * Free Software Foundation, Inc.,                                       *
23 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24 *                                                                       *
25 *************************************************************************
26
27	Module Name:
28	mlme.c
29
30	Abstract:
31
32	Revision History:
33	Who			When			What
34	--------	----------		----------------------------------------------
35	John Chang	2004-08-25		Modify from RT2500 code base
36	John Chang	2004-09-06		modified for RT2600
37*/
38
39#include "../rt_config.h"
40#include <stdarg.h>
41
42u8 CISCO_OUI[] = { 0x00, 0x40, 0x96 };
43
44u8 WPA_OUI[] = { 0x00, 0x50, 0xf2, 0x01 };
45u8 RSN_OUI[] = { 0x00, 0x0f, 0xac };
46u8 WME_INFO_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01 };
47u8 WME_PARM_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01 };
48u8 Ccx2QosInfo[] = { 0x00, 0x40, 0x96, 0x04 };
49u8 RALINK_OUI[] = { 0x00, 0x0c, 0x43 };
50u8 BROADCOM_OUI[] = { 0x00, 0x90, 0x4c };
51u8 WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
52u8 PRE_N_HT_OUI[] = { 0x00, 0x90, 0x4c };
53
54u8 RateSwitchTable[] = {
55/* 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) */
56	0x11, 0x00, 0, 0, 0,	/* Initial used item after association */
57	0x00, 0x00, 0, 40, 101,
58	0x01, 0x00, 1, 40, 50,
59	0x02, 0x00, 2, 35, 45,
60	0x03, 0x00, 3, 20, 45,
61	0x04, 0x21, 0, 30, 50,
62	0x05, 0x21, 1, 20, 50,
63	0x06, 0x21, 2, 20, 50,
64	0x07, 0x21, 3, 15, 50,
65	0x08, 0x21, 4, 15, 30,
66	0x09, 0x21, 5, 10, 25,
67	0x0a, 0x21, 6, 8, 25,
68	0x0b, 0x21, 7, 8, 25,
69	0x0c, 0x20, 12, 15, 30,
70	0x0d, 0x20, 13, 8, 20,
71	0x0e, 0x20, 14, 8, 20,
72	0x0f, 0x20, 15, 8, 25,
73	0x10, 0x22, 15, 8, 25,
74	0x11, 0x00, 0, 0, 0,
75	0x12, 0x00, 0, 0, 0,
76	0x13, 0x00, 0, 0, 0,
77	0x14, 0x00, 0, 0, 0,
78	0x15, 0x00, 0, 0, 0,
79	0x16, 0x00, 0, 0, 0,
80	0x17, 0x00, 0, 0, 0,
81	0x18, 0x00, 0, 0, 0,
82	0x19, 0x00, 0, 0, 0,
83	0x1a, 0x00, 0, 0, 0,
84	0x1b, 0x00, 0, 0, 0,
85	0x1c, 0x00, 0, 0, 0,
86	0x1d, 0x00, 0, 0, 0,
87	0x1e, 0x00, 0, 0, 0,
88	0x1f, 0x00, 0, 0, 0,
89};
90
91u8 RateSwitchTable11B[] = {
92/* 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) */
93	0x04, 0x03, 0, 0, 0,	/* Initial used item after association */
94	0x00, 0x00, 0, 40, 101,
95	0x01, 0x00, 1, 40, 50,
96	0x02, 0x00, 2, 35, 45,
97	0x03, 0x00, 3, 20, 45,
98};
99
100u8 RateSwitchTable11BG[] = {
101/* 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) */
102	0x0a, 0x00, 0, 0, 0,	/* Initial used item after association */
103	0x00, 0x00, 0, 40, 101,
104	0x01, 0x00, 1, 40, 50,
105	0x02, 0x00, 2, 35, 45,
106	0x03, 0x00, 3, 20, 45,
107	0x04, 0x10, 2, 20, 35,
108	0x05, 0x10, 3, 16, 35,
109	0x06, 0x10, 4, 10, 25,
110	0x07, 0x10, 5, 16, 25,
111	0x08, 0x10, 6, 10, 25,
112	0x09, 0x10, 7, 10, 13,
113};
114
115u8 RateSwitchTable11G[] = {
116/* 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) */
117	0x08, 0x00, 0, 0, 0,	/* Initial used item after association */
118	0x00, 0x10, 0, 20, 101,
119	0x01, 0x10, 1, 20, 35,
120	0x02, 0x10, 2, 20, 35,
121	0x03, 0x10, 3, 16, 35,
122	0x04, 0x10, 4, 10, 25,
123	0x05, 0x10, 5, 16, 25,
124	0x06, 0x10, 6, 10, 25,
125	0x07, 0x10, 7, 10, 13,
126};
127
128u8 RateSwitchTable11N1S[] = {
129/* 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) */
130	0x0c, 0x0a, 0, 0, 0,	/* Initial used item after association */
131	0x00, 0x00, 0, 40, 101,
132	0x01, 0x00, 1, 40, 50,
133	0x02, 0x00, 2, 25, 45,
134	0x03, 0x21, 0, 20, 35,
135	0x04, 0x21, 1, 20, 35,
136	0x05, 0x21, 2, 20, 35,
137	0x06, 0x21, 3, 15, 35,
138	0x07, 0x21, 4, 15, 30,
139	0x08, 0x21, 5, 10, 25,
140	0x09, 0x21, 6, 8, 14,
141	0x0a, 0x21, 7, 8, 14,
142	0x0b, 0x23, 7, 8, 14,
143};
144
145u8 RateSwitchTable11N2S[] = {
146/* 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) */
147	0x0e, 0x0c, 0, 0, 0,	/* Initial used item after association */
148	0x00, 0x00, 0, 40, 101,
149	0x01, 0x00, 1, 40, 50,
150	0x02, 0x00, 2, 25, 45,
151	0x03, 0x21, 0, 20, 35,
152	0x04, 0x21, 1, 20, 35,
153	0x05, 0x21, 2, 20, 35,
154	0x06, 0x21, 3, 15, 35,
155	0x07, 0x21, 4, 15, 30,
156	0x08, 0x20, 11, 15, 30,
157	0x09, 0x20, 12, 15, 30,
158	0x0a, 0x20, 13, 8, 20,
159	0x0b, 0x20, 14, 8, 20,
160	0x0c, 0x20, 15, 8, 25,
161	0x0d, 0x22, 15, 8, 15,
162};
163
164u8 RateSwitchTable11N3S[] = {
165/* 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) */
166	0x0b, 0x00, 0, 0, 0,	/* 0x0a, 0x00,  0,  0,  0,      // Initial used item after association */
167	0x00, 0x21, 0, 30, 101,
168	0x01, 0x21, 1, 20, 50,
169	0x02, 0x21, 2, 20, 50,
170	0x03, 0x21, 3, 15, 50,
171	0x04, 0x21, 4, 15, 30,
172	0x05, 0x20, 11, 15, 30,	/* Required by System-Alan @ 20080812 */
173	0x06, 0x20, 12, 15, 30,	/* 0x05, 0x20, 12, 15, 30, */
174	0x07, 0x20, 13, 8, 20,	/* 0x06, 0x20, 13,  8, 20, */
175	0x08, 0x20, 14, 8, 20,	/* 0x07, 0x20, 14,  8, 20, */
176	0x09, 0x20, 15, 8, 25,	/* 0x08, 0x20, 15,  8, 25, */
177	0x0a, 0x22, 15, 8, 25,	/* 0x09, 0x22, 15,  8, 25, */
178};
179
180u8 RateSwitchTable11N2SForABand[] = {
181/* 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) */
182	0x0b, 0x09, 0, 0, 0,	/* Initial used item after association */
183	0x00, 0x21, 0, 30, 101,
184	0x01, 0x21, 1, 20, 50,
185	0x02, 0x21, 2, 20, 50,
186	0x03, 0x21, 3, 15, 50,
187	0x04, 0x21, 4, 15, 30,
188	0x05, 0x21, 5, 15, 30,
189	0x06, 0x20, 12, 15, 30,
190	0x07, 0x20, 13, 8, 20,
191	0x08, 0x20, 14, 8, 20,
192	0x09, 0x20, 15, 8, 25,
193	0x0a, 0x22, 15, 8, 25,
194};
195
196u8 RateSwitchTable11N3SForABand[] = {	/* 3*3 */
197/* 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) */
198	0x0b, 0x09, 0, 0, 0,	/* Initial used item after association */
199	0x00, 0x21, 0, 30, 101,
200	0x01, 0x21, 1, 20, 50,
201	0x02, 0x21, 2, 20, 50,
202	0x03, 0x21, 3, 15, 50,
203	0x04, 0x21, 4, 15, 30,
204	0x05, 0x21, 5, 15, 30,
205	0x06, 0x20, 12, 15, 30,
206	0x07, 0x20, 13, 8, 20,
207	0x08, 0x20, 14, 8, 20,
208	0x09, 0x20, 15, 8, 25,
209	0x0a, 0x22, 15, 8, 25,
210};
211
212u8 RateSwitchTable11BGN1S[] = {
213/* 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) */
214	0x0c, 0x0a, 0, 0, 0,	/* Initial used item after association */
215	0x00, 0x00, 0, 40, 101,
216	0x01, 0x00, 1, 40, 50,
217	0x02, 0x00, 2, 25, 45,
218	0x03, 0x21, 0, 20, 35,
219	0x04, 0x21, 1, 20, 35,
220	0x05, 0x21, 2, 20, 35,
221	0x06, 0x21, 3, 15, 35,
222	0x07, 0x21, 4, 15, 30,
223	0x08, 0x21, 5, 10, 25,
224	0x09, 0x21, 6, 8, 14,
225	0x0a, 0x21, 7, 8, 14,
226	0x0b, 0x23, 7, 8, 14,
227};
228
229u8 RateSwitchTable11BGN2S[] = {
230/* 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) */
231	0x0e, 0x0c, 0, 0, 0,	/* Initial used item after association */
232	0x00, 0x00, 0, 40, 101,
233	0x01, 0x00, 1, 40, 50,
234	0x02, 0x00, 2, 25, 45,
235	0x03, 0x21, 0, 20, 35,
236	0x04, 0x21, 1, 20, 35,
237	0x05, 0x21, 2, 20, 35,
238	0x06, 0x21, 3, 15, 35,
239	0x07, 0x21, 4, 15, 30,
240	0x08, 0x20, 11, 15, 30,
241	0x09, 0x20, 12, 15, 30,
242	0x0a, 0x20, 13, 8, 20,
243	0x0b, 0x20, 14, 8, 20,
244	0x0c, 0x20, 15, 8, 25,
245	0x0d, 0x22, 15, 8, 15,
246};
247
248u8 RateSwitchTable11BGN3S[] = {	/* 3*3 */
249/* 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) */
250	0x0a, 0x00, 0, 0, 0,	/* Initial used item after association */
251	0x00, 0x21, 0, 30, 101,	/*50 */
252	0x01, 0x21, 1, 20, 50,
253	0x02, 0x21, 2, 20, 50,
254	0x03, 0x21, 3, 20, 50,
255	0x04, 0x21, 4, 15, 50,
256	0x05, 0x20, 20, 15, 30,
257	0x06, 0x20, 21, 8, 20,
258	0x07, 0x20, 22, 8, 20,
259	0x08, 0x20, 23, 8, 25,
260	0x09, 0x22, 23, 8, 25,
261};
262
263u8 RateSwitchTable11BGN2SForABand[] = {
264/* 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) */
265	0x0b, 0x09, 0, 0, 0,	/* Initial used item after association */
266	0x00, 0x21, 0, 30, 101,	/*50 */
267	0x01, 0x21, 1, 20, 50,
268	0x02, 0x21, 2, 20, 50,
269	0x03, 0x21, 3, 15, 50,
270	0x04, 0x21, 4, 15, 30,
271	0x05, 0x21, 5, 15, 30,
272	0x06, 0x20, 12, 15, 30,
273	0x07, 0x20, 13, 8, 20,
274	0x08, 0x20, 14, 8, 20,
275	0x09, 0x20, 15, 8, 25,
276	0x0a, 0x22, 15, 8, 25,
277};
278
279u8 RateSwitchTable11BGN3SForABand[] = {	/* 3*3 */
280/* 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) */
281	0x0c, 0x09, 0, 0, 0,	/* Initial used item after association */
282	0x00, 0x21, 0, 30, 101,	/*50 */
283	0x01, 0x21, 1, 20, 50,
284	0x02, 0x21, 2, 20, 50,
285	0x03, 0x21, 3, 15, 50,
286	0x04, 0x21, 4, 15, 30,
287	0x05, 0x21, 5, 15, 30,
288	0x06, 0x21, 12, 15, 30,
289	0x07, 0x20, 20, 15, 30,
290	0x08, 0x20, 21, 8, 20,
291	0x09, 0x20, 22, 8, 20,
292	0x0a, 0x20, 23, 8, 25,
293	0x0b, 0x22, 23, 8, 25,
294};
295
296extern u8 OfdmRateToRxwiMCS[];
297/* since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. */
298/* otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate */
299unsigned long BasicRateMask[12] =
300    { 0xfffff001 /* 1-Mbps */ , 0xfffff003 /* 2 Mbps */ , 0xfffff007 /* 5.5 */ ,
3010xfffff00f /* 11 */ ,
302	0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ ,
303	    0xfffff0ff /* 18 */ ,
304	0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ ,
305	    0xffffffff /* 54 */
306};
307
308u8 BROADCAST_ADDR[MAC_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
309u8 ZERO_MAC_ADDR[MAC_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
310
311/* e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than */
312/*              this value, then it's quaranteed capable of operating in 36 mbps TX rate in */
313/*              clean environment. */
314/*                                                                TxRate: 1   2   5.5   11       6        9    12       18       24   36   48   54       72  100 */
315char RssiSafeLevelForTxRate[] =
316    { -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 };
317
318u8 RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100 };
319u16 RateIdTo500Kbps[] =
320    { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200 };
321
322u8 SsidIe = IE_SSID;
323u8 SupRateIe = IE_SUPP_RATES;
324u8 ExtRateIe = IE_EXT_SUPP_RATES;
325u8 HtCapIe = IE_HT_CAP;
326u8 AddHtInfoIe = IE_ADD_HT;
327u8 NewExtChanIe = IE_SECONDARY_CH_OFFSET;
328u8 ErpIe = IE_ERP;
329u8 DsIe = IE_DS_PARM;
330u8 TimIe = IE_TIM;
331u8 WpaIe = IE_WPA;
332u8 Wpa2Ie = IE_WPA2;
333u8 IbssIe = IE_IBSS_PARM;
334
335extern u8 WPA_OUI[];
336
337u8 SES_OUI[] = { 0x00, 0x90, 0x4c };
338
339u8 ZeroSsid[32] =
340    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3410x00, 0x00, 0x00, 0x00,
342	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343	    0x00, 0x00, 0x00, 0x00
344};
345
346/*
347	==========================================================================
348	Description:
349		initialize the MLME task and its data structure (queue, spinlock,
350		timer, state machines).
351
352	IRQL = PASSIVE_LEVEL
353
354	Return:
355		always return NDIS_STATUS_SUCCESS
356
357	==========================================================================
358*/
359int MlmeInit(struct rt_rtmp_adapter *pAd)
360{
361	int Status = NDIS_STATUS_SUCCESS;
362
363	DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n"));
364
365	do {
366		Status = MlmeQueueInit(&pAd->Mlme.Queue);
367		if (Status != NDIS_STATUS_SUCCESS)
368			break;
369
370		pAd->Mlme.bRunning = FALSE;
371		NdisAllocateSpinLock(&pAd->Mlme.TaskLock);
372
373		{
374			BssTableInit(&pAd->ScanTab);
375
376			/* init STA state machines */
377			AssocStateMachineInit(pAd, &pAd->Mlme.AssocMachine,
378					      pAd->Mlme.AssocFunc);
379			AuthStateMachineInit(pAd, &pAd->Mlme.AuthMachine,
380					     pAd->Mlme.AuthFunc);
381			AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine,
382						pAd->Mlme.AuthRspFunc);
383			SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine,
384					     pAd->Mlme.SyncFunc);
385
386			/* Since we are using switch/case to implement it, the init is different from the above */
387			/* state machine init */
388			MlmeCntlInit(pAd, &pAd->Mlme.CntlMachine, NULL);
389		}
390
391		WpaStateMachineInit(pAd, &pAd->Mlme.WpaMachine,
392				    pAd->Mlme.WpaFunc);
393
394		ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine,
395				       pAd->Mlme.ActFunc);
396
397		/* Init mlme periodic timer */
398		RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer,
399			      GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE);
400
401		/* Set mlme periodic timer */
402		RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
403
404		/* software-based RX Antenna diversity */
405		RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer,
406			      GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd,
407			      FALSE);
408
409		{
410#ifdef RTMP_PCI_SUPPORT
411			if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) {
412				/* only PCIe cards need these two timers */
413				RTMPInitTimer(pAd, &pAd->Mlme.PsPollTimer,
414					      GET_TIMER_FUNCTION
415					      (PsPollWakeExec), pAd, FALSE);
416				RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer,
417					      GET_TIMER_FUNCTION(RadioOnExec),
418					      pAd, FALSE);
419			}
420#endif /* RTMP_PCI_SUPPORT // */
421
422			RTMPInitTimer(pAd, &pAd->Mlme.LinkDownTimer,
423				      GET_TIMER_FUNCTION(LinkDownExec), pAd,
424				      FALSE);
425
426#ifdef RTMP_MAC_USB
427			RTMPInitTimer(pAd, &pAd->Mlme.AutoWakeupTimer,
428				      GET_TIMER_FUNCTION
429				      (RtmpUsbStaAsicForceWakeupTimeout), pAd,
430				      FALSE);
431			pAd->Mlme.AutoWakeupTimerRunning = FALSE;
432#endif /* RTMP_MAC_USB // */
433		}
434
435	} while (FALSE);
436
437	DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n"));
438
439	return Status;
440}
441
442/*
443	==========================================================================
444	Description:
445		main loop of the MLME
446	Pre:
447		Mlme has to be initialized, and there are something inside the queue
448	Note:
449		This function is invoked from MPSetInformation and MPReceive;
450		This task guarantee only one MlmeHandler will run.
451
452	IRQL = DISPATCH_LEVEL
453
454	==========================================================================
455 */
456void MlmeHandler(struct rt_rtmp_adapter *pAd)
457{
458	struct rt_mlme_queue_elem *Elem = NULL;
459
460	/* Only accept MLME and Frame from peer side, no other (control/data) frame should */
461	/* get into this state machine */
462
463	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
464	if (pAd->Mlme.bRunning) {
465		NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
466		return;
467	} else {
468		pAd->Mlme.bRunning = TRUE;
469	}
470	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
471
472	while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) {
473		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MLME_RESET_IN_PROGRESS) ||
474		    RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS) ||
475		    RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
476			DBGPRINT(RT_DEBUG_TRACE,
477				 ("Device Halted or Removed or MlmeRest, exit MlmeHandler! (queue num = %ld)\n",
478				  pAd->Mlme.Queue.Num));
479			break;
480		}
481		/*From message type, determine which state machine I should drive */
482		if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) {
483#ifdef RTMP_MAC_USB
484			if (Elem->MsgType == MT2_RESET_CONF) {
485				DBGPRINT_RAW(RT_DEBUG_TRACE,
486					     ("reset MLME state machine!\n"));
487				MlmeRestartStateMachine(pAd);
488				Elem->Occupied = FALSE;
489				Elem->MsgLen = 0;
490				continue;
491			}
492#endif /* RTMP_MAC_USB // */
493
494			/* if dequeue success */
495			switch (Elem->Machine) {
496				/* STA state machines */
497			case ASSOC_STATE_MACHINE:
498				StateMachinePerformAction(pAd,
499							  &pAd->Mlme.
500							  AssocMachine, Elem);
501				break;
502			case AUTH_STATE_MACHINE:
503				StateMachinePerformAction(pAd,
504							  &pAd->Mlme.
505							  AuthMachine, Elem);
506				break;
507			case AUTH_RSP_STATE_MACHINE:
508				StateMachinePerformAction(pAd,
509							  &pAd->Mlme.
510							  AuthRspMachine, Elem);
511				break;
512			case SYNC_STATE_MACHINE:
513				StateMachinePerformAction(pAd,
514							  &pAd->Mlme.
515							  SyncMachine, Elem);
516				break;
517			case MLME_CNTL_STATE_MACHINE:
518				MlmeCntlMachinePerformAction(pAd,
519							     &pAd->Mlme.
520							     CntlMachine, Elem);
521				break;
522			case WPA_PSK_STATE_MACHINE:
523				StateMachinePerformAction(pAd,
524							  &pAd->Mlme.
525							  WpaPskMachine, Elem);
526				break;
527
528			case ACTION_STATE_MACHINE:
529				StateMachinePerformAction(pAd,
530							  &pAd->Mlme.ActMachine,
531							  Elem);
532				break;
533
534			case WPA_STATE_MACHINE:
535				StateMachinePerformAction(pAd,
536							  &pAd->Mlme.WpaMachine,
537							  Elem);
538				break;
539
540			default:
541				DBGPRINT(RT_DEBUG_TRACE,
542					 ("ERROR: Illegal machine %ld in MlmeHandler()\n",
543					  Elem->Machine));
544				break;
545			}	/* end of switch */
546
547			/* free MLME element */
548			Elem->Occupied = FALSE;
549			Elem->MsgLen = 0;
550
551		} else {
552			DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n"));
553		}
554	}
555
556	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
557	pAd->Mlme.bRunning = FALSE;
558	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
559}
560
561/*
562	==========================================================================
563	Description:
564		Destructor of MLME (Destroy queue, state machine, spin lock and timer)
565	Parameters:
566		Adapter - NIC Adapter pointer
567	Post:
568		The MLME task will no longer work properly
569
570	IRQL = PASSIVE_LEVEL
571
572	==========================================================================
573 */
574void MlmeHalt(struct rt_rtmp_adapter *pAd)
575{
576	BOOLEAN Cancelled;
577
578	DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n"));
579
580	if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
581		/* disable BEACON generation and other BEACON related hardware timers */
582		AsicDisableSync(pAd);
583	}
584
585	{
586		/* Cancel pending timers */
587		RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled);
588		RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled);
589		RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled);
590		RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled);
591		RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled);
592		RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
593
594#ifdef RTMP_MAC_PCI
595		if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
596		    && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) {
597			RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
598			RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
599		}
600#endif /* RTMP_MAC_PCI // */
601
602		RTMPCancelTimer(&pAd->Mlme.LinkDownTimer, &Cancelled);
603
604#ifdef RTMP_MAC_USB
605		RTMPCancelTimer(&pAd->Mlme.AutoWakeupTimer, &Cancelled);
606#endif /* RTMP_MAC_USB // */
607	}
608
609	RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled);
610	RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled);
611
612	if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
613		struct rt_rtmp_chip_op *pChipOps = &pAd->chipOps;
614
615		/* Set LED */
616		RTMPSetLED(pAd, LED_HALT);
617		RTMPSetSignalLED(pAd, -100);	/* Force signal strength Led to be turned off, firmware is not done it. */
618#ifdef RTMP_MAC_USB
619		{
620			LED_CFG_STRUC LedCfg;
621			RTMP_IO_READ32(pAd, LED_CFG, &LedCfg.word);
622			LedCfg.field.LedPolar = 0;
623			LedCfg.field.RLedMode = 0;
624			LedCfg.field.GLedMode = 0;
625			LedCfg.field.YLedMode = 0;
626			RTMP_IO_WRITE32(pAd, LED_CFG, LedCfg.word);
627		}
628#endif /* RTMP_MAC_USB // */
629
630		if (pChipOps->AsicHaltAction)
631			pChipOps->AsicHaltAction(pAd);
632	}
633
634	RTMPusecDelay(5000);	/*  5 msec to gurantee Ant Diversity timer canceled */
635
636	MlmeQueueDestroy(&pAd->Mlme.Queue);
637	NdisFreeSpinLock(&pAd->Mlme.TaskLock);
638
639	DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n"));
640}
641
642void MlmeResetRalinkCounters(struct rt_rtmp_adapter *pAd)
643{
644	pAd->RalinkCounters.LastOneSecRxOkDataCnt =
645	    pAd->RalinkCounters.OneSecRxOkDataCnt;
646	/* clear all OneSecxxx counters. */
647	pAd->RalinkCounters.OneSecBeaconSentCnt = 0;
648	pAd->RalinkCounters.OneSecFalseCCACnt = 0;
649	pAd->RalinkCounters.OneSecRxFcsErrCnt = 0;
650	pAd->RalinkCounters.OneSecRxOkCnt = 0;
651	pAd->RalinkCounters.OneSecTxFailCount = 0;
652	pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0;
653	pAd->RalinkCounters.OneSecTxRetryOkCount = 0;
654	pAd->RalinkCounters.OneSecRxOkDataCnt = 0;
655	pAd->RalinkCounters.OneSecReceivedByteCount = 0;
656	pAd->RalinkCounters.OneSecTransmittedByteCount = 0;
657
658	/* TODO: for debug only. to be removed */
659	pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0;
660	pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0;
661	pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0;
662	pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0;
663	pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0;
664	pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0;
665	pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0;
666	pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0;
667	pAd->RalinkCounters.OneSecTxDoneCount = 0;
668	pAd->RalinkCounters.OneSecRxCount = 0;
669	pAd->RalinkCounters.OneSecTxAggregationCount = 0;
670	pAd->RalinkCounters.OneSecRxAggregationCount = 0;
671
672	return;
673}
674
675/*
676	==========================================================================
677	Description:
678		This routine is executed periodically to -
679		1. Decide if it's a right time to turn on PwrMgmt bit of all
680		   outgoiing frames
681		2. Calculate ChannelQuality based on statistics of the last
682		   period, so that TX rate won't toggling very frequently between a
683		   successful TX and a failed TX.
684		3. If the calculated ChannelQuality indicated current connection not
685		   healthy, then a ROAMing attempt is tried here.
686
687	IRQL = DISPATCH_LEVEL
688
689	==========================================================================
690 */
691#define ADHOC_BEACON_LOST_TIME		(8*OS_HZ)	/* 8 sec */
692void MlmePeriodicExec(void *SystemSpecific1,
693		      void *FunctionContext,
694		      void *SystemSpecific2, void *SystemSpecific3)
695{
696	unsigned long TxTotalCnt;
697	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
698
699#ifdef RTMP_MAC_PCI
700	{
701		/* If Hardware controlled Radio enabled, we have to check GPIO pin2 every 2 second. */
702		/* Move code to here, because following code will return when radio is off */
703		if ((pAd->Mlme.PeriodicRound % (MLME_TASK_EXEC_MULTIPLE * 2) ==
704		     0) && (pAd->StaCfg.bHardwareRadio == TRUE)
705		    && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
706		    && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS))
707		    /*&&(pAd->bPCIclkOff == FALSE) */
708		    ) {
709			u32 data = 0;
710
711			/* Read GPIO pin2 as Hardware controlled radio state */
712#ifndef RT3090
713			RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data);
714#endif /* RT3090 // */
715/*KH(PCIE PS):Added based on Jane<-- */
716#ifdef RT3090
717/* Read GPIO pin2 as Hardware controlled radio state */
718/* We need to Read GPIO if HW said so no mater what advance power saving */
719			if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd))
720			    &&
721			    (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))
722			    && (pAd->StaCfg.PSControl.field.EnablePSinIdle ==
723				TRUE)) {
724				/* Want to make sure device goes to L0 state before reading register. */
725				RTMPPCIeLinkCtrlValueRestore(pAd, 0);
726				RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data);
727				RTMPPCIeLinkCtrlSetting(pAd, 3);
728			} else
729				RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data);
730#endif /* RT3090 // */
731/*KH(PCIE PS):Added based on Jane--> */
732
733			if (data & 0x04) {
734				pAd->StaCfg.bHwRadio = TRUE;
735			} else {
736				pAd->StaCfg.bHwRadio = FALSE;
737			}
738			if (pAd->StaCfg.bRadio !=
739			    (pAd->StaCfg.bHwRadio && pAd->StaCfg.bSwRadio)) {
740				pAd->StaCfg.bRadio = (pAd->StaCfg.bHwRadio
741						      && pAd->StaCfg.bSwRadio);
742				if (pAd->StaCfg.bRadio == TRUE) {
743					MlmeRadioOn(pAd);
744					/* Update extra information */
745					pAd->ExtraInfo = EXTRA_INFO_CLEAR;
746				} else {
747					MlmeRadioOff(pAd);
748					/* Update extra information */
749					pAd->ExtraInfo = HW_RADIO_OFF;
750				}
751			}
752		}
753	}
754#endif /* RTMP_MAC_PCI // */
755
756	/* Do nothing if the driver is starting halt state. */
757	/* This might happen when timer already been fired before cancel timer with mlmehalt */
758	if ((RTMP_TEST_FLAG(pAd, (fRTMP_ADAPTER_HALT_IN_PROGRESS |
759				  fRTMP_ADAPTER_RADIO_OFF |
760				  fRTMP_ADAPTER_RADIO_MEASUREMENT |
761				  fRTMP_ADAPTER_RESET_IN_PROGRESS))))
762		return;
763
764	RTMP_MLME_PRE_SANITY_CHECK(pAd);
765
766	{
767		/* Do nothing if monitor mode is on */
768		if (MONITOR_ON(pAd))
769			return;
770
771		if (pAd->Mlme.PeriodicRound & 0x1) {
772			/* This is the fix for wifi 11n extension channel overlapping test case.  for 2860D */
773			if (((pAd->MACVersion & 0xffff) == 0x0101) &&
774			    (STA_TGN_WIFI_ON(pAd)) &&
775			    (pAd->CommonCfg.IOTestParm.bToggle == FALSE))
776			{
777				RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x24Bf);
778				pAd->CommonCfg.IOTestParm.bToggle = TRUE;
779			} else if ((STA_TGN_WIFI_ON(pAd)) &&
780				   ((pAd->MACVersion & 0xffff) == 0x0101)) {
781				RTMP_IO_WRITE32(pAd, TXOP_CTRL_CFG, 0x243f);
782				pAd->CommonCfg.IOTestParm.bToggle = FALSE;
783			}
784		}
785	}
786
787	pAd->bUpdateBcnCntDone = FALSE;
788
789/*      RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); */
790	pAd->Mlme.PeriodicRound++;
791
792#ifdef RTMP_MAC_USB
793	/* execute every 100ms, update the Tx FIFO Cnt for update Tx Rate. */
794	NICUpdateFifoStaCounters(pAd);
795#endif /* RTMP_MAC_USB // */
796
797	/* execute every 500ms */
798	if ((pAd->Mlme.PeriodicRound % 5 == 0)
799	    && RTMPAutoRateSwitchCheck(pAd)
800	    /*(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)) */ )
801	{
802		/* perform dynamic tx rate switching based on past TX history */
803		{
804			if ((OPSTATUS_TEST_FLAG
805			     (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
806			    )
807			    && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)))
808				MlmeDynamicTxRateSwitching(pAd);
809		}
810	}
811	/* Normal 1 second Mlme PeriodicExec. */
812	if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE == 0) {
813		pAd->Mlme.OneSecPeriodicRound++;
814
815		/*ORIBATimerTimeout(pAd); */
816
817		/* Media status changed, report to NDIS */
818		if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE)) {
819			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_MEDIA_STATE_CHANGE);
820			if (OPSTATUS_TEST_FLAG
821			    (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
822				pAd->IndicateMediaState =
823				    NdisMediaStateConnected;
824				RTMP_IndicateMediaState(pAd);
825
826			} else {
827				pAd->IndicateMediaState =
828				    NdisMediaStateDisconnected;
829				RTMP_IndicateMediaState(pAd);
830			}
831		}
832
833		NdisGetSystemUpTime(&pAd->Mlme.Now32);
834
835		/* add the most up-to-date h/w raw counters into software variable, so that */
836		/* the dynamic tuning mechanism below are based on most up-to-date information */
837		NICUpdateRawCounters(pAd);
838
839#ifdef RTMP_MAC_USB
840		RTUSBWatchDog(pAd);
841#endif /* RTMP_MAC_USB // */
842
843		/* Need statistics after read counter. So put after NICUpdateRawCounters */
844		ORIBATimerTimeout(pAd);
845
846		/* if MGMT RING is full more than twice within 1 second, we consider there's */
847		/* a hardware problem stucking the TX path. In this case, try a hardware reset */
848		/* to recover the system */
849		/*      if (pAd->RalinkCounters.MgmtRingFullCount >= 2) */
850		/*              RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HARDWARE_ERROR); */
851		/*      else */
852		/*              pAd->RalinkCounters.MgmtRingFullCount = 0; */
853
854		/* The time period for checking antenna is according to traffic */
855		{
856			if (pAd->Mlme.bEnableAutoAntennaCheck) {
857				TxTotalCnt =
858				    pAd->RalinkCounters.OneSecTxNoRetryOkCount +
859				    pAd->RalinkCounters.OneSecTxRetryOkCount +
860				    pAd->RalinkCounters.OneSecTxFailCount;
861
862				/* dynamic adjust antenna evaluation period according to the traffic */
863				if (TxTotalCnt > 50) {
864					if (pAd->Mlme.OneSecPeriodicRound %
865					    10 == 0) {
866						AsicEvaluateRxAnt(pAd);
867					}
868				} else {
869					if (pAd->Mlme.OneSecPeriodicRound % 3 ==
870					    0) {
871						AsicEvaluateRxAnt(pAd);
872					}
873				}
874			}
875		}
876
877		STAMlmePeriodicExec(pAd);
878
879		MlmeResetRalinkCounters(pAd);
880
881		{
882#ifdef RTMP_MAC_PCI
883			if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)
884			    && (pAd->bPCIclkOff == FALSE))
885#endif /* RTMP_MAC_PCI // */
886			{
887				/* When Adhoc beacon is enabled and RTS/CTS is enabled, there is a chance that hardware MAC FSM will run into a deadlock */
888				/* and sending CTS-to-self over and over. */
889				/* Software Patch Solution: */
890				/* 1. Polling debug state register 0x10F4 every one second. */
891				/* 2. If in 0x10F4 the ((bit29==1) && (bit7==1)) OR ((bit29==1) && (bit5==1)), it means the deadlock has occurred. */
892				/* 3. If the deadlock occurred, reset MAC/BBP by setting 0x1004 to 0x0001 for a while then setting it back to 0x000C again. */
893
894				u32 MacReg = 0;
895
896				RTMP_IO_READ32(pAd, 0x10F4, &MacReg);
897				if (((MacReg & 0x20000000) && (MacReg & 0x80))
898				    || ((MacReg & 0x20000000)
899					&& (MacReg & 0x20))) {
900					RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x1);
901					RTMPusecDelay(1);
902					RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0xC);
903
904					DBGPRINT(RT_DEBUG_WARN,
905						 ("Warning, MAC specific condition occurs \n"));
906				}
907			}
908		}
909
910		RTMP_MLME_HANDLER(pAd);
911	}
912
913	pAd->bUpdateBcnCntDone = FALSE;
914}
915
916/*
917	==========================================================================
918	Validate SSID for connection try and rescan purpose
919	Valid SSID will have visible chars only.
920	The valid length is from 0 to 32.
921	IRQL = DISPATCH_LEVEL
922	==========================================================================
923 */
924BOOLEAN MlmeValidateSSID(u8 *pSsid, u8 SsidLen)
925{
926	int index;
927
928	if (SsidLen > MAX_LEN_OF_SSID)
929		return (FALSE);
930
931	/* Check each character value */
932	for (index = 0; index < SsidLen; index++) {
933		if (pSsid[index] < 0x20)
934			return (FALSE);
935	}
936
937	/* All checked */
938	return (TRUE);
939}
940
941void MlmeSelectTxRateTable(struct rt_rtmp_adapter *pAd,
942			   struct rt_mac_table_entry *pEntry,
943			   u8 ** ppTable,
944			   u8 *pTableSize, u8 *pInitTxRateIdx)
945{
946	do {
947		/* decide the rate table for tuning */
948		if (pAd->CommonCfg.TxRateTableSize > 0) {
949			*ppTable = RateSwitchTable;
950			*pTableSize = RateSwitchTable[0];
951			*pInitTxRateIdx = RateSwitchTable[1];
952
953			break;
954		}
955
956		if ((pAd->OpMode == OPMODE_STA) && ADHOC_ON(pAd)) {
957			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 */
958				*ppTable = RateSwitchTable11N1S;
959				*pTableSize = RateSwitchTable11N1S[0];
960				*pInitTxRateIdx = RateSwitchTable11N1S[1];
961
962			} 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 */
963				if (pAd->LatchRfRegs.Channel <= 14) {
964					*ppTable = RateSwitchTable11N2S;
965					*pTableSize = RateSwitchTable11N2S[0];
966					*pInitTxRateIdx =
967					    RateSwitchTable11N2S[1];
968				} else {
969					*ppTable = RateSwitchTable11N2SForABand;
970					*pTableSize =
971					    RateSwitchTable11N2SForABand[0];
972					*pInitTxRateIdx =
973					    RateSwitchTable11N2SForABand[1];
974				}
975
976			} else if ((pEntry->RateLen == 4)
977				   && (pEntry->HTCapability.MCSSet[0] == 0)
978				   && (pEntry->HTCapability.MCSSet[1] == 0)
979			    ) {
980				*ppTable = RateSwitchTable11B;
981				*pTableSize = RateSwitchTable11B[0];
982				*pInitTxRateIdx = RateSwitchTable11B[1];
983
984			} else if (pAd->LatchRfRegs.Channel <= 14) {
985				*ppTable = RateSwitchTable11BG;
986				*pTableSize = RateSwitchTable11BG[0];
987				*pInitTxRateIdx = RateSwitchTable11BG[1];
988
989			} else {
990				*ppTable = RateSwitchTable11G;
991				*pTableSize = RateSwitchTable11G[0];
992				*pInitTxRateIdx = RateSwitchTable11G[1];
993
994			}
995			break;
996		}
997		/*if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && */
998		/*      ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) */
999		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 */
1000			*ppTable = RateSwitchTable11BGN1S;
1001			*pTableSize = RateSwitchTable11BGN1S[0];
1002			*pInitTxRateIdx = RateSwitchTable11BGN1S[1];
1003
1004			break;
1005		}
1006		/*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 12) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && */
1007		/*      (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) */
1008		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 */
1009			if (pAd->LatchRfRegs.Channel <= 14) {
1010				*ppTable = RateSwitchTable11BGN2S;
1011				*pTableSize = RateSwitchTable11BGN2S[0];
1012				*pInitTxRateIdx = RateSwitchTable11BGN2S[1];
1013
1014			} else {
1015				*ppTable = RateSwitchTable11BGN2SForABand;
1016				*pTableSize = RateSwitchTable11BGN2SForABand[0];
1017				*pInitTxRateIdx =
1018				    RateSwitchTable11BGN2SForABand[1];
1019
1020			}
1021			break;
1022		}
1023		/*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && ((pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0x00) || (pAd->Antenna.field.TxPath == 1))) */
1024		if ((pEntry->HTCapability.MCSSet[0] == 0xff) && ((pEntry->HTCapability.MCSSet[1] == 0x00) || (pAd->CommonCfg.TxStream == 1))) {	/* 11N 1S AP */
1025			*ppTable = RateSwitchTable11N1S;
1026			*pTableSize = RateSwitchTable11N1S[0];
1027			*pInitTxRateIdx = RateSwitchTable11N1S[1];
1028
1029			break;
1030		}
1031		/*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0xff) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0xff) && (pAd->Antenna.field.TxPath == 2)) */
1032		if ((pEntry->HTCapability.MCSSet[0] == 0xff) && (pEntry->HTCapability.MCSSet[1] == 0xff) && (pAd->CommonCfg.TxStream == 2)) {	/* 11N 2S AP */
1033			if (pAd->LatchRfRegs.Channel <= 14) {
1034				*ppTable = RateSwitchTable11N2S;
1035				*pTableSize = RateSwitchTable11N2S[0];
1036				*pInitTxRateIdx = RateSwitchTable11N2S[1];
1037			} else {
1038				*ppTable = RateSwitchTable11N2SForABand;
1039				*pTableSize = RateSwitchTable11N2SForABand[0];
1040				*pInitTxRateIdx =
1041				    RateSwitchTable11N2SForABand[1];
1042			}
1043
1044			break;
1045		}
1046		/*else if ((pAd->StaActive.SupRateLen == 4) && (pAd->StaActive.ExtRateLen == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
1047		if ((pEntry->RateLen == 4 || pAd->CommonCfg.PhyMode == PHY_11B)
1048		    /*Iverson mark for Adhoc b mode,sta will use rate 54  Mbps when connect with sta b/g/n mode */
1049		    /* && (pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0) */
1050		    ) {		/* B only AP */
1051			*ppTable = RateSwitchTable11B;
1052			*pTableSize = RateSwitchTable11B[0];
1053			*pInitTxRateIdx = RateSwitchTable11B[1];
1054
1055			break;
1056		}
1057		/*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen > 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
1058		if ((pEntry->RateLen > 8)
1059		    && (pEntry->HTCapability.MCSSet[0] == 0)
1060		    && (pEntry->HTCapability.MCSSet[1] == 0)
1061		    ) {		/* B/G  mixed AP */
1062			*ppTable = RateSwitchTable11BG;
1063			*pTableSize = RateSwitchTable11BG[0];
1064			*pInitTxRateIdx = RateSwitchTable11BG[1];
1065
1066			break;
1067		}
1068		/*else if ((pAd->StaActive.SupRateLen + pAd->StaActive.ExtRateLen == 8) && (pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
1069		if ((pEntry->RateLen == 8)
1070		    && (pEntry->HTCapability.MCSSet[0] == 0)
1071		    && (pEntry->HTCapability.MCSSet[1] == 0)
1072		    ) {		/* G only AP */
1073			*ppTable = RateSwitchTable11G;
1074			*pTableSize = RateSwitchTable11G[0];
1075			*pInitTxRateIdx = RateSwitchTable11G[1];
1076
1077			break;
1078		}
1079
1080		{
1081			/*else if ((pAd->StaActive.SupportedPhyInfo.MCSSet[0] == 0) && (pAd->StaActive.SupportedPhyInfo.MCSSet[1] == 0)) */
1082			if ((pEntry->HTCapability.MCSSet[0] == 0) && (pEntry->HTCapability.MCSSet[1] == 0)) {	/* Legacy mode */
1083				if (pAd->CommonCfg.MaxTxRate <= RATE_11) {
1084					*ppTable = RateSwitchTable11B;
1085					*pTableSize = RateSwitchTable11B[0];
1086					*pInitTxRateIdx = RateSwitchTable11B[1];
1087				} else if ((pAd->CommonCfg.MaxTxRate > RATE_11)
1088					   && (pAd->CommonCfg.MinTxRate >
1089					       RATE_11)) {
1090					*ppTable = RateSwitchTable11G;
1091					*pTableSize = RateSwitchTable11G[0];
1092					*pInitTxRateIdx = RateSwitchTable11G[1];
1093
1094				} else {
1095					*ppTable = RateSwitchTable11BG;
1096					*pTableSize = RateSwitchTable11BG[0];
1097					*pInitTxRateIdx =
1098					    RateSwitchTable11BG[1];
1099				}
1100				break;
1101			}
1102			if (pAd->LatchRfRegs.Channel <= 14) {
1103				if (pAd->CommonCfg.TxStream == 1) {
1104					*ppTable = RateSwitchTable11N1S;
1105					*pTableSize = RateSwitchTable11N1S[0];
1106					*pInitTxRateIdx =
1107					    RateSwitchTable11N1S[1];
1108					DBGPRINT_RAW(RT_DEBUG_ERROR,
1109						     ("DRS: unkown mode,default use 11N 1S AP \n"));
1110				} else {
1111					*ppTable = RateSwitchTable11N2S;
1112					*pTableSize = RateSwitchTable11N2S[0];
1113					*pInitTxRateIdx =
1114					    RateSwitchTable11N2S[1];
1115					DBGPRINT_RAW(RT_DEBUG_ERROR,
1116						     ("DRS: unkown mode,default use 11N 2S AP \n"));
1117				}
1118			} else {
1119				if (pAd->CommonCfg.TxStream == 1) {
1120					*ppTable = RateSwitchTable11N1S;
1121					*pTableSize = RateSwitchTable11N1S[0];
1122					*pInitTxRateIdx =
1123					    RateSwitchTable11N1S[1];
1124					DBGPRINT_RAW(RT_DEBUG_ERROR,
1125						     ("DRS: unkown mode,default use 11N 1S AP \n"));
1126				} else {
1127					*ppTable = RateSwitchTable11N2SForABand;
1128					*pTableSize =
1129					    RateSwitchTable11N2SForABand[0];
1130					*pInitTxRateIdx =
1131					    RateSwitchTable11N2SForABand[1];
1132					DBGPRINT_RAW(RT_DEBUG_ERROR,
1133						     ("DRS: unkown mode,default use 11N 2S AP \n"));
1134				}
1135			}
1136			DBGPRINT_RAW(RT_DEBUG_ERROR,
1137				     ("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n",
1138				      pAd->StaActive.SupRateLen,
1139				      pAd->StaActive.ExtRateLen,
1140				      pAd->StaActive.SupportedPhyInfo.MCSSet[0],
1141				      pAd->StaActive.SupportedPhyInfo.
1142				      MCSSet[1]));
1143		}
1144	} while (FALSE);
1145}
1146
1147void STAMlmePeriodicExec(struct rt_rtmp_adapter *pAd)
1148{
1149	unsigned long TxTotalCnt;
1150	int i;
1151
1152	/*
1153	   We return here in ATE mode, because the statistics
1154	   that ATE need are not collected via this routine.
1155	 */
1156#if defined(RT305x)||defined(RT3070)
1157	/* request by Gary, if Rssi0 > -42, BBP 82 need to be changed from 0x62 to 0x42, , bbp 67 need to be changed from 0x20 to 0x18 */
1158	if (!pAd->CommonCfg.HighPowerPatchDisabled) {
1159#ifdef RT3070
1160		if ((IS_RT3070(pAd) && ((pAd->MACVersion & 0xffff) < 0x0201)))
1161#endif /* RT3070 // */
1162		{
1163			if ((pAd->StaCfg.RssiSample.AvgRssi0 != 0)
1164			    && (pAd->StaCfg.RssiSample.AvgRssi0 >
1165				(pAd->BbpRssiToDbmDelta - 35))) {
1166				RT30xxWriteRFRegister(pAd, RF_R27, 0x20);
1167			} else {
1168				RT30xxWriteRFRegister(pAd, RF_R27, 0x23);
1169			}
1170		}
1171	}
1172#endif
1173#ifdef PCIE_PS_SUPPORT
1174/* don't perform idle-power-save mechanism within 3 min after driver initialization. */
1175/* This can make rebooter test more robust */
1176	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) {
1177		if ((pAd->OpMode == OPMODE_STA) && (IDLE_ON(pAd))
1178		    && (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE)
1179		    && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)
1180		    && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF))) {
1181			if (IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) {
1182				if (pAd->StaCfg.PSControl.field.EnableNewPS ==
1183				    TRUE) {
1184					DBGPRINT(RT_DEBUG_TRACE,
1185						 ("%s\n", __func__));
1186					RT28xxPciAsicRadioOff(pAd,
1187							      GUI_IDLE_POWER_SAVE,
1188							      0);
1189				} else {
1190					AsicSendCommandToMcu(pAd, 0x30,
1191							     PowerSafeCID, 0xff,
1192							     0x2);
1193					/* Wait command success */
1194					AsicCheckCommanOk(pAd, PowerSafeCID);
1195					RTMP_SET_FLAG(pAd,
1196						      fRTMP_ADAPTER_IDLE_RADIO_OFF);
1197					DBGPRINT(RT_DEBUG_TRACE,
1198						 ("PSM - rt30xx Issue Sleep command)\n"));
1199				}
1200			} else if (pAd->Mlme.OneSecPeriodicRound > 180) {
1201				if (pAd->StaCfg.PSControl.field.EnableNewPS ==
1202				    TRUE) {
1203					DBGPRINT(RT_DEBUG_TRACE,
1204						 ("%s\n", __func__));
1205					RT28xxPciAsicRadioOff(pAd,
1206							      GUI_IDLE_POWER_SAVE,
1207							      0);
1208				} else {
1209					AsicSendCommandToMcu(pAd, 0x30,
1210							     PowerSafeCID, 0xff,
1211							     0x02);
1212					/* Wait command success */
1213					AsicCheckCommanOk(pAd, PowerSafeCID);
1214					RTMP_SET_FLAG(pAd,
1215						      fRTMP_ADAPTER_IDLE_RADIO_OFF);
1216					DBGPRINT(RT_DEBUG_TRACE,
1217						 ("PSM -  rt28xx Issue Sleep command)\n"));
1218				}
1219			}
1220		} else {
1221			DBGPRINT(RT_DEBUG_TRACE,
1222				 ("STAMlmePeriodicExec MMCHK - CommonCfg.Ssid[%d]=%c%c%c%c... MlmeAux.Ssid[%d]=%c%c%c%c...\n",
1223				  pAd->CommonCfg.SsidLen,
1224				  pAd->CommonCfg.Ssid[0],
1225				  pAd->CommonCfg.Ssid[1],
1226				  pAd->CommonCfg.Ssid[2],
1227				  pAd->CommonCfg.Ssid[3], pAd->MlmeAux.SsidLen,
1228				  pAd->MlmeAux.Ssid[0], pAd->MlmeAux.Ssid[1],
1229				  pAd->MlmeAux.Ssid[2], pAd->MlmeAux.Ssid[3]));
1230		}
1231	}
1232#endif /* PCIE_PS_SUPPORT // */
1233
1234	if (pAd->StaCfg.WpaSupplicantUP == WPA_SUPPLICANT_DISABLE) {
1235		/* WPA MIC error should block association attempt for 60 seconds */
1236		if (pAd->StaCfg.bBlockAssoc &&
1237		    RTMP_TIME_AFTER(pAd->Mlme.Now32,
1238				    pAd->StaCfg.LastMicErrorTime +
1239				    (60 * OS_HZ)))
1240			pAd->StaCfg.bBlockAssoc = FALSE;
1241	}
1242
1243	if ((pAd->PreMediaState != pAd->IndicateMediaState)
1244	    && (pAd->CommonCfg.bWirelessEvent)) {
1245		if (pAd->IndicateMediaState == NdisMediaStateConnected) {
1246			RTMPSendWirelessEvent(pAd, IW_STA_LINKUP_EVENT_FLAG,
1247					      pAd->MacTab.Content[BSSID_WCID].
1248					      Addr, BSS0, 0);
1249		}
1250		pAd->PreMediaState = pAd->IndicateMediaState;
1251	}
1252
1253	if (pAd->CommonCfg.PSPXlink && ADHOC_ON(pAd)) {
1254	} else {
1255		AsicStaBbpTuning(pAd);
1256	}
1257
1258	TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
1259	    pAd->RalinkCounters.OneSecTxRetryOkCount +
1260	    pAd->RalinkCounters.OneSecTxFailCount;
1261
1262	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
1263		/* update channel quality for Roaming and UI LinkQuality display */
1264		MlmeCalculateChannelQuality(pAd, NULL, pAd->Mlme.Now32);
1265	}
1266	/* must be AFTER MlmeDynamicTxRateSwitching() because it needs to know if */
1267	/* Radio is currently in noisy environment */
1268	if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1269		AsicAdjustTxPower(pAd);
1270
1271	if (INFRA_ON(pAd)) {
1272
1273		/* Is PSM bit consistent with user power management policy? */
1274		/* This is the only place that will set PSM bit ON. */
1275		if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
1276			MlmeCheckPsmChange(pAd, pAd->Mlme.Now32);
1277
1278		pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt;
1279
1280		if ((RTMP_TIME_AFTER
1281		     (pAd->Mlme.Now32,
1282		      pAd->StaCfg.LastBeaconRxTime + (1 * OS_HZ)))
1283		    &&
1284		    (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1285		    &&
1286		    (((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt) <
1287		      600))) {
1288			RTMPSetAGCInitValue(pAd, BW_20);
1289			DBGPRINT(RT_DEBUG_TRACE,
1290				 ("MMCHK - No BEACON. restore R66 to the low bound(%d) \n",
1291				  (0x2E + GET_LNA_GAIN(pAd))));
1292		}
1293		/*if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && */
1294		/*    (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) */
1295		{
1296			if (pAd->CommonCfg.bAPSDCapable
1297			    && pAd->CommonCfg.APEdcaParm.bAPSDCapable) {
1298				/* When APSD is enabled, the period changes as 20 sec */
1299				if ((pAd->Mlme.OneSecPeriodicRound % 20) == 8)
1300					RTMPSendNullFrame(pAd,
1301							  pAd->CommonCfg.TxRate,
1302							  TRUE);
1303			} else {
1304				/* Send out a NULL frame every 10 sec to inform AP that STA is still alive (Avoid being age out) */
1305				if ((pAd->Mlme.OneSecPeriodicRound % 10) == 8) {
1306					if (pAd->CommonCfg.bWmmCapable)
1307						RTMPSendNullFrame(pAd,
1308								  pAd->
1309								  CommonCfg.
1310								  TxRate, TRUE);
1311					else
1312						RTMPSendNullFrame(pAd,
1313								  pAd->
1314								  CommonCfg.
1315								  TxRate,
1316								  FALSE);
1317				}
1318			}
1319		}
1320
1321		if (CQI_IS_DEAD(pAd->Mlme.ChannelQuality)) {
1322			DBGPRINT(RT_DEBUG_TRACE,
1323				 ("MMCHK - No BEACON. Dead CQI. Auto Recovery attempt #%ld\n",
1324				  pAd->RalinkCounters.BadCQIAutoRecoveryCount));
1325
1326			/* Lost AP, send disconnect & link down event */
1327			LinkDown(pAd, FALSE);
1328
1329			RtmpOSWrielessEventSend(pAd, SIOCGIWAP, -1, NULL, NULL,
1330						0);
1331
1332			/* RTMPPatchMacBbpBug(pAd); */
1333			MlmeAutoReconnectLastSSID(pAd);
1334		} else if (CQI_IS_BAD(pAd->Mlme.ChannelQuality)) {
1335			pAd->RalinkCounters.BadCQIAutoRecoveryCount++;
1336			DBGPRINT(RT_DEBUG_TRACE,
1337				 ("MMCHK - Bad CQI. Auto Recovery attempt #%ld\n",
1338				  pAd->RalinkCounters.BadCQIAutoRecoveryCount));
1339			MlmeAutoReconnectLastSSID(pAd);
1340		}
1341
1342		if (pAd->StaCfg.bAutoRoaming) {
1343			BOOLEAN rv = FALSE;
1344			char dBmToRoam = pAd->StaCfg.dBmToRoam;
1345			char MaxRssi = RTMPMaxRssi(pAd,
1346						   pAd->StaCfg.RssiSample.
1347						   LastRssi0,
1348						   pAd->StaCfg.RssiSample.
1349						   LastRssi1,
1350						   pAd->StaCfg.RssiSample.
1351						   LastRssi2);
1352
1353			/* Scanning, ignore Roaming */
1354			if (!RTMP_TEST_FLAG
1355			    (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)
1356			    && (pAd->Mlme.SyncMachine.CurrState == SYNC_IDLE)
1357			    && (MaxRssi <= dBmToRoam)) {
1358				DBGPRINT(RT_DEBUG_TRACE,
1359					 ("Rssi=%d, dBmToRoam=%d\n", MaxRssi,
1360					  (char)dBmToRoam));
1361
1362				/* Add auto seamless roaming */
1363				if (rv == FALSE)
1364					rv = MlmeCheckForFastRoaming(pAd);
1365
1366				if (rv == FALSE) {
1367					if ((pAd->StaCfg.LastScanTime +
1368					     10 * OS_HZ) < pAd->Mlme.Now32) {
1369						DBGPRINT(RT_DEBUG_TRACE,
1370							 ("MMCHK - Roaming, No eligable entry, try new scan!\n"));
1371						pAd->StaCfg.ScanCnt = 2;
1372						pAd->StaCfg.LastScanTime =
1373						    pAd->Mlme.Now32;
1374						MlmeAutoScan(pAd);
1375					}
1376				}
1377			}
1378		}
1379	} else if (ADHOC_ON(pAd)) {
1380		/* If all peers leave, and this STA becomes the last one in this IBSS, then change MediaState */
1381		/* to DISCONNECTED. But still holding this IBSS (i.e. sending BEACON) so that other STAs can */
1382		/* join later. */
1383		if (RTMP_TIME_AFTER
1384		    (pAd->Mlme.Now32,
1385		     pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME)
1386		    && OPSTATUS_TEST_FLAG(pAd,
1387					  fOP_STATUS_MEDIA_STATE_CONNECTED)) {
1388			struct rt_mlme_start_req StartReq;
1389
1390			DBGPRINT(RT_DEBUG_TRACE,
1391				 ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n"));
1392			LinkDown(pAd, FALSE);
1393
1394			StartParmFill(pAd, &StartReq,
1395				      (char *) pAd->MlmeAux.Ssid,
1396				      pAd->MlmeAux.SsidLen);
1397			MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ,
1398				    sizeof(struct rt_mlme_start_req), &StartReq);
1399			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
1400		}
1401
1402		for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
1403			struct rt_mac_table_entry *pEntry = &pAd->MacTab.Content[i];
1404
1405			if (pEntry->ValidAsCLI == FALSE)
1406				continue;
1407
1408			if (RTMP_TIME_AFTER
1409			    (pAd->Mlme.Now32,
1410			     pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME))
1411				MacTableDeleteEntry(pAd, pEntry->Aid,
1412						    pEntry->Addr);
1413		}
1414	} else			/* no INFRA nor ADHOC connection */
1415	{
1416
1417		if (pAd->StaCfg.bScanReqIsFromWebUI &&
1418		    RTMP_TIME_BEFORE(pAd->Mlme.Now32,
1419				     pAd->StaCfg.LastScanTime + (30 * OS_HZ)))
1420			goto SKIP_AUTO_SCAN_CONN;
1421		else
1422			pAd->StaCfg.bScanReqIsFromWebUI = FALSE;
1423
1424		if ((pAd->StaCfg.bAutoReconnect == TRUE)
1425		    && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)
1426		    &&
1427		    (MlmeValidateSSID
1428		     (pAd->MlmeAux.AutoReconnectSsid,
1429		      pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) {
1430			if ((pAd->ScanTab.BssNr == 0)
1431			    && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) {
1432				struct rt_mlme_scan_req ScanReq;
1433
1434				if (RTMP_TIME_AFTER
1435				    (pAd->Mlme.Now32,
1436				     pAd->StaCfg.LastScanTime + (10 * OS_HZ))) {
1437					DBGPRINT(RT_DEBUG_TRACE,
1438						 ("STAMlmePeriodicExec():CNTL - ScanTab.BssNr==0, start a new ACTIVE scan SSID[%s]\n",
1439						  pAd->MlmeAux.
1440						  AutoReconnectSsid));
1441					ScanParmFill(pAd, &ScanReq,
1442						     (char *)pAd->MlmeAux.
1443						     AutoReconnectSsid,
1444						     pAd->MlmeAux.
1445						     AutoReconnectSsidLen,
1446						     BSS_ANY, SCAN_ACTIVE);
1447					MlmeEnqueue(pAd, SYNC_STATE_MACHINE,
1448						    MT2_MLME_SCAN_REQ,
1449						    sizeof
1450						    (struct rt_mlme_scan_req),
1451						    &ScanReq);
1452					pAd->Mlme.CntlMachine.CurrState =
1453					    CNTL_WAIT_OID_LIST_SCAN;
1454					/* Reset Missed scan number */
1455					pAd->StaCfg.LastScanTime =
1456					    pAd->Mlme.Now32;
1457				} else if (pAd->StaCfg.BssType == BSS_ADHOC)	/* Quit the forever scan when in a very clean room */
1458					MlmeAutoReconnectLastSSID(pAd);
1459			} else if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
1460				if ((pAd->Mlme.OneSecPeriodicRound % 7) == 0) {
1461					MlmeAutoScan(pAd);
1462					pAd->StaCfg.LastScanTime =
1463					    pAd->Mlme.Now32;
1464				} else {
1465					MlmeAutoReconnectLastSSID(pAd);
1466				}
1467			}
1468		}
1469	}
1470
1471SKIP_AUTO_SCAN_CONN:
1472
1473	if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap != 0)
1474	    && (pAd->MacTab.fAnyBASession == FALSE)) {
1475		pAd->MacTab.fAnyBASession = TRUE;
1476		AsicUpdateProtect(pAd, HT_FORCERTSCTS, ALLN_SETPROTECT, FALSE,
1477				  FALSE);
1478	} else if ((pAd->MacTab.Content[BSSID_WCID].TXBAbitmap == 0)
1479		   && (pAd->MacTab.fAnyBASession == TRUE)) {
1480		pAd->MacTab.fAnyBASession = FALSE;
1481		AsicUpdateProtect(pAd,
1482				  pAd->MlmeAux.AddHtInfo.AddHtInfo2.
1483				  OperaionMode, ALLN_SETPROTECT, FALSE, FALSE);
1484	}
1485
1486	return;
1487}
1488
1489/* Link down report */
1490void LinkDownExec(void *SystemSpecific1,
1491		  void *FunctionContext,
1492		  void *SystemSpecific2, void *SystemSpecific3)
1493{
1494	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
1495
1496	if (pAd != NULL) {
1497		struct rt_mlme_disassoc_req DisassocReq;
1498
1499		if ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) &&
1500		    (INFRA_ON(pAd))) {
1501			DBGPRINT(RT_DEBUG_TRACE,
1502				 ("LinkDownExec(): disassociate with current AP...\n"));
1503			DisassocParmFill(pAd, &DisassocReq,
1504					 pAd->CommonCfg.Bssid,
1505					 REASON_DISASSOC_STA_LEAVING);
1506			MlmeEnqueue(pAd, ASSOC_STATE_MACHINE,
1507				    MT2_MLME_DISASSOC_REQ,
1508				    sizeof(struct rt_mlme_disassoc_req),
1509				    &DisassocReq);
1510			pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
1511
1512			pAd->IndicateMediaState = NdisMediaStateDisconnected;
1513			RTMP_IndicateMediaState(pAd);
1514			pAd->ExtraInfo = GENERAL_LINK_DOWN;
1515		}
1516	}
1517}
1518
1519/* IRQL = DISPATCH_LEVEL */
1520void MlmeAutoScan(struct rt_rtmp_adapter *pAd)
1521{
1522	/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
1523	if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
1524		DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n"));
1525		MlmeEnqueue(pAd,
1526			    MLME_CNTL_STATE_MACHINE,
1527			    OID_802_11_BSSID_LIST_SCAN,
1528			    pAd->MlmeAux.AutoReconnectSsidLen,
1529			    pAd->MlmeAux.AutoReconnectSsid);
1530		RTMP_MLME_HANDLER(pAd);
1531	}
1532}
1533
1534/* IRQL = DISPATCH_LEVEL */
1535void MlmeAutoReconnectLastSSID(struct rt_rtmp_adapter *pAd)
1536{
1537	if (pAd->StaCfg.bAutoConnectByBssid) {
1538		DBGPRINT(RT_DEBUG_TRACE,
1539			 ("Driver auto reconnect to last OID_802_11_BSSID setting - %02X:%02X:%02X:%02X:%02X:%02X\n",
1540			  pAd->MlmeAux.Bssid[0], pAd->MlmeAux.Bssid[1],
1541			  pAd->MlmeAux.Bssid[2], pAd->MlmeAux.Bssid[3],
1542			  pAd->MlmeAux.Bssid[4], pAd->MlmeAux.Bssid[5]));
1543
1544		pAd->MlmeAux.Channel = pAd->CommonCfg.Channel;
1545		MlmeEnqueue(pAd,
1546			    MLME_CNTL_STATE_MACHINE,
1547			    OID_802_11_BSSID, MAC_ADDR_LEN, pAd->MlmeAux.Bssid);
1548
1549		pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
1550
1551		RTMP_MLME_HANDLER(pAd);
1552	}
1553	/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
1554	else if ((pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
1555		 (MlmeValidateSSID
1556		  (pAd->MlmeAux.AutoReconnectSsid,
1557		   pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) {
1558		struct rt_ndis_802_11_ssid OidSsid;
1559		OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen;
1560		NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid,
1561			       pAd->MlmeAux.AutoReconnectSsidLen);
1562
1563		DBGPRINT(RT_DEBUG_TRACE,
1564			 ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n",
1565			  pAd->MlmeAux.AutoReconnectSsid,
1566			  pAd->MlmeAux.AutoReconnectSsidLen));
1567		MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, OID_802_11_SSID,
1568			    sizeof(struct rt_ndis_802_11_ssid), &OidSsid);
1569		RTMP_MLME_HANDLER(pAd);
1570	}
1571}
1572
1573/*
1574	==========================================================================
1575	Description:
1576		This routine checks if there're other APs out there capable for
1577		roaming. Caller should call this routine only when Link up in INFRA mode
1578		and channel quality is below CQI_GOOD_THRESHOLD.
1579
1580	IRQL = DISPATCH_LEVEL
1581
1582	Output:
1583	==========================================================================
1584 */
1585void MlmeCheckForRoaming(struct rt_rtmp_adapter *pAd, unsigned long Now32)
1586{
1587	u16 i;
1588	struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
1589	struct rt_bss_entry *pBss;
1590
1591	DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n"));
1592	/* put all roaming candidates into RoamTab, and sort in RSSI order */
1593	BssTableInit(pRoamTab);
1594	for (i = 0; i < pAd->ScanTab.BssNr; i++) {
1595		pBss = &pAd->ScanTab.BssEntry[i];
1596
1597		if ((pBss->LastBeaconRxTime + pAd->StaCfg.BeaconLostTime) <
1598		    Now32)
1599			continue;	/* AP disappear */
1600		if (pBss->Rssi <= RSSI_THRESHOLD_FOR_ROAMING)
1601			continue;	/* RSSI too weak. forget it. */
1602		if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid))
1603			continue;	/* skip current AP */
1604		if (pBss->Rssi <
1605		    (pAd->StaCfg.RssiSample.LastRssi0 + RSSI_DELTA))
1606			continue;	/* only AP with stronger RSSI is eligible for roaming */
1607
1608		/* AP passing all above rules is put into roaming candidate table */
1609		NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss,
1610			       sizeof(struct rt_bss_entry));
1611		pRoamTab->BssNr += 1;
1612	}
1613
1614	if (pRoamTab->BssNr > 0) {
1615		/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
1616		if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
1617			pAd->RalinkCounters.PoorCQIRoamingCount++;
1618			DBGPRINT(RT_DEBUG_TRACE,
1619				 ("MMCHK - Roaming attempt #%ld\n",
1620				  pAd->RalinkCounters.PoorCQIRoamingCount));
1621			MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE,
1622				    MT2_MLME_ROAMING_REQ, 0, NULL);
1623			RTMP_MLME_HANDLER(pAd);
1624		}
1625	}
1626	DBGPRINT(RT_DEBUG_TRACE,
1627		 ("<== MlmeCheckForRoaming(# of candidate= %d)\n",
1628		  pRoamTab->BssNr));
1629}
1630
1631/*
1632	==========================================================================
1633	Description:
1634		This routine checks if there're other APs out there capable for
1635		roaming. Caller should call this routine only when link up in INFRA mode
1636		and channel quality is below CQI_GOOD_THRESHOLD.
1637
1638	IRQL = DISPATCH_LEVEL
1639
1640	Output:
1641	==========================================================================
1642 */
1643BOOLEAN MlmeCheckForFastRoaming(struct rt_rtmp_adapter *pAd)
1644{
1645	u16 i;
1646	struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
1647	struct rt_bss_entry *pBss;
1648
1649	DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n"));
1650	/* put all roaming candidates into RoamTab, and sort in RSSI order */
1651	BssTableInit(pRoamTab);
1652	for (i = 0; i < pAd->ScanTab.BssNr; i++) {
1653		pBss = &pAd->ScanTab.BssEntry[i];
1654
1655		if ((pBss->Rssi <= -50)
1656		    && (pBss->Channel == pAd->CommonCfg.Channel))
1657			continue;	/* RSSI too weak. forget it. */
1658		if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid))
1659			continue;	/* skip current AP */
1660		if (!SSID_EQUAL
1661		    (pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid,
1662		     pAd->CommonCfg.SsidLen))
1663			continue;	/* skip different SSID */
1664		if (pBss->Rssi <
1665		    (RTMPMaxRssi
1666		     (pAd, pAd->StaCfg.RssiSample.LastRssi0,
1667		      pAd->StaCfg.RssiSample.LastRssi1,
1668		      pAd->StaCfg.RssiSample.LastRssi2) + RSSI_DELTA))
1669			continue;	/* skip AP without better RSSI */
1670
1671		DBGPRINT(RT_DEBUG_TRACE,
1672			 ("LastRssi0 = %d, pBss->Rssi = %d\n",
1673			  RTMPMaxRssi(pAd, pAd->StaCfg.RssiSample.LastRssi0,
1674				      pAd->StaCfg.RssiSample.LastRssi1,
1675				      pAd->StaCfg.RssiSample.LastRssi2),
1676			  pBss->Rssi));
1677		/* AP passing all above rules is put into roaming candidate table */
1678		NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss,
1679			       sizeof(struct rt_bss_entry));
1680		pRoamTab->BssNr += 1;
1681	}
1682
1683	DBGPRINT(RT_DEBUG_TRACE,
1684		 ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr));
1685	if (pRoamTab->BssNr > 0) {
1686		/* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
1687		if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
1688			pAd->RalinkCounters.PoorCQIRoamingCount++;
1689			DBGPRINT(RT_DEBUG_TRACE,
1690				 ("MMCHK - Roaming attempt #%ld\n",
1691				  pAd->RalinkCounters.PoorCQIRoamingCount));
1692			MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE,
1693				    MT2_MLME_ROAMING_REQ, 0, NULL);
1694			RTMP_MLME_HANDLER(pAd);
1695			return TRUE;
1696		}
1697	}
1698
1699	return FALSE;
1700}
1701
1702void MlmeSetTxRate(struct rt_rtmp_adapter *pAd,
1703		   struct rt_mac_table_entry *pEntry, struct rt_rtmp_tx_rate_switch * pTxRate)
1704{
1705	u8 MaxMode = MODE_OFDM;
1706
1707	MaxMode = MODE_HTGREENFIELD;
1708
1709	if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC)
1710	    && (pAd->Antenna.field.TxPath == 2))
1711		pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE;
1712	else
1713		pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE;
1714
1715	if (pTxRate->CurrMCS < MCS_AUTO)
1716		pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS;
1717
1718	if (pAd->StaCfg.HTPhyMode.field.MCS > 7)
1719		pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE;
1720
1721	if (ADHOC_ON(pAd)) {
1722		/* If peer adhoc is b-only mode, we can't send 11g rate. */
1723		pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
1724		pEntry->HTPhyMode.field.STBC = STBC_NONE;
1725
1726		/* */
1727		/* For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary */
1728		/* */
1729		pEntry->HTPhyMode.field.MODE = pTxRate->Mode;
1730		pEntry->HTPhyMode.field.ShortGI =
1731		    pAd->StaCfg.HTPhyMode.field.ShortGI;
1732		pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS;
1733
1734		/* Patch speed error in status page */
1735		pAd->StaCfg.HTPhyMode.field.MODE = pEntry->HTPhyMode.field.MODE;
1736	} else {
1737		if (pTxRate->Mode <= MaxMode)
1738			pAd->StaCfg.HTPhyMode.field.MODE = pTxRate->Mode;
1739
1740		if (pTxRate->ShortGI
1741		    && (pAd->StaCfg.MaxHTPhyMode.field.ShortGI))
1742			pAd->StaCfg.HTPhyMode.field.ShortGI = GI_400;
1743		else
1744			pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
1745
1746		/* Reexam each bandwidth's SGI support. */
1747		if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) {
1748			if ((pEntry->HTPhyMode.field.BW == BW_20)
1749			    &&
1750			    (!CLIENT_STATUS_TEST_FLAG
1751			     (pEntry, fCLIENT_STATUS_SGI20_CAPABLE)))
1752				pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
1753			if ((pEntry->HTPhyMode.field.BW == BW_40)
1754			    &&
1755			    (!CLIENT_STATUS_TEST_FLAG
1756			     (pEntry, fCLIENT_STATUS_SGI40_CAPABLE)))
1757				pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
1758		}
1759		/* Turn RTS/CTS rate to 6Mbps. */
1760		if ((pEntry->HTPhyMode.field.MCS == 0)
1761		    && (pAd->StaCfg.HTPhyMode.field.MCS != 0)) {
1762			pEntry->HTPhyMode.field.MCS =
1763			    pAd->StaCfg.HTPhyMode.field.MCS;
1764			if (pAd->MacTab.fAnyBASession) {
1765				AsicUpdateProtect(pAd, HT_FORCERTSCTS,
1766						  ALLN_SETPROTECT, TRUE,
1767						  (BOOLEAN) pAd->MlmeAux.
1768						  AddHtInfo.AddHtInfo2.
1769						  NonGfPresent);
1770			} else {
1771				AsicUpdateProtect(pAd,
1772						  pAd->MlmeAux.AddHtInfo.
1773						  AddHtInfo2.OperaionMode,
1774						  ALLN_SETPROTECT, TRUE,
1775						  (BOOLEAN) pAd->MlmeAux.
1776						  AddHtInfo.AddHtInfo2.
1777						  NonGfPresent);
1778			}
1779		} else if ((pEntry->HTPhyMode.field.MCS == 8)
1780			   && (pAd->StaCfg.HTPhyMode.field.MCS != 8)) {
1781			pEntry->HTPhyMode.field.MCS =
1782			    pAd->StaCfg.HTPhyMode.field.MCS;
1783			if (pAd->MacTab.fAnyBASession) {
1784				AsicUpdateProtect(pAd, HT_FORCERTSCTS,
1785						  ALLN_SETPROTECT, TRUE,
1786						  (BOOLEAN) pAd->MlmeAux.
1787						  AddHtInfo.AddHtInfo2.
1788						  NonGfPresent);
1789			} else {
1790				AsicUpdateProtect(pAd,
1791						  pAd->MlmeAux.AddHtInfo.
1792						  AddHtInfo2.OperaionMode,
1793						  ALLN_SETPROTECT, TRUE,
1794						  (BOOLEAN) pAd->MlmeAux.
1795						  AddHtInfo.AddHtInfo2.
1796						  NonGfPresent);
1797			}
1798		} else if ((pEntry->HTPhyMode.field.MCS != 0)
1799			   && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) {
1800			AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT,
1801					  TRUE,
1802					  (BOOLEAN) pAd->MlmeAux.AddHtInfo.
1803					  AddHtInfo2.NonGfPresent);
1804
1805		} else if ((pEntry->HTPhyMode.field.MCS != 8)
1806			   && (pAd->StaCfg.HTPhyMode.field.MCS == 8)) {
1807			AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT,
1808					  TRUE,
1809					  (BOOLEAN) pAd->MlmeAux.AddHtInfo.
1810					  AddHtInfo2.NonGfPresent);
1811		}
1812
1813		pEntry->HTPhyMode.field.STBC = pAd->StaCfg.HTPhyMode.field.STBC;
1814		pEntry->HTPhyMode.field.ShortGI =
1815		    pAd->StaCfg.HTPhyMode.field.ShortGI;
1816		pEntry->HTPhyMode.field.MCS = pAd->StaCfg.HTPhyMode.field.MCS;
1817		pEntry->HTPhyMode.field.MODE = pAd->StaCfg.HTPhyMode.field.MODE;
1818		if ((pAd->StaCfg.MaxHTPhyMode.field.MODE == MODE_HTGREENFIELD)
1819		    && pAd->WIFItestbed.bGreenField)
1820			pEntry->HTPhyMode.field.MODE = MODE_HTGREENFIELD;
1821	}
1822
1823	pAd->LastTxRate = (u16)(pEntry->HTPhyMode.word);
1824}
1825
1826/*
1827	==========================================================================
1828	Description:
1829		This routine calculates the acumulated TxPER of eaxh TxRate. And
1830		according to the calculation result, change CommonCfg.TxRate which
1831		is the stable TX Rate we expect the Radio situation could sustained.
1832
1833		CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate}
1834	Output:
1835		CommonCfg.TxRate -
1836
1837	IRQL = DISPATCH_LEVEL
1838
1839	NOTE:
1840		call this routine every second
1841	==========================================================================
1842 */
1843void MlmeDynamicTxRateSwitching(struct rt_rtmp_adapter *pAd)
1844{
1845	u8 UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
1846	unsigned long i, AccuTxTotalCnt = 0, TxTotalCnt;
1847	unsigned long TxErrorRatio = 0;
1848	BOOLEAN bTxRateChanged = FALSE, bUpgradeQuality = FALSE;
1849	struct rt_rtmp_tx_rate_switch *pCurrTxRate, *pNextTxRate = NULL;
1850	u8 *pTable;
1851	u8 TableSize = 0;
1852	u8 InitTxRateIdx = 0, TrainUp, TrainDown;
1853	char Rssi, RssiOffset = 0;
1854	TX_STA_CNT1_STRUC StaTx1;
1855	TX_STA_CNT0_STRUC TxStaCnt0;
1856	unsigned long TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
1857	struct rt_mac_table_entry *pEntry;
1858	struct rt_rssi_sample *pRssi = &pAd->StaCfg.RssiSample;
1859
1860	/* */
1861	/* walk through MAC table, see if need to change AP's TX rate toward each entry */
1862	/* */
1863	for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
1864		pEntry = &pAd->MacTab.Content[i];
1865
1866		/* check if this entry need to switch rate automatically */
1867		if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
1868			continue;
1869
1870		if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) {
1871			Rssi = RTMPMaxRssi(pAd,
1872					   pRssi->AvgRssi0,
1873					   pRssi->AvgRssi1, pRssi->AvgRssi2);
1874
1875			/* Update statistic counter */
1876			RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
1877			RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
1878			pAd->bUpdateBcnCntDone = TRUE;
1879			TxRetransmit = StaTx1.field.TxRetransmit;
1880			TxSuccess = StaTx1.field.TxSuccess;
1881			TxFailCount = TxStaCnt0.field.TxFailCount;
1882			TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
1883
1884			pAd->RalinkCounters.OneSecTxRetryOkCount +=
1885			    StaTx1.field.TxRetransmit;
1886			pAd->RalinkCounters.OneSecTxNoRetryOkCount +=
1887			    StaTx1.field.TxSuccess;
1888			pAd->RalinkCounters.OneSecTxFailCount +=
1889			    TxStaCnt0.field.TxFailCount;
1890			pAd->WlanCounters.TransmittedFragmentCount.u.LowPart +=
1891			    StaTx1.field.TxSuccess;
1892			pAd->WlanCounters.RetryCount.u.LowPart +=
1893			    StaTx1.field.TxRetransmit;
1894			pAd->WlanCounters.FailedCount.u.LowPart +=
1895			    TxStaCnt0.field.TxFailCount;
1896
1897			/* if no traffic in the past 1-sec period, don't change TX rate, */
1898			/* but clear all bad history. because the bad history may affect the next */
1899			/* Chariot throughput test */
1900			AccuTxTotalCnt =
1901			    pAd->RalinkCounters.OneSecTxNoRetryOkCount +
1902			    pAd->RalinkCounters.OneSecTxRetryOkCount +
1903			    pAd->RalinkCounters.OneSecTxFailCount;
1904
1905			if (TxTotalCnt)
1906				TxErrorRatio =
1907				    ((TxRetransmit +
1908				      TxFailCount) * 100) / TxTotalCnt;
1909		} else {
1910			if (INFRA_ON(pAd) && (i == 1))
1911				Rssi = RTMPMaxRssi(pAd,
1912						   pRssi->AvgRssi0,
1913						   pRssi->AvgRssi1,
1914						   pRssi->AvgRssi2);
1915			else
1916				Rssi = RTMPMaxRssi(pAd,
1917						   pEntry->RssiSample.AvgRssi0,
1918						   pEntry->RssiSample.AvgRssi1,
1919						   pEntry->RssiSample.AvgRssi2);
1920
1921			TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
1922			    pEntry->OneSecTxRetryOkCount +
1923			    pEntry->OneSecTxFailCount;
1924
1925			if (TxTotalCnt)
1926				TxErrorRatio =
1927				    ((pEntry->OneSecTxRetryOkCount +
1928				      pEntry->OneSecTxFailCount) * 100) /
1929				    TxTotalCnt;
1930		}
1931
1932		if (TxTotalCnt) {
1933			/*
1934			   Three AdHoc connections can not work normally if one AdHoc connection is disappeared from a heavy traffic environment generated by ping tool
1935			   We force to set LongRtyLimit and ShortRtyLimit to 0 to stop retransmitting packet, after a while, resoring original settings
1936			 */
1937			if (TxErrorRatio == 100) {
1938				TX_RTY_CFG_STRUC TxRtyCfg, TxRtyCfgtmp;
1939				unsigned long Index;
1940				unsigned long MACValue;
1941
1942				RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word);
1943				TxRtyCfgtmp.word = TxRtyCfg.word;
1944				TxRtyCfg.field.LongRtyLimit = 0x0;
1945				TxRtyCfg.field.ShortRtyLimit = 0x0;
1946				RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word);
1947
1948				RTMPusecDelay(1);
1949
1950				Index = 0;
1951				MACValue = 0;
1952				do {
1953					RTMP_IO_READ32(pAd, TXRXQ_PCNT,
1954						       &MACValue);
1955					if ((MACValue & 0xffffff) == 0)
1956						break;
1957					Index++;
1958					RTMPusecDelay(1000);
1959				} while ((Index < 330)
1960					 &&
1961					 (!RTMP_TEST_FLAG
1962					  (pAd,
1963					   fRTMP_ADAPTER_HALT_IN_PROGRESS)));
1964
1965				RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word);
1966				TxRtyCfg.field.LongRtyLimit =
1967				    TxRtyCfgtmp.field.LongRtyLimit;
1968				TxRtyCfg.field.ShortRtyLimit =
1969				    TxRtyCfgtmp.field.ShortRtyLimit;
1970				RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word);
1971			}
1972		}
1973
1974		CurrRateIdx = pEntry->CurrTxRateIndex;
1975
1976		MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
1977				      &InitTxRateIdx);
1978
1979		if (CurrRateIdx >= TableSize) {
1980			CurrRateIdx = TableSize - 1;
1981		}
1982		/* When switch from Fixed rate -> auto rate, the REAL TX rate might be different from pAd->CommonCfg.TxRateIndex. */
1983		/* So need to sync here. */
1984		pCurrTxRate =
1985		    (struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
1986		if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS)
1987		    /*&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) */
1988		    ) {
1989
1990			/* Need to sync Real Tx rate and our record. */
1991			/* Then return for next DRS. */
1992			pCurrTxRate =
1993			    (struct rt_rtmp_tx_rate_switch *) & pTable[(InitTxRateIdx + 1)
1994							    * 5];
1995			pEntry->CurrTxRateIndex = InitTxRateIdx;
1996			MlmeSetTxRate(pAd, pEntry, pCurrTxRate);
1997
1998			/* reset all OneSecTx counters */
1999			RESET_ONE_SEC_TX_CNT(pEntry);
2000			continue;
2001		}
2002		/* decide the next upgrade rate and downgrade rate, if any */
2003		if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) {
2004			UpRateIdx = CurrRateIdx + 1;
2005			DownRateIdx = CurrRateIdx - 1;
2006		} else if (CurrRateIdx == 0) {
2007			UpRateIdx = CurrRateIdx + 1;
2008			DownRateIdx = CurrRateIdx;
2009		} else if (CurrRateIdx == (TableSize - 1)) {
2010			UpRateIdx = CurrRateIdx;
2011			DownRateIdx = CurrRateIdx - 1;
2012		}
2013
2014		pCurrTxRate =
2015		    (struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
2016
2017		if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) {
2018			TrainUp =
2019			    (pCurrTxRate->TrainUp +
2020			     (pCurrTxRate->TrainUp >> 1));
2021			TrainDown =
2022			    (pCurrTxRate->TrainDown +
2023			     (pCurrTxRate->TrainDown >> 1));
2024		} else {
2025			TrainUp = pCurrTxRate->TrainUp;
2026			TrainDown = pCurrTxRate->TrainDown;
2027		}
2028
2029		/*pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; */
2030
2031		/* */
2032		/* Keep the last time TxRateChangeAction status. */
2033		/* */
2034		pEntry->LastTimeTxRateChangeAction =
2035		    pEntry->LastSecTxRateChangeAction;
2036
2037		/* */
2038		/* CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI */
2039		/*         (criteria copied from RT2500 for Netopia case) */
2040		/* */
2041		if (TxTotalCnt <= 15) {
2042			char idx = 0;
2043			u8 TxRateIdx;
2044			u8 MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 =
2045			    0, MCS5 = 0, MCS6 = 0, MCS7 = 0;
2046			u8 MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
2047			u8 MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0;	/* 3*3 */
2048
2049			/* check the existence and index of each needed MCS */
2050			while (idx < pTable[0]) {
2051				pCurrTxRate =
2052				    (struct rt_rtmp_tx_rate_switch *) & pTable[(idx + 1) *
2053								    5];
2054
2055				if (pCurrTxRate->CurrMCS == MCS_0) {
2056					MCS0 = idx;
2057				} else if (pCurrTxRate->CurrMCS == MCS_1) {
2058					MCS1 = idx;
2059				} else if (pCurrTxRate->CurrMCS == MCS_2) {
2060					MCS2 = idx;
2061				} else if (pCurrTxRate->CurrMCS == MCS_3) {
2062					MCS3 = idx;
2063				} else if (pCurrTxRate->CurrMCS == MCS_4) {
2064					MCS4 = idx;
2065				} else if (pCurrTxRate->CurrMCS == MCS_5) {
2066					MCS5 = idx;
2067				} else if (pCurrTxRate->CurrMCS == MCS_6) {
2068					MCS6 = idx;
2069				}
2070				/*else if (pCurrTxRate->CurrMCS == MCS_7) */
2071				else if ((pCurrTxRate->CurrMCS == MCS_7) && (pCurrTxRate->ShortGI == GI_800))	/* prevent the highest MCS using short GI when 1T and low throughput */
2072				{
2073					MCS7 = idx;
2074				} else if (pCurrTxRate->CurrMCS == MCS_12) {
2075					MCS12 = idx;
2076				} else if (pCurrTxRate->CurrMCS == MCS_13) {
2077					MCS13 = idx;
2078				} else if (pCurrTxRate->CurrMCS == MCS_14) {
2079					MCS14 = idx;
2080				}
2081				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 */
2082				{
2083					MCS15 = idx;
2084				} else if (pCurrTxRate->CurrMCS == MCS_20)	/* 3*3 */
2085				{
2086					MCS20 = idx;
2087				} else if (pCurrTxRate->CurrMCS == MCS_21) {
2088					MCS21 = idx;
2089				} else if (pCurrTxRate->CurrMCS == MCS_22) {
2090					MCS22 = idx;
2091				} else if (pCurrTxRate->CurrMCS == MCS_23) {
2092					MCS23 = idx;
2093				}
2094				idx++;
2095			}
2096
2097			if (pAd->LatchRfRegs.Channel <= 14) {
2098				if (pAd->NicConfig2.field.ExternalLNAForG) {
2099					RssiOffset = 2;
2100				} else {
2101					RssiOffset = 5;
2102				}
2103			} else {
2104				if (pAd->NicConfig2.field.ExternalLNAForA) {
2105					RssiOffset = 5;
2106				} else {
2107					RssiOffset = 8;
2108				}
2109			}
2110
2111			/*if (MCS15) */
2112			if ((pTable == RateSwitchTable11BGN3S) || (pTable == RateSwitchTable11N3S) || (pTable == RateSwitchTable)) {	/* N mode with 3 stream // 3*3 */
2113				if (MCS23 && (Rssi >= -70))
2114					TxRateIdx = MCS23;
2115				else if (MCS22 && (Rssi >= -72))
2116					TxRateIdx = MCS22;
2117				else if (MCS21 && (Rssi >= -76))
2118					TxRateIdx = MCS21;
2119				else if (MCS20 && (Rssi >= -78))
2120					TxRateIdx = MCS20;
2121				else if (MCS4 && (Rssi >= -82))
2122					TxRateIdx = MCS4;
2123				else if (MCS3 && (Rssi >= -84))
2124					TxRateIdx = MCS3;
2125				else if (MCS2 && (Rssi >= -86))
2126					TxRateIdx = MCS2;
2127				else if (MCS1 && (Rssi >= -88))
2128					TxRateIdx = MCS1;
2129				else
2130					TxRateIdx = MCS0;
2131			}
2132/*              else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) */
2133			else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) || (pTable == RateSwitchTable11N2S) || (pTable == RateSwitchTable11N2SForABand))	/* 3*3 */
2134			{	/* N mode with 2 stream */
2135				if (MCS15 && (Rssi >= (-70 + RssiOffset)))
2136					TxRateIdx = MCS15;
2137				else if (MCS14 && (Rssi >= (-72 + RssiOffset)))
2138					TxRateIdx = MCS14;
2139				else if (MCS13 && (Rssi >= (-76 + RssiOffset)))
2140					TxRateIdx = MCS13;
2141				else if (MCS12 && (Rssi >= (-78 + RssiOffset)))
2142					TxRateIdx = MCS12;
2143				else if (MCS4 && (Rssi >= (-82 + RssiOffset)))
2144					TxRateIdx = MCS4;
2145				else if (MCS3 && (Rssi >= (-84 + RssiOffset)))
2146					TxRateIdx = MCS3;
2147				else if (MCS2 && (Rssi >= (-86 + RssiOffset)))
2148					TxRateIdx = MCS2;
2149				else if (MCS1 && (Rssi >= (-88 + RssiOffset)))
2150					TxRateIdx = MCS1;
2151				else
2152					TxRateIdx = MCS0;
2153			} else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) {	/* N mode with 1 stream */
2154				if (MCS7 && (Rssi > (-72 + RssiOffset)))
2155					TxRateIdx = MCS7;
2156				else if (MCS6 && (Rssi > (-74 + RssiOffset)))
2157					TxRateIdx = MCS6;
2158				else if (MCS5 && (Rssi > (-77 + RssiOffset)))
2159					TxRateIdx = MCS5;
2160				else if (MCS4 && (Rssi > (-79 + RssiOffset)))
2161					TxRateIdx = MCS4;
2162				else if (MCS3 && (Rssi > (-81 + RssiOffset)))
2163					TxRateIdx = MCS3;
2164				else if (MCS2 && (Rssi > (-83 + RssiOffset)))
2165					TxRateIdx = MCS2;
2166				else if (MCS1 && (Rssi > (-86 + RssiOffset)))
2167					TxRateIdx = MCS1;
2168				else
2169					TxRateIdx = MCS0;
2170			} else {	/* Legacy mode */
2171				if (MCS7 && (Rssi > -70))
2172					TxRateIdx = MCS7;
2173				else if (MCS6 && (Rssi > -74))
2174					TxRateIdx = MCS6;
2175				else if (MCS5 && (Rssi > -78))
2176					TxRateIdx = MCS5;
2177				else if (MCS4 && (Rssi > -82))
2178					TxRateIdx = MCS4;
2179				else if (MCS4 == 0)	/* for B-only mode */
2180					TxRateIdx = MCS3;
2181				else if (MCS3 && (Rssi > -85))
2182					TxRateIdx = MCS3;
2183				else if (MCS2 && (Rssi > -87))
2184					TxRateIdx = MCS2;
2185				else if (MCS1 && (Rssi > -90))
2186					TxRateIdx = MCS1;
2187				else
2188					TxRateIdx = MCS0;
2189			}
2190
2191			/*              if (TxRateIdx != pAd->CommonCfg.TxRateIndex) */
2192			{
2193				pEntry->CurrTxRateIndex = TxRateIdx;
2194				pNextTxRate =
2195				    (struct rt_rtmp_tx_rate_switch *) &
2196				    pTable[(pEntry->CurrTxRateIndex + 1) * 5];
2197				MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2198			}
2199
2200			NdisZeroMemory(pEntry->TxQuality,
2201				       sizeof(u16)*
2202				       MAX_STEP_OF_TX_RATE_SWITCH);
2203			NdisZeroMemory(pEntry->PER,
2204				       sizeof(u8)*
2205				       MAX_STEP_OF_TX_RATE_SWITCH);
2206			pEntry->fLastSecAccordingRSSI = TRUE;
2207			/* reset all OneSecTx counters */
2208			RESET_ONE_SEC_TX_CNT(pEntry);
2209
2210			continue;
2211		}
2212
2213		if (pEntry->fLastSecAccordingRSSI == TRUE) {
2214			pEntry->fLastSecAccordingRSSI = FALSE;
2215			pEntry->LastSecTxRateChangeAction = 0;
2216			/* reset all OneSecTx counters */
2217			RESET_ONE_SEC_TX_CNT(pEntry);
2218
2219			continue;
2220		}
2221
2222		do {
2223			BOOLEAN bTrainUpDown = FALSE;
2224
2225			pEntry->CurrTxRateStableTime++;
2226
2227			/* downgrade TX quality if PER >= Rate-Down threshold */
2228			if (TxErrorRatio >= TrainDown) {
2229				bTrainUpDown = TRUE;
2230				pEntry->TxQuality[CurrRateIdx] =
2231				    DRS_TX_QUALITY_WORST_BOUND;
2232			}
2233			/* upgrade TX quality if PER <= Rate-Up threshold */
2234			else if (TxErrorRatio <= TrainUp) {
2235				bTrainUpDown = TRUE;
2236				bUpgradeQuality = TRUE;
2237				if (pEntry->TxQuality[CurrRateIdx])
2238					pEntry->TxQuality[CurrRateIdx]--;	/* quality very good in CurrRate */
2239
2240				if (pEntry->TxRateUpPenalty)
2241					pEntry->TxRateUpPenalty--;
2242				else if (pEntry->TxQuality[UpRateIdx])
2243					pEntry->TxQuality[UpRateIdx]--;	/* may improve next UP rate's quality */
2244			}
2245
2246			pEntry->PER[CurrRateIdx] = (u8)TxErrorRatio;
2247
2248			if (bTrainUpDown) {
2249				/* perform DRS - consider TxRate Down first, then rate up. */
2250				if ((CurrRateIdx != DownRateIdx)
2251				    && (pEntry->TxQuality[CurrRateIdx] >=
2252					DRS_TX_QUALITY_WORST_BOUND)) {
2253					pEntry->CurrTxRateIndex = DownRateIdx;
2254				} else if ((CurrRateIdx != UpRateIdx)
2255					   && (pEntry->TxQuality[UpRateIdx] <=
2256					       0)) {
2257					pEntry->CurrTxRateIndex = UpRateIdx;
2258				}
2259			}
2260		} while (FALSE);
2261
2262		/* if rate-up happen, clear all bad history of all TX rates */
2263		if (pEntry->CurrTxRateIndex > CurrRateIdx) {
2264			pEntry->CurrTxRateStableTime = 0;
2265			pEntry->TxRateUpPenalty = 0;
2266			pEntry->LastSecTxRateChangeAction = 1;	/* rate UP */
2267			NdisZeroMemory(pEntry->TxQuality,
2268				       sizeof(u16)*
2269				       MAX_STEP_OF_TX_RATE_SWITCH);
2270			NdisZeroMemory(pEntry->PER,
2271				       sizeof(u8)*
2272				       MAX_STEP_OF_TX_RATE_SWITCH);
2273
2274			/* */
2275			/* For TxRate fast train up */
2276			/* */
2277			if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2278				RTMPSetTimer(&pAd->StaCfg.
2279					     StaQuickResponeForRateUpTimer,
2280					     100);
2281
2282				pAd->StaCfg.
2283				    StaQuickResponeForRateUpTimerRunning = TRUE;
2284			}
2285			bTxRateChanged = TRUE;
2286		}
2287		/* if rate-down happen, only clear DownRate's bad history */
2288		else if (pEntry->CurrTxRateIndex < CurrRateIdx) {
2289			pEntry->CurrTxRateStableTime = 0;
2290			pEntry->TxRateUpPenalty = 0;	/* no penalty */
2291			pEntry->LastSecTxRateChangeAction = 2;	/* rate DOWN */
2292			pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
2293			pEntry->PER[pEntry->CurrTxRateIndex] = 0;
2294
2295			/* */
2296			/* For TxRate fast train down */
2297			/* */
2298			if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2299				RTMPSetTimer(&pAd->StaCfg.
2300					     StaQuickResponeForRateUpTimer,
2301					     100);
2302
2303				pAd->StaCfg.
2304				    StaQuickResponeForRateUpTimerRunning = TRUE;
2305			}
2306			bTxRateChanged = TRUE;
2307		} else {
2308			pEntry->LastSecTxRateChangeAction = 0;	/* rate no change */
2309			bTxRateChanged = FALSE;
2310		}
2311
2312		pEntry->LastTxOkCount = TxSuccess;
2313		{
2314			u8 tmpTxRate;
2315
2316			/* to fix tcp ack issue */
2317			if (!bTxRateChanged
2318			    && (pAd->RalinkCounters.OneSecReceivedByteCount >
2319				(pAd->RalinkCounters.
2320				 OneSecTransmittedByteCount * 5))) {
2321				tmpTxRate = DownRateIdx;
2322				DBGPRINT_RAW(RT_DEBUG_TRACE,
2323					     ("DRS: Rx(%d) is 5 times larger than Tx(%d), use low rate (curr=%d, tmp=%d)\n",
2324					      pAd->RalinkCounters.
2325					      OneSecReceivedByteCount,
2326					      pAd->RalinkCounters.
2327					      OneSecTransmittedByteCount,
2328					      pEntry->CurrTxRateIndex,
2329					      tmpTxRate));
2330			} else {
2331				tmpTxRate = pEntry->CurrTxRateIndex;
2332			}
2333
2334			pNextTxRate =
2335			    (struct rt_rtmp_tx_rate_switch *) & pTable[(tmpTxRate + 1) *
2336							    5];
2337		}
2338		if (bTxRateChanged && pNextTxRate) {
2339			MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2340		}
2341		/* reset all OneSecTx counters */
2342		RESET_ONE_SEC_TX_CNT(pEntry);
2343	}
2344}
2345
2346/*
2347	========================================================================
2348	Routine Description:
2349		Station side, Auto TxRate faster train up timer call back function.
2350
2351	Arguments:
2352		SystemSpecific1			- Not used.
2353		FunctionContext			- Pointer to our Adapter context.
2354		SystemSpecific2			- Not used.
2355		SystemSpecific3			- Not used.
2356
2357	Return Value:
2358		None
2359
2360	========================================================================
2361*/
2362void StaQuickResponeForRateUpExec(void *SystemSpecific1,
2363				  void *FunctionContext,
2364				  void *SystemSpecific2,
2365				  void *SystemSpecific3)
2366{
2367	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
2368	u8 UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
2369	unsigned long TxTotalCnt;
2370	unsigned long TxErrorRatio = 0;
2371	BOOLEAN bTxRateChanged;	/*, bUpgradeQuality = FALSE; */
2372	struct rt_rtmp_tx_rate_switch *pCurrTxRate, *pNextTxRate = NULL;
2373	u8 *pTable;
2374	u8 TableSize = 0;
2375	u8 InitTxRateIdx = 0, TrainUp, TrainDown;
2376	TX_STA_CNT1_STRUC StaTx1;
2377	TX_STA_CNT0_STRUC TxStaCnt0;
2378	char Rssi, ratio;
2379	unsigned long TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
2380	struct rt_mac_table_entry *pEntry;
2381	unsigned long i;
2382
2383	pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE;
2384
2385	/* */
2386	/* walk through MAC table, see if need to change AP's TX rate toward each entry */
2387	/* */
2388	for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
2389		pEntry = &pAd->MacTab.Content[i];
2390
2391		/* check if this entry need to switch rate automatically */
2392		if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
2393			continue;
2394
2395		if (INFRA_ON(pAd) && (i == 1))
2396			Rssi = RTMPMaxRssi(pAd,
2397					   pAd->StaCfg.RssiSample.AvgRssi0,
2398					   pAd->StaCfg.RssiSample.AvgRssi1,
2399					   pAd->StaCfg.RssiSample.AvgRssi2);
2400		else
2401			Rssi = RTMPMaxRssi(pAd,
2402					   pEntry->RssiSample.AvgRssi0,
2403					   pEntry->RssiSample.AvgRssi1,
2404					   pEntry->RssiSample.AvgRssi2);
2405
2406		CurrRateIdx = pAd->CommonCfg.TxRateIndex;
2407
2408		MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
2409				      &InitTxRateIdx);
2410
2411		/* decide the next upgrade rate and downgrade rate, if any */
2412		if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) {
2413			UpRateIdx = CurrRateIdx + 1;
2414			DownRateIdx = CurrRateIdx - 1;
2415		} else if (CurrRateIdx == 0) {
2416			UpRateIdx = CurrRateIdx + 1;
2417			DownRateIdx = CurrRateIdx;
2418		} else if (CurrRateIdx == (TableSize - 1)) {
2419			UpRateIdx = CurrRateIdx;
2420			DownRateIdx = CurrRateIdx - 1;
2421		}
2422
2423		pCurrTxRate =
2424		    (struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
2425
2426		if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) {
2427			TrainUp =
2428			    (pCurrTxRate->TrainUp +
2429			     (pCurrTxRate->TrainUp >> 1));
2430			TrainDown =
2431			    (pCurrTxRate->TrainDown +
2432			     (pCurrTxRate->TrainDown >> 1));
2433		} else {
2434			TrainUp = pCurrTxRate->TrainUp;
2435			TrainDown = pCurrTxRate->TrainDown;
2436		}
2437
2438		if (pAd->MacTab.Size == 1) {
2439			/* Update statistic counter */
2440			RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
2441			RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
2442
2443			TxRetransmit = StaTx1.field.TxRetransmit;
2444			TxSuccess = StaTx1.field.TxSuccess;
2445			TxFailCount = TxStaCnt0.field.TxFailCount;
2446			TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
2447
2448			pAd->RalinkCounters.OneSecTxRetryOkCount +=
2449			    StaTx1.field.TxRetransmit;
2450			pAd->RalinkCounters.OneSecTxNoRetryOkCount +=
2451			    StaTx1.field.TxSuccess;
2452			pAd->RalinkCounters.OneSecTxFailCount +=
2453			    TxStaCnt0.field.TxFailCount;
2454			pAd->WlanCounters.TransmittedFragmentCount.u.LowPart +=
2455			    StaTx1.field.TxSuccess;
2456			pAd->WlanCounters.RetryCount.u.LowPart +=
2457			    StaTx1.field.TxRetransmit;
2458			pAd->WlanCounters.FailedCount.u.LowPart +=
2459			    TxStaCnt0.field.TxFailCount;
2460
2461			if (TxTotalCnt)
2462				TxErrorRatio =
2463				    ((TxRetransmit +
2464				      TxFailCount) * 100) / TxTotalCnt;
2465		} else {
2466			TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
2467			    pEntry->OneSecTxRetryOkCount +
2468			    pEntry->OneSecTxFailCount;
2469
2470			if (TxTotalCnt)
2471				TxErrorRatio =
2472				    ((pEntry->OneSecTxRetryOkCount +
2473				      pEntry->OneSecTxFailCount) * 100) /
2474				    TxTotalCnt;
2475		}
2476
2477		/* */
2478		/* CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI */
2479		/*         (criteria copied from RT2500 for Netopia case) */
2480		/* */
2481		if (TxTotalCnt <= 12) {
2482			NdisZeroMemory(pAd->DrsCounters.TxQuality,
2483				       sizeof(u16)*
2484				       MAX_STEP_OF_TX_RATE_SWITCH);
2485			NdisZeroMemory(pAd->DrsCounters.PER,
2486				       sizeof(u8)*
2487				       MAX_STEP_OF_TX_RATE_SWITCH);
2488
2489			if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1)
2490			    && (CurrRateIdx != DownRateIdx)) {
2491				pAd->CommonCfg.TxRateIndex = DownRateIdx;
2492				pAd->DrsCounters.TxQuality[CurrRateIdx] =
2493				    DRS_TX_QUALITY_WORST_BOUND;
2494			} else
2495			    if ((pAd->DrsCounters.LastSecTxRateChangeAction ==
2496				 2) && (CurrRateIdx != UpRateIdx)) {
2497				pAd->CommonCfg.TxRateIndex = UpRateIdx;
2498			}
2499
2500			DBGPRINT_RAW(RT_DEBUG_TRACE,
2501				     ("QuickDRS: TxTotalCnt <= 15, train back to original rate \n"));
2502			return;
2503		}
2504
2505		do {
2506			unsigned long OneSecTxNoRetryOKRationCount;
2507
2508			if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0)
2509				ratio = 5;
2510			else
2511				ratio = 4;
2512
2513			/* downgrade TX quality if PER >= Rate-Down threshold */
2514			if (TxErrorRatio >= TrainDown) {
2515				pAd->DrsCounters.TxQuality[CurrRateIdx] =
2516				    DRS_TX_QUALITY_WORST_BOUND;
2517			}
2518
2519			pAd->DrsCounters.PER[CurrRateIdx] =
2520			    (u8)TxErrorRatio;
2521
2522			OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);
2523
2524			/* perform DRS - consider TxRate Down first, then rate up. */
2525			if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1)
2526			    && (CurrRateIdx != DownRateIdx)) {
2527				if ((pAd->DrsCounters.LastTxOkCount + 2) >=
2528				    OneSecTxNoRetryOKRationCount) {
2529					pAd->CommonCfg.TxRateIndex =
2530					    DownRateIdx;
2531					pAd->DrsCounters.
2532					    TxQuality[CurrRateIdx] =
2533					    DRS_TX_QUALITY_WORST_BOUND;
2534
2535				}
2536
2537			} else
2538			    if ((pAd->DrsCounters.LastSecTxRateChangeAction ==
2539				 2) && (CurrRateIdx != UpRateIdx)) {
2540				if ((TxErrorRatio >= 50)
2541				    || (TxErrorRatio >= TrainDown)) {
2542
2543				} else if ((pAd->DrsCounters.LastTxOkCount + 2)
2544					   >= OneSecTxNoRetryOKRationCount) {
2545					pAd->CommonCfg.TxRateIndex = UpRateIdx;
2546				}
2547			}
2548		} while (FALSE);
2549
2550		/* if rate-up happen, clear all bad history of all TX rates */
2551		if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) {
2552			pAd->DrsCounters.TxRateUpPenalty = 0;
2553			NdisZeroMemory(pAd->DrsCounters.TxQuality,
2554				       sizeof(u16)*
2555				       MAX_STEP_OF_TX_RATE_SWITCH);
2556			NdisZeroMemory(pAd->DrsCounters.PER,
2557				       sizeof(u8)*
2558				       MAX_STEP_OF_TX_RATE_SWITCH);
2559			bTxRateChanged = TRUE;
2560		}
2561		/* if rate-down happen, only clear DownRate's bad history */
2562		else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) {
2563			DBGPRINT_RAW(RT_DEBUG_TRACE,
2564				     ("QuickDRS: --TX rate from %d to %d \n",
2565				      CurrRateIdx, pAd->CommonCfg.TxRateIndex));
2566
2567			pAd->DrsCounters.TxRateUpPenalty = 0;	/* no penalty */
2568			pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] =
2569			    0;
2570			pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0;
2571			bTxRateChanged = TRUE;
2572		} else {
2573			bTxRateChanged = FALSE;
2574		}
2575
2576		pNextTxRate =
2577		    (struct rt_rtmp_tx_rate_switch *) &
2578		    pTable[(pAd->CommonCfg.TxRateIndex + 1) * 5];
2579		if (bTxRateChanged && pNextTxRate) {
2580			MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2581		}
2582	}
2583}
2584
2585/*
2586	==========================================================================
2587	Description:
2588		This routine is executed periodically inside MlmePeriodicExec() after
2589		association with an AP.
2590		It checks if StaCfg.Psm is consistent with user policy (recorded in
2591		StaCfg.WindowsPowerMode). If not, enforce user policy. However,
2592		there're some conditions to consider:
2593		1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
2594		   the time when Mibss==TRUE
2595		2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE
2596		   if outgoing traffic available in TxRing or MgmtRing.
2597	Output:
2598		1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched
2599
2600	IRQL = DISPATCH_LEVEL
2601
2602	==========================================================================
2603 */
2604void MlmeCheckPsmChange(struct rt_rtmp_adapter *pAd, unsigned long Now32)
2605{
2606	unsigned long PowerMode;
2607
2608	/* condition - */
2609	/* 1. Psm maybe ON only happen in INFRASTRUCTURE mode */
2610	/* 2. user wants either MAX_PSP or FAST_PSP */
2611	/* 3. but current psm is not in PWR_SAVE */
2612	/* 4. CNTL state machine is not doing SCANning */
2613	/* 5. no TX SUCCESS event for the past 1-sec period */
2614	PowerMode = pAd->StaCfg.WindowsPowerMode;
2615
2616	if (INFRA_ON(pAd) &&
2617	    (PowerMode != Ndis802_11PowerModeCAM) &&
2618	    (pAd->StaCfg.Psm == PWR_ACTIVE) &&
2619/*              (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) */
2620	    (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
2621	    RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP)
2622	    /*&&
2623	       (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) &&
2624	       (pAd->RalinkCounters.OneSecTxRetryOkCount == 0) */
2625	    ) {
2626		NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime);
2627		pAd->RalinkCounters.RxCountSinceLastNULL = 0;
2628		RTMP_SET_PSM_BIT(pAd, PWR_SAVE);
2629		if (!
2630		    (pAd->CommonCfg.bAPSDCapable
2631		     && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) {
2632			RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE);
2633		} else {
2634			RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
2635		}
2636	}
2637}
2638
2639/* IRQL = PASSIVE_LEVEL */
2640/* IRQL = DISPATCH_LEVEL */
2641void MlmeSetPsmBit(struct rt_rtmp_adapter *pAd, u16 psm)
2642{
2643	AUTO_RSP_CFG_STRUC csr4;
2644
2645	pAd->StaCfg.Psm = psm;
2646	RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
2647	csr4.field.AckCtsPsmBit = (psm == PWR_SAVE) ? 1 : 0;
2648	RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
2649
2650	DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm));
2651}
2652
2653/*
2654	==========================================================================
2655	Description:
2656		This routine calculates TxPER, RxPER of the past N-sec period. And
2657		according to the calculation result, ChannelQuality is calculated here
2658		to decide if current AP is still doing the job.
2659
2660		If ChannelQuality is not good, a ROAMing attempt may be tried later.
2661	Output:
2662		StaCfg.ChannelQuality - 0..100
2663
2664	IRQL = DISPATCH_LEVEL
2665
2666	NOTE: This routine decide channle quality based on RX CRC error ratio.
2667		Caller should make sure a function call to NICUpdateRawCounters(pAd)
2668		is performed right before this routine, so that this routine can decide
2669		channel quality based on the most up-to-date information
2670	==========================================================================
2671 */
2672void MlmeCalculateChannelQuality(struct rt_rtmp_adapter *pAd,
2673				 struct rt_mac_table_entry *pMacEntry, unsigned long Now32)
2674{
2675	unsigned long TxOkCnt, TxCnt, TxPER, TxPRR;
2676	unsigned long RxCnt, RxPER;
2677	u8 NorRssi;
2678	char MaxRssi;
2679	struct rt_rssi_sample *pRssiSample = NULL;
2680	u32 OneSecTxNoRetryOkCount = 0;
2681	u32 OneSecTxRetryOkCount = 0;
2682	u32 OneSecTxFailCount = 0;
2683	u32 OneSecRxOkCnt = 0;
2684	u32 OneSecRxFcsErrCnt = 0;
2685	unsigned long ChannelQuality = 0;	/* 0..100, Channel Quality Indication for Roaming */
2686	unsigned long BeaconLostTime = pAd->StaCfg.BeaconLostTime;
2687
2688	if (pAd->OpMode == OPMODE_STA) {
2689		pRssiSample = &pAd->StaCfg.RssiSample;
2690		OneSecTxNoRetryOkCount =
2691		    pAd->RalinkCounters.OneSecTxNoRetryOkCount;
2692		OneSecTxRetryOkCount = pAd->RalinkCounters.OneSecTxRetryOkCount;
2693		OneSecTxFailCount = pAd->RalinkCounters.OneSecTxFailCount;
2694		OneSecRxOkCnt = pAd->RalinkCounters.OneSecRxOkCnt;
2695		OneSecRxFcsErrCnt = pAd->RalinkCounters.OneSecRxFcsErrCnt;
2696	}
2697
2698	MaxRssi = RTMPMaxRssi(pAd, pRssiSample->LastRssi0,
2699			      pRssiSample->LastRssi1, pRssiSample->LastRssi2);
2700
2701	/* */
2702	/* calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics */
2703	/* */
2704	TxOkCnt = OneSecTxNoRetryOkCount + OneSecTxRetryOkCount;
2705	TxCnt = TxOkCnt + OneSecTxFailCount;
2706	if (TxCnt < 5) {
2707		TxPER = 0;
2708		TxPRR = 0;
2709	} else {
2710		TxPER = (OneSecTxFailCount * 100) / TxCnt;
2711		TxPRR = ((TxCnt - OneSecTxNoRetryOkCount) * 100) / TxCnt;
2712	}
2713
2714	/* */
2715	/* calculate RX PER - don't take RxPER into consideration if too few sample */
2716	/* */
2717	RxCnt = OneSecRxOkCnt + OneSecRxFcsErrCnt;
2718	if (RxCnt < 5)
2719		RxPER = 0;
2720	else
2721		RxPER = (OneSecRxFcsErrCnt * 100) / RxCnt;
2722
2723	/* */
2724	/* decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER */
2725	/* */
2726	if ((pAd->OpMode == OPMODE_STA) && INFRA_ON(pAd) && (OneSecTxNoRetryOkCount < 2) &&	/* no heavy traffic */
2727	    ((pAd->StaCfg.LastBeaconRxTime + BeaconLostTime) < Now32)) {
2728		DBGPRINT(RT_DEBUG_TRACE,
2729			 ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n",
2730			  BeaconLostTime, TxOkCnt));
2731		ChannelQuality = 0;
2732	} else {
2733		/* Normalize Rssi */
2734		if (MaxRssi > -40)
2735			NorRssi = 100;
2736		else if (MaxRssi < -90)
2737			NorRssi = 0;
2738		else
2739			NorRssi = (MaxRssi + 90) * 2;
2740
2741		/* ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER        (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) */
2742		ChannelQuality = (RSSI_WEIGHTING * NorRssi +
2743				  TX_WEIGHTING * (100 - TxPRR) +
2744				  RX_WEIGHTING * (100 - RxPER)) / 100;
2745	}
2746
2747	if (pAd->OpMode == OPMODE_STA)
2748		pAd->Mlme.ChannelQuality =
2749		    (ChannelQuality > 100) ? 100 : ChannelQuality;
2750
2751}
2752
2753/* IRQL = DISPATCH_LEVEL */
2754void MlmeSetTxPreamble(struct rt_rtmp_adapter *pAd, u16 TxPreamble)
2755{
2756	AUTO_RSP_CFG_STRUC csr4;
2757
2758	/* */
2759	/* Always use Long preamble before verifiation short preamble functionality works well. */
2760	/* Todo: remove the following line if short preamble functionality works */
2761	/* */
2762	/*TxPreamble = Rt802_11PreambleLong; */
2763
2764	RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
2765	if (TxPreamble == Rt802_11PreambleLong) {
2766		DBGPRINT(RT_DEBUG_TRACE,
2767			 ("MlmeSetTxPreamble (= long PREAMBLE)\n"));
2768		OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
2769		csr4.field.AutoResponderPreamble = 0;
2770	} else {
2771		/* NOTE: 1Mbps should always use long preamble */
2772		DBGPRINT(RT_DEBUG_TRACE,
2773			 ("MlmeSetTxPreamble (= short PREAMBLE)\n"));
2774		OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
2775		csr4.field.AutoResponderPreamble = 1;
2776	}
2777
2778	RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
2779}
2780
2781/*
2782    ==========================================================================
2783    Description:
2784        Update basic rate bitmap
2785    ==========================================================================
2786 */
2787
2788void UpdateBasicRateBitmap(struct rt_rtmp_adapter *pAdapter)
2789{
2790	int i, j;
2791	/* 1  2  5.5, 11,  6,  9, 12, 18, 24, 36, 48,  54 */
2792	u8 rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
2793	u8 *sup_p = pAdapter->CommonCfg.SupRate;
2794	u8 *ext_p = pAdapter->CommonCfg.ExtRate;
2795	unsigned long bitmap = pAdapter->CommonCfg.BasicRateBitmap;
2796
2797	/* if A mode, always use fix BasicRateBitMap */
2798	/*if (pAdapter->CommonCfg.Channel == PHY_11A) */
2799	if (pAdapter->CommonCfg.Channel > 14)
2800		pAdapter->CommonCfg.BasicRateBitmap = 0x150;	/* 6, 12, 24M */
2801	/* End of if */
2802
2803	if (pAdapter->CommonCfg.BasicRateBitmap > 4095) {
2804		/* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */
2805		return;
2806	}
2807	/* End of if */
2808	for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2809		sup_p[i] &= 0x7f;
2810		ext_p[i] &= 0x7f;
2811	}			/* End of for */
2812
2813	for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2814		if (bitmap & (1 << i)) {
2815			for (j = 0; j < MAX_LEN_OF_SUPPORTED_RATES; j++) {
2816				if (sup_p[j] == rate[i])
2817					sup_p[j] |= 0x80;
2818				/* End of if */
2819			}	/* End of for */
2820
2821			for (j = 0; j < MAX_LEN_OF_SUPPORTED_RATES; j++) {
2822				if (ext_p[j] == rate[i])
2823					ext_p[j] |= 0x80;
2824				/* End of if */
2825			}	/* End of for */
2826		}		/* End of if */
2827	}			/* End of for */
2828}				/* End of UpdateBasicRateBitmap */
2829
2830/* IRQL = PASSIVE_LEVEL */
2831/* IRQL = DISPATCH_LEVEL */
2832/* bLinkUp is to identify the inital link speed. */
2833/* TRUE indicates the rate update at linkup, we should not try to set the rate at 54Mbps. */
2834void MlmeUpdateTxRates(struct rt_rtmp_adapter *pAd, IN BOOLEAN bLinkUp, u8 apidx)
2835{
2836	int i, num;
2837	u8 Rate = RATE_6, MaxDesire = RATE_1, MaxSupport = RATE_1;
2838	u8 MinSupport = RATE_54;
2839	unsigned long BasicRateBitmap = 0;
2840	u8 CurrBasicRate = RATE_1;
2841	u8 *pSupRate, SupRateLen, *pExtRate, ExtRateLen;
2842	PHTTRANSMIT_SETTING pHtPhy = NULL;
2843	PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
2844	PHTTRANSMIT_SETTING pMinHtPhy = NULL;
2845	BOOLEAN *auto_rate_cur_p;
2846	u8 HtMcs = MCS_AUTO;
2847
2848	/* find max desired rate */
2849	UpdateBasicRateBitmap(pAd);
2850
2851	num = 0;
2852	auto_rate_cur_p = NULL;
2853	for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2854		switch (pAd->CommonCfg.DesireRate[i] & 0x7f) {
2855		case 2:
2856			Rate = RATE_1;
2857			num++;
2858			break;
2859		case 4:
2860			Rate = RATE_2;
2861			num++;
2862			break;
2863		case 11:
2864			Rate = RATE_5_5;
2865			num++;
2866			break;
2867		case 22:
2868			Rate = RATE_11;
2869			num++;
2870			break;
2871		case 12:
2872			Rate = RATE_6;
2873			num++;
2874			break;
2875		case 18:
2876			Rate = RATE_9;
2877			num++;
2878			break;
2879		case 24:
2880			Rate = RATE_12;
2881			num++;
2882			break;
2883		case 36:
2884			Rate = RATE_18;
2885			num++;
2886			break;
2887		case 48:
2888			Rate = RATE_24;
2889			num++;
2890			break;
2891		case 72:
2892			Rate = RATE_36;
2893			num++;
2894			break;
2895		case 96:
2896			Rate = RATE_48;
2897			num++;
2898			break;
2899		case 108:
2900			Rate = RATE_54;
2901			num++;
2902			break;
2903			/*default: Rate = RATE_1;   break; */
2904		}
2905		if (MaxDesire < Rate)
2906			MaxDesire = Rate;
2907	}
2908
2909/*=========================================================================== */
2910/*=========================================================================== */
2911	{
2912		pHtPhy = &pAd->StaCfg.HTPhyMode;
2913		pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
2914		pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
2915
2916		auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
2917		HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS;
2918
2919		if ((pAd->StaCfg.BssType == BSS_ADHOC) &&
2920		    (pAd->CommonCfg.PhyMode == PHY_11B) &&
2921		    (MaxDesire > RATE_11)) {
2922			MaxDesire = RATE_11;
2923		}
2924	}
2925
2926	pAd->CommonCfg.MaxDesiredRate = MaxDesire;
2927	pMinHtPhy->word = 0;
2928	pMaxHtPhy->word = 0;
2929	pHtPhy->word = 0;
2930
2931	/* Auto rate switching is enabled only if more than one DESIRED RATES are */
2932	/* specified; otherwise disabled */
2933	if (num <= 1) {
2934		/*OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2935		/*pAd->CommonCfg.bAutoTxRateSwitch      = FALSE; */
2936		*auto_rate_cur_p = FALSE;
2937	} else {
2938		/*OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2939		/*pAd->CommonCfg.bAutoTxRateSwitch      = TRUE; */
2940		*auto_rate_cur_p = TRUE;
2941	}
2942
2943	if (HtMcs != MCS_AUTO) {
2944		/*OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2945		/*pAd->CommonCfg.bAutoTxRateSwitch      = FALSE; */
2946		*auto_rate_cur_p = FALSE;
2947	} else {
2948		/*OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2949		/*pAd->CommonCfg.bAutoTxRateSwitch      = TRUE; */
2950		*auto_rate_cur_p = TRUE;
2951	}
2952
2953	if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) {
2954		pSupRate = &pAd->StaActive.SupRate[0];
2955		pExtRate = &pAd->StaActive.ExtRate[0];
2956		SupRateLen = pAd->StaActive.SupRateLen;
2957		ExtRateLen = pAd->StaActive.ExtRateLen;
2958	} else {
2959		pSupRate = &pAd->CommonCfg.SupRate[0];
2960		pExtRate = &pAd->CommonCfg.ExtRate[0];
2961		SupRateLen = pAd->CommonCfg.SupRateLen;
2962		ExtRateLen = pAd->CommonCfg.ExtRateLen;
2963	}
2964
2965	/* find max supported rate */
2966	for (i = 0; i < SupRateLen; i++) {
2967		switch (pSupRate[i] & 0x7f) {
2968		case 2:
2969			Rate = RATE_1;
2970			if (pSupRate[i] & 0x80)
2971				BasicRateBitmap |= 0x0001;
2972			break;
2973		case 4:
2974			Rate = RATE_2;
2975			if (pSupRate[i] & 0x80)
2976				BasicRateBitmap |= 0x0002;
2977			break;
2978		case 11:
2979			Rate = RATE_5_5;
2980			if (pSupRate[i] & 0x80)
2981				BasicRateBitmap |= 0x0004;
2982			break;
2983		case 22:
2984			Rate = RATE_11;
2985			if (pSupRate[i] & 0x80)
2986				BasicRateBitmap |= 0x0008;
2987			break;
2988		case 12:
2989			Rate = RATE_6;	/*if (pSupRate[i] & 0x80) */
2990			BasicRateBitmap |= 0x0010;
2991			break;
2992		case 18:
2993			Rate = RATE_9;
2994			if (pSupRate[i] & 0x80)
2995				BasicRateBitmap |= 0x0020;
2996			break;
2997		case 24:
2998			Rate = RATE_12;	/*if (pSupRate[i] & 0x80) */
2999			BasicRateBitmap |= 0x0040;
3000			break;
3001		case 36:
3002			Rate = RATE_18;
3003			if (pSupRate[i] & 0x80)
3004				BasicRateBitmap |= 0x0080;
3005			break;
3006		case 48:
3007			Rate = RATE_24;	/*if (pSupRate[i] & 0x80) */
3008			BasicRateBitmap |= 0x0100;
3009			break;
3010		case 72:
3011			Rate = RATE_36;
3012			if (pSupRate[i] & 0x80)
3013				BasicRateBitmap |= 0x0200;
3014			break;
3015		case 96:
3016			Rate = RATE_48;
3017			if (pSupRate[i] & 0x80)
3018				BasicRateBitmap |= 0x0400;
3019			break;
3020		case 108:
3021			Rate = RATE_54;
3022			if (pSupRate[i] & 0x80)
3023				BasicRateBitmap |= 0x0800;
3024			break;
3025		default:
3026			Rate = RATE_1;
3027			break;
3028		}
3029		if (MaxSupport < Rate)
3030			MaxSupport = Rate;
3031
3032		if (MinSupport > Rate)
3033			MinSupport = Rate;
3034	}
3035
3036	for (i = 0; i < ExtRateLen; i++) {
3037		switch (pExtRate[i] & 0x7f) {
3038		case 2:
3039			Rate = RATE_1;
3040			if (pExtRate[i] & 0x80)
3041				BasicRateBitmap |= 0x0001;
3042			break;
3043		case 4:
3044			Rate = RATE_2;
3045			if (pExtRate[i] & 0x80)
3046				BasicRateBitmap |= 0x0002;
3047			break;
3048		case 11:
3049			Rate = RATE_5_5;
3050			if (pExtRate[i] & 0x80)
3051				BasicRateBitmap |= 0x0004;
3052			break;
3053		case 22:
3054			Rate = RATE_11;
3055			if (pExtRate[i] & 0x80)
3056				BasicRateBitmap |= 0x0008;
3057			break;
3058		case 12:
3059			Rate = RATE_6;	/*if (pExtRate[i] & 0x80) */
3060			BasicRateBitmap |= 0x0010;
3061			break;
3062		case 18:
3063			Rate = RATE_9;
3064			if (pExtRate[i] & 0x80)
3065				BasicRateBitmap |= 0x0020;
3066			break;
3067		case 24:
3068			Rate = RATE_12;	/*if (pExtRate[i] & 0x80) */
3069			BasicRateBitmap |= 0x0040;
3070			break;
3071		case 36:
3072			Rate = RATE_18;
3073			if (pExtRate[i] & 0x80)
3074				BasicRateBitmap |= 0x0080;
3075			break;
3076		case 48:
3077			Rate = RATE_24;	/*if (pExtRate[i] & 0x80) */
3078			BasicRateBitmap |= 0x0100;
3079			break;
3080		case 72:
3081			Rate = RATE_36;
3082			if (pExtRate[i] & 0x80)
3083				BasicRateBitmap |= 0x0200;
3084			break;
3085		case 96:
3086			Rate = RATE_48;
3087			if (pExtRate[i] & 0x80)
3088				BasicRateBitmap |= 0x0400;
3089			break;
3090		case 108:
3091			Rate = RATE_54;
3092			if (pExtRate[i] & 0x80)
3093				BasicRateBitmap |= 0x0800;
3094			break;
3095		default:
3096			Rate = RATE_1;
3097			break;
3098		}
3099		if (MaxSupport < Rate)
3100			MaxSupport = Rate;
3101
3102		if (MinSupport > Rate)
3103			MinSupport = Rate;
3104	}
3105
3106	RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap);
3107
3108	/* bug fix */
3109	/* pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap; */
3110
3111	/* calculate the exptected ACK rate for each TX rate. This info is used to caculate */
3112	/* the DURATION field of outgoing uniicast DATA/MGMT frame */
3113	for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
3114		if (BasicRateBitmap & (0x01 << i))
3115			CurrBasicRate = (u8)i;
3116		pAd->CommonCfg.ExpectedACKRate[i] = CurrBasicRate;
3117	}
3118
3119	DBGPRINT(RT_DEBUG_TRACE,
3120		 ("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n",
3121		  RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire]));
3122	/* max tx rate = min {max desire rate, max supported rate} */
3123	if (MaxSupport < MaxDesire)
3124		pAd->CommonCfg.MaxTxRate = MaxSupport;
3125	else
3126		pAd->CommonCfg.MaxTxRate = MaxDesire;
3127
3128	pAd->CommonCfg.MinTxRate = MinSupport;
3129	/* 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success */
3130	/* ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending */
3131	/* on average RSSI */
3132	/*       1. RSSI >= -70db, start at 54 Mbps (short distance) */
3133	/*       2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) */
3134	/*       3. -75 > RSSI, start at 11 Mbps (long distance) */
3135	if (*auto_rate_cur_p) {
3136		short dbm = 0;
3137
3138		dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta;
3139
3140		if (bLinkUp == TRUE)
3141			pAd->CommonCfg.TxRate = RATE_24;
3142		else
3143			pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3144
3145		if (dbm < -75)
3146			pAd->CommonCfg.TxRate = RATE_11;
3147		else if (dbm < -70)
3148			pAd->CommonCfg.TxRate = RATE_24;
3149
3150		/* should never exceed MaxTxRate (consider 11B-only mode) */
3151		if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate)
3152			pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3153
3154		pAd->CommonCfg.TxRateIndex = 0;
3155	} else {
3156		pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3157		pHtPhy->field.MCS =
3158		    (pAd->CommonCfg.MaxTxRate >
3159		     3) ? (pAd->CommonCfg.MaxTxRate -
3160			   4) : pAd->CommonCfg.MaxTxRate;
3161		pHtPhy->field.MODE =
3162		    (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK;
3163
3164		pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC =
3165		    pHtPhy->field.STBC;
3166		pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI =
3167		    pHtPhy->field.ShortGI;
3168		pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS =
3169		    pHtPhy->field.MCS;
3170		pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE =
3171		    pHtPhy->field.MODE;
3172	}
3173
3174	if (pAd->CommonCfg.TxRate <= RATE_11) {
3175		pMaxHtPhy->field.MODE = MODE_CCK;
3176		pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate;
3177		pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
3178	} else {
3179		pMaxHtPhy->field.MODE = MODE_OFDM;
3180		pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate];
3181		if (pAd->CommonCfg.MinTxRate >= RATE_6
3182		    && (pAd->CommonCfg.MinTxRate <= RATE_54)) {
3183			pMinHtPhy->field.MCS =
3184			    OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];
3185		} else {
3186			pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
3187		}
3188	}
3189
3190	pHtPhy->word = (pMaxHtPhy->word);
3191	if (bLinkUp && (pAd->OpMode == OPMODE_STA)) {
3192		pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word;
3193		pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word =
3194		    pMaxHtPhy->word;
3195		pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word =
3196		    pMinHtPhy->word;
3197	} else {
3198		switch (pAd->CommonCfg.PhyMode) {
3199		case PHY_11BG_MIXED:
3200		case PHY_11B:
3201		case PHY_11BGN_MIXED:
3202			pAd->CommonCfg.MlmeRate = RATE_1;
3203			pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
3204			pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
3205
3206/*#ifdef        WIFI_TEST */
3207			pAd->CommonCfg.RtsRate = RATE_11;
3208/*#else */
3209/*                              pAd->CommonCfg.RtsRate = RATE_1; */
3210/*#endif */
3211			break;
3212		case PHY_11G:
3213		case PHY_11A:
3214		case PHY_11AGN_MIXED:
3215		case PHY_11GN_MIXED:
3216		case PHY_11N_2_4G:
3217		case PHY_11AN_MIXED:
3218		case PHY_11N_5G:
3219			pAd->CommonCfg.MlmeRate = RATE_6;
3220			pAd->CommonCfg.RtsRate = RATE_6;
3221			pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
3222			pAd->CommonCfg.MlmeTransmit.field.MCS =
3223			    OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3224			break;
3225		case PHY_11ABG_MIXED:
3226		case PHY_11ABGN_MIXED:
3227			if (pAd->CommonCfg.Channel <= 14) {
3228				pAd->CommonCfg.MlmeRate = RATE_1;
3229				pAd->CommonCfg.RtsRate = RATE_1;
3230				pAd->CommonCfg.MlmeTransmit.field.MODE =
3231				    MODE_CCK;
3232				pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
3233			} else {
3234				pAd->CommonCfg.MlmeRate = RATE_6;
3235				pAd->CommonCfg.RtsRate = RATE_6;
3236				pAd->CommonCfg.MlmeTransmit.field.MODE =
3237				    MODE_OFDM;
3238				pAd->CommonCfg.MlmeTransmit.field.MCS =
3239				    OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3240			}
3241			break;
3242		default:	/* error */
3243			pAd->CommonCfg.MlmeRate = RATE_6;
3244			pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
3245			pAd->CommonCfg.MlmeTransmit.field.MCS =
3246			    OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3247			pAd->CommonCfg.RtsRate = RATE_1;
3248			break;
3249		}
3250		/* */
3251		/* Keep Basic Mlme Rate. */
3252		/* */
3253		pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word =
3254		    pAd->CommonCfg.MlmeTransmit.word;
3255		if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM)
3256			pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS =
3257			    OfdmRateToRxwiMCS[RATE_24];
3258		else
3259			pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS =
3260			    RATE_1;
3261		pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate;
3262	}
3263
3264	DBGPRINT(RT_DEBUG_TRACE,
3265		 (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n",
3266		  RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport],
3267		  RateIdToMbps[pAd->CommonCfg.MaxTxRate],
3268		  RateIdToMbps[pAd->CommonCfg.MinTxRate],
3269		  /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) */
3270		  *auto_rate_cur_p));
3271	DBGPRINT(RT_DEBUG_TRACE,
3272		 (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n",
3273		  RateIdToMbps[pAd->CommonCfg.TxRate],
3274		  RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap));
3275	DBGPRINT(RT_DEBUG_TRACE,
3276		 ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n",
3277		  pAd->CommonCfg.MlmeTransmit.word,
3278		  pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word,
3279		  pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word,
3280		  pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word));
3281}
3282
3283/*
3284	==========================================================================
3285	Description:
3286		This function update HT Rate setting.
3287		Input Wcid value is valid for 2 case :
3288		1. it's used for Station in infra mode that copy AP rate to Mactable.
3289		2. OR Station	in adhoc mode to copy peer's HT rate to Mactable.
3290
3291 IRQL = DISPATCH_LEVEL
3292
3293	==========================================================================
3294 */
3295void MlmeUpdateHtTxRates(struct rt_rtmp_adapter *pAd, u8 apidx)
3296{
3297	u8 StbcMcs;		/*j, StbcMcs, bitmask; */
3298	char i;			/* 3*3 */
3299	struct rt_ht_capability *pRtHtCap = NULL;
3300	struct rt_ht_phy_info *pActiveHtPhy = NULL;
3301	unsigned long BasicMCS;
3302	u8 j, bitmask;
3303	struct rt_ht_phy_info *pDesireHtPhy = NULL;
3304	PHTTRANSMIT_SETTING pHtPhy = NULL;
3305	PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
3306	PHTTRANSMIT_SETTING pMinHtPhy = NULL;
3307	BOOLEAN *auto_rate_cur_p;
3308
3309	DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateHtTxRates===> \n"));
3310
3311	auto_rate_cur_p = NULL;
3312
3313	{
3314		pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
3315		pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
3316		pHtPhy = &pAd->StaCfg.HTPhyMode;
3317		pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
3318		pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
3319
3320		auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
3321	}
3322
3323	if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) {
3324		if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE)
3325			return;
3326
3327		pRtHtCap = &pAd->StaActive.SupportedHtPhy;
3328		pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo;
3329		StbcMcs = (u8)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs;
3330		BasicMCS =
3331		    pAd->MlmeAux.AddHtInfo.MCSSet[0] +
3332		    (pAd->MlmeAux.AddHtInfo.MCSSet[1] << 8) + (StbcMcs << 16);
3333		if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC)
3334		    && (pAd->Antenna.field.TxPath == 2))
3335			pMaxHtPhy->field.STBC = STBC_USE;
3336		else
3337			pMaxHtPhy->field.STBC = STBC_NONE;
3338	} else {
3339		if (pDesireHtPhy->bHtEnable == FALSE)
3340			return;
3341
3342		pRtHtCap = &pAd->CommonCfg.DesiredHtPhy;
3343		StbcMcs = (u8)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs;
3344		BasicMCS =
3345		    pAd->CommonCfg.AddHTInfo.MCSSet[0] +
3346		    (pAd->CommonCfg.AddHTInfo.MCSSet[1] << 8) + (StbcMcs << 16);
3347		if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC)
3348		    && (pAd->Antenna.field.TxPath == 2))
3349			pMaxHtPhy->field.STBC = STBC_USE;
3350		else
3351			pMaxHtPhy->field.STBC = STBC_NONE;
3352	}
3353
3354	/* Decide MAX ht rate. */
3355	if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF))
3356		pMaxHtPhy->field.MODE = MODE_HTGREENFIELD;
3357	else
3358		pMaxHtPhy->field.MODE = MODE_HTMIX;
3359
3360	if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth)
3361	    && (pRtHtCap->ChannelWidth))
3362		pMaxHtPhy->field.BW = BW_40;
3363	else
3364		pMaxHtPhy->field.BW = BW_20;
3365
3366	if (pMaxHtPhy->field.BW == BW_20)
3367		pMaxHtPhy->field.ShortGI =
3368		    (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->
3369		     ShortGIfor20);
3370	else
3371		pMaxHtPhy->field.ShortGI =
3372		    (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->
3373		     ShortGIfor40);
3374
3375	if (pDesireHtPhy->MCSSet[4] != 0) {
3376		pMaxHtPhy->field.MCS = 32;
3377	}
3378
3379	for (i = 23; i >= 0; i--)	/* 3*3 */
3380	{
3381		j = i / 8;
3382		bitmask = (1 << (i - (j * 8)));
3383
3384		if ((pActiveHtPhy->MCSSet[j] & bitmask)
3385		    && (pDesireHtPhy->MCSSet[j] & bitmask)) {
3386			pMaxHtPhy->field.MCS = i;
3387			break;
3388		}
3389
3390		if (i == 0)
3391			break;
3392	}
3393
3394	/* Copy MIN ht rate.  rt2860??? */
3395	pMinHtPhy->field.BW = BW_20;
3396	pMinHtPhy->field.MCS = 0;
3397	pMinHtPhy->field.STBC = 0;
3398	pMinHtPhy->field.ShortGI = 0;
3399	/*If STA assigns fixed rate. update to fixed here. */
3400	if ((pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) {
3401		if (pDesireHtPhy->MCSSet[4] != 0) {
3402			pMaxHtPhy->field.MCS = 32;
3403			pMinHtPhy->field.MCS = 32;
3404			DBGPRINT(RT_DEBUG_TRACE,
3405				 ("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",
3406				  pMinHtPhy->field.MCS));
3407		}
3408
3409		for (i = 23; (char)i >= 0; i--)	/* 3*3 */
3410		{
3411			j = i / 8;
3412			bitmask = (1 << (i - (j * 8)));
3413			if ((pDesireHtPhy->MCSSet[j] & bitmask)
3414			    && (pActiveHtPhy->MCSSet[j] & bitmask)) {
3415				pMaxHtPhy->field.MCS = i;
3416				pMinHtPhy->field.MCS = i;
3417				break;
3418			}
3419			if (i == 0)
3420				break;
3421		}
3422	}
3423
3424	/* Decide ht rate */
3425	pHtPhy->field.STBC = pMaxHtPhy->field.STBC;
3426	pHtPhy->field.BW = pMaxHtPhy->field.BW;
3427	pHtPhy->field.MODE = pMaxHtPhy->field.MODE;
3428	pHtPhy->field.MCS = pMaxHtPhy->field.MCS;
3429	pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI;
3430
3431	/* use default now. rt2860 */
3432	if (pDesireHtPhy->MCSSet[0] != 0xff)
3433		*auto_rate_cur_p = FALSE;
3434	else
3435		*auto_rate_cur_p = TRUE;
3436
3437	DBGPRINT(RT_DEBUG_TRACE,
3438		 (" MlmeUpdateHtTxRates<---.AMsduSize = %d  \n",
3439		  pAd->CommonCfg.DesiredHtPhy.AmsduSize));
3440	DBGPRINT(RT_DEBUG_TRACE,
3441		 ("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d,  \n",
3442		  pActiveHtPhy->MCSSet[0], pHtPhy->field.MCS, pHtPhy->field.BW,
3443		  pHtPhy->field.ShortGI, pHtPhy->field.MODE));
3444	DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateHtTxRates<=== \n"));
3445}
3446
3447void BATableInit(struct rt_rtmp_adapter *pAd, struct rt_ba_table *Tab)
3448{
3449	int i;
3450
3451	Tab->numAsOriginator = 0;
3452	Tab->numAsRecipient = 0;
3453	Tab->numDoneOriginator = 0;
3454	NdisAllocateSpinLock(&pAd->BATabLock);
3455	for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) {
3456		Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE;
3457		NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock));
3458	}
3459	for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) {
3460		Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE;
3461	}
3462}
3463
3464/* IRQL = DISPATCH_LEVEL */
3465void MlmeRadioOff(struct rt_rtmp_adapter *pAd)
3466{
3467	RTMP_MLME_RADIO_OFF(pAd);
3468}
3469
3470/* IRQL = DISPATCH_LEVEL */
3471void MlmeRadioOn(struct rt_rtmp_adapter *pAd)
3472{
3473	RTMP_MLME_RADIO_ON(pAd);
3474}
3475
3476/* =========================================================================================== */
3477/* bss_table.c */
3478/* =========================================================================================== */
3479
3480/*! \brief initialize BSS table
3481 *	\param p_tab pointer to the table
3482 *	\return none
3483 *	\pre
3484 *	\post
3485
3486 IRQL = PASSIVE_LEVEL
3487 IRQL = DISPATCH_LEVEL
3488
3489 */
3490void BssTableInit(struct rt_bss_table *Tab)
3491{
3492	int i;
3493
3494	Tab->BssNr = 0;
3495	Tab->BssOverlapNr = 0;
3496	for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) {
3497		NdisZeroMemory(&Tab->BssEntry[i], sizeof(struct rt_bss_entry));
3498		Tab->BssEntry[i].Rssi = -127;	/* initial the rssi as a minimum value */
3499	}
3500}
3501
3502/*! \brief search the BSS table by SSID
3503 *	\param p_tab pointer to the bss table
3504 *	\param ssid SSID string
3505 *	\return index of the table, BSS_NOT_FOUND if not in the table
3506 *	\pre
3507 *	\post
3508 *	\note search by sequential search
3509
3510 IRQL = DISPATCH_LEVEL
3511
3512 */
3513unsigned long BssTableSearch(struct rt_bss_table *Tab, u8 *pBssid, u8 Channel)
3514{
3515	u8 i;
3516
3517	for (i = 0; i < Tab->BssNr; i++) {
3518		/* */
3519		/* Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. */
3520		/* We should distinguish this case. */
3521		/* */
3522		if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3523		     ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3524		    MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) {
3525			return i;
3526		}
3527	}
3528	return (unsigned long)BSS_NOT_FOUND;
3529}
3530
3531unsigned long BssSsidTableSearch(struct rt_bss_table *Tab,
3532			 u8 *pBssid,
3533			 u8 *pSsid, u8 SsidLen, u8 Channel)
3534{
3535	u8 i;
3536
3537	for (i = 0; i < Tab->BssNr; i++) {
3538		/* */
3539		/* Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. */
3540		/* We should distinguish this case. */
3541		/* */
3542		if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3543		     ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3544		    MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) &&
3545		    SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3546			       Tab->BssEntry[i].SsidLen)) {
3547			return i;
3548		}
3549	}
3550	return (unsigned long)BSS_NOT_FOUND;
3551}
3552
3553unsigned long BssTableSearchWithSSID(struct rt_bss_table *Tab,
3554			     u8 *Bssid,
3555			     u8 *pSsid,
3556			     u8 SsidLen, u8 Channel)
3557{
3558	u8 i;
3559
3560	for (i = 0; i < Tab->BssNr; i++) {
3561		if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3562		     ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3563		    MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) &&
3564		    (SSID_EQUAL
3565		     (pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3566		      Tab->BssEntry[i].SsidLen)
3567		     || (NdisEqualMemory(pSsid, ZeroSsid, SsidLen))
3568		     ||
3569		     (NdisEqualMemory
3570		      (Tab->BssEntry[i].Ssid, ZeroSsid,
3571		       Tab->BssEntry[i].SsidLen)))) {
3572			return i;
3573		}
3574	}
3575	return (unsigned long)BSS_NOT_FOUND;
3576}
3577
3578unsigned long BssSsidTableSearchBySSID(struct rt_bss_table *Tab,
3579			       u8 *pSsid, u8 SsidLen)
3580{
3581	u8 i;
3582
3583	for (i = 0; i < Tab->BssNr; i++) {
3584		if (SSID_EQUAL
3585		    (pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3586		     Tab->BssEntry[i].SsidLen)) {
3587			return i;
3588		}
3589	}
3590	return (unsigned long)BSS_NOT_FOUND;
3591}
3592
3593/* IRQL = DISPATCH_LEVEL */
3594void BssTableDeleteEntry(struct rt_bss_table *Tab,
3595			 u8 *pBssid, u8 Channel)
3596{
3597	u8 i, j;
3598
3599	for (i = 0; i < Tab->BssNr; i++) {
3600		if ((Tab->BssEntry[i].Channel == Channel) &&
3601		    (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) {
3602			for (j = i; j < Tab->BssNr - 1; j++) {
3603				NdisMoveMemory(&(Tab->BssEntry[j]),
3604					       &(Tab->BssEntry[j + 1]),
3605					       sizeof(struct rt_bss_entry));
3606			}
3607			NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]),
3608				       sizeof(struct rt_bss_entry));
3609			Tab->BssNr -= 1;
3610			return;
3611		}
3612	}
3613}
3614
3615/*
3616	========================================================================
3617	Routine Description:
3618		Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed.
3619
3620	Arguments:
3621	// IRQL = DISPATCH_LEVEL
3622	========================================================================
3623*/
3624void BATableDeleteORIEntry(struct rt_rtmp_adapter *pAd,
3625			   struct rt_ba_ori_entry *pBAORIEntry)
3626{
3627
3628	if (pBAORIEntry->ORI_BA_Status != Originator_NONE) {
3629		NdisAcquireSpinLock(&pAd->BATabLock);
3630		if (pBAORIEntry->ORI_BA_Status == Originator_Done) {
3631			pAd->BATable.numAsOriginator -= 1;
3632			DBGPRINT(RT_DEBUG_TRACE,
3633				 ("BATableDeleteORIEntry numAsOriginator= %ld\n",
3634				  pAd->BATable.numAsRecipient));
3635			/* Erase Bitmap flag. */
3636		}
3637		pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1 << (pBAORIEntry->TID)));	/* If STA mode,  erase flag here */
3638		pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0;	/* If STA mode,  erase flag here */
3639		pBAORIEntry->ORI_BA_Status = Originator_NONE;
3640		pBAORIEntry->Token = 1;
3641		/* Not clear Sequence here. */
3642		NdisReleaseSpinLock(&pAd->BATabLock);
3643	}
3644}
3645
3646/*! \brief
3647 *	\param
3648 *	\return
3649 *	\pre
3650 *	\post
3651
3652 IRQL = DISPATCH_LEVEL
3653
3654 */
3655void BssEntrySet(struct rt_rtmp_adapter *pAd, struct rt_bss_entry *pBss, u8 *pBssid, char Ssid[], u8 SsidLen, u8 BssType, u16 BeaconPeriod, struct rt_cf_parm * pCfParm, u16 AtimWin, u16 CapabilityInfo, u8 SupRate[], u8 SupRateLen, u8 ExtRate[], u8 ExtRateLen, struct rt_ht_capability_ie * pHtCapability, struct rt_add_ht_info_ie * pAddHtInfo,	/* AP might use this additional ht info IE */
3656		 u8 HtCapabilityLen,
3657		 u8 AddHtInfoLen,
3658		 u8 NewExtChanOffset,
3659		 u8 Channel,
3660		 char Rssi,
3661		 IN LARGE_INTEGER TimeStamp,
3662		 u8 CkipFlag,
3663		 struct rt_edca_parm *pEdcaParm,
3664		 struct rt_qos_capability_parm *pQosCapability,
3665		 struct rt_qbss_load_parm *pQbssLoad,
3666		 u16 LengthVIE, struct rt_ndis_802_11_variable_ies *pVIE)
3667{
3668	COPY_MAC_ADDR(pBss->Bssid, pBssid);
3669	/* Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID */
3670	pBss->Hidden = 1;
3671	if (SsidLen > 0) {
3672		/* For hidden SSID AP, it might send beacon with SSID len equal to 0 */
3673		/* Or send beacon /probe response with SSID len matching real SSID length, */
3674		/* but SSID is all zero. such as "00-00-00-00" with length 4. */
3675		/* We have to prevent this case overwrite correct table */
3676		if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) {
3677			NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID);
3678			NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
3679			pBss->SsidLen = SsidLen;
3680			pBss->Hidden = 0;
3681		}
3682	} else
3683		pBss->SsidLen = 0;
3684	pBss->BssType = BssType;
3685	pBss->BeaconPeriod = BeaconPeriod;
3686	if (BssType == BSS_INFRA) {
3687		if (pCfParm->bValid) {
3688			pBss->CfpCount = pCfParm->CfpCount;
3689			pBss->CfpPeriod = pCfParm->CfpPeriod;
3690			pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
3691			pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
3692		}
3693	} else {
3694		pBss->AtimWin = AtimWin;
3695	}
3696
3697	pBss->CapabilityInfo = CapabilityInfo;
3698	/* The privacy bit indicate security is ON, it maight be WEP, TKIP or AES */
3699	/* Combine with AuthMode, they will decide the connection methods. */
3700	pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
3701	ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
3702	if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
3703		NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen);
3704	else
3705		NdisMoveMemory(pBss->SupRate, SupRate,
3706			       MAX_LEN_OF_SUPPORTED_RATES);
3707	pBss->SupRateLen = SupRateLen;
3708	ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
3709	NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen);
3710	pBss->NewExtChanOffset = NewExtChanOffset;
3711	pBss->ExtRateLen = ExtRateLen;
3712	pBss->Channel = Channel;
3713	pBss->CentralChannel = Channel;
3714	pBss->Rssi = Rssi;
3715	/* Update CkipFlag. if not exists, the value is 0x0 */
3716	pBss->CkipFlag = CkipFlag;
3717
3718	/* New for microsoft Fixed IEs */
3719	NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
3720	pBss->FixIEs.BeaconInterval = BeaconPeriod;
3721	pBss->FixIEs.Capabilities = CapabilityInfo;
3722
3723	/* New for microsoft Variable IEs */
3724	if (LengthVIE != 0) {
3725		pBss->VarIELen = LengthVIE;
3726		NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen);
3727	} else {
3728		pBss->VarIELen = 0;
3729	}
3730
3731	pBss->AddHtInfoLen = 0;
3732	pBss->HtCapabilityLen = 0;
3733	if (HtCapabilityLen > 0) {
3734		pBss->HtCapabilityLen = HtCapabilityLen;
3735		NdisMoveMemory(&pBss->HtCapability, pHtCapability,
3736			       HtCapabilityLen);
3737		if (AddHtInfoLen > 0) {
3738			pBss->AddHtInfoLen = AddHtInfoLen;
3739			NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo,
3740				       AddHtInfoLen);
3741
3742			if ((pAddHtInfo->ControlChan > 2)
3743			    && (pAddHtInfo->AddHtInfo.ExtChanOffset ==
3744				EXTCHA_BELOW)
3745			    && (pHtCapability->HtCapInfo.ChannelWidth ==
3746				BW_40)) {
3747				pBss->CentralChannel =
3748				    pAddHtInfo->ControlChan - 2;
3749			} else
3750			    if ((pAddHtInfo->AddHtInfo.ExtChanOffset ==
3751				 EXTCHA_ABOVE)
3752				&& (pHtCapability->HtCapInfo.ChannelWidth ==
3753				    BW_40)) {
3754				pBss->CentralChannel =
3755				    pAddHtInfo->ControlChan + 2;
3756			}
3757		}
3758	}
3759
3760	BssCipherParse(pBss);
3761
3762	/* new for QOS */
3763	if (pEdcaParm)
3764		NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(struct rt_edca_parm));
3765	else
3766		pBss->EdcaParm.bValid = FALSE;
3767	if (pQosCapability)
3768		NdisMoveMemory(&pBss->QosCapability, pQosCapability,
3769			       sizeof(struct rt_qos_capability_parm));
3770	else
3771		pBss->QosCapability.bValid = FALSE;
3772	if (pQbssLoad)
3773		NdisMoveMemory(&pBss->QbssLoad, pQbssLoad,
3774			       sizeof(struct rt_qbss_load_parm));
3775	else
3776		pBss->QbssLoad.bValid = FALSE;
3777
3778	{
3779		struct rt_eid * pEid;
3780		u16 Length = 0;
3781
3782		NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN);
3783		NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN);
3784		pEid = (struct rt_eid *) pVIE;
3785		while ((Length + 2 + (u16)pEid->Len) <= LengthVIE) {
3786			switch (pEid->Eid) {
3787			case IE_WPA:
3788				if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) {
3789					if ((pEid->Len + 2) > MAX_CUSTOM_LEN) {
3790						pBss->WpaIE.IELen = 0;
3791						break;
3792					}
3793					pBss->WpaIE.IELen = pEid->Len + 2;
3794					NdisMoveMemory(pBss->WpaIE.IE, pEid,
3795						       pBss->WpaIE.IELen);
3796				}
3797				break;
3798			case IE_RSN:
3799				if (NdisEqualMemory
3800				    (pEid->Octet + 2, RSN_OUI, 3)) {
3801					if ((pEid->Len + 2) > MAX_CUSTOM_LEN) {
3802						pBss->RsnIE.IELen = 0;
3803						break;
3804					}
3805					pBss->RsnIE.IELen = pEid->Len + 2;
3806					NdisMoveMemory(pBss->RsnIE.IE, pEid,
3807						       pBss->RsnIE.IELen);
3808				}
3809				break;
3810			}
3811			Length = Length + 2 + (u16)pEid->Len;	/* Eid[1] + Len[1]+ content[Len] */
3812			pEid = (struct rt_eid *) ((u8 *) pEid + 2 + pEid->Len);
3813		}
3814	}
3815}
3816
3817/*!
3818 *	\brief insert an entry into the bss table
3819 *	\param p_tab The BSS table
3820 *	\param Bssid BSSID
3821 *	\param ssid SSID
3822 *	\param ssid_len Length of SSID
3823 *	\param bss_type
3824 *	\param beacon_period
3825 *	\param timestamp
3826 *	\param p_cf
3827 *	\param atim_win
3828 *	\param cap
3829 *	\param rates
3830 *	\param rates_len
3831 *	\param channel_idx
3832 *	\return none
3833 *	\pre
3834 *	\post
3835 *	\note If SSID is identical, the old entry will be replaced by the new one
3836
3837 IRQL = DISPATCH_LEVEL
3838
3839 */
3840unsigned long BssTableSetEntry(struct rt_rtmp_adapter *pAd, struct rt_bss_table *Tab, u8 *pBssid, char Ssid[], u8 SsidLen, u8 BssType, u16 BeaconPeriod, struct rt_cf_parm * CfParm, u16 AtimWin, u16 CapabilityInfo, u8 SupRate[], u8 SupRateLen, u8 ExtRate[], u8 ExtRateLen, struct rt_ht_capability_ie * pHtCapability, struct rt_add_ht_info_ie * pAddHtInfo,	/* AP might use this additional ht info IE */
3841		       u8 HtCapabilityLen,
3842		       u8 AddHtInfoLen,
3843		       u8 NewExtChanOffset,
3844		       u8 ChannelNo,
3845		       char Rssi,
3846		       IN LARGE_INTEGER TimeStamp,
3847		       u8 CkipFlag,
3848		       struct rt_edca_parm *pEdcaParm,
3849		       struct rt_qos_capability_parm *pQosCapability,
3850		       struct rt_qbss_load_parm *pQbssLoad,
3851		       u16 LengthVIE, struct rt_ndis_802_11_variable_ies *pVIE)
3852{
3853	unsigned long Idx;
3854
3855	Idx =
3856	    BssTableSearchWithSSID(Tab, pBssid, (u8 *) Ssid, SsidLen,
3857				   ChannelNo);
3858	if (Idx == BSS_NOT_FOUND) {
3859		if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) {
3860			/* */
3861			/* It may happen when BSS Table was full. */
3862			/* The desired AP will not be added into BSS Table */
3863			/* In this case, if we found the desired AP then overwrite BSS Table. */
3864			/* */
3865			if (!OPSTATUS_TEST_FLAG
3866			    (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
3867				if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid)
3868				    || SSID_EQUAL(pAd->MlmeAux.Ssid,
3869						  pAd->MlmeAux.SsidLen, Ssid,
3870						  SsidLen)) {
3871					Idx = Tab->BssOverlapNr;
3872					BssEntrySet(pAd, &Tab->BssEntry[Idx],
3873						    pBssid, Ssid, SsidLen,
3874						    BssType, BeaconPeriod,
3875						    CfParm, AtimWin,
3876						    CapabilityInfo, SupRate,
3877						    SupRateLen, ExtRate,
3878						    ExtRateLen, pHtCapability,
3879						    pAddHtInfo, HtCapabilityLen,
3880						    AddHtInfoLen,
3881						    NewExtChanOffset, ChannelNo,
3882						    Rssi, TimeStamp, CkipFlag,
3883						    pEdcaParm, pQosCapability,
3884						    pQbssLoad, LengthVIE, pVIE);
3885					Tab->BssOverlapNr =
3886					    (Tab->BssOverlapNr++) %
3887					    MAX_LEN_OF_BSS_TABLE;
3888				}
3889				return Idx;
3890			} else {
3891				return BSS_NOT_FOUND;
3892			}
3893		}
3894		Idx = Tab->BssNr;
3895		BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen,
3896			    BssType, BeaconPeriod, CfParm, AtimWin,
3897			    CapabilityInfo, SupRate, SupRateLen, ExtRate,
3898			    ExtRateLen, pHtCapability, pAddHtInfo,
3899			    HtCapabilityLen, AddHtInfoLen, NewExtChanOffset,
3900			    ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm,
3901			    pQosCapability, pQbssLoad, LengthVIE, pVIE);
3902		Tab->BssNr++;
3903	} else {
3904		/* avoid  Hidden SSID form beacon to overwirite correct SSID from probe response */
3905		if ((SSID_EQUAL
3906		     (Ssid, SsidLen, Tab->BssEntry[Idx].Ssid,
3907		      Tab->BssEntry[Idx].SsidLen))
3908		    ||
3909		    (NdisEqualMemory
3910		     (Tab->BssEntry[Idx].Ssid, ZeroSsid,
3911		      Tab->BssEntry[Idx].SsidLen))) {
3912			BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid,
3913				    SsidLen, BssType, BeaconPeriod, CfParm,
3914				    AtimWin, CapabilityInfo, SupRate,
3915				    SupRateLen, ExtRate, ExtRateLen,
3916				    pHtCapability, pAddHtInfo, HtCapabilityLen,
3917				    AddHtInfoLen, NewExtChanOffset, ChannelNo,
3918				    Rssi, TimeStamp, CkipFlag, pEdcaParm,
3919				    pQosCapability, pQbssLoad, LengthVIE, pVIE);
3920		}
3921	}
3922
3923	return Idx;
3924}
3925
3926/* IRQL = DISPATCH_LEVEL */
3927void BssTableSsidSort(struct rt_rtmp_adapter *pAd,
3928		      struct rt_bss_table *OutTab, char Ssid[], u8 SsidLen)
3929{
3930	int i;
3931	BssTableInit(OutTab);
3932
3933	for (i = 0; i < pAd->ScanTab.BssNr; i++) {
3934		struct rt_bss_entry *pInBss = &pAd->ScanTab.BssEntry[i];
3935		BOOLEAN bIsHiddenApIncluded = FALSE;
3936
3937		if (((pAd->CommonCfg.bIEEE80211H == 1) &&
3938		     (pAd->MlmeAux.Channel > 14) &&
3939		     RadarChannelCheck(pAd, pInBss->Channel))
3940		    ) {
3941			if (pInBss->Hidden)
3942				bIsHiddenApIncluded = TRUE;
3943		}
3944
3945		if ((pInBss->BssType == pAd->StaCfg.BssType) &&
3946		    (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen)
3947		     || bIsHiddenApIncluded)) {
3948			struct rt_bss_entry *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
3949
3950			/* 2.4G/5G N only mode */
3951			if ((pInBss->HtCapabilityLen == 0) &&
3952			    ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G)
3953			     || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) {
3954				DBGPRINT(RT_DEBUG_TRACE,
3955					 ("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
3956				continue;
3957			}
3958			/* New for WPA2 */
3959			/* Check the Authmode first */
3960			if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) {
3961				/* Check AuthMode and AuthModeAux for matching, in case AP support dual-mode */
3962				if ((pAd->StaCfg.AuthMode != pInBss->AuthMode)
3963				    && (pAd->StaCfg.AuthMode !=
3964					pInBss->AuthModeAux))
3965					/* None matched */
3966					continue;
3967
3968				/* Check cipher suite, AP must have more secured cipher than station setting */
3969				if ((pAd->StaCfg.AuthMode ==
3970				     Ndis802_11AuthModeWPA)
3971				    || (pAd->StaCfg.AuthMode ==
3972					Ndis802_11AuthModeWPAPSK)) {
3973					/* If it's not mixed mode, we should only let BSS pass with the same encryption */
3974					if (pInBss->WPA.bMixMode == FALSE)
3975						if (pAd->StaCfg.WepStatus !=
3976						    pInBss->WPA.GroupCipher)
3977							continue;
3978
3979					/* check group cipher */
3980					if ((pAd->StaCfg.WepStatus <
3981					     pInBss->WPA.GroupCipher)
3982					    && (pInBss->WPA.GroupCipher !=
3983						Ndis802_11GroupWEP40Enabled)
3984					    && (pInBss->WPA.GroupCipher !=
3985						Ndis802_11GroupWEP104Enabled))
3986						continue;
3987
3988					/* check pairwise cipher, skip if none matched */
3989					/* If profile set to AES, let it pass without question. */
3990					/* If profile set to TKIP, we must find one mateched */
3991					if ((pAd->StaCfg.WepStatus ==
3992					     Ndis802_11Encryption2Enabled)
3993					    && (pAd->StaCfg.WepStatus !=
3994						pInBss->WPA.PairCipher)
3995					    && (pAd->StaCfg.WepStatus !=
3996						pInBss->WPA.PairCipherAux))
3997						continue;
3998				} else
3999				    if ((pAd->StaCfg.AuthMode ==
4000					 Ndis802_11AuthModeWPA2)
4001					|| (pAd->StaCfg.AuthMode ==
4002					    Ndis802_11AuthModeWPA2PSK)) {
4003					/* If it's not mixed mode, we should only let BSS pass with the same encryption */
4004					if (pInBss->WPA2.bMixMode == FALSE)
4005						if (pAd->StaCfg.WepStatus !=
4006						    pInBss->WPA2.GroupCipher)
4007							continue;
4008
4009					/* check group cipher */
4010					if ((pAd->StaCfg.WepStatus <
4011					     pInBss->WPA.GroupCipher)
4012					    && (pInBss->WPA2.GroupCipher !=
4013						Ndis802_11GroupWEP40Enabled)
4014					    && (pInBss->WPA2.GroupCipher !=
4015						Ndis802_11GroupWEP104Enabled))
4016						continue;
4017
4018					/* check pairwise cipher, skip if none matched */
4019					/* If profile set to AES, let it pass without question. */
4020					/* If profile set to TKIP, we must find one mateched */
4021					if ((pAd->StaCfg.WepStatus ==
4022					     Ndis802_11Encryption2Enabled)
4023					    && (pAd->StaCfg.WepStatus !=
4024						pInBss->WPA2.PairCipher)
4025					    && (pAd->StaCfg.WepStatus !=
4026						pInBss->WPA2.PairCipherAux))
4027						continue;
4028				}
4029			}
4030			/* Bss Type matched, SSID matched. */
4031			/* We will check wepstatus for qualification Bss */
4032			else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) {
4033				DBGPRINT(RT_DEBUG_TRACE,
4034					 ("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n",
4035					  pAd->StaCfg.WepStatus,
4036					  pInBss->WepStatus));
4037				/* */
4038				/* For the SESv2 case, we will not qualify WepStatus. */
4039				/* */
4040				if (!pInBss->bSES)
4041					continue;
4042			}
4043			/* Since the AP is using hidden SSID, and we are trying to connect to ANY */
4044			/* It definitely will fail. So, skip it. */
4045			/* CCX also require not even try to connect it! */
4046			if (SsidLen == 0)
4047				continue;
4048
4049			/* If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region */
4050			/* If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, */
4051			if ((pInBss->CentralChannel != pInBss->Channel) &&
4052			    (pAd->CommonCfg.RegTransmitSetting.field.BW ==
4053			     BW_40)) {
4054				if (RTMPCheckChannel
4055				    (pAd, pInBss->CentralChannel,
4056				     pInBss->Channel) == FALSE) {
4057					pAd->CommonCfg.RegTransmitSetting.field.
4058					    BW = BW_20;
4059					SetCommonHT(pAd);
4060					pAd->CommonCfg.RegTransmitSetting.field.
4061					    BW = BW_40;
4062				} else {
4063					if (pAd->CommonCfg.DesiredHtPhy.
4064					    ChannelWidth == BAND_WIDTH_20) {
4065						SetCommonHT(pAd);
4066					}
4067				}
4068			}
4069			/* copy matching BSS from InTab to OutTab */
4070			NdisMoveMemory(pOutBss, pInBss, sizeof(struct rt_bss_entry));
4071
4072			OutTab->BssNr++;
4073		} else if ((pInBss->BssType == pAd->StaCfg.BssType)
4074			   && (SsidLen == 0)) {
4075			struct rt_bss_entry *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
4076
4077			/* 2.4G/5G N only mode */
4078			if ((pInBss->HtCapabilityLen == 0) &&
4079			    ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G)
4080			     || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) {
4081				DBGPRINT(RT_DEBUG_TRACE,
4082					 ("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
4083				continue;
4084			}
4085			/* New for WPA2 */
4086			/* Check the Authmode first */
4087			if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) {
4088				/* Check AuthMode and AuthModeAux for matching, in case AP support dual-mode */
4089				if ((pAd->StaCfg.AuthMode != pInBss->AuthMode)
4090				    && (pAd->StaCfg.AuthMode !=
4091					pInBss->AuthModeAux))
4092					/* None matched */
4093					continue;
4094
4095				/* Check cipher suite, AP must have more secured cipher than station setting */
4096				if ((pAd->StaCfg.AuthMode ==
4097				     Ndis802_11AuthModeWPA)
4098				    || (pAd->StaCfg.AuthMode ==
4099					Ndis802_11AuthModeWPAPSK)) {
4100					/* If it's not mixed mode, we should only let BSS pass with the same encryption */
4101					if (pInBss->WPA.bMixMode == FALSE)
4102						if (pAd->StaCfg.WepStatus !=
4103						    pInBss->WPA.GroupCipher)
4104							continue;
4105
4106					/* check group cipher */
4107					if (pAd->StaCfg.WepStatus <
4108					    pInBss->WPA.GroupCipher)
4109						continue;
4110
4111					/* check pairwise cipher, skip if none matched */
4112					/* If profile set to AES, let it pass without question. */
4113					/* If profile set to TKIP, we must find one mateched */
4114					if ((pAd->StaCfg.WepStatus ==
4115					     Ndis802_11Encryption2Enabled)
4116					    && (pAd->StaCfg.WepStatus !=
4117						pInBss->WPA.PairCipher)
4118					    && (pAd->StaCfg.WepStatus !=
4119						pInBss->WPA.PairCipherAux))
4120						continue;
4121				} else
4122				    if ((pAd->StaCfg.AuthMode ==
4123					 Ndis802_11AuthModeWPA2)
4124					|| (pAd->StaCfg.AuthMode ==
4125					    Ndis802_11AuthModeWPA2PSK)) {
4126					/* If it's not mixed mode, we should only let BSS pass with the same encryption */
4127					if (pInBss->WPA2.bMixMode == FALSE)
4128						if (pAd->StaCfg.WepStatus !=
4129						    pInBss->WPA2.GroupCipher)
4130							continue;
4131
4132					/* check group cipher */
4133					if (pAd->StaCfg.WepStatus <
4134					    pInBss->WPA2.GroupCipher)
4135						continue;
4136
4137					/* check pairwise cipher, skip if none matched */
4138					/* If profile set to AES, let it pass without question. */
4139					/* If profile set to TKIP, we must find one mateched */
4140					if ((pAd->StaCfg.WepStatus ==
4141					     Ndis802_11Encryption2Enabled)
4142					    && (pAd->StaCfg.WepStatus !=
4143						pInBss->WPA2.PairCipher)
4144					    && (pAd->StaCfg.WepStatus !=
4145						pInBss->WPA2.PairCipherAux))
4146						continue;
4147				}
4148			}
4149			/* Bss Type matched, SSID matched. */
4150			/* We will check wepstatus for qualification Bss */
4151			else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
4152				continue;
4153
4154			/* If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region */
4155			/* If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, */
4156			if ((pInBss->CentralChannel != pInBss->Channel) &&
4157			    (pAd->CommonCfg.RegTransmitSetting.field.BW ==
4158			     BW_40)) {
4159				if (RTMPCheckChannel
4160				    (pAd, pInBss->CentralChannel,
4161				     pInBss->Channel) == FALSE) {
4162					pAd->CommonCfg.RegTransmitSetting.field.
4163					    BW = BW_20;
4164					SetCommonHT(pAd);
4165					pAd->CommonCfg.RegTransmitSetting.field.
4166					    BW = BW_40;
4167				}
4168			}
4169			/* copy matching BSS from InTab to OutTab */
4170			NdisMoveMemory(pOutBss, pInBss, sizeof(struct rt_bss_entry));
4171
4172			OutTab->BssNr++;
4173		}
4174
4175		if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
4176			break;
4177	}
4178
4179	BssTableSortByRssi(OutTab);
4180}
4181
4182/* IRQL = DISPATCH_LEVEL */
4183void BssTableSortByRssi(struct rt_bss_table *OutTab)
4184{
4185	int i, j;
4186	struct rt_bss_entry TmpBss;
4187
4188	for (i = 0; i < OutTab->BssNr - 1; i++) {
4189		for (j = i + 1; j < OutTab->BssNr; j++) {
4190			if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) {
4191				NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j],
4192					       sizeof(struct rt_bss_entry));
4193				NdisMoveMemory(&OutTab->BssEntry[j],
4194					       &OutTab->BssEntry[i],
4195					       sizeof(struct rt_bss_entry));
4196				NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss,
4197					       sizeof(struct rt_bss_entry));
4198			}
4199		}
4200	}
4201}
4202
4203void BssCipherParse(struct rt_bss_entry *pBss)
4204{
4205	struct rt_eid * pEid;
4206	u8 *pTmp;
4207	struct rt_rsn_ie_header * pRsnHeader;
4208	struct rt_cipher_suite_struct * pCipher;
4209	struct rt_akm_suite * pAKM;
4210	u16 Count;
4211	int Length;
4212	NDIS_802_11_ENCRYPTION_STATUS TmpCipher;
4213
4214	/* */
4215	/* WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. */
4216	/* */
4217	if (pBss->Privacy) {
4218		pBss->WepStatus = Ndis802_11WEPEnabled;
4219	} else {
4220		pBss->WepStatus = Ndis802_11WEPDisabled;
4221	}
4222	/* Set default to disable & open authentication before parsing variable IE */
4223	pBss->AuthMode = Ndis802_11AuthModeOpen;
4224	pBss->AuthModeAux = Ndis802_11AuthModeOpen;
4225
4226	/* Init WPA setting */
4227	pBss->WPA.PairCipher = Ndis802_11WEPDisabled;
4228	pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled;
4229	pBss->WPA.GroupCipher = Ndis802_11WEPDisabled;
4230	pBss->WPA.RsnCapability = 0;
4231	pBss->WPA.bMixMode = FALSE;
4232
4233	/* Init WPA2 setting */
4234	pBss->WPA2.PairCipher = Ndis802_11WEPDisabled;
4235	pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled;
4236	pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled;
4237	pBss->WPA2.RsnCapability = 0;
4238	pBss->WPA2.bMixMode = FALSE;
4239
4240	Length = (int)pBss->VarIELen;
4241
4242	while (Length > 0) {
4243		/* Parse cipher suite base on WPA1 & WPA2, they should be parsed differently */
4244		pTmp = ((u8 *)pBss->VarIEs) + pBss->VarIELen - Length;
4245		pEid = (struct rt_eid *) pTmp;
4246		switch (pEid->Eid) {
4247		case IE_WPA:
4248			if (NdisEqualMemory(pEid->Octet, SES_OUI, 3)
4249			    && (pEid->Len == 7)) {
4250				pBss->bSES = TRUE;
4251				break;
4252			} else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) !=
4253				   1) {
4254				/* if unsupported vendor specific IE */
4255				break;
4256			}
4257			/* Skip OUI, version, and multicast suite */
4258			/* This part should be improved in the future when AP supported multiple cipher suite. */
4259			/* For now, it's OK since almost all APs have fixed cipher suite supported. */
4260			/* pTmp = (u8 *)pEid->Octet; */
4261			pTmp += 11;
4262
4263			/* Cipher Suite Selectors from Spec P802.11i/D3.2 P26. */
4264			/*      Value      Meaning */
4265			/*      0                       None */
4266			/*      1                       WEP-40 */
4267			/*      2                       Tkip */
4268			/*      3                       WRAP */
4269			/*      4                       AES */
4270			/*      5                       WEP-104 */
4271			/* Parse group cipher */
4272			switch (*pTmp) {
4273			case 1:
4274				pBss->WPA.GroupCipher =
4275				    Ndis802_11GroupWEP40Enabled;
4276				break;
4277			case 5:
4278				pBss->WPA.GroupCipher =
4279				    Ndis802_11GroupWEP104Enabled;
4280				break;
4281			case 2:
4282				pBss->WPA.GroupCipher =
4283				    Ndis802_11Encryption2Enabled;
4284				break;
4285			case 4:
4286				pBss->WPA.GroupCipher =
4287				    Ndis802_11Encryption3Enabled;
4288				break;
4289			default:
4290				break;
4291			}
4292			/* number of unicast suite */
4293			pTmp += 1;
4294
4295			/* skip all unicast cipher suites */
4296			/*Count = *(u16 *)pTmp; */
4297			Count = (pTmp[1] << 8) + pTmp[0];
4298			pTmp += sizeof(u16);
4299
4300			/* Parsing all unicast cipher suite */
4301			while (Count > 0) {
4302				/* Skip OUI */
4303				pTmp += 3;
4304				TmpCipher = Ndis802_11WEPDisabled;
4305				switch (*pTmp) {
4306				case 1:
4307				case 5:	/* Although WEP is not allowed in WPA related auth mode, we parse it anyway */
4308					TmpCipher =
4309					    Ndis802_11Encryption1Enabled;
4310					break;
4311				case 2:
4312					TmpCipher =
4313					    Ndis802_11Encryption2Enabled;
4314					break;
4315				case 4:
4316					TmpCipher =
4317					    Ndis802_11Encryption3Enabled;
4318					break;
4319				default:
4320					break;
4321				}
4322				if (TmpCipher > pBss->WPA.PairCipher) {
4323					/* Move the lower cipher suite to PairCipherAux */
4324					pBss->WPA.PairCipherAux =
4325					    pBss->WPA.PairCipher;
4326					pBss->WPA.PairCipher = TmpCipher;
4327				} else {
4328					pBss->WPA.PairCipherAux = TmpCipher;
4329				}
4330				pTmp++;
4331				Count--;
4332			}
4333
4334			/* 4. get AKM suite counts */
4335			/*Count = *(u16 *)pTmp; */
4336			Count = (pTmp[1] << 8) + pTmp[0];
4337			pTmp += sizeof(u16);
4338			pTmp += 3;
4339
4340			switch (*pTmp) {
4341			case 1:
4342				/* Set AP support WPA-enterprise mode */
4343				if (pBss->AuthMode == Ndis802_11AuthModeOpen)
4344					pBss->AuthMode = Ndis802_11AuthModeWPA;
4345				else
4346					pBss->AuthModeAux =
4347					    Ndis802_11AuthModeWPA;
4348				break;
4349			case 2:
4350				/* Set AP support WPA-PSK mode */
4351				if (pBss->AuthMode == Ndis802_11AuthModeOpen)
4352					pBss->AuthMode =
4353					    Ndis802_11AuthModeWPAPSK;
4354				else
4355					pBss->AuthModeAux =
4356					    Ndis802_11AuthModeWPAPSK;
4357				break;
4358			default:
4359				break;
4360			}
4361			pTmp += 1;
4362
4363			/* Fixed for WPA-None */
4364			if (pBss->BssType == BSS_ADHOC) {
4365				pBss->AuthMode = Ndis802_11AuthModeWPANone;
4366				pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
4367				pBss->WepStatus = pBss->WPA.GroupCipher;
4368				/* Patched bugs for old driver */
4369				if (pBss->WPA.PairCipherAux ==
4370				    Ndis802_11WEPDisabled)
4371					pBss->WPA.PairCipherAux =
4372					    pBss->WPA.GroupCipher;
4373			} else
4374				pBss->WepStatus = pBss->WPA.PairCipher;
4375
4376			/* Check the Pair & Group, if different, turn on mixed mode flag */
4377			if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher)
4378				pBss->WPA.bMixMode = TRUE;
4379
4380			break;
4381
4382		case IE_RSN:
4383			pRsnHeader = (struct rt_rsn_ie_header *) pTmp;
4384
4385			/* 0. Version must be 1 */
4386			if (le2cpu16(pRsnHeader->Version) != 1)
4387				break;
4388			pTmp += sizeof(struct rt_rsn_ie_header);
4389
4390			/* 1. Check group cipher */
4391			pCipher = (struct rt_cipher_suite_struct *) pTmp;
4392			if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
4393				break;
4394
4395			/* Parse group cipher */
4396			switch (pCipher->Type) {
4397			case 1:
4398				pBss->WPA2.GroupCipher =
4399				    Ndis802_11GroupWEP40Enabled;
4400				break;
4401			case 5:
4402				pBss->WPA2.GroupCipher =
4403				    Ndis802_11GroupWEP104Enabled;
4404				break;
4405			case 2:
4406				pBss->WPA2.GroupCipher =
4407				    Ndis802_11Encryption2Enabled;
4408				break;
4409			case 4:
4410				pBss->WPA2.GroupCipher =
4411				    Ndis802_11Encryption3Enabled;
4412				break;
4413			default:
4414				break;
4415			}
4416			/* set to correct offset for next parsing */
4417			pTmp += sizeof(struct rt_cipher_suite_struct);
4418
4419			/* 2. Get pairwise cipher counts */
4420			/*Count = *(u16 *)pTmp; */
4421			Count = (pTmp[1] << 8) + pTmp[0];
4422			pTmp += sizeof(u16);
4423
4424			/* 3. Get pairwise cipher */
4425			/* Parsing all unicast cipher suite */
4426			while (Count > 0) {
4427				/* Skip OUI */
4428				pCipher = (struct rt_cipher_suite_struct *) pTmp;
4429				TmpCipher = Ndis802_11WEPDisabled;
4430				switch (pCipher->Type) {
4431				case 1:
4432				case 5:	/* Although WEP is not allowed in WPA related auth mode, we parse it anyway */
4433					TmpCipher =
4434					    Ndis802_11Encryption1Enabled;
4435					break;
4436				case 2:
4437					TmpCipher =
4438					    Ndis802_11Encryption2Enabled;
4439					break;
4440				case 4:
4441					TmpCipher =
4442					    Ndis802_11Encryption3Enabled;
4443					break;
4444				default:
4445					break;
4446				}
4447				if (TmpCipher > pBss->WPA2.PairCipher) {
4448					/* Move the lower cipher suite to PairCipherAux */
4449					pBss->WPA2.PairCipherAux =
4450					    pBss->WPA2.PairCipher;
4451					pBss->WPA2.PairCipher = TmpCipher;
4452				} else {
4453					pBss->WPA2.PairCipherAux = TmpCipher;
4454				}
4455				pTmp += sizeof(struct rt_cipher_suite_struct);
4456				Count--;
4457			}
4458
4459			/* 4. get AKM suite counts */
4460			/*Count = *(u16 *)pTmp; */
4461			Count = (pTmp[1] << 8) + pTmp[0];
4462			pTmp += sizeof(u16);
4463
4464			/* 5. Get AKM ciphers */
4465			/* Parsing all AKM ciphers */
4466			while (Count > 0) {
4467				pAKM = (struct rt_akm_suite *) pTmp;
4468				if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
4469					break;
4470
4471				switch (pAKM->Type) {
4472				case 1:
4473					/* Set AP support WPA-enterprise mode */
4474					if (pBss->AuthMode ==
4475					    Ndis802_11AuthModeOpen)
4476						pBss->AuthMode =
4477						    Ndis802_11AuthModeWPA2;
4478					else
4479						pBss->AuthModeAux =
4480						    Ndis802_11AuthModeWPA2;
4481					break;
4482				case 2:
4483					/* Set AP support WPA-PSK mode */
4484					if (pBss->AuthMode ==
4485					    Ndis802_11AuthModeOpen)
4486						pBss->AuthMode =
4487						    Ndis802_11AuthModeWPA2PSK;
4488					else
4489						pBss->AuthModeAux =
4490						    Ndis802_11AuthModeWPA2PSK;
4491					break;
4492				default:
4493					if (pBss->AuthMode ==
4494					    Ndis802_11AuthModeOpen)
4495						pBss->AuthMode =
4496						    Ndis802_11AuthModeMax;
4497					else
4498						pBss->AuthModeAux =
4499						    Ndis802_11AuthModeMax;
4500					break;
4501				}
4502				pTmp += (Count * sizeof(struct rt_akm_suite));
4503				Count--;
4504			}
4505
4506			/* Fixed for WPA-None */
4507			if (pBss->BssType == BSS_ADHOC) {
4508				pBss->AuthMode = Ndis802_11AuthModeWPANone;
4509				pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
4510				pBss->WPA.PairCipherAux =
4511				    pBss->WPA2.PairCipherAux;
4512				pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher;
4513				pBss->WepStatus = pBss->WPA.GroupCipher;
4514				/* Patched bugs for old driver */
4515				if (pBss->WPA.PairCipherAux ==
4516				    Ndis802_11WEPDisabled)
4517					pBss->WPA.PairCipherAux =
4518					    pBss->WPA.GroupCipher;
4519			}
4520			pBss->WepStatus = pBss->WPA2.PairCipher;
4521
4522			/* 6. Get RSN capability */
4523			/*pBss->WPA2.RsnCapability = *(u16 *)pTmp; */
4524			pBss->WPA2.RsnCapability = (pTmp[1] << 8) + pTmp[0];
4525			pTmp += sizeof(u16);
4526
4527			/* Check the Pair & Group, if different, turn on mixed mode flag */
4528			if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher)
4529				pBss->WPA2.bMixMode = TRUE;
4530
4531			break;
4532		default:
4533			break;
4534		}
4535		Length -= (pEid->Len + 2);
4536	}
4537}
4538
4539/* =========================================================================================== */
4540/* mac_table.c */
4541/* =========================================================================================== */
4542
4543/*! \brief generates a random mac address value for IBSS BSSID
4544 *	\param Addr the bssid location
4545 *	\return none
4546 *	\pre
4547 *	\post
4548 */
4549void MacAddrRandomBssid(struct rt_rtmp_adapter *pAd, u8 *pAddr)
4550{
4551	int i;
4552
4553	for (i = 0; i < MAC_ADDR_LEN; i++) {
4554		pAddr[i] = RandomByte(pAd);
4555	}
4556
4557	pAddr[0] = (pAddr[0] & 0xfe) | 0x02;	/* the first 2 bits must be 01xxxxxxxx */
4558}
4559
4560/*! \brief init the management mac frame header
4561 *	\param p_hdr mac header
4562 *	\param subtype subtype of the frame
4563 *	\param p_ds destination address, don't care if it is a broadcast address
4564 *	\return none
4565 *	\pre the station has the following information in the pAd->StaCfg
4566 *	 - bssid
4567 *	 - station address
4568 *	\post
4569 *	\note this function initializes the following field
4570
4571	IRQL = PASSIVE_LEVEL
4572	IRQL = DISPATCH_LEVEL
4573
4574 */
4575void MgtMacHeaderInit(struct rt_rtmp_adapter *pAd,
4576		      struct rt_header_802_11 * pHdr80211,
4577		      u8 SubType,
4578		      u8 ToDs, u8 *pDA, u8 *pBssid)
4579{
4580	NdisZeroMemory(pHdr80211, sizeof(struct rt_header_802_11));
4581
4582	pHdr80211->FC.Type = BTYPE_MGMT;
4583	pHdr80211->FC.SubType = SubType;
4584/*      if (SubType == SUBTYPE_ACK)     // sample, no use, it will conflict with ACTION frame sub type */
4585/*              pHdr80211->FC.Type = BTYPE_CNTL; */
4586	pHdr80211->FC.ToDs = ToDs;
4587	COPY_MAC_ADDR(pHdr80211->Addr1, pDA);
4588	COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);
4589	COPY_MAC_ADDR(pHdr80211->Addr3, pBssid);
4590}
4591
4592/* =========================================================================================== */
4593/* mem_mgmt.c */
4594/* =========================================================================================== */
4595
4596/*!***************************************************************************
4597 * This routine build an outgoing frame, and fill all information specified
4598 * in argument list to the frame body. The actual frame size is the summation
4599 * of all arguments.
4600 * input params:
4601 *		Buffer - pointer to a pre-allocated memory segment
4602 *		args - a list of <int arg_size, arg> pairs.
4603 *		NOTE NOTE NOTE! the last argument must be NULL, otherwise this
4604 *						   function will FAIL!
4605 * return:
4606 *		Size of the buffer
4607 * usage:
4608 *		MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);
4609
4610 IRQL = PASSIVE_LEVEL
4611	IRQL = DISPATCH_LEVEL
4612
4613 ****************************************************************************/
4614unsigned long MakeOutgoingFrame(u8 * Buffer, unsigned long * FrameLen, ...)
4615{
4616	u8 *p;
4617	int leng;
4618	unsigned long TotLeng;
4619	va_list Args;
4620
4621	/* calculates the total length */
4622	TotLeng = 0;
4623	va_start(Args, FrameLen);
4624	do {
4625		leng = va_arg(Args, int);
4626		if (leng == END_OF_ARGS) {
4627			break;
4628		}
4629		p = va_arg(Args, void *);
4630		NdisMoveMemory(&Buffer[TotLeng], p, leng);
4631		TotLeng = TotLeng + leng;
4632	} while (TRUE);
4633
4634	va_end(Args);		/* clean up */
4635	*FrameLen = TotLeng;
4636	return TotLeng;
4637}
4638
4639/* =========================================================================================== */
4640/* mlme_queue.c */
4641/* =========================================================================================== */
4642
4643/*! \brief	Initialize The MLME Queue, used by MLME Functions
4644 *	\param	*Queue	   The MLME Queue
4645 *	\return Always	   Return NDIS_STATE_SUCCESS in this implementation
4646 *	\pre
4647 *	\post
4648 *	\note	Because this is done only once (at the init stage), no need to be locked
4649
4650 IRQL = PASSIVE_LEVEL
4651
4652 */
4653int MlmeQueueInit(struct rt_mlme_queue *Queue)
4654{
4655	int i;
4656
4657	NdisAllocateSpinLock(&Queue->Lock);
4658
4659	Queue->Num = 0;
4660	Queue->Head = 0;
4661	Queue->Tail = 0;
4662
4663	for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) {
4664		Queue->Entry[i].Occupied = FALSE;
4665		Queue->Entry[i].MsgLen = 0;
4666		NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE);
4667	}
4668
4669	return NDIS_STATUS_SUCCESS;
4670}
4671
4672/*! \brief	 Enqueue a message for other threads, if they want to send messages to MLME thread
4673 *	\param	*Queue	  The MLME Queue
4674 *	\param	 Machine  The State Machine Id
4675 *	\param	 MsgType  The Message Type
4676 *	\param	 MsgLen   The Message length
4677 *	\param	*Msg	  The message pointer
4678 *	\return  TRUE if enqueue is successful, FALSE if the queue is full
4679 *	\pre
4680 *	\post
4681 *	\note	 The message has to be initialized
4682
4683	IRQL = PASSIVE_LEVEL
4684	IRQL = DISPATCH_LEVEL
4685
4686 */
4687BOOLEAN MlmeEnqueue(struct rt_rtmp_adapter *pAd,
4688		    unsigned long Machine,
4689		    unsigned long MsgType, unsigned long MsgLen, void * Msg)
4690{
4691	int Tail;
4692	struct rt_mlme_queue *Queue = (struct rt_mlme_queue *)& pAd->Mlme.Queue;
4693
4694	/* Do nothing if the driver is starting halt state. */
4695	/* This might happen when timer already been fired before cancel timer with mlmehalt */
4696	if (RTMP_TEST_FLAG
4697	    (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
4698		return FALSE;
4699
4700	/* First check the size, it MUST not exceed the mlme queue size */
4701	if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
4702		DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n",
4703			      MsgLen));
4704		return FALSE;
4705	}
4706
4707	if (MlmeQueueFull(Queue)) {
4708		return FALSE;
4709	}
4710
4711	NdisAcquireSpinLock(&(Queue->Lock));
4712	Tail = Queue->Tail;
4713	Queue->Tail++;
4714	Queue->Num++;
4715	if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) {
4716		Queue->Tail = 0;
4717	}
4718
4719	Queue->Entry[Tail].Wcid = RESERVED_WCID;
4720	Queue->Entry[Tail].Occupied = TRUE;
4721	Queue->Entry[Tail].Machine = Machine;
4722	Queue->Entry[Tail].MsgType = MsgType;
4723	Queue->Entry[Tail].MsgLen = MsgLen;
4724
4725	if (Msg != NULL) {
4726		NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4727	}
4728
4729	NdisReleaseSpinLock(&(Queue->Lock));
4730	return TRUE;
4731}
4732
4733/*! \brief	 This function is used when Recv gets a MLME message
4734 *	\param	*Queue			 The MLME Queue
4735 *	\param	 TimeStampHigh	 The upper 32 bit of timestamp
4736 *	\param	 TimeStampLow	 The lower 32 bit of timestamp
4737 *	\param	 Rssi			 The receiving RSSI strength
4738 *	\param	 MsgLen			 The length of the message
4739 *	\param	*Msg			 The message pointer
4740 *	\return  TRUE if everything ok, FALSE otherwise (like Queue Full)
4741 *	\pre
4742 *	\post
4743
4744 IRQL = DISPATCH_LEVEL
4745
4746 */
4747BOOLEAN MlmeEnqueueForRecv(struct rt_rtmp_adapter *pAd,
4748			   unsigned long Wcid,
4749			   unsigned long TimeStampHigh,
4750			   unsigned long TimeStampLow,
4751			   u8 Rssi0,
4752			   u8 Rssi1,
4753			   u8 Rssi2,
4754			   unsigned long MsgLen, void * Msg, u8 Signal)
4755{
4756	int Tail, Machine;
4757	struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) Msg;
4758	int MsgType;
4759	struct rt_mlme_queue *Queue = (struct rt_mlme_queue *)& pAd->Mlme.Queue;
4760
4761	/* Do nothing if the driver is starting halt state. */
4762	/* This might happen when timer already been fired before cancel timer with mlmehalt */
4763	if (RTMP_TEST_FLAG
4764	    (pAd,
4765	     fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) {
4766		DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n"));
4767		return FALSE;
4768	}
4769	/* First check the size, it MUST not exceed the mlme queue size */
4770	if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
4771		DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
4772		return FALSE;
4773	}
4774
4775	if (MlmeQueueFull(Queue)) {
4776		return FALSE;
4777	}
4778
4779	{
4780		if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) {
4781			DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType));
4782			return FALSE;
4783		}
4784	}
4785
4786	/* OK, we got all the informations, it is time to put things into queue */
4787	NdisAcquireSpinLock(&(Queue->Lock));
4788	Tail = Queue->Tail;
4789	Queue->Tail++;
4790	Queue->Num++;
4791	if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) {
4792		Queue->Tail = 0;
4793	}
4794	Queue->Entry[Tail].Occupied = TRUE;
4795	Queue->Entry[Tail].Machine = Machine;
4796	Queue->Entry[Tail].MsgType = MsgType;
4797	Queue->Entry[Tail].MsgLen = MsgLen;
4798	Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow;
4799	Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh;
4800	Queue->Entry[Tail].Rssi0 = Rssi0;
4801	Queue->Entry[Tail].Rssi1 = Rssi1;
4802	Queue->Entry[Tail].Rssi2 = Rssi2;
4803	Queue->Entry[Tail].Signal = Signal;
4804	Queue->Entry[Tail].Wcid = (u8)Wcid;
4805
4806	Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel;
4807
4808	if (Msg != NULL) {
4809		NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4810	}
4811
4812	NdisReleaseSpinLock(&(Queue->Lock));
4813
4814	RTMP_MLME_HANDLER(pAd);
4815
4816	return TRUE;
4817}
4818
4819/*! \brief	 Dequeue a message from the MLME Queue
4820 *	\param	*Queue	  The MLME Queue
4821 *	\param	*Elem	  The message dequeued from MLME Queue
4822 *	\return  TRUE if the Elem contains something, FALSE otherwise
4823 *	\pre
4824 *	\post
4825
4826 IRQL = DISPATCH_LEVEL
4827
4828 */
4829BOOLEAN MlmeDequeue(struct rt_mlme_queue *Queue, struct rt_mlme_queue_elem ** Elem)
4830{
4831	NdisAcquireSpinLock(&(Queue->Lock));
4832	*Elem = &(Queue->Entry[Queue->Head]);
4833	Queue->Num--;
4834	Queue->Head++;
4835	if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) {
4836		Queue->Head = 0;
4837	}
4838	NdisReleaseSpinLock(&(Queue->Lock));
4839	return TRUE;
4840}
4841
4842/* IRQL = DISPATCH_LEVEL */
4843void MlmeRestartStateMachine(struct rt_rtmp_adapter *pAd)
4844{
4845#ifdef RTMP_MAC_PCI
4846	struct rt_mlme_queue_elem *Elem = NULL;
4847#endif /* RTMP_MAC_PCI // */
4848	BOOLEAN Cancelled;
4849
4850	DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n"));
4851
4852#ifdef RTMP_MAC_PCI
4853	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
4854	if (pAd->Mlme.bRunning) {
4855		NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4856		return;
4857	} else {
4858		pAd->Mlme.bRunning = TRUE;
4859	}
4860	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4861
4862	/* Remove all Mlme queues elements */
4863	while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) {
4864		/*From message type, determine which state machine I should drive */
4865		if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) {
4866			/* free MLME element */
4867			Elem->Occupied = FALSE;
4868			Elem->MsgLen = 0;
4869
4870		} else {
4871			DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n"));
4872		}
4873	}
4874#endif /* RTMP_MAC_PCI // */
4875
4876	{
4877		/* Cancel all timer events */
4878		/* Be careful to cancel new added timer */
4879		RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled);
4880		RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled);
4881		RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled);
4882		RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled);
4883		RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled);
4884		RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
4885
4886	}
4887
4888	/* Change back to original channel in case of doing scan */
4889	AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
4890	AsicLockChannel(pAd, pAd->CommonCfg.Channel);
4891
4892	/* Resume MSDU which is turned off durning scan */
4893	RTMPResumeMsduTransmission(pAd);
4894
4895	{
4896		/* Set all state machines back IDLE */
4897		pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
4898		pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
4899		pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
4900		pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
4901		pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
4902		pAd->Mlme.ActMachine.CurrState = ACT_IDLE;
4903	}
4904
4905#ifdef RTMP_MAC_PCI
4906	/* Remove running state */
4907	NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
4908	pAd->Mlme.bRunning = FALSE;
4909	NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4910#endif /* RTMP_MAC_PCI // */
4911}
4912
4913/*! \brief	test if the MLME Queue is empty
4914 *	\param	*Queue	  The MLME Queue
4915 *	\return TRUE if the Queue is empty, FALSE otherwise
4916 *	\pre
4917 *	\post
4918
4919 IRQL = DISPATCH_LEVEL
4920
4921 */
4922BOOLEAN MlmeQueueEmpty(struct rt_mlme_queue *Queue)
4923{
4924	BOOLEAN Ans;
4925
4926	NdisAcquireSpinLock(&(Queue->Lock));
4927	Ans = (Queue->Num == 0);
4928	NdisReleaseSpinLock(&(Queue->Lock));
4929
4930	return Ans;
4931}
4932
4933/*! \brief	 test if the MLME Queue is full
4934 *	\param	 *Queue		 The MLME Queue
4935 *	\return  TRUE if the Queue is empty, FALSE otherwise
4936 *	\pre
4937 *	\post
4938
4939 IRQL = PASSIVE_LEVEL
4940 IRQL = DISPATCH_LEVEL
4941
4942 */
4943BOOLEAN MlmeQueueFull(struct rt_mlme_queue *Queue)
4944{
4945	BOOLEAN Ans;
4946
4947	NdisAcquireSpinLock(&(Queue->Lock));
4948	Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE
4949	       || Queue->Entry[Queue->Tail].Occupied);
4950	NdisReleaseSpinLock(&(Queue->Lock));
4951
4952	return Ans;
4953}
4954
4955/*! \brief	 The destructor of MLME Queue
4956 *	\param
4957 *	\return
4958 *	\pre
4959 *	\post
4960 *	\note	Clear Mlme Queue, Set Queue->Num to Zero.
4961
4962 IRQL = PASSIVE_LEVEL
4963
4964 */
4965void MlmeQueueDestroy(struct rt_mlme_queue *pQueue)
4966{
4967	NdisAcquireSpinLock(&(pQueue->Lock));
4968	pQueue->Num = 0;
4969	pQueue->Head = 0;
4970	pQueue->Tail = 0;
4971	NdisReleaseSpinLock(&(pQueue->Lock));
4972	NdisFreeSpinLock(&(pQueue->Lock));
4973}
4974
4975/*! \brief	 To substitute the message type if the message is coming from external
4976 *	\param	pFrame		   The frame received
4977 *	\param	*Machine	   The state machine
4978 *	\param	*MsgType	   the message type for the state machine
4979 *	\return TRUE if the substitution is successful, FALSE otherwise
4980 *	\pre
4981 *	\post
4982
4983 IRQL = DISPATCH_LEVEL
4984
4985 */
4986BOOLEAN MsgTypeSubst(struct rt_rtmp_adapter *pAd,
4987		     struct rt_frame_802_11 * pFrame,
4988		     int * Machine, int * MsgType)
4989{
4990	u16 Seq, Alg;
4991	u8 EAPType;
4992	u8 *pData;
4993
4994	/* Pointer to start of data frames including SNAP header */
4995	pData = (u8 *)pFrame + LENGTH_802_11;
4996
4997	/* The only data type will pass to this function is EAPOL frame */
4998	if (pFrame->Hdr.FC.Type == BTYPE_DATA) {
4999		{
5000			*Machine = WPA_STATE_MACHINE;
5001			EAPType =
5002			    *((u8 *) pFrame + LENGTH_802_11 +
5003			      LENGTH_802_1_H + 1);
5004			return (WpaMsgTypeSubst(EAPType, (int *) MsgType));
5005		}
5006	}
5007
5008	switch (pFrame->Hdr.FC.SubType) {
5009	case SUBTYPE_ASSOC_REQ:
5010		*Machine = ASSOC_STATE_MACHINE;
5011		*MsgType = MT2_PEER_ASSOC_REQ;
5012		break;
5013	case SUBTYPE_ASSOC_RSP:
5014		*Machine = ASSOC_STATE_MACHINE;
5015		*MsgType = MT2_PEER_ASSOC_RSP;
5016		break;
5017	case SUBTYPE_REASSOC_REQ:
5018		*Machine = ASSOC_STATE_MACHINE;
5019		*MsgType = MT2_PEER_REASSOC_REQ;
5020		break;
5021	case SUBTYPE_REASSOC_RSP:
5022		*Machine = ASSOC_STATE_MACHINE;
5023		*MsgType = MT2_PEER_REASSOC_RSP;
5024		break;
5025	case SUBTYPE_PROBE_REQ:
5026		*Machine = SYNC_STATE_MACHINE;
5027		*MsgType = MT2_PEER_PROBE_REQ;
5028		break;
5029	case SUBTYPE_PROBE_RSP:
5030		*Machine = SYNC_STATE_MACHINE;
5031		*MsgType = MT2_PEER_PROBE_RSP;
5032		break;
5033	case SUBTYPE_BEACON:
5034		*Machine = SYNC_STATE_MACHINE;
5035		*MsgType = MT2_PEER_BEACON;
5036		break;
5037	case SUBTYPE_ATIM:
5038		*Machine = SYNC_STATE_MACHINE;
5039		*MsgType = MT2_PEER_ATIM;
5040		break;
5041	case SUBTYPE_DISASSOC:
5042		*Machine = ASSOC_STATE_MACHINE;
5043		*MsgType = MT2_PEER_DISASSOC_REQ;
5044		break;
5045	case SUBTYPE_AUTH:
5046		/* get the sequence number from payload 24 Mac Header + 2 bytes algorithm */
5047		NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(u16));
5048		NdisMoveMemory(&Alg, &pFrame->Octet[0], sizeof(u16));
5049		if (Seq == 1 || Seq == 3) {
5050			*Machine = AUTH_RSP_STATE_MACHINE;
5051			*MsgType = MT2_PEER_AUTH_ODD;
5052		} else if (Seq == 2 || Seq == 4) {
5053			if (Alg == AUTH_MODE_OPEN || Alg == AUTH_MODE_KEY) {
5054				*Machine = AUTH_STATE_MACHINE;
5055				*MsgType = MT2_PEER_AUTH_EVEN;
5056			}
5057		} else {
5058			return FALSE;
5059		}
5060		break;
5061	case SUBTYPE_DEAUTH:
5062		*Machine = AUTH_RSP_STATE_MACHINE;
5063		*MsgType = MT2_PEER_DEAUTH;
5064		break;
5065	case SUBTYPE_ACTION:
5066		*Machine = ACTION_STATE_MACHINE;
5067		/*  Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support */
5068		if ((pFrame->Octet[0] & 0x7F) > MAX_PEER_CATE_MSG) {
5069			*MsgType = MT2_ACT_INVALID;
5070		} else {
5071			*MsgType = (pFrame->Octet[0] & 0x7F);
5072		}
5073		break;
5074	default:
5075		return FALSE;
5076		break;
5077	}
5078
5079	return TRUE;
5080}
5081
5082/* =========================================================================================== */
5083/* state_machine.c */
5084/* =========================================================================================== */
5085
5086/*! \brief Initialize the state machine.
5087 *	\param *S			pointer to the state machine
5088 *	\param	Trans		State machine transition function
5089 *	\param	StNr		number of states
5090 *	\param	MsgNr		number of messages
5091 *	\param	DefFunc		default function, when there is invalid state/message combination
5092 *	\param	InitState	initial state of the state machine
5093 *	\param	Base		StateMachine base, internal use only
5094 *	\pre p_sm should be a legal pointer
5095 *	\post
5096
5097 IRQL = PASSIVE_LEVEL
5098
5099 */
5100void StateMachineInit(struct rt_state_machine *S,
5101		      IN STATE_MACHINE_FUNC Trans[],
5102		      unsigned long StNr,
5103		      unsigned long MsgNr,
5104		      IN STATE_MACHINE_FUNC DefFunc,
5105		      unsigned long InitState, unsigned long Base)
5106{
5107	unsigned long i, j;
5108
5109	/* set number of states and messages */
5110	S->NrState = StNr;
5111	S->NrMsg = MsgNr;
5112	S->Base = Base;
5113
5114	S->TransFunc = Trans;
5115
5116	/* init all state transition to default function */
5117	for (i = 0; i < StNr; i++) {
5118		for (j = 0; j < MsgNr; j++) {
5119			S->TransFunc[i * MsgNr + j] = DefFunc;
5120		}
5121	}
5122
5123	/* set the starting state */
5124	S->CurrState = InitState;
5125}
5126
5127/*! \brief This function fills in the function pointer into the cell in the state machine
5128 *	\param *S	pointer to the state machine
5129 *	\param St	state
5130 *	\param Msg	incoming message
5131 *	\param f	the function to be executed when (state, message) combination occurs at the state machine
5132 *	\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
5133 *	\post
5134
5135 IRQL = PASSIVE_LEVEL
5136
5137 */
5138void StateMachineSetAction(struct rt_state_machine *S,
5139			   unsigned long St,
5140			   unsigned long Msg, IN STATE_MACHINE_FUNC Func)
5141{
5142	unsigned long MsgIdx;
5143
5144	MsgIdx = Msg - S->Base;
5145
5146	if (St < S->NrState && MsgIdx < S->NrMsg) {
5147		/* boundary checking before setting the action */
5148		S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
5149	}
5150}
5151
5152/*! \brief	 This function does the state transition
5153 *	\param	 *Adapter the NIC adapter pointer
5154 *	\param	 *S	  the state machine
5155 *	\param	 *Elem	  the message to be executed
5156 *	\return   None
5157
5158 IRQL = DISPATCH_LEVEL
5159
5160 */
5161void StateMachinePerformAction(struct rt_rtmp_adapter *pAd,
5162			       struct rt_state_machine *S, struct rt_mlme_queue_elem *Elem)
5163{
5164	(*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))
5165	    (pAd, Elem);
5166}
5167
5168/*
5169	==========================================================================
5170	Description:
5171		The drop function, when machine executes this, the message is simply
5172		ignored. This function does nothing, the message is freed in
5173		StateMachinePerformAction()
5174	==========================================================================
5175 */
5176void Drop(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
5177{
5178}
5179
5180/* =========================================================================================== */
5181/* lfsr.c */
5182/* =========================================================================================== */
5183
5184/*
5185	==========================================================================
5186	Description:
5187
5188	IRQL = PASSIVE_LEVEL
5189
5190	==========================================================================
5191 */
5192void LfsrInit(struct rt_rtmp_adapter *pAd, unsigned long Seed)
5193{
5194	if (Seed == 0)
5195		pAd->Mlme.ShiftReg = 1;
5196	else
5197		pAd->Mlme.ShiftReg = Seed;
5198}
5199
5200/*
5201	==========================================================================
5202	Description:
5203	==========================================================================
5204 */
5205u8 RandomByte(struct rt_rtmp_adapter *pAd)
5206{
5207	unsigned long i;
5208	u8 R, Result;
5209
5210	R = 0;
5211
5212	if (pAd->Mlme.ShiftReg == 0)
5213		NdisGetSystemUpTime((unsigned long *) & pAd->Mlme.ShiftReg);
5214
5215	for (i = 0; i < 8; i++) {
5216		if (pAd->Mlme.ShiftReg & 0x00000001) {
5217			pAd->Mlme.ShiftReg =
5218			    ((pAd->Mlme.
5219			      ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000;
5220			Result = 1;
5221		} else {
5222			pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1;
5223			Result = 0;
5224		}
5225		R = (R << 1) | Result;
5226	}
5227
5228	return R;
5229}
5230
5231/*
5232	========================================================================
5233
5234	Routine Description:
5235		Verify the support rate for different PHY type
5236
5237	Arguments:
5238		pAd 				Pointer to our adapter
5239
5240	Return Value:
5241		None
5242
5243	IRQL = PASSIVE_LEVEL
5244
5245	========================================================================
5246*/
5247void RTMPCheckRates(struct rt_rtmp_adapter *pAd,
5248		    IN u8 SupRate[], IN u8 * SupRateLen)
5249{
5250	u8 RateIdx, i, j;
5251	u8 NewRate[12], NewRateLen;
5252
5253	NewRateLen = 0;
5254
5255	if (pAd->CommonCfg.PhyMode == PHY_11B)
5256		RateIdx = 4;
5257	else
5258		RateIdx = 12;
5259
5260	/* Check for support rates exclude basic rate bit */
5261	for (i = 0; i < *SupRateLen; i++)
5262		for (j = 0; j < RateIdx; j++)
5263			if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j])
5264				NewRate[NewRateLen++] = SupRate[i];
5265
5266	*SupRateLen = NewRateLen;
5267	NdisMoveMemory(SupRate, NewRate, NewRateLen);
5268}
5269
5270BOOLEAN RTMPCheckChannel(struct rt_rtmp_adapter *pAd,
5271			 u8 CentralChannel, u8 Channel)
5272{
5273	u8 k;
5274	u8 UpperChannel = 0, LowerChannel = 0;
5275	u8 NoEffectChannelinList = 0;
5276
5277	/* Find upper and lower channel according to 40MHz current operation. */
5278	if (CentralChannel < Channel) {
5279		UpperChannel = Channel;
5280		if (CentralChannel > 2)
5281			LowerChannel = CentralChannel - 2;
5282		else
5283			return FALSE;
5284	} else if (CentralChannel > Channel) {
5285		UpperChannel = CentralChannel + 2;
5286		LowerChannel = Channel;
5287	}
5288
5289	for (k = 0; k < pAd->ChannelListNum; k++) {
5290		if (pAd->ChannelList[k].Channel == UpperChannel) {
5291			NoEffectChannelinList++;
5292		}
5293		if (pAd->ChannelList[k].Channel == LowerChannel) {
5294			NoEffectChannelinList++;
5295		}
5296	}
5297
5298	DBGPRINT(RT_DEBUG_TRACE,
5299		 ("Total Channel in Channel List = [%d]\n",
5300		  NoEffectChannelinList));
5301	if (NoEffectChannelinList == 2)
5302		return TRUE;
5303	else
5304		return FALSE;
5305}
5306
5307/*
5308	========================================================================
5309
5310	Routine Description:
5311		Verify the support rate for HT phy type
5312
5313	Arguments:
5314		pAd 				Pointer to our adapter
5315
5316	Return Value:
5317		FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability.  (AP Mode)
5318
5319	IRQL = PASSIVE_LEVEL
5320
5321	========================================================================
5322*/
5323BOOLEAN RTMPCheckHt(struct rt_rtmp_adapter *pAd,
5324		    u8 Wcid,
5325		    struct rt_ht_capability_ie * pHtCapability,
5326		    struct rt_add_ht_info_ie * pAddHtInfo)
5327{
5328	if (Wcid >= MAX_LEN_OF_MAC_TABLE)
5329		return FALSE;
5330
5331	/* If use AMSDU, set flag. */
5332	if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable)
5333		CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5334				       fCLIENT_STATUS_AMSDU_INUSED);
5335	/* Save Peer Capability */
5336	if (pHtCapability->HtCapInfo.ShortGIfor20)
5337		CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5338				       fCLIENT_STATUS_SGI20_CAPABLE);
5339	if (pHtCapability->HtCapInfo.ShortGIfor40)
5340		CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5341				       fCLIENT_STATUS_SGI40_CAPABLE);
5342	if (pHtCapability->HtCapInfo.TxSTBC)
5343		CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5344				       fCLIENT_STATUS_TxSTBC_CAPABLE);
5345	if (pHtCapability->HtCapInfo.RxSTBC)
5346		CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5347				       fCLIENT_STATUS_RxSTBC_CAPABLE);
5348	if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) {
5349		CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5350				       fCLIENT_STATUS_RDG_CAPABLE);
5351	}
5352
5353	if (Wcid < MAX_LEN_OF_MAC_TABLE) {
5354		pAd->MacTab.Content[Wcid].MpduDensity =
5355		    pHtCapability->HtCapParm.MpduDensity;
5356	}
5357	/* Will check ChannelWidth for MCSSet[4] below */
5358	pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1;
5359	switch (pAd->CommonCfg.RxStream) {
5360	case 1:
5361		pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5362		pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00;
5363		pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
5364		pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5365		break;
5366	case 2:
5367		pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5368		pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
5369		pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
5370		pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5371		break;
5372	case 3:
5373		pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5374		pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
5375		pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff;
5376		pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5377		break;
5378	}
5379
5380	pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth =
5381	    pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.
5382	    ChannelWidth;
5383
5384	DBGPRINT(RT_DEBUG_TRACE,
5385		 ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n",
5386		  pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth,
5387		  pAddHtInfo->AddHtInfo.RecomWidth,
5388		  pAd->CommonCfg.DesiredHtPhy.ChannelWidth,
5389		  pAd->NicConfig2.field.BW40MAvailForA,
5390		  pAd->NicConfig2.field.BW40MAvailForG,
5391		  pAd->CommonCfg.PhyMode));
5392
5393	pAd->MlmeAux.HtCapability.HtCapInfo.GF =
5394	    pHtCapability->HtCapInfo.GF & pAd->CommonCfg.DesiredHtPhy.GF;
5395
5396	/* Send Assoc Req with my HT capability. */
5397	pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize =
5398	    pAd->CommonCfg.DesiredHtPhy.AmsduSize;
5399	pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs =
5400	    pAd->CommonCfg.DesiredHtPhy.MimoPs;
5401	pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 =
5402	    (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->
5403							  HtCapInfo.
5404							  ShortGIfor20);
5405	pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 =
5406	    (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->
5407							  HtCapInfo.
5408							  ShortGIfor40);
5409	pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC =
5410	    (pAd->CommonCfg.DesiredHtPhy.TxSTBC) & (pHtCapability->HtCapInfo.
5411						    RxSTBC);
5412	pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC =
5413	    (pAd->CommonCfg.DesiredHtPhy.RxSTBC) & (pHtCapability->HtCapInfo.
5414						    TxSTBC);
5415	pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor =
5416	    pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor;
5417	pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity =
5418	    pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity;
5419	pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC =
5420	    pHtCapability->ExtHtCapInfo.PlusHTC;
5421	pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC =
5422	    pHtCapability->ExtHtCapInfo.PlusHTC;
5423	if (pAd->CommonCfg.bRdg) {
5424		pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport =
5425		    pHtCapability->ExtHtCapInfo.RDGSupport;
5426		pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1;
5427	}
5428
5429	if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20)
5430		pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0;	/* BW20 can't transmit MCS32 */
5431
5432	COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability);
5433	return TRUE;
5434}
5435
5436/*
5437	========================================================================
5438
5439	Routine Description:
5440		Verify the support rate for different PHY type
5441
5442	Arguments:
5443		pAd 				Pointer to our adapter
5444
5445	Return Value:
5446		None
5447
5448	IRQL = PASSIVE_LEVEL
5449
5450	========================================================================
5451*/
5452void RTMPUpdateMlmeRate(struct rt_rtmp_adapter *pAd)
5453{
5454	u8 MinimumRate;
5455	u8 ProperMlmeRate;	/*= RATE_54; */
5456	u8 i, j, RateIdx = 12;	/*1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */
5457	BOOLEAN bMatch = FALSE;
5458
5459	switch (pAd->CommonCfg.PhyMode) {
5460	case PHY_11B:
5461		ProperMlmeRate = RATE_11;
5462		MinimumRate = RATE_1;
5463		break;
5464	case PHY_11BG_MIXED:
5465	case PHY_11ABGN_MIXED:
5466	case PHY_11BGN_MIXED:
5467		if ((pAd->MlmeAux.SupRateLen == 4) &&
5468		    (pAd->MlmeAux.ExtRateLen == 0))
5469			/* B only AP */
5470			ProperMlmeRate = RATE_11;
5471		else
5472			ProperMlmeRate = RATE_24;
5473
5474		if (pAd->MlmeAux.Channel <= 14)
5475			MinimumRate = RATE_1;
5476		else
5477			MinimumRate = RATE_6;
5478		break;
5479	case PHY_11A:
5480	case PHY_11N_2_4G:	/* rt2860 need to check mlmerate for 802.11n */
5481	case PHY_11GN_MIXED:
5482	case PHY_11AGN_MIXED:
5483	case PHY_11AN_MIXED:
5484	case PHY_11N_5G:
5485		ProperMlmeRate = RATE_24;
5486		MinimumRate = RATE_6;
5487		break;
5488	case PHY_11ABG_MIXED:
5489		ProperMlmeRate = RATE_24;
5490		if (pAd->MlmeAux.Channel <= 14)
5491			MinimumRate = RATE_1;
5492		else
5493			MinimumRate = RATE_6;
5494		break;
5495	default:		/* error */
5496		ProperMlmeRate = RATE_1;
5497		MinimumRate = RATE_1;
5498		break;
5499	}
5500
5501	for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) {
5502		for (j = 0; j < RateIdx; j++) {
5503			if ((pAd->MlmeAux.SupRate[i] & 0x7f) ==
5504			    RateIdTo500Kbps[j]) {
5505				if (j == ProperMlmeRate) {
5506					bMatch = TRUE;
5507					break;
5508				}
5509			}
5510		}
5511
5512		if (bMatch)
5513			break;
5514	}
5515
5516	if (bMatch == FALSE) {
5517		for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) {
5518			for (j = 0; j < RateIdx; j++) {
5519				if ((pAd->MlmeAux.ExtRate[i] & 0x7f) ==
5520				    RateIdTo500Kbps[j]) {
5521					if (j == ProperMlmeRate) {
5522						bMatch = TRUE;
5523						break;
5524					}
5525				}
5526			}
5527
5528			if (bMatch)
5529				break;
5530		}
5531	}
5532
5533	if (bMatch == FALSE) {
5534		ProperMlmeRate = MinimumRate;
5535	}
5536
5537	pAd->CommonCfg.MlmeRate = MinimumRate;
5538	pAd->CommonCfg.RtsRate = ProperMlmeRate;
5539	if (pAd->CommonCfg.MlmeRate >= RATE_6) {
5540		pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
5541		pAd->CommonCfg.MlmeTransmit.field.MCS =
5542		    OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
5543		pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE =
5544		    MODE_OFDM;
5545		pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS =
5546		    OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
5547	} else {
5548		pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
5549		pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate;
5550		pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE =
5551		    MODE_CCK;
5552		pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS =
5553		    pAd->CommonCfg.MlmeRate;
5554	}
5555
5556	DBGPRINT(RT_DEBUG_TRACE,
5557		 ("RTMPUpdateMlmeRate ==>   MlmeTransmit = 0x%x  \n",
5558		  pAd->CommonCfg.MlmeTransmit.word));
5559}
5560
5561char RTMPMaxRssi(struct rt_rtmp_adapter *pAd,
5562		 char Rssi0, char Rssi1, char Rssi2)
5563{
5564	char larger = -127;
5565
5566	if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) {
5567		larger = Rssi0;
5568	}
5569
5570	if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) {
5571		larger = max(Rssi0, Rssi1);
5572	}
5573
5574	if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) {
5575		larger = max(larger, Rssi2);
5576	}
5577
5578	if (larger == -127)
5579		larger = 0;
5580
5581	return larger;
5582}
5583
5584/*
5585    ========================================================================
5586    Routine Description:
5587        Periodic evaluate antenna link status
5588
5589    Arguments:
5590        pAd         - Adapter pointer
5591
5592    Return Value:
5593        None
5594
5595    ========================================================================
5596*/
5597void AsicEvaluateRxAnt(struct rt_rtmp_adapter *pAd)
5598{
5599	u8 BBPR3 = 0;
5600
5601	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
5602			   fRTMP_ADAPTER_HALT_IN_PROGRESS |
5603			   fRTMP_ADAPTER_RADIO_OFF |
5604			   fRTMP_ADAPTER_NIC_NOT_EXIST |
5605			   fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) ||
5606	    OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
5607#ifdef RT30xx
5608	    || (pAd->EepromAccess)
5609#endif /* RT30xx // */
5610#ifdef RT3090
5611	    || (pAd->bPCIclkOff == TRUE)
5612#endif /* RT3090 // */
5613	    )
5614		return;
5615
5616	{
5617		/*if (pAd->StaCfg.Psm == PWR_SAVE) */
5618		/*      return; */
5619
5620		{
5621
5622			if (pAd->StaCfg.Psm == PWR_SAVE)
5623				return;
5624
5625			RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
5626			BBPR3 &= (~0x18);
5627			if (pAd->Antenna.field.RxPath == 3) {
5628				BBPR3 |= (0x10);
5629			} else if (pAd->Antenna.field.RxPath == 2) {
5630				BBPR3 |= (0x8);
5631			} else if (pAd->Antenna.field.RxPath == 1) {
5632				BBPR3 |= (0x0);
5633			}
5634			RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
5635#ifdef RTMP_MAC_PCI
5636			pAd->StaCfg.BBPR3 = BBPR3;
5637#endif /* RTMP_MAC_PCI // */
5638			if (OPSTATUS_TEST_FLAG
5639			    (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
5640			    ) {
5641				unsigned long TxTotalCnt =
5642				    pAd->RalinkCounters.OneSecTxNoRetryOkCount +
5643				    pAd->RalinkCounters.OneSecTxRetryOkCount +
5644				    pAd->RalinkCounters.OneSecTxFailCount;
5645
5646				/* dynamic adjust antenna evaluation period according to the traffic */
5647				if (TxTotalCnt > 50) {
5648					RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer,
5649						     20);
5650					pAd->Mlme.bLowThroughput = FALSE;
5651				} else {
5652					RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer,
5653						     300);
5654					pAd->Mlme.bLowThroughput = TRUE;
5655				}
5656			}
5657		}
5658
5659	}
5660
5661}
5662
5663/*
5664    ========================================================================
5665    Routine Description:
5666        After evaluation, check antenna link status
5667
5668    Arguments:
5669        pAd         - Adapter pointer
5670
5671    Return Value:
5672        None
5673
5674    ========================================================================
5675*/
5676void AsicRxAntEvalTimeout(void *SystemSpecific1,
5677			  void *FunctionContext,
5678			  void *SystemSpecific2, void *SystemSpecific3)
5679{
5680	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
5681	u8 BBPR3 = 0;
5682	char larger = -127, rssi0, rssi1, rssi2;
5683
5684	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
5685			   fRTMP_ADAPTER_HALT_IN_PROGRESS |
5686			   fRTMP_ADAPTER_RADIO_OFF |
5687			   fRTMP_ADAPTER_NIC_NOT_EXIST) ||
5688	    OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
5689#ifdef RT30xx
5690	    || (pAd->EepromAccess)
5691#endif /* RT30xx // */
5692#ifdef RT3090
5693	    || (pAd->bPCIclkOff == TRUE)
5694#endif /* RT3090 // */
5695	    )
5696		return;
5697
5698	{
5699		/*if (pAd->StaCfg.Psm == PWR_SAVE) */
5700		/*      return; */
5701		{
5702			if (pAd->StaCfg.Psm == PWR_SAVE)
5703				return;
5704
5705			/* if the traffic is low, use average rssi as the criteria */
5706			if (pAd->Mlme.bLowThroughput == TRUE) {
5707				rssi0 = pAd->StaCfg.RssiSample.LastRssi0;
5708				rssi1 = pAd->StaCfg.RssiSample.LastRssi1;
5709				rssi2 = pAd->StaCfg.RssiSample.LastRssi2;
5710			} else {
5711				rssi0 = pAd->StaCfg.RssiSample.AvgRssi0;
5712				rssi1 = pAd->StaCfg.RssiSample.AvgRssi1;
5713				rssi2 = pAd->StaCfg.RssiSample.AvgRssi2;
5714			}
5715
5716			if (pAd->Antenna.field.RxPath == 3) {
5717				larger = max(rssi0, rssi1);
5718
5719				if (larger > (rssi2 + 20))
5720					pAd->Mlme.RealRxPath = 2;
5721				else
5722					pAd->Mlme.RealRxPath = 3;
5723			} else if (pAd->Antenna.field.RxPath == 2) {
5724				if (rssi0 > (rssi1 + 20))
5725					pAd->Mlme.RealRxPath = 1;
5726				else
5727					pAd->Mlme.RealRxPath = 2;
5728			}
5729
5730			RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
5731			BBPR3 &= (~0x18);
5732			if (pAd->Mlme.RealRxPath == 3) {
5733				BBPR3 |= (0x10);
5734			} else if (pAd->Mlme.RealRxPath == 2) {
5735				BBPR3 |= (0x8);
5736			} else if (pAd->Mlme.RealRxPath == 1) {
5737				BBPR3 |= (0x0);
5738			}
5739			RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
5740#ifdef RTMP_MAC_PCI
5741			pAd->StaCfg.BBPR3 = BBPR3;
5742#endif /* RTMP_MAC_PCI // */
5743		}
5744	}
5745
5746}
5747
5748void APSDPeriodicExec(void *SystemSpecific1,
5749		      void *FunctionContext,
5750		      void *SystemSpecific2, void *SystemSpecific3)
5751{
5752	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
5753
5754	if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
5755		return;
5756
5757	pAd->CommonCfg.TriggerTimerCount++;
5758
5759/* Driver should not send trigger frame, it should be send by application layer */
5760/*
5761	if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable
5762		&& (pAd->CommonCfg.bNeedSendTriggerFrame ||
5763		(((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO))))
5764	{
5765		DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n"));
5766		RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
5767		pAd->CommonCfg.bNeedSendTriggerFrame = FALSE;
5768		pAd->CommonCfg.TriggerTimerCount = 0;
5769		pAd->CommonCfg.bInServicePeriod = TRUE;
5770	}*/
5771}
5772
5773/*
5774    ========================================================================
5775    Routine Description:
5776        Set/reset MAC registers according to bPiggyBack parameter
5777
5778    Arguments:
5779        pAd         - Adapter pointer
5780        bPiggyBack  - Enable / Disable Piggy-Back
5781
5782    Return Value:
5783        None
5784
5785    ========================================================================
5786*/
5787void RTMPSetPiggyBack(struct rt_rtmp_adapter *pAd, IN BOOLEAN bPiggyBack)
5788{
5789	TX_LINK_CFG_STRUC TxLinkCfg;
5790
5791	RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
5792
5793	TxLinkCfg.field.TxCFAckEn = bPiggyBack;
5794	RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
5795}
5796
5797/*
5798    ========================================================================
5799    Routine Description:
5800        check if this entry need to switch rate automatically
5801
5802    Arguments:
5803        pAd
5804        pEntry
5805
5806    Return Value:
5807        TURE
5808        FALSE
5809
5810    ========================================================================
5811*/
5812BOOLEAN RTMPCheckEntryEnableAutoRateSwitch(struct rt_rtmp_adapter *pAd,
5813					   struct rt_mac_table_entry *pEntry)
5814{
5815	BOOLEAN result = TRUE;
5816
5817	{
5818		/* only associated STA counts */
5819		if (pEntry && (pEntry->ValidAsCLI)
5820		    && (pEntry->Sst == SST_ASSOC)) {
5821			result = pAd->StaCfg.bAutoTxRateSwitch;
5822		} else
5823			result = FALSE;
5824	}
5825
5826	return result;
5827}
5828
5829BOOLEAN RTMPAutoRateSwitchCheck(struct rt_rtmp_adapter *pAd)
5830{
5831	{
5832		if (pAd->StaCfg.bAutoTxRateSwitch)
5833			return TRUE;
5834	}
5835	return FALSE;
5836}
5837
5838/*
5839    ========================================================================
5840    Routine Description:
5841        check if this entry need to fix tx legacy rate
5842
5843    Arguments:
5844        pAd
5845        pEntry
5846
5847    Return Value:
5848        TURE
5849        FALSE
5850
5851    ========================================================================
5852*/
5853u8 RTMPStaFixedTxMode(struct rt_rtmp_adapter *pAd, struct rt_mac_table_entry *pEntry)
5854{
5855	u8 tx_mode = FIXED_TXMODE_HT;
5856
5857	{
5858		tx_mode =
5859		    (u8)pAd->StaCfg.DesiredTransmitSetting.field.
5860		    FixedTxMode;
5861	}
5862
5863	return tx_mode;
5864}
5865
5866/*
5867    ========================================================================
5868    Routine Description:
5869        Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified.
5870
5871    Arguments:
5872        pAd
5873        pEntry
5874
5875    Return Value:
5876        TURE
5877        FALSE
5878
5879    ========================================================================
5880*/
5881void RTMPUpdateLegacyTxSetting(u8 fixed_tx_mode, struct rt_mac_table_entry *pEntry)
5882{
5883	HTTRANSMIT_SETTING TransmitSetting;
5884
5885	if (fixed_tx_mode == FIXED_TXMODE_HT)
5886		return;
5887
5888	TransmitSetting.word = 0;
5889
5890	TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE;
5891	TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS;
5892
5893	if (fixed_tx_mode == FIXED_TXMODE_CCK) {
5894		TransmitSetting.field.MODE = MODE_CCK;
5895		/* CCK mode allow MCS 0~3 */
5896		if (TransmitSetting.field.MCS > MCS_3)
5897			TransmitSetting.field.MCS = MCS_3;
5898	} else {
5899		TransmitSetting.field.MODE = MODE_OFDM;
5900		/* OFDM mode allow MCS 0~7 */
5901		if (TransmitSetting.field.MCS > MCS_7)
5902			TransmitSetting.field.MCS = MCS_7;
5903	}
5904
5905	if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) {
5906		pEntry->HTPhyMode.word = TransmitSetting.word;
5907		DBGPRINT(RT_DEBUG_TRACE,
5908			 ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n",
5909			  pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE),
5910			  pEntry->HTPhyMode.field.MCS));
5911	}
5912}
5913
5914/*
5915	==========================================================================
5916	Description:
5917		dynamic tune BBP R66 to find a balance between sensibility and
5918		noise isolation
5919
5920	IRQL = DISPATCH_LEVEL
5921
5922	==========================================================================
5923 */
5924void AsicStaBbpTuning(struct rt_rtmp_adapter *pAd)
5925{
5926	u8 OrigR66Value = 0, R66;	/*, R66UpperBound = 0x30, R66LowerBound = 0x30; */
5927	char Rssi;
5928
5929	/* 2860C did not support Fase CCA, therefore can't tune */
5930	if (pAd->MACVersion == 0x28600100)
5931		return;
5932
5933	/* */
5934	/* work as a STA */
5935	/* */
5936	if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE)	/* no R66 tuning when SCANNING */
5937		return;
5938
5939	if ((pAd->OpMode == OPMODE_STA)
5940	    && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
5941	    )
5942	    && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
5943#ifdef RTMP_MAC_PCI
5944	    && (pAd->bPCIclkOff == FALSE)
5945#endif /* RTMP_MAC_PCI // */
5946	    ) {
5947		RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value);
5948		R66 = OrigR66Value;
5949
5950		if (pAd->Antenna.field.RxPath > 1)
5951			Rssi =
5952			    (pAd->StaCfg.RssiSample.AvgRssi0 +
5953			     pAd->StaCfg.RssiSample.AvgRssi1) >> 1;
5954		else
5955			Rssi = pAd->StaCfg.RssiSample.AvgRssi0;
5956
5957		if (pAd->LatchRfRegs.Channel <= 14) {	/*BG band */
5958#ifdef RT30xx
5959			/* RT3070 is a no LNA solution, it should have different control regarding to AGC gain control */
5960			/* Otherwise, it will have some throughput side effect when low RSSI */
5961
5962			if (IS_RT3070(pAd) || IS_RT3090(pAd) || IS_RT3572(pAd)
5963			    || IS_RT3390(pAd)) {
5964				if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5965					R66 =
5966					    0x1C + 2 * GET_LNA_GAIN(pAd) + 0x20;
5967					if (OrigR66Value != R66) {
5968						RTMP_BBP_IO_WRITE8_BY_REG_ID
5969						    (pAd, BBP_R66, R66);
5970					}
5971				} else {
5972					R66 = 0x1C + 2 * GET_LNA_GAIN(pAd);
5973					if (OrigR66Value != R66) {
5974						RTMP_BBP_IO_WRITE8_BY_REG_ID
5975						    (pAd, BBP_R66, R66);
5976					}
5977				}
5978			} else
5979#endif /* RT30xx // */
5980			{
5981				if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5982					R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10;
5983					if (OrigR66Value != R66) {
5984						RTMP_BBP_IO_WRITE8_BY_REG_ID
5985						    (pAd, BBP_R66, R66);
5986					}
5987				} else {
5988					R66 = 0x2E + GET_LNA_GAIN(pAd);
5989					if (OrigR66Value != R66) {
5990						RTMP_BBP_IO_WRITE8_BY_REG_ID
5991						    (pAd, BBP_R66, R66);
5992					}
5993				}
5994			}
5995		} else {	/*A band */
5996			if (pAd->CommonCfg.BBPCurrentBW == BW_20) {
5997				if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5998					R66 =
5999					    0x32 + (GET_LNA_GAIN(pAd) * 5) / 3 +
6000					    0x10;
6001					if (OrigR66Value != R66) {
6002						RTMP_BBP_IO_WRITE8_BY_REG_ID
6003						    (pAd, BBP_R66, R66);
6004					}
6005				} else {
6006					R66 =
6007					    0x32 + (GET_LNA_GAIN(pAd) * 5) / 3;
6008					if (OrigR66Value != R66) {
6009						RTMP_BBP_IO_WRITE8_BY_REG_ID
6010						    (pAd, BBP_R66, R66);
6011					}
6012				}
6013			} else {
6014				if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
6015					R66 =
6016					    0x3A + (GET_LNA_GAIN(pAd) * 5) / 3 +
6017					    0x10;
6018					if (OrigR66Value != R66) {
6019						RTMP_BBP_IO_WRITE8_BY_REG_ID
6020						    (pAd, BBP_R66, R66);
6021					}
6022				} else {
6023					R66 =
6024					    0x3A + (GET_LNA_GAIN(pAd) * 5) / 3;
6025					if (OrigR66Value != R66) {
6026						RTMP_BBP_IO_WRITE8_BY_REG_ID
6027						    (pAd, BBP_R66, R66);
6028					}
6029				}
6030			}
6031		}
6032
6033	}
6034}
6035
6036void RTMPSetAGCInitValue(struct rt_rtmp_adapter *pAd, u8 BandWidth)
6037{
6038	u8 R66 = 0x30;
6039
6040	if (pAd->LatchRfRegs.Channel <= 14) {	/* BG band */
6041#ifdef RT30xx
6042		/* Gary was verified Amazon AP and find that RT307x has BBP_R66 invalid default value */
6043
6044		if (IS_RT3070(pAd) || IS_RT3090(pAd) || IS_RT3572(pAd)
6045		    || IS_RT3390(pAd)) {
6046			R66 = 0x1C + 2 * GET_LNA_GAIN(pAd);
6047			RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6048		} else
6049#endif /* RT30xx // */
6050		{
6051			R66 = 0x2E + GET_LNA_GAIN(pAd);
6052			RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6053		}
6054	} else {		/*A band */
6055		{
6056			if (BandWidth == BW_20) {
6057				R66 =
6058				    (u8)(0x32 +
6059					     (GET_LNA_GAIN(pAd) * 5) / 3);
6060				RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6061			} else {
6062				R66 =
6063				    (u8)(0x3A +
6064					     (GET_LNA_GAIN(pAd) * 5) / 3);
6065				RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6066			}
6067		}
6068	}
6069
6070}
6071