2 *************************************************************************
4 * 5F., No.36, Taiyuan St., Jhubei City,
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. *
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. *
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. *
25 *************************************************************************
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"
42 UCHAR CISCO_OUI[] = { 0x00, 0x40, 0x96 };
44 UCHAR WPA_OUI[] = { 0x00, 0x50, 0xf2, 0x01 };
45 UCHAR RSN_OUI[] = { 0x00, 0x0f, 0xac };
46 UCHAR WME_INFO_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01 };
47 UCHAR WME_PARM_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01 };
48 UCHAR Ccx2QosInfo[] = { 0x00, 0x40, 0x96, 0x04 };
49 UCHAR RALINK_OUI[] = { 0x00, 0x0c, 0x43 };
50 UCHAR BROADCOM_OUI[] = { 0x00, 0x90, 0x4c };
51 UCHAR WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
52 UCHAR PRE_N_HT_OUI[] = { 0x00, 0x90, 0x4c };
54 UCHAR 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,
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,
91 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 UCHAR 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 ULONG 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 */ ,
308 UCHAR BROADCAST_ADDR[MAC_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
309 UCHAR 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 UCHAR RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100 };
319 USHORT RateIdTo500Kbps[] =
320 { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200 };
322 UCHAR SsidIe = IE_SSID;
323 UCHAR SupRateIe = IE_SUPP_RATES;
324 UCHAR ExtRateIe = IE_EXT_SUPP_RATES;
325 UCHAR HtCapIe = IE_HT_CAP;
326 UCHAR AddHtInfoIe = IE_ADD_HT;
327 UCHAR NewExtChanIe = IE_SECONDARY_CH_OFFSET;
328 UCHAR ErpIe = IE_ERP;
329 UCHAR DsIe = IE_DS_PARM;
330 UCHAR TimIe = IE_TIM;
331 UCHAR WpaIe = IE_WPA;
332 UCHAR Wpa2Ie = IE_WPA2;
333 UCHAR IbssIe = IE_IBSS_PARM;
335 extern UCHAR WPA_OUI[];
337 UCHAR SES_OUI[] = { 0x00, 0x90, 0x4c };
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 ==========================================================================
349 initialize the MLME task and its data structure (queue, spinlock,
350 timer, state machines).
355 always return NDIS_STATUS_SUCCESS
357 ==========================================================================
359 NDIS_STATUS MlmeInit(IN PRTMP_ADAPTER pAd)
361 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
363 DBGPRINT(RT_DEBUG_TRACE, ("--> MLME Initialize\n"));
366 Status = MlmeQueueInit(&pAd->Mlme.Queue);
367 if (Status != NDIS_STATUS_SUCCESS)
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,
381 AuthRspStateMachineInit(pAd, &pAd->Mlme.AuthRspMachine,
382 pAd->Mlme.AuthRspFunc);
383 SyncStateMachineInit(pAd, &pAd->Mlme.SyncMachine,
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,
394 ActionStateMachineInit(pAd, &pAd->Mlme.ActMachine,
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,
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,
415 (PsPollWakeExec), pAd, FALSE);
416 RTMPInitTimer(pAd, &pAd->Mlme.RadioOnOffTimer,
417 GET_TIMER_FUNCTION(RadioOnExec),
420 #endif // RTMP_PCI_SUPPORT //
422 RTMPInitTimer(pAd, &pAd->Mlme.LinkDownTimer,
423 GET_TIMER_FUNCTION(LinkDownExec), pAd,
427 RTMPInitTimer(pAd, &pAd->Mlme.AutoWakeupTimer,
429 (RtmpUsbStaAsicForceWakeupTimeout), pAd,
431 pAd->Mlme.AutoWakeupTimerRunning = FALSE;
432 #endif // RTMP_MAC_USB //
437 DBGPRINT(RT_DEBUG_TRACE, ("<-- MLME Initialize\n"));
443 ==========================================================================
445 main loop of the MLME
447 Mlme has to be initialized, and there are something inside the queue
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(IN PRTMP_ADAPTER pAd)
458 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);
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));
481 //From message type, determine which state machine I should drive
482 if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) {
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;
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,
502 case AUTH_STATE_MACHINE:
503 StateMachinePerformAction(pAd,
507 case AUTH_RSP_STATE_MACHINE:
508 StateMachinePerformAction(pAd,
510 AuthRspMachine, Elem);
512 case SYNC_STATE_MACHINE:
513 StateMachinePerformAction(pAd,
517 case MLME_CNTL_STATE_MACHINE:
518 MlmeCntlMachinePerformAction(pAd,
522 case WPA_PSK_STATE_MACHINE:
523 StateMachinePerformAction(pAd,
525 WpaPskMachine, Elem);
528 case ACTION_STATE_MACHINE:
529 StateMachinePerformAction(pAd,
530 &pAd->Mlme.ActMachine,
534 case WPA_STATE_MACHINE:
535 StateMachinePerformAction(pAd,
536 &pAd->Mlme.WpaMachine,
541 DBGPRINT(RT_DEBUG_TRACE,
542 ("ERROR: Illegal machine %ld in MlmeHandler()\n",
548 Elem->Occupied = FALSE;
552 DBGPRINT_ERR(("MlmeHandler: MlmeQueue empty\n"));
556 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
557 pAd->Mlme.bRunning = FALSE;
558 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
562 ==========================================================================
564 Destructor of MLME (Destroy queue, state machine, spin lock and timer)
566 Adapter - NIC Adapter pointer
568 The MLME task will no longer work properly
572 ==========================================================================
574 VOID MlmeHalt(IN PRTMP_ADAPTER pAd)
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);
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);
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 RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
616 RTMPSetLED(pAd, LED_HALT);
617 RTMPSetSignalLED(pAd, -100); // Force signal strength Led to be turned off, firmware is not done it.
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(IN PRTMP_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;
676 ==========================================================================
678 This routine is executed periodically to -
679 1. Decide if it's a right time to turn on PwrMgmt bit of all
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(IN PVOID SystemSpecific1,
693 IN PVOID FunctionContext,
694 IN PVOID SystemSpecific2, IN PVOID SystemSpecific3)
697 PRTMP_ADAPTER pAd = (RTMP_ADAPTER *) FunctionContext;
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) */
711 // Read GPIO pin2 as Hardware controlled radio state
713 RTMP_IO_READ32(pAd, GPIO_CTRL_CFG, &data);
715 //KH(PCIE PS):Added based on Jane<--
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 ==
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);
729 RTMP_IO_FORCE_READ32(pAd, GPIO_CTRL_CFG, &data);
731 //KH(PCIE PS):Added based on Jane-->
734 pAd->StaCfg.bHwRadio = TRUE;
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) {
744 // Update extra information
745 pAd->ExtraInfo = EXTRA_INFO_CLEAR;
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))))
764 RTMP_MLME_PRE_SANITY_CHECK(pAd);
767 // Do nothing if monitor mode is on
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++;
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);
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);
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);
852 // pAd->RalinkCounters.MgmtRingFullCount = 0;
854 // The time period for checking antenna is according to traffic
856 if (pAd->Mlme.bEnableAutoAntennaCheck) {
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 %
866 AsicEvaluateRxAnt(pAd);
869 if (pAd->Mlme.OneSecPeriodicRound % 3 ==
871 AsicEvaluateRxAnt(pAd);
877 STAMlmePeriodicExec(pAd);
879 MlmeResetRalinkCounters(pAd);
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.
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);
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(IN PUCHAR pSsid, IN UCHAR SsidLen)
928 if (SsidLen > MAX_LEN_OF_SSID)
931 // Check each character value
932 for (index = 0; index < SsidLen; index++) {
933 if (pSsid[index] < 0x20)
941 VOID MlmeSelectTxRateTable(IN PRTMP_ADAPTER pAd,
942 IN PMAC_TABLE_ENTRY pEntry,
944 IN PUCHAR pTableSize, IN PUCHAR pInitTxRateIdx)
947 // decide the rate table for tuning
948 if (pAd->CommonCfg.TxRateTableSize > 0) {
949 *ppTable = RateSwitchTable;
950 *pTableSize = RateSwitchTable[0];
951 *pInitTxRateIdx = RateSwitchTable[1];
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];
967 RateSwitchTable11N2S[1];
969 *ppTable = RateSwitchTable11N2SForABand;
971 RateSwitchTable11N2SForABand[0];
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];
990 *ppTable = RateSwitchTable11G;
991 *pTableSize = RateSwitchTable11G[0];
992 *pInitTxRateIdx = RateSwitchTable11G[1];
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];
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];
1015 *ppTable = RateSwitchTable11BGN2SForABand;
1016 *pTableSize = RateSwitchTable11BGN2SForABand[0];
1018 RateSwitchTable11BGN2SForABand[1];
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];
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];
1038 *ppTable = RateSwitchTable11N2SForABand;
1039 *pTableSize = RateSwitchTable11N2SForABand[0];
1041 RateSwitchTable11N2SForABand[1];
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) */
1051 *ppTable = RateSwitchTable11B;
1052 *pTableSize = RateSwitchTable11B[0];
1053 *pInitTxRateIdx = RateSwitchTable11B[1];
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)
1062 *ppTable = RateSwitchTable11BG;
1063 *pTableSize = RateSwitchTable11BG[0];
1064 *pInitTxRateIdx = RateSwitchTable11BG[1];
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)
1073 *ppTable = RateSwitchTable11G;
1074 *pTableSize = RateSwitchTable11G[0];
1075 *pInitTxRateIdx = RateSwitchTable11G[1];
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 >
1090 *ppTable = RateSwitchTable11G;
1091 *pTableSize = RateSwitchTable11G[0];
1092 *pInitTxRateIdx = RateSwitchTable11G[1];
1095 *ppTable = RateSwitchTable11BG;
1096 *pTableSize = RateSwitchTable11BG[0];
1098 RateSwitchTable11BG[1];
1102 if (pAd->LatchRfRegs.Channel <= 14) {
1103 if (pAd->CommonCfg.TxStream == 1) {
1104 *ppTable = RateSwitchTable11N1S;
1105 *pTableSize = RateSwitchTable11N1S[0];
1107 RateSwitchTable11N1S[1];
1108 DBGPRINT_RAW(RT_DEBUG_ERROR,
1109 ("DRS: unkown mode,default use 11N 1S AP \n"));
1111 *ppTable = RateSwitchTable11N2S;
1112 *pTableSize = RateSwitchTable11N2S[0];
1114 RateSwitchTable11N2S[1];
1115 DBGPRINT_RAW(RT_DEBUG_ERROR,
1116 ("DRS: unkown mode,default use 11N 2S AP \n"));
1119 if (pAd->CommonCfg.TxStream == 1) {
1120 *ppTable = RateSwitchTable11N1S;
1121 *pTableSize = RateSwitchTable11N1S[0];
1123 RateSwitchTable11N1S[1];
1124 DBGPRINT_RAW(RT_DEBUG_ERROR,
1125 ("DRS: unkown mode,default use 11N 1S AP \n"));
1127 *ppTable = RateSwitchTable11N2SForABand;
1129 RateSwitchTable11N2SForABand[0];
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.
1147 VOID STAMlmePeriodicExec(PRTMP_ADAPTER pAd)
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) {
1160 if ((IS_RT3070(pAd) && ((pAd->MACVersion & 0xffff) < 0x0201)))
1163 if ((pAd->StaCfg.RssiSample.AvgRssi0 != 0)
1164 && (pAd->StaCfg.RssiSample.AvgRssi0 >
1165 (pAd->BbpRssiToDbmDelta - 35))) {
1166 RT30xxWriteRFRegister(pAd, RF_R27, 0x20);
1168 RT30xxWriteRFRegister(pAd, RF_R27, 0x23);
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 ==
1184 DBGPRINT(RT_DEBUG_TRACE,
1185 ("%s\n", __func__));
1186 RT28xxPciAsicRadioOff(pAd,
1187 GUI_IDLE_POWER_SAVE,
1190 AsicSendCommandToMcu(pAd, 0x30,
1193 // Wait command success
1194 AsicCheckCommanOk(pAd, PowerSafeCID);
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 ==
1203 DBGPRINT(RT_DEBUG_TRACE,
1204 ("%s\n", __func__));
1205 RT28xxPciAsicRadioOff(pAd,
1206 GUI_IDLE_POWER_SAVE,
1209 AsicSendCommandToMcu(pAd, 0x30,
1212 // Wait command success
1213 AsicCheckCommanOk(pAd, PowerSafeCID);
1215 fRTMP_ADAPTER_IDLE_RADIO_OFF);
1216 DBGPRINT(RT_DEBUG_TRACE,
1217 ("PSM - rt28xx Issue Sleep command)\n"));
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 +
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].
1250 pAd->PreMediaState = pAd->IndicateMediaState;
1253 if (pAd->CommonCfg.PSPXlink && ADHOC_ON(pAd)) {
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
1282 pAd->StaCfg.LastBeaconRxTime + (1 * OS_HZ)))
1284 (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1286 (((TxTotalCnt + pAd->RalinkCounters.OneSecRxOkCnt) <
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,
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,
1312 RTMPSendNullFrame(pAd,
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) {
1344 CHAR dBmToRoam = pAd->StaCfg.dBmToRoam;
1345 CHAR MaxRssi = RTMPMaxRssi(pAd,
1346 pAd->StaCfg.RssiSample.
1348 pAd->StaCfg.RssiSample.
1350 pAd->StaCfg.RssiSample.
1353 // Scanning, ignore Roaming
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,
1362 // Add auto seamless roaming
1364 rv = MlmeCheckForFastRoaming(pAd);
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 =
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
1385 pAd->StaCfg.LastBeaconRxTime + ADHOC_BEACON_LOST_TIME)
1386 && OPSTATUS_TEST_FLAG(pAd,
1387 fOP_STATUS_MEDIA_STATE_CONNECTED)) {
1388 MLME_START_REQ_STRUCT 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(MLME_START_REQ_STRUCT), &StartReq);
1399 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
1402 for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
1403 MAC_TABLE_ENTRY *pEntry = &pAd->MacTab.Content[i];
1405 if (pEntry->ValidAsCLI == FALSE)
1410 pEntry->LastBeaconRxTime + ADHOC_BEACON_LOST_TIME))
1411 MacTableDeleteEntry(pAd, pEntry->Aid,
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;
1422 pAd->StaCfg.bScanReqIsFromWebUI = FALSE;
1424 if ((pAd->StaCfg.bAutoReconnect == TRUE)
1425 && RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_START_UP)
1428 (pAd->MlmeAux.AutoReconnectSsid,
1429 pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) {
1430 if ((pAd->ScanTab.BssNr == 0)
1431 && (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE)) {
1432 MLME_SCAN_REQ_STRUCT ScanReq;
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",
1440 AutoReconnectSsid));
1441 ScanParmFill(pAd, &ScanReq,
1442 (PSTRING) pAd->MlmeAux.
1445 AutoReconnectSsidLen,
1446 BSS_ANY, SCAN_ACTIVE);
1447 MlmeEnqueue(pAd, SYNC_STATE_MACHINE,
1450 (MLME_SCAN_REQ_STRUCT),
1452 pAd->Mlme.CntlMachine.CurrState =
1453 CNTL_WAIT_OID_LIST_SCAN;
1454 // Reset Missed scan number
1455 pAd->StaCfg.LastScanTime =
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) {
1462 pAd->StaCfg.LastScanTime =
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,
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);
1490 VOID LinkDownExec(IN PVOID SystemSpecific1,
1491 IN PVOID FunctionContext,
1492 IN PVOID SystemSpecific2, IN PVOID SystemSpecific3)
1494 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *) FunctionContext;
1497 MLME_DISASSOC_REQ_STRUCT DisassocReq;
1499 if ((pAd->StaCfg.PortSecured == WPA_802_1X_PORT_NOT_SECURED) &&
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(MLME_DISASSOC_REQ_STRUCT),
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(IN PRTMP_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"));
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(IN PRTMP_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;
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) &&
1556 (pAd->MlmeAux.AutoReconnectSsid,
1557 pAd->MlmeAux.AutoReconnectSsidLen) == TRUE)) {
1558 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(NDIS_802_11_SSID), &OidSsid);
1569 RTMP_MLME_HANDLER(pAd);
1574 ==========================================================================
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
1583 ==========================================================================
1585 VOID MlmeCheckForRoaming(IN PRTMP_ADAPTER pAd, IN ULONG Now32)
1588 BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab;
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) <
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
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,
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",
1632 ==========================================================================
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
1641 ==========================================================================
1643 BOOLEAN MlmeCheckForFastRoaming(IN PRTMP_ADAPTER pAd)
1646 BSS_TABLE *pRoamTab = &pAd->MlmeAux.RoamTab;
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
1661 (pBss->Ssid, pBss->SsidLen, pAd->CommonCfg.Ssid,
1662 pAd->CommonCfg.SsidLen))
1663 continue; // skip different SSID
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),
1677 // AP passing all above rules is put into roaming candidate table
1678 NdisMoveMemory(&pRoamTab->BssEntry[pRoamTab->BssNr], pBss,
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);
1702 VOID MlmeSetTxRate(IN PRTMP_ADAPTER pAd,
1703 IN PMAC_TABLE_ENTRY pEntry, IN PRTMP_TX_RATE_SWITCH pTxRate)
1705 UCHAR 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;
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;
1727 // For Adhoc MODE_CCK, driver will use AdhocBOnlyJoined flag to roll back to B only if necessary
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;
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;
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.
1771 AsicUpdateProtect(pAd,
1772 pAd->MlmeAux.AddHtInfo.
1773 AddHtInfo2.OperaionMode,
1774 ALLN_SETPROTECT, TRUE,
1775 (BOOLEAN) pAd->MlmeAux.
1776 AddHtInfo.AddHtInfo2.
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.
1790 AsicUpdateProtect(pAd,
1791 pAd->MlmeAux.AddHtInfo.
1792 AddHtInfo2.OperaionMode,
1793 ALLN_SETPROTECT, TRUE,
1794 (BOOLEAN) pAd->MlmeAux.
1795 AddHtInfo.AddHtInfo2.
1798 } else if ((pEntry->HTPhyMode.field.MCS != 0)
1799 && (pAd->StaCfg.HTPhyMode.field.MCS == 0)) {
1800 AsicUpdateProtect(pAd, HT_RTSCTS_6M, ALLN_SETPROTECT,
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,
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 = (USHORT) (pEntry->HTPhyMode.word);
1827 ==========================================================================
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}
1837 IRQL = DISPATCH_LEVEL
1840 call this routine every second
1841 ==========================================================================
1843 VOID MlmeDynamicTxRateSwitching(IN PRTMP_ADAPTER pAd)
1845 UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
1846 ULONG i, AccuTxTotalCnt = 0, TxTotalCnt;
1847 ULONG TxErrorRatio = 0;
1848 BOOLEAN bTxRateChanged = FALSE, bUpgradeQuality = FALSE;
1849 PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL;
1851 UCHAR TableSize = 0;
1852 UCHAR InitTxRateIdx = 0, TrainUp, TrainDown;
1853 CHAR Rssi, RssiOffset = 0;
1854 TX_STA_CNT1_STRUC StaTx1;
1855 TX_STA_CNT0_STRUC TxStaCnt0;
1856 ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
1857 MAC_TABLE_ENTRY *pEntry;
1858 RSSI_SAMPLE *pRssi = &pAd->StaCfg.RssiSample;
1861 // walk through MAC table, see if need to change AP's TX rate toward each entry
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)
1870 if ((pAd->MacTab.Size == 1) || (pEntry->ValidAsDls)) {
1871 Rssi = RTMPMaxRssi(pAd,
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
1901 pAd->RalinkCounters.OneSecTxNoRetryOkCount +
1902 pAd->RalinkCounters.OneSecTxRetryOkCount +
1903 pAd->RalinkCounters.OneSecTxFailCount;
1908 TxFailCount) * 100) / TxTotalCnt;
1910 if (INFRA_ON(pAd) && (i == 1))
1911 Rssi = RTMPMaxRssi(pAd,
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;
1927 ((pEntry->OneSecTxRetryOkCount +
1928 pEntry->OneSecTxFailCount) * 100) /
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;
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);
1953 RTMP_IO_READ32(pAd, TXRXQ_PCNT,
1955 if ((MACValue & 0xffffff) == 0)
1958 RTMPusecDelay(1000);
1959 } while ((Index < 330)
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,
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.
1985 (PRTMP_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.
1993 (PRTMP_TX_RATE_SWITCH) & pTable[(InitTxRateIdx + 1)
1995 pEntry->CurrTxRateIndex = InitTxRateIdx;
1996 MlmeSetTxRate(pAd, pEntry, pCurrTxRate);
1998 // reset all OneSecTx counters
1999 RESET_ONE_SEC_TX_CNT(pEntry);
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;
2015 (PRTMP_TX_RATE_SWITCH) & pTable[(CurrRateIdx + 1) * 5];
2017 if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) {
2019 (pCurrTxRate->TrainUp +
2020 (pCurrTxRate->TrainUp >> 1));
2022 (pCurrTxRate->TrainDown +
2023 (pCurrTxRate->TrainDown >> 1));
2025 TrainUp = pCurrTxRate->TrainUp;
2026 TrainDown = pCurrTxRate->TrainDown;
2029 //pAd->DrsCounters.LastTimeTxRateChangeAction = pAd->DrsCounters.LastSecTxRateChangeAction;
2032 // Keep the last time TxRateChangeAction status.
2034 pEntry->LastTimeTxRateChangeAction =
2035 pEntry->LastSecTxRateChangeAction;
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)
2041 if (TxTotalCnt <= 15) {
2044 UCHAR MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 =
2045 0, MCS5 = 0, MCS6 = 0, MCS7 = 0;
2046 UCHAR MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
2047 UCHAR 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]) {
2052 (PRTMP_TX_RATE_SWITCH) & pTable[(idx + 1) *
2055 if (pCurrTxRate->CurrMCS == MCS_0) {
2057 } else if (pCurrTxRate->CurrMCS == MCS_1) {
2059 } else if (pCurrTxRate->CurrMCS == MCS_2) {
2061 } else if (pCurrTxRate->CurrMCS == MCS_3) {
2063 } else if (pCurrTxRate->CurrMCS == MCS_4) {
2065 } else if (pCurrTxRate->CurrMCS == MCS_5) {
2067 } else if (pCurrTxRate->CurrMCS == MCS_6) {
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
2074 } else if (pCurrTxRate->CurrMCS == MCS_12) {
2076 } else if (pCurrTxRate->CurrMCS == MCS_13) {
2078 } else if (pCurrTxRate->CurrMCS == MCS_14) {
2081 //else if ((pCurrTxRate->CurrMCS == MCS_15)/* && (pCurrTxRate->ShortGI == GI_800)*/) //we hope to use ShortGI as initial rate
2082 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
2085 } else if (pCurrTxRate->CurrMCS == MCS_20) // 3*3
2088 } else if (pCurrTxRate->CurrMCS == MCS_21) {
2090 } else if (pCurrTxRate->CurrMCS == MCS_22) {
2092 } else if (pCurrTxRate->CurrMCS == MCS_23) {
2098 if (pAd->LatchRfRegs.Channel <= 14) {
2099 if (pAd->NicConfig2.field.ExternalLNAForG) {
2105 if (pAd->NicConfig2.field.ExternalLNAForA) {
2113 if ((pTable == RateSwitchTable11BGN3S) || (pTable == RateSwitchTable11N3S) || (pTable == RateSwitchTable)) { // N mode with 3 stream // 3*3
2114 if (MCS23 && (Rssi >= -70))
2116 else if (MCS22 && (Rssi >= -72))
2118 else if (MCS21 && (Rssi >= -76))
2120 else if (MCS20 && (Rssi >= -78))
2122 else if (MCS4 && (Rssi >= -82))
2124 else if (MCS3 && (Rssi >= -84))
2126 else if (MCS2 && (Rssi >= -86))
2128 else if (MCS1 && (Rssi >= -88))
2133 // else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable))
2134 else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) || (pTable == RateSwitchTable11N2S) || (pTable == RateSwitchTable11N2SForABand)) // 3*3
2135 { // N mode with 2 stream
2136 if (MCS15 && (Rssi >= (-70 + RssiOffset)))
2138 else if (MCS14 && (Rssi >= (-72 + RssiOffset)))
2140 else if (MCS13 && (Rssi >= (-76 + RssiOffset)))
2142 else if (MCS12 && (Rssi >= (-78 + RssiOffset)))
2144 else if (MCS4 && (Rssi >= (-82 + RssiOffset)))
2146 else if (MCS3 && (Rssi >= (-84 + RssiOffset)))
2148 else if (MCS2 && (Rssi >= (-86 + RssiOffset)))
2150 else if (MCS1 && (Rssi >= (-88 + RssiOffset)))
2154 } else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) { // N mode with 1 stream
2155 if (MCS7 && (Rssi > (-72 + RssiOffset)))
2157 else if (MCS6 && (Rssi > (-74 + RssiOffset)))
2159 else if (MCS5 && (Rssi > (-77 + RssiOffset)))
2161 else if (MCS4 && (Rssi > (-79 + RssiOffset)))
2163 else if (MCS3 && (Rssi > (-81 + RssiOffset)))
2165 else if (MCS2 && (Rssi > (-83 + RssiOffset)))
2167 else if (MCS1 && (Rssi > (-86 + RssiOffset)))
2171 } else { // Legacy mode
2172 if (MCS7 && (Rssi > -70))
2174 else if (MCS6 && (Rssi > -74))
2176 else if (MCS5 && (Rssi > -78))
2178 else if (MCS4 && (Rssi > -82))
2180 else if (MCS4 == 0) // for B-only mode
2182 else if (MCS3 && (Rssi > -85))
2184 else if (MCS2 && (Rssi > -87))
2186 else if (MCS1 && (Rssi > -90))
2192 // if (TxRateIdx != pAd->CommonCfg.TxRateIndex)
2194 pEntry->CurrTxRateIndex = TxRateIdx;
2196 (PRTMP_TX_RATE_SWITCH) &
2197 pTable[(pEntry->CurrTxRateIndex + 1) * 5];
2198 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2201 NdisZeroMemory(pEntry->TxQuality,
2203 MAX_STEP_OF_TX_RATE_SWITCH);
2204 NdisZeroMemory(pEntry->PER,
2206 MAX_STEP_OF_TX_RATE_SWITCH);
2207 pEntry->fLastSecAccordingRSSI = TRUE;
2208 // reset all OneSecTx counters
2209 RESET_ONE_SEC_TX_CNT(pEntry);
2214 if (pEntry->fLastSecAccordingRSSI == TRUE) {
2215 pEntry->fLastSecAccordingRSSI = FALSE;
2216 pEntry->LastSecTxRateChangeAction = 0;
2217 // reset all OneSecTx counters
2218 RESET_ONE_SEC_TX_CNT(pEntry);
2224 BOOLEAN bTrainUpDown = FALSE;
2226 pEntry->CurrTxRateStableTime++;
2228 // downgrade TX quality if PER >= Rate-Down threshold
2229 if (TxErrorRatio >= TrainDown) {
2230 bTrainUpDown = TRUE;
2231 pEntry->TxQuality[CurrRateIdx] =
2232 DRS_TX_QUALITY_WORST_BOUND;
2234 // upgrade TX quality if PER <= Rate-Up threshold
2235 else if (TxErrorRatio <= TrainUp) {
2236 bTrainUpDown = TRUE;
2237 bUpgradeQuality = TRUE;
2238 if (pEntry->TxQuality[CurrRateIdx])
2239 pEntry->TxQuality[CurrRateIdx]--; // quality very good in CurrRate
2241 if (pEntry->TxRateUpPenalty)
2242 pEntry->TxRateUpPenalty--;
2243 else if (pEntry->TxQuality[UpRateIdx])
2244 pEntry->TxQuality[UpRateIdx]--; // may improve next UP rate's quality
2247 pEntry->PER[CurrRateIdx] = (UCHAR) TxErrorRatio;
2250 // perform DRS - consider TxRate Down first, then rate up.
2251 if ((CurrRateIdx != DownRateIdx)
2252 && (pEntry->TxQuality[CurrRateIdx] >=
2253 DRS_TX_QUALITY_WORST_BOUND)) {
2254 pEntry->CurrTxRateIndex = DownRateIdx;
2255 } else if ((CurrRateIdx != UpRateIdx)
2256 && (pEntry->TxQuality[UpRateIdx] <=
2258 pEntry->CurrTxRateIndex = UpRateIdx;
2263 // if rate-up happen, clear all bad history of all TX rates
2264 if (pEntry->CurrTxRateIndex > CurrRateIdx) {
2265 pEntry->CurrTxRateStableTime = 0;
2266 pEntry->TxRateUpPenalty = 0;
2267 pEntry->LastSecTxRateChangeAction = 1; // rate UP
2268 NdisZeroMemory(pEntry->TxQuality,
2270 MAX_STEP_OF_TX_RATE_SWITCH);
2271 NdisZeroMemory(pEntry->PER,
2273 MAX_STEP_OF_TX_RATE_SWITCH);
2276 // For TxRate fast train up
2278 if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2279 RTMPSetTimer(&pAd->StaCfg.
2280 StaQuickResponeForRateUpTimer,
2284 StaQuickResponeForRateUpTimerRunning = TRUE;
2286 bTxRateChanged = TRUE;
2288 // if rate-down happen, only clear DownRate's bad history
2289 else if (pEntry->CurrTxRateIndex < CurrRateIdx) {
2290 pEntry->CurrTxRateStableTime = 0;
2291 pEntry->TxRateUpPenalty = 0; // no penalty
2292 pEntry->LastSecTxRateChangeAction = 2; // rate DOWN
2293 pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
2294 pEntry->PER[pEntry->CurrTxRateIndex] = 0;
2297 // For TxRate fast train down
2299 if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2300 RTMPSetTimer(&pAd->StaCfg.
2301 StaQuickResponeForRateUpTimer,
2305 StaQuickResponeForRateUpTimerRunning = TRUE;
2307 bTxRateChanged = TRUE;
2309 pEntry->LastSecTxRateChangeAction = 0; // rate no change
2310 bTxRateChanged = FALSE;
2313 pEntry->LastTxOkCount = TxSuccess;
2317 // to fix tcp ack issue
2319 && (pAd->RalinkCounters.OneSecReceivedByteCount >
2320 (pAd->RalinkCounters.
2321 OneSecTransmittedByteCount * 5))) {
2322 tmpTxRate = DownRateIdx;
2323 DBGPRINT_RAW(RT_DEBUG_TRACE,
2324 ("DRS: Rx(%d) is 5 times larger than Tx(%d), use low rate (curr=%d, tmp=%d)\n",
2325 pAd->RalinkCounters.
2326 OneSecReceivedByteCount,
2327 pAd->RalinkCounters.
2328 OneSecTransmittedByteCount,
2329 pEntry->CurrTxRateIndex,
2332 tmpTxRate = pEntry->CurrTxRateIndex;
2336 (PRTMP_TX_RATE_SWITCH) & pTable[(tmpTxRate + 1) *
2339 if (bTxRateChanged && pNextTxRate) {
2340 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2342 // reset all OneSecTx counters
2343 RESET_ONE_SEC_TX_CNT(pEntry);
2348 ========================================================================
2349 Routine Description:
2350 Station side, Auto TxRate faster train up timer call back function.
2353 SystemSpecific1 - Not used.
2354 FunctionContext - Pointer to our Adapter context.
2355 SystemSpecific2 - Not used.
2356 SystemSpecific3 - Not used.
2361 ========================================================================
2363 VOID StaQuickResponeForRateUpExec(IN PVOID SystemSpecific1,
2364 IN PVOID FunctionContext,
2365 IN PVOID SystemSpecific2,
2366 IN PVOID SystemSpecific3)
2368 PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) FunctionContext;
2369 UCHAR UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
2371 ULONG TxErrorRatio = 0;
2372 BOOLEAN bTxRateChanged; //, bUpgradeQuality = FALSE;
2373 PRTMP_TX_RATE_SWITCH pCurrTxRate, pNextTxRate = NULL;
2375 UCHAR TableSize = 0;
2376 UCHAR InitTxRateIdx = 0, TrainUp, TrainDown;
2377 TX_STA_CNT1_STRUC StaTx1;
2378 TX_STA_CNT0_STRUC TxStaCnt0;
2380 ULONG TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
2381 MAC_TABLE_ENTRY *pEntry;
2384 pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE;
2387 // walk through MAC table, see if need to change AP's TX rate toward each entry
2389 for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
2390 pEntry = &pAd->MacTab.Content[i];
2392 // check if this entry need to switch rate automatically
2393 if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
2396 if (INFRA_ON(pAd) && (i == 1))
2397 Rssi = RTMPMaxRssi(pAd,
2398 pAd->StaCfg.RssiSample.AvgRssi0,
2399 pAd->StaCfg.RssiSample.AvgRssi1,
2400 pAd->StaCfg.RssiSample.AvgRssi2);
2402 Rssi = RTMPMaxRssi(pAd,
2403 pEntry->RssiSample.AvgRssi0,
2404 pEntry->RssiSample.AvgRssi1,
2405 pEntry->RssiSample.AvgRssi2);
2407 CurrRateIdx = pAd->CommonCfg.TxRateIndex;
2409 MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
2412 // decide the next upgrade rate and downgrade rate, if any
2413 if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) {
2414 UpRateIdx = CurrRateIdx + 1;
2415 DownRateIdx = CurrRateIdx - 1;
2416 } else if (CurrRateIdx == 0) {
2417 UpRateIdx = CurrRateIdx + 1;
2418 DownRateIdx = CurrRateIdx;
2419 } else if (CurrRateIdx == (TableSize - 1)) {
2420 UpRateIdx = CurrRateIdx;
2421 DownRateIdx = CurrRateIdx - 1;
2425 (PRTMP_TX_RATE_SWITCH) & pTable[(CurrRateIdx + 1) * 5];
2427 if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) {
2429 (pCurrTxRate->TrainUp +
2430 (pCurrTxRate->TrainUp >> 1));
2432 (pCurrTxRate->TrainDown +
2433 (pCurrTxRate->TrainDown >> 1));
2435 TrainUp = pCurrTxRate->TrainUp;
2436 TrainDown = pCurrTxRate->TrainDown;
2439 if (pAd->MacTab.Size == 1) {
2440 // Update statistic counter
2441 RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
2442 RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
2444 TxRetransmit = StaTx1.field.TxRetransmit;
2445 TxSuccess = StaTx1.field.TxSuccess;
2446 TxFailCount = TxStaCnt0.field.TxFailCount;
2447 TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
2449 pAd->RalinkCounters.OneSecTxRetryOkCount +=
2450 StaTx1.field.TxRetransmit;
2451 pAd->RalinkCounters.OneSecTxNoRetryOkCount +=
2452 StaTx1.field.TxSuccess;
2453 pAd->RalinkCounters.OneSecTxFailCount +=
2454 TxStaCnt0.field.TxFailCount;
2455 pAd->WlanCounters.TransmittedFragmentCount.u.LowPart +=
2456 StaTx1.field.TxSuccess;
2457 pAd->WlanCounters.RetryCount.u.LowPart +=
2458 StaTx1.field.TxRetransmit;
2459 pAd->WlanCounters.FailedCount.u.LowPart +=
2460 TxStaCnt0.field.TxFailCount;
2465 TxFailCount) * 100) / TxTotalCnt;
2467 TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
2468 pEntry->OneSecTxRetryOkCount +
2469 pEntry->OneSecTxFailCount;
2473 ((pEntry->OneSecTxRetryOkCount +
2474 pEntry->OneSecTxFailCount) * 100) /
2479 // CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI
2480 // (criteria copied from RT2500 for Netopia case)
2482 if (TxTotalCnt <= 12) {
2483 NdisZeroMemory(pAd->DrsCounters.TxQuality,
2485 MAX_STEP_OF_TX_RATE_SWITCH);
2486 NdisZeroMemory(pAd->DrsCounters.PER,
2488 MAX_STEP_OF_TX_RATE_SWITCH);
2490 if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1)
2491 && (CurrRateIdx != DownRateIdx)) {
2492 pAd->CommonCfg.TxRateIndex = DownRateIdx;
2493 pAd->DrsCounters.TxQuality[CurrRateIdx] =
2494 DRS_TX_QUALITY_WORST_BOUND;
2496 if ((pAd->DrsCounters.LastSecTxRateChangeAction ==
2497 2) && (CurrRateIdx != UpRateIdx)) {
2498 pAd->CommonCfg.TxRateIndex = UpRateIdx;
2501 DBGPRINT_RAW(RT_DEBUG_TRACE,
2502 ("QuickDRS: TxTotalCnt <= 15, train back to original rate \n"));
2507 ULONG OneSecTxNoRetryOKRationCount;
2509 if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0)
2514 // downgrade TX quality if PER >= Rate-Down threshold
2515 if (TxErrorRatio >= TrainDown) {
2516 pAd->DrsCounters.TxQuality[CurrRateIdx] =
2517 DRS_TX_QUALITY_WORST_BOUND;
2520 pAd->DrsCounters.PER[CurrRateIdx] =
2521 (UCHAR) TxErrorRatio;
2523 OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);
2525 // perform DRS - consider TxRate Down first, then rate up.
2526 if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1)
2527 && (CurrRateIdx != DownRateIdx)) {
2528 if ((pAd->DrsCounters.LastTxOkCount + 2) >=
2529 OneSecTxNoRetryOKRationCount) {
2530 pAd->CommonCfg.TxRateIndex =
2533 TxQuality[CurrRateIdx] =
2534 DRS_TX_QUALITY_WORST_BOUND;
2539 if ((pAd->DrsCounters.LastSecTxRateChangeAction ==
2540 2) && (CurrRateIdx != UpRateIdx)) {
2541 if ((TxErrorRatio >= 50)
2542 || (TxErrorRatio >= TrainDown)) {
2544 } else if ((pAd->DrsCounters.LastTxOkCount + 2)
2545 >= OneSecTxNoRetryOKRationCount) {
2546 pAd->CommonCfg.TxRateIndex = UpRateIdx;
2551 // if rate-up happen, clear all bad history of all TX rates
2552 if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) {
2553 pAd->DrsCounters.TxRateUpPenalty = 0;
2554 NdisZeroMemory(pAd->DrsCounters.TxQuality,
2556 MAX_STEP_OF_TX_RATE_SWITCH);
2557 NdisZeroMemory(pAd->DrsCounters.PER,
2559 MAX_STEP_OF_TX_RATE_SWITCH);
2560 bTxRateChanged = TRUE;
2562 // if rate-down happen, only clear DownRate's bad history
2563 else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) {
2564 DBGPRINT_RAW(RT_DEBUG_TRACE,
2565 ("QuickDRS: --TX rate from %d to %d \n",
2566 CurrRateIdx, pAd->CommonCfg.TxRateIndex));
2568 pAd->DrsCounters.TxRateUpPenalty = 0; // no penalty
2569 pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] =
2571 pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0;
2572 bTxRateChanged = TRUE;
2574 bTxRateChanged = FALSE;
2578 (PRTMP_TX_RATE_SWITCH) &
2579 pTable[(pAd->CommonCfg.TxRateIndex + 1) * 5];
2580 if (bTxRateChanged && pNextTxRate) {
2581 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2587 ==========================================================================
2589 This routine is executed periodically inside MlmePeriodicExec() after
2590 association with an AP.
2591 It checks if StaCfg.Psm is consistent with user policy (recorded in
2592 StaCfg.WindowsPowerMode). If not, enforce user policy. However,
2593 there're some conditions to consider:
2594 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
2595 the time when Mibss==TRUE
2596 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE
2597 if outgoing traffic available in TxRing or MgmtRing.
2599 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched
2601 IRQL = DISPATCH_LEVEL
2603 ==========================================================================
2605 VOID MlmeCheckPsmChange(IN PRTMP_ADAPTER pAd, IN ULONG Now32)
2610 // 1. Psm maybe ON only happen in INFRASTRUCTURE mode
2611 // 2. user wants either MAX_PSP or FAST_PSP
2612 // 3. but current psm is not in PWR_SAVE
2613 // 4. CNTL state machine is not doing SCANning
2614 // 5. no TX SUCCESS event for the past 1-sec period
2615 PowerMode = pAd->StaCfg.WindowsPowerMode;
2617 if (INFRA_ON(pAd) &&
2618 (PowerMode != Ndis802_11PowerModeCAM) &&
2619 (pAd->StaCfg.Psm == PWR_ACTIVE) &&
2620 // (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
2621 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
2622 RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP)
2624 (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) &&
2625 (pAd->RalinkCounters.OneSecTxRetryOkCount == 0) */
2627 NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime);
2628 pAd->RalinkCounters.RxCountSinceLastNULL = 0;
2629 RTMP_SET_PSM_BIT(pAd, PWR_SAVE);
2631 (pAd->CommonCfg.bAPSDCapable
2632 && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) {
2633 RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE);
2635 RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
2640 // IRQL = PASSIVE_LEVEL
2641 // IRQL = DISPATCH_LEVEL
2642 VOID MlmeSetPsmBit(IN PRTMP_ADAPTER pAd, IN USHORT psm)
2644 AUTO_RSP_CFG_STRUC csr4;
2646 pAd->StaCfg.Psm = psm;
2647 RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
2648 csr4.field.AckCtsPsmBit = (psm == PWR_SAVE) ? 1 : 0;
2649 RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
2651 DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm));
2655 ==========================================================================
2657 This routine calculates TxPER, RxPER of the past N-sec period. And
2658 according to the calculation result, ChannelQuality is calculated here
2659 to decide if current AP is still doing the job.
2661 If ChannelQuality is not good, a ROAMing attempt may be tried later.
2663 StaCfg.ChannelQuality - 0..100
2665 IRQL = DISPATCH_LEVEL
2667 NOTE: This routine decide channle quality based on RX CRC error ratio.
2668 Caller should make sure a function call to NICUpdateRawCounters(pAd)
2669 is performed right before this routine, so that this routine can decide
2670 channel quality based on the most up-to-date information
2671 ==========================================================================
2673 VOID MlmeCalculateChannelQuality(IN PRTMP_ADAPTER pAd,
2674 IN PMAC_TABLE_ENTRY pMacEntry, IN ULONG Now32)
2676 ULONG TxOkCnt, TxCnt, TxPER, TxPRR;
2680 RSSI_SAMPLE *pRssiSample = NULL;
2681 UINT32 OneSecTxNoRetryOkCount = 0;
2682 UINT32 OneSecTxRetryOkCount = 0;
2683 UINT32 OneSecTxFailCount = 0;
2684 UINT32 OneSecRxOkCnt = 0;
2685 UINT32 OneSecRxFcsErrCnt = 0;
2686 ULONG ChannelQuality = 0; // 0..100, Channel Quality Indication for Roaming
2687 ULONG BeaconLostTime = pAd->StaCfg.BeaconLostTime;
2689 if (pAd->OpMode == OPMODE_STA) {
2690 pRssiSample = &pAd->StaCfg.RssiSample;
2691 OneSecTxNoRetryOkCount =
2692 pAd->RalinkCounters.OneSecTxNoRetryOkCount;
2693 OneSecTxRetryOkCount = pAd->RalinkCounters.OneSecTxRetryOkCount;
2694 OneSecTxFailCount = pAd->RalinkCounters.OneSecTxFailCount;
2695 OneSecRxOkCnt = pAd->RalinkCounters.OneSecRxOkCnt;
2696 OneSecRxFcsErrCnt = pAd->RalinkCounters.OneSecRxFcsErrCnt;
2699 MaxRssi = RTMPMaxRssi(pAd, pRssiSample->LastRssi0,
2700 pRssiSample->LastRssi1, pRssiSample->LastRssi2);
2703 // calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics
2705 TxOkCnt = OneSecTxNoRetryOkCount + OneSecTxRetryOkCount;
2706 TxCnt = TxOkCnt + OneSecTxFailCount;
2711 TxPER = (OneSecTxFailCount * 100) / TxCnt;
2712 TxPRR = ((TxCnt - OneSecTxNoRetryOkCount) * 100) / TxCnt;
2716 // calculate RX PER - don't take RxPER into consideration if too few sample
2718 RxCnt = OneSecRxOkCnt + OneSecRxFcsErrCnt;
2722 RxPER = (OneSecRxFcsErrCnt * 100) / RxCnt;
2725 // decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER
2727 if ((pAd->OpMode == OPMODE_STA) && INFRA_ON(pAd) && (OneSecTxNoRetryOkCount < 2) && // no heavy traffic
2728 ((pAd->StaCfg.LastBeaconRxTime + BeaconLostTime) < Now32)) {
2729 DBGPRINT(RT_DEBUG_TRACE,
2730 ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n",
2731 BeaconLostTime, TxOkCnt));
2737 else if (MaxRssi < -90)
2740 NorRssi = (MaxRssi + 90) * 2;
2742 // ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0)
2743 ChannelQuality = (RSSI_WEIGHTING * NorRssi +
2744 TX_WEIGHTING * (100 - TxPRR) +
2745 RX_WEIGHTING * (100 - RxPER)) / 100;
2748 if (pAd->OpMode == OPMODE_STA)
2749 pAd->Mlme.ChannelQuality =
2750 (ChannelQuality > 100) ? 100 : ChannelQuality;
2754 // IRQL = DISPATCH_LEVEL
2755 VOID MlmeSetTxPreamble(IN PRTMP_ADAPTER pAd, IN USHORT TxPreamble)
2757 AUTO_RSP_CFG_STRUC csr4;
2760 // Always use Long preamble before verifiation short preamble functionality works well.
2761 // Todo: remove the following line if short preamble functionality works
2763 //TxPreamble = Rt802_11PreambleLong;
2765 RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
2766 if (TxPreamble == Rt802_11PreambleLong) {
2767 DBGPRINT(RT_DEBUG_TRACE,
2768 ("MlmeSetTxPreamble (= LONG PREAMBLE)\n"));
2769 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
2770 csr4.field.AutoResponderPreamble = 0;
2772 // NOTE: 1Mbps should always use long preamble
2773 DBGPRINT(RT_DEBUG_TRACE,
2774 ("MlmeSetTxPreamble (= SHORT PREAMBLE)\n"));
2775 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
2776 csr4.field.AutoResponderPreamble = 1;
2779 RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
2783 ==========================================================================
2785 Update basic rate bitmap
2786 ==========================================================================
2789 VOID UpdateBasicRateBitmap(IN PRTMP_ADAPTER pAdapter)
2792 /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */
2793 UCHAR rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
2794 UCHAR *sup_p = pAdapter->CommonCfg.SupRate;
2795 UCHAR *ext_p = pAdapter->CommonCfg.ExtRate;
2796 ULONG bitmap = pAdapter->CommonCfg.BasicRateBitmap;
2798 /* if A mode, always use fix BasicRateBitMap */
2799 //if (pAdapter->CommonCfg.Channel == PHY_11A)
2800 if (pAdapter->CommonCfg.Channel > 14)
2801 pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */
2804 if (pAdapter->CommonCfg.BasicRateBitmap > 4095) {
2805 /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */
2809 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2814 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2815 if (bitmap & (1 << i)) {
2816 for (j = 0; j < MAX_LEN_OF_SUPPORTED_RATES; j++) {
2817 if (sup_p[j] == rate[i])
2822 for (j = 0; j < MAX_LEN_OF_SUPPORTED_RATES; j++) {
2823 if (ext_p[j] == rate[i])
2829 } /* End of UpdateBasicRateBitmap */
2831 // IRQL = PASSIVE_LEVEL
2832 // IRQL = DISPATCH_LEVEL
2833 // bLinkUp is to identify the inital link speed.
2834 // TRUE indicates the rate update at linkup, we should not try to set the rate at 54Mbps.
2835 VOID MlmeUpdateTxRates(IN PRTMP_ADAPTER pAd, IN BOOLEAN bLinkUp, IN UCHAR apidx)
2838 UCHAR Rate = RATE_6, MaxDesire = RATE_1, MaxSupport = RATE_1;
2839 UCHAR MinSupport = RATE_54;
2840 ULONG BasicRateBitmap = 0;
2841 UCHAR CurrBasicRate = RATE_1;
2842 UCHAR *pSupRate, SupRateLen, *pExtRate, ExtRateLen;
2843 PHTTRANSMIT_SETTING pHtPhy = NULL;
2844 PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
2845 PHTTRANSMIT_SETTING pMinHtPhy = NULL;
2846 BOOLEAN *auto_rate_cur_p;
2847 UCHAR HtMcs = MCS_AUTO;
2849 // find max desired rate
2850 UpdateBasicRateBitmap(pAd);
2853 auto_rate_cur_p = NULL;
2854 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2855 switch (pAd->CommonCfg.DesireRate[i] & 0x7f) {
2904 //default: Rate = RATE_1; break;
2906 if (MaxDesire < Rate)
2910 //===========================================================================
2911 //===========================================================================
2913 pHtPhy = &pAd->StaCfg.HTPhyMode;
2914 pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
2915 pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
2917 auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
2918 HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS;
2920 if ((pAd->StaCfg.BssType == BSS_ADHOC) &&
2921 (pAd->CommonCfg.PhyMode == PHY_11B) &&
2922 (MaxDesire > RATE_11)) {
2923 MaxDesire = RATE_11;
2927 pAd->CommonCfg.MaxDesiredRate = MaxDesire;
2928 pMinHtPhy->word = 0;
2929 pMaxHtPhy->word = 0;
2932 // Auto rate switching is enabled only if more than one DESIRED RATES are
2933 // specified; otherwise disabled
2935 //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
2936 //pAd->CommonCfg.bAutoTxRateSwitch = FALSE;
2937 *auto_rate_cur_p = FALSE;
2939 //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
2940 //pAd->CommonCfg.bAutoTxRateSwitch = TRUE;
2941 *auto_rate_cur_p = TRUE;
2944 if (HtMcs != MCS_AUTO) {
2945 //OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
2946 //pAd->CommonCfg.bAutoTxRateSwitch = FALSE;
2947 *auto_rate_cur_p = FALSE;
2949 //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED);
2950 //pAd->CommonCfg.bAutoTxRateSwitch = TRUE;
2951 *auto_rate_cur_p = TRUE;
2954 if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) {
2955 pSupRate = &pAd->StaActive.SupRate[0];
2956 pExtRate = &pAd->StaActive.ExtRate[0];
2957 SupRateLen = pAd->StaActive.SupRateLen;
2958 ExtRateLen = pAd->StaActive.ExtRateLen;
2960 pSupRate = &pAd->CommonCfg.SupRate[0];
2961 pExtRate = &pAd->CommonCfg.ExtRate[0];
2962 SupRateLen = pAd->CommonCfg.SupRateLen;
2963 ExtRateLen = pAd->CommonCfg.ExtRateLen;
2966 // find max supported rate
2967 for (i = 0; i < SupRateLen; i++) {
2968 switch (pSupRate[i] & 0x7f) {
2971 if (pSupRate[i] & 0x80)
2972 BasicRateBitmap |= 0x0001;
2976 if (pSupRate[i] & 0x80)
2977 BasicRateBitmap |= 0x0002;
2981 if (pSupRate[i] & 0x80)
2982 BasicRateBitmap |= 0x0004;
2986 if (pSupRate[i] & 0x80)
2987 BasicRateBitmap |= 0x0008;
2990 Rate = RATE_6; /*if (pSupRate[i] & 0x80) */
2991 BasicRateBitmap |= 0x0010;
2995 if (pSupRate[i] & 0x80)
2996 BasicRateBitmap |= 0x0020;
2999 Rate = RATE_12; /*if (pSupRate[i] & 0x80) */
3000 BasicRateBitmap |= 0x0040;
3004 if (pSupRate[i] & 0x80)
3005 BasicRateBitmap |= 0x0080;
3008 Rate = RATE_24; /*if (pSupRate[i] & 0x80) */
3009 BasicRateBitmap |= 0x0100;
3013 if (pSupRate[i] & 0x80)
3014 BasicRateBitmap |= 0x0200;
3018 if (pSupRate[i] & 0x80)
3019 BasicRateBitmap |= 0x0400;
3023 if (pSupRate[i] & 0x80)
3024 BasicRateBitmap |= 0x0800;
3030 if (MaxSupport < Rate)
3033 if (MinSupport > Rate)
3037 for (i = 0; i < ExtRateLen; i++) {
3038 switch (pExtRate[i] & 0x7f) {
3041 if (pExtRate[i] & 0x80)
3042 BasicRateBitmap |= 0x0001;
3046 if (pExtRate[i] & 0x80)
3047 BasicRateBitmap |= 0x0002;
3051 if (pExtRate[i] & 0x80)
3052 BasicRateBitmap |= 0x0004;
3056 if (pExtRate[i] & 0x80)
3057 BasicRateBitmap |= 0x0008;
3060 Rate = RATE_6; /*if (pExtRate[i] & 0x80) */
3061 BasicRateBitmap |= 0x0010;
3065 if (pExtRate[i] & 0x80)
3066 BasicRateBitmap |= 0x0020;
3069 Rate = RATE_12; /*if (pExtRate[i] & 0x80) */
3070 BasicRateBitmap |= 0x0040;
3074 if (pExtRate[i] & 0x80)
3075 BasicRateBitmap |= 0x0080;
3078 Rate = RATE_24; /*if (pExtRate[i] & 0x80) */
3079 BasicRateBitmap |= 0x0100;
3083 if (pExtRate[i] & 0x80)
3084 BasicRateBitmap |= 0x0200;
3088 if (pExtRate[i] & 0x80)
3089 BasicRateBitmap |= 0x0400;
3093 if (pExtRate[i] & 0x80)
3094 BasicRateBitmap |= 0x0800;
3100 if (MaxSupport < Rate)
3103 if (MinSupport > Rate)
3107 RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap);
3110 // pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap;
3112 // calculate the exptected ACK rate for each TX rate. This info is used to caculate
3113 // the DURATION field of outgoing uniicast DATA/MGMT frame
3114 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
3115 if (BasicRateBitmap & (0x01 << i))
3116 CurrBasicRate = (UCHAR) i;
3117 pAd->CommonCfg.ExpectedACKRate[i] = CurrBasicRate;
3120 DBGPRINT(RT_DEBUG_TRACE,
3121 ("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n",
3122 RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire]));
3123 // max tx rate = min {max desire rate, max supported rate}
3124 if (MaxSupport < MaxDesire)
3125 pAd->CommonCfg.MaxTxRate = MaxSupport;
3127 pAd->CommonCfg.MaxTxRate = MaxDesire;
3129 pAd->CommonCfg.MinTxRate = MinSupport;
3130 // 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success
3131 // ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending
3133 // 1. RSSI >= -70db, start at 54 Mbps (short distance)
3134 // 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance)
3135 // 3. -75 > RSSI, start at 11 Mbps (long distance)
3136 //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED)/* &&
3137 // OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)*/)
3138 if (*auto_rate_cur_p) {
3141 dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta;
3143 if (bLinkUp == TRUE)
3144 pAd->CommonCfg.TxRate = RATE_24;
3146 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3149 pAd->CommonCfg.TxRate = RATE_11;
3151 pAd->CommonCfg.TxRate = RATE_24;
3153 // should never exceed MaxTxRate (consider 11B-only mode)
3154 if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate)
3155 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3157 pAd->CommonCfg.TxRateIndex = 0;
3159 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3161 (pAd->CommonCfg.MaxTxRate >
3162 3) ? (pAd->CommonCfg.MaxTxRate -
3163 4) : pAd->CommonCfg.MaxTxRate;
3164 pHtPhy->field.MODE =
3165 (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK;
3167 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC =
3169 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI =
3170 pHtPhy->field.ShortGI;
3171 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS =
3173 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE =
3177 if (pAd->CommonCfg.TxRate <= RATE_11) {
3178 pMaxHtPhy->field.MODE = MODE_CCK;
3179 pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate;
3180 pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
3182 pMaxHtPhy->field.MODE = MODE_OFDM;
3183 pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate];
3184 if (pAd->CommonCfg.MinTxRate >= RATE_6
3185 && (pAd->CommonCfg.MinTxRate <= RATE_54)) {
3186 pMinHtPhy->field.MCS =
3187 OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];
3189 pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
3193 pHtPhy->word = (pMaxHtPhy->word);
3194 if (bLinkUp && (pAd->OpMode == OPMODE_STA)) {
3195 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word;
3196 pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word =
3198 pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word =
3201 switch (pAd->CommonCfg.PhyMode) {
3202 case PHY_11BG_MIXED:
3204 case PHY_11BGN_MIXED:
3205 pAd->CommonCfg.MlmeRate = RATE_1;
3206 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
3207 pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
3210 pAd->CommonCfg.RtsRate = RATE_11;
3212 // pAd->CommonCfg.RtsRate = RATE_1;
3217 case PHY_11AGN_MIXED:
3218 case PHY_11GN_MIXED:
3220 case PHY_11AN_MIXED:
3222 pAd->CommonCfg.MlmeRate = RATE_6;
3223 pAd->CommonCfg.RtsRate = RATE_6;
3224 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
3225 pAd->CommonCfg.MlmeTransmit.field.MCS =
3226 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3228 case PHY_11ABG_MIXED:
3229 case PHY_11ABGN_MIXED:
3230 if (pAd->CommonCfg.Channel <= 14) {
3231 pAd->CommonCfg.MlmeRate = RATE_1;
3232 pAd->CommonCfg.RtsRate = RATE_1;
3233 pAd->CommonCfg.MlmeTransmit.field.MODE =
3235 pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
3237 pAd->CommonCfg.MlmeRate = RATE_6;
3238 pAd->CommonCfg.RtsRate = RATE_6;
3239 pAd->CommonCfg.MlmeTransmit.field.MODE =
3241 pAd->CommonCfg.MlmeTransmit.field.MCS =
3242 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3246 pAd->CommonCfg.MlmeRate = RATE_6;
3247 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
3248 pAd->CommonCfg.MlmeTransmit.field.MCS =
3249 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3250 pAd->CommonCfg.RtsRate = RATE_1;
3254 // Keep Basic Mlme Rate.
3256 pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word =
3257 pAd->CommonCfg.MlmeTransmit.word;
3258 if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM)
3259 pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS =
3260 OfdmRateToRxwiMCS[RATE_24];
3262 pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS =
3264 pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate;
3267 DBGPRINT(RT_DEBUG_TRACE,
3268 (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n",
3269 RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport],
3270 RateIdToMbps[pAd->CommonCfg.MaxTxRate],
3271 RateIdToMbps[pAd->CommonCfg.MinTxRate],
3272 /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) */
3274 DBGPRINT(RT_DEBUG_TRACE,
3275 (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n",
3276 RateIdToMbps[pAd->CommonCfg.TxRate],
3277 RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap));
3278 DBGPRINT(RT_DEBUG_TRACE,
3279 ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n",
3280 pAd->CommonCfg.MlmeTransmit.word,
3281 pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word,
3282 pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word,
3283 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word));
3287 ==========================================================================
3289 This function update HT Rate setting.
3290 Input Wcid value is valid for 2 case :
3291 1. it's used for Station in infra mode that copy AP rate to Mactable.
3292 2. OR Station in adhoc mode to copy peer's HT rate to Mactable.
3294 IRQL = DISPATCH_LEVEL
3296 ==========================================================================
3298 VOID MlmeUpdateHtTxRates(IN PRTMP_ADAPTER pAd, IN UCHAR apidx)
3300 UCHAR StbcMcs; //j, StbcMcs, bitmask;
3302 RT_HT_CAPABILITY *pRtHtCap = NULL;
3303 RT_HT_PHY_INFO *pActiveHtPhy = NULL;
3306 PRT_HT_PHY_INFO pDesireHtPhy = NULL;
3307 PHTTRANSMIT_SETTING pHtPhy = NULL;
3308 PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
3309 PHTTRANSMIT_SETTING pMinHtPhy = NULL;
3310 BOOLEAN *auto_rate_cur_p;
3312 DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateHtTxRates===> \n"));
3314 auto_rate_cur_p = NULL;
3317 pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
3318 pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
3319 pHtPhy = &pAd->StaCfg.HTPhyMode;
3320 pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
3321 pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
3323 auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
3326 if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) {
3327 if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE)
3330 pRtHtCap = &pAd->StaActive.SupportedHtPhy;
3331 pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo;
3332 StbcMcs = (UCHAR) pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs;
3334 pAd->MlmeAux.AddHtInfo.MCSSet[0] +
3335 (pAd->MlmeAux.AddHtInfo.MCSSet[1] << 8) + (StbcMcs << 16);
3336 if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC)
3337 && (pAd->Antenna.field.TxPath == 2))
3338 pMaxHtPhy->field.STBC = STBC_USE;
3340 pMaxHtPhy->field.STBC = STBC_NONE;
3342 if (pDesireHtPhy->bHtEnable == FALSE)
3345 pRtHtCap = &pAd->CommonCfg.DesiredHtPhy;
3346 StbcMcs = (UCHAR) pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs;
3348 pAd->CommonCfg.AddHTInfo.MCSSet[0] +
3349 (pAd->CommonCfg.AddHTInfo.MCSSet[1] << 8) + (StbcMcs << 16);
3350 if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC)
3351 && (pAd->Antenna.field.TxPath == 2))
3352 pMaxHtPhy->field.STBC = STBC_USE;
3354 pMaxHtPhy->field.STBC = STBC_NONE;
3357 // Decide MAX ht rate.
3358 if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF))
3359 pMaxHtPhy->field.MODE = MODE_HTGREENFIELD;
3361 pMaxHtPhy->field.MODE = MODE_HTMIX;
3363 if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth)
3364 && (pRtHtCap->ChannelWidth))
3365 pMaxHtPhy->field.BW = BW_40;
3367 pMaxHtPhy->field.BW = BW_20;
3369 if (pMaxHtPhy->field.BW == BW_20)
3370 pMaxHtPhy->field.ShortGI =
3371 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->
3374 pMaxHtPhy->field.ShortGI =
3375 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->
3378 if (pDesireHtPhy->MCSSet[4] != 0) {
3379 pMaxHtPhy->field.MCS = 32;
3382 for (i = 23; i >= 0; i--) // 3*3
3385 bitmask = (1 << (i - (j * 8)));
3387 if ((pActiveHtPhy->MCSSet[j] & bitmask)
3388 && (pDesireHtPhy->MCSSet[j] & bitmask)) {
3389 pMaxHtPhy->field.MCS = i;
3397 // Copy MIN ht rate. rt2860???
3398 pMinHtPhy->field.BW = BW_20;
3399 pMinHtPhy->field.MCS = 0;
3400 pMinHtPhy->field.STBC = 0;
3401 pMinHtPhy->field.ShortGI = 0;
3402 //If STA assigns fixed rate. update to fixed here.
3403 if ((pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) {
3404 if (pDesireHtPhy->MCSSet[4] != 0) {
3405 pMaxHtPhy->field.MCS = 32;
3406 pMinHtPhy->field.MCS = 32;
3407 DBGPRINT(RT_DEBUG_TRACE,
3408 ("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",
3409 pMinHtPhy->field.MCS));
3412 for (i = 23; (CHAR) i >= 0; i--) // 3*3
3415 bitmask = (1 << (i - (j * 8)));
3416 if ((pDesireHtPhy->MCSSet[j] & bitmask)
3417 && (pActiveHtPhy->MCSSet[j] & bitmask)) {
3418 pMaxHtPhy->field.MCS = i;
3419 pMinHtPhy->field.MCS = i;
3428 pHtPhy->field.STBC = pMaxHtPhy->field.STBC;
3429 pHtPhy->field.BW = pMaxHtPhy->field.BW;
3430 pHtPhy->field.MODE = pMaxHtPhy->field.MODE;
3431 pHtPhy->field.MCS = pMaxHtPhy->field.MCS;
3432 pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI;
3434 // use default now. rt2860
3435 if (pDesireHtPhy->MCSSet[0] != 0xff)
3436 *auto_rate_cur_p = FALSE;
3438 *auto_rate_cur_p = TRUE;
3440 DBGPRINT(RT_DEBUG_TRACE,
3441 (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n",
3442 pAd->CommonCfg.DesiredHtPhy.AmsduSize));
3443 DBGPRINT(RT_DEBUG_TRACE,
3444 ("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n",
3445 pActiveHtPhy->MCSSet[0], pHtPhy->field.MCS, pHtPhy->field.BW,
3446 pHtPhy->field.ShortGI, pHtPhy->field.MODE));
3447 DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateHtTxRates<=== \n"));
3450 VOID BATableInit(IN PRTMP_ADAPTER pAd, IN BA_TABLE * Tab)
3454 Tab->numAsOriginator = 0;
3455 Tab->numAsRecipient = 0;
3456 Tab->numDoneOriginator = 0;
3457 NdisAllocateSpinLock(&pAd->BATabLock);
3458 for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) {
3459 Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE;
3460 NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock));
3462 for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) {
3463 Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE;
3467 // IRQL = DISPATCH_LEVEL
3468 VOID MlmeRadioOff(IN PRTMP_ADAPTER pAd)
3470 RTMP_MLME_RADIO_OFF(pAd);
3473 // IRQL = DISPATCH_LEVEL
3474 VOID MlmeRadioOn(IN PRTMP_ADAPTER pAd)
3476 RTMP_MLME_RADIO_ON(pAd);
3479 // ===========================================================================================
3481 // ===========================================================================================
3483 /*! \brief initialize BSS table
3484 * \param p_tab pointer to the table
3489 IRQL = PASSIVE_LEVEL
3490 IRQL = DISPATCH_LEVEL
3493 VOID BssTableInit(IN BSS_TABLE * Tab)
3498 Tab->BssOverlapNr = 0;
3499 for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) {
3500 NdisZeroMemory(&Tab->BssEntry[i], sizeof(BSS_ENTRY));
3501 Tab->BssEntry[i].Rssi = -127; // initial the rssi as a minimum value
3505 /*! \brief search the BSS table by SSID
3506 * \param p_tab pointer to the bss table
3507 * \param ssid SSID string
3508 * \return index of the table, BSS_NOT_FOUND if not in the table
3511 * \note search by sequential search
3513 IRQL = DISPATCH_LEVEL
3516 ULONG BssTableSearch(IN BSS_TABLE * Tab, IN PUCHAR pBssid, IN UCHAR Channel)
3520 for (i = 0; i < Tab->BssNr; i++) {
3522 // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G.
3523 // We should distinguish this case.
3525 if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3526 ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3527 MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) {
3531 return (ULONG) BSS_NOT_FOUND;
3534 ULONG BssSsidTableSearch(IN BSS_TABLE * Tab,
3536 IN PUCHAR pSsid, IN UCHAR SsidLen, IN UCHAR Channel)
3540 for (i = 0; i < Tab->BssNr; i++) {
3542 // Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G.
3543 // We should distinguish this case.
3545 if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3546 ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3547 MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) &&
3548 SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3549 Tab->BssEntry[i].SsidLen)) {
3553 return (ULONG) BSS_NOT_FOUND;
3556 ULONG BssTableSearchWithSSID(IN BSS_TABLE * Tab,
3559 IN UCHAR SsidLen, IN UCHAR Channel)
3563 for (i = 0; i < Tab->BssNr; i++) {
3564 if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3565 ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3566 MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) &&
3568 (pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3569 Tab->BssEntry[i].SsidLen)
3570 || (NdisEqualMemory(pSsid, ZeroSsid, SsidLen))
3573 (Tab->BssEntry[i].Ssid, ZeroSsid,
3574 Tab->BssEntry[i].SsidLen)))) {
3578 return (ULONG) BSS_NOT_FOUND;
3581 ULONG BssSsidTableSearchBySSID(IN BSS_TABLE * Tab,
3582 IN PUCHAR pSsid, IN UCHAR SsidLen)
3586 for (i = 0; i < Tab->BssNr; i++) {
3588 (pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3589 Tab->BssEntry[i].SsidLen)) {
3593 return (ULONG) BSS_NOT_FOUND;
3596 // IRQL = DISPATCH_LEVEL
3597 VOID BssTableDeleteEntry(IN OUT BSS_TABLE * Tab,
3598 IN PUCHAR pBssid, IN UCHAR Channel)
3602 for (i = 0; i < Tab->BssNr; i++) {
3603 if ((Tab->BssEntry[i].Channel == Channel) &&
3604 (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) {
3605 for (j = i; j < Tab->BssNr - 1; j++) {
3606 NdisMoveMemory(&(Tab->BssEntry[j]),
3607 &(Tab->BssEntry[j + 1]),
3610 NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]),
3619 ========================================================================
3620 Routine Description:
3621 Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed.
3624 // IRQL = DISPATCH_LEVEL
3625 ========================================================================
3627 VOID BATableDeleteORIEntry(IN OUT PRTMP_ADAPTER pAd,
3628 IN BA_ORI_ENTRY * pBAORIEntry)
3631 if (pBAORIEntry->ORI_BA_Status != Originator_NONE) {
3632 NdisAcquireSpinLock(&pAd->BATabLock);
3633 if (pBAORIEntry->ORI_BA_Status == Originator_Done) {
3634 pAd->BATable.numAsOriginator -= 1;
3635 DBGPRINT(RT_DEBUG_TRACE,
3636 ("BATableDeleteORIEntry numAsOriginator= %ld\n",
3637 pAd->BATable.numAsRecipient));
3638 // Erase Bitmap flag.
3640 pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1 << (pBAORIEntry->TID))); // If STA mode, erase flag here
3641 pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; // If STA mode, erase flag here
3642 pBAORIEntry->ORI_BA_Status = Originator_NONE;
3643 pBAORIEntry->Token = 1;
3644 // Not clear Sequence here.
3645 NdisReleaseSpinLock(&pAd->BATabLock);
3655 IRQL = DISPATCH_LEVEL
3658 VOID BssEntrySet(IN PRTMP_ADAPTER pAd, OUT BSS_ENTRY * pBss, IN PUCHAR pBssid, IN CHAR Ssid[], IN UCHAR SsidLen, IN UCHAR BssType, IN USHORT BeaconPeriod, IN PCF_PARM pCfParm, IN USHORT AtimWin, IN USHORT CapabilityInfo, IN UCHAR SupRate[], IN UCHAR SupRateLen, IN UCHAR ExtRate[], IN UCHAR ExtRateLen, IN HT_CAPABILITY_IE * pHtCapability, IN ADD_HT_INFO_IE * pAddHtInfo, // AP might use this additional ht info IE
3659 IN UCHAR HtCapabilityLen,
3660 IN UCHAR AddHtInfoLen,
3661 IN UCHAR NewExtChanOffset,
3664 IN LARGE_INTEGER TimeStamp,
3666 IN PEDCA_PARM pEdcaParm,
3667 IN PQOS_CAPABILITY_PARM pQosCapability,
3668 IN PQBSS_LOAD_PARM pQbssLoad,
3669 IN USHORT LengthVIE, IN PNDIS_802_11_VARIABLE_IEs pVIE)
3671 COPY_MAC_ADDR(pBss->Bssid, pBssid);
3672 // Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID
3675 // For hidden SSID AP, it might send beacon with SSID len equal to 0
3676 // Or send beacon /probe response with SSID len matching real SSID length,
3677 // but SSID is all zero. such as "00-00-00-00" with length 4.
3678 // We have to prevent this case overwrite correct table
3679 if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) {
3680 NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID);
3681 NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
3682 pBss->SsidLen = SsidLen;
3687 pBss->BssType = BssType;
3688 pBss->BeaconPeriod = BeaconPeriod;
3689 if (BssType == BSS_INFRA) {
3690 if (pCfParm->bValid) {
3691 pBss->CfpCount = pCfParm->CfpCount;
3692 pBss->CfpPeriod = pCfParm->CfpPeriod;
3693 pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
3694 pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
3697 pBss->AtimWin = AtimWin;
3700 pBss->CapabilityInfo = CapabilityInfo;
3701 // The privacy bit indicate security is ON, it maight be WEP, TKIP or AES
3702 // Combine with AuthMode, they will decide the connection methods.
3703 pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
3704 ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
3705 if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
3706 NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen);
3708 NdisMoveMemory(pBss->SupRate, SupRate,
3709 MAX_LEN_OF_SUPPORTED_RATES);
3710 pBss->SupRateLen = SupRateLen;
3711 ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
3712 NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen);
3713 pBss->NewExtChanOffset = NewExtChanOffset;
3714 pBss->ExtRateLen = ExtRateLen;
3715 pBss->Channel = Channel;
3716 pBss->CentralChannel = Channel;
3718 // Update CkipFlag. if not exists, the value is 0x0
3719 pBss->CkipFlag = CkipFlag;
3721 // New for microsoft Fixed IEs
3722 NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
3723 pBss->FixIEs.BeaconInterval = BeaconPeriod;
3724 pBss->FixIEs.Capabilities = CapabilityInfo;
3726 // New for microsoft Variable IEs
3727 if (LengthVIE != 0) {
3728 pBss->VarIELen = LengthVIE;
3729 NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen);
3734 pBss->AddHtInfoLen = 0;
3735 pBss->HtCapabilityLen = 0;
3736 if (HtCapabilityLen > 0) {
3737 pBss->HtCapabilityLen = HtCapabilityLen;
3738 NdisMoveMemory(&pBss->HtCapability, pHtCapability,
3740 if (AddHtInfoLen > 0) {
3741 pBss->AddHtInfoLen = AddHtInfoLen;
3742 NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo,
3745 if ((pAddHtInfo->ControlChan > 2)
3746 && (pAddHtInfo->AddHtInfo.ExtChanOffset ==
3748 && (pHtCapability->HtCapInfo.ChannelWidth ==
3750 pBss->CentralChannel =
3751 pAddHtInfo->ControlChan - 2;
3753 if ((pAddHtInfo->AddHtInfo.ExtChanOffset ==
3755 && (pHtCapability->HtCapInfo.ChannelWidth ==
3757 pBss->CentralChannel =
3758 pAddHtInfo->ControlChan + 2;
3763 BssCipherParse(pBss);
3767 NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(EDCA_PARM));
3769 pBss->EdcaParm.bValid = FALSE;
3771 NdisMoveMemory(&pBss->QosCapability, pQosCapability,
3772 sizeof(QOS_CAPABILITY_PARM));
3774 pBss->QosCapability.bValid = FALSE;
3776 NdisMoveMemory(&pBss->QbssLoad, pQbssLoad,
3777 sizeof(QBSS_LOAD_PARM));
3779 pBss->QbssLoad.bValid = FALSE;
3785 NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN);
3786 NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN);
3787 pEid = (PEID_STRUCT) pVIE;
3788 while ((Length + 2 + (USHORT) pEid->Len) <= LengthVIE) {
3789 switch (pEid->Eid) {
3791 if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) {
3792 if ((pEid->Len + 2) > MAX_CUSTOM_LEN) {
3793 pBss->WpaIE.IELen = 0;
3796 pBss->WpaIE.IELen = pEid->Len + 2;
3797 NdisMoveMemory(pBss->WpaIE.IE, pEid,
3803 (pEid->Octet + 2, RSN_OUI, 3)) {
3804 if ((pEid->Len + 2) > MAX_CUSTOM_LEN) {
3805 pBss->RsnIE.IELen = 0;
3808 pBss->RsnIE.IELen = pEid->Len + 2;
3809 NdisMoveMemory(pBss->RsnIE.IE, pEid,
3814 Length = Length + 2 + (USHORT) pEid->Len; // Eid[1] + Len[1]+ content[Len]
3815 pEid = (PEID_STRUCT) ((UCHAR *) pEid + 2 + pEid->Len);
3821 * \brief insert an entry into the bss table
3822 * \param p_tab The BSS table
3823 * \param Bssid BSSID
3825 * \param ssid_len Length of SSID
3827 * \param beacon_period
3834 * \param channel_idx
3838 * \note If SSID is identical, the old entry will be replaced by the new one
3840 IRQL = DISPATCH_LEVEL
3843 ULONG BssTableSetEntry(IN PRTMP_ADAPTER pAd, OUT BSS_TABLE * Tab, IN PUCHAR pBssid, IN CHAR Ssid[], IN UCHAR SsidLen, IN UCHAR BssType, IN USHORT BeaconPeriod, IN CF_PARM * CfParm, IN USHORT AtimWin, IN USHORT CapabilityInfo, IN UCHAR SupRate[], IN UCHAR SupRateLen, IN UCHAR ExtRate[], IN UCHAR ExtRateLen, IN HT_CAPABILITY_IE * pHtCapability, IN ADD_HT_INFO_IE * pAddHtInfo, // AP might use this additional ht info IE
3844 IN UCHAR HtCapabilityLen,
3845 IN UCHAR AddHtInfoLen,
3846 IN UCHAR NewExtChanOffset,
3849 IN LARGE_INTEGER TimeStamp,
3851 IN PEDCA_PARM pEdcaParm,
3852 IN PQOS_CAPABILITY_PARM pQosCapability,
3853 IN PQBSS_LOAD_PARM pQbssLoad,
3854 IN USHORT LengthVIE, IN PNDIS_802_11_VARIABLE_IEs pVIE)
3859 BssTableSearchWithSSID(Tab, pBssid, (UCHAR *) Ssid, SsidLen,
3861 if (Idx == BSS_NOT_FOUND) {
3862 if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) {
3864 // It may happen when BSS Table was full.
3865 // The desired AP will not be added into BSS Table
3866 // In this case, if we found the desired AP then overwrite BSS Table.
3868 if (!OPSTATUS_TEST_FLAG
3869 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
3870 if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid)
3871 || SSID_EQUAL(pAd->MlmeAux.Ssid,
3872 pAd->MlmeAux.SsidLen, Ssid,
3874 Idx = Tab->BssOverlapNr;
3875 BssEntrySet(pAd, &Tab->BssEntry[Idx],
3876 pBssid, Ssid, SsidLen,
3877 BssType, BeaconPeriod,
3879 CapabilityInfo, SupRate,
3880 SupRateLen, ExtRate,
3881 ExtRateLen, pHtCapability,
3882 pAddHtInfo, HtCapabilityLen,
3884 NewExtChanOffset, ChannelNo,
3885 Rssi, TimeStamp, CkipFlag,
3886 pEdcaParm, pQosCapability,
3887 pQbssLoad, LengthVIE, pVIE);
3889 (Tab->BssOverlapNr++) %
3890 MAX_LEN_OF_BSS_TABLE;
3894 return BSS_NOT_FOUND;
3898 BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen,
3899 BssType, BeaconPeriod, CfParm, AtimWin,
3900 CapabilityInfo, SupRate, SupRateLen, ExtRate,
3901 ExtRateLen, pHtCapability, pAddHtInfo,
3902 HtCapabilityLen, AddHtInfoLen, NewExtChanOffset,
3903 ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm,
3904 pQosCapability, pQbssLoad, LengthVIE, pVIE);
3907 /* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */
3909 (Ssid, SsidLen, Tab->BssEntry[Idx].Ssid,
3910 Tab->BssEntry[Idx].SsidLen))
3913 (Tab->BssEntry[Idx].Ssid, ZeroSsid,
3914 Tab->BssEntry[Idx].SsidLen))) {
3915 BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid,
3916 SsidLen, BssType, BeaconPeriod, CfParm,
3917 AtimWin, CapabilityInfo, SupRate,
3918 SupRateLen, ExtRate, ExtRateLen,
3919 pHtCapability, pAddHtInfo, HtCapabilityLen,
3920 AddHtInfoLen, NewExtChanOffset, ChannelNo,
3921 Rssi, TimeStamp, CkipFlag, pEdcaParm,
3922 pQosCapability, pQbssLoad, LengthVIE, pVIE);
3929 // IRQL = DISPATCH_LEVEL
3930 VOID BssTableSsidSort(IN PRTMP_ADAPTER pAd,
3931 OUT BSS_TABLE * OutTab, IN CHAR Ssid[], IN UCHAR SsidLen)
3934 BssTableInit(OutTab);
3936 for (i = 0; i < pAd->ScanTab.BssNr; i++) {
3937 BSS_ENTRY *pInBss = &pAd->ScanTab.BssEntry[i];
3938 BOOLEAN bIsHiddenApIncluded = FALSE;
3940 if (((pAd->CommonCfg.bIEEE80211H == 1) &&
3941 (pAd->MlmeAux.Channel > 14) &&
3942 RadarChannelCheck(pAd, pInBss->Channel))
3945 bIsHiddenApIncluded = TRUE;
3948 if ((pInBss->BssType == pAd->StaCfg.BssType) &&
3949 (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen)
3950 || bIsHiddenApIncluded)) {
3951 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
3953 // 2.4G/5G N only mode
3954 if ((pInBss->HtCapabilityLen == 0) &&
3955 ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G)
3956 || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) {
3957 DBGPRINT(RT_DEBUG_TRACE,
3958 ("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
3962 // Check the Authmode first
3963 if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) {
3964 // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
3965 if ((pAd->StaCfg.AuthMode != pInBss->AuthMode)
3966 && (pAd->StaCfg.AuthMode !=
3967 pInBss->AuthModeAux))
3971 // Check cipher suite, AP must have more secured cipher than station setting
3972 if ((pAd->StaCfg.AuthMode ==
3973 Ndis802_11AuthModeWPA)
3974 || (pAd->StaCfg.AuthMode ==
3975 Ndis802_11AuthModeWPAPSK)) {
3976 // If it's not mixed mode, we should only let BSS pass with the same encryption
3977 if (pInBss->WPA.bMixMode == FALSE)
3978 if (pAd->StaCfg.WepStatus !=
3979 pInBss->WPA.GroupCipher)
3982 // check group cipher
3983 if ((pAd->StaCfg.WepStatus <
3984 pInBss->WPA.GroupCipher)
3985 && (pInBss->WPA.GroupCipher !=
3986 Ndis802_11GroupWEP40Enabled)
3987 && (pInBss->WPA.GroupCipher !=
3988 Ndis802_11GroupWEP104Enabled))
3991 // check pairwise cipher, skip if none matched
3992 // If profile set to AES, let it pass without question.
3993 // If profile set to TKIP, we must find one mateched
3994 if ((pAd->StaCfg.WepStatus ==
3995 Ndis802_11Encryption2Enabled)
3996 && (pAd->StaCfg.WepStatus !=
3997 pInBss->WPA.PairCipher)
3998 && (pAd->StaCfg.WepStatus !=
3999 pInBss->WPA.PairCipherAux))
4002 if ((pAd->StaCfg.AuthMode ==
4003 Ndis802_11AuthModeWPA2)
4004 || (pAd->StaCfg.AuthMode ==
4005 Ndis802_11AuthModeWPA2PSK)) {
4006 // If it's not mixed mode, we should only let BSS pass with the same encryption
4007 if (pInBss->WPA2.bMixMode == FALSE)
4008 if (pAd->StaCfg.WepStatus !=
4009 pInBss->WPA2.GroupCipher)
4012 // check group cipher
4013 if ((pAd->StaCfg.WepStatus <
4014 pInBss->WPA.GroupCipher)
4015 && (pInBss->WPA2.GroupCipher !=
4016 Ndis802_11GroupWEP40Enabled)
4017 && (pInBss->WPA2.GroupCipher !=
4018 Ndis802_11GroupWEP104Enabled))
4021 // check pairwise cipher, skip if none matched
4022 // If profile set to AES, let it pass without question.
4023 // If profile set to TKIP, we must find one mateched
4024 if ((pAd->StaCfg.WepStatus ==
4025 Ndis802_11Encryption2Enabled)
4026 && (pAd->StaCfg.WepStatus !=
4027 pInBss->WPA2.PairCipher)
4028 && (pAd->StaCfg.WepStatus !=
4029 pInBss->WPA2.PairCipherAux))
4033 // Bss Type matched, SSID matched.
4034 // We will check wepstatus for qualification Bss
4035 else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) {
4036 DBGPRINT(RT_DEBUG_TRACE,
4037 ("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n",
4038 pAd->StaCfg.WepStatus,
4039 pInBss->WepStatus));
4041 // For the SESv2 case, we will not qualify WepStatus.
4046 // Since the AP is using hidden SSID, and we are trying to connect to ANY
4047 // It definitely will fail. So, skip it.
4048 // CCX also require not even try to connect it!!
4052 // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region
4053 // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead,
4054 if ((pInBss->CentralChannel != pInBss->Channel) &&
4055 (pAd->CommonCfg.RegTransmitSetting.field.BW ==
4057 if (RTMPCheckChannel
4058 (pAd, pInBss->CentralChannel,
4059 pInBss->Channel) == FALSE) {
4060 pAd->CommonCfg.RegTransmitSetting.field.
4063 pAd->CommonCfg.RegTransmitSetting.field.
4066 if (pAd->CommonCfg.DesiredHtPhy.
4067 ChannelWidth == BAND_WIDTH_20) {
4072 // copy matching BSS from InTab to OutTab
4073 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
4076 } else if ((pInBss->BssType == pAd->StaCfg.BssType)
4077 && (SsidLen == 0)) {
4078 BSS_ENTRY *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
4080 // 2.4G/5G N only mode
4081 if ((pInBss->HtCapabilityLen == 0) &&
4082 ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G)
4083 || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) {
4084 DBGPRINT(RT_DEBUG_TRACE,
4085 ("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
4089 // Check the Authmode first
4090 if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) {
4091 // Check AuthMode and AuthModeAux for matching, in case AP support dual-mode
4092 if ((pAd->StaCfg.AuthMode != pInBss->AuthMode)
4093 && (pAd->StaCfg.AuthMode !=
4094 pInBss->AuthModeAux))
4098 // Check cipher suite, AP must have more secured cipher than station setting
4099 if ((pAd->StaCfg.AuthMode ==
4100 Ndis802_11AuthModeWPA)
4101 || (pAd->StaCfg.AuthMode ==
4102 Ndis802_11AuthModeWPAPSK)) {
4103 // If it's not mixed mode, we should only let BSS pass with the same encryption
4104 if (pInBss->WPA.bMixMode == FALSE)
4105 if (pAd->StaCfg.WepStatus !=
4106 pInBss->WPA.GroupCipher)
4109 // check group cipher
4110 if (pAd->StaCfg.WepStatus <
4111 pInBss->WPA.GroupCipher)
4114 // check pairwise cipher, skip if none matched
4115 // If profile set to AES, let it pass without question.
4116 // If profile set to TKIP, we must find one mateched
4117 if ((pAd->StaCfg.WepStatus ==
4118 Ndis802_11Encryption2Enabled)
4119 && (pAd->StaCfg.WepStatus !=
4120 pInBss->WPA.PairCipher)
4121 && (pAd->StaCfg.WepStatus !=
4122 pInBss->WPA.PairCipherAux))
4125 if ((pAd->StaCfg.AuthMode ==
4126 Ndis802_11AuthModeWPA2)
4127 || (pAd->StaCfg.AuthMode ==
4128 Ndis802_11AuthModeWPA2PSK)) {
4129 // If it's not mixed mode, we should only let BSS pass with the same encryption
4130 if (pInBss->WPA2.bMixMode == FALSE)
4131 if (pAd->StaCfg.WepStatus !=
4132 pInBss->WPA2.GroupCipher)
4135 // check group cipher
4136 if (pAd->StaCfg.WepStatus <
4137 pInBss->WPA2.GroupCipher)
4140 // check pairwise cipher, skip if none matched
4141 // If profile set to AES, let it pass without question.
4142 // If profile set to TKIP, we must find one mateched
4143 if ((pAd->StaCfg.WepStatus ==
4144 Ndis802_11Encryption2Enabled)
4145 && (pAd->StaCfg.WepStatus !=
4146 pInBss->WPA2.PairCipher)
4147 && (pAd->StaCfg.WepStatus !=
4148 pInBss->WPA2.PairCipherAux))
4152 // Bss Type matched, SSID matched.
4153 // We will check wepstatus for qualification Bss
4154 else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
4157 // If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region
4158 // If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead,
4159 if ((pInBss->CentralChannel != pInBss->Channel) &&
4160 (pAd->CommonCfg.RegTransmitSetting.field.BW ==
4162 if (RTMPCheckChannel
4163 (pAd, pInBss->CentralChannel,
4164 pInBss->Channel) == FALSE) {
4165 pAd->CommonCfg.RegTransmitSetting.field.
4168 pAd->CommonCfg.RegTransmitSetting.field.
4172 // copy matching BSS from InTab to OutTab
4173 NdisMoveMemory(pOutBss, pInBss, sizeof(BSS_ENTRY));
4178 if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
4182 BssTableSortByRssi(OutTab);
4185 // IRQL = DISPATCH_LEVEL
4186 VOID BssTableSortByRssi(IN OUT BSS_TABLE * OutTab)
4191 for (i = 0; i < OutTab->BssNr - 1; i++) {
4192 for (j = i + 1; j < OutTab->BssNr; j++) {
4193 if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) {
4194 NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j],
4196 NdisMoveMemory(&OutTab->BssEntry[j],
4197 &OutTab->BssEntry[i],
4199 NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss,
4206 VOID BssCipherParse(IN OUT PBSS_ENTRY pBss)
4210 PRSN_IE_HEADER_STRUCT pRsnHeader;
4211 PCIPHER_SUITE_STRUCT pCipher;
4212 PAKM_SUITE_STRUCT pAKM;
4215 NDIS_802_11_ENCRYPTION_STATUS TmpCipher;
4218 // WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame.
4220 if (pBss->Privacy) {
4221 pBss->WepStatus = Ndis802_11WEPEnabled;
4223 pBss->WepStatus = Ndis802_11WEPDisabled;
4225 // Set default to disable & open authentication before parsing variable IE
4226 pBss->AuthMode = Ndis802_11AuthModeOpen;
4227 pBss->AuthModeAux = Ndis802_11AuthModeOpen;
4230 pBss->WPA.PairCipher = Ndis802_11WEPDisabled;
4231 pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled;
4232 pBss->WPA.GroupCipher = Ndis802_11WEPDisabled;
4233 pBss->WPA.RsnCapability = 0;
4234 pBss->WPA.bMixMode = FALSE;
4236 // Init WPA2 setting
4237 pBss->WPA2.PairCipher = Ndis802_11WEPDisabled;
4238 pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled;
4239 pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled;
4240 pBss->WPA2.RsnCapability = 0;
4241 pBss->WPA2.bMixMode = FALSE;
4243 Length = (INT) pBss->VarIELen;
4245 while (Length > 0) {
4246 // Parse cipher suite base on WPA1 & WPA2, they should be parsed differently
4247 pTmp = ((PUCHAR) pBss->VarIEs) + pBss->VarIELen - Length;
4248 pEid = (PEID_STRUCT) pTmp;
4249 switch (pEid->Eid) {
4251 if (NdisEqualMemory(pEid->Octet, SES_OUI, 3)
4252 && (pEid->Len == 7)) {
4255 } else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) !=
4257 // if unsupported vendor specific IE
4260 // Skip OUI, version, and multicast suite
4261 // This part should be improved in the future when AP supported multiple cipher suite.
4262 // For now, it's OK since almost all APs have fixed cipher suite supported.
4263 // pTmp = (PUCHAR) pEid->Octet;
4266 // Cipher Suite Selectors from Spec P802.11i/D3.2 P26.
4274 // Parse group cipher
4277 pBss->WPA.GroupCipher =
4278 Ndis802_11GroupWEP40Enabled;
4281 pBss->WPA.GroupCipher =
4282 Ndis802_11GroupWEP104Enabled;
4285 pBss->WPA.GroupCipher =
4286 Ndis802_11Encryption2Enabled;
4289 pBss->WPA.GroupCipher =
4290 Ndis802_11Encryption3Enabled;
4295 // number of unicast suite
4298 // skip all unicast cipher suites
4299 //Count = *(PUSHORT) pTmp;
4300 Count = (pTmp[1] << 8) + pTmp[0];
4301 pTmp += sizeof(USHORT);
4303 // Parsing all unicast cipher suite
4307 TmpCipher = Ndis802_11WEPDisabled;
4310 case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway
4312 Ndis802_11Encryption1Enabled;
4316 Ndis802_11Encryption2Enabled;
4320 Ndis802_11Encryption3Enabled;
4325 if (TmpCipher > pBss->WPA.PairCipher) {
4326 // Move the lower cipher suite to PairCipherAux
4327 pBss->WPA.PairCipherAux =
4328 pBss->WPA.PairCipher;
4329 pBss->WPA.PairCipher = TmpCipher;
4331 pBss->WPA.PairCipherAux = TmpCipher;
4337 // 4. get AKM suite counts
4338 //Count = *(PUSHORT) pTmp;
4339 Count = (pTmp[1] << 8) + pTmp[0];
4340 pTmp += sizeof(USHORT);
4345 // Set AP support WPA-enterprise mode
4346 if (pBss->AuthMode == Ndis802_11AuthModeOpen)
4347 pBss->AuthMode = Ndis802_11AuthModeWPA;
4350 Ndis802_11AuthModeWPA;
4353 // Set AP support WPA-PSK mode
4354 if (pBss->AuthMode == Ndis802_11AuthModeOpen)
4356 Ndis802_11AuthModeWPAPSK;
4359 Ndis802_11AuthModeWPAPSK;
4366 // Fixed for WPA-None
4367 if (pBss->BssType == BSS_ADHOC) {
4368 pBss->AuthMode = Ndis802_11AuthModeWPANone;
4369 pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
4370 pBss->WepStatus = pBss->WPA.GroupCipher;
4371 // Patched bugs for old driver
4372 if (pBss->WPA.PairCipherAux ==
4373 Ndis802_11WEPDisabled)
4374 pBss->WPA.PairCipherAux =
4375 pBss->WPA.GroupCipher;
4377 pBss->WepStatus = pBss->WPA.PairCipher;
4379 // Check the Pair & Group, if different, turn on mixed mode flag
4380 if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher)
4381 pBss->WPA.bMixMode = TRUE;
4386 pRsnHeader = (PRSN_IE_HEADER_STRUCT) pTmp;
4388 // 0. Version must be 1
4389 if (le2cpu16(pRsnHeader->Version) != 1)
4391 pTmp += sizeof(RSN_IE_HEADER_STRUCT);
4393 // 1. Check group cipher
4394 pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
4395 if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
4398 // Parse group cipher
4399 switch (pCipher->Type) {
4401 pBss->WPA2.GroupCipher =
4402 Ndis802_11GroupWEP40Enabled;
4405 pBss->WPA2.GroupCipher =
4406 Ndis802_11GroupWEP104Enabled;
4409 pBss->WPA2.GroupCipher =
4410 Ndis802_11Encryption2Enabled;
4413 pBss->WPA2.GroupCipher =
4414 Ndis802_11Encryption3Enabled;
4419 // set to correct offset for next parsing
4420 pTmp += sizeof(CIPHER_SUITE_STRUCT);
4422 // 2. Get pairwise cipher counts
4423 //Count = *(PUSHORT) pTmp;
4424 Count = (pTmp[1] << 8) + pTmp[0];
4425 pTmp += sizeof(USHORT);
4427 // 3. Get pairwise cipher
4428 // Parsing all unicast cipher suite
4431 pCipher = (PCIPHER_SUITE_STRUCT) pTmp;
4432 TmpCipher = Ndis802_11WEPDisabled;
4433 switch (pCipher->Type) {
4435 case 5: // Although WEP is not allowed in WPA related auth mode, we parse it anyway
4437 Ndis802_11Encryption1Enabled;
4441 Ndis802_11Encryption2Enabled;
4445 Ndis802_11Encryption3Enabled;
4450 if (TmpCipher > pBss->WPA2.PairCipher) {
4451 // Move the lower cipher suite to PairCipherAux
4452 pBss->WPA2.PairCipherAux =
4453 pBss->WPA2.PairCipher;
4454 pBss->WPA2.PairCipher = TmpCipher;
4456 pBss->WPA2.PairCipherAux = TmpCipher;
4458 pTmp += sizeof(CIPHER_SUITE_STRUCT);
4462 // 4. get AKM suite counts
4463 //Count = *(PUSHORT) pTmp;
4464 Count = (pTmp[1] << 8) + pTmp[0];
4465 pTmp += sizeof(USHORT);
4467 // 5. Get AKM ciphers
4468 // Parsing all AKM ciphers
4470 pAKM = (PAKM_SUITE_STRUCT) pTmp;
4471 if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
4474 switch (pAKM->Type) {
4476 // Set AP support WPA-enterprise mode
4477 if (pBss->AuthMode ==
4478 Ndis802_11AuthModeOpen)
4480 Ndis802_11AuthModeWPA2;
4483 Ndis802_11AuthModeWPA2;
4486 // Set AP support WPA-PSK mode
4487 if (pBss->AuthMode ==
4488 Ndis802_11AuthModeOpen)
4490 Ndis802_11AuthModeWPA2PSK;
4493 Ndis802_11AuthModeWPA2PSK;
4496 if (pBss->AuthMode ==
4497 Ndis802_11AuthModeOpen)
4499 Ndis802_11AuthModeMax;
4502 Ndis802_11AuthModeMax;
4505 pTmp += (Count * sizeof(AKM_SUITE_STRUCT));
4509 // Fixed for WPA-None
4510 if (pBss->BssType == BSS_ADHOC) {
4511 pBss->AuthMode = Ndis802_11AuthModeWPANone;
4512 pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
4513 pBss->WPA.PairCipherAux =
4514 pBss->WPA2.PairCipherAux;
4515 pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher;
4516 pBss->WepStatus = pBss->WPA.GroupCipher;
4517 // Patched bugs for old driver
4518 if (pBss->WPA.PairCipherAux ==
4519 Ndis802_11WEPDisabled)
4520 pBss->WPA.PairCipherAux =
4521 pBss->WPA.GroupCipher;
4523 pBss->WepStatus = pBss->WPA2.PairCipher;
4525 // 6. Get RSN capability
4526 //pBss->WPA2.RsnCapability = *(PUSHORT) pTmp;
4527 pBss->WPA2.RsnCapability = (pTmp[1] << 8) + pTmp[0];
4528 pTmp += sizeof(USHORT);
4530 // Check the Pair & Group, if different, turn on mixed mode flag
4531 if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher)
4532 pBss->WPA2.bMixMode = TRUE;
4538 Length -= (pEid->Len + 2);
4542 // ===========================================================================================
4544 // ===========================================================================================
4546 /*! \brief generates a random mac address value for IBSS BSSID
4547 * \param Addr the bssid location
4552 VOID MacAddrRandomBssid(IN PRTMP_ADAPTER pAd, OUT PUCHAR pAddr)
4556 for (i = 0; i < MAC_ADDR_LEN; i++) {
4557 pAddr[i] = RandomByte(pAd);
4560 pAddr[0] = (pAddr[0] & 0xfe) | 0x02; // the first 2 bits must be 01xxxxxxxx
4563 /*! \brief init the management mac frame header
4564 * \param p_hdr mac header
4565 * \param subtype subtype of the frame
4566 * \param p_ds destination address, don't care if it is a broadcast address
4568 * \pre the station has the following information in the pAd->StaCfg
4572 * \note this function initializes the following field
4574 IRQL = PASSIVE_LEVEL
4575 IRQL = DISPATCH_LEVEL
4578 VOID MgtMacHeaderInit(IN PRTMP_ADAPTER pAd,
4579 IN OUT PHEADER_802_11 pHdr80211,
4581 IN UCHAR ToDs, IN PUCHAR pDA, IN PUCHAR pBssid)
4583 NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11));
4585 pHdr80211->FC.Type = BTYPE_MGMT;
4586 pHdr80211->FC.SubType = SubType;
4587 // if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type
4588 // pHdr80211->FC.Type = BTYPE_CNTL;
4589 pHdr80211->FC.ToDs = ToDs;
4590 COPY_MAC_ADDR(pHdr80211->Addr1, pDA);
4591 COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);
4592 COPY_MAC_ADDR(pHdr80211->Addr3, pBssid);
4595 // ===========================================================================================
4597 // ===========================================================================================
4599 /*!***************************************************************************
4600 * This routine build an outgoing frame, and fill all information specified
4601 * in argument list to the frame body. The actual frame size is the summation
4604 * Buffer - pointer to a pre-allocated memory segment
4605 * args - a list of <int arg_size, arg> pairs.
4606 * NOTE NOTE NOTE!!!! the last argument must be NULL, otherwise this
4607 * function will FAIL!!!
4609 * Size of the buffer
4611 * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);
4613 IRQL = PASSIVE_LEVEL
4614 IRQL = DISPATCH_LEVEL
4616 ****************************************************************************/
4617 ULONG MakeOutgoingFrame(OUT UCHAR * Buffer, OUT ULONG * FrameLen, ...)
4624 // calculates the total length
4626 va_start(Args, FrameLen);
4628 leng = va_arg(Args, int);
4629 if (leng == END_OF_ARGS) {
4632 p = va_arg(Args, PVOID);
4633 NdisMoveMemory(&Buffer[TotLeng], p, leng);
4634 TotLeng = TotLeng + leng;
4637 va_end(Args); /* clean up */
4638 *FrameLen = TotLeng;
4642 // ===========================================================================================
4644 // ===========================================================================================
4646 /*! \brief Initialize The MLME Queue, used by MLME Functions
4647 * \param *Queue The MLME Queue
4648 * \return Always Return NDIS_STATE_SUCCESS in this implementation
4651 * \note Because this is done only once (at the init stage), no need to be locked
4653 IRQL = PASSIVE_LEVEL
4656 NDIS_STATUS MlmeQueueInit(IN MLME_QUEUE * Queue)
4660 NdisAllocateSpinLock(&Queue->Lock);
4666 for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) {
4667 Queue->Entry[i].Occupied = FALSE;
4668 Queue->Entry[i].MsgLen = 0;
4669 NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE);
4672 return NDIS_STATUS_SUCCESS;
4675 /*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread
4676 * \param *Queue The MLME Queue
4677 * \param Machine The State Machine Id
4678 * \param MsgType The Message Type
4679 * \param MsgLen The Message length
4680 * \param *Msg The message pointer
4681 * \return TRUE if enqueue is successful, FALSE if the queue is full
4684 * \note The message has to be initialized
4686 IRQL = PASSIVE_LEVEL
4687 IRQL = DISPATCH_LEVEL
4690 BOOLEAN MlmeEnqueue(IN PRTMP_ADAPTER pAd,
4692 IN ULONG MsgType, IN ULONG MsgLen, IN VOID * Msg)
4695 MLME_QUEUE *Queue = (MLME_QUEUE *) & pAd->Mlme.Queue;
4697 // Do nothing if the driver is starting halt state.
4698 // This might happen when timer already been fired before cancel timer with mlmehalt
4700 (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
4703 // First check the size, it MUST not exceed the mlme queue size
4704 if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
4705 DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n",
4710 if (MlmeQueueFull(Queue)) {
4714 NdisAcquireSpinLock(&(Queue->Lock));
4718 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) {
4722 Queue->Entry[Tail].Wcid = RESERVED_WCID;
4723 Queue->Entry[Tail].Occupied = TRUE;
4724 Queue->Entry[Tail].Machine = Machine;
4725 Queue->Entry[Tail].MsgType = MsgType;
4726 Queue->Entry[Tail].MsgLen = MsgLen;
4729 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4732 NdisReleaseSpinLock(&(Queue->Lock));
4736 /*! \brief This function is used when Recv gets a MLME message
4737 * \param *Queue The MLME Queue
4738 * \param TimeStampHigh The upper 32 bit of timestamp
4739 * \param TimeStampLow The lower 32 bit of timestamp
4740 * \param Rssi The receiving RSSI strength
4741 * \param MsgLen The length of the message
4742 * \param *Msg The message pointer
4743 * \return TRUE if everything ok, FALSE otherwise (like Queue Full)
4747 IRQL = DISPATCH_LEVEL
4750 BOOLEAN MlmeEnqueueForRecv(IN PRTMP_ADAPTER pAd,
4752 IN ULONG TimeStampHigh,
4753 IN ULONG TimeStampLow,
4757 IN ULONG MsgLen, IN VOID * Msg, IN UCHAR Signal)
4760 PFRAME_802_11 pFrame = (PFRAME_802_11) Msg;
4762 MLME_QUEUE *Queue = (MLME_QUEUE *) & pAd->Mlme.Queue;
4764 // Do nothing if the driver is starting halt state.
4765 // This might happen when timer already been fired before cancel timer with mlmehalt
4768 fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) {
4769 DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n"));
4772 // First check the size, it MUST not exceed the mlme queue size
4773 if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
4774 DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
4778 if (MlmeQueueFull(Queue)) {
4783 if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) {
4784 DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType));
4789 // OK, we got all the informations, it is time to put things into queue
4790 NdisAcquireSpinLock(&(Queue->Lock));
4794 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) {
4797 Queue->Entry[Tail].Occupied = TRUE;
4798 Queue->Entry[Tail].Machine = Machine;
4799 Queue->Entry[Tail].MsgType = MsgType;
4800 Queue->Entry[Tail].MsgLen = MsgLen;
4801 Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow;
4802 Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh;
4803 Queue->Entry[Tail].Rssi0 = Rssi0;
4804 Queue->Entry[Tail].Rssi1 = Rssi1;
4805 Queue->Entry[Tail].Rssi2 = Rssi2;
4806 Queue->Entry[Tail].Signal = Signal;
4807 Queue->Entry[Tail].Wcid = (UCHAR) Wcid;
4809 Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel;
4812 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4815 NdisReleaseSpinLock(&(Queue->Lock));
4817 RTMP_MLME_HANDLER(pAd);
4822 /*! \brief Dequeue a message from the MLME Queue
4823 * \param *Queue The MLME Queue
4824 * \param *Elem The message dequeued from MLME Queue
4825 * \return TRUE if the Elem contains something, FALSE otherwise
4829 IRQL = DISPATCH_LEVEL
4832 BOOLEAN MlmeDequeue(IN MLME_QUEUE * Queue, OUT MLME_QUEUE_ELEM ** Elem)
4834 NdisAcquireSpinLock(&(Queue->Lock));
4835 *Elem = &(Queue->Entry[Queue->Head]);
4838 if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) {
4841 NdisReleaseSpinLock(&(Queue->Lock));
4845 // IRQL = DISPATCH_LEVEL
4846 VOID MlmeRestartStateMachine(IN PRTMP_ADAPTER pAd)
4849 MLME_QUEUE_ELEM *Elem = NULL;
4850 #endif // RTMP_MAC_PCI //
4853 DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n"));
4856 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
4857 if (pAd->Mlme.bRunning) {
4858 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4861 pAd->Mlme.bRunning = TRUE;
4863 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4865 // Remove all Mlme queues elements
4866 while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) {
4867 //From message type, determine which state machine I should drive
4868 if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) {
4869 // free MLME element
4870 Elem->Occupied = FALSE;
4874 DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n"));
4877 #endif // RTMP_MAC_PCI //
4880 // Cancel all timer events
4881 // Be careful to cancel new added timer
4882 RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled);
4883 RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled);
4884 RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled);
4885 RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled);
4886 RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled);
4887 RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
4891 // Change back to original channel in case of doing scan
4892 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
4893 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
4895 // Resume MSDU which is turned off durning scan
4896 RTMPResumeMsduTransmission(pAd);
4899 // Set all state machines back IDLE
4900 pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
4901 pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
4902 pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
4903 pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
4904 pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
4905 pAd->Mlme.ActMachine.CurrState = ACT_IDLE;
4909 // Remove running state
4910 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
4911 pAd->Mlme.bRunning = FALSE;
4912 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4913 #endif // RTMP_MAC_PCI //
4916 /*! \brief test if the MLME Queue is empty
4917 * \param *Queue The MLME Queue
4918 * \return TRUE if the Queue is empty, FALSE otherwise
4922 IRQL = DISPATCH_LEVEL
4925 BOOLEAN MlmeQueueEmpty(IN MLME_QUEUE * Queue)
4929 NdisAcquireSpinLock(&(Queue->Lock));
4930 Ans = (Queue->Num == 0);
4931 NdisReleaseSpinLock(&(Queue->Lock));
4936 /*! \brief test if the MLME Queue is full
4937 * \param *Queue The MLME Queue
4938 * \return TRUE if the Queue is empty, FALSE otherwise
4942 IRQL = PASSIVE_LEVEL
4943 IRQL = DISPATCH_LEVEL
4946 BOOLEAN MlmeQueueFull(IN MLME_QUEUE * Queue)
4950 NdisAcquireSpinLock(&(Queue->Lock));
4951 Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE
4952 || Queue->Entry[Queue->Tail].Occupied);
4953 NdisReleaseSpinLock(&(Queue->Lock));
4958 /*! \brief The destructor of MLME Queue
4963 * \note Clear Mlme Queue, Set Queue->Num to Zero.
4965 IRQL = PASSIVE_LEVEL
4968 VOID MlmeQueueDestroy(IN MLME_QUEUE * pQueue)
4970 NdisAcquireSpinLock(&(pQueue->Lock));
4974 NdisReleaseSpinLock(&(pQueue->Lock));
4975 NdisFreeSpinLock(&(pQueue->Lock));
4978 /*! \brief To substitute the message type if the message is coming from external
4979 * \param pFrame The frame received
4980 * \param *Machine The state machine
4981 * \param *MsgType the message type for the state machine
4982 * \return TRUE if the substitution is successful, FALSE otherwise
4986 IRQL = DISPATCH_LEVEL
4989 BOOLEAN MsgTypeSubst(IN PRTMP_ADAPTER pAd,
4990 IN PFRAME_802_11 pFrame,
4991 OUT INT * Machine, OUT INT * MsgType)
4997 // Pointer to start of data frames including SNAP header
4998 pData = (PUCHAR) pFrame + LENGTH_802_11;
5000 // The only data type will pass to this function is EAPOL frame
5001 if (pFrame->Hdr.FC.Type == BTYPE_DATA) {
5003 *Machine = WPA_STATE_MACHINE;
5005 *((UCHAR *) pFrame + LENGTH_802_11 +
5006 LENGTH_802_1_H + 1);
5007 return (WpaMsgTypeSubst(EAPType, (INT *) MsgType));
5011 switch (pFrame->Hdr.FC.SubType) {
5012 case SUBTYPE_ASSOC_REQ:
5013 *Machine = ASSOC_STATE_MACHINE;
5014 *MsgType = MT2_PEER_ASSOC_REQ;
5016 case SUBTYPE_ASSOC_RSP:
5017 *Machine = ASSOC_STATE_MACHINE;
5018 *MsgType = MT2_PEER_ASSOC_RSP;
5020 case SUBTYPE_REASSOC_REQ:
5021 *Machine = ASSOC_STATE_MACHINE;
5022 *MsgType = MT2_PEER_REASSOC_REQ;
5024 case SUBTYPE_REASSOC_RSP:
5025 *Machine = ASSOC_STATE_MACHINE;
5026 *MsgType = MT2_PEER_REASSOC_RSP;
5028 case SUBTYPE_PROBE_REQ:
5029 *Machine = SYNC_STATE_MACHINE;
5030 *MsgType = MT2_PEER_PROBE_REQ;
5032 case SUBTYPE_PROBE_RSP:
5033 *Machine = SYNC_STATE_MACHINE;
5034 *MsgType = MT2_PEER_PROBE_RSP;
5036 case SUBTYPE_BEACON:
5037 *Machine = SYNC_STATE_MACHINE;
5038 *MsgType = MT2_PEER_BEACON;
5041 *Machine = SYNC_STATE_MACHINE;
5042 *MsgType = MT2_PEER_ATIM;
5044 case SUBTYPE_DISASSOC:
5045 *Machine = ASSOC_STATE_MACHINE;
5046 *MsgType = MT2_PEER_DISASSOC_REQ;
5049 // get the sequence number from payload 24 Mac Header + 2 bytes algorithm
5050 NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(USHORT));
5051 NdisMoveMemory(&Alg, &pFrame->Octet[0], sizeof(USHORT));
5052 if (Seq == 1 || Seq == 3) {
5053 *Machine = AUTH_RSP_STATE_MACHINE;
5054 *MsgType = MT2_PEER_AUTH_ODD;
5055 } else if (Seq == 2 || Seq == 4) {
5056 if (Alg == AUTH_MODE_OPEN || Alg == AUTH_MODE_KEY) {
5057 *Machine = AUTH_STATE_MACHINE;
5058 *MsgType = MT2_PEER_AUTH_EVEN;
5064 case SUBTYPE_DEAUTH:
5065 *Machine = AUTH_RSP_STATE_MACHINE;
5066 *MsgType = MT2_PEER_DEAUTH;
5068 case SUBTYPE_ACTION:
5069 *Machine = ACTION_STATE_MACHINE;
5070 // Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support
5071 if ((pFrame->Octet[0] & 0x7F) > MAX_PEER_CATE_MSG) {
5072 *MsgType = MT2_ACT_INVALID;
5074 *MsgType = (pFrame->Octet[0] & 0x7F);
5085 // ===========================================================================================
5087 // ===========================================================================================
5089 /*! \brief Initialize the state machine.
5090 * \param *S pointer to the state machine
5091 * \param Trans State machine transition function
5092 * \param StNr number of states
5093 * \param MsgNr number of messages
5094 * \param DefFunc default function, when there is invalid state/message combination
5095 * \param InitState initial state of the state machine
5096 * \param Base StateMachine base, internal use only
5097 * \pre p_sm should be a legal pointer
5100 IRQL = PASSIVE_LEVEL
5103 VOID StateMachineInit(IN STATE_MACHINE * S,
5104 IN STATE_MACHINE_FUNC Trans[],
5107 IN STATE_MACHINE_FUNC DefFunc,
5108 IN ULONG InitState, IN ULONG Base)
5112 // set number of states and messages
5117 S->TransFunc = Trans;
5119 // init all state transition to default function
5120 for (i = 0; i < StNr; i++) {
5121 for (j = 0; j < MsgNr; j++) {
5122 S->TransFunc[i * MsgNr + j] = DefFunc;
5126 // set the starting state
5127 S->CurrState = InitState;
5130 /*! \brief This function fills in the function pointer into the cell in the state machine
5131 * \param *S pointer to the state machine
5133 * \param Msg incoming message
5134 * \param f the function to be executed when (state, message) combination occurs at the state machine
5135 * \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
5138 IRQL = PASSIVE_LEVEL
5141 VOID StateMachineSetAction(IN STATE_MACHINE * S,
5143 IN ULONG Msg, IN STATE_MACHINE_FUNC Func)
5147 MsgIdx = Msg - S->Base;
5149 if (St < S->NrState && MsgIdx < S->NrMsg) {
5150 // boundary checking before setting the action
5151 S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
5155 /*! \brief This function does the state transition
5156 * \param *Adapter the NIC adapter pointer
5157 * \param *S the state machine
5158 * \param *Elem the message to be executed
5161 IRQL = DISPATCH_LEVEL
5164 VOID StateMachinePerformAction(IN PRTMP_ADAPTER pAd,
5165 IN STATE_MACHINE * S, IN MLME_QUEUE_ELEM * Elem)
5167 (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))
5172 ==========================================================================
5174 The drop function, when machine executes this, the message is simply
5175 ignored. This function does nothing, the message is freed in
5176 StateMachinePerformAction()
5177 ==========================================================================
5179 VOID Drop(IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM * Elem)
5183 // ===========================================================================================
5185 // ===========================================================================================
5188 ==========================================================================
5191 IRQL = PASSIVE_LEVEL
5193 ==========================================================================
5195 VOID LfsrInit(IN PRTMP_ADAPTER pAd, IN ULONG Seed)
5198 pAd->Mlme.ShiftReg = 1;
5200 pAd->Mlme.ShiftReg = Seed;
5204 ==========================================================================
5206 ==========================================================================
5208 UCHAR RandomByte(IN PRTMP_ADAPTER pAd)
5215 if (pAd->Mlme.ShiftReg == 0)
5216 NdisGetSystemUpTime((ULONG *) & pAd->Mlme.ShiftReg);
5218 for (i = 0; i < 8; i++) {
5219 if (pAd->Mlme.ShiftReg & 0x00000001) {
5220 pAd->Mlme.ShiftReg =
5222 ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000;
5225 pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1;
5228 R = (R << 1) | Result;
5235 ========================================================================
5237 Routine Description:
5238 Verify the support rate for different PHY type
5241 pAd Pointer to our adapter
5246 IRQL = PASSIVE_LEVEL
5248 ========================================================================
5250 VOID RTMPCheckRates(IN PRTMP_ADAPTER pAd,
5251 IN OUT UCHAR SupRate[], IN OUT UCHAR * SupRateLen)
5253 UCHAR RateIdx, i, j;
5254 UCHAR NewRate[12], NewRateLen;
5258 if (pAd->CommonCfg.PhyMode == PHY_11B)
5263 // Check for support rates exclude basic rate bit
5264 for (i = 0; i < *SupRateLen; i++)
5265 for (j = 0; j < RateIdx; j++)
5266 if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j])
5267 NewRate[NewRateLen++] = SupRate[i];
5269 *SupRateLen = NewRateLen;
5270 NdisMoveMemory(SupRate, NewRate, NewRateLen);
5273 BOOLEAN RTMPCheckChannel(IN PRTMP_ADAPTER pAd,
5274 IN UCHAR CentralChannel, IN UCHAR Channel)
5277 UCHAR UpperChannel = 0, LowerChannel = 0;
5278 UCHAR NoEffectChannelinList = 0;
5280 // Find upper and lower channel according to 40MHz current operation.
5281 if (CentralChannel < Channel) {
5282 UpperChannel = Channel;
5283 if (CentralChannel > 2)
5284 LowerChannel = CentralChannel - 2;
5287 } else if (CentralChannel > Channel) {
5288 UpperChannel = CentralChannel + 2;
5289 LowerChannel = Channel;
5292 for (k = 0; k < pAd->ChannelListNum; k++) {
5293 if (pAd->ChannelList[k].Channel == UpperChannel) {
5294 NoEffectChannelinList++;
5296 if (pAd->ChannelList[k].Channel == LowerChannel) {
5297 NoEffectChannelinList++;
5301 DBGPRINT(RT_DEBUG_TRACE,
5302 ("Total Channel in Channel List = [%d]\n",
5303 NoEffectChannelinList));
5304 if (NoEffectChannelinList == 2)
5311 ========================================================================
5313 Routine Description:
5314 Verify the support rate for HT phy type
5317 pAd Pointer to our adapter
5320 FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode)
5322 IRQL = PASSIVE_LEVEL
5324 ========================================================================
5326 BOOLEAN RTMPCheckHt(IN PRTMP_ADAPTER pAd,
5328 IN HT_CAPABILITY_IE * pHtCapability,
5329 IN ADD_HT_INFO_IE * pAddHtInfo)
5331 if (Wcid >= MAX_LEN_OF_MAC_TABLE)
5334 // If use AMSDU, set flag.
5335 if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable)
5336 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5337 fCLIENT_STATUS_AMSDU_INUSED);
5338 // Save Peer Capability
5339 if (pHtCapability->HtCapInfo.ShortGIfor20)
5340 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5341 fCLIENT_STATUS_SGI20_CAPABLE);
5342 if (pHtCapability->HtCapInfo.ShortGIfor40)
5343 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5344 fCLIENT_STATUS_SGI40_CAPABLE);
5345 if (pHtCapability->HtCapInfo.TxSTBC)
5346 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5347 fCLIENT_STATUS_TxSTBC_CAPABLE);
5348 if (pHtCapability->HtCapInfo.RxSTBC)
5349 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5350 fCLIENT_STATUS_RxSTBC_CAPABLE);
5351 if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) {
5352 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5353 fCLIENT_STATUS_RDG_CAPABLE);
5356 if (Wcid < MAX_LEN_OF_MAC_TABLE) {
5357 pAd->MacTab.Content[Wcid].MpduDensity =
5358 pHtCapability->HtCapParm.MpduDensity;
5360 // Will check ChannelWidth for MCSSet[4] below
5361 pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1;
5362 switch (pAd->CommonCfg.RxStream) {
5364 pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5365 pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00;
5366 pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
5367 pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5370 pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5371 pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
5372 pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
5373 pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5376 pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5377 pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
5378 pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff;
5379 pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5383 pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth =
5384 pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.
5387 DBGPRINT(RT_DEBUG_TRACE,
5388 ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n",
5389 pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth,
5390 pAddHtInfo->AddHtInfo.RecomWidth,
5391 pAd->CommonCfg.DesiredHtPhy.ChannelWidth,
5392 pAd->NicConfig2.field.BW40MAvailForA,
5393 pAd->NicConfig2.field.BW40MAvailForG,
5394 pAd->CommonCfg.PhyMode));
5396 pAd->MlmeAux.HtCapability.HtCapInfo.GF =
5397 pHtCapability->HtCapInfo.GF & pAd->CommonCfg.DesiredHtPhy.GF;
5399 // Send Assoc Req with my HT capability.
5400 pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize =
5401 pAd->CommonCfg.DesiredHtPhy.AmsduSize;
5402 pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs =
5403 pAd->CommonCfg.DesiredHtPhy.MimoPs;
5404 pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 =
5405 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->
5408 pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 =
5409 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->
5412 pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC =
5413 (pAd->CommonCfg.DesiredHtPhy.TxSTBC) & (pHtCapability->HtCapInfo.
5415 pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC =
5416 (pAd->CommonCfg.DesiredHtPhy.RxSTBC) & (pHtCapability->HtCapInfo.
5418 pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor =
5419 pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor;
5420 pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity =
5421 pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity;
5422 pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC =
5423 pHtCapability->ExtHtCapInfo.PlusHTC;
5424 pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC =
5425 pHtCapability->ExtHtCapInfo.PlusHTC;
5426 if (pAd->CommonCfg.bRdg) {
5427 pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport =
5428 pHtCapability->ExtHtCapInfo.RDGSupport;
5429 pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1;
5432 if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20)
5433 pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; // BW20 can't transmit MCS32
5435 COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability);
5440 ========================================================================
5442 Routine Description:
5443 Verify the support rate for different PHY type
5446 pAd Pointer to our adapter
5451 IRQL = PASSIVE_LEVEL
5453 ========================================================================
5455 VOID RTMPUpdateMlmeRate(IN PRTMP_ADAPTER pAd)
5458 UCHAR ProperMlmeRate; //= RATE_54;
5459 UCHAR i, j, RateIdx = 12; //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54
5460 BOOLEAN bMatch = FALSE;
5462 switch (pAd->CommonCfg.PhyMode) {
5464 ProperMlmeRate = RATE_11;
5465 MinimumRate = RATE_1;
5467 case PHY_11BG_MIXED:
5468 case PHY_11ABGN_MIXED:
5469 case PHY_11BGN_MIXED:
5470 if ((pAd->MlmeAux.SupRateLen == 4) &&
5471 (pAd->MlmeAux.ExtRateLen == 0))
5473 ProperMlmeRate = RATE_11;
5475 ProperMlmeRate = RATE_24;
5477 if (pAd->MlmeAux.Channel <= 14)
5478 MinimumRate = RATE_1;
5480 MinimumRate = RATE_6;
5483 case PHY_11N_2_4G: // rt2860 need to check mlmerate for 802.11n
5484 case PHY_11GN_MIXED:
5485 case PHY_11AGN_MIXED:
5486 case PHY_11AN_MIXED:
5488 ProperMlmeRate = RATE_24;
5489 MinimumRate = RATE_6;
5491 case PHY_11ABG_MIXED:
5492 ProperMlmeRate = RATE_24;
5493 if (pAd->MlmeAux.Channel <= 14)
5494 MinimumRate = RATE_1;
5496 MinimumRate = RATE_6;
5499 ProperMlmeRate = RATE_1;
5500 MinimumRate = RATE_1;
5504 for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) {
5505 for (j = 0; j < RateIdx; j++) {
5506 if ((pAd->MlmeAux.SupRate[i] & 0x7f) ==
5507 RateIdTo500Kbps[j]) {
5508 if (j == ProperMlmeRate) {
5519 if (bMatch == FALSE) {
5520 for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) {
5521 for (j = 0; j < RateIdx; j++) {
5522 if ((pAd->MlmeAux.ExtRate[i] & 0x7f) ==
5523 RateIdTo500Kbps[j]) {
5524 if (j == ProperMlmeRate) {
5536 if (bMatch == FALSE) {
5537 ProperMlmeRate = MinimumRate;
5540 pAd->CommonCfg.MlmeRate = MinimumRate;
5541 pAd->CommonCfg.RtsRate = ProperMlmeRate;
5542 if (pAd->CommonCfg.MlmeRate >= RATE_6) {
5543 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
5544 pAd->CommonCfg.MlmeTransmit.field.MCS =
5545 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
5546 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE =
5548 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS =
5549 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
5551 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
5552 pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate;
5553 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE =
5555 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS =
5556 pAd->CommonCfg.MlmeRate;
5559 DBGPRINT(RT_DEBUG_TRACE,
5560 ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n",
5561 pAd->CommonCfg.MlmeTransmit.word));
5564 CHAR RTMPMaxRssi(IN PRTMP_ADAPTER pAd,
5565 IN CHAR Rssi0, IN CHAR Rssi1, IN CHAR Rssi2)
5569 if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) {
5573 if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) {
5574 larger = max(Rssi0, Rssi1);
5577 if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) {
5578 larger = max(larger, Rssi2);
5588 ========================================================================
5589 Routine Description:
5590 Periodic evaluate antenna link status
5593 pAd - Adapter pointer
5598 ========================================================================
5600 VOID AsicEvaluateRxAnt(IN PRTMP_ADAPTER pAd)
5604 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
5605 fRTMP_ADAPTER_HALT_IN_PROGRESS |
5606 fRTMP_ADAPTER_RADIO_OFF |
5607 fRTMP_ADAPTER_NIC_NOT_EXIST |
5608 fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) ||
5609 OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
5611 || (pAd->EepromAccess)
5614 || (pAd->bPCIclkOff == TRUE)
5620 //if (pAd->StaCfg.Psm == PWR_SAVE)
5625 if (pAd->StaCfg.Psm == PWR_SAVE)
5628 RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
5630 if (pAd->Antenna.field.RxPath == 3) {
5632 } else if (pAd->Antenna.field.RxPath == 2) {
5634 } else if (pAd->Antenna.field.RxPath == 1) {
5637 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
5639 pAd->StaCfg.BBPR3 = BBPR3;
5640 #endif // RTMP_MAC_PCI //
5641 if (OPSTATUS_TEST_FLAG
5642 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
5645 pAd->RalinkCounters.OneSecTxNoRetryOkCount +
5646 pAd->RalinkCounters.OneSecTxRetryOkCount +
5647 pAd->RalinkCounters.OneSecTxFailCount;
5649 // dynamic adjust antenna evaluation period according to the traffic
5650 if (TxTotalCnt > 50) {
5651 RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer,
5653 pAd->Mlme.bLowThroughput = FALSE;
5655 RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer,
5657 pAd->Mlme.bLowThroughput = TRUE;
5667 ========================================================================
5668 Routine Description:
5669 After evaluation, check antenna link status
5672 pAd - Adapter pointer
5677 ========================================================================
5679 VOID AsicRxAntEvalTimeout(IN PVOID SystemSpecific1,
5680 IN PVOID FunctionContext,
5681 IN PVOID SystemSpecific2, IN PVOID SystemSpecific3)
5683 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *) FunctionContext;
5685 CHAR larger = -127, rssi0, rssi1, rssi2;
5687 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
5688 fRTMP_ADAPTER_HALT_IN_PROGRESS |
5689 fRTMP_ADAPTER_RADIO_OFF |
5690 fRTMP_ADAPTER_NIC_NOT_EXIST) ||
5691 OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
5693 || (pAd->EepromAccess)
5696 || (pAd->bPCIclkOff == TRUE)
5702 //if (pAd->StaCfg.Psm == PWR_SAVE)
5705 if (pAd->StaCfg.Psm == PWR_SAVE)
5708 // if the traffic is low, use average rssi as the criteria
5709 if (pAd->Mlme.bLowThroughput == TRUE) {
5710 rssi0 = pAd->StaCfg.RssiSample.LastRssi0;
5711 rssi1 = pAd->StaCfg.RssiSample.LastRssi1;
5712 rssi2 = pAd->StaCfg.RssiSample.LastRssi2;
5714 rssi0 = pAd->StaCfg.RssiSample.AvgRssi0;
5715 rssi1 = pAd->StaCfg.RssiSample.AvgRssi1;
5716 rssi2 = pAd->StaCfg.RssiSample.AvgRssi2;
5719 if (pAd->Antenna.field.RxPath == 3) {
5720 larger = max(rssi0, rssi1);
5722 if (larger > (rssi2 + 20))
5723 pAd->Mlme.RealRxPath = 2;
5725 pAd->Mlme.RealRxPath = 3;
5726 } else if (pAd->Antenna.field.RxPath == 2) {
5727 if (rssi0 > (rssi1 + 20))
5728 pAd->Mlme.RealRxPath = 1;
5730 pAd->Mlme.RealRxPath = 2;
5733 RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
5735 if (pAd->Mlme.RealRxPath == 3) {
5737 } else if (pAd->Mlme.RealRxPath == 2) {
5739 } else if (pAd->Mlme.RealRxPath == 1) {
5742 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
5744 pAd->StaCfg.BBPR3 = BBPR3;
5745 #endif // RTMP_MAC_PCI //
5751 VOID APSDPeriodicExec(IN PVOID SystemSpecific1,
5752 IN PVOID FunctionContext,
5753 IN PVOID SystemSpecific2, IN PVOID SystemSpecific3)
5755 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *) FunctionContext;
5757 if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
5760 pAd->CommonCfg.TriggerTimerCount++;
5762 // Driver should not send trigger frame, it should be send by application layer
5764 if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable
5765 && (pAd->CommonCfg.bNeedSendTriggerFrame ||
5766 (((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO))))
5768 DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n"));
5769 RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
5770 pAd->CommonCfg.bNeedSendTriggerFrame = FALSE;
5771 pAd->CommonCfg.TriggerTimerCount = 0;
5772 pAd->CommonCfg.bInServicePeriod = TRUE;
5777 ========================================================================
5778 Routine Description:
5779 Set/reset MAC registers according to bPiggyBack parameter
5782 pAd - Adapter pointer
5783 bPiggyBack - Enable / Disable Piggy-Back
5788 ========================================================================
5790 VOID RTMPSetPiggyBack(IN PRTMP_ADAPTER pAd, IN BOOLEAN bPiggyBack)
5792 TX_LINK_CFG_STRUC TxLinkCfg;
5794 RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
5796 TxLinkCfg.field.TxCFAckEn = bPiggyBack;
5797 RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
5801 ========================================================================
5802 Routine Description:
5803 check if this entry need to switch rate automatically
5813 ========================================================================
5815 BOOLEAN RTMPCheckEntryEnableAutoRateSwitch(IN PRTMP_ADAPTER pAd,
5816 IN PMAC_TABLE_ENTRY pEntry)
5818 BOOLEAN result = TRUE;
5821 // only associated STA counts
5822 if (pEntry && (pEntry->ValidAsCLI)
5823 && (pEntry->Sst == SST_ASSOC)) {
5824 result = pAd->StaCfg.bAutoTxRateSwitch;
5832 BOOLEAN RTMPAutoRateSwitchCheck(IN PRTMP_ADAPTER pAd)
5835 if (pAd->StaCfg.bAutoTxRateSwitch)
5842 ========================================================================
5843 Routine Description:
5844 check if this entry need to fix tx legacy rate
5854 ========================================================================
5856 UCHAR RTMPStaFixedTxMode(IN PRTMP_ADAPTER pAd, IN PMAC_TABLE_ENTRY pEntry)
5858 UCHAR tx_mode = FIXED_TXMODE_HT;
5862 (UCHAR) pAd->StaCfg.DesiredTransmitSetting.field.
5870 ========================================================================
5871 Routine Description:
5872 Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified.
5882 ========================================================================
5884 VOID RTMPUpdateLegacyTxSetting(UCHAR fixed_tx_mode, PMAC_TABLE_ENTRY pEntry)
5886 HTTRANSMIT_SETTING TransmitSetting;
5888 if (fixed_tx_mode == FIXED_TXMODE_HT)
5891 TransmitSetting.word = 0;
5893 TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE;
5894 TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS;
5896 if (fixed_tx_mode == FIXED_TXMODE_CCK) {
5897 TransmitSetting.field.MODE = MODE_CCK;
5898 // CCK mode allow MCS 0~3
5899 if (TransmitSetting.field.MCS > MCS_3)
5900 TransmitSetting.field.MCS = MCS_3;
5902 TransmitSetting.field.MODE = MODE_OFDM;
5903 // OFDM mode allow MCS 0~7
5904 if (TransmitSetting.field.MCS > MCS_7)
5905 TransmitSetting.field.MCS = MCS_7;
5908 if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) {
5909 pEntry->HTPhyMode.word = TransmitSetting.word;
5910 DBGPRINT(RT_DEBUG_TRACE,
5911 ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n",
5912 pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE),
5913 pEntry->HTPhyMode.field.MCS));
5918 ==========================================================================
5920 dynamic tune BBP R66 to find a balance between sensibility and
5923 IRQL = DISPATCH_LEVEL
5925 ==========================================================================
5927 VOID AsicStaBbpTuning(IN PRTMP_ADAPTER pAd)
5929 UCHAR OrigR66Value = 0, R66; //, R66UpperBound = 0x30, R66LowerBound = 0x30;
5932 // 2860C did not support Fase CCA, therefore can't tune
5933 if (pAd->MACVersion == 0x28600100)
5939 if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) // no R66 tuning when SCANNING
5942 if ((pAd->OpMode == OPMODE_STA)
5943 && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
5945 && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
5947 && (pAd->bPCIclkOff == FALSE)
5948 #endif // RTMP_MAC_PCI //
5950 RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value);
5953 if (pAd->Antenna.field.RxPath > 1)
5955 (pAd->StaCfg.RssiSample.AvgRssi0 +
5956 pAd->StaCfg.RssiSample.AvgRssi1) >> 1;
5958 Rssi = pAd->StaCfg.RssiSample.AvgRssi0;
5960 if (pAd->LatchRfRegs.Channel <= 14) { //BG band
5962 // RT3070 is a no LNA solution, it should have different control regarding to AGC gain control
5963 // Otherwise, it will have some throughput side effect when low RSSI
5965 if (IS_RT3070(pAd) || IS_RT3090(pAd) || IS_RT3572(pAd)
5966 || IS_RT3390(pAd)) {
5967 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5969 0x1C + 2 * GET_LNA_GAIN(pAd) + 0x20;
5970 if (OrigR66Value != R66) {
5971 RTMP_BBP_IO_WRITE8_BY_REG_ID
5972 (pAd, BBP_R66, R66);
5975 R66 = 0x1C + 2 * GET_LNA_GAIN(pAd);
5976 if (OrigR66Value != R66) {
5977 RTMP_BBP_IO_WRITE8_BY_REG_ID
5978 (pAd, BBP_R66, R66);
5984 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5985 R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10;
5986 if (OrigR66Value != R66) {
5987 RTMP_BBP_IO_WRITE8_BY_REG_ID
5988 (pAd, BBP_R66, R66);
5991 R66 = 0x2E + GET_LNA_GAIN(pAd);
5992 if (OrigR66Value != R66) {
5993 RTMP_BBP_IO_WRITE8_BY_REG_ID
5994 (pAd, BBP_R66, R66);
5999 if (pAd->CommonCfg.BBPCurrentBW == BW_20) {
6000 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
6002 0x32 + (GET_LNA_GAIN(pAd) * 5) / 3 +
6004 if (OrigR66Value != R66) {
6005 RTMP_BBP_IO_WRITE8_BY_REG_ID
6006 (pAd, BBP_R66, R66);
6010 0x32 + (GET_LNA_GAIN(pAd) * 5) / 3;
6011 if (OrigR66Value != R66) {
6012 RTMP_BBP_IO_WRITE8_BY_REG_ID
6013 (pAd, BBP_R66, R66);
6017 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
6019 0x3A + (GET_LNA_GAIN(pAd) * 5) / 3 +
6021 if (OrigR66Value != R66) {
6022 RTMP_BBP_IO_WRITE8_BY_REG_ID
6023 (pAd, BBP_R66, R66);
6027 0x3A + (GET_LNA_GAIN(pAd) * 5) / 3;
6028 if (OrigR66Value != R66) {
6029 RTMP_BBP_IO_WRITE8_BY_REG_ID
6030 (pAd, BBP_R66, R66);
6039 VOID RTMPSetAGCInitValue(IN PRTMP_ADAPTER pAd, IN UCHAR BandWidth)
6043 if (pAd->LatchRfRegs.Channel <= 14) { // BG band
6045 /* Gary was verified Amazon AP and find that RT307x has BBP_R66 invalid default value */
6047 if (IS_RT3070(pAd) || IS_RT3090(pAd) || IS_RT3572(pAd)
6048 || IS_RT3390(pAd)) {
6049 R66 = 0x1C + 2 * GET_LNA_GAIN(pAd);
6050 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6054 R66 = 0x2E + GET_LNA_GAIN(pAd);
6055 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6059 if (BandWidth == BW_20) {
6062 (GET_LNA_GAIN(pAd) * 5) / 3);
6063 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6067 (GET_LNA_GAIN(pAd) * 5) / 3);
6068 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);