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 u8 CISCO_OUI[] = { 0x00, 0x40, 0x96 };
44 u8 WPA_OUI[] = { 0x00, 0x50, 0xf2, 0x01 };
45 u8 RSN_OUI[] = { 0x00, 0x0f, 0xac };
46 u8 WME_INFO_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x00, 0x01 };
47 u8 WME_PARM_ELEM[] = { 0x00, 0x50, 0xf2, 0x02, 0x01, 0x01 };
48 u8 Ccx2QosInfo[] = { 0x00, 0x40, 0x96, 0x04 };
49 u8 RALINK_OUI[] = { 0x00, 0x0c, 0x43 };
50 u8 BROADCOM_OUI[] = { 0x00, 0x90, 0x4c };
51 u8 WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
52 u8 PRE_N_HT_OUI[] = { 0x00, 0x90, 0x4c };
54 u8 RateSwitchTable[] = {
55 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
56 0x11, 0x00, 0, 0, 0, /* Initial used item after association */
57 0x00, 0x00, 0, 40, 101,
58 0x01, 0x00, 1, 40, 50,
59 0x02, 0x00, 2, 35, 45,
60 0x03, 0x00, 3, 20, 45,
61 0x04, 0x21, 0, 30, 50,
62 0x05, 0x21, 1, 20, 50,
63 0x06, 0x21, 2, 20, 50,
64 0x07, 0x21, 3, 15, 50,
65 0x08, 0x21, 4, 15, 30,
66 0x09, 0x21, 5, 10, 25,
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 u8 RateSwitchTable11B[] = {
92 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
93 0x04, 0x03, 0, 0, 0, /* Initial used item after association */
94 0x00, 0x00, 0, 40, 101,
95 0x01, 0x00, 1, 40, 50,
96 0x02, 0x00, 2, 35, 45,
97 0x03, 0x00, 3, 20, 45,
100 u8 RateSwitchTable11BG[] = {
101 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
102 0x0a, 0x00, 0, 0, 0, /* Initial used item after association */
103 0x00, 0x00, 0, 40, 101,
104 0x01, 0x00, 1, 40, 50,
105 0x02, 0x00, 2, 35, 45,
106 0x03, 0x00, 3, 20, 45,
107 0x04, 0x10, 2, 20, 35,
108 0x05, 0x10, 3, 16, 35,
109 0x06, 0x10, 4, 10, 25,
110 0x07, 0x10, 5, 16, 25,
111 0x08, 0x10, 6, 10, 25,
112 0x09, 0x10, 7, 10, 13,
115 u8 RateSwitchTable11G[] = {
116 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
117 0x08, 0x00, 0, 0, 0, /* Initial used item after association */
118 0x00, 0x10, 0, 20, 101,
119 0x01, 0x10, 1, 20, 35,
120 0x02, 0x10, 2, 20, 35,
121 0x03, 0x10, 3, 16, 35,
122 0x04, 0x10, 4, 10, 25,
123 0x05, 0x10, 5, 16, 25,
124 0x06, 0x10, 6, 10, 25,
125 0x07, 0x10, 7, 10, 13,
128 u8 RateSwitchTable11N1S[] = {
129 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
130 0x0c, 0x0a, 0, 0, 0, /* Initial used item after association */
131 0x00, 0x00, 0, 40, 101,
132 0x01, 0x00, 1, 40, 50,
133 0x02, 0x00, 2, 25, 45,
134 0x03, 0x21, 0, 20, 35,
135 0x04, 0x21, 1, 20, 35,
136 0x05, 0x21, 2, 20, 35,
137 0x06, 0x21, 3, 15, 35,
138 0x07, 0x21, 4, 15, 30,
139 0x08, 0x21, 5, 10, 25,
140 0x09, 0x21, 6, 8, 14,
141 0x0a, 0x21, 7, 8, 14,
142 0x0b, 0x23, 7, 8, 14,
145 u8 RateSwitchTable11N2S[] = {
146 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
147 0x0e, 0x0c, 0, 0, 0, /* Initial used item after association */
148 0x00, 0x00, 0, 40, 101,
149 0x01, 0x00, 1, 40, 50,
150 0x02, 0x00, 2, 25, 45,
151 0x03, 0x21, 0, 20, 35,
152 0x04, 0x21, 1, 20, 35,
153 0x05, 0x21, 2, 20, 35,
154 0x06, 0x21, 3, 15, 35,
155 0x07, 0x21, 4, 15, 30,
156 0x08, 0x20, 11, 15, 30,
157 0x09, 0x20, 12, 15, 30,
158 0x0a, 0x20, 13, 8, 20,
159 0x0b, 0x20, 14, 8, 20,
160 0x0c, 0x20, 15, 8, 25,
161 0x0d, 0x22, 15, 8, 15,
164 u8 RateSwitchTable11N3S[] = {
165 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
166 0x0b, 0x00, 0, 0, 0, /* 0x0a, 0x00, 0, 0, 0, // Initial used item after association */
167 0x00, 0x21, 0, 30, 101,
168 0x01, 0x21, 1, 20, 50,
169 0x02, 0x21, 2, 20, 50,
170 0x03, 0x21, 3, 15, 50,
171 0x04, 0x21, 4, 15, 30,
172 0x05, 0x20, 11, 15, 30, /* Required by System-Alan @ 20080812 */
173 0x06, 0x20, 12, 15, 30, /* 0x05, 0x20, 12, 15, 30, */
174 0x07, 0x20, 13, 8, 20, /* 0x06, 0x20, 13, 8, 20, */
175 0x08, 0x20, 14, 8, 20, /* 0x07, 0x20, 14, 8, 20, */
176 0x09, 0x20, 15, 8, 25, /* 0x08, 0x20, 15, 8, 25, */
177 0x0a, 0x22, 15, 8, 25, /* 0x09, 0x22, 15, 8, 25, */
180 u8 RateSwitchTable11N2SForABand[] = {
181 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
182 0x0b, 0x09, 0, 0, 0, /* Initial used item after association */
183 0x00, 0x21, 0, 30, 101,
184 0x01, 0x21, 1, 20, 50,
185 0x02, 0x21, 2, 20, 50,
186 0x03, 0x21, 3, 15, 50,
187 0x04, 0x21, 4, 15, 30,
188 0x05, 0x21, 5, 15, 30,
189 0x06, 0x20, 12, 15, 30,
190 0x07, 0x20, 13, 8, 20,
191 0x08, 0x20, 14, 8, 20,
192 0x09, 0x20, 15, 8, 25,
193 0x0a, 0x22, 15, 8, 25,
196 u8 RateSwitchTable11N3SForABand[] = { /* 3*3 */
197 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
198 0x0b, 0x09, 0, 0, 0, /* Initial used item after association */
199 0x00, 0x21, 0, 30, 101,
200 0x01, 0x21, 1, 20, 50,
201 0x02, 0x21, 2, 20, 50,
202 0x03, 0x21, 3, 15, 50,
203 0x04, 0x21, 4, 15, 30,
204 0x05, 0x21, 5, 15, 30,
205 0x06, 0x20, 12, 15, 30,
206 0x07, 0x20, 13, 8, 20,
207 0x08, 0x20, 14, 8, 20,
208 0x09, 0x20, 15, 8, 25,
209 0x0a, 0x22, 15, 8, 25,
212 u8 RateSwitchTable11BGN1S[] = {
213 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
214 0x0c, 0x0a, 0, 0, 0, /* Initial used item after association */
215 0x00, 0x00, 0, 40, 101,
216 0x01, 0x00, 1, 40, 50,
217 0x02, 0x00, 2, 25, 45,
218 0x03, 0x21, 0, 20, 35,
219 0x04, 0x21, 1, 20, 35,
220 0x05, 0x21, 2, 20, 35,
221 0x06, 0x21, 3, 15, 35,
222 0x07, 0x21, 4, 15, 30,
223 0x08, 0x21, 5, 10, 25,
224 0x09, 0x21, 6, 8, 14,
225 0x0a, 0x21, 7, 8, 14,
226 0x0b, 0x23, 7, 8, 14,
229 u8 RateSwitchTable11BGN2S[] = {
230 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
231 0x0e, 0x0c, 0, 0, 0, /* Initial used item after association */
232 0x00, 0x00, 0, 40, 101,
233 0x01, 0x00, 1, 40, 50,
234 0x02, 0x00, 2, 25, 45,
235 0x03, 0x21, 0, 20, 35,
236 0x04, 0x21, 1, 20, 35,
237 0x05, 0x21, 2, 20, 35,
238 0x06, 0x21, 3, 15, 35,
239 0x07, 0x21, 4, 15, 30,
240 0x08, 0x20, 11, 15, 30,
241 0x09, 0x20, 12, 15, 30,
242 0x0a, 0x20, 13, 8, 20,
243 0x0b, 0x20, 14, 8, 20,
244 0x0c, 0x20, 15, 8, 25,
245 0x0d, 0x22, 15, 8, 15,
248 u8 RateSwitchTable11BGN3S[] = { /* 3*3 */
249 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
250 0x0a, 0x00, 0, 0, 0, /* Initial used item after association */
251 0x00, 0x21, 0, 30, 101, /*50 */
252 0x01, 0x21, 1, 20, 50,
253 0x02, 0x21, 2, 20, 50,
254 0x03, 0x21, 3, 20, 50,
255 0x04, 0x21, 4, 15, 50,
256 0x05, 0x20, 20, 15, 30,
257 0x06, 0x20, 21, 8, 20,
258 0x07, 0x20, 22, 8, 20,
259 0x08, 0x20, 23, 8, 25,
260 0x09, 0x22, 23, 8, 25,
263 u8 RateSwitchTable11BGN2SForABand[] = {
264 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
265 0x0b, 0x09, 0, 0, 0, /* Initial used item after association */
266 0x00, 0x21, 0, 30, 101, /*50 */
267 0x01, 0x21, 1, 20, 50,
268 0x02, 0x21, 2, 20, 50,
269 0x03, 0x21, 3, 15, 50,
270 0x04, 0x21, 4, 15, 30,
271 0x05, 0x21, 5, 15, 30,
272 0x06, 0x20, 12, 15, 30,
273 0x07, 0x20, 13, 8, 20,
274 0x08, 0x20, 14, 8, 20,
275 0x09, 0x20, 15, 8, 25,
276 0x0a, 0x22, 15, 8, 25,
279 u8 RateSwitchTable11BGN3SForABand[] = { /* 3*3 */
280 /* Item No. Mode Curr-MCS TrainUp TrainDown // Mode- Bit0: STBC, Bit1: Short GI, Bit4,5: Mode(0:CCK, 1:OFDM, 2:HT Mix, 3:HT GF) */
281 0x0c, 0x09, 0, 0, 0, /* Initial used item after association */
282 0x00, 0x21, 0, 30, 101, /*50 */
283 0x01, 0x21, 1, 20, 50,
284 0x02, 0x21, 2, 20, 50,
285 0x03, 0x21, 3, 15, 50,
286 0x04, 0x21, 4, 15, 30,
287 0x05, 0x21, 5, 15, 30,
288 0x06, 0x21, 12, 15, 30,
289 0x07, 0x20, 20, 15, 30,
290 0x08, 0x20, 21, 8, 20,
291 0x09, 0x20, 22, 8, 20,
292 0x0a, 0x20, 23, 8, 25,
293 0x0b, 0x22, 23, 8, 25,
296 extern u8 OfdmRateToRxwiMCS[];
297 /* since RT61 has better RX sensibility, we have to limit TX ACK rate not to exceed our normal data TX rate. */
298 /* otherwise the WLAN peer may not be able to receive the ACK thus downgrade its data TX rate */
299 unsigned long BasicRateMask[12] =
300 { 0xfffff001 /* 1-Mbps */ , 0xfffff003 /* 2 Mbps */ , 0xfffff007 /* 5.5 */ ,
301 0xfffff00f /* 11 */ ,
302 0xfffff01f /* 6 */ , 0xfffff03f /* 9 */ , 0xfffff07f /* 12 */ ,
303 0xfffff0ff /* 18 */ ,
304 0xfffff1ff /* 24 */ , 0xfffff3ff /* 36 */ , 0xfffff7ff /* 48 */ ,
308 u8 BROADCAST_ADDR[MAC_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
309 u8 ZERO_MAC_ADDR[MAC_ADDR_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
311 /* e.g. RssiSafeLevelForTxRate[RATE_36]" means if the current RSSI is greater than */
312 /* this value, then it's quaranteed capable of operating in 36 mbps TX rate in */
313 /* clean environment. */
314 /* TxRate: 1 2 5.5 11 6 9 12 18 24 36 48 54 72 100 */
315 char RssiSafeLevelForTxRate[] =
316 { -92, -91, -90, -87, -88, -86, -85, -83, -81, -78, -72, -71, -40, -40 };
318 u8 RateIdToMbps[] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 72, 100 };
319 u16 RateIdTo500Kbps[] =
320 { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 144, 200 };
323 u8 SupRateIe = IE_SUPP_RATES;
324 u8 ExtRateIe = IE_EXT_SUPP_RATES;
325 u8 HtCapIe = IE_HT_CAP;
326 u8 AddHtInfoIe = IE_ADD_HT;
327 u8 NewExtChanIe = IE_SECONDARY_CH_OFFSET;
329 u8 DsIe = IE_DS_PARM;
333 u8 IbssIe = IE_IBSS_PARM;
337 u8 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 int MlmeInit(struct rt_rtmp_adapter *pAd)
361 int 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(struct rt_rtmp_adapter *pAd)
458 struct rt_mlme_queue_elem *Elem = NULL;
460 /* Only accept MLME and Frame from peer side, no other (control/data) frame should */
461 /* get into this state machine */
463 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
464 if (pAd->Mlme.bRunning) {
465 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
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",
545 } /* end of switch */
547 /* free MLME element */
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(struct rt_rtmp_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 struct rt_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(struct rt_rtmp_adapter *pAd)
644 pAd->RalinkCounters.LastOneSecRxOkDataCnt =
645 pAd->RalinkCounters.OneSecRxOkDataCnt;
646 /* clear all OneSecxxx counters. */
647 pAd->RalinkCounters.OneSecBeaconSentCnt = 0;
648 pAd->RalinkCounters.OneSecFalseCCACnt = 0;
649 pAd->RalinkCounters.OneSecRxFcsErrCnt = 0;
650 pAd->RalinkCounters.OneSecRxOkCnt = 0;
651 pAd->RalinkCounters.OneSecTxFailCount = 0;
652 pAd->RalinkCounters.OneSecTxNoRetryOkCount = 0;
653 pAd->RalinkCounters.OneSecTxRetryOkCount = 0;
654 pAd->RalinkCounters.OneSecRxOkDataCnt = 0;
655 pAd->RalinkCounters.OneSecReceivedByteCount = 0;
656 pAd->RalinkCounters.OneSecTransmittedByteCount = 0;
658 /* TODO: for debug only. to be removed */
659 pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BE] = 0;
660 pAd->RalinkCounters.OneSecOsTxCount[QID_AC_BK] = 0;
661 pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VI] = 0;
662 pAd->RalinkCounters.OneSecOsTxCount[QID_AC_VO] = 0;
663 pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BE] = 0;
664 pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_BK] = 0;
665 pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VI] = 0;
666 pAd->RalinkCounters.OneSecDmaDoneCount[QID_AC_VO] = 0;
667 pAd->RalinkCounters.OneSecTxDoneCount = 0;
668 pAd->RalinkCounters.OneSecRxCount = 0;
669 pAd->RalinkCounters.OneSecTxAggregationCount = 0;
670 pAd->RalinkCounters.OneSecRxAggregationCount = 0;
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(void *SystemSpecific1,
693 void *FunctionContext,
694 void *SystemSpecific2, void *SystemSpecific3)
696 unsigned long TxTotalCnt;
697 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
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);
714 #endif /* RT3090 // */
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);
730 #endif /* RT3090 // */
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(u8 *pSsid, u8 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(struct rt_rtmp_adapter *pAd,
942 struct rt_mac_table_entry *pEntry,
944 u8 *pTableSize, u8 *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)
1061 ) { /* B/G mixed AP */
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(struct rt_rtmp_adapter *pAd)
1149 unsigned long TxTotalCnt;
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)))
1161 #endif /* RT3070 // */
1163 if ((pAd->StaCfg.RssiSample.AvgRssi0 != 0)
1164 && (pAd->StaCfg.RssiSample.AvgRssi0 >
1165 (pAd->BbpRssiToDbmDelta - 35))) {
1166 RT30xxWriteRFRegister(pAd, RF_R27, 0x20);
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 struct rt_mlme_start_req StartReq;
1390 DBGPRINT(RT_DEBUG_TRACE,
1391 ("MMCHK - excessive BEACON lost, last STA in this IBSS, MediaState=Disconnected\n"));
1392 LinkDown(pAd, FALSE);
1394 StartParmFill(pAd, &StartReq,
1395 (char *) pAd->MlmeAux.Ssid,
1396 pAd->MlmeAux.SsidLen);
1397 MlmeEnqueue(pAd, SYNC_STATE_MACHINE, MT2_MLME_START_REQ,
1398 sizeof(struct rt_mlme_start_req), &StartReq);
1399 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_START;
1402 for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
1403 struct rt_mac_table_entry *pEntry = &pAd->MacTab.Content[i];
1405 if (pEntry->ValidAsCLI == FALSE)
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 struct rt_mlme_scan_req 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 (char *)pAd->MlmeAux.
1445 AutoReconnectSsidLen,
1446 BSS_ANY, SCAN_ACTIVE);
1447 MlmeEnqueue(pAd, SYNC_STATE_MACHINE,
1450 (struct rt_mlme_scan_req),
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);
1489 /* Link down report */
1490 void LinkDownExec(void *SystemSpecific1,
1491 void *FunctionContext,
1492 void *SystemSpecific2, void *SystemSpecific3)
1494 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
1497 struct rt_mlme_disassoc_req 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(struct rt_mlme_disassoc_req),
1510 pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC;
1512 pAd->IndicateMediaState = NdisMediaStateDisconnected;
1513 RTMP_IndicateMediaState(pAd);
1514 pAd->ExtraInfo = GENERAL_LINK_DOWN;
1519 /* IRQL = DISPATCH_LEVEL */
1520 void MlmeAutoScan(struct rt_rtmp_adapter *pAd)
1522 /* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
1523 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
1524 DBGPRINT(RT_DEBUG_TRACE, ("MMCHK - Driver auto scan\n"));
1526 MLME_CNTL_STATE_MACHINE,
1527 OID_802_11_BSSID_LIST_SCAN,
1528 pAd->MlmeAux.AutoReconnectSsidLen,
1529 pAd->MlmeAux.AutoReconnectSsid);
1530 RTMP_MLME_HANDLER(pAd);
1534 /* IRQL = DISPATCH_LEVEL */
1535 void MlmeAutoReconnectLastSSID(struct rt_rtmp_adapter *pAd)
1537 if (pAd->StaCfg.bAutoConnectByBssid) {
1538 DBGPRINT(RT_DEBUG_TRACE,
1539 ("Driver auto reconnect to last OID_802_11_BSSID setting - %02X:%02X:%02X:%02X:%02X:%02X\n",
1540 pAd->MlmeAux.Bssid[0], pAd->MlmeAux.Bssid[1],
1541 pAd->MlmeAux.Bssid[2], pAd->MlmeAux.Bssid[3],
1542 pAd->MlmeAux.Bssid[4], pAd->MlmeAux.Bssid[5]));
1544 pAd->MlmeAux.Channel = pAd->CommonCfg.Channel;
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 struct rt_ndis_802_11_ssid OidSsid;
1559 OidSsid.SsidLength = pAd->MlmeAux.AutoReconnectSsidLen;
1560 NdisMoveMemory(OidSsid.Ssid, pAd->MlmeAux.AutoReconnectSsid,
1561 pAd->MlmeAux.AutoReconnectSsidLen);
1563 DBGPRINT(RT_DEBUG_TRACE,
1564 ("Driver auto reconnect to last OID_802_11_SSID setting - %s, len - %d\n",
1565 pAd->MlmeAux.AutoReconnectSsid,
1566 pAd->MlmeAux.AutoReconnectSsidLen));
1567 MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, OID_802_11_SSID,
1568 sizeof(struct rt_ndis_802_11_ssid), &OidSsid);
1569 RTMP_MLME_HANDLER(pAd);
1574 ==========================================================================
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(struct rt_rtmp_adapter *pAd, unsigned long Now32)
1588 struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
1589 struct rt_bss_entry *pBss;
1591 DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForRoaming\n"));
1592 /* put all roaming candidates into RoamTab, and sort in RSSI order */
1593 BssTableInit(pRoamTab);
1594 for (i = 0; i < pAd->ScanTab.BssNr; i++) {
1595 pBss = &pAd->ScanTab.BssEntry[i];
1597 if ((pBss->LastBeaconRxTime + pAd->StaCfg.BeaconLostTime) <
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,
1610 sizeof(struct rt_bss_entry));
1611 pRoamTab->BssNr += 1;
1614 if (pRoamTab->BssNr > 0) {
1615 /* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
1616 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
1617 pAd->RalinkCounters.PoorCQIRoamingCount++;
1618 DBGPRINT(RT_DEBUG_TRACE,
1619 ("MMCHK - Roaming attempt #%ld\n",
1620 pAd->RalinkCounters.PoorCQIRoamingCount));
1621 MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE,
1622 MT2_MLME_ROAMING_REQ, 0, NULL);
1623 RTMP_MLME_HANDLER(pAd);
1626 DBGPRINT(RT_DEBUG_TRACE,
1627 ("<== MlmeCheckForRoaming(# of candidate= %d)\n",
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(struct rt_rtmp_adapter *pAd)
1646 struct rt_bss_table *pRoamTab = &pAd->MlmeAux.RoamTab;
1647 struct rt_bss_entry *pBss;
1649 DBGPRINT(RT_DEBUG_TRACE, ("==> MlmeCheckForFastRoaming\n"));
1650 /* put all roaming candidates into RoamTab, and sort in RSSI order */
1651 BssTableInit(pRoamTab);
1652 for (i = 0; i < pAd->ScanTab.BssNr; i++) {
1653 pBss = &pAd->ScanTab.BssEntry[i];
1655 if ((pBss->Rssi <= -50)
1656 && (pBss->Channel == pAd->CommonCfg.Channel))
1657 continue; /* RSSI too weak. forget it. */
1658 if (MAC_ADDR_EQUAL(pBss->Bssid, pAd->CommonCfg.Bssid))
1659 continue; /* skip current AP */
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,
1679 sizeof(struct rt_bss_entry));
1680 pRoamTab->BssNr += 1;
1683 DBGPRINT(RT_DEBUG_TRACE,
1684 ("<== MlmeCheckForFastRoaming (BssNr=%d)\n", pRoamTab->BssNr));
1685 if (pRoamTab->BssNr > 0) {
1686 /* check CntlMachine.CurrState to avoid collision with NDIS SetOID request */
1687 if (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) {
1688 pAd->RalinkCounters.PoorCQIRoamingCount++;
1689 DBGPRINT(RT_DEBUG_TRACE,
1690 ("MMCHK - Roaming attempt #%ld\n",
1691 pAd->RalinkCounters.PoorCQIRoamingCount));
1692 MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE,
1693 MT2_MLME_ROAMING_REQ, 0, NULL);
1694 RTMP_MLME_HANDLER(pAd);
1702 void MlmeSetTxRate(struct rt_rtmp_adapter *pAd,
1703 struct rt_mac_table_entry *pEntry, struct rt_rtmp_tx_rate_switch * pTxRate)
1705 u8 MaxMode = MODE_OFDM;
1707 MaxMode = MODE_HTGREENFIELD;
1709 if (pTxRate->STBC && (pAd->StaCfg.MaxHTPhyMode.field.STBC)
1710 && (pAd->Antenna.field.TxPath == 2))
1711 pAd->StaCfg.HTPhyMode.field.STBC = STBC_USE;
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 = (u16)(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(struct rt_rtmp_adapter *pAd)
1845 u8 UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx;
1846 unsigned long i, AccuTxTotalCnt = 0, TxTotalCnt;
1847 unsigned long TxErrorRatio = 0;
1848 BOOLEAN bTxRateChanged = FALSE, bUpgradeQuality = FALSE;
1849 struct rt_rtmp_tx_rate_switch *pCurrTxRate, *pNextTxRate = NULL;
1852 u8 InitTxRateIdx = 0, TrainUp, TrainDown;
1853 char Rssi, RssiOffset = 0;
1854 TX_STA_CNT1_STRUC StaTx1;
1855 TX_STA_CNT0_STRUC TxStaCnt0;
1856 unsigned long TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
1857 struct rt_mac_table_entry *pEntry;
1858 struct rt_rssi_sample *pRssi = &pAd->StaCfg.RssiSample;
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;
1939 unsigned long Index;
1940 unsigned long MACValue;
1942 RTMP_IO_READ32(pAd, TX_RTY_CFG, &TxRtyCfg.word);
1943 TxRtyCfgtmp.word = TxRtyCfg.word;
1944 TxRtyCfg.field.LongRtyLimit = 0x0;
1945 TxRtyCfg.field.ShortRtyLimit = 0x0;
1946 RTMP_IO_WRITE32(pAd, TX_RTY_CFG, TxRtyCfg.word);
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 (struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
1986 if ((pEntry->HTPhyMode.field.MCS != pCurrTxRate->CurrMCS)
1987 /*&& (pAd->StaCfg.bAutoTxRateSwitch == TRUE) */
1990 /* Need to sync Real Tx rate and our record. */
1991 /* Then return for next DRS. */
1993 (struct rt_rtmp_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 (struct rt_rtmp_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 u8 MCS0 = 0, MCS1 = 0, MCS2 = 0, MCS3 = 0, MCS4 =
2045 0, MCS5 = 0, MCS6 = 0, MCS7 = 0;
2046 u8 MCS12 = 0, MCS13 = 0, MCS14 = 0, MCS15 = 0;
2047 u8 MCS20 = 0, MCS21 = 0, MCS22 = 0, MCS23 = 0; /* 3*3 */
2049 /* check the existence and index of each needed MCS */
2050 while (idx < pTable[0]) {
2052 (struct rt_rtmp_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, however Atheros's chip has bugs when short GI */
2084 } else if (pCurrTxRate->CurrMCS == MCS_20) /* 3*3 */
2087 } else if (pCurrTxRate->CurrMCS == MCS_21) {
2089 } else if (pCurrTxRate->CurrMCS == MCS_22) {
2091 } else if (pCurrTxRate->CurrMCS == MCS_23) {
2097 if (pAd->LatchRfRegs.Channel <= 14) {
2098 if (pAd->NicConfig2.field.ExternalLNAForG) {
2104 if (pAd->NicConfig2.field.ExternalLNAForA) {
2112 if ((pTable == RateSwitchTable11BGN3S) || (pTable == RateSwitchTable11N3S) || (pTable == RateSwitchTable)) { /* N mode with 3 stream // 3*3 */
2113 if (MCS23 && (Rssi >= -70))
2115 else if (MCS22 && (Rssi >= -72))
2117 else if (MCS21 && (Rssi >= -76))
2119 else if (MCS20 && (Rssi >= -78))
2121 else if (MCS4 && (Rssi >= -82))
2123 else if (MCS3 && (Rssi >= -84))
2125 else if (MCS2 && (Rssi >= -86))
2127 else if (MCS1 && (Rssi >= -88))
2132 /* else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) ||(pTable == RateSwitchTable11N2S) ||(pTable == RateSwitchTable11N2SForABand) || (pTable == RateSwitchTable)) */
2133 else if ((pTable == RateSwitchTable11BGN2S) || (pTable == RateSwitchTable11BGN2SForABand) || (pTable == RateSwitchTable11N2S) || (pTable == RateSwitchTable11N2SForABand)) /* 3*3 */
2134 { /* N mode with 2 stream */
2135 if (MCS15 && (Rssi >= (-70 + RssiOffset)))
2137 else if (MCS14 && (Rssi >= (-72 + RssiOffset)))
2139 else if (MCS13 && (Rssi >= (-76 + RssiOffset)))
2141 else if (MCS12 && (Rssi >= (-78 + RssiOffset)))
2143 else if (MCS4 && (Rssi >= (-82 + RssiOffset)))
2145 else if (MCS3 && (Rssi >= (-84 + RssiOffset)))
2147 else if (MCS2 && (Rssi >= (-86 + RssiOffset)))
2149 else if (MCS1 && (Rssi >= (-88 + RssiOffset)))
2153 } else if ((pTable == RateSwitchTable11BGN1S) || (pTable == RateSwitchTable11N1S)) { /* N mode with 1 stream */
2154 if (MCS7 && (Rssi > (-72 + RssiOffset)))
2156 else if (MCS6 && (Rssi > (-74 + RssiOffset)))
2158 else if (MCS5 && (Rssi > (-77 + RssiOffset)))
2160 else if (MCS4 && (Rssi > (-79 + RssiOffset)))
2162 else if (MCS3 && (Rssi > (-81 + RssiOffset)))
2164 else if (MCS2 && (Rssi > (-83 + RssiOffset)))
2166 else if (MCS1 && (Rssi > (-86 + RssiOffset)))
2170 } else { /* Legacy mode */
2171 if (MCS7 && (Rssi > -70))
2173 else if (MCS6 && (Rssi > -74))
2175 else if (MCS5 && (Rssi > -78))
2177 else if (MCS4 && (Rssi > -82))
2179 else if (MCS4 == 0) /* for B-only mode */
2181 else if (MCS3 && (Rssi > -85))
2183 else if (MCS2 && (Rssi > -87))
2185 else if (MCS1 && (Rssi > -90))
2191 /* if (TxRateIdx != pAd->CommonCfg.TxRateIndex) */
2193 pEntry->CurrTxRateIndex = TxRateIdx;
2195 (struct rt_rtmp_tx_rate_switch *) &
2196 pTable[(pEntry->CurrTxRateIndex + 1) * 5];
2197 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2200 NdisZeroMemory(pEntry->TxQuality,
2202 MAX_STEP_OF_TX_RATE_SWITCH);
2203 NdisZeroMemory(pEntry->PER,
2205 MAX_STEP_OF_TX_RATE_SWITCH);
2206 pEntry->fLastSecAccordingRSSI = TRUE;
2207 /* reset all OneSecTx counters */
2208 RESET_ONE_SEC_TX_CNT(pEntry);
2213 if (pEntry->fLastSecAccordingRSSI == TRUE) {
2214 pEntry->fLastSecAccordingRSSI = FALSE;
2215 pEntry->LastSecTxRateChangeAction = 0;
2216 /* reset all OneSecTx counters */
2217 RESET_ONE_SEC_TX_CNT(pEntry);
2223 BOOLEAN bTrainUpDown = FALSE;
2225 pEntry->CurrTxRateStableTime++;
2227 /* downgrade TX quality if PER >= Rate-Down threshold */
2228 if (TxErrorRatio >= TrainDown) {
2229 bTrainUpDown = TRUE;
2230 pEntry->TxQuality[CurrRateIdx] =
2231 DRS_TX_QUALITY_WORST_BOUND;
2233 /* upgrade TX quality if PER <= Rate-Up threshold */
2234 else if (TxErrorRatio <= TrainUp) {
2235 bTrainUpDown = TRUE;
2236 bUpgradeQuality = TRUE;
2237 if (pEntry->TxQuality[CurrRateIdx])
2238 pEntry->TxQuality[CurrRateIdx]--; /* quality very good in CurrRate */
2240 if (pEntry->TxRateUpPenalty)
2241 pEntry->TxRateUpPenalty--;
2242 else if (pEntry->TxQuality[UpRateIdx])
2243 pEntry->TxQuality[UpRateIdx]--; /* may improve next UP rate's quality */
2246 pEntry->PER[CurrRateIdx] = (u8)TxErrorRatio;
2249 /* perform DRS - consider TxRate Down first, then rate up. */
2250 if ((CurrRateIdx != DownRateIdx)
2251 && (pEntry->TxQuality[CurrRateIdx] >=
2252 DRS_TX_QUALITY_WORST_BOUND)) {
2253 pEntry->CurrTxRateIndex = DownRateIdx;
2254 } else if ((CurrRateIdx != UpRateIdx)
2255 && (pEntry->TxQuality[UpRateIdx] <=
2257 pEntry->CurrTxRateIndex = UpRateIdx;
2262 /* if rate-up happen, clear all bad history of all TX rates */
2263 if (pEntry->CurrTxRateIndex > CurrRateIdx) {
2264 pEntry->CurrTxRateStableTime = 0;
2265 pEntry->TxRateUpPenalty = 0;
2266 pEntry->LastSecTxRateChangeAction = 1; /* rate UP */
2267 NdisZeroMemory(pEntry->TxQuality,
2269 MAX_STEP_OF_TX_RATE_SWITCH);
2270 NdisZeroMemory(pEntry->PER,
2272 MAX_STEP_OF_TX_RATE_SWITCH);
2275 /* For TxRate fast train up */
2277 if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2278 RTMPSetTimer(&pAd->StaCfg.
2279 StaQuickResponeForRateUpTimer,
2283 StaQuickResponeForRateUpTimerRunning = TRUE;
2285 bTxRateChanged = TRUE;
2287 /* if rate-down happen, only clear DownRate's bad history */
2288 else if (pEntry->CurrTxRateIndex < CurrRateIdx) {
2289 pEntry->CurrTxRateStableTime = 0;
2290 pEntry->TxRateUpPenalty = 0; /* no penalty */
2291 pEntry->LastSecTxRateChangeAction = 2; /* rate DOWN */
2292 pEntry->TxQuality[pEntry->CurrTxRateIndex] = 0;
2293 pEntry->PER[pEntry->CurrTxRateIndex] = 0;
2296 /* For TxRate fast train down */
2298 if (!pAd->StaCfg.StaQuickResponeForRateUpTimerRunning) {
2299 RTMPSetTimer(&pAd->StaCfg.
2300 StaQuickResponeForRateUpTimer,
2304 StaQuickResponeForRateUpTimerRunning = TRUE;
2306 bTxRateChanged = TRUE;
2308 pEntry->LastSecTxRateChangeAction = 0; /* rate no change */
2309 bTxRateChanged = FALSE;
2312 pEntry->LastTxOkCount = TxSuccess;
2316 /* to fix tcp ack issue */
2318 && (pAd->RalinkCounters.OneSecReceivedByteCount >
2319 (pAd->RalinkCounters.
2320 OneSecTransmittedByteCount * 5))) {
2321 tmpTxRate = DownRateIdx;
2322 DBGPRINT_RAW(RT_DEBUG_TRACE,
2323 ("DRS: Rx(%d) is 5 times larger than Tx(%d), use low rate (curr=%d, tmp=%d)\n",
2324 pAd->RalinkCounters.
2325 OneSecReceivedByteCount,
2326 pAd->RalinkCounters.
2327 OneSecTransmittedByteCount,
2328 pEntry->CurrTxRateIndex,
2331 tmpTxRate = pEntry->CurrTxRateIndex;
2335 (struct rt_rtmp_tx_rate_switch *) & pTable[(tmpTxRate + 1) *
2338 if (bTxRateChanged && pNextTxRate) {
2339 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2341 /* reset all OneSecTx counters */
2342 RESET_ONE_SEC_TX_CNT(pEntry);
2347 ========================================================================
2348 Routine Description:
2349 Station side, Auto TxRate faster train up timer call back function.
2352 SystemSpecific1 - Not used.
2353 FunctionContext - Pointer to our Adapter context.
2354 SystemSpecific2 - Not used.
2355 SystemSpecific3 - Not used.
2360 ========================================================================
2362 void StaQuickResponeForRateUpExec(void *SystemSpecific1,
2363 void *FunctionContext,
2364 void *SystemSpecific2,
2365 void *SystemSpecific3)
2367 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
2368 u8 UpRateIdx = 0, DownRateIdx = 0, CurrRateIdx = 0;
2369 unsigned long TxTotalCnt;
2370 unsigned long TxErrorRatio = 0;
2371 BOOLEAN bTxRateChanged; /*, bUpgradeQuality = FALSE; */
2372 struct rt_rtmp_tx_rate_switch *pCurrTxRate, *pNextTxRate = NULL;
2375 u8 InitTxRateIdx = 0, TrainUp, TrainDown;
2376 TX_STA_CNT1_STRUC StaTx1;
2377 TX_STA_CNT0_STRUC TxStaCnt0;
2379 unsigned long TxRetransmit = 0, TxSuccess = 0, TxFailCount = 0;
2380 struct rt_mac_table_entry *pEntry;
2383 pAd->StaCfg.StaQuickResponeForRateUpTimerRunning = FALSE;
2386 /* walk through MAC table, see if need to change AP's TX rate toward each entry */
2388 for (i = 1; i < MAX_LEN_OF_MAC_TABLE; i++) {
2389 pEntry = &pAd->MacTab.Content[i];
2391 /* check if this entry need to switch rate automatically */
2392 if (RTMPCheckEntryEnableAutoRateSwitch(pAd, pEntry) == FALSE)
2395 if (INFRA_ON(pAd) && (i == 1))
2396 Rssi = RTMPMaxRssi(pAd,
2397 pAd->StaCfg.RssiSample.AvgRssi0,
2398 pAd->StaCfg.RssiSample.AvgRssi1,
2399 pAd->StaCfg.RssiSample.AvgRssi2);
2401 Rssi = RTMPMaxRssi(pAd,
2402 pEntry->RssiSample.AvgRssi0,
2403 pEntry->RssiSample.AvgRssi1,
2404 pEntry->RssiSample.AvgRssi2);
2406 CurrRateIdx = pAd->CommonCfg.TxRateIndex;
2408 MlmeSelectTxRateTable(pAd, pEntry, &pTable, &TableSize,
2411 /* decide the next upgrade rate and downgrade rate, if any */
2412 if ((CurrRateIdx > 0) && (CurrRateIdx < (TableSize - 1))) {
2413 UpRateIdx = CurrRateIdx + 1;
2414 DownRateIdx = CurrRateIdx - 1;
2415 } else if (CurrRateIdx == 0) {
2416 UpRateIdx = CurrRateIdx + 1;
2417 DownRateIdx = CurrRateIdx;
2418 } else if (CurrRateIdx == (TableSize - 1)) {
2419 UpRateIdx = CurrRateIdx;
2420 DownRateIdx = CurrRateIdx - 1;
2424 (struct rt_rtmp_tx_rate_switch *) & pTable[(CurrRateIdx + 1) * 5];
2426 if ((Rssi > -65) && (pCurrTxRate->Mode >= MODE_HTMIX)) {
2428 (pCurrTxRate->TrainUp +
2429 (pCurrTxRate->TrainUp >> 1));
2431 (pCurrTxRate->TrainDown +
2432 (pCurrTxRate->TrainDown >> 1));
2434 TrainUp = pCurrTxRate->TrainUp;
2435 TrainDown = pCurrTxRate->TrainDown;
2438 if (pAd->MacTab.Size == 1) {
2439 /* Update statistic counter */
2440 RTMP_IO_READ32(pAd, TX_STA_CNT0, &TxStaCnt0.word);
2441 RTMP_IO_READ32(pAd, TX_STA_CNT1, &StaTx1.word);
2443 TxRetransmit = StaTx1.field.TxRetransmit;
2444 TxSuccess = StaTx1.field.TxSuccess;
2445 TxFailCount = TxStaCnt0.field.TxFailCount;
2446 TxTotalCnt = TxRetransmit + TxSuccess + TxFailCount;
2448 pAd->RalinkCounters.OneSecTxRetryOkCount +=
2449 StaTx1.field.TxRetransmit;
2450 pAd->RalinkCounters.OneSecTxNoRetryOkCount +=
2451 StaTx1.field.TxSuccess;
2452 pAd->RalinkCounters.OneSecTxFailCount +=
2453 TxStaCnt0.field.TxFailCount;
2454 pAd->WlanCounters.TransmittedFragmentCount.u.LowPart +=
2455 StaTx1.field.TxSuccess;
2456 pAd->WlanCounters.RetryCount.u.LowPart +=
2457 StaTx1.field.TxRetransmit;
2458 pAd->WlanCounters.FailedCount.u.LowPart +=
2459 TxStaCnt0.field.TxFailCount;
2464 TxFailCount) * 100) / TxTotalCnt;
2466 TxTotalCnt = pEntry->OneSecTxNoRetryOkCount +
2467 pEntry->OneSecTxRetryOkCount +
2468 pEntry->OneSecTxFailCount;
2472 ((pEntry->OneSecTxRetryOkCount +
2473 pEntry->OneSecTxFailCount) * 100) /
2478 /* CASE 1. when TX samples are fewer than 15, then decide TX rate solely on RSSI */
2479 /* (criteria copied from RT2500 for Netopia case) */
2481 if (TxTotalCnt <= 12) {
2482 NdisZeroMemory(pAd->DrsCounters.TxQuality,
2484 MAX_STEP_OF_TX_RATE_SWITCH);
2485 NdisZeroMemory(pAd->DrsCounters.PER,
2487 MAX_STEP_OF_TX_RATE_SWITCH);
2489 if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1)
2490 && (CurrRateIdx != DownRateIdx)) {
2491 pAd->CommonCfg.TxRateIndex = DownRateIdx;
2492 pAd->DrsCounters.TxQuality[CurrRateIdx] =
2493 DRS_TX_QUALITY_WORST_BOUND;
2495 if ((pAd->DrsCounters.LastSecTxRateChangeAction ==
2496 2) && (CurrRateIdx != UpRateIdx)) {
2497 pAd->CommonCfg.TxRateIndex = UpRateIdx;
2500 DBGPRINT_RAW(RT_DEBUG_TRACE,
2501 ("QuickDRS: TxTotalCnt <= 15, train back to original rate \n"));
2506 unsigned long OneSecTxNoRetryOKRationCount;
2508 if (pAd->DrsCounters.LastTimeTxRateChangeAction == 0)
2513 /* downgrade TX quality if PER >= Rate-Down threshold */
2514 if (TxErrorRatio >= TrainDown) {
2515 pAd->DrsCounters.TxQuality[CurrRateIdx] =
2516 DRS_TX_QUALITY_WORST_BOUND;
2519 pAd->DrsCounters.PER[CurrRateIdx] =
2522 OneSecTxNoRetryOKRationCount = (TxSuccess * ratio);
2524 /* perform DRS - consider TxRate Down first, then rate up. */
2525 if ((pAd->DrsCounters.LastSecTxRateChangeAction == 1)
2526 && (CurrRateIdx != DownRateIdx)) {
2527 if ((pAd->DrsCounters.LastTxOkCount + 2) >=
2528 OneSecTxNoRetryOKRationCount) {
2529 pAd->CommonCfg.TxRateIndex =
2532 TxQuality[CurrRateIdx] =
2533 DRS_TX_QUALITY_WORST_BOUND;
2538 if ((pAd->DrsCounters.LastSecTxRateChangeAction ==
2539 2) && (CurrRateIdx != UpRateIdx)) {
2540 if ((TxErrorRatio >= 50)
2541 || (TxErrorRatio >= TrainDown)) {
2543 } else if ((pAd->DrsCounters.LastTxOkCount + 2)
2544 >= OneSecTxNoRetryOKRationCount) {
2545 pAd->CommonCfg.TxRateIndex = UpRateIdx;
2550 /* if rate-up happen, clear all bad history of all TX rates */
2551 if (pAd->CommonCfg.TxRateIndex > CurrRateIdx) {
2552 pAd->DrsCounters.TxRateUpPenalty = 0;
2553 NdisZeroMemory(pAd->DrsCounters.TxQuality,
2555 MAX_STEP_OF_TX_RATE_SWITCH);
2556 NdisZeroMemory(pAd->DrsCounters.PER,
2558 MAX_STEP_OF_TX_RATE_SWITCH);
2559 bTxRateChanged = TRUE;
2561 /* if rate-down happen, only clear DownRate's bad history */
2562 else if (pAd->CommonCfg.TxRateIndex < CurrRateIdx) {
2563 DBGPRINT_RAW(RT_DEBUG_TRACE,
2564 ("QuickDRS: --TX rate from %d to %d \n",
2565 CurrRateIdx, pAd->CommonCfg.TxRateIndex));
2567 pAd->DrsCounters.TxRateUpPenalty = 0; /* no penalty */
2568 pAd->DrsCounters.TxQuality[pAd->CommonCfg.TxRateIndex] =
2570 pAd->DrsCounters.PER[pAd->CommonCfg.TxRateIndex] = 0;
2571 bTxRateChanged = TRUE;
2573 bTxRateChanged = FALSE;
2577 (struct rt_rtmp_tx_rate_switch *) &
2578 pTable[(pAd->CommonCfg.TxRateIndex + 1) * 5];
2579 if (bTxRateChanged && pNextTxRate) {
2580 MlmeSetTxRate(pAd, pEntry, pNextTxRate);
2586 ==========================================================================
2588 This routine is executed periodically inside MlmePeriodicExec() after
2589 association with an AP.
2590 It checks if StaCfg.Psm is consistent with user policy (recorded in
2591 StaCfg.WindowsPowerMode). If not, enforce user policy. However,
2592 there're some conditions to consider:
2593 1. we don't support power-saving in ADHOC mode, so Psm=PWR_ACTIVE all
2594 the time when Mibss==TRUE
2595 2. When link up in INFRA mode, Psm should not be switch to PWR_SAVE
2596 if outgoing traffic available in TxRing or MgmtRing.
2598 1. change pAd->StaCfg.Psm to PWR_SAVE or leave it untouched
2600 IRQL = DISPATCH_LEVEL
2602 ==========================================================================
2604 void MlmeCheckPsmChange(struct rt_rtmp_adapter *pAd, unsigned long Now32)
2606 unsigned long PowerMode;
2609 /* 1. Psm maybe ON only happen in INFRASTRUCTURE mode */
2610 /* 2. user wants either MAX_PSP or FAST_PSP */
2611 /* 3. but current psm is not in PWR_SAVE */
2612 /* 4. CNTL state machine is not doing SCANning */
2613 /* 5. no TX SUCCESS event for the past 1-sec period */
2614 PowerMode = pAd->StaCfg.WindowsPowerMode;
2616 if (INFRA_ON(pAd) &&
2617 (PowerMode != Ndis802_11PowerModeCAM) &&
2618 (pAd->StaCfg.Psm == PWR_ACTIVE) &&
2619 /* (! RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) */
2620 (pAd->Mlme.CntlMachine.CurrState == CNTL_IDLE) &&
2621 RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP)
2623 (pAd->RalinkCounters.OneSecTxNoRetryOkCount == 0) &&
2624 (pAd->RalinkCounters.OneSecTxRetryOkCount == 0) */
2626 NdisGetSystemUpTime(&pAd->Mlme.LastSendNULLpsmTime);
2627 pAd->RalinkCounters.RxCountSinceLastNULL = 0;
2628 RTMP_SET_PSM_BIT(pAd, PWR_SAVE);
2630 (pAd->CommonCfg.bAPSDCapable
2631 && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) {
2632 RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, FALSE);
2634 RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
2639 /* IRQL = PASSIVE_LEVEL */
2640 /* IRQL = DISPATCH_LEVEL */
2641 void MlmeSetPsmBit(struct rt_rtmp_adapter *pAd, u16 psm)
2643 AUTO_RSP_CFG_STRUC csr4;
2645 pAd->StaCfg.Psm = psm;
2646 RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
2647 csr4.field.AckCtsPsmBit = (psm == PWR_SAVE) ? 1 : 0;
2648 RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
2650 DBGPRINT(RT_DEBUG_TRACE, ("MlmeSetPsmBit = %d\n", psm));
2654 ==========================================================================
2656 This routine calculates TxPER, RxPER of the past N-sec period. And
2657 according to the calculation result, ChannelQuality is calculated here
2658 to decide if current AP is still doing the job.
2660 If ChannelQuality is not good, a ROAMing attempt may be tried later.
2662 StaCfg.ChannelQuality - 0..100
2664 IRQL = DISPATCH_LEVEL
2666 NOTE: This routine decide channle quality based on RX CRC error ratio.
2667 Caller should make sure a function call to NICUpdateRawCounters(pAd)
2668 is performed right before this routine, so that this routine can decide
2669 channel quality based on the most up-to-date information
2670 ==========================================================================
2672 void MlmeCalculateChannelQuality(struct rt_rtmp_adapter *pAd,
2673 struct rt_mac_table_entry *pMacEntry, unsigned long Now32)
2675 unsigned long TxOkCnt, TxCnt, TxPER, TxPRR;
2676 unsigned long RxCnt, RxPER;
2679 struct rt_rssi_sample *pRssiSample = NULL;
2680 u32 OneSecTxNoRetryOkCount = 0;
2681 u32 OneSecTxRetryOkCount = 0;
2682 u32 OneSecTxFailCount = 0;
2683 u32 OneSecRxOkCnt = 0;
2684 u32 OneSecRxFcsErrCnt = 0;
2685 unsigned long ChannelQuality = 0; /* 0..100, Channel Quality Indication for Roaming */
2686 unsigned long BeaconLostTime = pAd->StaCfg.BeaconLostTime;
2688 if (pAd->OpMode == OPMODE_STA) {
2689 pRssiSample = &pAd->StaCfg.RssiSample;
2690 OneSecTxNoRetryOkCount =
2691 pAd->RalinkCounters.OneSecTxNoRetryOkCount;
2692 OneSecTxRetryOkCount = pAd->RalinkCounters.OneSecTxRetryOkCount;
2693 OneSecTxFailCount = pAd->RalinkCounters.OneSecTxFailCount;
2694 OneSecRxOkCnt = pAd->RalinkCounters.OneSecRxOkCnt;
2695 OneSecRxFcsErrCnt = pAd->RalinkCounters.OneSecRxFcsErrCnt;
2698 MaxRssi = RTMPMaxRssi(pAd, pRssiSample->LastRssi0,
2699 pRssiSample->LastRssi1, pRssiSample->LastRssi2);
2702 /* calculate TX packet error ratio and TX retry ratio - if too few TX samples, skip TX related statistics */
2704 TxOkCnt = OneSecTxNoRetryOkCount + OneSecTxRetryOkCount;
2705 TxCnt = TxOkCnt + OneSecTxFailCount;
2710 TxPER = (OneSecTxFailCount * 100) / TxCnt;
2711 TxPRR = ((TxCnt - OneSecTxNoRetryOkCount) * 100) / TxCnt;
2715 /* calculate RX PER - don't take RxPER into consideration if too few sample */
2717 RxCnt = OneSecRxOkCnt + OneSecRxFcsErrCnt;
2721 RxPER = (OneSecRxFcsErrCnt * 100) / RxCnt;
2724 /* decide ChannelQuality based on: 1)last BEACON received time, 2)last RSSI, 3)TxPER, and 4)RxPER */
2726 if ((pAd->OpMode == OPMODE_STA) && INFRA_ON(pAd) && (OneSecTxNoRetryOkCount < 2) && /* no heavy traffic */
2727 ((pAd->StaCfg.LastBeaconRxTime + BeaconLostTime) < Now32)) {
2728 DBGPRINT(RT_DEBUG_TRACE,
2729 ("BEACON lost > %ld msec with TxOkCnt=%ld -> CQI=0\n",
2730 BeaconLostTime, TxOkCnt));
2733 /* Normalize Rssi */
2736 else if (MaxRssi < -90)
2739 NorRssi = (MaxRssi + 90) * 2;
2741 /* ChannelQuality = W1*RSSI + W2*TxPRR + W3*RxPER (RSSI 0..100), (TxPER 100..0), (RxPER 100..0) */
2742 ChannelQuality = (RSSI_WEIGHTING * NorRssi +
2743 TX_WEIGHTING * (100 - TxPRR) +
2744 RX_WEIGHTING * (100 - RxPER)) / 100;
2747 if (pAd->OpMode == OPMODE_STA)
2748 pAd->Mlme.ChannelQuality =
2749 (ChannelQuality > 100) ? 100 : ChannelQuality;
2753 /* IRQL = DISPATCH_LEVEL */
2754 void MlmeSetTxPreamble(struct rt_rtmp_adapter *pAd, u16 TxPreamble)
2756 AUTO_RSP_CFG_STRUC csr4;
2759 /* Always use Long preamble before verifiation short preamble functionality works well. */
2760 /* Todo: remove the following line if short preamble functionality works */
2762 /*TxPreamble = Rt802_11PreambleLong; */
2764 RTMP_IO_READ32(pAd, AUTO_RSP_CFG, &csr4.word);
2765 if (TxPreamble == Rt802_11PreambleLong) {
2766 DBGPRINT(RT_DEBUG_TRACE,
2767 ("MlmeSetTxPreamble (= long PREAMBLE)\n"));
2768 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
2769 csr4.field.AutoResponderPreamble = 0;
2771 /* NOTE: 1Mbps should always use long preamble */
2772 DBGPRINT(RT_DEBUG_TRACE,
2773 ("MlmeSetTxPreamble (= short PREAMBLE)\n"));
2774 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
2775 csr4.field.AutoResponderPreamble = 1;
2778 RTMP_IO_WRITE32(pAd, AUTO_RSP_CFG, csr4.word);
2782 ==========================================================================
2784 Update basic rate bitmap
2785 ==========================================================================
2788 void UpdateBasicRateBitmap(struct rt_rtmp_adapter *pAdapter)
2791 /* 1 2 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */
2792 u8 rate[] = { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
2793 u8 *sup_p = pAdapter->CommonCfg.SupRate;
2794 u8 *ext_p = pAdapter->CommonCfg.ExtRate;
2795 unsigned long bitmap = pAdapter->CommonCfg.BasicRateBitmap;
2797 /* if A mode, always use fix BasicRateBitMap */
2798 /*if (pAdapter->CommonCfg.Channel == PHY_11A) */
2799 if (pAdapter->CommonCfg.Channel > 14)
2800 pAdapter->CommonCfg.BasicRateBitmap = 0x150; /* 6, 12, 24M */
2803 if (pAdapter->CommonCfg.BasicRateBitmap > 4095) {
2804 /* (2 ^ MAX_LEN_OF_SUPPORTED_RATES) -1 */
2808 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2813 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2814 if (bitmap & (1 << i)) {
2815 for (j = 0; j < MAX_LEN_OF_SUPPORTED_RATES; j++) {
2816 if (sup_p[j] == rate[i])
2821 for (j = 0; j < MAX_LEN_OF_SUPPORTED_RATES; j++) {
2822 if (ext_p[j] == rate[i])
2828 } /* End of UpdateBasicRateBitmap */
2830 /* IRQL = PASSIVE_LEVEL */
2831 /* IRQL = DISPATCH_LEVEL */
2832 /* bLinkUp is to identify the inital link speed. */
2833 /* TRUE indicates the rate update at linkup, we should not try to set the rate at 54Mbps. */
2834 void MlmeUpdateTxRates(struct rt_rtmp_adapter *pAd, IN BOOLEAN bLinkUp, u8 apidx)
2837 u8 Rate = RATE_6, MaxDesire = RATE_1, MaxSupport = RATE_1;
2838 u8 MinSupport = RATE_54;
2839 unsigned long BasicRateBitmap = 0;
2840 u8 CurrBasicRate = RATE_1;
2841 u8 *pSupRate, SupRateLen, *pExtRate, ExtRateLen;
2842 PHTTRANSMIT_SETTING pHtPhy = NULL;
2843 PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
2844 PHTTRANSMIT_SETTING pMinHtPhy = NULL;
2845 BOOLEAN *auto_rate_cur_p;
2846 u8 HtMcs = MCS_AUTO;
2848 /* find max desired rate */
2849 UpdateBasicRateBitmap(pAd);
2852 auto_rate_cur_p = NULL;
2853 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
2854 switch (pAd->CommonCfg.DesireRate[i] & 0x7f) {
2903 /*default: Rate = RATE_1; break; */
2905 if (MaxDesire < Rate)
2909 /*=========================================================================== */
2910 /*=========================================================================== */
2912 pHtPhy = &pAd->StaCfg.HTPhyMode;
2913 pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
2914 pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
2916 auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
2917 HtMcs = pAd->StaCfg.DesiredTransmitSetting.field.MCS;
2919 if ((pAd->StaCfg.BssType == BSS_ADHOC) &&
2920 (pAd->CommonCfg.PhyMode == PHY_11B) &&
2921 (MaxDesire > RATE_11)) {
2922 MaxDesire = RATE_11;
2926 pAd->CommonCfg.MaxDesiredRate = MaxDesire;
2927 pMinHtPhy->word = 0;
2928 pMaxHtPhy->word = 0;
2931 /* Auto rate switching is enabled only if more than one DESIRED RATES are */
2932 /* specified; otherwise disabled */
2934 /*OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2935 /*pAd->CommonCfg.bAutoTxRateSwitch = FALSE; */
2936 *auto_rate_cur_p = FALSE;
2938 /*OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2939 /*pAd->CommonCfg.bAutoTxRateSwitch = TRUE; */
2940 *auto_rate_cur_p = TRUE;
2943 if (HtMcs != MCS_AUTO) {
2944 /*OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2945 /*pAd->CommonCfg.bAutoTxRateSwitch = FALSE; */
2946 *auto_rate_cur_p = FALSE;
2948 /*OPSTATUS_SET_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED); */
2949 /*pAd->CommonCfg.bAutoTxRateSwitch = TRUE; */
2950 *auto_rate_cur_p = TRUE;
2953 if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) {
2954 pSupRate = &pAd->StaActive.SupRate[0];
2955 pExtRate = &pAd->StaActive.ExtRate[0];
2956 SupRateLen = pAd->StaActive.SupRateLen;
2957 ExtRateLen = pAd->StaActive.ExtRateLen;
2959 pSupRate = &pAd->CommonCfg.SupRate[0];
2960 pExtRate = &pAd->CommonCfg.ExtRate[0];
2961 SupRateLen = pAd->CommonCfg.SupRateLen;
2962 ExtRateLen = pAd->CommonCfg.ExtRateLen;
2965 /* find max supported rate */
2966 for (i = 0; i < SupRateLen; i++) {
2967 switch (pSupRate[i] & 0x7f) {
2970 if (pSupRate[i] & 0x80)
2971 BasicRateBitmap |= 0x0001;
2975 if (pSupRate[i] & 0x80)
2976 BasicRateBitmap |= 0x0002;
2980 if (pSupRate[i] & 0x80)
2981 BasicRateBitmap |= 0x0004;
2985 if (pSupRate[i] & 0x80)
2986 BasicRateBitmap |= 0x0008;
2989 Rate = RATE_6; /*if (pSupRate[i] & 0x80) */
2990 BasicRateBitmap |= 0x0010;
2994 if (pSupRate[i] & 0x80)
2995 BasicRateBitmap |= 0x0020;
2998 Rate = RATE_12; /*if (pSupRate[i] & 0x80) */
2999 BasicRateBitmap |= 0x0040;
3003 if (pSupRate[i] & 0x80)
3004 BasicRateBitmap |= 0x0080;
3007 Rate = RATE_24; /*if (pSupRate[i] & 0x80) */
3008 BasicRateBitmap |= 0x0100;
3012 if (pSupRate[i] & 0x80)
3013 BasicRateBitmap |= 0x0200;
3017 if (pSupRate[i] & 0x80)
3018 BasicRateBitmap |= 0x0400;
3022 if (pSupRate[i] & 0x80)
3023 BasicRateBitmap |= 0x0800;
3029 if (MaxSupport < Rate)
3032 if (MinSupport > Rate)
3036 for (i = 0; i < ExtRateLen; i++) {
3037 switch (pExtRate[i] & 0x7f) {
3040 if (pExtRate[i] & 0x80)
3041 BasicRateBitmap |= 0x0001;
3045 if (pExtRate[i] & 0x80)
3046 BasicRateBitmap |= 0x0002;
3050 if (pExtRate[i] & 0x80)
3051 BasicRateBitmap |= 0x0004;
3055 if (pExtRate[i] & 0x80)
3056 BasicRateBitmap |= 0x0008;
3059 Rate = RATE_6; /*if (pExtRate[i] & 0x80) */
3060 BasicRateBitmap |= 0x0010;
3064 if (pExtRate[i] & 0x80)
3065 BasicRateBitmap |= 0x0020;
3068 Rate = RATE_12; /*if (pExtRate[i] & 0x80) */
3069 BasicRateBitmap |= 0x0040;
3073 if (pExtRate[i] & 0x80)
3074 BasicRateBitmap |= 0x0080;
3077 Rate = RATE_24; /*if (pExtRate[i] & 0x80) */
3078 BasicRateBitmap |= 0x0100;
3082 if (pExtRate[i] & 0x80)
3083 BasicRateBitmap |= 0x0200;
3087 if (pExtRate[i] & 0x80)
3088 BasicRateBitmap |= 0x0400;
3092 if (pExtRate[i] & 0x80)
3093 BasicRateBitmap |= 0x0800;
3099 if (MaxSupport < Rate)
3102 if (MinSupport > Rate)
3106 RTMP_IO_WRITE32(pAd, LEGACY_BASIC_RATE, BasicRateBitmap);
3109 /* pAd->CommonCfg.BasicRateBitmap = BasicRateBitmap; */
3111 /* calculate the exptected ACK rate for each TX rate. This info is used to caculate */
3112 /* the DURATION field of outgoing uniicast DATA/MGMT frame */
3113 for (i = 0; i < MAX_LEN_OF_SUPPORTED_RATES; i++) {
3114 if (BasicRateBitmap & (0x01 << i))
3115 CurrBasicRate = (u8)i;
3116 pAd->CommonCfg.ExpectedACKRate[i] = CurrBasicRate;
3119 DBGPRINT(RT_DEBUG_TRACE,
3120 ("MlmeUpdateTxRates[MaxSupport = %d] = MaxDesire %d Mbps\n",
3121 RateIdToMbps[MaxSupport], RateIdToMbps[MaxDesire]));
3122 /* max tx rate = min {max desire rate, max supported rate} */
3123 if (MaxSupport < MaxDesire)
3124 pAd->CommonCfg.MaxTxRate = MaxSupport;
3126 pAd->CommonCfg.MaxTxRate = MaxDesire;
3128 pAd->CommonCfg.MinTxRate = MinSupport;
3129 /* 2003-07-31 john - 2500 doesn't have good sensitivity at high OFDM rates. to increase the success */
3130 /* ratio of initial DHCP packet exchange, TX rate starts from a lower rate depending */
3131 /* on average RSSI */
3132 /* 1. RSSI >= -70db, start at 54 Mbps (short distance) */
3133 /* 2. -70 > RSSI >= -75, start at 24 Mbps (mid distance) */
3134 /* 3. -75 > RSSI, start at 11 Mbps (long distance) */
3135 if (*auto_rate_cur_p) {
3138 dbm = pAd->StaCfg.RssiSample.AvgRssi0 - pAd->BbpRssiToDbmDelta;
3140 if (bLinkUp == TRUE)
3141 pAd->CommonCfg.TxRate = RATE_24;
3143 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3146 pAd->CommonCfg.TxRate = RATE_11;
3148 pAd->CommonCfg.TxRate = RATE_24;
3150 /* should never exceed MaxTxRate (consider 11B-only mode) */
3151 if (pAd->CommonCfg.TxRate > pAd->CommonCfg.MaxTxRate)
3152 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3154 pAd->CommonCfg.TxRateIndex = 0;
3156 pAd->CommonCfg.TxRate = pAd->CommonCfg.MaxTxRate;
3158 (pAd->CommonCfg.MaxTxRate >
3159 3) ? (pAd->CommonCfg.MaxTxRate -
3160 4) : pAd->CommonCfg.MaxTxRate;
3161 pHtPhy->field.MODE =
3162 (pAd->CommonCfg.MaxTxRate > 3) ? MODE_OFDM : MODE_CCK;
3164 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.STBC =
3166 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.ShortGI =
3167 pHtPhy->field.ShortGI;
3168 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MCS =
3170 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.field.MODE =
3174 if (pAd->CommonCfg.TxRate <= RATE_11) {
3175 pMaxHtPhy->field.MODE = MODE_CCK;
3176 pMaxHtPhy->field.MCS = pAd->CommonCfg.TxRate;
3177 pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
3179 pMaxHtPhy->field.MODE = MODE_OFDM;
3180 pMaxHtPhy->field.MCS = OfdmRateToRxwiMCS[pAd->CommonCfg.TxRate];
3181 if (pAd->CommonCfg.MinTxRate >= RATE_6
3182 && (pAd->CommonCfg.MinTxRate <= RATE_54)) {
3183 pMinHtPhy->field.MCS =
3184 OfdmRateToRxwiMCS[pAd->CommonCfg.MinTxRate];
3186 pMinHtPhy->field.MCS = pAd->CommonCfg.MinTxRate;
3190 pHtPhy->word = (pMaxHtPhy->word);
3191 if (bLinkUp && (pAd->OpMode == OPMODE_STA)) {
3192 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word = pHtPhy->word;
3193 pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word =
3195 pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word =
3198 switch (pAd->CommonCfg.PhyMode) {
3199 case PHY_11BG_MIXED:
3201 case PHY_11BGN_MIXED:
3202 pAd->CommonCfg.MlmeRate = RATE_1;
3203 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
3204 pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
3206 /*#ifdef WIFI_TEST */
3207 pAd->CommonCfg.RtsRate = RATE_11;
3209 /* pAd->CommonCfg.RtsRate = RATE_1; */
3214 case PHY_11AGN_MIXED:
3215 case PHY_11GN_MIXED:
3217 case PHY_11AN_MIXED:
3219 pAd->CommonCfg.MlmeRate = RATE_6;
3220 pAd->CommonCfg.RtsRate = RATE_6;
3221 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
3222 pAd->CommonCfg.MlmeTransmit.field.MCS =
3223 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3225 case PHY_11ABG_MIXED:
3226 case PHY_11ABGN_MIXED:
3227 if (pAd->CommonCfg.Channel <= 14) {
3228 pAd->CommonCfg.MlmeRate = RATE_1;
3229 pAd->CommonCfg.RtsRate = RATE_1;
3230 pAd->CommonCfg.MlmeTransmit.field.MODE =
3232 pAd->CommonCfg.MlmeTransmit.field.MCS = RATE_1;
3234 pAd->CommonCfg.MlmeRate = RATE_6;
3235 pAd->CommonCfg.RtsRate = RATE_6;
3236 pAd->CommonCfg.MlmeTransmit.field.MODE =
3238 pAd->CommonCfg.MlmeTransmit.field.MCS =
3239 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3242 default: /* error */
3243 pAd->CommonCfg.MlmeRate = RATE_6;
3244 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
3245 pAd->CommonCfg.MlmeTransmit.field.MCS =
3246 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
3247 pAd->CommonCfg.RtsRate = RATE_1;
3251 /* Keep Basic Mlme Rate. */
3253 pAd->MacTab.Content[MCAST_WCID].HTPhyMode.word =
3254 pAd->CommonCfg.MlmeTransmit.word;
3255 if (pAd->CommonCfg.MlmeTransmit.field.MODE == MODE_OFDM)
3256 pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS =
3257 OfdmRateToRxwiMCS[RATE_24];
3259 pAd->MacTab.Content[MCAST_WCID].HTPhyMode.field.MCS =
3261 pAd->CommonCfg.BasicMlmeRate = pAd->CommonCfg.MlmeRate;
3264 DBGPRINT(RT_DEBUG_TRACE,
3265 (" MlmeUpdateTxRates (MaxDesire=%d, MaxSupport=%d, MaxTxRate=%d, MinRate=%d, Rate Switching =%d)\n",
3266 RateIdToMbps[MaxDesire], RateIdToMbps[MaxSupport],
3267 RateIdToMbps[pAd->CommonCfg.MaxTxRate],
3268 RateIdToMbps[pAd->CommonCfg.MinTxRate],
3269 /*OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED) */
3271 DBGPRINT(RT_DEBUG_TRACE,
3272 (" MlmeUpdateTxRates (TxRate=%d, RtsRate=%d, BasicRateBitmap=0x%04lx)\n",
3273 RateIdToMbps[pAd->CommonCfg.TxRate],
3274 RateIdToMbps[pAd->CommonCfg.RtsRate], BasicRateBitmap));
3275 DBGPRINT(RT_DEBUG_TRACE,
3276 ("MlmeUpdateTxRates (MlmeTransmit=0x%x, MinHTPhyMode=%x, MaxHTPhyMode=0x%x, HTPhyMode=0x%x)\n",
3277 pAd->CommonCfg.MlmeTransmit.word,
3278 pAd->MacTab.Content[BSSID_WCID].MinHTPhyMode.word,
3279 pAd->MacTab.Content[BSSID_WCID].MaxHTPhyMode.word,
3280 pAd->MacTab.Content[BSSID_WCID].HTPhyMode.word));
3284 ==========================================================================
3286 This function update HT Rate setting.
3287 Input Wcid value is valid for 2 case :
3288 1. it's used for Station in infra mode that copy AP rate to Mactable.
3289 2. OR Station in adhoc mode to copy peer's HT rate to Mactable.
3291 IRQL = DISPATCH_LEVEL
3293 ==========================================================================
3295 void MlmeUpdateHtTxRates(struct rt_rtmp_adapter *pAd, u8 apidx)
3297 u8 StbcMcs; /*j, StbcMcs, bitmask; */
3299 struct rt_ht_capability *pRtHtCap = NULL;
3300 struct rt_ht_phy_info *pActiveHtPhy = NULL;
3301 unsigned long BasicMCS;
3303 struct rt_ht_phy_info *pDesireHtPhy = NULL;
3304 PHTTRANSMIT_SETTING pHtPhy = NULL;
3305 PHTTRANSMIT_SETTING pMaxHtPhy = NULL;
3306 PHTTRANSMIT_SETTING pMinHtPhy = NULL;
3307 BOOLEAN *auto_rate_cur_p;
3309 DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateHtTxRates===> \n"));
3311 auto_rate_cur_p = NULL;
3314 pDesireHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
3315 pActiveHtPhy = &pAd->StaCfg.DesiredHtPhyInfo;
3316 pHtPhy = &pAd->StaCfg.HTPhyMode;
3317 pMaxHtPhy = &pAd->StaCfg.MaxHTPhyMode;
3318 pMinHtPhy = &pAd->StaCfg.MinHTPhyMode;
3320 auto_rate_cur_p = &pAd->StaCfg.bAutoTxRateSwitch;
3323 if ((ADHOC_ON(pAd) || INFRA_ON(pAd)) && (pAd->OpMode == OPMODE_STA)) {
3324 if (pAd->StaActive.SupportedPhyInfo.bHtEnable == FALSE)
3327 pRtHtCap = &pAd->StaActive.SupportedHtPhy;
3328 pActiveHtPhy = &pAd->StaActive.SupportedPhyInfo;
3329 StbcMcs = (u8)pAd->MlmeAux.AddHtInfo.AddHtInfo3.StbcMcs;
3331 pAd->MlmeAux.AddHtInfo.MCSSet[0] +
3332 (pAd->MlmeAux.AddHtInfo.MCSSet[1] << 8) + (StbcMcs << 16);
3333 if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC)
3334 && (pAd->Antenna.field.TxPath == 2))
3335 pMaxHtPhy->field.STBC = STBC_USE;
3337 pMaxHtPhy->field.STBC = STBC_NONE;
3339 if (pDesireHtPhy->bHtEnable == FALSE)
3342 pRtHtCap = &pAd->CommonCfg.DesiredHtPhy;
3343 StbcMcs = (u8)pAd->CommonCfg.AddHTInfo.AddHtInfo3.StbcMcs;
3345 pAd->CommonCfg.AddHTInfo.MCSSet[0] +
3346 (pAd->CommonCfg.AddHTInfo.MCSSet[1] << 8) + (StbcMcs << 16);
3347 if ((pAd->CommonCfg.DesiredHtPhy.TxSTBC) && (pRtHtCap->RxSTBC)
3348 && (pAd->Antenna.field.TxPath == 2))
3349 pMaxHtPhy->field.STBC = STBC_USE;
3351 pMaxHtPhy->field.STBC = STBC_NONE;
3354 /* Decide MAX ht rate. */
3355 if ((pRtHtCap->GF) && (pAd->CommonCfg.DesiredHtPhy.GF))
3356 pMaxHtPhy->field.MODE = MODE_HTGREENFIELD;
3358 pMaxHtPhy->field.MODE = MODE_HTMIX;
3360 if ((pAd->CommonCfg.DesiredHtPhy.ChannelWidth)
3361 && (pRtHtCap->ChannelWidth))
3362 pMaxHtPhy->field.BW = BW_40;
3364 pMaxHtPhy->field.BW = BW_20;
3366 if (pMaxHtPhy->field.BW == BW_20)
3367 pMaxHtPhy->field.ShortGI =
3368 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20 & pRtHtCap->
3371 pMaxHtPhy->field.ShortGI =
3372 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40 & pRtHtCap->
3375 if (pDesireHtPhy->MCSSet[4] != 0) {
3376 pMaxHtPhy->field.MCS = 32;
3379 for (i = 23; i >= 0; i--) /* 3*3 */
3382 bitmask = (1 << (i - (j * 8)));
3384 if ((pActiveHtPhy->MCSSet[j] & bitmask)
3385 && (pDesireHtPhy->MCSSet[j] & bitmask)) {
3386 pMaxHtPhy->field.MCS = i;
3394 /* Copy MIN ht rate. rt2860??? */
3395 pMinHtPhy->field.BW = BW_20;
3396 pMinHtPhy->field.MCS = 0;
3397 pMinHtPhy->field.STBC = 0;
3398 pMinHtPhy->field.ShortGI = 0;
3399 /*If STA assigns fixed rate. update to fixed here. */
3400 if ((pAd->OpMode == OPMODE_STA) && (pDesireHtPhy->MCSSet[0] != 0xff)) {
3401 if (pDesireHtPhy->MCSSet[4] != 0) {
3402 pMaxHtPhy->field.MCS = 32;
3403 pMinHtPhy->field.MCS = 32;
3404 DBGPRINT(RT_DEBUG_TRACE,
3405 ("MlmeUpdateHtTxRates<=== Use Fixed MCS = %d\n",
3406 pMinHtPhy->field.MCS));
3409 for (i = 23; (char)i >= 0; i--) /* 3*3 */
3412 bitmask = (1 << (i - (j * 8)));
3413 if ((pDesireHtPhy->MCSSet[j] & bitmask)
3414 && (pActiveHtPhy->MCSSet[j] & bitmask)) {
3415 pMaxHtPhy->field.MCS = i;
3416 pMinHtPhy->field.MCS = i;
3424 /* Decide ht rate */
3425 pHtPhy->field.STBC = pMaxHtPhy->field.STBC;
3426 pHtPhy->field.BW = pMaxHtPhy->field.BW;
3427 pHtPhy->field.MODE = pMaxHtPhy->field.MODE;
3428 pHtPhy->field.MCS = pMaxHtPhy->field.MCS;
3429 pHtPhy->field.ShortGI = pMaxHtPhy->field.ShortGI;
3431 /* use default now. rt2860 */
3432 if (pDesireHtPhy->MCSSet[0] != 0xff)
3433 *auto_rate_cur_p = FALSE;
3435 *auto_rate_cur_p = TRUE;
3437 DBGPRINT(RT_DEBUG_TRACE,
3438 (" MlmeUpdateHtTxRates<---.AMsduSize = %d \n",
3439 pAd->CommonCfg.DesiredHtPhy.AmsduSize));
3440 DBGPRINT(RT_DEBUG_TRACE,
3441 ("TX: MCS[0] = %x (choose %d), BW = %d, ShortGI = %d, MODE = %d, \n",
3442 pActiveHtPhy->MCSSet[0], pHtPhy->field.MCS, pHtPhy->field.BW,
3443 pHtPhy->field.ShortGI, pHtPhy->field.MODE));
3444 DBGPRINT(RT_DEBUG_TRACE, ("MlmeUpdateHtTxRates<=== \n"));
3447 void BATableInit(struct rt_rtmp_adapter *pAd, struct rt_ba_table *Tab)
3451 Tab->numAsOriginator = 0;
3452 Tab->numAsRecipient = 0;
3453 Tab->numDoneOriginator = 0;
3454 NdisAllocateSpinLock(&pAd->BATabLock);
3455 for (i = 0; i < MAX_LEN_OF_BA_REC_TABLE; i++) {
3456 Tab->BARecEntry[i].REC_BA_Status = Recipient_NONE;
3457 NdisAllocateSpinLock(&(Tab->BARecEntry[i].RxReRingLock));
3459 for (i = 0; i < MAX_LEN_OF_BA_ORI_TABLE; i++) {
3460 Tab->BAOriEntry[i].ORI_BA_Status = Originator_NONE;
3464 /* IRQL = DISPATCH_LEVEL */
3465 void MlmeRadioOff(struct rt_rtmp_adapter *pAd)
3467 RTMP_MLME_RADIO_OFF(pAd);
3470 /* IRQL = DISPATCH_LEVEL */
3471 void MlmeRadioOn(struct rt_rtmp_adapter *pAd)
3473 RTMP_MLME_RADIO_ON(pAd);
3476 /* =========================================================================================== */
3478 /* =========================================================================================== */
3480 /*! \brief initialize BSS table
3481 * \param p_tab pointer to the table
3486 IRQL = PASSIVE_LEVEL
3487 IRQL = DISPATCH_LEVEL
3490 void BssTableInit(struct rt_bss_table *Tab)
3495 Tab->BssOverlapNr = 0;
3496 for (i = 0; i < MAX_LEN_OF_BSS_TABLE; i++) {
3497 NdisZeroMemory(&Tab->BssEntry[i], sizeof(struct rt_bss_entry));
3498 Tab->BssEntry[i].Rssi = -127; /* initial the rssi as a minimum value */
3502 /*! \brief search the BSS table by SSID
3503 * \param p_tab pointer to the bss table
3504 * \param ssid SSID string
3505 * \return index of the table, BSS_NOT_FOUND if not in the table
3508 * \note search by sequential search
3510 IRQL = DISPATCH_LEVEL
3513 unsigned long BssTableSearch(struct rt_bss_table *Tab, u8 *pBssid, u8 Channel)
3517 for (i = 0; i < Tab->BssNr; i++) {
3519 /* Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. */
3520 /* We should distinguish this case. */
3522 if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3523 ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3524 MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid)) {
3528 return (unsigned long)BSS_NOT_FOUND;
3531 unsigned long BssSsidTableSearch(struct rt_bss_table *Tab,
3533 u8 *pSsid, u8 SsidLen, u8 Channel)
3537 for (i = 0; i < Tab->BssNr; i++) {
3539 /* Some AP that support A/B/G mode that may used the same BSSID on 11A and 11B/G. */
3540 /* We should distinguish this case. */
3542 if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3543 ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3544 MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid) &&
3545 SSID_EQUAL(pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3546 Tab->BssEntry[i].SsidLen)) {
3550 return (unsigned long)BSS_NOT_FOUND;
3553 unsigned long BssTableSearchWithSSID(struct rt_bss_table *Tab,
3556 u8 SsidLen, u8 Channel)
3560 for (i = 0; i < Tab->BssNr; i++) {
3561 if ((((Tab->BssEntry[i].Channel <= 14) && (Channel <= 14)) ||
3562 ((Tab->BssEntry[i].Channel > 14) && (Channel > 14))) &&
3563 MAC_ADDR_EQUAL(&(Tab->BssEntry[i].Bssid), Bssid) &&
3565 (pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3566 Tab->BssEntry[i].SsidLen)
3567 || (NdisEqualMemory(pSsid, ZeroSsid, SsidLen))
3570 (Tab->BssEntry[i].Ssid, ZeroSsid,
3571 Tab->BssEntry[i].SsidLen)))) {
3575 return (unsigned long)BSS_NOT_FOUND;
3578 unsigned long BssSsidTableSearchBySSID(struct rt_bss_table *Tab,
3579 u8 *pSsid, u8 SsidLen)
3583 for (i = 0; i < Tab->BssNr; i++) {
3585 (pSsid, SsidLen, Tab->BssEntry[i].Ssid,
3586 Tab->BssEntry[i].SsidLen)) {
3590 return (unsigned long)BSS_NOT_FOUND;
3593 /* IRQL = DISPATCH_LEVEL */
3594 void BssTableDeleteEntry(struct rt_bss_table *Tab,
3595 u8 *pBssid, u8 Channel)
3599 for (i = 0; i < Tab->BssNr; i++) {
3600 if ((Tab->BssEntry[i].Channel == Channel) &&
3601 (MAC_ADDR_EQUAL(Tab->BssEntry[i].Bssid, pBssid))) {
3602 for (j = i; j < Tab->BssNr - 1; j++) {
3603 NdisMoveMemory(&(Tab->BssEntry[j]),
3604 &(Tab->BssEntry[j + 1]),
3605 sizeof(struct rt_bss_entry));
3607 NdisZeroMemory(&(Tab->BssEntry[Tab->BssNr - 1]),
3608 sizeof(struct rt_bss_entry));
3616 ========================================================================
3617 Routine Description:
3618 Delete the Originator Entry in BAtable. Or decrease numAs Originator by 1 if needed.
3621 // IRQL = DISPATCH_LEVEL
3622 ========================================================================
3624 void BATableDeleteORIEntry(struct rt_rtmp_adapter *pAd,
3625 struct rt_ba_ori_entry *pBAORIEntry)
3628 if (pBAORIEntry->ORI_BA_Status != Originator_NONE) {
3629 NdisAcquireSpinLock(&pAd->BATabLock);
3630 if (pBAORIEntry->ORI_BA_Status == Originator_Done) {
3631 pAd->BATable.numAsOriginator -= 1;
3632 DBGPRINT(RT_DEBUG_TRACE,
3633 ("BATableDeleteORIEntry numAsOriginator= %ld\n",
3634 pAd->BATable.numAsRecipient));
3635 /* Erase Bitmap flag. */
3637 pAd->MacTab.Content[pBAORIEntry->Wcid].TXBAbitmap &= (~(1 << (pBAORIEntry->TID))); /* If STA mode, erase flag here */
3638 pAd->MacTab.Content[pBAORIEntry->Wcid].BAOriWcidArray[pBAORIEntry->TID] = 0; /* If STA mode, erase flag here */
3639 pBAORIEntry->ORI_BA_Status = Originator_NONE;
3640 pBAORIEntry->Token = 1;
3641 /* Not clear Sequence here. */
3642 NdisReleaseSpinLock(&pAd->BATabLock);
3652 IRQL = DISPATCH_LEVEL
3655 void BssEntrySet(struct rt_rtmp_adapter *pAd, struct rt_bss_entry *pBss, u8 *pBssid, char Ssid[], u8 SsidLen, u8 BssType, u16 BeaconPeriod, struct rt_cf_parm * pCfParm, u16 AtimWin, u16 CapabilityInfo, u8 SupRate[], u8 SupRateLen, u8 ExtRate[], u8 ExtRateLen, struct rt_ht_capability_ie * pHtCapability, struct rt_add_ht_info_ie * pAddHtInfo, /* AP might use this additional ht info IE */
3658 u8 NewExtChanOffset,
3661 IN LARGE_INTEGER TimeStamp,
3663 struct rt_edca_parm *pEdcaParm,
3664 struct rt_qos_capability_parm *pQosCapability,
3665 struct rt_qbss_load_parm *pQbssLoad,
3666 u16 LengthVIE, struct rt_ndis_802_11_variable_ies *pVIE)
3668 COPY_MAC_ADDR(pBss->Bssid, pBssid);
3669 /* Default Hidden SSID to be TRUE, it will be turned to FALSE after coping SSID */
3672 /* For hidden SSID AP, it might send beacon with SSID len equal to 0 */
3673 /* Or send beacon /probe response with SSID len matching real SSID length, */
3674 /* but SSID is all zero. such as "00-00-00-00" with length 4. */
3675 /* We have to prevent this case overwrite correct table */
3676 if (NdisEqualMemory(Ssid, ZeroSsid, SsidLen) == 0) {
3677 NdisZeroMemory(pBss->Ssid, MAX_LEN_OF_SSID);
3678 NdisMoveMemory(pBss->Ssid, Ssid, SsidLen);
3679 pBss->SsidLen = SsidLen;
3684 pBss->BssType = BssType;
3685 pBss->BeaconPeriod = BeaconPeriod;
3686 if (BssType == BSS_INFRA) {
3687 if (pCfParm->bValid) {
3688 pBss->CfpCount = pCfParm->CfpCount;
3689 pBss->CfpPeriod = pCfParm->CfpPeriod;
3690 pBss->CfpMaxDuration = pCfParm->CfpMaxDuration;
3691 pBss->CfpDurRemaining = pCfParm->CfpDurRemaining;
3694 pBss->AtimWin = AtimWin;
3697 pBss->CapabilityInfo = CapabilityInfo;
3698 /* The privacy bit indicate security is ON, it maight be WEP, TKIP or AES */
3699 /* Combine with AuthMode, they will decide the connection methods. */
3700 pBss->Privacy = CAP_IS_PRIVACY_ON(pBss->CapabilityInfo);
3701 ASSERT(SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
3702 if (SupRateLen <= MAX_LEN_OF_SUPPORTED_RATES)
3703 NdisMoveMemory(pBss->SupRate, SupRate, SupRateLen);
3705 NdisMoveMemory(pBss->SupRate, SupRate,
3706 MAX_LEN_OF_SUPPORTED_RATES);
3707 pBss->SupRateLen = SupRateLen;
3708 ASSERT(ExtRateLen <= MAX_LEN_OF_SUPPORTED_RATES);
3709 NdisMoveMemory(pBss->ExtRate, ExtRate, ExtRateLen);
3710 pBss->NewExtChanOffset = NewExtChanOffset;
3711 pBss->ExtRateLen = ExtRateLen;
3712 pBss->Channel = Channel;
3713 pBss->CentralChannel = Channel;
3715 /* Update CkipFlag. if not exists, the value is 0x0 */
3716 pBss->CkipFlag = CkipFlag;
3718 /* New for microsoft Fixed IEs */
3719 NdisMoveMemory(pBss->FixIEs.Timestamp, &TimeStamp, 8);
3720 pBss->FixIEs.BeaconInterval = BeaconPeriod;
3721 pBss->FixIEs.Capabilities = CapabilityInfo;
3723 /* New for microsoft Variable IEs */
3724 if (LengthVIE != 0) {
3725 pBss->VarIELen = LengthVIE;
3726 NdisMoveMemory(pBss->VarIEs, pVIE, pBss->VarIELen);
3731 pBss->AddHtInfoLen = 0;
3732 pBss->HtCapabilityLen = 0;
3733 if (HtCapabilityLen > 0) {
3734 pBss->HtCapabilityLen = HtCapabilityLen;
3735 NdisMoveMemory(&pBss->HtCapability, pHtCapability,
3737 if (AddHtInfoLen > 0) {
3738 pBss->AddHtInfoLen = AddHtInfoLen;
3739 NdisMoveMemory(&pBss->AddHtInfo, pAddHtInfo,
3742 if ((pAddHtInfo->ControlChan > 2)
3743 && (pAddHtInfo->AddHtInfo.ExtChanOffset ==
3745 && (pHtCapability->HtCapInfo.ChannelWidth ==
3747 pBss->CentralChannel =
3748 pAddHtInfo->ControlChan - 2;
3750 if ((pAddHtInfo->AddHtInfo.ExtChanOffset ==
3752 && (pHtCapability->HtCapInfo.ChannelWidth ==
3754 pBss->CentralChannel =
3755 pAddHtInfo->ControlChan + 2;
3760 BssCipherParse(pBss);
3764 NdisMoveMemory(&pBss->EdcaParm, pEdcaParm, sizeof(struct rt_edca_parm));
3766 pBss->EdcaParm.bValid = FALSE;
3768 NdisMoveMemory(&pBss->QosCapability, pQosCapability,
3769 sizeof(struct rt_qos_capability_parm));
3771 pBss->QosCapability.bValid = FALSE;
3773 NdisMoveMemory(&pBss->QbssLoad, pQbssLoad,
3774 sizeof(struct rt_qbss_load_parm));
3776 pBss->QbssLoad.bValid = FALSE;
3779 struct rt_eid * pEid;
3782 NdisZeroMemory(&pBss->WpaIE.IE[0], MAX_CUSTOM_LEN);
3783 NdisZeroMemory(&pBss->RsnIE.IE[0], MAX_CUSTOM_LEN);
3784 pEid = (struct rt_eid *) pVIE;
3785 while ((Length + 2 + (u16)pEid->Len) <= LengthVIE) {
3786 switch (pEid->Eid) {
3788 if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4)) {
3789 if ((pEid->Len + 2) > MAX_CUSTOM_LEN) {
3790 pBss->WpaIE.IELen = 0;
3793 pBss->WpaIE.IELen = pEid->Len + 2;
3794 NdisMoveMemory(pBss->WpaIE.IE, pEid,
3800 (pEid->Octet + 2, RSN_OUI, 3)) {
3801 if ((pEid->Len + 2) > MAX_CUSTOM_LEN) {
3802 pBss->RsnIE.IELen = 0;
3805 pBss->RsnIE.IELen = pEid->Len + 2;
3806 NdisMoveMemory(pBss->RsnIE.IE, pEid,
3811 Length = Length + 2 + (u16)pEid->Len; /* Eid[1] + Len[1]+ content[Len] */
3812 pEid = (struct rt_eid *) ((u8 *) pEid + 2 + pEid->Len);
3818 * \brief insert an entry into the bss table
3819 * \param p_tab The BSS table
3820 * \param Bssid BSSID
3822 * \param ssid_len Length of SSID
3824 * \param beacon_period
3831 * \param channel_idx
3835 * \note If SSID is identical, the old entry will be replaced by the new one
3837 IRQL = DISPATCH_LEVEL
3840 unsigned long BssTableSetEntry(struct rt_rtmp_adapter *pAd, struct rt_bss_table *Tab, u8 *pBssid, char Ssid[], u8 SsidLen, u8 BssType, u16 BeaconPeriod, struct rt_cf_parm * CfParm, u16 AtimWin, u16 CapabilityInfo, u8 SupRate[], u8 SupRateLen, u8 ExtRate[], u8 ExtRateLen, struct rt_ht_capability_ie * pHtCapability, struct rt_add_ht_info_ie * pAddHtInfo, /* AP might use this additional ht info IE */
3843 u8 NewExtChanOffset,
3846 IN LARGE_INTEGER TimeStamp,
3848 struct rt_edca_parm *pEdcaParm,
3849 struct rt_qos_capability_parm *pQosCapability,
3850 struct rt_qbss_load_parm *pQbssLoad,
3851 u16 LengthVIE, struct rt_ndis_802_11_variable_ies *pVIE)
3856 BssTableSearchWithSSID(Tab, pBssid, (u8 *) Ssid, SsidLen,
3858 if (Idx == BSS_NOT_FOUND) {
3859 if (Tab->BssNr >= MAX_LEN_OF_BSS_TABLE) {
3861 /* It may happen when BSS Table was full. */
3862 /* The desired AP will not be added into BSS Table */
3863 /* In this case, if we found the desired AP then overwrite BSS Table. */
3865 if (!OPSTATUS_TEST_FLAG
3866 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)) {
3867 if (MAC_ADDR_EQUAL(pAd->MlmeAux.Bssid, pBssid)
3868 || SSID_EQUAL(pAd->MlmeAux.Ssid,
3869 pAd->MlmeAux.SsidLen, Ssid,
3871 Idx = Tab->BssOverlapNr;
3872 BssEntrySet(pAd, &Tab->BssEntry[Idx],
3873 pBssid, Ssid, SsidLen,
3874 BssType, BeaconPeriod,
3876 CapabilityInfo, SupRate,
3877 SupRateLen, ExtRate,
3878 ExtRateLen, pHtCapability,
3879 pAddHtInfo, HtCapabilityLen,
3881 NewExtChanOffset, ChannelNo,
3882 Rssi, TimeStamp, CkipFlag,
3883 pEdcaParm, pQosCapability,
3884 pQbssLoad, LengthVIE, pVIE);
3886 (Tab->BssOverlapNr++) %
3887 MAX_LEN_OF_BSS_TABLE;
3891 return BSS_NOT_FOUND;
3895 BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid, SsidLen,
3896 BssType, BeaconPeriod, CfParm, AtimWin,
3897 CapabilityInfo, SupRate, SupRateLen, ExtRate,
3898 ExtRateLen, pHtCapability, pAddHtInfo,
3899 HtCapabilityLen, AddHtInfoLen, NewExtChanOffset,
3900 ChannelNo, Rssi, TimeStamp, CkipFlag, pEdcaParm,
3901 pQosCapability, pQbssLoad, LengthVIE, pVIE);
3904 /* avoid Hidden SSID form beacon to overwirite correct SSID from probe response */
3906 (Ssid, SsidLen, Tab->BssEntry[Idx].Ssid,
3907 Tab->BssEntry[Idx].SsidLen))
3910 (Tab->BssEntry[Idx].Ssid, ZeroSsid,
3911 Tab->BssEntry[Idx].SsidLen))) {
3912 BssEntrySet(pAd, &Tab->BssEntry[Idx], pBssid, Ssid,
3913 SsidLen, BssType, BeaconPeriod, CfParm,
3914 AtimWin, CapabilityInfo, SupRate,
3915 SupRateLen, ExtRate, ExtRateLen,
3916 pHtCapability, pAddHtInfo, HtCapabilityLen,
3917 AddHtInfoLen, NewExtChanOffset, ChannelNo,
3918 Rssi, TimeStamp, CkipFlag, pEdcaParm,
3919 pQosCapability, pQbssLoad, LengthVIE, pVIE);
3926 /* IRQL = DISPATCH_LEVEL */
3927 void BssTableSsidSort(struct rt_rtmp_adapter *pAd,
3928 struct rt_bss_table *OutTab, char Ssid[], u8 SsidLen)
3931 BssTableInit(OutTab);
3933 for (i = 0; i < pAd->ScanTab.BssNr; i++) {
3934 struct rt_bss_entry *pInBss = &pAd->ScanTab.BssEntry[i];
3935 BOOLEAN bIsHiddenApIncluded = FALSE;
3937 if (((pAd->CommonCfg.bIEEE80211H == 1) &&
3938 (pAd->MlmeAux.Channel > 14) &&
3939 RadarChannelCheck(pAd, pInBss->Channel))
3942 bIsHiddenApIncluded = TRUE;
3945 if ((pInBss->BssType == pAd->StaCfg.BssType) &&
3946 (SSID_EQUAL(Ssid, SsidLen, pInBss->Ssid, pInBss->SsidLen)
3947 || bIsHiddenApIncluded)) {
3948 struct rt_bss_entry *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
3950 /* 2.4G/5G N only mode */
3951 if ((pInBss->HtCapabilityLen == 0) &&
3952 ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G)
3953 || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) {
3954 DBGPRINT(RT_DEBUG_TRACE,
3955 ("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
3959 /* Check the Authmode first */
3960 if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) {
3961 /* Check AuthMode and AuthModeAux for matching, in case AP support dual-mode */
3962 if ((pAd->StaCfg.AuthMode != pInBss->AuthMode)
3963 && (pAd->StaCfg.AuthMode !=
3964 pInBss->AuthModeAux))
3968 /* Check cipher suite, AP must have more secured cipher than station setting */
3969 if ((pAd->StaCfg.AuthMode ==
3970 Ndis802_11AuthModeWPA)
3971 || (pAd->StaCfg.AuthMode ==
3972 Ndis802_11AuthModeWPAPSK)) {
3973 /* If it's not mixed mode, we should only let BSS pass with the same encryption */
3974 if (pInBss->WPA.bMixMode == FALSE)
3975 if (pAd->StaCfg.WepStatus !=
3976 pInBss->WPA.GroupCipher)
3979 /* check group cipher */
3980 if ((pAd->StaCfg.WepStatus <
3981 pInBss->WPA.GroupCipher)
3982 && (pInBss->WPA.GroupCipher !=
3983 Ndis802_11GroupWEP40Enabled)
3984 && (pInBss->WPA.GroupCipher !=
3985 Ndis802_11GroupWEP104Enabled))
3988 /* check pairwise cipher, skip if none matched */
3989 /* If profile set to AES, let it pass without question. */
3990 /* If profile set to TKIP, we must find one mateched */
3991 if ((pAd->StaCfg.WepStatus ==
3992 Ndis802_11Encryption2Enabled)
3993 && (pAd->StaCfg.WepStatus !=
3994 pInBss->WPA.PairCipher)
3995 && (pAd->StaCfg.WepStatus !=
3996 pInBss->WPA.PairCipherAux))
3999 if ((pAd->StaCfg.AuthMode ==
4000 Ndis802_11AuthModeWPA2)
4001 || (pAd->StaCfg.AuthMode ==
4002 Ndis802_11AuthModeWPA2PSK)) {
4003 /* If it's not mixed mode, we should only let BSS pass with the same encryption */
4004 if (pInBss->WPA2.bMixMode == FALSE)
4005 if (pAd->StaCfg.WepStatus !=
4006 pInBss->WPA2.GroupCipher)
4009 /* check group cipher */
4010 if ((pAd->StaCfg.WepStatus <
4011 pInBss->WPA.GroupCipher)
4012 && (pInBss->WPA2.GroupCipher !=
4013 Ndis802_11GroupWEP40Enabled)
4014 && (pInBss->WPA2.GroupCipher !=
4015 Ndis802_11GroupWEP104Enabled))
4018 /* check pairwise cipher, skip if none matched */
4019 /* If profile set to AES, let it pass without question. */
4020 /* If profile set to TKIP, we must find one mateched */
4021 if ((pAd->StaCfg.WepStatus ==
4022 Ndis802_11Encryption2Enabled)
4023 && (pAd->StaCfg.WepStatus !=
4024 pInBss->WPA2.PairCipher)
4025 && (pAd->StaCfg.WepStatus !=
4026 pInBss->WPA2.PairCipherAux))
4030 /* Bss Type matched, SSID matched. */
4031 /* We will check wepstatus for qualification Bss */
4032 else if (pAd->StaCfg.WepStatus != pInBss->WepStatus) {
4033 DBGPRINT(RT_DEBUG_TRACE,
4034 ("StaCfg.WepStatus=%d, while pInBss->WepStatus=%d\n",
4035 pAd->StaCfg.WepStatus,
4036 pInBss->WepStatus));
4038 /* For the SESv2 case, we will not qualify WepStatus. */
4043 /* Since the AP is using hidden SSID, and we are trying to connect to ANY */
4044 /* It definitely will fail. So, skip it. */
4045 /* CCX also require not even try to connect it! */
4049 /* If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region */
4050 /* If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, */
4051 if ((pInBss->CentralChannel != pInBss->Channel) &&
4052 (pAd->CommonCfg.RegTransmitSetting.field.BW ==
4054 if (RTMPCheckChannel
4055 (pAd, pInBss->CentralChannel,
4056 pInBss->Channel) == FALSE) {
4057 pAd->CommonCfg.RegTransmitSetting.field.
4060 pAd->CommonCfg.RegTransmitSetting.field.
4063 if (pAd->CommonCfg.DesiredHtPhy.
4064 ChannelWidth == BAND_WIDTH_20) {
4069 /* copy matching BSS from InTab to OutTab */
4070 NdisMoveMemory(pOutBss, pInBss, sizeof(struct rt_bss_entry));
4073 } else if ((pInBss->BssType == pAd->StaCfg.BssType)
4074 && (SsidLen == 0)) {
4075 struct rt_bss_entry *pOutBss = &OutTab->BssEntry[OutTab->BssNr];
4077 /* 2.4G/5G N only mode */
4078 if ((pInBss->HtCapabilityLen == 0) &&
4079 ((pAd->CommonCfg.PhyMode == PHY_11N_2_4G)
4080 || (pAd->CommonCfg.PhyMode == PHY_11N_5G))) {
4081 DBGPRINT(RT_DEBUG_TRACE,
4082 ("STA is in N-only Mode, this AP don't have Ht capability in Beacon.\n"));
4086 /* Check the Authmode first */
4087 if (pAd->StaCfg.AuthMode >= Ndis802_11AuthModeWPA) {
4088 /* Check AuthMode and AuthModeAux for matching, in case AP support dual-mode */
4089 if ((pAd->StaCfg.AuthMode != pInBss->AuthMode)
4090 && (pAd->StaCfg.AuthMode !=
4091 pInBss->AuthModeAux))
4095 /* Check cipher suite, AP must have more secured cipher than station setting */
4096 if ((pAd->StaCfg.AuthMode ==
4097 Ndis802_11AuthModeWPA)
4098 || (pAd->StaCfg.AuthMode ==
4099 Ndis802_11AuthModeWPAPSK)) {
4100 /* If it's not mixed mode, we should only let BSS pass with the same encryption */
4101 if (pInBss->WPA.bMixMode == FALSE)
4102 if (pAd->StaCfg.WepStatus !=
4103 pInBss->WPA.GroupCipher)
4106 /* check group cipher */
4107 if (pAd->StaCfg.WepStatus <
4108 pInBss->WPA.GroupCipher)
4111 /* check pairwise cipher, skip if none matched */
4112 /* If profile set to AES, let it pass without question. */
4113 /* If profile set to TKIP, we must find one mateched */
4114 if ((pAd->StaCfg.WepStatus ==
4115 Ndis802_11Encryption2Enabled)
4116 && (pAd->StaCfg.WepStatus !=
4117 pInBss->WPA.PairCipher)
4118 && (pAd->StaCfg.WepStatus !=
4119 pInBss->WPA.PairCipherAux))
4122 if ((pAd->StaCfg.AuthMode ==
4123 Ndis802_11AuthModeWPA2)
4124 || (pAd->StaCfg.AuthMode ==
4125 Ndis802_11AuthModeWPA2PSK)) {
4126 /* If it's not mixed mode, we should only let BSS pass with the same encryption */
4127 if (pInBss->WPA2.bMixMode == FALSE)
4128 if (pAd->StaCfg.WepStatus !=
4129 pInBss->WPA2.GroupCipher)
4132 /* check group cipher */
4133 if (pAd->StaCfg.WepStatus <
4134 pInBss->WPA2.GroupCipher)
4137 /* check pairwise cipher, skip if none matched */
4138 /* If profile set to AES, let it pass without question. */
4139 /* If profile set to TKIP, we must find one mateched */
4140 if ((pAd->StaCfg.WepStatus ==
4141 Ndis802_11Encryption2Enabled)
4142 && (pAd->StaCfg.WepStatus !=
4143 pInBss->WPA2.PairCipher)
4144 && (pAd->StaCfg.WepStatus !=
4145 pInBss->WPA2.PairCipherAux))
4149 /* Bss Type matched, SSID matched. */
4150 /* We will check wepstatus for qualification Bss */
4151 else if (pAd->StaCfg.WepStatus != pInBss->WepStatus)
4154 /* If both station and AP use 40MHz, still need to check if the 40MHZ band's legality in my country region */
4155 /* If this 40MHz wideband is not allowed in my country list, use bandwidth 20MHZ instead, */
4156 if ((pInBss->CentralChannel != pInBss->Channel) &&
4157 (pAd->CommonCfg.RegTransmitSetting.field.BW ==
4159 if (RTMPCheckChannel
4160 (pAd, pInBss->CentralChannel,
4161 pInBss->Channel) == FALSE) {
4162 pAd->CommonCfg.RegTransmitSetting.field.
4165 pAd->CommonCfg.RegTransmitSetting.field.
4169 /* copy matching BSS from InTab to OutTab */
4170 NdisMoveMemory(pOutBss, pInBss, sizeof(struct rt_bss_entry));
4175 if (OutTab->BssNr >= MAX_LEN_OF_BSS_TABLE)
4179 BssTableSortByRssi(OutTab);
4182 /* IRQL = DISPATCH_LEVEL */
4183 void BssTableSortByRssi(struct rt_bss_table *OutTab)
4186 struct rt_bss_entry TmpBss;
4188 for (i = 0; i < OutTab->BssNr - 1; i++) {
4189 for (j = i + 1; j < OutTab->BssNr; j++) {
4190 if (OutTab->BssEntry[j].Rssi > OutTab->BssEntry[i].Rssi) {
4191 NdisMoveMemory(&TmpBss, &OutTab->BssEntry[j],
4192 sizeof(struct rt_bss_entry));
4193 NdisMoveMemory(&OutTab->BssEntry[j],
4194 &OutTab->BssEntry[i],
4195 sizeof(struct rt_bss_entry));
4196 NdisMoveMemory(&OutTab->BssEntry[i], &TmpBss,
4197 sizeof(struct rt_bss_entry));
4203 void BssCipherParse(struct rt_bss_entry *pBss)
4205 struct rt_eid * pEid;
4207 struct rt_rsn_ie_header * pRsnHeader;
4208 struct rt_cipher_suite_struct * pCipher;
4209 struct rt_akm_suite * pAKM;
4212 NDIS_802_11_ENCRYPTION_STATUS TmpCipher;
4215 /* WepStatus will be reset later, if AP announce TKIP or AES on the beacon frame. */
4217 if (pBss->Privacy) {
4218 pBss->WepStatus = Ndis802_11WEPEnabled;
4220 pBss->WepStatus = Ndis802_11WEPDisabled;
4222 /* Set default to disable & open authentication before parsing variable IE */
4223 pBss->AuthMode = Ndis802_11AuthModeOpen;
4224 pBss->AuthModeAux = Ndis802_11AuthModeOpen;
4226 /* Init WPA setting */
4227 pBss->WPA.PairCipher = Ndis802_11WEPDisabled;
4228 pBss->WPA.PairCipherAux = Ndis802_11WEPDisabled;
4229 pBss->WPA.GroupCipher = Ndis802_11WEPDisabled;
4230 pBss->WPA.RsnCapability = 0;
4231 pBss->WPA.bMixMode = FALSE;
4233 /* Init WPA2 setting */
4234 pBss->WPA2.PairCipher = Ndis802_11WEPDisabled;
4235 pBss->WPA2.PairCipherAux = Ndis802_11WEPDisabled;
4236 pBss->WPA2.GroupCipher = Ndis802_11WEPDisabled;
4237 pBss->WPA2.RsnCapability = 0;
4238 pBss->WPA2.bMixMode = FALSE;
4240 Length = (int)pBss->VarIELen;
4242 while (Length > 0) {
4243 /* Parse cipher suite base on WPA1 & WPA2, they should be parsed differently */
4244 pTmp = ((u8 *)pBss->VarIEs) + pBss->VarIELen - Length;
4245 pEid = (struct rt_eid *) pTmp;
4246 switch (pEid->Eid) {
4248 if (NdisEqualMemory(pEid->Octet, SES_OUI, 3)
4249 && (pEid->Len == 7)) {
4252 } else if (NdisEqualMemory(pEid->Octet, WPA_OUI, 4) !=
4254 /* if unsupported vendor specific IE */
4257 /* Skip OUI, version, and multicast suite */
4258 /* This part should be improved in the future when AP supported multiple cipher suite. */
4259 /* For now, it's OK since almost all APs have fixed cipher suite supported. */
4260 /* pTmp = (u8 *)pEid->Octet; */
4263 /* Cipher Suite Selectors from Spec P802.11i/D3.2 P26. */
4271 /* Parse group cipher */
4274 pBss->WPA.GroupCipher =
4275 Ndis802_11GroupWEP40Enabled;
4278 pBss->WPA.GroupCipher =
4279 Ndis802_11GroupWEP104Enabled;
4282 pBss->WPA.GroupCipher =
4283 Ndis802_11Encryption2Enabled;
4286 pBss->WPA.GroupCipher =
4287 Ndis802_11Encryption3Enabled;
4292 /* number of unicast suite */
4295 /* skip all unicast cipher suites */
4296 /*Count = *(u16 *)pTmp; */
4297 Count = (pTmp[1] << 8) + pTmp[0];
4298 pTmp += sizeof(u16);
4300 /* Parsing all unicast cipher suite */
4304 TmpCipher = Ndis802_11WEPDisabled;
4307 case 5: /* Although WEP is not allowed in WPA related auth mode, we parse it anyway */
4309 Ndis802_11Encryption1Enabled;
4313 Ndis802_11Encryption2Enabled;
4317 Ndis802_11Encryption3Enabled;
4322 if (TmpCipher > pBss->WPA.PairCipher) {
4323 /* Move the lower cipher suite to PairCipherAux */
4324 pBss->WPA.PairCipherAux =
4325 pBss->WPA.PairCipher;
4326 pBss->WPA.PairCipher = TmpCipher;
4328 pBss->WPA.PairCipherAux = TmpCipher;
4334 /* 4. get AKM suite counts */
4335 /*Count = *(u16 *)pTmp; */
4336 Count = (pTmp[1] << 8) + pTmp[0];
4337 pTmp += sizeof(u16);
4342 /* Set AP support WPA-enterprise mode */
4343 if (pBss->AuthMode == Ndis802_11AuthModeOpen)
4344 pBss->AuthMode = Ndis802_11AuthModeWPA;
4347 Ndis802_11AuthModeWPA;
4350 /* Set AP support WPA-PSK mode */
4351 if (pBss->AuthMode == Ndis802_11AuthModeOpen)
4353 Ndis802_11AuthModeWPAPSK;
4356 Ndis802_11AuthModeWPAPSK;
4363 /* Fixed for WPA-None */
4364 if (pBss->BssType == BSS_ADHOC) {
4365 pBss->AuthMode = Ndis802_11AuthModeWPANone;
4366 pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
4367 pBss->WepStatus = pBss->WPA.GroupCipher;
4368 /* Patched bugs for old driver */
4369 if (pBss->WPA.PairCipherAux ==
4370 Ndis802_11WEPDisabled)
4371 pBss->WPA.PairCipherAux =
4372 pBss->WPA.GroupCipher;
4374 pBss->WepStatus = pBss->WPA.PairCipher;
4376 /* Check the Pair & Group, if different, turn on mixed mode flag */
4377 if (pBss->WPA.GroupCipher != pBss->WPA.PairCipher)
4378 pBss->WPA.bMixMode = TRUE;
4383 pRsnHeader = (struct rt_rsn_ie_header *) pTmp;
4385 /* 0. Version must be 1 */
4386 if (le2cpu16(pRsnHeader->Version) != 1)
4388 pTmp += sizeof(struct rt_rsn_ie_header);
4390 /* 1. Check group cipher */
4391 pCipher = (struct rt_cipher_suite_struct *) pTmp;
4392 if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
4395 /* Parse group cipher */
4396 switch (pCipher->Type) {
4398 pBss->WPA2.GroupCipher =
4399 Ndis802_11GroupWEP40Enabled;
4402 pBss->WPA2.GroupCipher =
4403 Ndis802_11GroupWEP104Enabled;
4406 pBss->WPA2.GroupCipher =
4407 Ndis802_11Encryption2Enabled;
4410 pBss->WPA2.GroupCipher =
4411 Ndis802_11Encryption3Enabled;
4416 /* set to correct offset for next parsing */
4417 pTmp += sizeof(struct rt_cipher_suite_struct);
4419 /* 2. Get pairwise cipher counts */
4420 /*Count = *(u16 *)pTmp; */
4421 Count = (pTmp[1] << 8) + pTmp[0];
4422 pTmp += sizeof(u16);
4424 /* 3. Get pairwise cipher */
4425 /* Parsing all unicast cipher suite */
4428 pCipher = (struct rt_cipher_suite_struct *) pTmp;
4429 TmpCipher = Ndis802_11WEPDisabled;
4430 switch (pCipher->Type) {
4432 case 5: /* Although WEP is not allowed in WPA related auth mode, we parse it anyway */
4434 Ndis802_11Encryption1Enabled;
4438 Ndis802_11Encryption2Enabled;
4442 Ndis802_11Encryption3Enabled;
4447 if (TmpCipher > pBss->WPA2.PairCipher) {
4448 /* Move the lower cipher suite to PairCipherAux */
4449 pBss->WPA2.PairCipherAux =
4450 pBss->WPA2.PairCipher;
4451 pBss->WPA2.PairCipher = TmpCipher;
4453 pBss->WPA2.PairCipherAux = TmpCipher;
4455 pTmp += sizeof(struct rt_cipher_suite_struct);
4459 /* 4. get AKM suite counts */
4460 /*Count = *(u16 *)pTmp; */
4461 Count = (pTmp[1] << 8) + pTmp[0];
4462 pTmp += sizeof(u16);
4464 /* 5. Get AKM ciphers */
4465 /* Parsing all AKM ciphers */
4467 pAKM = (struct rt_akm_suite *) pTmp;
4468 if (!RTMPEqualMemory(pTmp, RSN_OUI, 3))
4471 switch (pAKM->Type) {
4473 /* Set AP support WPA-enterprise mode */
4474 if (pBss->AuthMode ==
4475 Ndis802_11AuthModeOpen)
4477 Ndis802_11AuthModeWPA2;
4480 Ndis802_11AuthModeWPA2;
4483 /* Set AP support WPA-PSK mode */
4484 if (pBss->AuthMode ==
4485 Ndis802_11AuthModeOpen)
4487 Ndis802_11AuthModeWPA2PSK;
4490 Ndis802_11AuthModeWPA2PSK;
4493 if (pBss->AuthMode ==
4494 Ndis802_11AuthModeOpen)
4496 Ndis802_11AuthModeMax;
4499 Ndis802_11AuthModeMax;
4502 pTmp += (Count * sizeof(struct rt_akm_suite));
4506 /* Fixed for WPA-None */
4507 if (pBss->BssType == BSS_ADHOC) {
4508 pBss->AuthMode = Ndis802_11AuthModeWPANone;
4509 pBss->AuthModeAux = Ndis802_11AuthModeWPANone;
4510 pBss->WPA.PairCipherAux =
4511 pBss->WPA2.PairCipherAux;
4512 pBss->WPA.GroupCipher = pBss->WPA2.GroupCipher;
4513 pBss->WepStatus = pBss->WPA.GroupCipher;
4514 /* Patched bugs for old driver */
4515 if (pBss->WPA.PairCipherAux ==
4516 Ndis802_11WEPDisabled)
4517 pBss->WPA.PairCipherAux =
4518 pBss->WPA.GroupCipher;
4520 pBss->WepStatus = pBss->WPA2.PairCipher;
4522 /* 6. Get RSN capability */
4523 /*pBss->WPA2.RsnCapability = *(u16 *)pTmp; */
4524 pBss->WPA2.RsnCapability = (pTmp[1] << 8) + pTmp[0];
4525 pTmp += sizeof(u16);
4527 /* Check the Pair & Group, if different, turn on mixed mode flag */
4528 if (pBss->WPA2.GroupCipher != pBss->WPA2.PairCipher)
4529 pBss->WPA2.bMixMode = TRUE;
4535 Length -= (pEid->Len + 2);
4539 /* =========================================================================================== */
4541 /* =========================================================================================== */
4543 /*! \brief generates a random mac address value for IBSS BSSID
4544 * \param Addr the bssid location
4549 void MacAddrRandomBssid(struct rt_rtmp_adapter *pAd, u8 *pAddr)
4553 for (i = 0; i < MAC_ADDR_LEN; i++) {
4554 pAddr[i] = RandomByte(pAd);
4557 pAddr[0] = (pAddr[0] & 0xfe) | 0x02; /* the first 2 bits must be 01xxxxxxxx */
4560 /*! \brief init the management mac frame header
4561 * \param p_hdr mac header
4562 * \param subtype subtype of the frame
4563 * \param p_ds destination address, don't care if it is a broadcast address
4565 * \pre the station has the following information in the pAd->StaCfg
4569 * \note this function initializes the following field
4571 IRQL = PASSIVE_LEVEL
4572 IRQL = DISPATCH_LEVEL
4575 void MgtMacHeaderInit(struct rt_rtmp_adapter *pAd,
4576 struct rt_header_802_11 * pHdr80211,
4578 u8 ToDs, u8 *pDA, u8 *pBssid)
4580 NdisZeroMemory(pHdr80211, sizeof(struct rt_header_802_11));
4582 pHdr80211->FC.Type = BTYPE_MGMT;
4583 pHdr80211->FC.SubType = SubType;
4584 /* if (SubType == SUBTYPE_ACK) // sample, no use, it will conflict with ACTION frame sub type */
4585 /* pHdr80211->FC.Type = BTYPE_CNTL; */
4586 pHdr80211->FC.ToDs = ToDs;
4587 COPY_MAC_ADDR(pHdr80211->Addr1, pDA);
4588 COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress);
4589 COPY_MAC_ADDR(pHdr80211->Addr3, pBssid);
4592 /* =========================================================================================== */
4594 /* =========================================================================================== */
4596 /*!***************************************************************************
4597 * This routine build an outgoing frame, and fill all information specified
4598 * in argument list to the frame body. The actual frame size is the summation
4601 * Buffer - pointer to a pre-allocated memory segment
4602 * args - a list of <int arg_size, arg> pairs.
4603 * NOTE NOTE NOTE! the last argument must be NULL, otherwise this
4604 * function will FAIL!
4606 * Size of the buffer
4608 * MakeOutgoingFrame(Buffer, output_length, 2, &fc, 2, &dur, 6, p_addr1, 6,p_addr2, END_OF_ARGS);
4610 IRQL = PASSIVE_LEVEL
4611 IRQL = DISPATCH_LEVEL
4613 ****************************************************************************/
4614 unsigned long MakeOutgoingFrame(u8 * Buffer, unsigned long * FrameLen, ...)
4618 unsigned long TotLeng;
4621 /* calculates the total length */
4623 va_start(Args, FrameLen);
4625 leng = va_arg(Args, int);
4626 if (leng == END_OF_ARGS) {
4629 p = va_arg(Args, void *);
4630 NdisMoveMemory(&Buffer[TotLeng], p, leng);
4631 TotLeng = TotLeng + leng;
4634 va_end(Args); /* clean up */
4635 *FrameLen = TotLeng;
4639 /* =========================================================================================== */
4641 /* =========================================================================================== */
4643 /*! \brief Initialize The MLME Queue, used by MLME Functions
4644 * \param *Queue The MLME Queue
4645 * \return Always Return NDIS_STATE_SUCCESS in this implementation
4648 * \note Because this is done only once (at the init stage), no need to be locked
4650 IRQL = PASSIVE_LEVEL
4653 int MlmeQueueInit(struct rt_mlme_queue *Queue)
4657 NdisAllocateSpinLock(&Queue->Lock);
4663 for (i = 0; i < MAX_LEN_OF_MLME_QUEUE; i++) {
4664 Queue->Entry[i].Occupied = FALSE;
4665 Queue->Entry[i].MsgLen = 0;
4666 NdisZeroMemory(Queue->Entry[i].Msg, MGMT_DMA_BUFFER_SIZE);
4669 return NDIS_STATUS_SUCCESS;
4672 /*! \brief Enqueue a message for other threads, if they want to send messages to MLME thread
4673 * \param *Queue The MLME Queue
4674 * \param Machine The State Machine Id
4675 * \param MsgType The Message Type
4676 * \param MsgLen The Message length
4677 * \param *Msg The message pointer
4678 * \return TRUE if enqueue is successful, FALSE if the queue is full
4681 * \note The message has to be initialized
4683 IRQL = PASSIVE_LEVEL
4684 IRQL = DISPATCH_LEVEL
4687 BOOLEAN MlmeEnqueue(struct rt_rtmp_adapter *pAd,
4688 unsigned long Machine,
4689 unsigned long MsgType, unsigned long MsgLen, void * Msg)
4692 struct rt_mlme_queue *Queue = (struct rt_mlme_queue *)& pAd->Mlme.Queue;
4694 /* Do nothing if the driver is starting halt state. */
4695 /* This might happen when timer already been fired before cancel timer with mlmehalt */
4697 (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST))
4700 /* First check the size, it MUST not exceed the mlme queue size */
4701 if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
4702 DBGPRINT_ERR(("MlmeEnqueue: msg too large, size = %ld \n",
4707 if (MlmeQueueFull(Queue)) {
4711 NdisAcquireSpinLock(&(Queue->Lock));
4715 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) {
4719 Queue->Entry[Tail].Wcid = RESERVED_WCID;
4720 Queue->Entry[Tail].Occupied = TRUE;
4721 Queue->Entry[Tail].Machine = Machine;
4722 Queue->Entry[Tail].MsgType = MsgType;
4723 Queue->Entry[Tail].MsgLen = MsgLen;
4726 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4729 NdisReleaseSpinLock(&(Queue->Lock));
4733 /*! \brief This function is used when Recv gets a MLME message
4734 * \param *Queue The MLME Queue
4735 * \param TimeStampHigh The upper 32 bit of timestamp
4736 * \param TimeStampLow The lower 32 bit of timestamp
4737 * \param Rssi The receiving RSSI strength
4738 * \param MsgLen The length of the message
4739 * \param *Msg The message pointer
4740 * \return TRUE if everything ok, FALSE otherwise (like Queue Full)
4744 IRQL = DISPATCH_LEVEL
4747 BOOLEAN MlmeEnqueueForRecv(struct rt_rtmp_adapter *pAd,
4749 unsigned long TimeStampHigh,
4750 unsigned long TimeStampLow,
4754 unsigned long MsgLen, void * Msg, u8 Signal)
4757 struct rt_frame_802_11 * pFrame = (struct rt_frame_802_11 *) Msg;
4759 struct rt_mlme_queue *Queue = (struct rt_mlme_queue *)& pAd->Mlme.Queue;
4761 /* Do nothing if the driver is starting halt state. */
4762 /* This might happen when timer already been fired before cancel timer with mlmehalt */
4765 fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) {
4766 DBGPRINT_ERR(("MlmeEnqueueForRecv: fRTMP_ADAPTER_HALT_IN_PROGRESS\n"));
4769 /* First check the size, it MUST not exceed the mlme queue size */
4770 if (MsgLen > MGMT_DMA_BUFFER_SIZE) {
4771 DBGPRINT_ERR(("MlmeEnqueueForRecv: frame too large, size = %ld \n", MsgLen));
4775 if (MlmeQueueFull(Queue)) {
4780 if (!MsgTypeSubst(pAd, pFrame, &Machine, &MsgType)) {
4781 DBGPRINT_ERR(("MlmeEnqueueForRecv: un-recongnized mgmt->subtype=%d\n", pFrame->Hdr.FC.SubType));
4786 /* OK, we got all the informations, it is time to put things into queue */
4787 NdisAcquireSpinLock(&(Queue->Lock));
4791 if (Queue->Tail == MAX_LEN_OF_MLME_QUEUE) {
4794 Queue->Entry[Tail].Occupied = TRUE;
4795 Queue->Entry[Tail].Machine = Machine;
4796 Queue->Entry[Tail].MsgType = MsgType;
4797 Queue->Entry[Tail].MsgLen = MsgLen;
4798 Queue->Entry[Tail].TimeStamp.u.LowPart = TimeStampLow;
4799 Queue->Entry[Tail].TimeStamp.u.HighPart = TimeStampHigh;
4800 Queue->Entry[Tail].Rssi0 = Rssi0;
4801 Queue->Entry[Tail].Rssi1 = Rssi1;
4802 Queue->Entry[Tail].Rssi2 = Rssi2;
4803 Queue->Entry[Tail].Signal = Signal;
4804 Queue->Entry[Tail].Wcid = (u8)Wcid;
4806 Queue->Entry[Tail].Channel = pAd->LatchRfRegs.Channel;
4809 NdisMoveMemory(Queue->Entry[Tail].Msg, Msg, MsgLen);
4812 NdisReleaseSpinLock(&(Queue->Lock));
4814 RTMP_MLME_HANDLER(pAd);
4819 /*! \brief Dequeue a message from the MLME Queue
4820 * \param *Queue The MLME Queue
4821 * \param *Elem The message dequeued from MLME Queue
4822 * \return TRUE if the Elem contains something, FALSE otherwise
4826 IRQL = DISPATCH_LEVEL
4829 BOOLEAN MlmeDequeue(struct rt_mlme_queue *Queue, struct rt_mlme_queue_elem ** Elem)
4831 NdisAcquireSpinLock(&(Queue->Lock));
4832 *Elem = &(Queue->Entry[Queue->Head]);
4835 if (Queue->Head == MAX_LEN_OF_MLME_QUEUE) {
4838 NdisReleaseSpinLock(&(Queue->Lock));
4842 /* IRQL = DISPATCH_LEVEL */
4843 void MlmeRestartStateMachine(struct rt_rtmp_adapter *pAd)
4846 struct rt_mlme_queue_elem *Elem = NULL;
4847 #endif /* RTMP_MAC_PCI // */
4850 DBGPRINT(RT_DEBUG_TRACE, ("MlmeRestartStateMachine \n"));
4853 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
4854 if (pAd->Mlme.bRunning) {
4855 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4858 pAd->Mlme.bRunning = TRUE;
4860 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4862 /* Remove all Mlme queues elements */
4863 while (!MlmeQueueEmpty(&pAd->Mlme.Queue)) {
4864 /*From message type, determine which state machine I should drive */
4865 if (MlmeDequeue(&pAd->Mlme.Queue, &Elem)) {
4866 /* free MLME element */
4867 Elem->Occupied = FALSE;
4871 DBGPRINT_ERR(("MlmeRestartStateMachine: MlmeQueue empty\n"));
4874 #endif /* RTMP_MAC_PCI // */
4877 /* Cancel all timer events */
4878 /* Be careful to cancel new added timer */
4879 RTMPCancelTimer(&pAd->MlmeAux.AssocTimer, &Cancelled);
4880 RTMPCancelTimer(&pAd->MlmeAux.ReassocTimer, &Cancelled);
4881 RTMPCancelTimer(&pAd->MlmeAux.DisassocTimer, &Cancelled);
4882 RTMPCancelTimer(&pAd->MlmeAux.AuthTimer, &Cancelled);
4883 RTMPCancelTimer(&pAd->MlmeAux.BeaconTimer, &Cancelled);
4884 RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
4888 /* Change back to original channel in case of doing scan */
4889 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
4890 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
4892 /* Resume MSDU which is turned off durning scan */
4893 RTMPResumeMsduTransmission(pAd);
4896 /* Set all state machines back IDLE */
4897 pAd->Mlme.CntlMachine.CurrState = CNTL_IDLE;
4898 pAd->Mlme.AssocMachine.CurrState = ASSOC_IDLE;
4899 pAd->Mlme.AuthMachine.CurrState = AUTH_REQ_IDLE;
4900 pAd->Mlme.AuthRspMachine.CurrState = AUTH_RSP_IDLE;
4901 pAd->Mlme.SyncMachine.CurrState = SYNC_IDLE;
4902 pAd->Mlme.ActMachine.CurrState = ACT_IDLE;
4906 /* Remove running state */
4907 NdisAcquireSpinLock(&pAd->Mlme.TaskLock);
4908 pAd->Mlme.bRunning = FALSE;
4909 NdisReleaseSpinLock(&pAd->Mlme.TaskLock);
4910 #endif /* RTMP_MAC_PCI // */
4913 /*! \brief test if the MLME Queue is empty
4914 * \param *Queue The MLME Queue
4915 * \return TRUE if the Queue is empty, FALSE otherwise
4919 IRQL = DISPATCH_LEVEL
4922 BOOLEAN MlmeQueueEmpty(struct rt_mlme_queue *Queue)
4926 NdisAcquireSpinLock(&(Queue->Lock));
4927 Ans = (Queue->Num == 0);
4928 NdisReleaseSpinLock(&(Queue->Lock));
4933 /*! \brief test if the MLME Queue is full
4934 * \param *Queue The MLME Queue
4935 * \return TRUE if the Queue is empty, FALSE otherwise
4939 IRQL = PASSIVE_LEVEL
4940 IRQL = DISPATCH_LEVEL
4943 BOOLEAN MlmeQueueFull(struct rt_mlme_queue *Queue)
4947 NdisAcquireSpinLock(&(Queue->Lock));
4948 Ans = (Queue->Num == MAX_LEN_OF_MLME_QUEUE
4949 || Queue->Entry[Queue->Tail].Occupied);
4950 NdisReleaseSpinLock(&(Queue->Lock));
4955 /*! \brief The destructor of MLME Queue
4960 * \note Clear Mlme Queue, Set Queue->Num to Zero.
4962 IRQL = PASSIVE_LEVEL
4965 void MlmeQueueDestroy(struct rt_mlme_queue *pQueue)
4967 NdisAcquireSpinLock(&(pQueue->Lock));
4971 NdisReleaseSpinLock(&(pQueue->Lock));
4972 NdisFreeSpinLock(&(pQueue->Lock));
4975 /*! \brief To substitute the message type if the message is coming from external
4976 * \param pFrame The frame received
4977 * \param *Machine The state machine
4978 * \param *MsgType the message type for the state machine
4979 * \return TRUE if the substitution is successful, FALSE otherwise
4983 IRQL = DISPATCH_LEVEL
4986 BOOLEAN MsgTypeSubst(struct rt_rtmp_adapter *pAd,
4987 struct rt_frame_802_11 * pFrame,
4988 int * Machine, int * MsgType)
4994 /* Pointer to start of data frames including SNAP header */
4995 pData = (u8 *)pFrame + LENGTH_802_11;
4997 /* The only data type will pass to this function is EAPOL frame */
4998 if (pFrame->Hdr.FC.Type == BTYPE_DATA) {
5000 *Machine = WPA_STATE_MACHINE;
5002 *((u8 *) pFrame + LENGTH_802_11 +
5003 LENGTH_802_1_H + 1);
5004 return (WpaMsgTypeSubst(EAPType, (int *) MsgType));
5008 switch (pFrame->Hdr.FC.SubType) {
5009 case SUBTYPE_ASSOC_REQ:
5010 *Machine = ASSOC_STATE_MACHINE;
5011 *MsgType = MT2_PEER_ASSOC_REQ;
5013 case SUBTYPE_ASSOC_RSP:
5014 *Machine = ASSOC_STATE_MACHINE;
5015 *MsgType = MT2_PEER_ASSOC_RSP;
5017 case SUBTYPE_REASSOC_REQ:
5018 *Machine = ASSOC_STATE_MACHINE;
5019 *MsgType = MT2_PEER_REASSOC_REQ;
5021 case SUBTYPE_REASSOC_RSP:
5022 *Machine = ASSOC_STATE_MACHINE;
5023 *MsgType = MT2_PEER_REASSOC_RSP;
5025 case SUBTYPE_PROBE_REQ:
5026 *Machine = SYNC_STATE_MACHINE;
5027 *MsgType = MT2_PEER_PROBE_REQ;
5029 case SUBTYPE_PROBE_RSP:
5030 *Machine = SYNC_STATE_MACHINE;
5031 *MsgType = MT2_PEER_PROBE_RSP;
5033 case SUBTYPE_BEACON:
5034 *Machine = SYNC_STATE_MACHINE;
5035 *MsgType = MT2_PEER_BEACON;
5038 *Machine = SYNC_STATE_MACHINE;
5039 *MsgType = MT2_PEER_ATIM;
5041 case SUBTYPE_DISASSOC:
5042 *Machine = ASSOC_STATE_MACHINE;
5043 *MsgType = MT2_PEER_DISASSOC_REQ;
5046 /* get the sequence number from payload 24 Mac Header + 2 bytes algorithm */
5047 NdisMoveMemory(&Seq, &pFrame->Octet[2], sizeof(u16));
5048 NdisMoveMemory(&Alg, &pFrame->Octet[0], sizeof(u16));
5049 if (Seq == 1 || Seq == 3) {
5050 *Machine = AUTH_RSP_STATE_MACHINE;
5051 *MsgType = MT2_PEER_AUTH_ODD;
5052 } else if (Seq == 2 || Seq == 4) {
5053 if (Alg == AUTH_MODE_OPEN || Alg == AUTH_MODE_KEY) {
5054 *Machine = AUTH_STATE_MACHINE;
5055 *MsgType = MT2_PEER_AUTH_EVEN;
5061 case SUBTYPE_DEAUTH:
5062 *Machine = AUTH_RSP_STATE_MACHINE;
5063 *MsgType = MT2_PEER_DEAUTH;
5065 case SUBTYPE_ACTION:
5066 *Machine = ACTION_STATE_MACHINE;
5067 /* Sometimes Sta will return with category bytes with MSB = 1, if they receive catogory out of their support */
5068 if ((pFrame->Octet[0] & 0x7F) > MAX_PEER_CATE_MSG) {
5069 *MsgType = MT2_ACT_INVALID;
5071 *MsgType = (pFrame->Octet[0] & 0x7F);
5082 /* =========================================================================================== */
5083 /* state_machine.c */
5084 /* =========================================================================================== */
5086 /*! \brief Initialize the state machine.
5087 * \param *S pointer to the state machine
5088 * \param Trans State machine transition function
5089 * \param StNr number of states
5090 * \param MsgNr number of messages
5091 * \param DefFunc default function, when there is invalid state/message combination
5092 * \param InitState initial state of the state machine
5093 * \param Base StateMachine base, internal use only
5094 * \pre p_sm should be a legal pointer
5097 IRQL = PASSIVE_LEVEL
5100 void StateMachineInit(struct rt_state_machine *S,
5101 IN STATE_MACHINE_FUNC Trans[],
5103 unsigned long MsgNr,
5104 IN STATE_MACHINE_FUNC DefFunc,
5105 unsigned long InitState, unsigned long Base)
5109 /* set number of states and messages */
5114 S->TransFunc = Trans;
5116 /* init all state transition to default function */
5117 for (i = 0; i < StNr; i++) {
5118 for (j = 0; j < MsgNr; j++) {
5119 S->TransFunc[i * MsgNr + j] = DefFunc;
5123 /* set the starting state */
5124 S->CurrState = InitState;
5127 /*! \brief This function fills in the function pointer into the cell in the state machine
5128 * \param *S pointer to the state machine
5130 * \param Msg incoming message
5131 * \param f the function to be executed when (state, message) combination occurs at the state machine
5132 * \pre *S should be a legal pointer to the state machine, st, msg, should be all within the range, Base should be set in the initial state
5135 IRQL = PASSIVE_LEVEL
5138 void StateMachineSetAction(struct rt_state_machine *S,
5140 unsigned long Msg, IN STATE_MACHINE_FUNC Func)
5142 unsigned long MsgIdx;
5144 MsgIdx = Msg - S->Base;
5146 if (St < S->NrState && MsgIdx < S->NrMsg) {
5147 /* boundary checking before setting the action */
5148 S->TransFunc[St * S->NrMsg + MsgIdx] = Func;
5152 /*! \brief This function does the state transition
5153 * \param *Adapter the NIC adapter pointer
5154 * \param *S the state machine
5155 * \param *Elem the message to be executed
5158 IRQL = DISPATCH_LEVEL
5161 void StateMachinePerformAction(struct rt_rtmp_adapter *pAd,
5162 struct rt_state_machine *S, struct rt_mlme_queue_elem *Elem)
5164 (*(S->TransFunc[S->CurrState * S->NrMsg + Elem->MsgType - S->Base]))
5169 ==========================================================================
5171 The drop function, when machine executes this, the message is simply
5172 ignored. This function does nothing, the message is freed in
5173 StateMachinePerformAction()
5174 ==========================================================================
5176 void Drop(struct rt_rtmp_adapter *pAd, struct rt_mlme_queue_elem *Elem)
5180 /* =========================================================================================== */
5182 /* =========================================================================================== */
5185 ==========================================================================
5188 IRQL = PASSIVE_LEVEL
5190 ==========================================================================
5192 void LfsrInit(struct rt_rtmp_adapter *pAd, unsigned long Seed)
5195 pAd->Mlme.ShiftReg = 1;
5197 pAd->Mlme.ShiftReg = Seed;
5201 ==========================================================================
5203 ==========================================================================
5205 u8 RandomByte(struct rt_rtmp_adapter *pAd)
5212 if (pAd->Mlme.ShiftReg == 0)
5213 NdisGetSystemUpTime((unsigned long *) & pAd->Mlme.ShiftReg);
5215 for (i = 0; i < 8; i++) {
5216 if (pAd->Mlme.ShiftReg & 0x00000001) {
5217 pAd->Mlme.ShiftReg =
5219 ShiftReg ^ LFSR_MASK) >> 1) | 0x80000000;
5222 pAd->Mlme.ShiftReg = pAd->Mlme.ShiftReg >> 1;
5225 R = (R << 1) | Result;
5232 ========================================================================
5234 Routine Description:
5235 Verify the support rate for different PHY type
5238 pAd Pointer to our adapter
5243 IRQL = PASSIVE_LEVEL
5245 ========================================================================
5247 void RTMPCheckRates(struct rt_rtmp_adapter *pAd,
5248 IN u8 SupRate[], IN u8 * SupRateLen)
5251 u8 NewRate[12], NewRateLen;
5255 if (pAd->CommonCfg.PhyMode == PHY_11B)
5260 /* Check for support rates exclude basic rate bit */
5261 for (i = 0; i < *SupRateLen; i++)
5262 for (j = 0; j < RateIdx; j++)
5263 if ((SupRate[i] & 0x7f) == RateIdTo500Kbps[j])
5264 NewRate[NewRateLen++] = SupRate[i];
5266 *SupRateLen = NewRateLen;
5267 NdisMoveMemory(SupRate, NewRate, NewRateLen);
5270 BOOLEAN RTMPCheckChannel(struct rt_rtmp_adapter *pAd,
5271 u8 CentralChannel, u8 Channel)
5274 u8 UpperChannel = 0, LowerChannel = 0;
5275 u8 NoEffectChannelinList = 0;
5277 /* Find upper and lower channel according to 40MHz current operation. */
5278 if (CentralChannel < Channel) {
5279 UpperChannel = Channel;
5280 if (CentralChannel > 2)
5281 LowerChannel = CentralChannel - 2;
5284 } else if (CentralChannel > Channel) {
5285 UpperChannel = CentralChannel + 2;
5286 LowerChannel = Channel;
5289 for (k = 0; k < pAd->ChannelListNum; k++) {
5290 if (pAd->ChannelList[k].Channel == UpperChannel) {
5291 NoEffectChannelinList++;
5293 if (pAd->ChannelList[k].Channel == LowerChannel) {
5294 NoEffectChannelinList++;
5298 DBGPRINT(RT_DEBUG_TRACE,
5299 ("Total Channel in Channel List = [%d]\n",
5300 NoEffectChannelinList));
5301 if (NoEffectChannelinList == 2)
5308 ========================================================================
5310 Routine Description:
5311 Verify the support rate for HT phy type
5314 pAd Pointer to our adapter
5317 FALSE if pAd->CommonCfg.SupportedHtPhy doesn't accept the pHtCapability. (AP Mode)
5319 IRQL = PASSIVE_LEVEL
5321 ========================================================================
5323 BOOLEAN RTMPCheckHt(struct rt_rtmp_adapter *pAd,
5325 struct rt_ht_capability_ie * pHtCapability,
5326 struct rt_add_ht_info_ie * pAddHtInfo)
5328 if (Wcid >= MAX_LEN_OF_MAC_TABLE)
5331 /* If use AMSDU, set flag. */
5332 if (pAd->CommonCfg.DesiredHtPhy.AmsduEnable)
5333 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5334 fCLIENT_STATUS_AMSDU_INUSED);
5335 /* Save Peer Capability */
5336 if (pHtCapability->HtCapInfo.ShortGIfor20)
5337 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5338 fCLIENT_STATUS_SGI20_CAPABLE);
5339 if (pHtCapability->HtCapInfo.ShortGIfor40)
5340 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5341 fCLIENT_STATUS_SGI40_CAPABLE);
5342 if (pHtCapability->HtCapInfo.TxSTBC)
5343 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5344 fCLIENT_STATUS_TxSTBC_CAPABLE);
5345 if (pHtCapability->HtCapInfo.RxSTBC)
5346 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5347 fCLIENT_STATUS_RxSTBC_CAPABLE);
5348 if (pAd->CommonCfg.bRdg && pHtCapability->ExtHtCapInfo.RDGSupport) {
5349 CLIENT_STATUS_SET_FLAG(&pAd->MacTab.Content[Wcid],
5350 fCLIENT_STATUS_RDG_CAPABLE);
5353 if (Wcid < MAX_LEN_OF_MAC_TABLE) {
5354 pAd->MacTab.Content[Wcid].MpduDensity =
5355 pHtCapability->HtCapParm.MpduDensity;
5357 /* Will check ChannelWidth for MCSSet[4] below */
5358 pAd->MlmeAux.HtCapability.MCSSet[4] = 0x1;
5359 switch (pAd->CommonCfg.RxStream) {
5361 pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5362 pAd->MlmeAux.HtCapability.MCSSet[1] = 0x00;
5363 pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
5364 pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5367 pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5368 pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
5369 pAd->MlmeAux.HtCapability.MCSSet[2] = 0x00;
5370 pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5373 pAd->MlmeAux.HtCapability.MCSSet[0] = 0xff;
5374 pAd->MlmeAux.HtCapability.MCSSet[1] = 0xff;
5375 pAd->MlmeAux.HtCapability.MCSSet[2] = 0xff;
5376 pAd->MlmeAux.HtCapability.MCSSet[3] = 0x00;
5380 pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth =
5381 pAddHtInfo->AddHtInfo.RecomWidth & pAd->CommonCfg.DesiredHtPhy.
5384 DBGPRINT(RT_DEBUG_TRACE,
5385 ("RTMPCheckHt:: HtCapInfo.ChannelWidth=%d, RecomWidth=%d, DesiredHtPhy.ChannelWidth=%d, BW40MAvailForA/G=%d/%d, PhyMode=%d \n",
5386 pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth,
5387 pAddHtInfo->AddHtInfo.RecomWidth,
5388 pAd->CommonCfg.DesiredHtPhy.ChannelWidth,
5389 pAd->NicConfig2.field.BW40MAvailForA,
5390 pAd->NicConfig2.field.BW40MAvailForG,
5391 pAd->CommonCfg.PhyMode));
5393 pAd->MlmeAux.HtCapability.HtCapInfo.GF =
5394 pHtCapability->HtCapInfo.GF & pAd->CommonCfg.DesiredHtPhy.GF;
5396 /* Send Assoc Req with my HT capability. */
5397 pAd->MlmeAux.HtCapability.HtCapInfo.AMsduSize =
5398 pAd->CommonCfg.DesiredHtPhy.AmsduSize;
5399 pAd->MlmeAux.HtCapability.HtCapInfo.MimoPs =
5400 pAd->CommonCfg.DesiredHtPhy.MimoPs;
5401 pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor20 =
5402 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor20) & (pHtCapability->
5405 pAd->MlmeAux.HtCapability.HtCapInfo.ShortGIfor40 =
5406 (pAd->CommonCfg.DesiredHtPhy.ShortGIfor40) & (pHtCapability->
5409 pAd->MlmeAux.HtCapability.HtCapInfo.TxSTBC =
5410 (pAd->CommonCfg.DesiredHtPhy.TxSTBC) & (pHtCapability->HtCapInfo.
5412 pAd->MlmeAux.HtCapability.HtCapInfo.RxSTBC =
5413 (pAd->CommonCfg.DesiredHtPhy.RxSTBC) & (pHtCapability->HtCapInfo.
5415 pAd->MlmeAux.HtCapability.HtCapParm.MaxRAmpduFactor =
5416 pAd->CommonCfg.DesiredHtPhy.MaxRAmpduFactor;
5417 pAd->MlmeAux.HtCapability.HtCapParm.MpduDensity =
5418 pAd->CommonCfg.HtCapability.HtCapParm.MpduDensity;
5419 pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC =
5420 pHtCapability->ExtHtCapInfo.PlusHTC;
5421 pAd->MacTab.Content[Wcid].HTCapability.ExtHtCapInfo.PlusHTC =
5422 pHtCapability->ExtHtCapInfo.PlusHTC;
5423 if (pAd->CommonCfg.bRdg) {
5424 pAd->MlmeAux.HtCapability.ExtHtCapInfo.RDGSupport =
5425 pHtCapability->ExtHtCapInfo.RDGSupport;
5426 pAd->MlmeAux.HtCapability.ExtHtCapInfo.PlusHTC = 1;
5429 if (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_20)
5430 pAd->MlmeAux.HtCapability.MCSSet[4] = 0x0; /* BW20 can't transmit MCS32 */
5432 COPY_AP_HTSETTINGS_FROM_BEACON(pAd, pHtCapability);
5437 ========================================================================
5439 Routine Description:
5440 Verify the support rate for different PHY type
5443 pAd Pointer to our adapter
5448 IRQL = PASSIVE_LEVEL
5450 ========================================================================
5452 void RTMPUpdateMlmeRate(struct rt_rtmp_adapter *pAd)
5455 u8 ProperMlmeRate; /*= RATE_54; */
5456 u8 i, j, RateIdx = 12; /*1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54 */
5457 BOOLEAN bMatch = FALSE;
5459 switch (pAd->CommonCfg.PhyMode) {
5461 ProperMlmeRate = RATE_11;
5462 MinimumRate = RATE_1;
5464 case PHY_11BG_MIXED:
5465 case PHY_11ABGN_MIXED:
5466 case PHY_11BGN_MIXED:
5467 if ((pAd->MlmeAux.SupRateLen == 4) &&
5468 (pAd->MlmeAux.ExtRateLen == 0))
5470 ProperMlmeRate = RATE_11;
5472 ProperMlmeRate = RATE_24;
5474 if (pAd->MlmeAux.Channel <= 14)
5475 MinimumRate = RATE_1;
5477 MinimumRate = RATE_6;
5480 case PHY_11N_2_4G: /* rt2860 need to check mlmerate for 802.11n */
5481 case PHY_11GN_MIXED:
5482 case PHY_11AGN_MIXED:
5483 case PHY_11AN_MIXED:
5485 ProperMlmeRate = RATE_24;
5486 MinimumRate = RATE_6;
5488 case PHY_11ABG_MIXED:
5489 ProperMlmeRate = RATE_24;
5490 if (pAd->MlmeAux.Channel <= 14)
5491 MinimumRate = RATE_1;
5493 MinimumRate = RATE_6;
5495 default: /* error */
5496 ProperMlmeRate = RATE_1;
5497 MinimumRate = RATE_1;
5501 for (i = 0; i < pAd->MlmeAux.SupRateLen; i++) {
5502 for (j = 0; j < RateIdx; j++) {
5503 if ((pAd->MlmeAux.SupRate[i] & 0x7f) ==
5504 RateIdTo500Kbps[j]) {
5505 if (j == ProperMlmeRate) {
5516 if (bMatch == FALSE) {
5517 for (i = 0; i < pAd->MlmeAux.ExtRateLen; i++) {
5518 for (j = 0; j < RateIdx; j++) {
5519 if ((pAd->MlmeAux.ExtRate[i] & 0x7f) ==
5520 RateIdTo500Kbps[j]) {
5521 if (j == ProperMlmeRate) {
5533 if (bMatch == FALSE) {
5534 ProperMlmeRate = MinimumRate;
5537 pAd->CommonCfg.MlmeRate = MinimumRate;
5538 pAd->CommonCfg.RtsRate = ProperMlmeRate;
5539 if (pAd->CommonCfg.MlmeRate >= RATE_6) {
5540 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_OFDM;
5541 pAd->CommonCfg.MlmeTransmit.field.MCS =
5542 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
5543 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE =
5545 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS =
5546 OfdmRateToRxwiMCS[pAd->CommonCfg.MlmeRate];
5548 pAd->CommonCfg.MlmeTransmit.field.MODE = MODE_CCK;
5549 pAd->CommonCfg.MlmeTransmit.field.MCS = pAd->CommonCfg.MlmeRate;
5550 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MODE =
5552 pAd->MacTab.Content[BSS0Mcast_WCID].HTPhyMode.field.MCS =
5553 pAd->CommonCfg.MlmeRate;
5556 DBGPRINT(RT_DEBUG_TRACE,
5557 ("RTMPUpdateMlmeRate ==> MlmeTransmit = 0x%x \n",
5558 pAd->CommonCfg.MlmeTransmit.word));
5561 char RTMPMaxRssi(struct rt_rtmp_adapter *pAd,
5562 char Rssi0, char Rssi1, char Rssi2)
5566 if ((pAd->Antenna.field.RxPath == 1) && (Rssi0 != 0)) {
5570 if ((pAd->Antenna.field.RxPath >= 2) && (Rssi1 != 0)) {
5571 larger = max(Rssi0, Rssi1);
5574 if ((pAd->Antenna.field.RxPath == 3) && (Rssi2 != 0)) {
5575 larger = max(larger, Rssi2);
5585 ========================================================================
5586 Routine Description:
5587 Periodic evaluate antenna link status
5590 pAd - Adapter pointer
5595 ========================================================================
5597 void AsicEvaluateRxAnt(struct rt_rtmp_adapter *pAd)
5601 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
5602 fRTMP_ADAPTER_HALT_IN_PROGRESS |
5603 fRTMP_ADAPTER_RADIO_OFF |
5604 fRTMP_ADAPTER_NIC_NOT_EXIST |
5605 fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS) ||
5606 OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
5608 || (pAd->EepromAccess)
5609 #endif /* RT30xx // */
5611 || (pAd->bPCIclkOff == TRUE)
5612 #endif /* RT3090 // */
5617 /*if (pAd->StaCfg.Psm == PWR_SAVE) */
5622 if (pAd->StaCfg.Psm == PWR_SAVE)
5625 RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
5627 if (pAd->Antenna.field.RxPath == 3) {
5629 } else if (pAd->Antenna.field.RxPath == 2) {
5631 } else if (pAd->Antenna.field.RxPath == 1) {
5634 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
5636 pAd->StaCfg.BBPR3 = BBPR3;
5637 #endif /* RTMP_MAC_PCI // */
5638 if (OPSTATUS_TEST_FLAG
5639 (pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
5641 unsigned long TxTotalCnt =
5642 pAd->RalinkCounters.OneSecTxNoRetryOkCount +
5643 pAd->RalinkCounters.OneSecTxRetryOkCount +
5644 pAd->RalinkCounters.OneSecTxFailCount;
5646 /* dynamic adjust antenna evaluation period according to the traffic */
5647 if (TxTotalCnt > 50) {
5648 RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer,
5650 pAd->Mlme.bLowThroughput = FALSE;
5652 RTMPSetTimer(&pAd->Mlme.RxAntEvalTimer,
5654 pAd->Mlme.bLowThroughput = TRUE;
5664 ========================================================================
5665 Routine Description:
5666 After evaluation, check antenna link status
5669 pAd - Adapter pointer
5674 ========================================================================
5676 void AsicRxAntEvalTimeout(void *SystemSpecific1,
5677 void *FunctionContext,
5678 void *SystemSpecific2, void *SystemSpecific3)
5680 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
5682 char larger = -127, rssi0, rssi1, rssi2;
5684 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS |
5685 fRTMP_ADAPTER_HALT_IN_PROGRESS |
5686 fRTMP_ADAPTER_RADIO_OFF |
5687 fRTMP_ADAPTER_NIC_NOT_EXIST) ||
5688 OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)
5690 || (pAd->EepromAccess)
5691 #endif /* RT30xx // */
5693 || (pAd->bPCIclkOff == TRUE)
5694 #endif /* RT3090 // */
5699 /*if (pAd->StaCfg.Psm == PWR_SAVE) */
5702 if (pAd->StaCfg.Psm == PWR_SAVE)
5705 /* if the traffic is low, use average rssi as the criteria */
5706 if (pAd->Mlme.bLowThroughput == TRUE) {
5707 rssi0 = pAd->StaCfg.RssiSample.LastRssi0;
5708 rssi1 = pAd->StaCfg.RssiSample.LastRssi1;
5709 rssi2 = pAd->StaCfg.RssiSample.LastRssi2;
5711 rssi0 = pAd->StaCfg.RssiSample.AvgRssi0;
5712 rssi1 = pAd->StaCfg.RssiSample.AvgRssi1;
5713 rssi2 = pAd->StaCfg.RssiSample.AvgRssi2;
5716 if (pAd->Antenna.field.RxPath == 3) {
5717 larger = max(rssi0, rssi1);
5719 if (larger > (rssi2 + 20))
5720 pAd->Mlme.RealRxPath = 2;
5722 pAd->Mlme.RealRxPath = 3;
5723 } else if (pAd->Antenna.field.RxPath == 2) {
5724 if (rssi0 > (rssi1 + 20))
5725 pAd->Mlme.RealRxPath = 1;
5727 pAd->Mlme.RealRxPath = 2;
5730 RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R3, &BBPR3);
5732 if (pAd->Mlme.RealRxPath == 3) {
5734 } else if (pAd->Mlme.RealRxPath == 2) {
5736 } else if (pAd->Mlme.RealRxPath == 1) {
5739 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, BBPR3);
5741 pAd->StaCfg.BBPR3 = BBPR3;
5742 #endif /* RTMP_MAC_PCI // */
5748 void APSDPeriodicExec(void *SystemSpecific1,
5749 void *FunctionContext,
5750 void *SystemSpecific2, void *SystemSpecific3)
5752 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
5754 if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED))
5757 pAd->CommonCfg.TriggerTimerCount++;
5759 /* Driver should not send trigger frame, it should be send by application layer */
5761 if (pAd->CommonCfg.bAPSDCapable && pAd->CommonCfg.APEdcaParm.bAPSDCapable
5762 && (pAd->CommonCfg.bNeedSendTriggerFrame ||
5763 (((pAd->CommonCfg.TriggerTimerCount%20) == 19) && (!pAd->CommonCfg.bAPSDAC_BE || !pAd->CommonCfg.bAPSDAC_BK || !pAd->CommonCfg.bAPSDAC_VI || !pAd->CommonCfg.bAPSDAC_VO))))
5765 DBGPRINT(RT_DEBUG_TRACE,("Sending trigger frame and enter service period when support APSD\n"));
5766 RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE);
5767 pAd->CommonCfg.bNeedSendTriggerFrame = FALSE;
5768 pAd->CommonCfg.TriggerTimerCount = 0;
5769 pAd->CommonCfg.bInServicePeriod = TRUE;
5774 ========================================================================
5775 Routine Description:
5776 Set/reset MAC registers according to bPiggyBack parameter
5779 pAd - Adapter pointer
5780 bPiggyBack - Enable / Disable Piggy-Back
5785 ========================================================================
5787 void RTMPSetPiggyBack(struct rt_rtmp_adapter *pAd, IN BOOLEAN bPiggyBack)
5789 TX_LINK_CFG_STRUC TxLinkCfg;
5791 RTMP_IO_READ32(pAd, TX_LINK_CFG, &TxLinkCfg.word);
5793 TxLinkCfg.field.TxCFAckEn = bPiggyBack;
5794 RTMP_IO_WRITE32(pAd, TX_LINK_CFG, TxLinkCfg.word);
5798 ========================================================================
5799 Routine Description:
5800 check if this entry need to switch rate automatically
5810 ========================================================================
5812 BOOLEAN RTMPCheckEntryEnableAutoRateSwitch(struct rt_rtmp_adapter *pAd,
5813 struct rt_mac_table_entry *pEntry)
5815 BOOLEAN result = TRUE;
5818 /* only associated STA counts */
5819 if (pEntry && (pEntry->ValidAsCLI)
5820 && (pEntry->Sst == SST_ASSOC)) {
5821 result = pAd->StaCfg.bAutoTxRateSwitch;
5829 BOOLEAN RTMPAutoRateSwitchCheck(struct rt_rtmp_adapter *pAd)
5832 if (pAd->StaCfg.bAutoTxRateSwitch)
5839 ========================================================================
5840 Routine Description:
5841 check if this entry need to fix tx legacy rate
5851 ========================================================================
5853 u8 RTMPStaFixedTxMode(struct rt_rtmp_adapter *pAd, struct rt_mac_table_entry *pEntry)
5855 u8 tx_mode = FIXED_TXMODE_HT;
5859 (u8)pAd->StaCfg.DesiredTransmitSetting.field.
5867 ========================================================================
5868 Routine Description:
5869 Overwrite HT Tx Mode by Fixed Legency Tx Mode, if specified.
5879 ========================================================================
5881 void RTMPUpdateLegacyTxSetting(u8 fixed_tx_mode, struct rt_mac_table_entry *pEntry)
5883 HTTRANSMIT_SETTING TransmitSetting;
5885 if (fixed_tx_mode == FIXED_TXMODE_HT)
5888 TransmitSetting.word = 0;
5890 TransmitSetting.field.MODE = pEntry->HTPhyMode.field.MODE;
5891 TransmitSetting.field.MCS = pEntry->HTPhyMode.field.MCS;
5893 if (fixed_tx_mode == FIXED_TXMODE_CCK) {
5894 TransmitSetting.field.MODE = MODE_CCK;
5895 /* CCK mode allow MCS 0~3 */
5896 if (TransmitSetting.field.MCS > MCS_3)
5897 TransmitSetting.field.MCS = MCS_3;
5899 TransmitSetting.field.MODE = MODE_OFDM;
5900 /* OFDM mode allow MCS 0~7 */
5901 if (TransmitSetting.field.MCS > MCS_7)
5902 TransmitSetting.field.MCS = MCS_7;
5905 if (pEntry->HTPhyMode.field.MODE >= TransmitSetting.field.MODE) {
5906 pEntry->HTPhyMode.word = TransmitSetting.word;
5907 DBGPRINT(RT_DEBUG_TRACE,
5908 ("RTMPUpdateLegacyTxSetting : wcid-%d, MODE=%s, MCS=%d \n",
5909 pEntry->Aid, GetPhyMode(pEntry->HTPhyMode.field.MODE),
5910 pEntry->HTPhyMode.field.MCS));
5915 ==========================================================================
5917 dynamic tune BBP R66 to find a balance between sensibility and
5920 IRQL = DISPATCH_LEVEL
5922 ==========================================================================
5924 void AsicStaBbpTuning(struct rt_rtmp_adapter *pAd)
5926 u8 OrigR66Value = 0, R66; /*, R66UpperBound = 0x30, R66LowerBound = 0x30; */
5929 /* 2860C did not support Fase CCA, therefore can't tune */
5930 if (pAd->MACVersion == 0x28600100)
5936 if (pAd->Mlme.CntlMachine.CurrState != CNTL_IDLE) /* no R66 tuning when SCANNING */
5939 if ((pAd->OpMode == OPMODE_STA)
5940 && (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_MEDIA_STATE_CONNECTED)
5942 && !(OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
5944 && (pAd->bPCIclkOff == FALSE)
5945 #endif /* RTMP_MAC_PCI // */
5947 RTMP_BBP_IO_READ8_BY_REG_ID(pAd, BBP_R66, &OrigR66Value);
5950 if (pAd->Antenna.field.RxPath > 1)
5952 (pAd->StaCfg.RssiSample.AvgRssi0 +
5953 pAd->StaCfg.RssiSample.AvgRssi1) >> 1;
5955 Rssi = pAd->StaCfg.RssiSample.AvgRssi0;
5957 if (pAd->LatchRfRegs.Channel <= 14) { /*BG band */
5959 /* RT3070 is a no LNA solution, it should have different control regarding to AGC gain control */
5960 /* Otherwise, it will have some throughput side effect when low RSSI */
5962 if (IS_RT3070(pAd) || IS_RT3090(pAd) || IS_RT3572(pAd)
5963 || IS_RT3390(pAd)) {
5964 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5966 0x1C + 2 * GET_LNA_GAIN(pAd) + 0x20;
5967 if (OrigR66Value != R66) {
5968 RTMP_BBP_IO_WRITE8_BY_REG_ID
5969 (pAd, BBP_R66, R66);
5972 R66 = 0x1C + 2 * GET_LNA_GAIN(pAd);
5973 if (OrigR66Value != R66) {
5974 RTMP_BBP_IO_WRITE8_BY_REG_ID
5975 (pAd, BBP_R66, R66);
5979 #endif /* RT30xx // */
5981 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5982 R66 = (0x2E + GET_LNA_GAIN(pAd)) + 0x10;
5983 if (OrigR66Value != R66) {
5984 RTMP_BBP_IO_WRITE8_BY_REG_ID
5985 (pAd, BBP_R66, R66);
5988 R66 = 0x2E + GET_LNA_GAIN(pAd);
5989 if (OrigR66Value != R66) {
5990 RTMP_BBP_IO_WRITE8_BY_REG_ID
5991 (pAd, BBP_R66, R66);
5995 } else { /*A band */
5996 if (pAd->CommonCfg.BBPCurrentBW == BW_20) {
5997 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
5999 0x32 + (GET_LNA_GAIN(pAd) * 5) / 3 +
6001 if (OrigR66Value != R66) {
6002 RTMP_BBP_IO_WRITE8_BY_REG_ID
6003 (pAd, BBP_R66, R66);
6007 0x32 + (GET_LNA_GAIN(pAd) * 5) / 3;
6008 if (OrigR66Value != R66) {
6009 RTMP_BBP_IO_WRITE8_BY_REG_ID
6010 (pAd, BBP_R66, R66);
6014 if (Rssi > RSSI_FOR_MID_LOW_SENSIBILITY) {
6016 0x3A + (GET_LNA_GAIN(pAd) * 5) / 3 +
6018 if (OrigR66Value != R66) {
6019 RTMP_BBP_IO_WRITE8_BY_REG_ID
6020 (pAd, BBP_R66, R66);
6024 0x3A + (GET_LNA_GAIN(pAd) * 5) / 3;
6025 if (OrigR66Value != R66) {
6026 RTMP_BBP_IO_WRITE8_BY_REG_ID
6027 (pAd, BBP_R66, R66);
6036 void RTMPSetAGCInitValue(struct rt_rtmp_adapter *pAd, u8 BandWidth)
6040 if (pAd->LatchRfRegs.Channel <= 14) { /* BG band */
6042 /* Gary was verified Amazon AP and find that RT307x has BBP_R66 invalid default value */
6044 if (IS_RT3070(pAd) || IS_RT3090(pAd) || IS_RT3572(pAd)
6045 || IS_RT3390(pAd)) {
6046 R66 = 0x1C + 2 * GET_LNA_GAIN(pAd);
6047 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6049 #endif /* RT30xx // */
6051 R66 = 0x2E + GET_LNA_GAIN(pAd);
6052 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6054 } else { /*A band */
6056 if (BandWidth == BW_20) {
6059 (GET_LNA_GAIN(pAd) * 5) / 3);
6060 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);
6064 (GET_LNA_GAIN(pAd) * 5) / 3);
6065 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R66, R66);