• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *
14  ******************************************************************************/
15 #define _IEEE80211_C
16 
17 #include <linux/ieee80211.h>
18 
19 #include <drv_types.h>
20 #include <osdep_intf.h>
21 #include <ieee80211.h>
22 #include <wifi.h>
23 #include <osdep_service.h>
24 #include <wlan_bssdef.h>
25 
26 u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
27 u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
28 u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
29 u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
30 u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
31 u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
32 u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
33 u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
34 u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
35 u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
36 
37 u16 RSN_VERSION_BSD = 1;
38 u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
39 u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
40 u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
41 u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
42 u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
43 u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
44 u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
45 u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
46 /*  */
47 /*  for adhoc-master to generate ie and provide supported-rate to fw */
48 /*  */
49 
50 static 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 
57 static 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 
rtw_get_bit_value_from_ieee_value(u8 val)69 int 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 
rtw_is_cckrates_included(u8 * rate)84 uint	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 
rtw_is_cckratesonly_included(u8 * rate)97 uint	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 
rtw_check_network_type(unsigned char * rate,int ratelen,int channel)111 int 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 
rtw_set_fixed_ie(void * pbuf,unsigned int len,void * source,unsigned int * frlen)128 u8 *rtw_set_fixed_ie(void *pbuf, unsigned int len, void *source,
129 		     unsigned int *frlen)
130 {
131 	memcpy(pbuf, source, len);
132 	*frlen = *frlen + len;
133 	return ((u8 *)pbuf) + len;
134 }
135 
136 /*  rtw_set_ie will update frame length */
rtw_set_ie(u8 * pbuf,int index,uint len,u8 * source,uint * frlen)137 u8 *rtw_set_ie
138 (
139 	u8 *pbuf,
140 	int index,
141 	uint len,
142 	u8 *source,
143 	uint *frlen /* frame length */
144 )
145 {
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 
155 	return pbuf + len + 2;
156 }
157 
158 /*----------------------------------------------------------------------------
159 index: the information element id index, limit is the limit for search
160 -----------------------------------------------------------------------------*/
rtw_get_ie(u8 * pbuf,int index,int * len,int limit)161 u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit)
162 {
163 	int tmp, i;
164 	u8 *p;
165 	if (limit < 1)
166 		return NULL;
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 	}
183 	return NULL;
184 }
185 
rtw_set_supported_rate(u8 * SupportedRates,uint mode)186 void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
187 {
188 
189 	memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
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 	}
209 }
210 
rtw_get_rateset_len(u8 * rateset)211 uint	rtw_get_rateset_len(u8	*rateset)
212 {
213 	uint i = 0;
214 	while (1) {
215 		if ((rateset[i]) == 0)
216 			break;
217 		if (i > 12)
218 			break;
219 		i++;
220 	}
221 	return i;
222 }
223 
rtw_generate_ie(struct registry_priv * pregistrypriv)224 int 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 
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);
288 
289 	return sz;
290 }
291 
rtw_get_wpa_ie(unsigned char * pie,int * wpa_ie_len,int limit)292 unsigned 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... */
306 			if (!memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)) == false)
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 
322 check_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 
rtw_get_wpa2_ie(unsigned char * pie,int * rsn_ie_len,int limit)332 unsigned 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 
rtw_get_wpa_cipher_suite(u8 * s)338 int rtw_get_wpa_cipher_suite(u8 *s)
339 {
340 	if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN))
341 		return WPA_CIPHER_NONE;
342 	if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN))
343 		return WPA_CIPHER_WEP40;
344 	if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN))
345 		return WPA_CIPHER_TKIP;
346 	if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN))
347 		return WPA_CIPHER_CCMP;
348 	if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN))
349 		return WPA_CIPHER_WEP104;
350 
351 	return 0;
352 }
353 
rtw_get_wpa2_cipher_suite(u8 * s)354 int rtw_get_wpa2_cipher_suite(u8 *s)
355 {
356 	if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN))
357 		return WPA_CIPHER_NONE;
358 	if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN))
359 		return WPA_CIPHER_WEP40;
360 	if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN))
361 		return WPA_CIPHER_TKIP;
362 	if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN))
363 		return WPA_CIPHER_CCMP;
364 	if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN))
365 		return WPA_CIPHER_WEP104;
366 
367 	return 0;
368 }
369 
370 
rtw_parse_wpa_ie(u8 * wpa_ie,int wpa_ie_len,int * group_cipher,int * pairwise_cipher,int * is_8021x)371 int 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 
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)))
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) {
406 		count = get_unaligned_le16(pos);
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;
430 			if (!memcmp(pos, SUITE_1X, 4)) {
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 
rtw_parse_wpa2_ie(u8 * rsn_ie,int rsn_ie_len,int * group_cipher,int * pairwise_cipher,int * is_8021x)440 int 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 
453 	if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2)))
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) {
474 		count = get_unaligned_le16(pos);
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;
500 			if (!memcmp(pos, SUITE_1X, 4)) {
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 
rtw_get_sec_ie(u8 * in_ie,uint in_len,u8 * rsn_ie,u16 * rsn_len,u8 * wpa_ie,u16 * wpa_len)509 int 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 
515 
516 	/* Search required WPA or WPA2 IE and copy to sec_ie[] */
517 
518 	cnt = _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_;
519 
520 	sec_idx = 0;
521 
522 	while (cnt < in_len) {
523 		authmode = in_ie[cnt];
524 
525 		if ((authmode == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) {
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",
528 					 sec_idx, in_ie[cnt + 1] + 2));
529 
530 				if (wpa_ie) {
531 					memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
532 
533 					for (i = 0; i < (in_ie[cnt + 1] + 2); i += 8) {
534 						RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
535 							 ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
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]));
538 					}
539 				}
540 
541 				*wpa_len = in_ie[cnt + 1] + 2;
542 				cnt += in_ie[cnt + 1] + 2;  /* get next */
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",
547 					 sec_idx, in_ie[cnt + 1] + 2));
548 
549 				if (rsn_ie) {
550 					memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
551 
552 					for (i = 0; i < (in_ie[cnt + 1] + 2); i += 8) {
553 						RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
554 							 ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
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]));
557 						}
558 				}
559 
560 				*rsn_len = in_ie[cnt + 1] + 2;
561 				cnt += in_ie[cnt + 1] + 2;  /* get next */
562 			} else {
563 				cnt += in_ie[cnt + 1] + 2;   /* get next */
564 			}
565 		}
566 	}
567 
568 
569 	return *rsn_len + *wpa_len;
570 }
571 
rtw_is_wps_ie(u8 * ie_ptr,uint * wps_ielen)572 u8 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 
582 	if ((eid == _WPA_IE_ID_) && (!memcmp(&ie_ptr[2], wps_oui, 4))) {
583 		*wps_ielen = ie_ptr[1] + 2;
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  */
rtw_get_wps_ie(u8 * in_ie,uint in_len,u8 * wps_ie,uint * wps_ielen)598 u8 *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 
615 		if ((eid == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
616 			wpsie_ptr = &in_ie[cnt];
617 
618 			if (wps_ie)
619 				memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
620 
621 			if (wps_ielen)
622 				*wps_ielen = in_ie[cnt + 1] + 2;
623 
624 			cnt += in_ie[cnt + 1] + 2;
625 
626 			break;
627 		} else {
628 			cnt += in_ie[cnt + 1] + 2; /* goto next */
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  */
rtw_get_wps_attr(u8 * wps_ie,uint wps_ielen,u16 target_attr_id,u8 * buf_attr,u32 * len_attr)644 u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_attr, u32 *len_attr)
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_) ||
654 	    (memcmp(wps_ie + 2, wps_oui, 4)))
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) */
662 		u16 attr_id = get_unaligned_be16(attr_ptr);
663 		u16 attr_data_len = get_unaligned_be16(attr_ptr + 2);
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  */
rtw_get_wps_attr_content(u8 * wps_ie,uint wps_ielen,u16 target_attr_id,u8 * buf_content,uint * len_content)690 u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_content, uint *len_content)
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)
702 			memcpy(buf_content, attr_ptr + 4, attr_len - 4);
703 
704 		if (len_content)
705 			*len_content = attr_len - 4;
706 
707 		return attr_ptr + 4;
708 	}
709 
710 	return NULL;
711 }
712 
rtw_ieee802_11_parse_vendor_specific(u8 * pos,uint elen,struct rtw_ieee802_11_elems * elems,int show_errors)713 static 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",
725 				(unsigned long)elen);
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",
745 					(unsigned long)elen);
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",
760 					pos[4], (unsigned long)elen);
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",
771 				pos[3], (unsigned long)elen);
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",
784 				pos[3], (unsigned long)elen);
785 			return -1;
786 		}
787 		break;
788 	default:
789 		DBG_88E("unknown vendor specific information element ignored (vendor OUI %3phC len=%lu)\n",
790 			pos, (unsigned long)elen);
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  */
rtw_ieee802_11_parse_elems(u8 * start,uint len,struct rtw_ieee802_11_elems * elems,int show_errors)804 enum 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 
812 	memset(elems, 0, sizeof(*elems));
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",
824 					id, elen, (unsigned long)left);
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;
898 		case WLAN_EID_HT_CAPABILITY:
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 
rtw_macaddr_cfg(u8 * mac_addr)922 void rtw_macaddr_cfg(u8 *mac_addr)
923 {
924 	u8 mac[ETH_ALEN];
925 
926 	if (mac_addr == NULL)
927 		return;
928 
929 	if (rtw_initmac && mac_pton(rtw_initmac, mac)) {
930 		/* Users specify the mac address */
931 		memcpy(mac_addr, mac, ETH_ALEN);
932 	} else {
933 		/* Use the mac address stored in the Efuse */
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;
947 		/*  use default mac address */
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 
955 /* Baron adds to avoid FreeBSD warning */
ieee80211_is_empty_essid(const char * essid,int essid_len)956 int 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 
ieee80211_get_hdrlen(u16 fc)972 int 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 
rtw_get_cipher_info(struct wlan_network * pnetwork)999 static 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;
1005 	pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
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));
1009 		if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
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 {
1018 		pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
1019 
1020 		if (pbuf && (wpa_ielen > 0)) {
1021 			RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n"));
1022 			if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) {
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 
rtw_get_bcn_info(struct wlan_network * pnetwork)1038 void 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;
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 	}
1056 	rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len);
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) {
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);
1084 	} else {
1085 		pnetwork->BcnInfo.ht_cap_info = 0;
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 */
rtw_mcs_rate(u8 rf_type,u8 bw_40MHz,u8 short_GI_20,u8 short_GI_40,unsigned char * MCS_rate)1098 u16 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 }
1158