[go: nahoru, domu]

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