GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / rt2860 / common / mlme.c
blob9fc34a8f218022dc651a984d1c323bc1836e484c
1 /*
2 *************************************************************************
3 * Ralink Tech Inc.
4 * 5F., No.36, Taiyuan St., Jhubei City,
5 * Hsinchu County 302,
6 * Taiwan, R.O.C.
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
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 *************************************************************************
27 Module Name:
28 mlme.c
30 Abstract:
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
39 #include "../rt_config.h"
40 #include <stdarg.h>
42 u8 CISCO_OUI[] = { 0x00, 0x40, 0x96 };
44 u8 WPA_OUI[] = { 0x00, 0x50, 0xf2, 0x01 };
45 u8 RSN_OUI[] = { 0x00, 0x0f, 0xac };
46 u8 WME_INFO_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01 };
47 u8 WME_PARM_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01 };
48 u8 Ccx2QosInfo[] = { 0x00, 0x40, 0x96, 0x04 };
49 u8 RALINK_OUI[] = { 0x00, 0x0c, 0x43 };
50 u8 BROADCOM_OUI[] = { 0x00, 0x90, 0x4c };
51 u8 WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
52 u8 PRE_N_HT_OUI[] = { 0x00, 0x90, 0x4c };
54 u8 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,
91 u8 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,
100 u8 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,
115 u8 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,
128 u8 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,
145 u8 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,
164 u8 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, */
180 u8 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,
196 u8 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,
212 u8 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,
229 u8 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,
248 u8 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,
263 u8 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,
279 u8 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,
296 extern 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 */
299 unsigned long BasicRateMask[12] =
300 { 0xfffff001 /* 1-Mbps */ , 0xfffff003 /* 2 Mbps */ , 0xfffff007 /* 5.5 */ ,
301 0xfffff00f /* 11 */ ,
302 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ ,
303 0xfffff0ff /* 18 */ ,
304 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ ,
305 0xffffffff /* 54 */
308 u8 BROADCAST_ADDR[MAC_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
309 u8 ZERO_MAC_ADDR[MAC_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
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 */
315 char RssiSafeLevelForTxRate[] =
316 { -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 };
318 u8 RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100 };
319 u16 RateIdTo500Kbps[] =
320 { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200 };
322 u8 SsidIe = IE_SSID;
323 u8 SupRateIe = IE_SUPP_RATES;
324 u8 ExtRateIe = IE_EXT_SUPP_RATES;
325 u8 HtCapIe = IE_HT_CAP;
326 u8 AddHtInfoIe = IE_ADD_HT;
327 u8 NewExtChanIe = IE_SECONDARY_CH_OFFSET;
328 u8 ErpIe = IE_ERP;
329 u8 DsIe = IE_DS_PARM;
330 u8 TimIe = IE_TIM;
331 u8 WpaIe = IE_WPA;
332 u8 Wpa2Ie = IE_WPA2;
333 u8 IbssIe = IE_IBSS_PARM;
335 extern u8 WPA_OUI[];
337 u8 SES_OUI[] = { 0x00, 0x90, 0x4c };
339 u8 ZeroSsid[32] =
340 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 0x00, 0x00, 0x00, 0x00
347 ==========================================================================
348 Description:
349 initialize the MLME task and its data structure (queue, spinlock,
350 timer, state machines).
352 IRQL = PASSIVE_LEVEL
354 Return:
355 always return NDIS_STATUS_SUCCESS
357 ==========================================================================
359 int MlmeInit(struct rt_rtmp_adapter *pAd)
361 int Status = NDIS_STATUS_SUCCESS;
363 DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n"));
365 do {
366 Status = MlmeQueueInit(&pAd->Mlme.Queue);
367 if (Status != NDIS_STATUS_SUCCESS)
368 break;
370 pAd->Mlme.bRunning = FALSE;
371 NdisAllocateSpinLock(&pAd->Mlme.TaskLock);
374 BssTableInit(&pAd->ScanTab);
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);
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);
391 WpaStateMachineInit(pAd, &pAd->Mlme.WpaMachine,
392 pAd->Mlme.WpaFunc);
394 ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine,
395 pAd->Mlme.ActFunc);
397 /* Init mlme periodic timer */
398 RTMPInitTimer(pAd, &pAd->Mlme.PeriodicTimer,
399 GET_TIMER_FUNCTION(MlmePeriodicExec), pAd, TRUE);
401 /* Set mlme periodic timer */
402 RTMPSetTimer(&pAd->Mlme.PeriodicTimer, MLME_TASK_EXEC_INTV);
404 /* software-based RX Antenna diversity */
405 RTMPInitTimer(pAd, &pAd->Mlme.RxAntEvalTimer,
406 GET_TIMER_FUNCTION(AsicRxAntEvalTimeout), pAd,
407 FALSE);
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);
420 #endif /* RTMP_PCI_SUPPORT // */
422 RTMPInitTimer(pAd, &pAd->Mlme.LinkDownTimer,
423 GET_TIMER_FUNCTION(LinkDownExec), pAd,
424 FALSE);
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 // */
435 } while (FALSE);
437 DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n"));
439 return Status;
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.
452 IRQL = DISPATCH_LEVEL
454 ==========================================================================
456 void MlmeHandler(struct rt_rtmp_adapter *pAd)
458 struct rt_mlme_queue_elem *Elem = NULL;
460 /* Only accept MLME and Frame from peer side, no other (control/data) frame should */
461 /* get into this state machine */
463 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
464 if (pAd->Mlme.bRunning) {
465 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
466 return;
467 } else {
468 pAd->Mlme.bRunning = TRUE;
470 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
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;
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;
492 #endif /* RTMP_MAC_USB // */
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;
528 case ACTION_STATE_MACHINE:
529 StateMachinePerformAction(pAd,
530 &pAd->Mlme.ActMachine,
531 Elem);
532 break;
534 case WPA_STATE_MACHINE:
535 StateMachinePerformAction(pAd,
536 &pAd->Mlme.WpaMachine,
537 Elem);
538 break;
540 default:
541 DBGPRINT(RT_DEBUG_TRACE,
542 ("ERROR: Illegal machine %ld in MlmeHandler()\n",
543 Elem->Machine));
544 break;
545 } /* end of switch */
547 /* free MLME element */
548 Elem->Occupied = FALSE;
549 Elem->MsgLen = 0;
551 } else {
552 DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n"));
556 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
557 pAd->Mlme.bRunning = FALSE;
558 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
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
570 IRQL = PASSIVE_LEVEL
572 ==========================================================================
574 void MlmeHalt(struct rt_rtmp_adapter *pAd)
576 BOOLEAN Cancelled;
578 DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeHalt\n"));
580 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
581 /* disable BEACON generation and other BEACON related hardware timers */
582 AsicDisableSync(pAd);
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);
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);
600 #endif /* RTMP_MAC_PCI // */
602 RTMPCancelTimer(&pAd->Mlme.LinkDownTimer, &Cancelled);
604 #ifdef RTMP_MAC_USB
605 RTMPCancelTimer(&pAd->Mlme.AutoWakeupTimer, &Cancelled);
606 #endif /* RTMP_MAC_USB // */
609 RTMPCancelTimer(&pAd->Mlme.PeriodicTimer, &Cancelled);
610 RTMPCancelTimer(&pAd->Mlme.RxAntEvalTimer, &Cancelled);
612 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
613 struct rt_rtmp_chip_op *pChipOps = &pAd->chipOps;
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
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);
628 #endif /* RTMP_MAC_USB // */
630 if (pChipOps->AsicHaltAction)
631 pChipOps->AsicHaltAction(pAd);
634 RTMPusecDelay(5000); /* 5 msec to gurantee Ant Diversity timer canceled */
636 MlmeQueueDestroy(&pAd->Mlme.Queue);
637 NdisFreeSpinLock(&pAd->Mlme.TaskLock);
639 DBGPRINT(RT_DEBUG_TRACE, ("<== MlmeHalt\n"));
642 void MlmeResetRalinkCounters(struct rt_rtmp_adapter *pAd)
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;
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;
672 return;
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.
687 IRQL = DISPATCH_LEVEL
689 ==========================================================================
691 #define ADHOC_BEACON_LOST_TIME (8*OS_HZ) /* 8 sec */
692 void MlmePeriodicExec(void *SystemSpecific1,
693 void *FunctionContext,
694 void *SystemSpecific2, void *SystemSpecific3)
696 unsigned long TxTotalCnt;
697 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
699 #ifdef RTMP_MAC_PCI
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) */
709 u32 data = 0;
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))
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--> */
733 if (data & 0x04) {
734 pAd->StaCfg.bHwRadio = TRUE;
735 } else {
736 pAd->StaCfg.bHwRadio = FALSE;
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;
754 #endif /* RTMP_MAC_PCI // */
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;
764 RTMP_MLME_PRE_SANITY_CHECK(pAd);
767 /* Do nothing if monitor mode is on */
768 if (MONITOR_ON(pAd))
769 return;
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))
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;
787 pAd->bUpdateBcnCntDone = FALSE;
789 /* RECBATimerTimeout(SystemSpecific1,FunctionContext,SystemSpecific2,SystemSpecific3); */
790 pAd->Mlme.PeriodicRound++;
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 // */
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)) */ )
802 /* perform dynamic tx rate switching based on past TX history */
804 if ((OPSTATUS_TEST_FLAG
805 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
807 && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)))
808 MlmeDynamicTxRateSwitching(pAd);
811 /* Normal 1 second Mlme PeriodicExec. */
812 if (pAd->Mlme.PeriodicRound % MLME_TASK_EXEC_MULTIPLE == 0) {
813 pAd->Mlme.OneSecPeriodicRound++;
815 /*ORIBATimerTimeout(pAd); */
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);
826 } else {
827 pAd->IndicateMediaState =
828 NdisMediaStateDisconnected;
829 RTMP_IndicateMediaState(pAd);
833 NdisGetSystemUpTime(&pAd->Mlme.Now32);
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);
839 #ifdef RTMP_MAC_USB
840 RTUSBWatchDog(pAd);
841 #endif /* RTMP_MAC_USB // */
843 /* Need statistics after read counter. So put after NICUpdateRawCounters */
844 ORIBATimerTimeout(pAd);
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; */
854 /* The time period for checking antenna is according to traffic */
856 if (pAd->Mlme.bEnableAutoAntennaCheck) {
857 TxTotalCnt =
858 pAd->RalinkCounters.OneSecTxNoRetryOkCount +
859 pAd->RalinkCounters.OneSecTxRetryOkCount +
860 pAd->RalinkCounters.OneSecTxFailCount;
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);
868 } else {
869 if (pAd->Mlme.OneSecPeriodicRound % 3 ==
870 0) {
871 AsicEvaluateRxAnt(pAd);
877 STAMlmePeriodicExec(pAd);
879 MlmeResetRalinkCounters(pAd);
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 // */
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. */
894 u32 MacReg = 0;
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);
904 DBGPRINT(RT_DEBUG_WARN,
905 ("Warning, MAC specific condition occurs \n"));
910 RTMP_MLME_HANDLER(pAd);
913 pAd->bUpdateBcnCntDone = FALSE;
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 ==========================================================================
924 BOOLEAN MlmeValidateSSID(u8 *pSsid, u8 SsidLen)
926 int index;
928 if (SsidLen > MAX_LEN_OF_SSID)
929 return (FALSE);
931 /* Check each character value */
932 for (index = 0; index < SsidLen; index++) {
933 if (pSsid[index] < 0x20)
934 return (FALSE);
937 /* All checked */
938 return (TRUE);
941 void MlmeSelectTxRateTable(struct rt_rtmp_adapter *pAd,
942 struct rt_mac_table_entry *pEntry,
943 u8 ** ppTable,
944 u8 *pTableSize, u8 *pInitTxRateIdx)
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];
953 break;
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];
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];
976 } else if ((pEntry->RateLen == 4)
977 && (pEntry->HTCapability.MCSSet[0] == 0)
978 && (pEntry->HTCapability.MCSSet[1] == 0)
980 *ppTable = RateSwitchTable11B;
981 *pTableSize = RateSwitchTable11B[0];
982 *pInitTxRateIdx = RateSwitchTable11B[1];
984 } else if (pAd->LatchRfRegs.Channel <= 14) {
985 *ppTable = RateSwitchTable11BG;
986 *pTableSize = RateSwitchTable11BG[0];
987 *pInitTxRateIdx = RateSwitchTable11BG[1];
989 } else {
990 *ppTable = RateSwitchTable11G;
991 *pTableSize = RateSwitchTable11G[0];
992 *pInitTxRateIdx = RateSwitchTable11G[1];
995 break;
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];
1004 break;
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];
1014 } else {
1015 *ppTable = RateSwitchTable11BGN2SForABand;
1016 *pTableSize = RateSwitchTable11BGN2SForABand[0];
1017 *pInitTxRateIdx =
1018 RateSwitchTable11BGN2SForABand[1];
1021 break;
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];
1029 break;
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];
1044 break;
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];
1055 break;
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];
1066 break;
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];
1077 break;
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];
1094 } else {
1095 *ppTable = RateSwitchTable11BG;
1096 *pTableSize = RateSwitchTable11BG[0];
1097 *pInitTxRateIdx =
1098 RateSwitchTable11BG[1];
1100 break;
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"));
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"));
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]));
1144 } while (FALSE);
1147 void STAMlmePeriodicExec(struct rt_rtmp_adapter *pAd)
1149 unsigned long TxTotalCnt;
1150 int i;
1153 We return here in ATE mode, because the statistics
1154 that ATE need are not collected via this routine.
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 // */
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);
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,
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"));
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,
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"));
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]));
1232 #endif /* PCIE_PS_SUPPORT // */
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;
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);
1250 pAd->PreMediaState = pAd->IndicateMediaState;
1253 if (pAd->CommonCfg.PSPXlink && ADHOC_ON(pAd)) {
1254 } else {
1255 AsicStaBbpTuning(pAd);
1258 TxTotalCnt = pAd->RalinkCounters.OneSecTxNoRetryOkCount +
1259 pAd->RalinkCounters.OneSecTxRetryOkCount +
1260 pAd->RalinkCounters.OneSecTxFailCount;
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);
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);
1271 if (INFRA_ON(pAd)) {
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);
1278 pAd->RalinkCounters.LastOneSecTotalTxCount = TxTotalCnt;
1280 if ((RTMP_TIME_AFTER
1281 (pAd->Mlme.Now32,
1282 pAd->StaCfg.LastBeaconRxTime + (1 * OS_HZ)))
1284 (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
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))));
1293 /*if ((pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) && */
1294 /* (pAd->RalinkCounters.OneSecTxRetryOkCount == 0)) */
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);
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));
1326 /* Lost AP, send disconnect & link down event */
1327 LinkDown(pAd, FALSE);
1329 RtmpOSWrielessEventSend(pAd, SIOCGIWAP, -1, NULL, NULL,
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);
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);
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));
1362 /* Add auto seamless roaming */
1363 if (rv == FALSE)
1364 rv = MlmeCheckForFastRoaming(pAd);
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);
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;
1390 DBGPRINT(RT_DEBUG_TRACE,
1391 ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n"));
1392 LinkDown(pAd, FALSE);
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;
1402 for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
1403 struct rt_mac_table_entry *pEntry = &pAd->MacTab.Content[i];
1405 if (pEntry->ValidAsCLI == FALSE)
1406 continue;
1408 if (RTMP_TIME_AFTER
1409 (pAd->Mlme.Now32,
1410 pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME))
1411 MacTableDeleteEntry(pAd, pEntry->Aid,
1412 pEntry->Addr);
1414 } else /* no INFRA nor ADHOC connection */
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;
1424 if ((pAd->StaCfg.bAutoReconnect == TRUE)
1425 && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)
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;
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);
1471 SKIP_AUTO_SCAN_CONN:
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);
1486 return;
1489 /* Link down report */
1490 void LinkDownExec(void *SystemSpecific1,
1491 void *FunctionContext,
1492 void *SystemSpecific2, void *SystemSpecific3)
1494 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
1496 if (pAd != NULL) {
1497 struct rt_mlme_disassoc_req DisassocReq;
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;
1512 pAd->IndicateMediaState = NdisMediaStateDisconnected;
1513 RTMP_IndicateMediaState(pAd);
1514 pAd->ExtraInfo = GENERAL_LINK_DOWN;
1519 /* IRQL = DISPATCH_LEVEL */
1520 void MlmeAutoScan(struct rt_rtmp_adapter *pAd)
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);
1534 /* IRQL = DISPATCH_LEVEL */
1535 void MlmeAutoReconnectLastSSID(struct rt_rtmp_adapter *pAd)
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]));
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);
1549 pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
1551 RTMP_MLME_HANDLER(pAd);
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);
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);
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.
1580 IRQL = DISPATCH_LEVEL
1582 Output:
1583 ==========================================================================
1585 void MlmeCheckForRoaming(struct rt_rtmp_adapter *pAd, unsigned long Now32)
1587 u16 i;
1588 struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
1589 struct rt_bss_entry *pBss;
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];
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 */
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;
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);
1626 DBGPRINT(RT_DEBUG_TRACE,
1627 ("<== MlmeCheckForRoaming(# of candidate= %d)\n",
1628 pRoamTab->BssNr));
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.
1638 IRQL = DISPATCH_LEVEL
1640 Output:
1641 ==========================================================================
1643 BOOLEAN MlmeCheckForFastRoaming(struct rt_rtmp_adapter *pAd)
1645 u16 i;
1646 struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
1647 struct rt_bss_entry *pBss;
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];
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 */
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;
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;
1699 return FALSE;
1702 void MlmeSetTxRate(struct rt_rtmp_adapter *pAd,
1703 struct rt_mac_table_entry *pEntry, struct rt_rtmp_tx_rate_switch * pTxRate)
1705 u8 MaxMode = MODE_OFDM;
1707 MaxMode = MODE_HTGREENFIELD;
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;
1715 if (pTxRate->CurrMCS < MCS_AUTO)
1716 pAd->StaCfg.HTPhyMode.field.MCS = pTxRate->CurrMCS;
1718 if (pAd->StaCfg.HTPhyMode.field.MCS > 7)
1719 pAd->StaCfg.HTPhyMode.field.STBC = STBC_NONE;
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;
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;
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;
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;
1746 /* Reexam each bandwidth's SGI support. */
1747 if (pAd->StaCfg.HTPhyMode.field.ShortGI == GI_400) {
1748 if ((pEntry->HTPhyMode.field.BW == BW_20)
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)
1755 (!CLIENT_STATUS_TEST_FLAG
1756 (pEntry, fCLIENT_STATUS_SGI40_CAPABLE)))
1757 pAd->StaCfg.HTPhyMode.field.ShortGI = GI_800;
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);
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);
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);
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);
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;
1823 pAd->LastTxRate = (u16)(pEntry->HTPhyMode.word);
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.
1833 CommonCfg.TxRate will change dynamically within {RATE_1/RATE_6, MaxTxRate}
1834 Output:
1835 CommonCfg.TxRate -
1837 IRQL = DISPATCH_LEVEL
1839 NOTE:
1840 call this routine every second
1841 ==========================================================================
1843 void MlmeDynamicTxRateSwitching(struct rt_rtmp_adapter *pAd)
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;
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];
1866 /* check if this entry need to switch rate automatically */
1867 if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
1868 continue;
1870 if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) {
1871 Rssi = RTMPMaxRssi(pAd,
1872 pRssi->AvgRssi0,
1873 pRssi->AvgRssi1, pRssi->AvgRssi2);
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;
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;
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;
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);
1921 TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
1922 pEntry->OneSecTxRetryOkCount +
1923 pEntry->OneSecTxFailCount;
1925 if (TxTotalCnt)
1926 TxErrorRatio =
1927 ((pEntry->OneSecTxRetryOkCount +
1928 pEntry->OneSecTxFailCount) * 100) /
1929 TxTotalCnt;
1932 if (TxTotalCnt) {
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
1937 if (TxErrorRatio == 100) {
1938 TX_RTY_CFG_STRUC TxRtyCfg, TxRtyCfgtmp;
1939 unsigned long Index;
1940 unsigned long MACValue;
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);
1948 RTMPusecDelay(1);
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)
1961 (!RTMP_TEST_FLAG
1962 (pAd,
1963 fRTMP_ADAPTER_HALT_IN_PROGRESS)));
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);
1974 CurrRateIdx = pEntry->CurrTxRateIndex;
1976 MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
1977 &InitTxRateIdx);
1979 if (CurrRateIdx >= TableSize) {
1980 CurrRateIdx = TableSize - 1;
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) */
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);
1998 /* reset all OneSecTx counters */
1999 RESET_ONE_SEC_TX_CNT(pEntry);
2000 continue;
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;
2014 pCurrTxRate =
2015 (struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
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;
2029 /*pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction; */
2031 /* */
2032 /* Keep the last time TxRateChangeAction status. */
2033 /* */
2034 pEntry->LastTimeTxRateChangeAction =
2035 pEntry->LastSecTxRateChangeAction;
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 */
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) *
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;
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 */
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;
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 */
2083 MCS15 = idx;
2084 } else if (pCurrTxRate->CurrMCS == MCS_20) /* 3*3 */
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;
2094 idx++;
2097 if (pAd->LatchRfRegs.Channel <= 14) {
2098 if (pAd->NicConfig2.field.ExternalLNAForG) {
2099 RssiOffset = 2;
2100 } else {
2101 RssiOffset = 5;
2103 } else {
2104 if (pAd->NicConfig2.field.ExternalLNAForA) {
2105 RssiOffset = 5;
2106 } else {
2107 RssiOffset = 8;
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;
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;
2191 /* if (TxRateIdx != pAd->CommonCfg.TxRateIndex) */
2193 pEntry->CurrTxRateIndex = TxRateIdx;
2194 pNextTxRate =
2195 (struct rt_rtmp_tx_rate_switch *) &
2196 pTable[(pEntry->CurrTxRateIndex + 1) * 5];
2197 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
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);
2210 continue;
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);
2219 continue;
2222 do {
2223 BOOLEAN bTrainUpDown = FALSE;
2225 pEntry->CurrTxRateStableTime++;
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;
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 */
2240 if (pEntry->TxRateUpPenalty)
2241 pEntry->TxRateUpPenalty--;
2242 else if (pEntry->TxQuality[UpRateIdx])
2243 pEntry->TxQuality[UpRateIdx]--; /* may improve next UP rate's quality */
2246 pEntry->PER[CurrRateIdx] = (u8)TxErrorRatio;
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;
2260 } while (FALSE);
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);
2274 /* */
2275 /* For TxRate fast train up */
2276 /* */
2277 if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2278 RTMPSetTimer(&pAd->StaCfg.
2279 StaQuickResponeForRateUpTimer,
2280 100);
2282 pAd->StaCfg.
2283 StaQuickResponeForRateUpTimerRunning = TRUE;
2285 bTxRateChanged = TRUE;
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;
2295 /* */
2296 /* For TxRate fast train down */
2297 /* */
2298 if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2299 RTMPSetTimer(&pAd->StaCfg.
2300 StaQuickResponeForRateUpTimer,
2301 100);
2303 pAd->StaCfg.
2304 StaQuickResponeForRateUpTimerRunning = TRUE;
2306 bTxRateChanged = TRUE;
2307 } else {
2308 pEntry->LastSecTxRateChangeAction = 0; /* rate no change */
2309 bTxRateChanged = FALSE;
2312 pEntry->LastTxOkCount = TxSuccess;
2314 u8 tmpTxRate;
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;
2334 pNextTxRate =
2335 (struct rt_rtmp_tx_rate_switch *) & pTable[(tmpTxRate + 1) *
2338 if (bTxRateChanged && pNextTxRate) {
2339 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2341 /* reset all OneSecTx counters */
2342 RESET_ONE_SEC_TX_CNT(pEntry);
2347 ========================================================================
2348 Routine Description:
2349 Station side, Auto TxRate faster train up timer call back function.
2351 Arguments:
2352 SystemSpecific1 - Not used.
2353 FunctionContext - Pointer to our Adapter context.
2354 SystemSpecific2 - Not used.
2355 SystemSpecific3 - Not used.
2357 Return Value:
2358 None
2360 ========================================================================
2362 void StaQuickResponeForRateUpExec(void *SystemSpecific1,
2363 void *FunctionContext,
2364 void *SystemSpecific2,
2365 void *SystemSpecific3)
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;
2383 pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE;
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];
2391 /* check if this entry need to switch rate automatically */
2392 if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
2393 continue;
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);
2406 CurrRateIdx = pAd->CommonCfg.TxRateIndex;
2408 MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
2409 &InitTxRateIdx);
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;
2423 pCurrTxRate =
2424 (struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
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;
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);
2443 TxRetransmit = StaTx1.field.TxRetransmit;
2444 TxSuccess = StaTx1.field.TxSuccess;
2445 TxFailCount = TxStaCnt0.field.TxFailCount;
2446 TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
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;
2461 if (TxTotalCnt)
2462 TxErrorRatio =
2463 ((TxRetransmit +
2464 TxFailCount) * 100) / TxTotalCnt;
2465 } else {
2466 TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
2467 pEntry->OneSecTxRetryOkCount +
2468 pEntry->OneSecTxFailCount;
2470 if (TxTotalCnt)
2471 TxErrorRatio =
2472 ((pEntry->OneSecTxRetryOkCount +
2473 pEntry->OneSecTxFailCount) * 100) /
2474 TxTotalCnt;
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);
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;
2500 DBGPRINT_RAW(RT_DEBUG_TRACE,
2501 ("QuickDRS: TxTotalCnt <= 15, train back to original rate \n"));
2502 return;
2505 do {
2506 unsigned long OneSecTxNoRetryOKRationCount;
2508 if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0)
2509 ratio = 5;
2510 else
2511 ratio = 4;
2513 /* downgrade TX quality if PER >= Rate-Down threshold */
2514 if (TxErrorRatio >= TrainDown) {
2515 pAd->DrsCounters.TxQuality[CurrRateIdx] =
2516 DRS_TX_QUALITY_WORST_BOUND;
2519 pAd->DrsCounters.PER[CurrRateIdx] =
2520 (u8)TxErrorRatio;
2522 OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);
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;
2537 } else
2538 if ((pAd->DrsCounters.LastSecTxRateChangeAction ==
2539 2) && (CurrRateIdx != UpRateIdx)) {
2540 if ((TxErrorRatio >= 50)
2541 || (TxErrorRatio >= TrainDown)) {
2543 } else if ((pAd->DrsCounters.LastTxOkCount + 2)
2544 >= OneSecTxNoRetryOKRationCount) {
2545 pAd->CommonCfg.TxRateIndex = UpRateIdx;
2548 } while (FALSE);
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;
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));
2567 pAd->DrsCounters.TxRateUpPenalty = 0; /* no penalty */
2568 pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] =
2570 pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0;
2571 bTxRateChanged = TRUE;
2572 } else {
2573 bTxRateChanged = FALSE;
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);
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
2600 IRQL = DISPATCH_LEVEL
2602 ==========================================================================
2604 void MlmeCheckPsmChange(struct rt_rtmp_adapter *pAd, unsigned long Now32)
2606 unsigned long PowerMode;
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;
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) */
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);
2639 /* IRQL = PASSIVE_LEVEL */
2640 /* IRQL = DISPATCH_LEVEL */
2641 void MlmeSetPsmBit(struct rt_rtmp_adapter *pAd, u16 psm)
2643 AUTO_RSP_CFG_STRUC csr4;
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);
2650 DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm));
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.
2660 If ChannelQuality is not good, a ROAMing attempt may be tried later.
2661 Output:
2662 StaCfg.ChannelQuality - 0..100
2664 IRQL = DISPATCH_LEVEL
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 ==========================================================================
2672 void MlmeCalculateChannelQuality(struct rt_rtmp_adapter *pAd,
2673 struct rt_mac_table_entry *pMacEntry, unsigned long Now32)
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;
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;
2698 MaxRssi = RTMPMaxRssi(pAd, pRssiSample->LastRssi0,
2699 pRssiSample->LastRssi1, pRssiSample->LastRssi2);
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;
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;
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;
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;
2747 if (pAd->OpMode == OPMODE_STA)
2748 pAd->Mlme.ChannelQuality =
2749 (ChannelQuality > 100) ? 100 : ChannelQuality;
2753 /* IRQL = DISPATCH_LEVEL */
2754 void MlmeSetTxPreamble(struct rt_rtmp_adapter *pAd, u16 TxPreamble)
2756 AUTO_RSP_CFG_STRUC csr4;
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; */
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;
2778 RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
2782 ==========================================================================
2783 Description:
2784 Update basic rate bitmap
2785 ==========================================================================
2788 void UpdateBasicRateBitmap(struct rt_rtmp_adapter *pAdapter)
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;
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 */
2803 if (pAdapter->CommonCfg.BasicRateBitmap > 4095) {
2804 /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */
2805 return;
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 */
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 */
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 */
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. */
2834 void MlmeUpdateTxRates(struct rt_rtmp_adapter *pAd, IN BOOLEAN bLinkUp, u8 apidx)
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;
2848 /* find max desired rate */
2849 UpdateBasicRateBitmap(pAd);
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; */
2905 if (MaxDesire < Rate)
2906 MaxDesire = Rate;
2909 /*=========================================================================== */
2910 /*=========================================================================== */
2912 pHtPhy = &pAd->StaCfg.HTPhyMode;
2913 pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
2914 pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
2916 auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
2917 HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS;
2919 if ((pAd->StaCfg.BssType == BSS_ADHOC) &&
2920 (pAd->CommonCfg.PhyMode == PHY_11B) &&
2921 (MaxDesire > RATE_11)) {
2922 MaxDesire = RATE_11;
2926 pAd->CommonCfg.MaxDesiredRate = MaxDesire;
2927 pMinHtPhy->word = 0;
2928 pMaxHtPhy->word = 0;
2929 pHtPhy->word = 0;
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;
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;
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;
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;
3029 if (MaxSupport < Rate)
3030 MaxSupport = Rate;
3032 if (MinSupport > Rate)
3033 MinSupport = Rate;
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;
3099 if (MaxSupport < Rate)
3100 MaxSupport = Rate;
3102 if (MinSupport > Rate)
3103 MinSupport = Rate;
3106 RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap);
3108 /* bug fix */
3109 /* pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap; */
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;
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;
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;
3138 dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta;
3140 if (bLinkUp == TRUE)
3141 pAd->CommonCfg.TxRate = RATE_24;
3142 else
3143 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3145 if (dbm < -75)
3146 pAd->CommonCfg.TxRate = RATE_11;
3147 else if (dbm < -70)
3148 pAd->CommonCfg.TxRate = RATE_24;
3150 /* should never exceed MaxTxRate (consider 11B-only mode) */
3151 if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate)
3152 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
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;
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;
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;
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;
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];
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;
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;
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));
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.
3291 IRQL = DISPATCH_LEVEL
3293 ==========================================================================
3295 void MlmeUpdateHtTxRates(struct rt_rtmp_adapter *pAd, u8 apidx)
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;
3309 DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateHtTxRates===> \n"));
3311 auto_rate_cur_p = NULL;
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;
3320 auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
3323 if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) {
3324 if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE)
3325 return;
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;
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;
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;
3360 if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth)
3361 && (pRtHtCap->ChannelWidth))
3362 pMaxHtPhy->field.BW = BW_40;
3363 else
3364 pMaxHtPhy->field.BW = BW_20;
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);
3375 if (pDesireHtPhy->MCSSet[4] != 0) {
3376 pMaxHtPhy->field.MCS = 32;
3379 for (i = 23; i >= 0; i--) /* 3*3 */
3381 j = i / 8;
3382 bitmask = (1 << (i - (j * 8)));
3384 if ((pActiveHtPhy->MCSSet[j] & bitmask)
3385 && (pDesireHtPhy->MCSSet[j] & bitmask)) {
3386 pMaxHtPhy->field.MCS = i;
3387 break;
3390 if (i == 0)
3391 break;
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));
3409 for (i = 23; (char)i >= 0; i--) /* 3*3 */
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;
3419 if (i == 0)
3420 break;
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;
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;
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"));
3447 void BATableInit(struct rt_rtmp_adapter *pAd, struct rt_ba_table *Tab)
3449 int i;
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));
3459 for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) {
3460 Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE;
3464 /* IRQL = DISPATCH_LEVEL */
3465 void MlmeRadioOff(struct rt_rtmp_adapter *pAd)
3467 RTMP_MLME_RADIO_OFF(pAd);
3470 /* IRQL = DISPATCH_LEVEL */
3471 void MlmeRadioOn(struct rt_rtmp_adapter *pAd)
3473 RTMP_MLME_RADIO_ON(pAd);
3476 /* =========================================================================================== */
3477 /* bss_table.c */
3478 /* =========================================================================================== */
3480 /*! \brief initialize BSS table
3481 * \param p_tab pointer to the table
3482 * \return none
3483 * \pre
3484 * \post
3486 IRQL = PASSIVE_LEVEL
3487 IRQL = DISPATCH_LEVEL
3490 void BssTableInit(struct rt_bss_table *Tab)
3492 int i;
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 */
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
3510 IRQL = DISPATCH_LEVEL
3513 unsigned long BssTableSearch(struct rt_bss_table *Tab, u8 *pBssid, u8 Channel)
3515 u8 i;
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;
3528 return (unsigned long)BSS_NOT_FOUND;
3531 unsigned long BssSsidTableSearch(struct rt_bss_table *Tab,
3532 u8 *pBssid,
3533 u8 *pSsid, u8 SsidLen, u8 Channel)
3535 u8 i;
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;
3550 return (unsigned long)BSS_NOT_FOUND;
3553 unsigned long BssTableSearchWithSSID(struct rt_bss_table *Tab,
3554 u8 *Bssid,
3555 u8 *pSsid,
3556 u8 SsidLen, u8 Channel)
3558 u8 i;
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))
3569 (NdisEqualMemory
3570 (Tab->BssEntry[i].Ssid, ZeroSsid,
3571 Tab->BssEntry[i].SsidLen)))) {
3572 return i;
3575 return (unsigned long)BSS_NOT_FOUND;
3578 unsigned long BssSsidTableSearchBySSID(struct rt_bss_table *Tab,
3579 u8 *pSsid, u8 SsidLen)
3581 u8 i;
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;
3590 return (unsigned long)BSS_NOT_FOUND;
3593 /* IRQL = DISPATCH_LEVEL */
3594 void BssTableDeleteEntry(struct rt_bss_table *Tab,
3595 u8 *pBssid, u8 Channel)
3597 u8 i, j;
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));
3607 NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]),
3608 sizeof(struct rt_bss_entry));
3609 Tab->BssNr -= 1;
3610 return;
3616 ========================================================================
3617 Routine Description:
3618 Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed.
3620 Arguments:
3621 // IRQL = DISPATCH_LEVEL
3622 ========================================================================
3624 void BATableDeleteORIEntry(struct rt_rtmp_adapter *pAd,
3625 struct rt_ba_ori_entry *pBAORIEntry)
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. */
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);
3646 /*! \brief
3647 * \param
3648 * \return
3649 * \pre
3650 * \post
3652 IRQL = DISPATCH_LEVEL
3655 void 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)
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;
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;
3693 } else {
3694 pBss->AtimWin = AtimWin;
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;
3718 /* New for microsoft Fixed IEs */
3719 NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
3720 pBss->FixIEs.BeaconInterval = BeaconPeriod;
3721 pBss->FixIEs.Capabilities = CapabilityInfo;
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;
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);
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;
3760 BssCipherParse(pBss);
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;
3779 struct rt_eid * pEid;
3780 u16 Length = 0;
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;
3793 pBss->WpaIE.IELen = pEid->Len + 2;
3794 NdisMoveMemory(pBss->WpaIE.IE, pEid,
3795 pBss->WpaIE.IELen);
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;
3805 pBss->RsnIE.IELen = pEid->Len + 2;
3806 NdisMoveMemory(pBss->RsnIE.IE, pEid,
3807 pBss->RsnIE.IELen);
3809 break;
3811 Length = Length + 2 + (u16)pEid->Len; /* Eid[1] + Len[1]+ content[Len] */
3812 pEid = (struct rt_eid *) ((u8 *) pEid + 2 + pEid->Len);
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
3837 IRQL = DISPATCH_LEVEL
3840 unsigned 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)
3853 unsigned long Idx;
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;
3889 return Idx;
3890 } else {
3891 return BSS_NOT_FOUND;
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))
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);
3923 return Idx;
3926 /* IRQL = DISPATCH_LEVEL */
3927 void BssTableSsidSort(struct rt_rtmp_adapter *pAd,
3928 struct rt_bss_table *OutTab, char Ssid[], u8 SsidLen)
3930 int i;
3931 BssTableInit(OutTab);
3933 for (i = 0; i < pAd->ScanTab.BssNr; i++) {
3934 struct rt_bss_entry *pInBss = &pAd->ScanTab.BssEntry[i];
3935 BOOLEAN bIsHiddenApIncluded = FALSE;
3937 if (((pAd->CommonCfg.bIEEE80211H == 1) &&
3938 (pAd->MlmeAux.Channel > 14) &&
3939 RadarChannelCheck(pAd, pInBss->Channel))
3941 if (pInBss->Hidden)
3942 bIsHiddenApIncluded = TRUE;
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];
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;
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;
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;
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;
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;
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;
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;
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;
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;
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);
4069 /* copy matching BSS from InTab to OutTab */
4070 NdisMoveMemory(pOutBss, pInBss, sizeof(struct rt_bss_entry));
4072 OutTab->BssNr++;
4073 } else if ((pInBss->BssType == pAd->StaCfg.BssType)
4074 && (SsidLen == 0)) {
4075 struct rt_bss_entry *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
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;
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;
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;
4106 /* check group cipher */
4107 if (pAd->StaCfg.WepStatus <
4108 pInBss->WPA.GroupCipher)
4109 continue;
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;
4132 /* check group cipher */
4133 if (pAd->StaCfg.WepStatus <
4134 pInBss->WPA2.GroupCipher)
4135 continue;
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;
4149 /* Bss Type matched, SSID matched. */
4150 /* We will check wepstatus for qualification Bss */
4151 else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
4152 continue;
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;
4169 /* copy matching BSS from InTab to OutTab */
4170 NdisMoveMemory(pOutBss, pInBss, sizeof(struct rt_bss_entry));
4172 OutTab->BssNr++;
4175 if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
4176 break;
4179 BssTableSortByRssi(OutTab);
4182 /* IRQL = DISPATCH_LEVEL */
4183 void BssTableSortByRssi(struct rt_bss_table *OutTab)
4185 int i, j;
4186 struct rt_bss_entry TmpBss;
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));
4203 void BssCipherParse(struct rt_bss_entry *pBss)
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;
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;
4222 /* Set default to disable & open authentication before parsing variable IE */
4223 pBss->AuthMode = Ndis802_11AuthModeOpen;
4224 pBss->AuthModeAux = Ndis802_11AuthModeOpen;
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;
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;
4240 Length = (int)pBss->VarIELen;
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;
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;
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;
4292 /* number of unicast suite */
4293 pTmp += 1;
4295 /* skip all unicast cipher suites */
4296 /*Count = *(u16 *)pTmp; */
4297 Count = (pTmp[1] << 8) + pTmp[0];
4298 pTmp += sizeof(u16);
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;
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;
4330 pTmp++;
4331 Count--;
4334 /* 4. get AKM suite counts */
4335 /*Count = *(u16 *)pTmp; */
4336 Count = (pTmp[1] << 8) + pTmp[0];
4337 pTmp += sizeof(u16);
4338 pTmp += 3;
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;
4361 pTmp += 1;
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;
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;
4380 break;
4382 case IE_RSN:
4383 pRsnHeader = (struct rt_rsn_ie_header *) pTmp;
4385 /* 0. Version must be 1 */
4386 if (le2cpu16(pRsnHeader->Version) != 1)
4387 break;
4388 pTmp += sizeof(struct rt_rsn_ie_header);
4390 /* 1. Check group cipher */
4391 pCipher = (struct rt_cipher_suite_struct *) pTmp;
4392 if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
4393 break;
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;
4416 /* set to correct offset for next parsing */
4417 pTmp += sizeof(struct rt_cipher_suite_struct);
4419 /* 2. Get pairwise cipher counts */
4420 /*Count = *(u16 *)pTmp; */
4421 Count = (pTmp[1] << 8) + pTmp[0];
4422 pTmp += sizeof(u16);
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;
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;
4455 pTmp += sizeof(struct rt_cipher_suite_struct);
4456 Count--;
4459 /* 4. get AKM suite counts */
4460 /*Count = *(u16 *)pTmp; */
4461 Count = (pTmp[1] << 8) + pTmp[0];
4462 pTmp += sizeof(u16);
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;
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;
4502 pTmp += (Count * sizeof(struct rt_akm_suite));
4503 Count--;
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;
4520 pBss->WepStatus = pBss->WPA2.PairCipher;
4522 /* 6. Get RSN capability */
4523 /*pBss->WPA2.RsnCapability = *(u16 *)pTmp; */
4524 pBss->WPA2.RsnCapability = (pTmp[1] << 8) + pTmp[0];
4525 pTmp += sizeof(u16);
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;
4531 break;
4532 default:
4533 break;
4535 Length -= (pEid->Len + 2);
4539 /* =========================================================================================== */
4540 /* mac_table.c */
4541 /* =========================================================================================== */
4543 /*! \brief generates a random mac address value for IBSS BSSID
4544 * \param Addr the bssid location
4545 * \return none
4546 * \pre
4547 * \post
4549 void MacAddrRandomBssid(struct rt_rtmp_adapter *pAd, u8 *pAddr)
4551 int i;
4553 for (i = 0; i < MAC_ADDR_LEN; i++) {
4554 pAddr[i] = RandomByte(pAd);
4557 pAddr[0] = (pAddr[0] & 0xfe) | 0x02; /* the first 2 bits must be 01xxxxxxxx */
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
4571 IRQL = PASSIVE_LEVEL
4572 IRQL = DISPATCH_LEVEL
4575 void MgtMacHeaderInit(struct rt_rtmp_adapter *pAd,
4576 struct rt_header_802_11 * pHdr80211,
4577 u8 SubType,
4578 u8 ToDs, u8 *pDA, u8 *pBssid)
4580 NdisZeroMemory(pHdr80211, sizeof(struct rt_header_802_11));
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);
4592 /* =========================================================================================== */
4593 /* mem_mgmt.c */
4594 /* =========================================================================================== */
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);
4610 IRQL = PASSIVE_LEVEL
4611 IRQL = DISPATCH_LEVEL
4613 ****************************************************************************/
4614 unsigned long MakeOutgoingFrame(u8 * Buffer, unsigned long * FrameLen, ...)
4616 u8 *p;
4617 int leng;
4618 unsigned long TotLeng;
4619 va_list Args;
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;
4629 p = va_arg(Args, void *);
4630 NdisMoveMemory(&Buffer[TotLeng], p, leng);
4631 TotLeng = TotLeng + leng;
4632 } while (TRUE);
4634 va_end(Args); /* clean up */
4635 *FrameLen = TotLeng;
4636 return TotLeng;
4639 /* =========================================================================================== */
4640 /* mlme_queue.c */
4641 /* =========================================================================================== */
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
4650 IRQL = PASSIVE_LEVEL
4653 int MlmeQueueInit(struct rt_mlme_queue *Queue)
4655 int i;
4657 NdisAllocateSpinLock(&Queue->Lock);
4659 Queue->Num = 0;
4660 Queue->Head = 0;
4661 Queue->Tail = 0;
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);
4669 return NDIS_STATUS_SUCCESS;
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
4683 IRQL = PASSIVE_LEVEL
4684 IRQL = DISPATCH_LEVEL
4687 BOOLEAN MlmeEnqueue(struct rt_rtmp_adapter *pAd,
4688 unsigned long Machine,
4689 unsigned long MsgType, unsigned long MsgLen, void * Msg)
4691 int Tail;
4692 struct rt_mlme_queue *Queue = (struct rt_mlme_queue *)& pAd->Mlme.Queue;
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;
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;
4707 if (MlmeQueueFull(Queue)) {
4708 return FALSE;
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;
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;
4725 if (Msg != NULL) {
4726 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4729 NdisReleaseSpinLock(&(Queue->Lock));
4730 return TRUE;
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
4744 IRQL = DISPATCH_LEVEL
4747 BOOLEAN 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)
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;
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;
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;
4775 if (MlmeQueueFull(Queue)) {
4776 return FALSE;
4780 if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) {
4781 DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType));
4782 return FALSE;
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;
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;
4806 Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel;
4808 if (Msg != NULL) {
4809 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4812 NdisReleaseSpinLock(&(Queue->Lock));
4814 RTMP_MLME_HANDLER(pAd);
4816 return TRUE;
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
4826 IRQL = DISPATCH_LEVEL
4829 BOOLEAN MlmeDequeue(struct rt_mlme_queue *Queue, struct rt_mlme_queue_elem ** Elem)
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;
4838 NdisReleaseSpinLock(&(Queue->Lock));
4839 return TRUE;
4842 /* IRQL = DISPATCH_LEVEL */
4843 void MlmeRestartStateMachine(struct rt_rtmp_adapter *pAd)
4845 #ifdef RTMP_MAC_PCI
4846 struct rt_mlme_queue_elem *Elem = NULL;
4847 #endif /* RTMP_MAC_PCI // */
4848 BOOLEAN Cancelled;
4850 DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n"));
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;
4860 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
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;
4870 } else {
4871 DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n"));
4874 #endif /* RTMP_MAC_PCI // */
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);
4888 /* Change back to original channel in case of doing scan */
4889 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
4890 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
4892 /* Resume MSDU which is turned off durning scan */
4893 RTMPResumeMsduTransmission(pAd);
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;
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 // */
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
4919 IRQL = DISPATCH_LEVEL
4922 BOOLEAN MlmeQueueEmpty(struct rt_mlme_queue *Queue)
4924 BOOLEAN Ans;
4926 NdisAcquireSpinLock(&(Queue->Lock));
4927 Ans = (Queue->Num == 0);
4928 NdisReleaseSpinLock(&(Queue->Lock));
4930 return Ans;
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
4939 IRQL = PASSIVE_LEVEL
4940 IRQL = DISPATCH_LEVEL
4943 BOOLEAN MlmeQueueFull(struct rt_mlme_queue *Queue)
4945 BOOLEAN Ans;
4947 NdisAcquireSpinLock(&(Queue->Lock));
4948 Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE
4949 || Queue->Entry[Queue->Tail].Occupied);
4950 NdisReleaseSpinLock(&(Queue->Lock));
4952 return Ans;
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.
4962 IRQL = PASSIVE_LEVEL
4965 void MlmeQueueDestroy(struct rt_mlme_queue *pQueue)
4967 NdisAcquireSpinLock(&(pQueue->Lock));
4968 pQueue->Num = 0;
4969 pQueue->Head = 0;
4970 pQueue->Tail = 0;
4971 NdisReleaseSpinLock(&(pQueue->Lock));
4972 NdisFreeSpinLock(&(pQueue->Lock));
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
4983 IRQL = DISPATCH_LEVEL
4986 BOOLEAN MsgTypeSubst(struct rt_rtmp_adapter *pAd,
4987 struct rt_frame_802_11 * pFrame,
4988 int * Machine, int * MsgType)
4990 u16 Seq, Alg;
4991 u8 EAPType;
4992 u8 *pData;
4994 /* Pointer to start of data frames including SNAP header */
4995 pData = (u8 *)pFrame + LENGTH_802_11;
4997 /* The only data type will pass to this function is EAPOL frame */
4998 if (pFrame->Hdr.FC.Type == BTYPE_DATA) {
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));
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;
5057 } else {
5058 return FALSE;
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);
5073 break;
5074 default:
5075 return FALSE;
5076 break;
5079 return TRUE;
5082 /* =========================================================================================== */
5083 /* state_machine.c */
5084 /* =========================================================================================== */
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
5097 IRQL = PASSIVE_LEVEL
5100 void 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)
5107 unsigned long i, j;
5109 /* set number of states and messages */
5110 S->NrState = StNr;
5111 S->NrMsg = MsgNr;
5112 S->Base = Base;
5114 S->TransFunc = Trans;
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;
5123 /* set the starting state */
5124 S->CurrState = InitState;
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
5135 IRQL = PASSIVE_LEVEL
5138 void StateMachineSetAction(struct rt_state_machine *S,
5139 unsigned long St,
5140 unsigned long Msg, IN STATE_MACHINE_FUNC Func)
5142 unsigned long MsgIdx;
5144 MsgIdx = Msg - S->Base;
5146 if (St < S->NrState && MsgIdx < S->NrMsg) {
5147 /* boundary checking before setting the action */
5148 S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
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
5158 IRQL = DISPATCH_LEVEL
5161 void StateMachinePerformAction(struct rt_rtmp_adapter *pAd,
5162 struct rt_state_machine *S, struct rt_mlme_queue_elem *Elem)
5164 (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))
5165 (pAd, Elem);
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 ==========================================================================
5176 void Drop(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
5180 /* =========================================================================================== */
5181 /* lfsr.c */
5182 /* =========================================================================================== */
5185 ==========================================================================
5186 Description:
5188 IRQL = PASSIVE_LEVEL
5190 ==========================================================================
5192 void LfsrInit(struct rt_rtmp_adapter *pAd, unsigned long Seed)
5194 if (Seed == 0)
5195 pAd->Mlme.ShiftReg = 1;
5196 else
5197 pAd->Mlme.ShiftReg = Seed;
5201 ==========================================================================
5202 Description:
5203 ==========================================================================
5205 u8 RandomByte(struct rt_rtmp_adapter *pAd)
5207 unsigned long i;
5208 u8 R, Result;
5210 R = 0;
5212 if (pAd->Mlme.ShiftReg == 0)
5213 NdisGetSystemUpTime((unsigned long *) & pAd->Mlme.ShiftReg);
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;
5225 R = (R << 1) | Result;
5228 return R;
5232 ========================================================================
5234 Routine Description:
5235 Verify the support rate for different PHY type
5237 Arguments:
5238 pAd Pointer to our adapter
5240 Return Value:
5241 None
5243 IRQL = PASSIVE_LEVEL
5245 ========================================================================
5247 void RTMPCheckRates(struct rt_rtmp_adapter *pAd,
5248 IN u8 SupRate[], IN u8 * SupRateLen)
5250 u8 RateIdx, i, j;
5251 u8 NewRate[12], NewRateLen;
5253 NewRateLen = 0;
5255 if (pAd->CommonCfg.PhyMode == PHY_11B)
5256 RateIdx = 4;
5257 else
5258 RateIdx = 12;
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];
5266 *SupRateLen = NewRateLen;
5267 NdisMoveMemory(SupRate, NewRate, NewRateLen);
5270 BOOLEAN RTMPCheckChannel(struct rt_rtmp_adapter *pAd,
5271 u8 CentralChannel, u8 Channel)
5273 u8 k;
5274 u8 UpperChannel = 0, LowerChannel = 0;
5275 u8 NoEffectChannelinList = 0;
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;
5289 for (k = 0; k < pAd->ChannelListNum; k++) {
5290 if (pAd->ChannelList[k].Channel == UpperChannel) {
5291 NoEffectChannelinList++;
5293 if (pAd->ChannelList[k].Channel == LowerChannel) {
5294 NoEffectChannelinList++;
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;
5308 ========================================================================
5310 Routine Description:
5311 Verify the support rate for HT phy type
5313 Arguments:
5314 pAd Pointer to our adapter
5316 Return Value:
5317 FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode)
5319 IRQL = PASSIVE_LEVEL
5321 ========================================================================
5323 BOOLEAN RTMPCheckHt(struct rt_rtmp_adapter *pAd,
5324 u8 Wcid,
5325 struct rt_ht_capability_ie * pHtCapability,
5326 struct rt_add_ht_info_ie * pAddHtInfo)
5328 if (Wcid >= MAX_LEN_OF_MAC_TABLE)
5329 return FALSE;
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);
5353 if (Wcid < MAX_LEN_OF_MAC_TABLE) {
5354 pAd->MacTab.Content[Wcid].MpduDensity =
5355 pHtCapability->HtCapParm.MpduDensity;
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;
5380 pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth =
5381 pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.
5382 ChannelWidth;
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));
5393 pAd->MlmeAux.HtCapability.HtCapInfo.GF =
5394 pHtCapability->HtCapInfo.GF & pAd->CommonCfg.DesiredHtPhy.GF;
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;
5429 if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20)
5430 pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; /* BW20 can't transmit MCS32 */
5432 COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability);
5433 return TRUE;
5437 ========================================================================
5439 Routine Description:
5440 Verify the support rate for different PHY type
5442 Arguments:
5443 pAd Pointer to our adapter
5445 Return Value:
5446 None
5448 IRQL = PASSIVE_LEVEL
5450 ========================================================================
5452 void RTMPUpdateMlmeRate(struct rt_rtmp_adapter *pAd)
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;
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;
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;
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;
5512 if (bMatch)
5513 break;
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;
5528 if (bMatch)
5529 break;
5533 if (bMatch == FALSE) {
5534 ProperMlmeRate = MinimumRate;
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;
5556 DBGPRINT(RT_DEBUG_TRACE,
5557 ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n",
5558 pAd->CommonCfg.MlmeTransmit.word));
5561 char RTMPMaxRssi(struct rt_rtmp_adapter *pAd,
5562 char Rssi0, char Rssi1, char Rssi2)
5564 char larger = -127;
5566 if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) {
5567 larger = Rssi0;
5570 if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) {
5571 larger = max(Rssi0, Rssi1);
5574 if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) {
5575 larger = max(larger, Rssi2);
5578 if (larger == -127)
5579 larger = 0;
5581 return larger;
5585 ========================================================================
5586 Routine Description:
5587 Periodic evaluate antenna link status
5589 Arguments:
5590 pAd - Adapter pointer
5592 Return Value:
5593 None
5595 ========================================================================
5597 void AsicEvaluateRxAnt(struct rt_rtmp_adapter *pAd)
5599 u8 BBPR3 = 0;
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 // */
5614 return;
5617 /*if (pAd->StaCfg.Psm == PWR_SAVE) */
5618 /* return; */
5622 if (pAd->StaCfg.Psm == PWR_SAVE)
5623 return;
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);
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)
5641 unsigned long TxTotalCnt =
5642 pAd->RalinkCounters.OneSecTxNoRetryOkCount +
5643 pAd->RalinkCounters.OneSecTxRetryOkCount +
5644 pAd->RalinkCounters.OneSecTxFailCount;
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;
5664 ========================================================================
5665 Routine Description:
5666 After evaluation, check antenna link status
5668 Arguments:
5669 pAd - Adapter pointer
5671 Return Value:
5672 None
5674 ========================================================================
5676 void AsicRxAntEvalTimeout(void *SystemSpecific1,
5677 void *FunctionContext,
5678 void *SystemSpecific2, void *SystemSpecific3)
5680 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
5681 u8 BBPR3 = 0;
5682 char larger = -127, rssi0, rssi1, rssi2;
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 // */
5696 return;
5699 /*if (pAd->StaCfg.Psm == PWR_SAVE) */
5700 /* return; */
5702 if (pAd->StaCfg.Psm == PWR_SAVE)
5703 return;
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;
5716 if (pAd->Antenna.field.RxPath == 3) {
5717 larger = max(rssi0, rssi1);
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;
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);
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 // */
5748 void APSDPeriodicExec(void *SystemSpecific1,
5749 void *FunctionContext,
5750 void *SystemSpecific2, void *SystemSpecific3)
5752 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
5754 if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
5755 return;
5757 pAd->CommonCfg.TriggerTimerCount++;
5759 /* Driver should not send trigger frame, it should be send by application layer */
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))))
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;
5774 ========================================================================
5775 Routine Description:
5776 Set/reset MAC registers according to bPiggyBack parameter
5778 Arguments:
5779 pAd - Adapter pointer
5780 bPiggyBack - Enable / Disable Piggy-Back
5782 Return Value:
5783 None
5785 ========================================================================
5787 void RTMPSetPiggyBack(struct rt_rtmp_adapter *pAd, IN BOOLEAN bPiggyBack)
5789 TX_LINK_CFG_STRUC TxLinkCfg;
5791 RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
5793 TxLinkCfg.field.TxCFAckEn = bPiggyBack;
5794 RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
5798 ========================================================================
5799 Routine Description:
5800 check if this entry need to switch rate automatically
5802 Arguments:
5804 pEntry
5806 Return Value:
5807 TURE
5808 FALSE
5810 ========================================================================
5812 BOOLEAN RTMPCheckEntryEnableAutoRateSwitch(struct rt_rtmp_adapter *pAd,
5813 struct rt_mac_table_entry *pEntry)
5815 BOOLEAN result = TRUE;
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;
5826 return result;
5829 BOOLEAN RTMPAutoRateSwitchCheck(struct rt_rtmp_adapter *pAd)
5832 if (pAd->StaCfg.bAutoTxRateSwitch)
5833 return TRUE;
5835 return FALSE;
5839 ========================================================================
5840 Routine Description:
5841 check if this entry need to fix tx legacy rate
5843 Arguments:
5845 pEntry
5847 Return Value:
5848 TURE
5849 FALSE
5851 ========================================================================
5853 u8 RTMPStaFixedTxMode(struct rt_rtmp_adapter *pAd, struct rt_mac_table_entry *pEntry)
5855 u8 tx_mode = FIXED_TXMODE_HT;
5858 tx_mode =
5859 (u8)pAd->StaCfg.DesiredTransmitSetting.field.
5860 FixedTxMode;
5863 return tx_mode;
5867 ========================================================================
5868 Routine Description:
5869 Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified.
5871 Arguments:
5873 pEntry
5875 Return Value:
5876 TURE
5877 FALSE
5879 ========================================================================
5881 void RTMPUpdateLegacyTxSetting(u8 fixed_tx_mode, struct rt_mac_table_entry *pEntry)
5883 HTTRANSMIT_SETTING TransmitSetting;
5885 if (fixed_tx_mode == FIXED_TXMODE_HT)
5886 return;
5888 TransmitSetting.word = 0;
5890 TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE;
5891 TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS;
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;
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));
5915 ==========================================================================
5916 Description:
5917 dynamic tune BBP R66 to find a balance between sensibility and
5918 noise isolation
5920 IRQL = DISPATCH_LEVEL
5922 ==========================================================================
5924 void AsicStaBbpTuning(struct rt_rtmp_adapter *pAd)
5926 u8 OrigR66Value = 0, R66; /*, R66UpperBound = 0x30, R66LowerBound = 0x30; */
5927 char Rssi;
5929 /* 2860C did not support Fase CCA, therefore can't tune */
5930 if (pAd->MACVersion == 0x28600100)
5931 return;
5933 /* */
5934 /* work as a STA */
5935 /* */
5936 if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) /* no R66 tuning when SCANNING */
5937 return;
5939 if ((pAd->OpMode == OPMODE_STA)
5940 && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
5942 && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
5943 #ifdef RTMP_MAC_PCI
5944 && (pAd->bPCIclkOff == FALSE)
5945 #endif /* RTMP_MAC_PCI // */
5947 RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value);
5948 R66 = OrigR66Value;
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;
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 */
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);
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);
5978 } else
5979 #endif /* RT30xx // */
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);
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);
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);
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);
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);
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);
6036 void RTMPSetAGCInitValue(struct rt_rtmp_adapter *pAd, u8 BandWidth)
6038 u8 R66 = 0x30;
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 */
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 // */
6051 R66 = 0x2E + GET_LNA_GAIN(pAd);
6052 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6054 } else { /*A band */
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);