Merge remote-tracking branch 'staging/staging-next'
[deliverable/linux.git] / drivers / staging / rtl8188eu / core / rtw_ieee80211.c
CommitLineData
06a05884
LF
1/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
06a05884
LF
14 ******************************************************************************/
15#define _IEEE80211_C
16
027d3efd
JS
17#include <linux/ieee80211.h>
18
06a05884 19#include <drv_types.h>
0aba3f41 20#include <osdep_intf.h>
06a05884
LF
21#include <ieee80211.h>
22#include <wifi.h>
23#include <osdep_service.h>
24#include <wlan_bssdef.h>
06a05884
LF
25
26u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
06a05884
LF
27u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
28u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
29u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
30u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
31u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
32u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
33u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
34u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
35u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
36
37u16 RSN_VERSION_BSD = 1;
38u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
39u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
40u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
41u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
42u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
43u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
44u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
45u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
46/* */
47/* for adhoc-master to generate ie and provide supported-rate to fw */
48/* */
49
50static u8 WIFI_CCKRATES[] = {
51 (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK),
52 (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK),
53 (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK),
54 (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)
55 };
56
57static u8 WIFI_OFDMRATES[] = {
58 (IEEE80211_OFDM_RATE_6MB),
59 (IEEE80211_OFDM_RATE_9MB),
60 (IEEE80211_OFDM_RATE_12MB),
61 (IEEE80211_OFDM_RATE_18MB),
62 (IEEE80211_OFDM_RATE_24MB),
63 IEEE80211_OFDM_RATE_36MB,
64 IEEE80211_OFDM_RATE_48MB,
65 IEEE80211_OFDM_RATE_54MB
66 };
67
68
69int rtw_get_bit_value_from_ieee_value(u8 val)
70{
71 unsigned char dot11_rate_table[] = {
72 2, 4, 11, 22, 12, 18, 24, 36, 48,
73 72, 96, 108, 0}; /* last element must be zero!! */
74
75 int i = 0;
76 while (dot11_rate_table[i] != 0) {
77 if (dot11_rate_table[i] == val)
78 return BIT(i);
79 i++;
80 }
81 return 0;
82}
83
84uint rtw_is_cckrates_included(u8 *rate)
85{
86 u32 i = 0;
87
88 while (rate[i] != 0) {
89 if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
90 (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22))
91 return true;
92 i++;
93 }
94 return false;
95}
96
97uint rtw_is_cckratesonly_included(u8 *rate)
98{
99 u32 i = 0;
100
101 while (rate[i] != 0) {
102 if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
103 (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22))
104 return false;
105 i++;
106 }
107
108 return true;
109}
110
111int rtw_check_network_type(unsigned char *rate, int ratelen, int channel)
112{
113 if (channel > 14) {
114 if ((rtw_is_cckrates_included(rate)) == true)
115 return WIRELESS_INVALID;
116 else
117 return WIRELESS_11A;
118 } else { /* could be pure B, pure G, or B/G */
119 if ((rtw_is_cckratesonly_included(rate)) == true)
120 return WIRELESS_11B;
121 else if ((rtw_is_cckrates_included(rate)) == true)
122 return WIRELESS_11BG;
123 else
124 return WIRELESS_11G;
125 }
126}
127
3441d08c
LC
128u8 *rtw_set_fixed_ie(void *pbuf, unsigned int len, void *source,
129 unsigned int *frlen)
06a05884 130{
3441d08c 131 memcpy(pbuf, source, len);
06a05884 132 *frlen = *frlen + len;
3441d08c 133 return ((u8 *)pbuf) + len;
06a05884
LF
134}
135
136/* rtw_set_ie will update frame length */
137u8 *rtw_set_ie
138(
139 u8 *pbuf,
140 int index,
141 uint len,
142 u8 *source,
143 uint *frlen /* frame length */
144)
145{
06a05884
LF
146 *pbuf = (u8)index;
147
148 *(pbuf + 1) = (u8)len;
149
150 if (len > 0)
151 memcpy((void *)(pbuf + 2), (void *)source, len);
152
153 *frlen = *frlen + (len + 2);
154
fbb57f6d 155 return pbuf + len + 2;
06a05884
LF
156}
157
06a05884
LF
158/*----------------------------------------------------------------------------
159index: the information element id index, limit is the limit for search
160-----------------------------------------------------------------------------*/
161u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit)
162{
163 int tmp, i;
164 u8 *p;
9cdddda5 165 if (limit < 1)
06a05884 166 return NULL;
06a05884
LF
167
168 p = pbuf;
169 i = 0;
170 *len = 0;
171 while (1) {
172 if (*p == index) {
173 *len = *(p + 1);
174 return p;
175 } else {
176 tmp = *(p + 1);
177 p += (tmp + 2);
178 i += (tmp + 2);
179 }
180 if (i >= limit)
181 break;
182 }
06a05884
LF
183 return NULL;
184}
185
06a05884
LF
186void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
187{
06a05884 188
1ce39848 189 memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
06a05884
LF
190
191 switch (mode) {
192 case WIRELESS_11B:
193 memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
194 break;
195 case WIRELESS_11G:
196 case WIRELESS_11A:
197 case WIRELESS_11_5N:
198 case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */
199 memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
200 break;
201 case WIRELESS_11BG:
202 case WIRELESS_11G_24N:
203 case WIRELESS_11_24N:
204 case WIRELESS_11BG_24N:
205 memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
206 memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
207 break;
208 }
06a05884
LF
209}
210
211uint rtw_get_rateset_len(u8 *rateset)
212{
213 uint i = 0;
06a05884
LF
214 while (1) {
215 if ((rateset[i]) == 0)
216 break;
217 if (i > 12)
218 break;
219 i++;
220 }
06a05884
LF
221 return i;
222}
223
224int rtw_generate_ie(struct registry_priv *pregistrypriv)
225{
226 u8 wireless_mode;
227 int sz = 0, rateLen;
228 struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
229 u8 *ie = pdev_network->IEs;
230
06a05884
LF
231
232 /* timestamp will be inserted by hardware */
233 sz += 8;
234 ie += sz;
235
236 /* beacon interval : 2bytes */
237 *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */
238 sz += 2;
239 ie += 2;
240
241 /* capability info */
242 *(u16 *)ie = 0;
243
244 *(__le16 *)ie |= cpu_to_le16(cap_IBSS);
245
246 if (pregistrypriv->preamble == PREAMBLE_SHORT)
247 *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble);
248
249 if (pdev_network->Privacy)
250 *(__le16 *)ie |= cpu_to_le16(cap_Privacy);
251
252 sz += 2;
253 ie += 2;
254
255 /* SSID */
256 ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz);
257
258 /* supported rates */
259 if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) {
260 if (pdev_network->Configuration.DSConfig > 14)
261 wireless_mode = WIRELESS_11A_5N;
262 else
263 wireless_mode = WIRELESS_11BG_24N;
264 } else {
265 wireless_mode = pregistrypriv->wireless_mode;
266 }
267
268 rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
269
270 rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
271
272 if (rateLen > 8) {
273 ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz);
274 /* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */
275 } else {
276 ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz);
277 }
278
279 /* DS parameter set */
280 ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz);
281
282 /* IBSS Parameter Set */
283
284 ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz);
285
286 if (rateLen > 8)
287 ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
06a05884
LF
288
289 return sz;
290}
291
292unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
293{
294 int len;
295 u16 val16;
296 __le16 le_tmp;
297 unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
298 u8 *pbuf = pie;
299 int limit_new = limit;
300
301 while (1) {
302 pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new);
303
304 if (pbuf) {
305 /* check if oui matches... */
f42f52aa 306 if (!memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)) == false)
06a05884
LF
307 goto check_next_ie;
308
309 /* check version... */
310 memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16));
311
312 val16 = le16_to_cpu(le_tmp);
313 if (val16 != 0x0001)
314 goto check_next_ie;
315 *wpa_ie_len = *(pbuf + 1);
316 return pbuf;
317 } else {
318 *wpa_ie_len = 0;
319 return NULL;
320 }
321
322check_next_ie:
323 limit_new = limit - (pbuf - pie) - 2 - len;
324 if (limit_new <= 0)
325 break;
326 pbuf += (2 + len);
327 }
328 *wpa_ie_len = 0;
329 return NULL;
330}
331
332unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
333{
334
335 return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit);
336}
337
338int rtw_get_wpa_cipher_suite(u8 *s)
339{
05c9bc1f 340 if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN))
06a05884 341 return WPA_CIPHER_NONE;
05c9bc1f 342 if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN))
06a05884 343 return WPA_CIPHER_WEP40;
05c9bc1f 344 if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN))
06a05884 345 return WPA_CIPHER_TKIP;
05c9bc1f 346 if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN))
06a05884 347 return WPA_CIPHER_CCMP;
05c9bc1f 348 if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN))
06a05884
LF
349 return WPA_CIPHER_WEP104;
350
351 return 0;
352}
353
354int rtw_get_wpa2_cipher_suite(u8 *s)
355{
05c9bc1f 356 if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN))
06a05884 357 return WPA_CIPHER_NONE;
05c9bc1f 358 if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN))
06a05884 359 return WPA_CIPHER_WEP40;
05c9bc1f 360 if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN))
06a05884 361 return WPA_CIPHER_TKIP;
05c9bc1f 362 if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN))
06a05884 363 return WPA_CIPHER_CCMP;
05c9bc1f 364 if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN))
06a05884
LF
365 return WPA_CIPHER_WEP104;
366
367 return 0;
368}
369
370
371int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
372{
373 int i, ret = _SUCCESS;
374 int left, count;
375 u8 *pos;
376 u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
377
378 if (wpa_ie_len <= 0) {
379 /* No WPA IE - fail silently */
380 return _FAIL;
381 }
382
383
7a158635
KK
384 if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) ||
385 (memcmp(wpa_ie + 2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN)))
06a05884
LF
386 return _FAIL;
387
388 pos = wpa_ie;
389
390 pos += 8;
391 left = wpa_ie_len - 8;
392
393
394 /* group_cipher */
395 if (left >= WPA_SELECTOR_LEN) {
396 *group_cipher = rtw_get_wpa_cipher_suite(pos);
397 pos += WPA_SELECTOR_LEN;
398 left -= WPA_SELECTOR_LEN;
399 } else if (left > 0) {
400 RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
401 return _FAIL;
402 }
403
404 /* pairwise_cipher */
405 if (left >= 2) {
4b49a5b3 406 count = get_unaligned_le16(pos);
06a05884
LF
407 pos += 2;
408 left -= 2;
409
410 if (count == 0 || left < count * WPA_SELECTOR_LEN) {
411 RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), "
412 "count %u left %u", __func__, count, left));
413 return _FAIL;
414 }
415
416 for (i = 0; i < count; i++) {
417 *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
418
419 pos += WPA_SELECTOR_LEN;
420 left -= WPA_SELECTOR_LEN;
421 }
422 } else if (left == 1) {
423 RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__));
424 return _FAIL;
425 }
426
427 if (is_8021x) {
428 if (left >= 6) {
429 pos += 2;
05c9bc1f 430 if (!memcmp(pos, SUITE_1X, 4)) {
06a05884
LF
431 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__));
432 *is_8021x = 1;
433 }
434 }
435 }
436
437 return ret;
438}
439
440int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
441{
442 int i, ret = _SUCCESS;
443 int left, count;
444 u8 *pos;
445 u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
446
447 if (rsn_ie_len <= 0) {
448 /* No RSN IE - fail silently */
449 return _FAIL;
450 }
451
452
7a158635 453 if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2)))
06a05884
LF
454 return _FAIL;
455
456 pos = rsn_ie;
457 pos += 4;
458 left = rsn_ie_len - 4;
459
460 /* group_cipher */
461 if (left >= RSN_SELECTOR_LEN) {
462 *group_cipher = rtw_get_wpa2_cipher_suite(pos);
463
464 pos += RSN_SELECTOR_LEN;
465 left -= RSN_SELECTOR_LEN;
466
467 } else if (left > 0) {
468 RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
469 return _FAIL;
470 }
471
472 /* pairwise_cipher */
473 if (left >= 2) {
4b49a5b3 474 count = get_unaligned_le16(pos);
06a05884
LF
475 pos += 2;
476 left -= 2;
477
478 if (count == 0 || left < count * RSN_SELECTOR_LEN) {
479 RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), "
480 "count %u left %u", __func__, count, left));
481 return _FAIL;
482 }
483
484 for (i = 0; i < count; i++) {
485 *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
486
487 pos += RSN_SELECTOR_LEN;
488 left -= RSN_SELECTOR_LEN;
489 }
490
491 } else if (left == 1) {
492 RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__));
493
494 return _FAIL;
495 }
496
497 if (is_8021x) {
498 if (left >= 6) {
499 pos += 2;
05c9bc1f 500 if (!memcmp(pos, SUITE_1X, 4)) {
06a05884
LF
501 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__));
502 *is_8021x = 1;
503 }
504 }
505 }
506 return ret;
507}
508
509int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
510{
511 u8 authmode, sec_idx, i;
512 u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
513 uint cnt;
514
06a05884
LF
515
516 /* Search required WPA or WPA2 IE and copy to sec_ie[] */
517
adb3d770 518 cnt = _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_;
06a05884
LF
519
520 sec_idx = 0;
521
522 while (cnt < in_len) {
523 authmode = in_ie[cnt];
524
7a158635 525 if ((authmode == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) {
06a05884
LF
526 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
527 ("\n rtw_get_wpa_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
7a158635 528 sec_idx, in_ie[cnt + 1] + 2));
06a05884
LF
529
530 if (wpa_ie) {
7a158635 531 memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
06a05884 532
7a158635 533 for (i = 0; i < (in_ie[cnt + 1] + 2); i += 8) {
06a05884
LF
534 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
535 ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
7a158635
KK
536 wpa_ie[i], wpa_ie[i + 1], wpa_ie[i + 2], wpa_ie[i + 3], wpa_ie[i + 4],
537 wpa_ie[i + 5], wpa_ie[i + 6], wpa_ie[i + 7]));
06a05884
LF
538 }
539 }
540
7a158635
KK
541 *wpa_len = in_ie[cnt + 1] + 2;
542 cnt += in_ie[cnt + 1] + 2; /* get next */
06a05884
LF
543 } else {
544 if (authmode == _WPA2_IE_ID_) {
545 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
546 ("\n get_rsn_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
7a158635 547 sec_idx, in_ie[cnt + 1] + 2));
06a05884
LF
548
549 if (rsn_ie) {
7a158635 550 memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
06a05884 551
7a158635 552 for (i = 0; i < (in_ie[cnt + 1] + 2); i += 8) {
06a05884
LF
553 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
554 ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
7a158635
KK
555 rsn_ie[i], rsn_ie[i + 1], rsn_ie[i + 2], rsn_ie[i + 3], rsn_ie[i + 4],
556 rsn_ie[i + 5], rsn_ie[i + 6], rsn_ie[i + 7]));
06a05884
LF
557 }
558 }
559
7a158635
KK
560 *rsn_len = in_ie[cnt + 1] + 2;
561 cnt += in_ie[cnt + 1] + 2; /* get next */
06a05884 562 } else {
7a158635 563 cnt += in_ie[cnt + 1] + 2; /* get next */
06a05884
LF
564 }
565 }
566 }
567
06a05884
LF
568
569 return *rsn_len + *wpa_len;
570}
571
572u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
573{
574 u8 match = false;
575 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
576
577 if (ie_ptr == NULL)
578 return match;
579
580 eid = ie_ptr[0];
581
f42f52aa 582 if ((eid == _WPA_IE_ID_) && (!memcmp(&ie_ptr[2], wps_oui, 4))) {
7a158635 583 *wps_ielen = ie_ptr[1] + 2;
06a05884
LF
584 match = true;
585 }
586 return match;
587}
588
589/**
590 * rtw_get_wps_ie - Search WPS IE from a series of IEs
591 * @in_ie: Address of IEs to search
592 * @in_len: Length limit from in_ie
593 * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
594 * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
595 *
596 * Returns: The address of the WPS IE found, or NULL
597 */
598u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
599{
600 uint cnt;
601 u8 *wpsie_ptr = NULL;
602 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
603
604 if (wps_ielen)
605 *wps_ielen = 0;
606
607 if (!in_ie || in_len <= 0)
608 return wpsie_ptr;
609
610 cnt = 0;
611
612 while (cnt < in_len) {
613 eid = in_ie[cnt];
614
7a158635 615 if ((eid == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
06a05884
LF
616 wpsie_ptr = &in_ie[cnt];
617
618 if (wps_ie)
7a158635 619 memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
06a05884
LF
620
621 if (wps_ielen)
7a158635 622 *wps_ielen = in_ie[cnt + 1] + 2;
06a05884 623
7a158635 624 cnt += in_ie[cnt + 1] + 2;
06a05884
LF
625
626 break;
627 } else {
7a158635 628 cnt += in_ie[cnt + 1] + 2; /* goto next */
06a05884
LF
629 }
630 }
631 return wpsie_ptr;
632}
633
634/**
635 * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE
636 * @wps_ie: Address of WPS IE to search
637 * @wps_ielen: Length limit from wps_ie
638 * @target_attr_id: The attribute ID of WPS attribute to search
639 * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr
640 * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute
641 *
642 * Returns: the address of the specific WPS attribute found, or NULL
643 */
4c0dbe0a 644u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_attr, u32 *len_attr)
06a05884
LF
645{
646 u8 *attr_ptr = NULL;
647 u8 *target_attr_ptr = NULL;
648 u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04};
649
650 if (len_attr)
651 *len_attr = 0;
652
653 if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) ||
4c0dbe0a 654 (memcmp(wps_ie + 2, wps_oui, 4)))
06a05884
LF
655 return attr_ptr;
656
657 /* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */
658 attr_ptr = wps_ie + 6; /* goto first attr */
659
660 while (attr_ptr - wps_ie < wps_ielen) {
661 /* 4 = 2(Attribute ID) + 2(Length) */
27c8aac7 662 u16 attr_id = get_unaligned_be16(attr_ptr);
663 u16 attr_data_len = get_unaligned_be16(attr_ptr + 2);
06a05884
LF
664 u16 attr_len = attr_data_len + 4;
665
666 if (attr_id == target_attr_id) {
667 target_attr_ptr = attr_ptr;
668 if (buf_attr)
669 memcpy(buf_attr, attr_ptr, attr_len);
670 if (len_attr)
671 *len_attr = attr_len;
672 break;
673 } else {
674 attr_ptr += attr_len; /* goto next */
675 }
676 }
677 return target_attr_ptr;
678}
679
680/**
681 * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE
682 * @wps_ie: Address of WPS IE to search
683 * @wps_ielen: Length limit from wps_ie
684 * @target_attr_id: The attribute ID of WPS attribute to search
685 * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content
686 * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content
687 *
688 * Returns: the address of the specific WPS attribute content found, or NULL
689 */
4c0dbe0a 690u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_content, uint *len_content)
06a05884
LF
691{
692 u8 *attr_ptr;
693 u32 attr_len;
694
695 if (len_content)
696 *len_content = 0;
697
698 attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len);
699
700 if (attr_ptr && attr_len) {
701 if (buf_content)
7a158635 702 memcpy(buf_content, attr_ptr + 4, attr_len - 4);
06a05884
LF
703
704 if (len_content)
7a158635 705 *len_content = attr_len - 4;
06a05884 706
7a158635 707 return attr_ptr + 4;
06a05884
LF
708 }
709
710 return NULL;
711}
712
713static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
714 struct rtw_ieee802_11_elems *elems,
715 int show_errors)
716{
717 unsigned int oui;
718
719 /* first 3 bytes in vendor specific information element are the IEEE
720 * OUI of the vendor. The following byte is used a vendor specific
721 * sub-type. */
722 if (elen < 4) {
723 if (show_errors) {
724 DBG_88E("short vendor specific information element ignored (len=%lu)\n",
7be921a2 725 (unsigned long)elen);
06a05884
LF
726 }
727 return -1;
728 }
729
730 oui = RTW_GET_BE24(pos);
731 switch (oui) {
732 case OUI_MICROSOFT:
733 /* Microsoft/Wi-Fi information elements are further typed and
734 * subtyped */
735 switch (pos[3]) {
736 case 1:
737 /* Microsoft OUI (00:50:F2) with OUI Type 1:
738 * real WPA information element */
739 elems->wpa_ie = pos;
740 elems->wpa_ie_len = elen;
741 break;
742 case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
743 if (elen < 5) {
744 DBG_88E("short WME information element ignored (len=%lu)\n",
7be921a2 745 (unsigned long)elen);
06a05884
LF
746 return -1;
747 }
748 switch (pos[4]) {
749 case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
750 case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
751 elems->wme = pos;
752 elems->wme_len = elen;
753 break;
754 case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
755 elems->wme_tspec = pos;
756 elems->wme_tspec_len = elen;
757 break;
758 default:
759 DBG_88E("unknown WME information element ignored (subtype=%d len=%lu)\n",
7be921a2 760 pos[4], (unsigned long)elen);
06a05884
LF
761 return -1;
762 }
763 break;
764 case 4:
765 /* Wi-Fi Protected Setup (WPS) IE */
766 elems->wps_ie = pos;
767 elems->wps_ie_len = elen;
768 break;
769 default:
770 DBG_88E("Unknown Microsoft information element ignored (type=%d len=%lu)\n",
7be921a2 771 pos[3], (unsigned long)elen);
06a05884
LF
772 return -1;
773 }
774 break;
775
776 case OUI_BROADCOM:
777 switch (pos[3]) {
778 case VENDOR_HT_CAPAB_OUI_TYPE:
779 elems->vendor_ht_cap = pos;
780 elems->vendor_ht_cap_len = elen;
781 break;
782 default:
783 DBG_88E("Unknown Broadcom information element ignored (type=%d len=%lu)\n",
7be921a2 784 pos[3], (unsigned long)elen);
06a05884
LF
785 return -1;
786 }
787 break;
788 default:
a67080ee
AS
789 DBG_88E("unknown vendor specific information element ignored (vendor OUI %3phC len=%lu)\n",
790 pos, (unsigned long)elen);
06a05884
LF
791 return -1;
792 }
793 return 0;
794}
795
796/**
797 * ieee802_11_parse_elems - Parse information elements in management frames
798 * @start: Pointer to the start of IEs
799 * @len: Length of IE buffer in octets
800 * @elems: Data structure for parsed elements
801 * @show_errors: Whether to show parsing errors in debug log
802 * Returns: Parsing result
803 */
804enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
805 struct rtw_ieee802_11_elems *elems,
806 int show_errors)
807{
808 uint left = len;
809 u8 *pos = start;
810 int unknown = 0;
811
1ce39848 812 memset(elems, 0, sizeof(*elems));
06a05884
LF
813
814 while (left >= 2) {
815 u8 id, elen;
816
817 id = *pos++;
818 elen = *pos++;
819 left -= 2;
820
821 if (elen > left) {
822 if (show_errors) {
823 DBG_88E("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n",
7be921a2 824 id, elen, (unsigned long)left);
06a05884
LF
825 }
826 return ParseFailed;
827 }
828
829 switch (id) {
830 case WLAN_EID_SSID:
831 elems->ssid = pos;
832 elems->ssid_len = elen;
833 break;
834 case WLAN_EID_SUPP_RATES:
835 elems->supp_rates = pos;
836 elems->supp_rates_len = elen;
837 break;
838 case WLAN_EID_FH_PARAMS:
839 elems->fh_params = pos;
840 elems->fh_params_len = elen;
841 break;
842 case WLAN_EID_DS_PARAMS:
843 elems->ds_params = pos;
844 elems->ds_params_len = elen;
845 break;
846 case WLAN_EID_CF_PARAMS:
847 elems->cf_params = pos;
848 elems->cf_params_len = elen;
849 break;
850 case WLAN_EID_TIM:
851 elems->tim = pos;
852 elems->tim_len = elen;
853 break;
854 case WLAN_EID_IBSS_PARAMS:
855 elems->ibss_params = pos;
856 elems->ibss_params_len = elen;
857 break;
858 case WLAN_EID_CHALLENGE:
859 elems->challenge = pos;
860 elems->challenge_len = elen;
861 break;
862 case WLAN_EID_ERP_INFO:
863 elems->erp_info = pos;
864 elems->erp_info_len = elen;
865 break;
866 case WLAN_EID_EXT_SUPP_RATES:
867 elems->ext_supp_rates = pos;
868 elems->ext_supp_rates_len = elen;
869 break;
870 case WLAN_EID_VENDOR_SPECIFIC:
871 if (rtw_ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors))
872 unknown++;
873 break;
874 case WLAN_EID_RSN:
875 elems->rsn_ie = pos;
876 elems->rsn_ie_len = elen;
877 break;
878 case WLAN_EID_PWR_CAPABILITY:
879 elems->power_cap = pos;
880 elems->power_cap_len = elen;
881 break;
882 case WLAN_EID_SUPPORTED_CHANNELS:
883 elems->supp_channels = pos;
884 elems->supp_channels_len = elen;
885 break;
886 case WLAN_EID_MOBILITY_DOMAIN:
887 elems->mdie = pos;
888 elems->mdie_len = elen;
889 break;
890 case WLAN_EID_FAST_BSS_TRANSITION:
891 elems->ftie = pos;
892 elems->ftie_len = elen;
893 break;
894 case WLAN_EID_TIMEOUT_INTERVAL:
895 elems->timeout_int = pos;
896 elems->timeout_int_len = elen;
897 break;
35cf0b55 898 case WLAN_EID_HT_CAPABILITY:
06a05884
LF
899 elems->ht_capabilities = pos;
900 elems->ht_capabilities_len = elen;
901 break;
902 case WLAN_EID_HT_OPERATION:
903 elems->ht_operation = pos;
904 elems->ht_operation_len = elen;
905 break;
906 default:
907 unknown++;
908 if (!show_errors)
909 break;
910 DBG_88E("IEEE 802.11 element parse ignored unknown element (id=%d elen=%d)\n",
911 id, elen);
912 break;
913 }
914 left -= elen;
915 pos += elen;
916 }
917 if (left)
918 return ParseFailed;
919 return unknown ? ParseUnknown : ParseOK;
920}
921
06a05884
LF
922void rtw_macaddr_cfg(u8 *mac_addr)
923{
924 u8 mac[ETH_ALEN];
79374daf 925
06a05884
LF
926 if (mac_addr == NULL)
927 return;
928
79374daf
AS
929 if (rtw_initmac && mac_pton(rtw_initmac, mac)) {
930 /* Users specify the mac address */
06a05884 931 memcpy(mac_addr, mac, ETH_ALEN);
79374daf
AS
932 } else {
933 /* Use the mac address stored in the Efuse */
06a05884
LF
934 memcpy(mac, mac_addr, ETH_ALEN);
935 }
936
937 if (((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) &&
938 (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff)) ||
939 ((mac[0] == 0x0) && (mac[1] == 0x0) && (mac[2] == 0x0) &&
940 (mac[3] == 0x0) && (mac[4] == 0x0) && (mac[5] == 0x0))) {
941 mac[0] = 0x00;
942 mac[1] = 0xe0;
943 mac[2] = 0x4c;
944 mac[3] = 0x87;
945 mac[4] = 0x00;
946 mac[5] = 0x00;
08c64f93 947 /* use default mac address */
06a05884
LF
948 memcpy(mac_addr, mac, ETH_ALEN);
949 DBG_88E("MAC Address from efuse error, assign default one !!!\n");
950 }
951
952 DBG_88E("rtw_macaddr_cfg MAC Address = %pM\n", (mac_addr));
953}
954
06a05884
LF
955/* Baron adds to avoid FreeBSD warning */
956int ieee80211_is_empty_essid(const char *essid, int essid_len)
957{
958 /* Single white space is for Linksys APs */
959 if (essid_len == 1 && essid[0] == ' ')
960 return 1;
961
962 /* Otherwise, if the entire essid is 0, we assume it is hidden */
963 while (essid_len) {
964 essid_len--;
965 if (essid[essid_len] != '\0')
966 return 0;
967 }
968
969 return 1;
970}
971
972int ieee80211_get_hdrlen(u16 fc)
973{
974 int hdrlen = 24;
975
976 switch (WLAN_FC_GET_TYPE(fc)) {
977 case RTW_IEEE80211_FTYPE_DATA:
978 if (fc & RTW_IEEE80211_STYPE_QOS_DATA)
979 hdrlen += 2;
980 if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS))
981 hdrlen += 6; /* Addr4 */
982 break;
983 case RTW_IEEE80211_FTYPE_CTL:
984 switch (WLAN_FC_GET_STYPE(fc)) {
985 case RTW_IEEE80211_STYPE_CTS:
986 case RTW_IEEE80211_STYPE_ACK:
987 hdrlen = 10;
988 break;
989 default:
990 hdrlen = 16;
991 break;
992 }
993 break;
994 }
995
996 return hdrlen;
997}
998
999static int rtw_get_cipher_info(struct wlan_network *pnetwork)
1000{
1001 u32 wpa_ielen;
1002 unsigned char *pbuf;
1003 int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
1004 int ret = _FAIL;
7a158635 1005 pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
06a05884
LF
1006
1007 if (pbuf && (wpa_ielen > 0)) {
1008 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen));
7a158635 1009 if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
06a05884
LF
1010 pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
1011 pnetwork->BcnInfo.group_cipher = group_cipher;
1012 pnetwork->BcnInfo.is_8021x = is8021x;
1013 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d",
1014 __func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x));
1015 ret = _SUCCESS;
1016 }
1017 } else {
7a158635 1018 pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
06a05884
LF
1019
1020 if (pbuf && (wpa_ielen > 0)) {
1021 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n"));
7a158635 1022 if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
06a05884
LF
1023 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE OK!!!\n"));
1024 pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
1025 pnetwork->BcnInfo.group_cipher = group_cipher;
1026 pnetwork->BcnInfo.is_8021x = is8021x;
1027 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d,"
1028 "pnetwork->group_cipher is %d, is_8021x is %d", __func__, pnetwork->BcnInfo.pairwise_cipher,
1029 pnetwork->BcnInfo.group_cipher, pnetwork->BcnInfo.is_8021x));
1030 ret = _SUCCESS;
1031 }
1032 }
1033 }
1034
1035 return ret;
1036}
1037
1038void rtw_get_bcn_info(struct wlan_network *pnetwork)
1039{
1040 unsigned short cap = 0;
1041 u8 bencrypt = 0;
1042 __le16 le_tmp;
1043 u16 wpa_len = 0, rsn_len = 0;
1044 struct HT_info_element *pht_info = NULL;
06a05884
LF
1045 unsigned int len;
1046 unsigned char *p;
1047
1048 memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
1049 cap = le16_to_cpu(le_tmp);
1050 if (cap & WLAN_CAPABILITY_PRIVACY) {
1051 bencrypt = 1;
1052 pnetwork->network.Privacy = 1;
1053 } else {
1054 pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
1055 }
4c0dbe0a 1056 rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len);
06a05884
LF
1057 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
1058 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
1059 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
1060 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
1061
1062 if (rsn_len > 0) {
1063 pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
1064 } else if (wpa_len > 0) {
1065 pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA;
1066 } else {
1067 if (bencrypt)
1068 pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
1069 }
1070 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
1071 pnetwork->BcnInfo.encryp_protocol));
1072 RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
1073 pnetwork->BcnInfo.encryp_protocol));
1074 rtw_get_cipher_info(pnetwork);
1075
1076 /* get bwmode and ch_offset */
1077 /* parsing HT_CAP_IE */
1078 p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
1079 if (p && len > 0) {
c7873d8b
IS
1080 struct ieee80211_ht_cap *ht_cap =
1081 (struct ieee80211_ht_cap *)(p + 2);
1082
1083 pnetwork->BcnInfo.ht_cap_info = le16_to_cpu(ht_cap->cap_info);
06a05884 1084 } else {
c7873d8b 1085 pnetwork->BcnInfo.ht_cap_info = 0;
06a05884
LF
1086 }
1087 /* parsing HT_INFO_IE */
1088 p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
1089 if (p && len > 0) {
1090 pht_info = (struct HT_info_element *)(p + 2);
1091 pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0];
1092 } else {
1093 pnetwork->BcnInfo.ht_info_infos_0 = 0;
1094 }
1095}
1096
1097/* show MCS rate, unit: 100Kbps */
1098u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char *MCS_rate)
1099{
1100 u16 max_rate = 0;
1101
1102 if (rf_type == RF_1T1R) {
1103 if (MCS_rate[0] & BIT(7))
1104 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
1105 else if (MCS_rate[0] & BIT(6))
1106 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
1107 else if (MCS_rate[0] & BIT(5))
1108 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
1109 else if (MCS_rate[0] & BIT(4))
1110 max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
1111 else if (MCS_rate[0] & BIT(3))
1112 max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
1113 else if (MCS_rate[0] & BIT(2))
1114 max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
1115 else if (MCS_rate[0] & BIT(1))
1116 max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
1117 else if (MCS_rate[0] & BIT(0))
1118 max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
1119 } else {
1120 if (MCS_rate[1]) {
1121 if (MCS_rate[1] & BIT(7))
1122 max_rate = (bw_40MHz) ? ((short_GI_40) ? 3000 : 2700) : ((short_GI_20) ? 1444 : 1300);
1123 else if (MCS_rate[1] & BIT(6))
1124 max_rate = (bw_40MHz) ? ((short_GI_40) ? 2700 : 2430) : ((short_GI_20) ? 1300 : 1170);
1125 else if (MCS_rate[1] & BIT(5))
1126 max_rate = (bw_40MHz) ? ((short_GI_40) ? 2400 : 2160) : ((short_GI_20) ? 1156 : 1040);
1127 else if (MCS_rate[1] & BIT(4))
1128 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1800 : 1620) : ((short_GI_20) ? 867 : 780);
1129 else if (MCS_rate[1] & BIT(3))
1130 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
1131 else if (MCS_rate[1] & BIT(2))
1132 max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
1133 else if (MCS_rate[1] & BIT(1))
1134 max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
1135 else if (MCS_rate[1] & BIT(0))
1136 max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
1137 } else {
1138 if (MCS_rate[0] & BIT(7))
1139 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
1140 else if (MCS_rate[0] & BIT(6))
1141 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
1142 else if (MCS_rate[0] & BIT(5))
1143 max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
1144 else if (MCS_rate[0] & BIT(4))
1145 max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
1146 else if (MCS_rate[0] & BIT(3))
1147 max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
1148 else if (MCS_rate[0] & BIT(2))
1149 max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
1150 else if (MCS_rate[0] & BIT(1))
1151 max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
1152 else if (MCS_rate[0] & BIT(0))
1153 max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
1154 }
1155 }
1156 return max_rate;
1157}
This page took 0.466441 seconds and 5 git commands to generate.