xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rtl8189es/core/rtw_ieee80211.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 #ifdef CONFIG_PLATFORM_INTEL_BYT
23 #include <linux/fs.h>
24 #endif
25 #include <drv_types.h>
26 
27 
28 u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
29 u16 RTW_WPA_VERSION = 1;
30 u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
31 u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
32 u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
33 u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
34 u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
35 u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
36 u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
37 u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
38 u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
39 
40 u16 RSN_VERSION_BSD = 1;
41 u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
42 u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
43 u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
44 u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
45 u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
46 u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
47 u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
48 u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
49 //-----------------------------------------------------------
50 // for adhoc-master to generate ie and provide supported-rate to fw
51 //-----------------------------------------------------------
52 
53 static u8 	WIFI_CCKRATES[] =
54 {(IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK),
55  (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK),
56  (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK),
57  (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)};
58 
59 static u8 	WIFI_OFDMRATES[] =
60 {(IEEE80211_OFDM_RATE_6MB),
61  (IEEE80211_OFDM_RATE_9MB),
62  (IEEE80211_OFDM_RATE_12MB),
63  (IEEE80211_OFDM_RATE_18MB),
64  (IEEE80211_OFDM_RATE_24MB),
65  IEEE80211_OFDM_RATE_36MB,
66  IEEE80211_OFDM_RATE_48MB,
67  IEEE80211_OFDM_RATE_54MB};
68 
69 
rtw_get_bit_value_from_ieee_value(u8 val)70 int rtw_get_bit_value_from_ieee_value(u8 val)
71 {
72 	unsigned char dot11_rate_table[]={2,4,11,22,12,18,24,36,48,72,96,108,0}; // last element must be zero!!
73 
74 	int i=0;
75 	while(dot11_rate_table[i] != 0) {
76 		if (dot11_rate_table[i] == val)
77 			return BIT(i);
78 		i++;
79 	}
80 	return 0;
81 }
82 
rtw_is_cckrates_included(u8 * rate)83 uint	rtw_is_cckrates_included(u8 *rate)
84 {
85 		u32	i = 0;
86 
87 		while(rate[i]!=0)
88 		{
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 
95 		return _FALSE;
96 }
97 
rtw_is_cckratesonly_included(u8 * rate)98 uint	rtw_is_cckratesonly_included(u8 *rate)
99 {
100 	u32 i = 0;
101 
102 
103 	while(rate[i]!=0)
104 	{
105 			if  (  (((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
106 				(((rate[i]) & 0x7f) != 11)  && (((rate[i]) & 0x7f) != 22) )
107 				return _FALSE;
108 
109 			i++;
110 	}
111 
112 	return _TRUE;
113 
114 }
115 
rtw_check_network_type(unsigned char * rate,int ratelen,int channel)116 int rtw_check_network_type(unsigned char *rate, int ratelen, int channel)
117 {
118 	if (channel > 14)
119 	{
120 		if ((rtw_is_cckrates_included(rate)) == _TRUE)
121 			return WIRELESS_INVALID;
122 		else
123 			return WIRELESS_11A;
124 	}
125 	else  // could be pure B, pure G, or B/G
126 	{
127 		if ((rtw_is_cckratesonly_included(rate)) == _TRUE)
128 			return WIRELESS_11B;
129 		else if((rtw_is_cckrates_included(rate)) == _TRUE)
130 			return 	WIRELESS_11BG;
131 		else
132 			return WIRELESS_11G;
133 	}
134 
135 }
136 
rtw_set_fixed_ie(unsigned char * pbuf,unsigned int len,unsigned char * source,unsigned int * frlen)137 u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source,
138 				unsigned int *frlen)
139 {
140 	_rtw_memcpy((void *)pbuf, (void *)source, len);
141 	*frlen = *frlen + len;
142 	return (pbuf + len);
143 }
144 
145 // rtw_set_ie will update frame length
rtw_set_ie(u8 * pbuf,sint index,uint len,u8 * source,uint * frlen)146 u8 *rtw_set_ie
147 (
148 	u8 *pbuf,
149 	sint index,
150 	uint len,
151 	u8 *source,
152 	uint *frlen //frame length
153 )
154 {
155 	*pbuf = (u8)index;
156 
157 	*(pbuf + 1) = (u8)len;
158 
159 	if (len > 0)
160 		_rtw_memcpy((void *)(pbuf + 2), (void *)source, len);
161 
162 	*frlen = *frlen + (len + 2);
163 
164 	return (pbuf + len + 2);
165 }
166 
rtw_set_ie_ch_switch(u8 * buf,u32 * buf_len,u8 ch_switch_mode,u8 new_ch,u8 ch_switch_cnt)167 inline u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode,
168 	u8 new_ch, u8 ch_switch_cnt)
169 {
170 	u8 ie_data[3];
171 
172 	ie_data[0] = ch_switch_mode;
173 	ie_data[1] = new_ch;
174 	ie_data[2] = ch_switch_cnt;
175 	return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH,  3, ie_data, buf_len);
176 }
177 
secondary_ch_offset_to_hal_ch_offset(u8 ch_offset)178 inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset)
179 {
180 	if (ch_offset == SCN)
181 		return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
182 	else if(ch_offset == SCA)
183 		return HAL_PRIME_CHNL_OFFSET_UPPER;
184 	else if(ch_offset == SCB)
185 		return HAL_PRIME_CHNL_OFFSET_LOWER;
186 
187 	return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
188 }
189 
hal_ch_offset_to_secondary_ch_offset(u8 ch_offset)190 inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset)
191 {
192 	if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
193 		return SCN;
194 	else if(ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
195 		return SCB;
196 	else if(ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
197 		return SCA;
198 
199 	return SCN;
200 }
201 
rtw_set_ie_secondary_ch_offset(u8 * buf,u32 * buf_len,u8 secondary_ch_offset)202 inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset)
203 {
204 	return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET,  1, &secondary_ch_offset, buf_len);
205 }
206 
rtw_set_ie_mesh_ch_switch_parm(u8 * buf,u32 * buf_len,u8 ttl,u8 flags,u16 reason,u16 precedence)207 inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
208 	u8 flags, u16 reason, u16 precedence)
209 {
210 	u8 ie_data[6];
211 
212 	ie_data[0] = ttl;
213 	ie_data[1] = flags;
214 	RTW_PUT_LE16((u8*)&ie_data[2], reason);
215 	RTW_PUT_LE16((u8*)&ie_data[4], precedence);
216 
217 	return rtw_set_ie(buf, 0x118,  6, ie_data, buf_len);
218 }
219 
220 /*----------------------------------------------------------------------------
221 index: the information element id index, limit is the limit for search
222 -----------------------------------------------------------------------------*/
rtw_get_ie(u8 * pbuf,sint index,sint * len,sint limit)223 u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit)
224 {
225 	sint tmp,i;
226 	u8 *p;
227 _func_enter_;
228 	if (limit < 1){
229 		_func_exit_;
230 		return NULL;
231 	}
232 
233 	p = pbuf;
234 	i = 0;
235 	*len = 0;
236 	while(1)
237 	{
238 		if (*p == index)
239 		{
240 			*len = *(p + 1);
241 			return (p);
242 		}
243 		else
244 		{
245 			tmp = *(p + 1);
246 			p += (tmp + 2);
247 			i += (tmp + 2);
248 		}
249 		if (i >= limit)
250 			break;
251 	}
252 _func_exit_;
253 	return NULL;
254 }
255 
256 /**
257  * rtw_get_ie_ex - Search specific IE from a series of IEs
258  * @in_ie: Address of IEs to search
259  * @in_len: Length limit from in_ie
260  * @eid: Element ID to match
261  * @oui: OUI to match
262  * @oui_len: OUI length
263  * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE
264  * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE
265  *
266  * Returns: The address of the specific IE found, or NULL
267  */
rtw_get_ie_ex(u8 * in_ie,uint in_len,u8 eid,u8 * oui,u8 oui_len,u8 * ie,uint * ielen)268 u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen)
269 {
270 	uint cnt;
271 	u8 *target_ie = NULL;
272 
273 
274 	if(ielen)
275 		*ielen = 0;
276 
277 	if(!in_ie || in_len<=0)
278 		return target_ie;
279 
280 	cnt = 0;
281 
282 	while(cnt<in_len)
283 	{
284 		if(eid == in_ie[cnt]
285 			&& ( !oui || _rtw_memcmp(&in_ie[cnt+2], oui, oui_len) == _TRUE))
286 		{
287 			target_ie = &in_ie[cnt];
288 
289 			if(ie)
290 				_rtw_memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2);
291 
292 			if(ielen)
293 				*ielen = in_ie[cnt+1]+2;
294 
295 			break;
296 		}
297 		else
298 		{
299 			cnt+=in_ie[cnt+1]+2; //goto next
300 		}
301 
302 	}
303 
304 	return target_ie;
305 }
306 
307 /**
308  * rtw_ies_remove_ie - Find matching IEs and remove
309  * @ies: Address of IEs to search
310  * @ies_len: Pointer of length of ies, will update to new length
311  * @offset: The offset to start scarch
312  * @eid: Element ID to match
313  * @oui: OUI to match
314  * @oui_len: OUI length
315  *
316  * Returns: _SUCCESS: ies is updated, _FAIL: not updated
317  */
rtw_ies_remove_ie(u8 * ies,uint * ies_len,uint offset,u8 eid,u8 * oui,u8 oui_len)318 int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len)
319 {
320 	int ret = _FAIL;
321 	u8 *target_ie;
322 	u32 target_ielen;
323 	u8 *start;
324 	uint search_len;
325 
326 	if(!ies || !ies_len || *ies_len <= offset)
327 		goto exit;
328 
329 	start = ies + offset;
330 	search_len = *ies_len - offset;
331 
332 	while (1) {
333 		target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen);
334 		if (target_ie && target_ielen) {
335 			u8 buf[MAX_IE_SZ] = {0};
336 			u8 *remain_ies = target_ie + target_ielen;
337 			uint remain_len = search_len - (remain_ies - start);
338 
339 			_rtw_memcpy(buf, remain_ies, remain_len);
340 			_rtw_memcpy(target_ie, buf, remain_len);
341 			*ies_len = *ies_len - target_ielen;
342 			ret = _SUCCESS;
343 
344 			start = target_ie;
345 			search_len = remain_len;
346 		} else {
347 			break;
348 		}
349 	}
350 exit:
351 	return ret;
352 }
353 
rtw_set_supported_rate(u8 * SupportedRates,uint mode)354 void rtw_set_supported_rate(u8* SupportedRates, uint mode)
355 {
356 _func_enter_;
357 
358 	_rtw_memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
359 
360 	switch (mode)
361 	{
362 		case WIRELESS_11B:
363 			_rtw_memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
364 			break;
365 
366 		case WIRELESS_11G:
367 		case WIRELESS_11A:
368 		case WIRELESS_11_5N:
369 		case WIRELESS_11A_5N://Todo: no basic rate for ofdm ?
370 		case WIRELESS_11_5AC:
371 			_rtw_memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
372 			break;
373 
374 		case WIRELESS_11BG:
375 		case WIRELESS_11G_24N:
376 		case WIRELESS_11_24N:
377 		case WIRELESS_11BG_24N:
378 			_rtw_memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
379 			_rtw_memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
380 			break;
381 
382 	}
383 _func_exit_;
384 }
385 
rtw_get_rateset_len(u8 * rateset)386 uint	rtw_get_rateset_len(u8	*rateset)
387 {
388 	uint i = 0;
389 _func_enter_;
390 	while(1)
391 	{
392 		if ((rateset[i]) == 0)
393 			break;
394 
395 		if (i > 12)
396 			break;
397 
398 		i++;
399 	}
400 _func_exit_;
401 	return i;
402 }
403 
rtw_generate_ie(struct registry_priv * pregistrypriv)404 int rtw_generate_ie(struct registry_priv *pregistrypriv)
405 {
406 	u8	wireless_mode;
407 	int 	sz = 0, rateLen;
408 	WLAN_BSSID_EX*	pdev_network = &pregistrypriv->dev_network;
409 	u8*	ie = pdev_network->IEs;
410 
411 _func_enter_;
412 
413 	//timestamp will be inserted by hardware
414 	sz += 8;
415 	ie += sz;
416 
417 	//beacon interval : 2bytes
418 	*(u16*)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);//BCN_INTERVAL;
419 	sz += 2;
420 	ie += 2;
421 
422 	//capability info
423 	*(u16*)ie = 0;
424 
425 	*(u16*)ie |= cpu_to_le16(cap_IBSS);
426 
427 	if(pregistrypriv->preamble == PREAMBLE_SHORT)
428 		*(u16*)ie |= cpu_to_le16(cap_ShortPremble);
429 
430 	if (pdev_network->Privacy)
431 		*(u16*)ie |= cpu_to_le16(cap_Privacy);
432 
433 	sz += 2;
434 	ie += 2;
435 
436 	//SSID
437 	ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz);
438 
439 	//supported rates
440 	if(pregistrypriv->wireless_mode == WIRELESS_11ABGN)
441 	{
442 		if(pdev_network->Configuration.DSConfig > 14)
443 			wireless_mode = WIRELESS_11A_5N;
444 		else
445 			wireless_mode = WIRELESS_11BG_24N;
446 	}
447 	else
448 	{
449 		wireless_mode = pregistrypriv->wireless_mode;
450 	}
451 
452 	rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode) ;
453 
454 	rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
455 
456 	if (rateLen > 8)
457 	{
458 		ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz);
459 		//ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
460 	}
461 	else
462 	{
463 		ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz);
464 	}
465 
466 	//DS parameter set
467 	ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz);
468 
469 
470 	//IBSS Parameter Set
471 
472 	ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz);
473 
474 	if (rateLen > 8)
475 	{
476 		ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
477 	}
478 
479 #ifdef CONFIG_80211N_HT
480 	//HT Cap.
481 	if(((pregistrypriv->wireless_mode&WIRELESS_11_5N)||(pregistrypriv->wireless_mode&WIRELESS_11_24N))
482 		&& (pregistrypriv->ht_enable==_TRUE))
483 	{
484 		//todo:
485 	}
486 #endif //CONFIG_80211N_HT
487 
488 	//pdev_network->IELength =  sz; //update IELength
489 
490 _func_exit_;
491 
492 	//return _SUCCESS;
493 
494 	return sz;
495 
496 }
497 
rtw_regsty_adjust_chbw(struct registry_priv * regsty,u8 req_ch,u8 * req_bw,u8 * req_offset)498 bool rtw_regsty_adjust_chbw(struct registry_priv *regsty, u8 req_ch, u8 *req_bw, u8 *req_offset)
499 {
500 	u8 regsty_allowed_bw;
501 
502 	if (req_ch <= 14)
503 		regsty_allowed_bw = regsty->bw_mode & 0x0F;
504 	else
505 		regsty_allowed_bw = regsty->bw_mode >> 4;
506 
507 	if (regsty_allowed_bw == 2 && *req_bw > CHANNEL_WIDTH_80)
508 		*req_bw = CHANNEL_WIDTH_80;
509 	else if (regsty_allowed_bw == 1 && *req_bw > CHANNEL_WIDTH_40)
510 		*req_bw = CHANNEL_WIDTH_40;
511 	else if (regsty_allowed_bw == 0 && *req_bw > CHANNEL_WIDTH_20) {
512 		*req_bw = CHANNEL_WIDTH_20;
513 		*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
514 	} else
515 		return _FALSE;
516 
517 	return _TRUE;
518 }
519 
rtw_get_wpa_ie(unsigned char * pie,int * wpa_ie_len,int limit)520 unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
521 {
522 	int len;
523 	u16 val16;
524 	unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
525 	u8 *pbuf = pie;
526 	int limit_new = limit;
527 
528 	while(1)
529 	{
530 		pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new);
531 
532 		if (pbuf) {
533 
534 			//check if oui matches...
535 			if (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type)) == _FALSE) {
536 
537 				goto check_next_ie;
538 			}
539 
540 			//check version...
541 			_rtw_memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16));
542 
543 			val16 = le16_to_cpu(val16);
544 			if (val16 != 0x0001)
545 				goto check_next_ie;
546 
547 			*wpa_ie_len = *(pbuf + 1);
548 
549 			return pbuf;
550 
551 		}
552 		else {
553 
554 			*wpa_ie_len = 0;
555 			return NULL;
556 		}
557 
558 check_next_ie:
559 
560 		limit_new = limit - (pbuf - pie) - 2 - len;
561 
562 		if (limit_new <= 0)
563 			break;
564 
565 		pbuf += (2 + len);
566 
567 	}
568 
569 	*wpa_ie_len = 0;
570 
571 	return NULL;
572 
573 }
574 
rtw_get_wpa2_ie(unsigned char * pie,int * rsn_ie_len,int limit)575 unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
576 {
577 
578 	return rtw_get_ie(pie, _WPA2_IE_ID_,rsn_ie_len, limit);
579 
580 }
581 
rtw_get_wpa_cipher_suite(u8 * s)582 int rtw_get_wpa_cipher_suite(u8 *s)
583 {
584 	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == _TRUE)
585 		return WPA_CIPHER_NONE;
586 	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == _TRUE)
587 		return WPA_CIPHER_WEP40;
588 	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == _TRUE)
589 		return WPA_CIPHER_TKIP;
590 	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == _TRUE)
591 		return WPA_CIPHER_CCMP;
592 	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == _TRUE)
593 		return WPA_CIPHER_WEP104;
594 
595 	return 0;
596 }
597 
rtw_get_wpa2_cipher_suite(u8 * s)598 int rtw_get_wpa2_cipher_suite(u8 *s)
599 {
600 	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == _TRUE)
601 		return WPA_CIPHER_NONE;
602 	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == _TRUE)
603 		return WPA_CIPHER_WEP40;
604 	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == _TRUE)
605 		return WPA_CIPHER_TKIP;
606 	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == _TRUE)
607 		return WPA_CIPHER_CCMP;
608 	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == _TRUE)
609 		return WPA_CIPHER_WEP104;
610 
611 	return 0;
612 }
613 
614 
rtw_parse_wpa_ie(u8 * wpa_ie,int wpa_ie_len,int * group_cipher,int * pairwise_cipher,int * is_8021x)615 int rtw_parse_wpa_ie(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
616 {
617 	int i, ret=_SUCCESS;
618 	int left, count;
619 	u8 *pos;
620 	u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
621 
622 	if (wpa_ie_len <= 0) {
623 		/* No WPA IE - fail silently */
624 		return _FAIL;
625 	}
626 
627 
628 	if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) ||
629 	   (_rtw_memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != _TRUE) )
630 	{
631 		return _FAIL;
632 	}
633 
634 	pos = wpa_ie;
635 
636 	pos += 8;
637 	left = wpa_ie_len - 8;
638 
639 
640 	//group_cipher
641 	if (left >= WPA_SELECTOR_LEN) {
642 
643 		*group_cipher = rtw_get_wpa_cipher_suite(pos);
644 
645 		pos += WPA_SELECTOR_LEN;
646 		left -= WPA_SELECTOR_LEN;
647 
648 	}
649 	else if (left > 0)
650 	{
651 		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie length mismatch, %u too much", __FUNCTION__, left));
652 
653 		return _FAIL;
654 	}
655 
656 
657 	//pairwise_cipher
658 	if (left >= 2)
659 	{
660                 //count = le16_to_cpu(*(u16*)pos);
661 		count = RTW_GET_LE16(pos);
662 		pos += 2;
663 		left -= 2;
664 
665 		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
666 			RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie count botch (pairwise), "
667 				   		"count %u left %u", __FUNCTION__, count, left));
668 			return _FAIL;
669 		}
670 
671 		for (i = 0; i < count; i++)
672 		{
673 			*pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
674 
675 			pos += WPA_SELECTOR_LEN;
676 			left -= WPA_SELECTOR_LEN;
677 		}
678 
679 	}
680 	else if (left == 1)
681 	{
682 		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie too short (for key mgmt)",   __FUNCTION__));
683 		return _FAIL;
684 	}
685 
686 	if (is_8021x) {
687 		if (left >= 6) {
688 			pos += 2;
689 			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
690 				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s : there has 802.1x auth\n", __FUNCTION__));
691 				*is_8021x = 1;
692 			}
693 		}
694 	}
695 
696 	return ret;
697 
698 }
699 
rtw_parse_wpa2_ie(u8 * rsn_ie,int rsn_ie_len,int * group_cipher,int * pairwise_cipher,int * is_8021x)700 int rtw_parse_wpa2_ie(u8* rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
701 {
702 	int i, ret=_SUCCESS;
703 	int left, count;
704 	u8 *pos;
705 	u8 SUITE_1X[4] = {0x00,0x0f, 0xac, 0x01};
706 
707 	if (rsn_ie_len <= 0) {
708 		/* No RSN IE - fail silently */
709 		return _FAIL;
710 	}
711 
712 
713 	if ((*rsn_ie!= _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2)))
714 	{
715 		return _FAIL;
716 	}
717 
718 	pos = rsn_ie;
719 	pos += 4;
720 	left = rsn_ie_len - 4;
721 
722 	//group_cipher
723 	if (left >= RSN_SELECTOR_LEN) {
724 
725 		*group_cipher = rtw_get_wpa2_cipher_suite(pos);
726 
727 		pos += RSN_SELECTOR_LEN;
728 		left -= RSN_SELECTOR_LEN;
729 
730 	} else if (left > 0) {
731 		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie length mismatch, %u too much", __FUNCTION__, left));
732 		return _FAIL;
733 	}
734 
735 	//pairwise_cipher
736 	if (left >= 2)
737 	{
738 	        //count = le16_to_cpu(*(u16*)pos);
739 		count = RTW_GET_LE16(pos);
740 		pos += 2;
741 		left -= 2;
742 
743 		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
744 			RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie count botch (pairwise), "
745 				  		 "count %u left %u", __FUNCTION__, count, left));
746 			return _FAIL;
747 		}
748 
749 		for (i = 0; i < count; i++)
750 		{
751 			*pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
752 
753 			pos += RSN_SELECTOR_LEN;
754 			left -= RSN_SELECTOR_LEN;
755 		}
756 
757 	}
758 	else if (left == 1)
759 	{
760 		RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("%s: ie too short (for key mgmt)",  __FUNCTION__));
761 
762 		return _FAIL;
763 	}
764 
765 	if (is_8021x) {
766 		if (left >= 6) {
767 			pos += 2;
768 			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
769 				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s (): there has 802.1x auth\n", __FUNCTION__));
770 				*is_8021x = 1;
771 			}
772 		}
773 	}
774 
775 	return ret;
776 
777 }
778 
779 //#ifdef CONFIG_WAPI_SUPPORT
rtw_get_wapi_ie(u8 * in_ie,uint in_len,u8 * wapi_ie,u16 * wapi_len)780 int rtw_get_wapi_ie(u8 *in_ie,uint in_len,u8 *wapi_ie,u16 *wapi_len)
781 {
782 	int len = 0;
783 	u8 authmode, i;
784 	uint 	cnt;
785 	u8 wapi_oui1[4]={0x0,0x14,0x72,0x01};
786 	u8 wapi_oui2[4]={0x0,0x14,0x72,0x02};
787 
788 _func_enter_;
789 
790 	if(wapi_len)
791 		*wapi_len = 0;
792 
793 	if(!in_ie || in_len<=0)
794 		return len;
795 
796 	cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
797 
798 	while(cnt<in_len)
799 	{
800 		authmode=in_ie[cnt];
801 
802 		//if(authmode==_WAPI_IE_)
803 		if(authmode==_WAPI_IE_ && (_rtw_memcmp(&in_ie[cnt+6], wapi_oui1,4)==_TRUE ||
804 				       	_rtw_memcmp(&in_ie[cnt+6], wapi_oui2,4)==_TRUE))
805 		{
806 			if (wapi_ie) {
807 				_rtw_memcpy(wapi_ie, &in_ie[cnt],in_ie[cnt+1]+2);
808 
809 				for(i=0;i<(in_ie[cnt+1]+2);i=i+8){
810 					RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
811 								wapi_ie[i],wapi_ie[i+1],wapi_ie[i+2],wapi_ie[i+3],wapi_ie[i+4],
812 								wapi_ie[i+5],wapi_ie[i+6],wapi_ie[i+7]));
813 				}
814 			}
815 
816 			if(wapi_len)
817 				*wapi_len=in_ie[cnt+1]+2;
818 
819 			cnt+=in_ie[cnt+1]+2;  //get next
820 		}
821 		else
822 		{
823 			cnt+=in_ie[cnt+1]+2;   //get next
824 		}
825 	}
826 
827 	if(wapi_len)
828 		len = *wapi_len;
829 
830 _func_exit_;
831 
832 	return len;
833 
834 }
835 //#endif
836 
rtw_get_sec_ie(u8 * in_ie,uint in_len,u8 * rsn_ie,u16 * rsn_len,u8 * wpa_ie,u16 * wpa_len)837 int rtw_get_sec_ie(u8 *in_ie,uint in_len,u8 *rsn_ie,u16 *rsn_len,u8 *wpa_ie,u16 *wpa_len)
838 {
839 	u8 authmode, sec_idx, i;
840 	u8 wpa_oui[4]={0x0,0x50,0xf2,0x01};
841 	uint 	cnt;
842 
843 _func_enter_;
844 
845 	//Search required WPA or WPA2 IE and copy to sec_ie[ ]
846 
847 	cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
848 
849 	sec_idx=0;
850 
851 	while(cnt<in_len)
852 	{
853 		authmode=in_ie[cnt];
854 
855 		if((authmode==_WPA_IE_ID_)&&(_rtw_memcmp(&in_ie[cnt+2], &wpa_oui[0],4)==_TRUE))
856 		{
857 				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n rtw_get_wpa_ie: sec_idx=%d in_ie[cnt+1]+2=%d\n",sec_idx,in_ie[cnt+1]+2));
858 
859 				if (wpa_ie) {
860 				_rtw_memcpy(wpa_ie, &in_ie[cnt],in_ie[cnt+1]+2);
861 
862 				for(i=0;i<(in_ie[cnt+1]+2);i=i+8){
863 						RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
864 									wpa_ie[i],wpa_ie[i+1],wpa_ie[i+2],wpa_ie[i+3],wpa_ie[i+4],
865 									wpa_ie[i+5],wpa_ie[i+6],wpa_ie[i+7]));
866 					}
867 				}
868 
869 				*wpa_len=in_ie[cnt+1]+2;
870 				cnt+=in_ie[cnt+1]+2;  //get next
871 		}
872 		else
873 		{
874 			if(authmode==_WPA2_IE_ID_)
875 			{
876 				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n get_rsn_ie: sec_idx=%d in_ie[cnt+1]+2=%d\n",sec_idx,in_ie[cnt+1]+2));
877 
878 				if (rsn_ie) {
879 				_rtw_memcpy(rsn_ie, &in_ie[cnt],in_ie[cnt+1]+2);
880 
881 				for(i=0;i<(in_ie[cnt+1]+2);i=i+8){
882 						RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
883 									rsn_ie[i],rsn_ie[i+1],rsn_ie[i+2],rsn_ie[i+3],rsn_ie[i+4],
884 									rsn_ie[i+5],rsn_ie[i+6],rsn_ie[i+7]));
885 					}
886 				}
887 
888 				*rsn_len=in_ie[cnt+1]+2;
889 				cnt+=in_ie[cnt+1]+2;  //get next
890 			}
891 			else
892 			{
893 				cnt+=in_ie[cnt+1]+2;   //get next
894 			}
895 		}
896 
897 	}
898 
899 _func_exit_;
900 
901 	return (*rsn_len+*wpa_len);
902 
903 }
904 
rtw_is_wps_ie(u8 * ie_ptr,uint * wps_ielen)905 u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
906 {
907 	u8 match = _FALSE;
908 	u8 eid, wps_oui[4]={0x0,0x50,0xf2,0x04};
909 
910 	if(ie_ptr == NULL) return match;
911 
912 	eid = ie_ptr[0];
913 
914 	if((eid==_WPA_IE_ID_)&&(_rtw_memcmp(&ie_ptr[2], wps_oui, 4)==_TRUE))
915 	{
916 		//DBG_8192C("==> found WPS_IE.....\n");
917 		*wps_ielen = ie_ptr[1]+2;
918 		match=_TRUE;
919 	}
920 	return match;
921 }
922 
rtw_get_wps_ie_from_scan_queue(u8 * in_ie,uint in_len,u8 * wps_ie,uint * wps_ielen,u8 frame_type)923 u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, u8 frame_type)
924 {
925 	u8*	wps = NULL;
926 
927 	DBG_871X( "[%s] frame_type = %d\n", __FUNCTION__, frame_type );
928 	switch( frame_type )
929 	{
930 		case 1:
931 		case 3:
932 		{	//	Beacon or Probe Response
933 			wps = rtw_get_wps_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, wps_ie, wps_ielen);
934 			break;
935 		}
936 		case 2:
937 		{	//	Probe Request
938 			wps = rtw_get_wps_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , wps_ie, wps_ielen);
939 			break;
940 		}
941 	}
942 	return wps;
943 }
944 
945 /**
946  * rtw_get_wps_ie - Search WPS IE from a series of IEs
947  * @in_ie: Address of IEs to search
948  * @in_len: Length limit from in_ie
949  * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
950  * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
951  *
952  * Returns: The address of the WPS IE found, or NULL
953  */
rtw_get_wps_ie(u8 * in_ie,uint in_len,u8 * wps_ie,uint * wps_ielen)954 u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
955 {
956 	uint cnt;
957 	u8 *wpsie_ptr = NULL;
958 	u8 eid, wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
959 
960 	if (wps_ielen)
961 		*wps_ielen = 0;
962 
963 	if (!in_ie) {
964 		rtw_warn_on(1);
965 		return wpsie_ptr;
966 	}
967 
968 	if (in_len <= 0)
969 		return wpsie_ptr;
970 
971 	cnt = 0;
972 
973 	while (cnt + 1 + 4 < in_len) {
974 		eid = in_ie[cnt];
975 
976 		if (cnt + 1 + 4 >= MAX_IE_SZ) {
977 			rtw_warn_on(1);
978 			return NULL;
979 		}
980 
981 		if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], wps_oui, 4) == _TRUE) {
982 			wpsie_ptr = in_ie + cnt;
983 
984 			if (wps_ie)
985 				_rtw_memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
986 
987 			if (wps_ielen)
988 				*wps_ielen = in_ie[cnt + 1] + 2;
989 
990 			break;
991 		} else {
992 			cnt += in_ie[cnt + 1] + 2;
993 		}
994 
995 	}
996 
997 	return wpsie_ptr;
998 }
999 
1000 /**
1001  * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE
1002  * @wps_ie: Address of WPS IE to search
1003  * @wps_ielen: Length limit from wps_ie
1004  * @target_attr_id: The attribute ID of WPS attribute to search
1005  * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr
1006  * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute
1007  *
1008  * Returns: the address of the specific WPS attribute found, or NULL
1009  */
rtw_get_wps_attr(u8 * wps_ie,uint wps_ielen,u16 target_attr_id,u8 * buf_attr,u32 * len_attr)1010 u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_attr, u32 *len_attr)
1011 {
1012 	u8 *attr_ptr = NULL;
1013 	u8 * target_attr_ptr = NULL;
1014 	u8 wps_oui[4]={0x00,0x50,0xF2,0x04};
1015 
1016 	if(len_attr)
1017 		*len_attr = 0;
1018 
1019 	if ( ( wps_ie[0] != _VENDOR_SPECIFIC_IE_ ) ||
1020 		( _rtw_memcmp( wps_ie + 2, wps_oui , 4 ) != _TRUE ) )
1021 	{
1022 		return attr_ptr;
1023 	}
1024 
1025 	// 6 = 1(Element ID) + 1(Length) + 4(WPS OUI)
1026 	attr_ptr = wps_ie + 6; //goto first attr
1027 
1028 	while(attr_ptr - wps_ie < wps_ielen)
1029 	{
1030 		// 4 = 2(Attribute ID) + 2(Length)
1031 		u16 attr_id = RTW_GET_BE16(attr_ptr);
1032 		u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2);
1033 		u16 attr_len = attr_data_len + 4;
1034 
1035 		//DBG_871X("%s attr_ptr:%p, id:%u, length:%u\n", __FUNCTION__, attr_ptr, attr_id, attr_data_len);
1036 		if( attr_id == target_attr_id )
1037 		{
1038 			target_attr_ptr = attr_ptr;
1039 
1040 			if(buf_attr)
1041 				_rtw_memcpy(buf_attr, attr_ptr, attr_len);
1042 
1043 			if(len_attr)
1044 				*len_attr = attr_len;
1045 
1046 			break;
1047 		}
1048 		else
1049 		{
1050 			attr_ptr += attr_len; //goto next
1051 		}
1052 
1053 	}
1054 
1055 	return target_attr_ptr;
1056 }
1057 
1058 /**
1059  * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE
1060  * @wps_ie: Address of WPS IE to search
1061  * @wps_ielen: Length limit from wps_ie
1062  * @target_attr_id: The attribute ID of WPS attribute to search
1063  * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content
1064  * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content
1065  *
1066  * Returns: the address of the specific WPS attribute content found, or NULL
1067  */
rtw_get_wps_attr_content(u8 * wps_ie,uint wps_ielen,u16 target_attr_id,u8 * buf_content,uint * len_content)1068 u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_content, uint *len_content)
1069 {
1070 	u8 *attr_ptr;
1071 	u32 attr_len;
1072 
1073 	if(len_content)
1074 		*len_content = 0;
1075 
1076 	attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len);
1077 
1078 	if(attr_ptr && attr_len)
1079 	{
1080 		if(buf_content)
1081 			_rtw_memcpy(buf_content, attr_ptr+4, attr_len-4);
1082 
1083 		if(len_content)
1084 			*len_content = attr_len-4;
1085 
1086 		return attr_ptr+4;
1087 	}
1088 
1089 	return NULL;
1090 }
1091 
rtw_ieee802_11_parse_vendor_specific(u8 * pos,uint elen,struct rtw_ieee802_11_elems * elems,int show_errors)1092 static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
1093 					    struct rtw_ieee802_11_elems *elems,
1094 					    int show_errors)
1095 {
1096 	unsigned int oui;
1097 
1098 	/* first 3 bytes in vendor specific information element are the IEEE
1099 	 * OUI of the vendor. The following byte is used a vendor specific
1100 	 * sub-type. */
1101 	if (elen < 4) {
1102 		if (show_errors) {
1103 			DBG_871X("short vendor specific "
1104 				   "information element ignored (len=%lu)\n",
1105 				   (unsigned long) elen);
1106 		}
1107 		return -1;
1108 	}
1109 
1110 	oui = RTW_GET_BE24(pos);
1111 	switch (oui) {
1112 	case OUI_MICROSOFT:
1113 		/* Microsoft/Wi-Fi information elements are further typed and
1114 		 * subtyped */
1115 		switch (pos[3]) {
1116 		case 1:
1117 			/* Microsoft OUI (00:50:F2) with OUI Type 1:
1118 			 * real WPA information element */
1119 			elems->wpa_ie = pos;
1120 			elems->wpa_ie_len = elen;
1121 			break;
1122 		case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
1123 			if (elen < 5) {
1124 				DBG_871X("short WME "
1125 					   "information element ignored "
1126 					   "(len=%lu)\n",
1127 					   (unsigned long) elen);
1128 				return -1;
1129 			}
1130 			switch (pos[4]) {
1131 			case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
1132 			case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
1133 				elems->wme = pos;
1134 				elems->wme_len = elen;
1135 				break;
1136 			case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
1137 				elems->wme_tspec = pos;
1138 				elems->wme_tspec_len = elen;
1139 				break;
1140 			default:
1141 				DBG_871X_LEVEL(_drv_warning_, "unknown WME "
1142 					   "information element ignored "
1143 					   "(subtype=%d len=%lu)\n",
1144 					   pos[4], (unsigned long) elen);
1145 				return -1;
1146 			}
1147 			break;
1148 		case 4:
1149 			/* Wi-Fi Protected Setup (WPS) IE */
1150 			elems->wps_ie = pos;
1151 			elems->wps_ie_len = elen;
1152 			break;
1153 		default:
1154 			DBG_871X_LEVEL(_drv_warning_, "Unknown Microsoft "
1155 				   "information element ignored "
1156 				   "(type=%d len=%lu)\n",
1157 				   pos[3], (unsigned long) elen);
1158 			return -1;
1159 		}
1160 		break;
1161 
1162 	case OUI_BROADCOM:
1163 		switch (pos[3]) {
1164 		case VENDOR_HT_CAPAB_OUI_TYPE:
1165 			elems->vendor_ht_cap = pos;
1166 			elems->vendor_ht_cap_len = elen;
1167 			break;
1168 		default:
1169 			DBG_871X_LEVEL(_drv_warning_, "Unknown Broadcom "
1170 				   "information element ignored "
1171 				   "(type=%d len=%lu)\n",
1172 				   pos[3], (unsigned long) elen);
1173 			return -1;
1174 		}
1175 		break;
1176 
1177 	default:
1178 		DBG_871X_LEVEL(_drv_warning_, "unknown vendor specific information "
1179 			   "element ignored (vendor OUI %02x:%02x:%02x "
1180 			   "len=%lu)\n",
1181 			   pos[0], pos[1], pos[2], (unsigned long) elen);
1182 		return -1;
1183 	}
1184 
1185 	return 0;
1186 
1187 }
1188 
1189 /**
1190  * ieee802_11_parse_elems - Parse information elements in management frames
1191  * @start: Pointer to the start of IEs
1192  * @len: Length of IE buffer in octets
1193  * @elems: Data structure for parsed elements
1194  * @show_errors: Whether to show parsing errors in debug log
1195  * Returns: Parsing result
1196  */
rtw_ieee802_11_parse_elems(u8 * start,uint len,struct rtw_ieee802_11_elems * elems,int show_errors)1197 ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len,
1198 				struct rtw_ieee802_11_elems *elems,
1199 				int show_errors)
1200 {
1201 	uint left = len;
1202 	u8 *pos = start;
1203 	int unknown = 0;
1204 
1205 	_rtw_memset(elems, 0, sizeof(*elems));
1206 
1207 	while (left >= 2) {
1208 		u8 id, elen;
1209 
1210 		id = *pos++;
1211 		elen = *pos++;
1212 		left -= 2;
1213 
1214 		if (elen > left) {
1215 			if (show_errors) {
1216 				DBG_871X("IEEE 802.11 element "
1217 					   "parse failed (id=%d elen=%d "
1218 					   "left=%lu)\n",
1219 					   id, elen, (unsigned long) left);
1220 			}
1221 			return ParseFailed;
1222 		}
1223 
1224 		switch (id) {
1225 		case WLAN_EID_SSID:
1226 			elems->ssid = pos;
1227 			elems->ssid_len = elen;
1228 			break;
1229 		case WLAN_EID_SUPP_RATES:
1230 			elems->supp_rates = pos;
1231 			elems->supp_rates_len = elen;
1232 			break;
1233 		case WLAN_EID_FH_PARAMS:
1234 			elems->fh_params = pos;
1235 			elems->fh_params_len = elen;
1236 			break;
1237 		case WLAN_EID_DS_PARAMS:
1238 			elems->ds_params = pos;
1239 			elems->ds_params_len = elen;
1240 			break;
1241 		case WLAN_EID_CF_PARAMS:
1242 			elems->cf_params = pos;
1243 			elems->cf_params_len = elen;
1244 			break;
1245 		case WLAN_EID_TIM:
1246 			elems->tim = pos;
1247 			elems->tim_len = elen;
1248 			break;
1249 		case WLAN_EID_IBSS_PARAMS:
1250 			elems->ibss_params = pos;
1251 			elems->ibss_params_len = elen;
1252 			break;
1253 		case WLAN_EID_CHALLENGE:
1254 			elems->challenge = pos;
1255 			elems->challenge_len = elen;
1256 			break;
1257 		case WLAN_EID_ERP_INFO:
1258 			elems->erp_info = pos;
1259 			elems->erp_info_len = elen;
1260 			break;
1261 		case WLAN_EID_EXT_SUPP_RATES:
1262 			elems->ext_supp_rates = pos;
1263 			elems->ext_supp_rates_len = elen;
1264 			break;
1265 		case WLAN_EID_VENDOR_SPECIFIC:
1266 			if (rtw_ieee802_11_parse_vendor_specific(pos, elen,
1267 							     elems,
1268 							     show_errors))
1269 				unknown++;
1270 			break;
1271 		case WLAN_EID_RSN:
1272 			elems->rsn_ie = pos;
1273 			elems->rsn_ie_len = elen;
1274 			break;
1275 		case WLAN_EID_PWR_CAPABILITY:
1276 			elems->power_cap = pos;
1277 			elems->power_cap_len = elen;
1278 			break;
1279 		case WLAN_EID_SUPPORTED_CHANNELS:
1280 			elems->supp_channels = pos;
1281 			elems->supp_channels_len = elen;
1282 			break;
1283 		case WLAN_EID_MOBILITY_DOMAIN:
1284 			elems->mdie = pos;
1285 			elems->mdie_len = elen;
1286 			break;
1287 		case WLAN_EID_FAST_BSS_TRANSITION:
1288 			elems->ftie = pos;
1289 			elems->ftie_len = elen;
1290 			break;
1291 		case WLAN_EID_TIMEOUT_INTERVAL:
1292 			elems->timeout_int = pos;
1293 			elems->timeout_int_len = elen;
1294 			break;
1295 		case WLAN_EID_HT_CAP:
1296 			elems->ht_capabilities = pos;
1297 			elems->ht_capabilities_len = elen;
1298 			break;
1299 		case WLAN_EID_HT_OPERATION:
1300 			elems->ht_operation = pos;
1301 			elems->ht_operation_len = elen;
1302 			break;
1303 		case WLAN_EID_VHT_CAPABILITY:
1304 			elems->vht_capabilities = pos;
1305 			elems->vht_capabilities_len = elen;
1306 			break;
1307 		case WLAN_EID_VHT_OPERATION:
1308 			elems->vht_operation = pos;
1309 			elems->vht_operation_len = elen;
1310 			break;
1311 		case WLAN_EID_VHT_OP_MODE_NOTIFY:
1312 			elems->vht_op_mode_notify = pos;
1313 			elems->vht_op_mode_notify_len = elen;
1314 			break;
1315 		default:
1316 			unknown++;
1317 			if (!show_errors)
1318 				break;
1319 			DBG_871X_LEVEL(_drv_warning_,
1320 				"IEEE 802.11 element parse "
1321 				"ignored unknown element (id=%d elen=%d)\n",
1322 				id, elen);
1323 			break;
1324 		}
1325 
1326 		left -= elen;
1327 		pos += elen;
1328 	}
1329 
1330 	if (left)
1331 		return ParseFailed;
1332 
1333 	return unknown ? ParseUnknown : ParseOK;
1334 
1335 }
1336 
1337 static u8 key_char2num(u8 ch);
key_char2num(u8 ch)1338 static u8 key_char2num(u8 ch)
1339 {
1340     if((ch>='0')&&(ch<='9'))
1341         return ch - '0';
1342     else if ((ch>='a')&&(ch<='f'))
1343         return ch - 'a' + 10;
1344     else if ((ch>='A')&&(ch<='F'))
1345         return ch - 'A' + 10;
1346     else
1347 	 return 0xff;
1348 }
1349 
1350 u8 str_2char2num(u8 hch, u8 lch);
str_2char2num(u8 hch,u8 lch)1351 u8 str_2char2num(u8 hch, u8 lch)
1352 {
1353     return ((key_char2num(hch) * 10 ) + key_char2num(lch));
1354 }
1355 
1356 u8 key_2char2num(u8 hch, u8 lch);
key_2char2num(u8 hch,u8 lch)1357 u8 key_2char2num(u8 hch, u8 lch)
1358 {
1359     return ((key_char2num(hch) << 4) | key_char2num(lch));
1360 }
1361 
1362 void macstr2num(u8 *dst, u8 *src);
macstr2num(u8 * dst,u8 * src)1363 void macstr2num(u8 *dst, u8 *src)
1364 {
1365 	int	jj, kk;
1366 	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
1367 	{
1368 		dst[jj] = key_2char2num(src[kk], src[kk + 1]);
1369 	}
1370 }
1371 
convert_ip_addr(u8 hch,u8 mch,u8 lch)1372 u8 convert_ip_addr(u8 hch, u8 mch, u8 lch)
1373 {
1374     return ((key_char2num(hch) * 100) + (key_char2num(mch) * 10 ) + key_char2num(lch));
1375 }
1376 
1377 #ifdef CONFIG_PLATFORM_INTEL_BYT
1378 #define MAC_ADDRESS_LEN 12
1379 
rtw_get_mac_addr_intel(unsigned char * buf)1380 int rtw_get_mac_addr_intel(unsigned char *buf)
1381 {
1382 	int ret = 0;
1383 	int i;
1384 	struct file *fp = NULL;
1385 	mm_segment_t oldfs;
1386 	unsigned char c_mac[MAC_ADDRESS_LEN];
1387 	char fname[]="/config/wifi/mac.txt";
1388 	int jj,kk;
1389 
1390 	DBG_871X("%s Enter\n", __FUNCTION__);
1391 
1392 	ret = rtw_retrieve_from_file(fname, c_mac, MAC_ADDRESS_LEN);
1393 	if(ret < MAC_ADDRESS_LEN)
1394 	{
1395 		return -1;
1396 	}
1397 
1398 	for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 2 )
1399 	{
1400 		buf[jj] = key_2char2num(c_mac[kk], c_mac[kk+ 1]);
1401 	}
1402 
1403 	DBG_871X("%s: read from file mac address: "MAC_FMT"\n",
1404 		 __FUNCTION__, MAC_ARG(buf));
1405 
1406 	return 0;
1407 }
1408 #endif //CONFIG_PLATFORM_INTEL_BYT
1409 
1410 /*
1411  * Description:
1412  * rtw_check_invalid_mac_address:
1413  * This is only used for checking mac address valid or not.
1414  *
1415  * Input:
1416  * adapter: mac_address pointer.
1417  *
1418  * Output:
1419  * _TRUE: The mac address is invalid.
1420  * _FALSE: The mac address is valid.
1421  *
1422  * Auther: Isaac.Li
1423  */
rtw_check_invalid_mac_address(u8 * mac_addr)1424 u8 rtw_check_invalid_mac_address(u8 *mac_addr)
1425 {
1426 	u8 null_mac_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
1427 	u8 multi_mac_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1428 	u8 res = _FALSE;
1429 
1430 	if (_rtw_memcmp(mac_addr, null_mac_addr, ETH_ALEN)) {
1431 		res = _TRUE;
1432 		goto func_exit;
1433 	}
1434 
1435 	if (_rtw_memcmp(mac_addr, multi_mac_addr, ETH_ALEN)) {
1436 		res = _TRUE;
1437 		goto func_exit;
1438 	}
1439 
1440 	if (mac_addr[0] & BIT0) {
1441 		res = _TRUE;
1442 		goto func_exit;
1443 	}
1444 
1445 	if (mac_addr[0] & BIT1) {
1446 		res = _TRUE;
1447 		goto func_exit;
1448 	}
1449 
1450 func_exit:
1451 	return res;
1452 }
1453 
1454 extern char *rtw_initmac;
1455 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
1456 #include <linux/rfkill-wlan.h>
1457 #else
1458 extern int rk29sdk_wifi_mac_addr(unsigned char *buf);
1459 #endif
1460 /**
1461  * rtw_macaddr_cfg - Decide the mac address used
1462  * @out: buf to store mac address decided
1463  * @hw_mac_addr: mac address from efuse/epprom
1464  */
rtw_macaddr_cfg(u8 * out,const u8 * hw_mac_addr)1465 void rtw_macaddr_cfg(u8 *out, const u8 *hw_mac_addr)
1466 {
1467 #define DEFAULT_RANDOM_MACADDR 1
1468 	u8 mac[ETH_ALEN];
1469 
1470 	if (out == NULL) {
1471 		rtw_warn_on(1);
1472 		return;
1473 	}
1474 
1475 	/* Users specify the mac address */
1476 	if (rtw_initmac) {
1477 		int jj,kk;
1478 
1479 		for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
1480 			mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk + 1]);
1481 
1482 		goto err_chk;
1483 	}
1484 
1485 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
1486 	if (!rockchip_wifi_mac_addr(mac)) {
1487 		printk("=========> get mac address from flash=[%02x:%02x:%02x:%02x:%02x:%02x]\n", mac[0], mac[1],
1488                 mac[2], mac[3], mac[4], mac[5]);
1489 		//_rtw_memcpy(mac_addr, mac, ETH_ALEN);
1490 		goto err_chk;
1491 	}
1492 #else
1493 #ifndef CONFIG_ANDROID_4_2
1494 {
1495 	u8 macbuf[30] = {0};
1496 	if (!rk29sdk_wifi_mac_addr(macbuf)) {
1497 		int jj,kk;
1498 		printk("=========> get mac address from flash %s\n", macbuf);
1499 		for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3 )
1500 		    mac[jj] = key_2char2num(macbuf[kk], macbuf[kk+ 1]);
1501 		goto err_chk;
1502 	}
1503 }
1504 #endif
1505 #endif
1506 
1507 	/* platform specified */
1508 #ifdef CONFIG_PLATFORM_INTEL_BYT
1509 	if (rtw_get_mac_addr_intel(mac) == 0)
1510 		goto err_chk;
1511 #endif
1512 
1513 	/* Use the mac address stored in the Efuse */
1514 	if (hw_mac_addr) {
1515 		_rtw_memcpy(mac, hw_mac_addr, ETH_ALEN);
1516 		goto err_chk;
1517 	}
1518 
1519 err_chk:
1520 	if (rtw_check_invalid_mac_address(mac) == _TRUE) {
1521 		#if DEFAULT_RANDOM_MACADDR
1522 		DBG_871X_LEVEL(_drv_err_, "invalid mac addr:"MAC_FMT", assign random MAC\n", MAC_ARG(mac));
1523 		*((u32 *)(&mac[2])) = rtw_random32();
1524 		mac[0] = 0x00;
1525 		mac[1] = 0xe0;
1526 		mac[2] = 0x4c;
1527 		#else
1528 		DBG_871X_LEVEL(_drv_err_, "invalid mac addr:"MAC_FMT", assign default one\n", MAC_ARG(mac));
1529 		mac[0] = 0x00;
1530 		mac[1] = 0xe0;
1531 		mac[2] = 0x4c;
1532 		mac[3] = 0x87;
1533 		mac[4] = 0x00;
1534 		mac[5] = 0x00;
1535 		#endif
1536 	}
1537 
1538 	_rtw_memcpy(out, mac, ETH_ALEN);
1539 	DBG_871X("%s mac addr:"MAC_FMT"\n", __func__, MAC_ARG(out));
1540 }
1541 
1542 #ifdef CONFIG_80211N_HT
dump_ht_cap_ie_content(void * sel,u8 * buf,u32 buf_len)1543 void dump_ht_cap_ie_content(void *sel, u8 *buf, u32 buf_len)
1544 {
1545 	if (buf_len != 26) {
1546 		DBG_871X_SEL_NL(sel, "Invalid HT capability IE len:%d != %d\n", buf_len, 26);
1547 		return;
1548 	}
1549 
1550 	DBG_871X_SEL_NL(sel, "HT Capabilities Info:%02x%02x\n", *(buf), *(buf+1));
1551 	DBG_871X_SEL_NL(sel, "A-MPDU Parameters:"HT_AMPDU_PARA_FMT"\n"
1552 		, HT_AMPDU_PARA_ARG(HT_CAP_ELE_AMPDU_PARA(buf)));
1553 	DBG_871X_SEL_NL(sel, "Supported MCS Set:"HT_SUP_MCS_SET_FMT"\n"
1554 		, HT_SUP_MCS_SET_ARG(HT_CAP_ELE_SUP_MCS_SET(buf)));
1555 }
1556 
dump_ht_cap_ie(void * sel,u8 * ie,u32 ie_len)1557 void dump_ht_cap_ie(void *sel, u8 *ie, u32 ie_len)
1558 {
1559 	u8* pos = (u8*)ie;
1560 	u16 id;
1561 	u16 len;
1562 
1563 	u8 *ht_cap_ie;
1564 	sint ht_cap_ielen;
1565 
1566 	ht_cap_ie = rtw_get_ie(ie, _HT_CAPABILITY_IE_, &ht_cap_ielen, ie_len);
1567 	if(!ie || ht_cap_ie != ie)
1568 		return;
1569 
1570 	dump_ht_cap_ie_content(sel, ht_cap_ie+2, ht_cap_ielen);
1571 }
1572 #endif /* CONFIG_80211N_HT */
1573 
dump_ies(void * sel,u8 * buf,u32 buf_len)1574 void dump_ies(void *sel, u8 *buf, u32 buf_len)
1575 {
1576 	u8* pos = (u8*)buf;
1577 	u8 id, len;
1578 
1579 	while(pos-buf+1<buf_len){
1580 		id = *pos;
1581 		len = *(pos+1);
1582 
1583 		DBG_871X_SEL_NL(sel, "%s ID:%u, LEN:%u\n", __FUNCTION__, id, len);
1584 		#ifdef CONFIG_80211N_HT
1585 		dump_ht_cap_ie(sel, pos, len);
1586 		#endif
1587 		dump_wps_ie(sel, pos, len);
1588 		#ifdef CONFIG_P2P
1589 		dump_p2p_ie(sel, pos, len);
1590 		#ifdef CONFIG_WFD
1591 		dump_wfd_ie(sel, pos, len);
1592 		#endif
1593 		#endif
1594 
1595 		pos+=(2+len);
1596 	}
1597 }
1598 
dump_wps_ie(void * sel,u8 * ie,u32 ie_len)1599 void dump_wps_ie(void *sel, u8 *ie, u32 ie_len)
1600 {
1601 	u8* pos = (u8*)ie;
1602 	u16 id;
1603 	u16 len;
1604 
1605 	u8 *wps_ie;
1606 	uint wps_ielen;
1607 
1608 	wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen);
1609 	if(wps_ie != ie || wps_ielen == 0)
1610 		return;
1611 
1612 	pos+=6;
1613 	while(pos-ie < ie_len){
1614 		id = RTW_GET_BE16(pos);
1615 		len = RTW_GET_BE16(pos + 2);
1616 
1617 		DBG_871X_SEL_NL(sel, "%s ID:0x%04x, LEN:%u\n", __FUNCTION__, id, len);
1618 
1619 		pos+=(4+len);
1620 	}
1621 }
1622 
1623 /**
1624  * rtw_ies_get_chbw - get operation ch, bw, offset from IEs of BSS.
1625  * @ies: pointer of the first tlv IE
1626  * @ies_len: length of @ies
1627  * @ch: pointer of ch, used as output
1628  * @bw: pointer of bw, used as output
1629  * @offset: pointer of offset, used as output
1630  */
rtw_ies_get_chbw(u8 * ies,int ies_len,u8 * ch,u8 * bw,u8 * offset)1631 void rtw_ies_get_chbw(u8 *ies, int ies_len, u8 *ch, u8 *bw, u8 *offset)
1632 {
1633 	u8 *p;
1634 	int	ie_len;
1635 
1636 	*ch = 0;
1637 	*bw = CHANNEL_WIDTH_20;
1638 	*offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
1639 
1640 	p = rtw_get_ie(ies, _DSSET_IE_, &ie_len, ies_len);
1641 	if (p && ie_len > 0)
1642 		*ch = *(p + 2);
1643 
1644 #ifdef CONFIG_80211N_HT
1645 {
1646 	u8 *ht_cap_ie, *ht_op_ie;
1647 	int ht_cap_ielen, ht_op_ielen;
1648 
1649 	ht_cap_ie = rtw_get_ie(ies, EID_HTCapability, &ht_cap_ielen, ies_len);
1650 	if (ht_cap_ie && ht_cap_ielen) {
1651 		if (GET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2))
1652 			*bw = CHANNEL_WIDTH_40;
1653 	}
1654 
1655 	ht_op_ie = rtw_get_ie(ies, EID_HTInfo, &ht_op_ielen, ies_len);
1656 	if (ht_op_ie && ht_op_ielen) {
1657 		if (*ch == 0) {
1658 			*ch = GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2);
1659 		} else if (*ch != 0 && *ch != GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2)) {
1660 			DBG_871X("%s ch inconsistent, DSSS:%u, HT primary:%u\n"
1661 				, __func__, *ch, GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2));
1662 		}
1663 
1664 		if (!GET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2))
1665 			*bw = CHANNEL_WIDTH_20;
1666 
1667 		if (*bw == CHANNEL_WIDTH_40) {
1668 			switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2)) {
1669 			case SCA:
1670 				*offset = HAL_PRIME_CHNL_OFFSET_LOWER;
1671 				break;
1672 			case SCB:
1673 				*offset = HAL_PRIME_CHNL_OFFSET_UPPER;
1674 				break;
1675 			}
1676 		}
1677 	}
1678 }
1679 #endif /* CONFIG_80211N_HT */
1680 #ifdef CONFIG_80211AC_VHT
1681 {
1682 	u8 *vht_op_ie;
1683 	int vht_op_ielen;
1684 
1685 	vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len);
1686 	if (vht_op_ie && vht_op_ielen) {
1687 		if (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2) >= 1)
1688 			*bw = CHANNEL_WIDTH_80;
1689 	}
1690 }
1691 #endif
1692 }
1693 
rtw_bss_get_chbw(WLAN_BSSID_EX * bss,u8 * ch,u8 * bw,u8 * offset)1694 void rtw_bss_get_chbw(WLAN_BSSID_EX *bss, u8 *ch, u8 *bw, u8 *offset)
1695 {
1696 	rtw_ies_get_chbw(bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)
1697 		, bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)
1698 		, ch, bw, offset);
1699 
1700 	if (*ch == 0) {
1701 		*ch = bss->Configuration.DSConfig;
1702 	} else if (*ch != bss->Configuration.DSConfig) {
1703 		DBG_871X("inconsistent ch - ies:%u bss->Configuration.DSConfig:%u\n"
1704 			, *ch, bss->Configuration.DSConfig);
1705 		*ch = bss->Configuration.DSConfig;
1706 		rtw_warn_on(1);
1707 	}
1708 }
1709 
1710 /**
1711  * rtw_is_chbw_grouped - test if the two ch settings can be grouped together
1712  * @ch_a: ch of set a
1713  * @bw_a: bw of set a
1714  * @offset_a: offset of set a
1715  * @ch_b: ch of set b
1716  * @bw_b: bw of set b
1717  * @offset_b: offset of set b
1718  */
rtw_is_chbw_grouped(u8 ch_a,u8 bw_a,u8 offset_a,u8 ch_b,u8 bw_b,u8 offset_b)1719 bool rtw_is_chbw_grouped(u8 ch_a, u8 bw_a, u8 offset_a
1720 	, u8 ch_b, u8 bw_b, u8 offset_b)
1721 {
1722 	bool is_grouped = _FALSE;
1723 
1724 	if (ch_a != ch_b) {
1725 		/* ch is different */
1726 		goto exit;
1727 	} else if ((bw_a == CHANNEL_WIDTH_40 || bw_a == CHANNEL_WIDTH_80)
1728 			&& (bw_b == CHANNEL_WIDTH_40 || bw_b == CHANNEL_WIDTH_80)
1729 	) {
1730 		if (offset_a != offset_b)
1731 			goto exit;
1732 	}
1733 
1734 	is_grouped = _TRUE;
1735 
1736 exit:
1737 	return is_grouped;
1738 }
1739 
1740 /**
1741  * rtw_sync_chbw - obey g_ch, adjust g_bw, g_offset, bw, offset
1742  * @req_ch: pointer of the request ch, may be modified further
1743  * @req_bw: pointer of the request bw, may be modified further
1744  * @req_offset: pointer of the request offset, may be modified further
1745  * @g_ch: pointer of the ongoing group ch
1746  * @g_bw: pointer of the ongoing group bw, may be modified further
1747  * @g_offset: pointer of the ongoing group offset, may be modified further
1748  */
rtw_sync_chbw(u8 * req_ch,u8 * req_bw,u8 * req_offset,u8 * g_ch,u8 * g_bw,u8 * g_offset)1749 void rtw_sync_chbw(u8 *req_ch, u8 *req_bw, u8 *req_offset
1750 	, u8 *g_ch, u8 *g_bw, u8 *g_offset)
1751 {
1752 
1753 	*req_ch = *g_ch;
1754 
1755 	if (*req_bw == CHANNEL_WIDTH_80 && *g_ch <= 14) {
1756 		/*2.4G ch, downgrade to 40Mhz */
1757 		*req_bw = CHANNEL_WIDTH_40;
1758 	}
1759 
1760 	switch (*req_bw) {
1761 	case CHANNEL_WIDTH_80:
1762 		if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80)
1763 			*req_offset = *g_offset;
1764 		else if (*g_bw == CHANNEL_WIDTH_20)
1765 			*req_offset = rtw_get_offset_by_ch(*req_ch);
1766 
1767 		if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
1768 			DBG_871X_LEVEL(_drv_err_, "%s req 80MHz BW without offset, down to 20MHz\n", __func__);
1769 			rtw_warn_on(1);
1770 			*req_bw = CHANNEL_WIDTH_20;
1771 		}
1772 		break;
1773 	case CHANNEL_WIDTH_40:
1774 		if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80)
1775 			*req_offset = *g_offset;
1776 		else if (*g_bw == CHANNEL_WIDTH_20)
1777 			*req_offset = rtw_get_offset_by_ch(*req_ch);
1778 
1779 		if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) {
1780 			DBG_871X_LEVEL(_drv_err_, "%s req 40MHz BW without offset, down to 20MHz\n", __func__);
1781 			rtw_warn_on(1);
1782 			*req_bw = CHANNEL_WIDTH_20;
1783 		}
1784 		break;
1785 	case CHANNEL_WIDTH_20:
1786 		*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
1787 		break;
1788 	default:
1789 		DBG_871X_LEVEL(_drv_err_, "%s req unsupported BW:%u\n", __func__, *req_bw);
1790 		rtw_warn_on(1);
1791 	}
1792 
1793 	if (*req_bw > *g_bw) {
1794 		*g_bw = *req_bw;
1795 		*g_offset = *req_offset;
1796 	}
1797 }
1798 
1799 #ifdef CONFIG_P2P
1800 /**
1801  * rtw_get_p2p_merged_len - Get merged ie length from muitiple p2p ies.
1802  * @in_ie: Pointer of the first p2p ie
1803  * @in_len: Total len of muiltiple p2p ies
1804  * Returns: Length of merged p2p ie length
1805  */
rtw_get_p2p_merged_ies_len(u8 * in_ie,u32 in_len)1806 u32 rtw_get_p2p_merged_ies_len(u8 *in_ie, u32 in_len)
1807 {
1808 	PNDIS_802_11_VARIABLE_IEs	pIE;
1809 	u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 };
1810 	int i=0;
1811 	int j=0, len=0;
1812 
1813 	while( i < in_len)
1814 	{
1815 		pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie+ i);
1816 
1817 		if( pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4) )
1818 		{
1819 			len += pIE->Length-4; // 4 is P2P OUI length, don't count it in this loop
1820 		}
1821 
1822 		i += (pIE->Length + 2);
1823 	}
1824 
1825 	return len + 4;	// Append P2P OUI length at last.
1826 }
1827 
1828 /**
1829  * rtw_p2p_merge_ies - Merge muitiple p2p ies into one
1830  * @in_ie: Pointer of the first p2p ie
1831  * @in_len: Total len of muiltiple p2p ies
1832  * @merge_ie: Pointer of merged ie
1833  * Returns: Length of merged p2p ie
1834  */
rtw_p2p_merge_ies(u8 * in_ie,u32 in_len,u8 * merge_ie)1835 int rtw_p2p_merge_ies(u8 *in_ie, u32 in_len, u8 *merge_ie)
1836 {
1837 	PNDIS_802_11_VARIABLE_IEs	pIE;
1838 	u8 len = 0;
1839 	u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 };
1840 	u8 ELOUI[6] = { 0xDD, 0x00, 0x50, 0x6f, 0x9a, 0x09 };	//EID;Len;OUI, Len would copy at the end of function
1841 	int i=0;
1842 
1843 	if( merge_ie != NULL)
1844 	{
1845 		//Set first P2P OUI
1846 		_rtw_memcpy(merge_ie, ELOUI, 6);
1847 		merge_ie += 6;
1848 
1849 		while( i < in_len)
1850 		{
1851 			pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie+ i);
1852 
1853 			// Take out the rest of P2P OUIs
1854 			if( pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4) )
1855 			{
1856 				_rtw_memcpy( merge_ie, pIE->data +4, pIE->Length -4);
1857 				len += pIE->Length-4;
1858 				merge_ie += pIE->Length-4;
1859 			}
1860 
1861 			i += (pIE->Length + 2);
1862 		}
1863 
1864 		return len + 4;	// 4 is for P2P OUI
1865 
1866 	}
1867 
1868 	return 0;
1869 }
1870 
dump_p2p_ie(void * sel,u8 * ie,u32 ie_len)1871 void dump_p2p_ie(void *sel, u8 *ie, u32 ie_len) {
1872 	u8* pos = (u8*)ie;
1873 	u8 id;
1874 	u16 len;
1875 
1876 	u8 *p2p_ie;
1877 	uint p2p_ielen;
1878 
1879 	p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen);
1880 	if(p2p_ie != ie || p2p_ielen == 0)
1881 		return;
1882 
1883 	pos+=6;
1884 	while(pos-ie < ie_len){
1885 		id = *pos;
1886 		len = RTW_GET_LE16(pos+1);
1887 
1888 		DBG_871X_SEL_NL(sel, "%s ID:%u, LEN:%u\n", __FUNCTION__, id, len);
1889 
1890 		pos+=(3+len);
1891 	}
1892 }
1893 
rtw_get_p2p_ie_from_scan_queue(u8 * in_ie,int in_len,u8 * p2p_ie,uint * p2p_ielen,u8 frame_type)1894 u8 *rtw_get_p2p_ie_from_scan_queue(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen, u8 frame_type)
1895 {
1896 	u8*	p2p = NULL;
1897 
1898 	DBG_871X( "[%s] frame_type = %d\n", __FUNCTION__, frame_type );
1899 	switch( frame_type )
1900 	{
1901 		case 1:
1902 		case 3:
1903 		{	//	Beacon or Probe Response
1904 			p2p = rtw_get_p2p_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, p2p_ie, p2p_ielen);
1905 			break;
1906 		}
1907 		case 2:
1908 		{	//	Probe Request
1909 			p2p = rtw_get_p2p_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , p2p_ie, p2p_ielen);
1910 			break;
1911 		}
1912 	}
1913 	return p2p;
1914 }
1915 
1916 /**
1917  * rtw_get_p2p_ie - Search P2P IE from a series of IEs
1918  * @in_ie: Address of IEs to search
1919  * @in_len: Length limit from in_ie
1920  * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie
1921  * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE
1922  *
1923  * Returns: The address of the P2P IE found, or NULL
1924  */
rtw_get_p2p_ie(u8 * in_ie,int in_len,u8 * p2p_ie,uint * p2p_ielen)1925 u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
1926 {
1927 	uint cnt;
1928 	u8 *p2p_ie_ptr = NULL;
1929 	u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
1930 
1931 	if (p2p_ielen)
1932 		*p2p_ielen = 0;
1933 
1934 	if (!in_ie || in_len < 0) {
1935 		rtw_warn_on(1);
1936 		return p2p_ie_ptr;
1937 	}
1938 
1939 	if (in_len <= 0)
1940 		return p2p_ie_ptr;
1941 
1942 	cnt = 0;
1943 
1944 	while (cnt + 1 + 4 < in_len) {
1945 		eid = in_ie[cnt];
1946 
1947 		if (cnt + 1 + 4 >= MAX_IE_SZ) {
1948 			rtw_warn_on(1);
1949 			return NULL;
1950 		}
1951 
1952 		if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], p2p_oui, 4) == _TRUE) {
1953 			p2p_ie_ptr = in_ie + cnt;
1954 
1955 			if (p2p_ie)
1956 				_rtw_memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
1957 
1958 			if (p2p_ielen)
1959 				*p2p_ielen = in_ie[cnt + 1] + 2;
1960 
1961 			break;
1962 		} else {
1963 			cnt += in_ie[cnt + 1] + 2;
1964 		}
1965 
1966 	}
1967 
1968 	return p2p_ie_ptr;
1969 }
1970 
1971 /**
1972  * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE
1973  * @p2p_ie: Address of P2P IE to search
1974  * @p2p_ielen: Length limit from p2p_ie
1975  * @target_attr_id: The attribute ID of P2P attribute to search
1976  * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr
1977  * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute
1978  *
1979  * Returns: the address of the specific WPS attribute found, or NULL
1980  */
rtw_get_p2p_attr(u8 * p2p_ie,uint p2p_ielen,u8 target_attr_id,u8 * buf_attr,u32 * len_attr)1981 u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_attr, u32 *len_attr)
1982 {
1983 	u8 *attr_ptr = NULL;
1984 	u8 *target_attr_ptr = NULL;
1985 	u8 p2p_oui[4]={0x50,0x6F,0x9A,0x09};
1986 
1987 	if(len_attr)
1988 		*len_attr = 0;
1989 
1990 	if ( !p2p_ie || ( p2p_ie[0] != _VENDOR_SPECIFIC_IE_ ) ||
1991 		( _rtw_memcmp( p2p_ie + 2, p2p_oui , 4 ) != _TRUE ) )
1992 	{
1993 		return attr_ptr;
1994 	}
1995 
1996 	// 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type)
1997 	attr_ptr = p2p_ie + 6; //goto first attr
1998 
1999 	while(attr_ptr - p2p_ie < p2p_ielen)
2000 	{
2001 		// 3 = 1(Attribute ID) + 2(Length)
2002 		u8 attr_id = *attr_ptr;
2003 		u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1);
2004 		u16 attr_len = attr_data_len + 3;
2005 
2006 		//DBG_871X("%s attr_ptr:%p, id:%u, length:%u\n", __FUNCTION__, attr_ptr, attr_id, attr_data_len);
2007 		if( attr_id == target_attr_id )
2008 		{
2009 			target_attr_ptr = attr_ptr;
2010 
2011 			if(buf_attr)
2012 				_rtw_memcpy(buf_attr, attr_ptr, attr_len);
2013 
2014 			if(len_attr)
2015 				*len_attr = attr_len;
2016 
2017 			break;
2018 		}
2019 		else
2020 		{
2021 			attr_ptr += attr_len; //goto next
2022 		}
2023 
2024 	}
2025 
2026 	return target_attr_ptr;
2027 }
2028 
2029 /**
2030  * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE
2031  * @p2p_ie: Address of P2P IE to search
2032  * @p2p_ielen: Length limit from p2p_ie
2033  * @target_attr_id: The attribute ID of P2P attribute to search
2034  * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content
2035  * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content
2036  *
2037  * Returns: the address of the specific P2P attribute content found, or NULL
2038  */
rtw_get_p2p_attr_content(u8 * p2p_ie,uint p2p_ielen,u8 target_attr_id,u8 * buf_content,uint * len_content)2039 u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_content, uint *len_content)
2040 {
2041 	u8 *attr_ptr;
2042 	u32 attr_len;
2043 
2044 	if(len_content)
2045 		*len_content = 0;
2046 
2047 	attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len);
2048 
2049 	if(attr_ptr && attr_len)
2050 	{
2051 		if(buf_content)
2052 			_rtw_memcpy(buf_content, attr_ptr+3, attr_len-3);
2053 
2054 		if(len_content)
2055 			*len_content = attr_len-3;
2056 
2057 		return attr_ptr+3;
2058 	}
2059 
2060 	return NULL;
2061 }
2062 
rtw_set_p2p_attr_content(u8 * pbuf,u8 attr_id,u16 attr_len,u8 * pdata_attr)2063 u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr)
2064 {
2065 	u32 a_len;
2066 
2067 	*pbuf = attr_id;
2068 
2069 	//*(u16*)(pbuf + 1) = cpu_to_le16(attr_len);
2070 	RTW_PUT_LE16(pbuf + 1, attr_len);
2071 
2072 	if(pdata_attr)
2073 		_rtw_memcpy(pbuf + 3, pdata_attr, attr_len);
2074 
2075 	a_len = attr_len + 3;
2076 
2077 	return a_len;
2078 }
2079 
rtw_p2p_attr_remove(u8 * ie,uint ielen_ori,u8 attr_id)2080 static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id)
2081 {
2082 	u8 *target_attr;
2083 	u32 target_attr_len;
2084 	uint ielen = ielen_ori;
2085 	int index=0;
2086 
2087 	while(1) {
2088 		target_attr=rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len);
2089 		if(target_attr && target_attr_len)
2090 		{
2091 			u8 *next_attr = target_attr+target_attr_len;
2092 			uint remain_len = ielen-(next_attr-ie);
2093 			//dump_ies(RTW_DBGDUMP, ie, ielen);
2094 			#if 0
2095 			DBG_871X("[%d] ie:%p, ielen:%u\n"
2096 				"target_attr:%p, target_attr_len:%u\n"
2097 				"next_attr:%p, remain_len:%u\n"
2098 				, index++
2099 				, ie, ielen
2100 				, target_attr, target_attr_len
2101 				, next_attr, remain_len
2102 			);
2103 			#endif
2104 
2105 			_rtw_memset(target_attr, 0, target_attr_len);
2106 			_rtw_memcpy(target_attr, next_attr, remain_len);
2107 			_rtw_memset(target_attr+remain_len, 0, target_attr_len);
2108 			*(ie+1) -= target_attr_len;
2109 			ielen-=target_attr_len;
2110 		}
2111 		else
2112 		{
2113 			//if(index>0)
2114 			//	dump_ies(RTW_DBGDUMP, ie, ielen);
2115 			break;
2116 		}
2117 	}
2118 
2119 	return ielen;
2120 }
2121 
rtw_WLAN_BSSID_EX_remove_p2p_attr(WLAN_BSSID_EX * bss_ex,u8 attr_id)2122 void rtw_WLAN_BSSID_EX_remove_p2p_attr(WLAN_BSSID_EX *bss_ex, u8 attr_id)
2123 {
2124 	u8 *p2p_ie;
2125 	uint p2p_ielen, p2p_ielen_ori;
2126 	int cnt;
2127 
2128 	if( (p2p_ie=rtw_get_p2p_ie(bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_, NULL, &p2p_ielen_ori)) )
2129 	{
2130 		if (0)
2131 			if(rtw_get_p2p_attr(p2p_ie, p2p_ielen_ori, attr_id, NULL, NULL)) {
2132 				DBG_871X("rtw_get_p2p_attr: GOT P2P_ATTR:%u!!!!!!!!\n", attr_id);
2133 				dump_ies(RTW_DBGDUMP, bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_);
2134 			}
2135 
2136 		p2p_ielen=rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id);
2137 		if(p2p_ielen != p2p_ielen_ori) {
2138 
2139 			u8 *next_ie_ori = p2p_ie+p2p_ielen_ori;
2140 			u8 *next_ie = p2p_ie+p2p_ielen;
2141 			uint remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs);
2142 
2143 			_rtw_memcpy(next_ie, next_ie_ori, remain_len);
2144 			_rtw_memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen);
2145 			bss_ex->IELength -= p2p_ielen_ori-p2p_ielen;
2146 
2147 			if (0) {
2148 				DBG_871X("remove P2P_ATTR:%u!\n", attr_id);
2149 				dump_ies(RTW_DBGDUMP, bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_);
2150 			}
2151 		}
2152 	}
2153 }
2154 
2155 #endif //CONFIG_P2P
2156 
2157 #ifdef CONFIG_WFD
dump_wfd_ie(void * sel,u8 * ie,u32 ie_len)2158 void dump_wfd_ie(void *sel, u8 *ie, u32 ie_len)
2159 {
2160 	u8* pos = (u8*)ie;
2161 	u8 id;
2162 	u16 len;
2163 
2164 	u8 *wfd_ie;
2165 	uint wfd_ielen;
2166 
2167 	if(rtw_get_wfd_ie(ie, ie_len, NULL, &wfd_ielen) == _FALSE)
2168 		return;
2169 
2170 	pos+=6;
2171 	while(pos-ie < ie_len){
2172 		id = *pos;
2173 		len = RTW_GET_BE16(pos+1);
2174 
2175 		DBG_871X_SEL_NL(sel, "%s ID:%u, LEN:%u\n", __FUNCTION__, id, len);
2176 
2177 		pos+=(3+len);
2178 	}
2179 }
2180 
rtw_get_wfd_ie(u8 * in_ie,int in_len,u8 * wfd_ie,uint * wfd_ielen)2181 int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen)
2182 {
2183 	int match;
2184 	uint cnt = 0;
2185 	u8 eid, wfd_oui[4]={0x50,0x6F,0x9A,0x0A};
2186 
2187 
2188 	match=_FALSE;
2189 
2190 	if ( in_len < 0 )
2191 	{
2192 		return match;
2193 	}
2194 
2195 	while(cnt<in_len)
2196 	{
2197 		eid = in_ie[cnt];
2198 
2199 		if( ( eid == _VENDOR_SPECIFIC_IE_ ) && ( _rtw_memcmp( &in_ie[cnt+2], wfd_oui, 4) == _TRUE ) )
2200 		{
2201 			if ( wfd_ie != NULL )
2202 			{
2203 				_rtw_memcpy( wfd_ie, &in_ie[ cnt ], in_ie[ cnt + 1 ] + 2 );
2204 
2205 			}
2206 			else
2207 			{
2208 				if ( wfd_ielen != NULL )
2209 				{
2210 					*wfd_ielen = 0;
2211 				}
2212 			}
2213 
2214 			if ( wfd_ielen != NULL )
2215 			{
2216 				*wfd_ielen = in_ie[ cnt + 1 ] + 2;
2217 			}
2218 
2219 			cnt += in_ie[ cnt + 1 ] + 2;
2220 
2221 			match = _TRUE;
2222 			break;
2223 		}
2224 		else
2225 		{
2226 			cnt += in_ie[ cnt + 1 ] +2; //goto next
2227 		}
2228 
2229 	}
2230 
2231 	if ( match == _TRUE )
2232 	{
2233 		match = cnt;
2234 	}
2235 
2236 	return match;
2237 
2238 }
2239 
rtw_get_wfd_ie_from_scan_queue(u8 * in_ie,int in_len,u8 * wfd_ie,uint * wfd_ielen,u8 frame_type)2240 int rtw_get_wfd_ie_from_scan_queue(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen, u8 frame_type)
2241 {
2242 	int match;
2243 
2244 	match=_FALSE;
2245 
2246 	DBG_871X( "[%s] frame_type = %d\n", __FUNCTION__, frame_type );
2247 	switch( frame_type )
2248 	{
2249 		case 1:
2250 		case 3:
2251 		{	//	Beacon or Probe Response
2252 			match = rtw_get_wfd_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, wfd_ie, wfd_ielen);
2253 			break;
2254 		}
2255 		case 2:
2256 		{	//	Probe Request
2257 			match = rtw_get_wfd_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , wfd_ie, wfd_ielen);
2258 			break;
2259 		}
2260 	}
2261 	return match;
2262 }
2263 
2264 //	attr_content: The output buffer, contains the "body field" of WFD attribute.
2265 //	attr_contentlen: The data length of the "body field" of WFD attribute.
rtw_get_wfd_attr_content(u8 * wfd_ie,uint wfd_ielen,u8 target_attr_id,u8 * attr_content,uint * attr_contentlen)2266 int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id ,u8 *attr_content, uint *attr_contentlen)
2267 {
2268 	int match;
2269 	uint cnt = 0;
2270 	u8 attr_id, wfd_oui[4]={0x50,0x6F,0x9A,0x0A};
2271 
2272 
2273 	match=_FALSE;
2274 
2275 	if ( ( wfd_ie[ 0 ] != _VENDOR_SPECIFIC_IE_ ) ||
2276 		( _rtw_memcmp( wfd_ie + 2, wfd_oui , 4 ) != _TRUE ) )
2277 	{
2278 		return( match );
2279 	}
2280 
2281 	//	1 ( WFD IE ) + 1 ( Length ) + 3 ( OUI ) + 1 ( OUI Type )
2282 	cnt = 6;
2283 	while( cnt < wfd_ielen )
2284 	{
2285 		u16 attrlen = RTW_GET_BE16(wfd_ie + cnt + 1);
2286 
2287 		attr_id = wfd_ie[cnt];
2288 		if( attr_id == target_attr_id )
2289 		{
2290 			//	3 -> 1 byte for attribute ID field, 2 bytes for length field
2291 			if(attr_content)
2292 				_rtw_memcpy( attr_content, &wfd_ie[ cnt + 3 ], attrlen );
2293 
2294 			if(attr_contentlen)
2295 				*attr_contentlen = attrlen;
2296 
2297 			cnt += attrlen + 3;
2298 
2299 			match = _TRUE;
2300 			break;
2301 		}
2302 		else
2303 		{
2304 			cnt += attrlen + 3; //goto next
2305 		}
2306 
2307 	}
2308 
2309 	return match;
2310 
2311 }
2312 #endif // CONFIG_WFD
2313 
2314 //Baron adds to avoid FreeBSD warning
ieee80211_is_empty_essid(const char * essid,int essid_len)2315 int ieee80211_is_empty_essid(const char *essid, int essid_len)
2316 {
2317 	/* Single white space is for Linksys APs */
2318 	if (essid_len == 1 && essid[0] == ' ')
2319 		return 1;
2320 
2321 	/* Otherwise, if the entire essid is 0, we assume it is hidden */
2322 	while (essid_len) {
2323 		essid_len--;
2324 		if (essid[essid_len] != '\0')
2325 			return 0;
2326 	}
2327 
2328 	return 1;
2329 }
2330 
ieee80211_get_hdrlen(u16 fc)2331 int ieee80211_get_hdrlen(u16 fc)
2332 {
2333 	int hdrlen = 24;
2334 
2335 	switch (WLAN_FC_GET_TYPE(fc)) {
2336 	case RTW_IEEE80211_FTYPE_DATA:
2337 		if (fc & RTW_IEEE80211_STYPE_QOS_DATA)
2338 			hdrlen += 2;
2339 		if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS))
2340 			hdrlen += 6; /* Addr4 */
2341 		break;
2342 	case RTW_IEEE80211_FTYPE_CTL:
2343 		switch (WLAN_FC_GET_STYPE(fc)) {
2344 		case RTW_IEEE80211_STYPE_CTS:
2345 		case RTW_IEEE80211_STYPE_ACK:
2346 			hdrlen = 10;
2347 			break;
2348 		default:
2349 			hdrlen = 16;
2350 			break;
2351 		}
2352 		break;
2353 	}
2354 
2355 	return hdrlen;
2356 }
2357 
rtw_get_cipher_info(struct wlan_network * pnetwork)2358 int rtw_get_cipher_info(struct wlan_network *pnetwork)
2359 {
2360 	u32 wpa_ielen;
2361 	unsigned char *pbuf;
2362 	int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
2363 	int ret = _FAIL;
2364 	pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
2365 
2366 	if(pbuf && (wpa_ielen>0)) {
2367 		RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen));
2368 		if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) {
2369 
2370 			pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
2371 			pnetwork->BcnInfo.group_cipher = group_cipher;
2372 			pnetwork->BcnInfo.is_8021x = is8021x;
2373 			RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d",
2374 						__func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x));
2375 			ret = _SUCCESS;
2376 		}
2377 	} else {
2378 
2379 		pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
2380 
2381 		if(pbuf && (wpa_ielen>0)) {
2382 			RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("get RSN IE\n"));
2383 			if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) {
2384 				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("get RSN IE  OK!!!\n"));
2385 				pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
2386 				pnetwork->BcnInfo.group_cipher = group_cipher;
2387 				pnetwork->BcnInfo.is_8021x = is8021x;
2388 				RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("%s: pnetwork->pairwise_cipher: %d,"
2389 							"pnetwork->group_cipher is %d, is_8021x is %d",	__func__, pnetwork->BcnInfo.pairwise_cipher,
2390 							pnetwork->BcnInfo.group_cipher,pnetwork->BcnInfo.is_8021x));
2391 				ret = _SUCCESS;
2392 			}
2393 		}
2394 	}
2395 
2396 	return ret;
2397 }
2398 
rtw_get_bcn_info(struct wlan_network * pnetwork)2399 void rtw_get_bcn_info(struct wlan_network *pnetwork)
2400 {
2401 	unsigned short cap = 0;
2402 	u8 bencrypt = 0;
2403 	//u8 wpa_ie[255],rsn_ie[255];
2404 	u16 wpa_len=0,rsn_len=0;
2405 	struct HT_info_element *pht_info = NULL;
2406 	struct rtw_ieee80211_ht_cap *pht_cap = NULL;
2407 	unsigned int		len;
2408 	unsigned char		*p;
2409 
2410 	_rtw_memcpy((u8 *)&cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
2411 	cap = le16_to_cpu(cap);
2412 	if (cap & WLAN_CAPABILITY_PRIVACY) {
2413 		bencrypt = 1;
2414 		pnetwork->network.Privacy = 1;
2415 	} else {
2416 		pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
2417 	}
2418 	rtw_get_sec_ie(pnetwork->network.IEs ,pnetwork->network.IELength,NULL,&rsn_len,NULL,&wpa_len);
2419 	RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: ssid=%s\n",pnetwork->network.Ssid.Ssid));
2420 	RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: wpa_len=%d rsn_len=%d\n",wpa_len,rsn_len));
2421 	RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: ssid=%s\n",pnetwork->network.Ssid.Ssid));
2422 	RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: wpa_len=%d rsn_len=%d\n",wpa_len,rsn_len));
2423 
2424 	if (rsn_len > 0) {
2425 		pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
2426 	} else if (wpa_len > 0) {
2427 		pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA;
2428 	} else {
2429 		if (bencrypt)
2430 			pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
2431 	}
2432 	RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
2433 				pnetwork->BcnInfo.encryp_protocol));
2434 	RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
2435 				pnetwork->BcnInfo.encryp_protocol));
2436 	rtw_get_cipher_info(pnetwork);
2437 
2438 	/* get bwmode and ch_offset */
2439 	/* parsing HT_CAP_IE */
2440 	p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
2441 	if(p && len>0) {
2442 			pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
2443 			pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info;
2444 	} else {
2445 			pnetwork->BcnInfo.ht_cap_info = 0;
2446 	}
2447 	/* parsing HT_INFO_IE */
2448 	p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
2449 	if(p && len>0) {
2450 			pht_info = (struct HT_info_element *)(p + 2);
2451 			pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0];
2452 	} else {
2453 			pnetwork->BcnInfo.ht_info_infos_0 = 0;
2454 	}
2455 }
2456 
rtw_ht_mcsset_to_nss(u8 * supp_mcs_set)2457 u8	rtw_ht_mcsset_to_nss(u8 *supp_mcs_set)
2458 {
2459 	u8 nss = 1;
2460 
2461 	if (supp_mcs_set[3])
2462 		nss = 4;
2463 	else if (supp_mcs_set[2])
2464 		nss = 3;
2465 	else if (supp_mcs_set[1])
2466 		nss = 2;
2467 	else if (supp_mcs_set[0])
2468 		nss = 1;
2469 	else
2470 		DBG_871X("%s,%d, warning! supp_mcs_set is zero\n", __func__, __LINE__);
2471 	/* DBG_871X("%s HT: %dSS\n", __FUNCTION__, nss); */
2472 	return nss;
2473 }
2474 
2475 //show MCS rate, unit: 100Kbps
rtw_mcs_rate(u8 rf_type,u8 bw_40MHz,u8 short_GI,unsigned char * MCS_rate)2476 u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI, unsigned char * MCS_rate)
2477 {
2478 	u16 max_rate = 0;
2479 
2480 	if(rf_type == RF_1T1R)
2481 	{
2482 		if(MCS_rate[0] & BIT(7))
2483 			max_rate = (bw_40MHz) ? ((short_GI)?1500:1350):((short_GI)?722:650);
2484 		else if(MCS_rate[0] & BIT(6))
2485 			max_rate = (bw_40MHz) ? ((short_GI)?1350:1215):((short_GI)?650:585);
2486 		else if(MCS_rate[0] & BIT(5))
2487 			max_rate = (bw_40MHz) ? ((short_GI)?1200:1080):((short_GI)?578:520);
2488 		else if(MCS_rate[0] & BIT(4))
2489 			max_rate = (bw_40MHz) ? ((short_GI)?900:810):((short_GI)?433:390);
2490 		else if(MCS_rate[0] & BIT(3))
2491 			max_rate = (bw_40MHz) ? ((short_GI)?600:540):((short_GI)?289:260);
2492 		else if(MCS_rate[0] & BIT(2))
2493 			max_rate = (bw_40MHz) ? ((short_GI)?450:405):((short_GI)?217:195);
2494 		else if(MCS_rate[0] & BIT(1))
2495 			max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130);
2496 		else if(MCS_rate[0] & BIT(0))
2497 			max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65);
2498 	}
2499 	else
2500 	{
2501 		if(MCS_rate[1])
2502 		{
2503 			if(MCS_rate[1] & BIT(7))
2504 				max_rate = (bw_40MHz) ? ((short_GI)?3000:2700):((short_GI)?1444:1300);
2505 			else if(MCS_rate[1] & BIT(6))
2506 				max_rate = (bw_40MHz) ? ((short_GI)?2700:2430):((short_GI)?1300:1170);
2507 			else if(MCS_rate[1] & BIT(5))
2508 				max_rate = (bw_40MHz) ? ((short_GI)?2400:2160):((short_GI)?1156:1040);
2509 			else if(MCS_rate[1] & BIT(4))
2510 				max_rate = (bw_40MHz) ? ((short_GI)?1800:1620):((short_GI)?867:780);
2511 			else if(MCS_rate[1] & BIT(3))
2512 				max_rate = (bw_40MHz) ? ((short_GI)?1200:1080):((short_GI)?578:520);
2513 			else if(MCS_rate[1] & BIT(2))
2514 				max_rate = (bw_40MHz) ? ((short_GI)?900:810):((short_GI)?433:390);
2515 			else if(MCS_rate[1] & BIT(1))
2516 				max_rate = (bw_40MHz) ? ((short_GI)?600:540):((short_GI)?289:260);
2517 			else if(MCS_rate[1] & BIT(0))
2518 				max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130);
2519 		}
2520 		else
2521 		{
2522 			if(MCS_rate[0] & BIT(7))
2523 				max_rate = (bw_40MHz) ? ((short_GI)?1500:1350):((short_GI)?722:650);
2524 			else if(MCS_rate[0] & BIT(6))
2525 				max_rate = (bw_40MHz) ? ((short_GI)?1350:1215):((short_GI)?650:585);
2526 			else if(MCS_rate[0] & BIT(5))
2527 				max_rate = (bw_40MHz) ? ((short_GI)?1200:1080):((short_GI)?578:520);
2528 			else if(MCS_rate[0] & BIT(4))
2529 				max_rate = (bw_40MHz) ? ((short_GI)?900:810):((short_GI)?433:390);
2530 			else if(MCS_rate[0] & BIT(3))
2531 				max_rate = (bw_40MHz) ? ((short_GI)?600:540):((short_GI)?289:260);
2532 			else if(MCS_rate[0] & BIT(2))
2533 				max_rate = (bw_40MHz) ? ((short_GI)?450:405):((short_GI)?217:195);
2534 			else if(MCS_rate[0] & BIT(1))
2535 				max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130);
2536 			else if(MCS_rate[0] & BIT(0))
2537 				max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65);
2538 		}
2539 	}
2540 	return max_rate;
2541 }
2542 
rtw_action_frame_parse(const u8 * frame,u32 frame_len,u8 * category,u8 * action)2543 int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8* category, u8 *action)
2544 {
2545 	const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
2546 	u16 fc;
2547 	u8 c;
2548 	u8 a = ACT_PUBLIC_MAX;
2549 
2550 	fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl);
2551 
2552 	if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE))
2553 		!= (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION)
2554 	)
2555 	{
2556 		return _FALSE;
2557 	}
2558 
2559 	c = frame_body[0];
2560 
2561 	switch(c) {
2562 	case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */
2563 		break;
2564 	default:
2565 		a = frame_body[1];
2566 	}
2567 
2568 	if (category)
2569 		*category = c;
2570 	if (action)
2571 		*action = a;
2572 
2573 	return _TRUE;
2574 }
2575 
2576 static const char *_action_public_str[] = {
2577 	"ACT_PUB_BSSCOEXIST",
2578 	"ACT_PUB_DSE_ENABLE",
2579 	"ACT_PUB_DSE_DEENABLE",
2580 	"ACT_PUB_DSE_REG_LOCATION",
2581 	"ACT_PUB_EXT_CHL_SWITCH",
2582 	"ACT_PUB_DSE_MSR_REQ",
2583 	"ACT_PUB_DSE_MSR_RPRT",
2584 	"ACT_PUB_MP",
2585 	"ACT_PUB_DSE_PWR_CONSTRAINT",
2586 	"ACT_PUB_VENDOR",
2587 	"ACT_PUB_GAS_INITIAL_REQ",
2588 	"ACT_PUB_GAS_INITIAL_RSP",
2589 	"ACT_PUB_GAS_COMEBACK_REQ",
2590 	"ACT_PUB_GAS_COMEBACK_RSP",
2591 	"ACT_PUB_TDLS_DISCOVERY_RSP",
2592 	"ACT_PUB_LOCATION_TRACK",
2593 	"ACT_PUB_RSVD",
2594 };
2595 
action_public_str(u8 action)2596 const char *action_public_str(u8 action)
2597 {
2598 	action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action;
2599 	return _action_public_str[action];
2600 }
2601 
2602