xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlan/mlan_scan.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file mlan_scan.c
2  *
3  *  @brief Functions implementing wlan scan IOCTL and firmware command APIs
4  *
5  *  IOCTL handlers as well as command preparation and response routines
6  *  for sending scan commands to the firmware.
7  *
8  *  Copyright (C) 2008-2017, Marvell International Ltd.
9  *
10  *  This software file (the "File") is distributed by Marvell International
11  *  Ltd. under the terms of the GNU General Public License Version 2, June 1991
12  *  (the "License").  You may use, redistribute and/or modify this File in
13  *  accordance with the terms and conditions of the License, a copy of which
14  *  is available by writing to the Free Software Foundation, Inc.,
15  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
16  *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
17  *
18  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
19  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
20  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
21  *  this warranty disclaimer.
22  */
23 
24 /******************************************************
25 Change log:
26     10/28/2008: initial version
27 ******************************************************/
28 
29 #include "mlan.h"
30 #include "mlan_join.h"
31 #include "mlan_util.h"
32 #include "mlan_fw.h"
33 #include "mlan_main.h"
34 #include "mlan_11n.h"
35 #include "mlan_11h.h"
36 #ifdef DRV_EMBEDDED_SUPPLICANT
37 #include "authenticator_api.h"
38 #endif
39 /********************************************************
40 			Local Constants
41 ********************************************************/
42 #define MRVDRV_MAX_CHANNELS_PER_SCAN     40
43 /** The maximum number of channels the firmware can scan per command */
44 #define MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN   4
45 
46 /**
47  * Number of channels to scan per firmware scan command issuance.
48  *
49  * Number restricted to prevent hitting the limit on the amount of scan data
50  * returned in a single firmware scan command.
51  */
52 #define MRVDRV_CHANNELS_PER_SCAN_CMD            4
53 
54 /** Memory needed to store a max sized Channel List TLV for a firmware scan */
55 #define CHAN_TLV_MAX_SIZE  (sizeof(MrvlIEtypesHeader_t)                  \
56 				+ (MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN \
57 				* sizeof(ChanScanParamSet_t)))
58 
59 /** Memory needed to store supported rate */
60 #define RATE_TLV_MAX_SIZE   (sizeof(MrvlIEtypes_RatesParamSet_t) + HOSTCMD_SUPPORTED_RATES)
61 
62 /** Memory needed to store a max number/size WildCard
63  *  SSID TLV for a firmware scan */
64 #define WILDCARD_SSID_TLV_MAX_SIZE                     \
65 		(MRVDRV_MAX_SSID_LIST_LENGTH  *                \
66 		 (sizeof(MrvlIEtypes_WildCardSsIdParamSet_t) + \
67 		  MRVDRV_MAX_SSID_LENGTH))
68 
69 /** WPS TLV MAX size is MAX IE size plus 2 bytes for
70  *  t_u16 MRVL TLV extension */
71 #define WPS_TLV_MAX_SIZE   (sizeof(IEEEtypes_VendorSpecific_t) + 2)
72 /** Maximum memory needed for a wlan_scan_cmd_config
73  *  with all TLVs at max */
74 #define MAX_SCAN_CFG_ALLOC (sizeof(wlan_scan_cmd_config)        \
75 				+ sizeof(MrvlIEtypes_NumProbes_t)   \
76 				+ sizeof(MrvlIETypes_HTCap_t)       \
77 				+ CHAN_TLV_MAX_SIZE                 \
78 				+ RATE_TLV_MAX_SIZE                 \
79 				+ WILDCARD_SSID_TLV_MAX_SIZE        \
80 				+ WPS_TLV_MAX_SIZE)
81 
82 /********************************************************
83 			Local Variables
84 ********************************************************/
85 
86 /**
87  * Interally used to send a configured scan cmd between
88  * driver routines
89  */
90 typedef union {
91     /** Scan configuration (variable length) */
92 	wlan_scan_cmd_config config;
93     /** Max allocated block */
94 	t_u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
95 } wlan_scan_cmd_config_tlv;
96 
97 /********************************************************
98 			Global Variables
99 ********************************************************/
100 
101 /********************************************************
102 			Local Functions
103 ********************************************************/
104 /** Cipher suite definition */
105 enum cipher_suite {
106 	CIPHER_SUITE_WEP40,
107 	CIPHER_SUITE_TKIP,
108 	CIPHER_SUITE_CCMP,
109 	CIPHER_SUITE_WEP104,
110 	CIPHER_SUITE_MAX
111 };
112 
113 static t_u8 wpa_oui[CIPHER_SUITE_MAX][4] = {
114 	{0x00, 0x50, 0xf2, 0x01},	/* WEP40 */
115 	{0x00, 0x50, 0xf2, 0x02},	/* TKIP */
116 	{0x00, 0x50, 0xf2, 0x04},	/* AES */
117 	{0x00, 0x50, 0xf2, 0x05},	/* WEP104 */
118 };
119 
120 static t_u8 rsn_oui[CIPHER_SUITE_MAX][4] = {
121 	{0x00, 0x0f, 0xac, 0x01},	/* WEP40 */
122 	{0x00, 0x0f, 0xac, 0x02},	/* TKIP */
123 	{0x00, 0x0f, 0xac, 0x04},	/* AES */
124 	{0x00, 0x0f, 0xac, 0x05},	/* WEP104 */
125 };
126 
127 /**
128  *  @brief Convert radio type scan parameter to a band config used in join cmd
129  *
130  *  @param radio_type Scan parameter indicating the radio used for a channel
131  *                    in a scan command.
132  *
133  *  @return          Band type conversion of scanBand used in join/assoc cmds
134  *
135  */
136 t_u8
radio_type_to_band(t_u8 radio_type)137 radio_type_to_band(t_u8 radio_type)
138 {
139 	t_u8 ret_band;
140 
141 	switch (radio_type) {
142 	case BAND_5GHZ:
143 		ret_band = BAND_A;
144 		break;
145 	case BAND_2GHZ:
146 	default:
147 		ret_band = BAND_G;
148 		break;
149 	}
150 
151 	return ret_band;
152 }
153 
154 /**
155  *  @brief This function will update the channel statistics from scan result
156  *
157  *  @param pmpriv           A pointer to mlan_private structure
158  *  @param pchanstats_tlv   A pointer to MrvlIEtypes_ChannelStats_t tlv
159  *
160  *  @return                NA
161  */
162 void
wlan_update_chan_statistics(mlan_private * pmpriv,MrvlIEtypes_ChannelStats_t * pchanstats_tlv)163 wlan_update_chan_statistics(mlan_private *pmpriv,
164 			    MrvlIEtypes_ChannelStats_t *pchanstats_tlv)
165 {
166 	mlan_adapter *pmadapter = pmpriv->adapter;
167 	t_u8 i;
168 	ChanStatistics_t *pchan_stats =
169 		(ChanStatistics_t *)((t_u8 *)pchanstats_tlv +
170 				     sizeof(MrvlIEtypesHeader_t));
171 	t_u8 num_chan =
172 		wlan_le16_to_cpu(pchanstats_tlv->header.len) /
173 		sizeof(ChanStatistics_t);
174 
175 	ENTER();
176 
177 	for (i = 0; i < num_chan; i++) {
178 		if (pmadapter->idx_chan_stats >= pmadapter->num_in_chan_stats) {
179 			PRINTM(MERROR,
180 			       "Over flow: idx_chan_stats=%d, num_in_chan_stats=%d\n",
181 			       pmadapter->idx_chan_stats,
182 			       pmadapter->num_in_chan_stats);
183 			break;
184 		}
185 		pchan_stats->total_networks =
186 			wlan_le16_to_cpu(pchan_stats->total_networks);
187 		pchan_stats->cca_scan_duration =
188 			wlan_le16_to_cpu(pchan_stats->cca_scan_duration);
189 		pchan_stats->cca_busy_duration =
190 			wlan_le16_to_cpu(pchan_stats->cca_busy_duration);
191 		PRINTM(MCMND,
192 		       "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
193 		       pchan_stats->chan_num, pchan_stats->noise,
194 		       pchan_stats->total_networks,
195 		       pchan_stats->cca_scan_duration,
196 		       pchan_stats->cca_busy_duration);
197 		memcpy(pmadapter,
198 		       &pmadapter->pchan_stats[pmadapter->idx_chan_stats],
199 		       pchan_stats, sizeof(ChanStatistics_t));
200 		pmadapter->idx_chan_stats++;
201 		pchan_stats++;
202 	}
203 	LEAVE();
204 	return;
205 }
206 
207 /**
208  *  @brief This function will parse a given IE for a given OUI
209  *
210  *  Parse a given WPA/RSN IE to find if it has a given oui in PTK,
211  *  if no OUI found for PTK it returns 0.
212  *
213  *  @param pbss_desc       A pointer to current BSS descriptor
214  *  @return                0 on failure to find OUI, 1 on success.
215  */
216 static t_u8
search_oui_in_ie(mlan_adapter * pmadapter,IEBody * ie_body,t_u8 * oui)217 search_oui_in_ie(mlan_adapter *pmadapter, IEBody *ie_body, t_u8 *oui)
218 {
219 	t_u8 count;
220 
221 	count = ie_body->PtkCnt[0];
222 
223 	ENTER();
224 	/* There could be multiple OUIs for PTK hence
225 	 * 1) Take the length.
226 	 * 2) Check all the OUIs for AES.
227 	 * 3) If one of them is AES then pass success.
228 	 */
229 	while (count) {
230 		if (!memcmp
231 		    (pmadapter, ie_body->PtkBody, oui,
232 		     sizeof(ie_body->PtkBody))) {
233 			LEAVE();
234 			return MLAN_OUI_PRESENT;
235 		}
236 
237 		--count;
238 		if (count) {
239 			ie_body = (IEBody *)((t_u8 *)ie_body +
240 					     sizeof(ie_body->PtkBody));
241 		}
242 	}
243 
244 	PRINTM(MINFO, "The OUI %x:%x:%x:%x is not found in PTK\n", oui[0],
245 	       oui[1], oui[2], oui[3]);
246 	LEAVE();
247 	return MLAN_OUI_NOT_PRESENT;
248 }
249 
250 /**
251  *  @brief This function will pass the correct ie and oui to search_oui_in_ie
252  *
253  *  Check the pbss_desc for appropriate IE and then check if RSN IE has AES
254  *  OUI in it. If RSN IE does not have AES in PTK then return 0;
255  *
256  *  @param pbss_desc       A pointer to current BSS descriptor
257  *  @return                0 on failure to find AES OUI, 1 on success.
258  */
259 static t_u8
is_rsn_oui_present(mlan_adapter * pmadapter,BSSDescriptor_t * pbss_desc,t_u32 cipher_suite)260 is_rsn_oui_present(mlan_adapter *pmadapter, BSSDescriptor_t *pbss_desc,
261 		   t_u32 cipher_suite)
262 {
263 	t_u8 *oui = MNULL;
264 	IEBody *ie_body = MNULL;
265 	t_u8 ret = MLAN_OUI_NOT_PRESENT;
266 
267 	ENTER();
268 	if (((pbss_desc->prsn_ie) &&
269 	     ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
270 		ie_body =
271 			(IEBody *)(((t_u8 *)pbss_desc->prsn_ie->data) +
272 				   RSN_GTK_OUI_OFFSET);
273 		oui = &rsn_oui[cipher_suite][0];
274 		ret = search_oui_in_ie(pmadapter, ie_body, oui);
275 		if (ret) {
276 			LEAVE();
277 			return ret;
278 		}
279 	}
280 	LEAVE();
281 	return ret;
282 }
283 
284 /**
285  *  @brief This function will pass the correct ie and oui to search_oui_in_ie
286  *
287  *  Check the pbss_desc for appropriate IE and then check if WPA IE has AES
288  *  OUI in it. If WPA IE does not have AES in PTK then return 0;
289  *
290  *  @param pbss_desc       A pointer to current BSS descriptor
291  *  @return                0 on failure to find AES OUI, 1 on success.
292  */
293 static t_u8
is_wpa_oui_present(mlan_adapter * pmadapter,BSSDescriptor_t * pbss_desc,t_u32 cipher_suite)294 is_wpa_oui_present(mlan_adapter *pmadapter, BSSDescriptor_t *pbss_desc,
295 		   t_u32 cipher_suite)
296 {
297 	t_u8 *oui = MNULL;
298 	IEBody *ie_body = MNULL;
299 	t_u8 ret = MLAN_OUI_NOT_PRESENT;
300 
301 	ENTER();
302 	if (((pbss_desc->pwpa_ie) &&
303 	     ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE))) {
304 		ie_body = (IEBody *)pbss_desc->pwpa_ie->data;
305 		oui = &wpa_oui[cipher_suite][0];
306 		ret = search_oui_in_ie(pmadapter, ie_body, oui);
307 		if (ret) {
308 			LEAVE();
309 			return ret;
310 		}
311 	}
312 	LEAVE();
313 	return ret;
314 }
315 
316 /**
317  *  @brief compare config band and a band from the scan result,
318  *  which is defined by functiion radio_type_to_band(t_u8 radio_type) above
319  *
320  *  @param cfg_band:  band configured
321  *         scan_band: band from scan result
322  *
323  *  @return  matched: non-zero. unmatched: 0
324  *
325  */
326 static t_u8
wlan_is_band_compatible(t_u8 cfg_band,t_u8 scan_band)327 wlan_is_band_compatible(t_u8 cfg_band, t_u8 scan_band)
328 {
329 	t_u8 band;
330 	switch (scan_band) {
331 	case BAND_A:
332 		band = BAND_A | BAND_AN;
333 		break;
334 	case BAND_G:
335 	default:
336 		band = BAND_B | BAND_G | BAND_GN;
337 	}
338 	return cfg_band & band;
339 }
340 
341 /**
342  *  @brief This function finds the best SSID in the Scan List
343  *
344  *  Search the scan table for the best SSID that also matches the current
345  *   adapter network preference (infrastructure or adhoc)
346  *
347  *  @param pmpriv       A pointer to mlan_private structure
348  *  @return             index in BSSID list
349  */
350 static t_s32
wlan_find_best_network_in_list(IN mlan_private * pmpriv)351 wlan_find_best_network_in_list(IN mlan_private *pmpriv)
352 {
353 	mlan_adapter *pmadapter = pmpriv->adapter;
354 	t_u32 mode = pmpriv->bss_mode;
355 	t_s32 best_net = -1;
356 	t_s32 best_rssi = 0;
357 	t_u32 i;
358 
359 	ENTER();
360 
361 	PRINTM(MINFO, "Num of BSSIDs = %d\n", pmadapter->num_in_scan_table);
362 
363 	for (i = 0; i < pmadapter->num_in_scan_table; i++) {
364 		switch (mode) {
365 		case MLAN_BSS_MODE_INFRA:
366 		case MLAN_BSS_MODE_IBSS:
367 			if (wlan_is_network_compatible(pmpriv, i, mode) >= 0) {
368 				if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
369 				    best_rssi) {
370 					best_rssi =
371 						SCAN_RSSI(pmadapter->
372 							  pscan_table[i].rssi);
373 					best_net = i;
374 				}
375 			}
376 			break;
377 		case MLAN_BSS_MODE_AUTO:
378 		default:
379 			if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
380 			    best_rssi) {
381 				best_rssi =
382 					SCAN_RSSI(pmadapter->pscan_table[i].
383 						  rssi);
384 				best_net = i;
385 			}
386 			break;
387 		}
388 	}
389 
390 	LEAVE();
391 	return best_net;
392 }
393 
394 /**
395  *  @brief Create a channel list for the driver to scan based on region info
396  *
397  *  Use the driver region/band information to construct a comprehensive list
398  *    of channels to scan.  This routine is used for any scan that is not
399  *    provided a specific channel list to scan.
400  *
401  *  @param pmpriv           A pointer to mlan_private structure
402  *  @param puser_scan_in    MNULL or pointer to scan configuration parameters
403  *  @param pscan_chan_list  Output parameter: Resulting channel list to scan
404  *  @param filtered_scan    Flag indicating whether or not a BSSID or SSID filter
405  *                          is being sent in the command to firmware.  Used to
406  *                          increase the number of channels sent in a scan
407  *                          command and to disable the firmware channel scan
408  *                          filter.
409  *
410  *  @return                 N/A
411  */
412 static t_void
wlan_scan_create_channel_list(IN mlan_private * pmpriv,IN const wlan_user_scan_cfg * puser_scan_in,OUT ChanScanParamSet_t * pscan_chan_list,IN t_u8 filtered_scan)413 wlan_scan_create_channel_list(IN mlan_private *pmpriv,
414 			      IN const wlan_user_scan_cfg *puser_scan_in,
415 			      OUT ChanScanParamSet_t *pscan_chan_list,
416 			      IN t_u8 filtered_scan)
417 {
418 	mlan_adapter *pmadapter = pmpriv->adapter;
419 	region_chan_t *pscan_region;
420 	chan_freq_power_t *cfp;
421 	t_u32 region_idx;
422 	t_u32 chan_idx = 0;
423 	t_u32 next_chan;
424 	t_u8 scan_type;
425 	t_u8 radio_type;
426 
427 	ENTER();
428 
429 	for (region_idx = 0;
430 	     region_idx < NELEMENTS(pmadapter->region_channel); region_idx++) {
431 
432 		if (wlan_11d_is_enabled(pmpriv) &&
433 		    pmpriv->media_connected != MTRUE) {
434 			/* Scan all the supported chan for the first scan */
435 			if (!pmadapter->universal_channel[region_idx].valid)
436 				continue;
437 			pscan_region =
438 				&pmadapter->universal_channel[region_idx];
439 		} else {
440 			if (!pmadapter->region_channel[region_idx].valid)
441 				continue;
442 			pscan_region = &pmadapter->region_channel[region_idx];
443 		}
444 
445 		if (puser_scan_in && !puser_scan_in->chan_list[0].chan_number &&
446 		    puser_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
447 			radio_type =
448 				puser_scan_in->chan_list[0].
449 				radio_type & ~BAND_SPECIFIED;
450 			if (!radio_type && (pscan_region->band != BAND_B) &&
451 			    (pscan_region->band != BAND_G))
452 				continue;
453 			if (radio_type && (pscan_region->band != BAND_A))
454 				continue;
455 		}
456 		if (!wlan_is_band_compatible
457 		    (pmpriv->config_bands | pmadapter->adhoc_start_band,
458 		     pscan_region->band))
459 			continue;
460 		for (next_chan = 0;
461 		     next_chan < pscan_region->num_cfp;
462 		     next_chan++, chan_idx++) {
463 			/* Set the default scan type to the user specified type, will later
464 			 *   be changed to passive on a per channel basis if restricted by
465 			 *   regulatory requirements (11d or 11h)
466 			 */
467 			scan_type = pmadapter->scan_type;
468 			cfp = pscan_region->pcfp + next_chan;
469 
470 			switch (pscan_region->band) {
471 			case BAND_A:
472 				pscan_chan_list[chan_idx].bandcfg.chanBand =
473 					BAND_5GHZ;
474 				/* Passive scan on DFS channels */
475 				if (wlan_11h_radar_detect_required
476 				    (pmpriv, (t_u8)cfp->channel))
477 					scan_type = MLAN_SCAN_TYPE_PASSIVE;
478 				break;
479 			case BAND_B:
480 			case BAND_G:
481 				if (wlan_bg_scan_type_is_passive
482 				    (pmpriv, (t_u8)cfp->channel)) {
483 					scan_type = MLAN_SCAN_TYPE_PASSIVE;
484 				}
485 				pscan_chan_list[chan_idx].bandcfg.chanBand =
486 					BAND_2GHZ;
487 				break;
488 			default:
489 				pscan_chan_list[chan_idx].bandcfg.chanBand =
490 					BAND_2GHZ;
491 				break;
492 			}
493 
494 			if (puser_scan_in &&
495 			    puser_scan_in->chan_list[0].scan_time) {
496 				pscan_chan_list[chan_idx].max_scan_time =
497 					wlan_cpu_to_le16((t_u16)puser_scan_in->
498 							 chan_list[0].
499 							 scan_time);
500 			} else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
501 				pscan_chan_list[chan_idx].max_scan_time =
502 					wlan_cpu_to_le16(pmadapter->
503 							 passive_scan_time);
504 			} else if (filtered_scan) {
505 				pscan_chan_list[chan_idx].max_scan_time =
506 					wlan_cpu_to_le16(pmadapter->
507 							 specific_scan_time);
508 			} else {
509 				pscan_chan_list[chan_idx].max_scan_time =
510 					wlan_cpu_to_le16(pmadapter->
511 							 active_scan_time);
512 			}
513 
514 			if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
515 				pscan_chan_list[chan_idx].chan_scan_mode.
516 					passive_scan = MTRUE;
517 				pscan_chan_list[chan_idx].chan_scan_mode.
518 					hidden_ssid_report = MTRUE;
519 			} else {
520 				pscan_chan_list[chan_idx].chan_scan_mode.
521 					passive_scan = MFALSE;
522 			}
523 
524 			pscan_chan_list[chan_idx].chan_number =
525 				(t_u8)cfp->channel;
526 
527 			if (filtered_scan) {
528 				pscan_chan_list[chan_idx].chan_scan_mode.
529 					disable_chan_filt = MTRUE;
530 			}
531 		}
532 	}
533 
534 	LEAVE();
535 }
536 
537 /**
538  *  @brief Add WPS IE to probe request frame
539  *
540  *  @param pmpriv             A pointer to mlan_private structure
541  *  @param pptlv_out          A pointer to TLV to fill in
542  *
543  *  @return                   N/A
544  */
545 static void
wlan_add_wps_probe_request_ie(IN mlan_private * pmpriv,OUT t_u8 ** pptlv_out)546 wlan_add_wps_probe_request_ie(IN mlan_private *pmpriv, OUT t_u8 **pptlv_out)
547 {
548 	MrvlIEtypesHeader_t *tlv;
549 
550 	ENTER();
551 
552 	if (pmpriv->wps.wps_ie.vend_hdr.len) {
553 		tlv = (MrvlIEtypesHeader_t *)*pptlv_out;
554 		tlv->type = wlan_cpu_to_le16(VENDOR_SPECIFIC_221);
555 		tlv->len = wlan_cpu_to_le16(pmpriv->wps.wps_ie.vend_hdr.len);
556 		*pptlv_out += sizeof(MrvlIEtypesHeader_t);
557 		memcpy(pmpriv->adapter, *pptlv_out,
558 		       pmpriv->wps.wps_ie.vend_hdr.oui,
559 		       pmpriv->wps.wps_ie.vend_hdr.len);
560 		*pptlv_out += (pmpriv->wps.wps_ie.vend_hdr.len
561 			       + sizeof(MrvlIEtypesHeader_t));
562 	}
563 	LEAVE();
564 }
565 
566 /**
567  *  @brief Construct and send multiple scan config commands to the firmware
568  *
569  *  Previous routines have created a wlan_scan_cmd_config with any requested
570  *   TLVs.  This function splits the channel TLV into max_chan_per_scan lists
571  *   and sends the portion of the channel TLV along with the other TLVs
572  *   to the wlan_cmd routines for execution in the firmware.
573  *
574  *  @param pmpriv             A pointer to mlan_private structure
575  *  @param pioctl_buf         A pointer to MLAN IOCTL Request buffer
576  *  @param max_chan_per_scan  Maximum number channels to be included in each
577  *                            scan command sent to firmware
578  *  @param filtered_scan      Flag indicating whether or not a BSSID or SSID
579  *                            filter is being used for the firmware command
580  *                            scan command sent to firmware
581  *  @param pscan_cfg_out      Scan configuration used for this scan.
582  *  @param pchan_tlv_out      Pointer in the pscan_cfg_out where the channel TLV
583  *                            should start.  This is past any other TLVs that
584  *                            must be sent down in each firmware command.
585  *  @param pscan_chan_list    List of channels to scan in max_chan_per_scan segments
586  *
587  *  @return                   MLAN_STATUS_SUCCESS or error return otherwise
588  */
589 static mlan_status
wlan_scan_channel_list(IN mlan_private * pmpriv,IN t_void * pioctl_buf,IN t_u32 max_chan_per_scan,IN t_u8 filtered_scan,OUT wlan_scan_cmd_config * pscan_cfg_out,OUT MrvlIEtypes_ChanListParamSet_t * pchan_tlv_out,IN ChanScanParamSet_t * pscan_chan_list)590 wlan_scan_channel_list(IN mlan_private *pmpriv,
591 		       IN t_void *pioctl_buf,
592 		       IN t_u32 max_chan_per_scan,
593 		       IN t_u8 filtered_scan,
594 		       OUT wlan_scan_cmd_config *pscan_cfg_out,
595 		       OUT MrvlIEtypes_ChanListParamSet_t *pchan_tlv_out,
596 		       IN ChanScanParamSet_t *pscan_chan_list)
597 {
598 	mlan_status ret = MLAN_STATUS_SUCCESS;
599 	mlan_adapter *pmadapter = pmpriv->adapter;
600 	ChanScanParamSet_t *ptmp_chan_list;
601 	ChanScanParamSet_t *pstart_chan;
602 	pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
603 	t_u8 *pchan_tlv_out_temp = MNULL;
604 	t_u8 *ptlv_temp = MNULL;
605 	t_bool foundJPch14 = MFALSE;
606 	t_u16 tlv_buf_len = 0;
607 	t_u32 tlv_idx;
608 	t_u32 total_scan_time;
609 	t_u32 done_early;
610 	t_u32 cmd_no;
611 	t_u32 first_chan = 1;
612 	mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
613 
614 	ENTER();
615 
616 	if (!pscan_cfg_out || !pchan_tlv_out || !pscan_chan_list) {
617 		PRINTM(MINFO, "Scan: Null detect: %p, %p, %p\n",
618 		       pscan_cfg_out, pchan_tlv_out, pscan_chan_list);
619 		if (pioctl_req)
620 			pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
621 		LEAVE();
622 		return MLAN_STATUS_FAILURE;
623 	}
624 	if (!pscan_chan_list->chan_number) {
625 		PRINTM(MERROR, "Scan: No channel configured\n");
626 		if (pioctl_req)
627 			pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
628 		LEAVE();
629 		return MLAN_STATUS_FAILURE;
630 	}
631 
632 	/* check expiry before preparing scan list - may affect blacklist */
633 	wlan_11h_get_csa_closed_channel(pmpriv);
634 
635 	pchan_tlv_out->header.type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
636 
637 	/* Set the temp channel struct pointer to the start of the desired list */
638 	ptmp_chan_list = pscan_chan_list;
639 
640 	/*
641 	 * Loop through the desired channel list, sending a new firmware scan
642 	 * commands for each max_chan_per_scan channels (or for 1,6,11
643 	 * individually if configured accordingly)
644 	 */
645 	while (ptmp_chan_list->chan_number) {
646 
647 		tlv_idx = 0;
648 		total_scan_time = 0;
649 		pchan_tlv_out->header.len = 0;
650 		pstart_chan = ptmp_chan_list;
651 		done_early = MFALSE;
652 
653 		/*
654 		 * Construct the Channel TLV for the scan command.  Continue to
655 		 * insert channel TLVs until:
656 		 *   - the tlv_idx hits the maximum configured per scan command
657 		 *   - the next channel to insert is 0 (end of desired
658 		 *     channel list)
659 		 *   - done_early is set (controlling individual
660 		 *     scanning of 1,6,11)
661 		 */
662 		while (tlv_idx < max_chan_per_scan &&
663 		       ptmp_chan_list->chan_number && !done_early) {
664 			if (wlan_is_chan_blacklisted
665 			    (pmpriv,
666 			     radio_type_to_band(ptmp_chan_list->bandcfg.
667 						chanBand),
668 			     ptmp_chan_list->chan_number) ||
669 			    wlan_is_chan_disabled(pmpriv,
670 						  radio_type_to_band
671 						  (ptmp_chan_list->bandcfg.
672 						   chanBand),
673 						  ptmp_chan_list->
674 						  chan_number)) {
675 				ptmp_chan_list++;
676 				continue;
677 			}
678 
679 			if (first_chan) {
680 				ptmp_chan_list->chan_scan_mode.first_chan =
681 					MTRUE;
682 				first_chan = 0;
683 			}
684 
685 			PRINTM(MINFO,
686 			       "Scan: Chan(%3d), bandcfg(%x), Mode(%d,%d), Dur(%d)\n",
687 			       ptmp_chan_list->chan_number,
688 			       ptmp_chan_list->bandcfg,
689 			       ptmp_chan_list->chan_scan_mode.passive_scan,
690 			       ptmp_chan_list->chan_scan_mode.disable_chan_filt,
691 			       wlan_le16_to_cpu(ptmp_chan_list->max_scan_time));
692 
693 			if (foundJPch14 == MTRUE) {
694 				foundJPch14 = MFALSE;
695 				/* Restore the TLV buffer */
696 				pchan_tlv_out =
697 					(MrvlIEtypes_ChanListParamSet_t *)
698 					pchan_tlv_out_temp;
699 				pchan_tlv_out->header.type =
700 					wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
701 				pchan_tlv_out->header.len = 0;
702 				if (ptlv_temp) {
703 					memcpy(pmadapter,
704 					       pscan_cfg_out->tlv_buf,
705 					       ptlv_temp, tlv_buf_len);
706 					pcb->moal_mfree(pmadapter->pmoal_handle,
707 							ptlv_temp);
708 					ptlv_temp = MNULL;
709 				}
710 			}
711 
712 			/* Special Case: For Japan, Scan on CH14 for 11G rates is not allowed
713 			   Hence Rates TLV needs to be updated to support only 11B rates */
714 			if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
715 			     pmadapter->region_code == COUNTRY_CODE_JP_FF)
716 			    && (ptmp_chan_list->chan_number == 14)
717 			    && (pmadapter->ext_scan_type != EXT_SCAN_ENHANCE)
718 				) {
719 
720 				t_u8 *ptlv_pos = pscan_cfg_out->tlv_buf;
721 				t_u16 old_ratetlv_len, new_ratetlv_len;
722 				MrvlIEtypesHeader_t *header;
723 				MrvlIEtypes_RatesParamSet_t *prates_tlv;
724 
725 				/* Preserve the current TLV buffer */
726 				ret = pcb->moal_malloc(pmadapter->pmoal_handle,
727 						       MAX_SCAN_CFG_ALLOC -
728 						       CHAN_TLV_MAX_SIZE,
729 						       MLAN_MEM_DEF,
730 						       (t_u8 **)&ptlv_temp);
731 				if (ret != MLAN_STATUS_SUCCESS || !ptlv_temp) {
732 					PRINTM(MERROR,
733 					       "Memory allocation for pscan_cfg_out failed!\n");
734 					if (pioctl_req)
735 						pioctl_req->status_code =
736 							MLAN_ERROR_NO_MEM;
737 					LEAVE();
738 					return MLAN_STATUS_FAILURE;
739 				}
740 				pchan_tlv_out_temp = (t_u8 *)pchan_tlv_out;
741 				tlv_buf_len =
742 					(t_u32)(pchan_tlv_out_temp -
743 						pscan_cfg_out->tlv_buf);
744 				memcpy(pmadapter, ptlv_temp, ptlv_pos,
745 				       tlv_buf_len);
746 
747 				/* Search for Rates TLV */
748 				while ((!foundJPch14) &&
749 				       (ptlv_pos < pchan_tlv_out_temp)) {
750 					header = (MrvlIEtypesHeader_t *)
751 						ptlv_pos;
752 					if (header->type ==
753 					    wlan_cpu_to_le16(TLV_TYPE_RATES))
754 						foundJPch14 = MTRUE;
755 					else
756 						ptlv_pos +=
757 							(sizeof
758 							 (MrvlIEtypesHeader_t) +
759 							 wlan_le16_to_cpu
760 							 (header->len));
761 				}
762 
763 				if (foundJPch14) {
764 					/* Update the TLV buffer with *new* Rates TLV and rearrange remaining TLV buffer */
765 					prates_tlv =
766 						(MrvlIEtypes_RatesParamSet_t *)
767 						ptlv_pos;
768 					old_ratetlv_len =
769 						sizeof(MrvlIEtypesHeader_t) +
770 						wlan_le16_to_cpu(prates_tlv->
771 								 header.len);
772 
773 					prates_tlv->header.len =
774 						wlan_copy_rates(prates_tlv->
775 								rates, 0,
776 								SupportedRates_B,
777 								sizeof
778 								(SupportedRates_B));
779 					new_ratetlv_len =
780 						sizeof(MrvlIEtypesHeader_t) +
781 						prates_tlv->header.len;
782 					prates_tlv->header.len =
783 						wlan_cpu_to_le16(prates_tlv->
784 								 header.len);
785 
786 					memmove(pmadapter,
787 						ptlv_pos + new_ratetlv_len,
788 						ptlv_pos + old_ratetlv_len,
789 						(t_u32)(pchan_tlv_out_temp -
790 							(ptlv_pos +
791 							 old_ratetlv_len)));
792 					pchan_tlv_out =
793 						(MrvlIEtypes_ChanListParamSet_t
794 						 *)
795 						(pchan_tlv_out_temp -
796 						 (old_ratetlv_len -
797 						  new_ratetlv_len));
798 					pchan_tlv_out->header.type =
799 						wlan_cpu_to_le16
800 						(TLV_TYPE_CHANLIST);
801 					pchan_tlv_out->header.len = 0;
802 				}
803 			}
804 
805 			/* Copy the current channel TLV to the command being prepared */
806 			memcpy(pmadapter,
807 			       pchan_tlv_out->chan_scan_param + tlv_idx,
808 			       ptmp_chan_list,
809 			       sizeof(pchan_tlv_out->chan_scan_param));
810 
811 			/* Increment the TLV header length by the size appended */
812 			pchan_tlv_out->header.len +=
813 				sizeof(pchan_tlv_out->chan_scan_param);
814 
815 			/*
816 			 * The tlv buffer length is set to the number of
817 			 * bytes of the between the channel tlv pointer
818 			 * and the start of the tlv buffer.  This
819 			 * compensates for any TLVs that were appended
820 			 * before the channel list.
821 			 */
822 			pscan_cfg_out->tlv_buf_len =
823 				(t_u32)((t_u8 *)pchan_tlv_out -
824 					pscan_cfg_out->tlv_buf);
825 
826 			/* Add the size of the channel tlv header and the data length */
827 			pscan_cfg_out->tlv_buf_len +=
828 				(sizeof(pchan_tlv_out->header)
829 				 + pchan_tlv_out->header.len);
830 
831 			/* Increment the index to the channel tlv we are constructing */
832 			tlv_idx++;
833 
834 			/* Count the total scan time per command */
835 			total_scan_time +=
836 				wlan_le16_to_cpu(ptmp_chan_list->max_scan_time);
837 
838 			done_early = MFALSE;
839 
840 			/*
841 			 * Stop the loop if the *current* channel is in the 1,6,11 set
842 			 * and we are not filtering on a BSSID or SSID.
843 			 */
844 			if (!filtered_scan &&
845 			    (ptmp_chan_list->chan_number == 1 ||
846 			     ptmp_chan_list->chan_number == 6 ||
847 			     ptmp_chan_list->chan_number == 11)) {
848 				done_early = MTRUE;
849 			}
850 
851 			/*
852 			 * Stop the loop if the *current* channel is 14
853 			 * and region code is Japan (0x40 or 0xFF)
854 			 */
855 			if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
856 			     pmadapter->region_code == COUNTRY_CODE_JP_FF)
857 			    && (ptmp_chan_list->chan_number == 14)) {
858 				done_early = MTRUE;
859 			}
860 
861 			/* Increment the tmp pointer to the next channel to be scanned */
862 			ptmp_chan_list++;
863 
864 			/*
865 			 * Stop the loop if the *next* channel is in the 1,6,11 set.
866 			 * This will cause it to be the only channel scanned on the next
867 			 * interation
868 			 */
869 			if (!filtered_scan &&
870 			    (ptmp_chan_list->chan_number == 1 ||
871 			     ptmp_chan_list->chan_number == 6 ||
872 			     ptmp_chan_list->chan_number == 11)) {
873 				done_early = MTRUE;
874 			}
875 
876 			/*
877 			 * Stop the loop if the *next* channel is 14
878 			 * and region code is Japan (0x40 or 0xFF)
879 			 */
880 			if ((pmadapter->region_code == COUNTRY_CODE_JP_40 ||
881 			     pmadapter->region_code == COUNTRY_CODE_JP_FF)
882 			    && (ptmp_chan_list->chan_number == 14)) {
883 				done_early = MTRUE;
884 			}
885 			if (pmadapter->ext_scan && pmadapter->ext_scan_enh &&
886 			    pmadapter->ext_scan_type == EXT_SCAN_ENHANCE)
887 				done_early = MFALSE;
888 		}
889 
890 		/* The total scan time should be less than scan command timeout value */
891 		if (total_scan_time > MRVDRV_MAX_TOTAL_SCAN_TIME) {
892 			PRINTM(MMSG,
893 			       "Total scan time %d ms is over limit (%d ms), scan skipped\n",
894 			       total_scan_time, MRVDRV_MAX_TOTAL_SCAN_TIME);
895 			if (pioctl_req)
896 				pioctl_req->status_code =
897 					MLAN_ERROR_CMD_SCAN_FAIL;
898 			ret = MLAN_STATUS_FAILURE;
899 			break;
900 		}
901 
902 		pchan_tlv_out->header.len =
903 			wlan_cpu_to_le16(pchan_tlv_out->header.len);
904 
905 		pmadapter->pscan_channels = pstart_chan;
906 
907 		/* Send the scan command to the firmware with the specified cfg */
908 		if (pmadapter->ext_scan)
909 			cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
910 		else
911 			cmd_no = HostCmd_CMD_802_11_SCAN;
912 		ret = wlan_prepare_cmd(pmpriv,
913 				       cmd_no,
914 				       HostCmd_ACT_GEN_SET,
915 				       0, MNULL, pscan_cfg_out);
916 		if (ret)
917 			break;
918 	}
919 
920 	LEAVE();
921 
922 	if (ptlv_temp)
923 		pcb->moal_mfree(pmadapter->pmoal_handle, ptlv_temp);
924 
925 	if (ret)
926 		return MLAN_STATUS_FAILURE;
927 
928 	return MLAN_STATUS_SUCCESS;
929 }
930 
931 /**
932  *  @brief Construct a wlan_scan_cmd_config structure to use in scan commands
933  *
934  *  Application layer or other functions can invoke wlan_scan_networks
935  *    with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
936  *    This structure is used as the basis of one or many wlan_scan_cmd_config
937  *    commands that are sent to the command processing module and sent to
938  *    firmware.
939  *
940  *  Create a wlan_scan_cmd_config based on the following user supplied
941  *    parameters (if present):
942  *             - SSID filter
943  *             - BSSID filter
944  *             - Number of Probes to be sent
945  *             - Channel list
946  *
947  *  If the SSID or BSSID filter is not present, disable/clear the filter.
948  *  If the number of probes is not set, use the adapter default setting
949  *  Qualify the channel
950  *
951  *  @param pmpriv              A pointer to mlan_private structure
952  *  @param puser_scan_in       MNULL or pointer to scan config parameters
953  *  @param pscan_cfg_out       Output parameter: Resulting scan configuration
954  *  @param ppchan_list_out     Output parameter: Pointer to the start of the
955  *                             channel TLV portion of the output scan config
956  *  @param pscan_chan_list     Output parameter: Pointer to the resulting
957  *                             channel list to scan
958  *  @param pmax_chan_per_scan  Output parameter: Number of channels to scan for
959  *                             each issuance of the firmware scan command
960  *  @param pfiltered_scan      Output parameter: Flag indicating whether or not
961  *                             a BSSID or SSID filter is being sent in the
962  *                             command to firmware. Used to increase the number
963  *                             of channels sent in a scan command and to
964  *                             disable the firmware channel scan filter.
965  *  @param pscan_current_only  Output parameter: Flag indicating whether or not
966  *                             we are only scanning our current active channel
967  *
968  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
969  */
970 static mlan_status
wlan_scan_setup_scan_config(IN mlan_private * pmpriv,IN wlan_user_scan_cfg * puser_scan_in,OUT wlan_scan_cmd_config * pscan_cfg_out,OUT MrvlIEtypes_ChanListParamSet_t ** ppchan_list_out,OUT ChanScanParamSet_t * pscan_chan_list,OUT t_u8 * pmax_chan_per_scan,OUT t_u8 * pfiltered_scan,OUT t_u8 * pscan_current_only)971 wlan_scan_setup_scan_config(IN mlan_private *pmpriv,
972 			    IN wlan_user_scan_cfg *puser_scan_in,
973 			    OUT wlan_scan_cmd_config *pscan_cfg_out,
974 			    OUT MrvlIEtypes_ChanListParamSet_t
975 			    **ppchan_list_out,
976 			    OUT ChanScanParamSet_t *pscan_chan_list,
977 			    OUT t_u8 *pmax_chan_per_scan,
978 			    OUT t_u8 *pfiltered_scan,
979 			    OUT t_u8 *pscan_current_only)
980 {
981 	mlan_adapter *pmadapter = pmpriv->adapter;
982 	mlan_status ret = MLAN_STATUS_SUCCESS;
983 	MrvlIEtypes_NumProbes_t *pnum_probes_tlv;
984 	MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv;
985 	MrvlIEtypes_RatesParamSet_t *prates_tlv;
986 	MrvlIEtypes_Bssid_List_t *pbssid_tlv;
987 
988 	const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 };
989 	t_u8 *ptlv_pos;
990 	t_u32 num_probes;
991 	t_u32 ssid_len;
992 	t_u32 chan_idx;
993 	t_u32 scan_type;
994 	t_u16 scan_dur;
995 	t_u8 channel;
996 	t_u8 radio_type;
997 	t_u32 ssid_idx;
998 	t_u8 ssid_filter;
999 	WLAN_802_11_RATES rates;
1000 	t_u32 rates_size;
1001 	MrvlIETypes_HTCap_t *pht_cap;
1002 
1003 	MrvlIEtypes_ScanChanGap_t *pscan_gap_tlv;
1004 	MrvlIEtypes_BssMode_t *pbss_mode;
1005 	ENTER();
1006 
1007 	/* The tlv_buf_len is calculated for each scan command.  The TLVs added
1008 	 *   in this routine will be preserved since the routine that sends
1009 	 *   the command will append channelTLVs at *ppchan_list_out.  The
1010 	 *   difference between the *ppchan_list_out and the tlv_buf start will be
1011 	 *   used to calculate the size of anything we add in this routine.
1012 	 */
1013 	pscan_cfg_out->tlv_buf_len = 0;
1014 
1015 	/* Running tlv pointer.  Assigned to ppchan_list_out at end of function
1016 	 *  so later routines know where channels can be added to the command buf
1017 	 */
1018 	ptlv_pos = pscan_cfg_out->tlv_buf;
1019 
1020 	/* Initialize the scan as un-filtered; the flag is later set to
1021 	 *   TRUE below if a SSID or BSSID filter is sent in the command
1022 	 */
1023 	*pfiltered_scan = MFALSE;
1024 
1025 	/* Initialize the scan as not being only on the current channel.  If
1026 	 *   the channel list is customized, only contains one channel, and
1027 	 *   is the active channel, this is set true and data flow is not halted.
1028 	 */
1029 	*pscan_current_only = MFALSE;
1030 
1031 	if (puser_scan_in) {
1032 
1033 		ssid_filter = MFALSE;
1034 
1035 		/* Set the bss type scan filter, use Adapter setting if unset */
1036 		pscan_cfg_out->bss_mode = (puser_scan_in->bss_mode
1037 					   ? (t_u8)puser_scan_in->bss_mode :
1038 					   (t_u8)pmadapter->scan_mode);
1039 
1040 		/* Set the number of probes to send, use Adapter setting if unset */
1041 		num_probes =
1042 			(puser_scan_in->num_probes ? puser_scan_in->
1043 			 num_probes : pmadapter->scan_probes);
1044 		/*
1045 		 * Set the BSSID filter to the incoming configuration,
1046 		 *  if non-zero.  If not set, it will remain disabled
1047 		 * (all zeros).
1048 		 */
1049 		memcpy(pmadapter, pscan_cfg_out->specific_bssid,
1050 		       puser_scan_in->specific_bssid,
1051 		       sizeof(pscan_cfg_out->specific_bssid));
1052 
1053 		if (pmadapter->ext_scan
1054 		    && memcmp(pmadapter, pscan_cfg_out->specific_bssid,
1055 			      &zero_mac, sizeof(zero_mac))) {
1056 			pbssid_tlv = (MrvlIEtypes_Bssid_List_t *)ptlv_pos;
1057 			pbssid_tlv->header.type = TLV_TYPE_BSSID;
1058 			pbssid_tlv->header.len = MLAN_MAC_ADDR_LENGTH;
1059 			memcpy(pmadapter, pbssid_tlv->bssid,
1060 			       puser_scan_in->specific_bssid,
1061 			       MLAN_MAC_ADDR_LENGTH);
1062 			ptlv_pos += sizeof(MrvlIEtypes_Bssid_List_t);
1063 		}
1064 
1065 		for (ssid_idx = 0;
1066 		     ((ssid_idx < NELEMENTS(puser_scan_in->ssid_list))
1067 		      && (*puser_scan_in->ssid_list[ssid_idx].ssid ||
1068 			  puser_scan_in->ssid_list[ssid_idx].max_len));
1069 		     ssid_idx++) {
1070 
1071 			ssid_len =
1072 				wlan_strlen((char *)puser_scan_in->
1073 					    ssid_list[ssid_idx].ssid);
1074 
1075 			pwildcard_ssid_tlv
1076 				=
1077 				(MrvlIEtypes_WildCardSsIdParamSet_t *)ptlv_pos;
1078 			pwildcard_ssid_tlv->header.type =
1079 				wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
1080 			pwildcard_ssid_tlv->header.len =
1081 				(t_u16)(ssid_len +
1082 					sizeof(pwildcard_ssid_tlv->
1083 					       max_ssid_length));
1084 			pwildcard_ssid_tlv->max_ssid_length =
1085 				puser_scan_in->ssid_list[ssid_idx].max_len;
1086 
1087 			memcpy(pmadapter, pwildcard_ssid_tlv->ssid,
1088 			       puser_scan_in->ssid_list[ssid_idx].ssid,
1089 			       MIN(MLAN_MAX_SSID_LENGTH, ssid_len));
1090 
1091 			ptlv_pos += (sizeof(pwildcard_ssid_tlv->header)
1092 				     + pwildcard_ssid_tlv->header.len);
1093 
1094 			pwildcard_ssid_tlv->header.len
1095 				=
1096 				wlan_cpu_to_le16(pwildcard_ssid_tlv->header.
1097 						 len);
1098 
1099 			PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n",
1100 			       ssid_idx,
1101 			       pwildcard_ssid_tlv->ssid,
1102 			       pwildcard_ssid_tlv->max_ssid_length);
1103 
1104 			if (ssid_len) {
1105 				ssid_filter = MTRUE;
1106 				if (!puser_scan_in->ssid_list[ssid_idx].max_len) {
1107 					PRINTM(MCMND, "user scan: %s\n",
1108 					       pwildcard_ssid_tlv->ssid);
1109 					puser_scan_in->ssid_filter = MTRUE;
1110 				}
1111 			}
1112 		}
1113 
1114 		/*
1115 		 *  The default number of channels sent in the command is low to
1116 		 *  ensure the response buffer from the firmware does not
1117 		 *  truncate scan results.  That is not an issue with an SSID or
1118 		 *  BSSID filter applied to the scan results in the firmware.
1119 		 */
1120 		if ((ssid_idx && ssid_filter) ||
1121 		    memcmp(pmadapter, pscan_cfg_out->specific_bssid, &zero_mac,
1122 			   sizeof(zero_mac))) {
1123 			*pfiltered_scan = MTRUE;
1124 		}
1125 
1126 	} else {
1127 		pscan_cfg_out->bss_mode = (t_u8)pmadapter->scan_mode;
1128 		num_probes = pmadapter->scan_probes;
1129 	}
1130 
1131 	/*
1132 	 *  If a specific BSSID or SSID is used, the number of channels in
1133 	 *  the scan command will be increased to the absolute maximum.
1134 	 */
1135 	if (*pfiltered_scan)
1136 		*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
1137 	else
1138 		*pmax_chan_per_scan = MRVDRV_CHANNELS_PER_SCAN_CMD;
1139 
1140 	if (puser_scan_in && puser_scan_in->scan_chan_gap) {
1141 		*pmax_chan_per_scan = MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
1142 		PRINTM(MINFO, "Scan: channel gap = %d\n",
1143 		       puser_scan_in->scan_chan_gap);
1144 		pscan_gap_tlv = (MrvlIEtypes_ScanChanGap_t *)ptlv_pos;
1145 		pscan_gap_tlv->header.type =
1146 			wlan_cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
1147 		pscan_gap_tlv->header.len = sizeof(pscan_gap_tlv->gap);
1148 		pscan_gap_tlv->gap =
1149 			wlan_cpu_to_le16((t_u16)puser_scan_in->scan_chan_gap);
1150 		ptlv_pos +=
1151 			sizeof(pscan_gap_tlv->header) +
1152 			pscan_gap_tlv->header.len;
1153 		pscan_gap_tlv->header.len =
1154 			wlan_cpu_to_le16(pscan_gap_tlv->header.len);
1155 	}
1156 	if (pmadapter->ext_scan) {
1157 		pbss_mode = (MrvlIEtypes_BssMode_t *) ptlv_pos;
1158 		pbss_mode->header.type = wlan_cpu_to_le16(TLV_TYPE_BSS_MODE);
1159 		pbss_mode->header.len = sizeof(pbss_mode->bss_mode);
1160 		pbss_mode->bss_mode = pscan_cfg_out->bss_mode;
1161 		ptlv_pos += sizeof(pbss_mode->header) + pbss_mode->header.len;
1162 		pbss_mode->header.len = wlan_cpu_to_le16(pbss_mode->header.len);
1163 		if (pmadapter->ext_scan_enh) {
1164 			if (puser_scan_in) {
1165 				if (puser_scan_in->ext_scan_type ==
1166 				    EXT_SCAN_ENHANCE)
1167 					pmadapter->ext_scan_type =
1168 						EXT_SCAN_ENHANCE;
1169 				else
1170 					pmadapter->ext_scan_type =
1171 						EXT_SCAN_DEFAULT;
1172 			} else if (pmadapter->ext_scan == EXT_SCAN_TYPE_ENH)
1173 				pmadapter->ext_scan_type = EXT_SCAN_ENHANCE;
1174 			else
1175 				pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
1176 			if (pmadapter->ext_scan_type == EXT_SCAN_ENHANCE)
1177 				*pmax_chan_per_scan =
1178 					MRVDRV_MAX_CHANNELS_PER_SCAN;
1179 		}
1180 	}
1181 	/* If the input config or adapter has the number of Probes set, add tlv */
1182 	if (num_probes) {
1183 
1184 		PRINTM(MINFO, "Scan: num_probes = %d\n", num_probes);
1185 
1186 		pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *)ptlv_pos;
1187 		pnum_probes_tlv->header.type =
1188 			wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
1189 		pnum_probes_tlv->header.len =
1190 			sizeof(pnum_probes_tlv->num_probes);
1191 		pnum_probes_tlv->num_probes =
1192 			wlan_cpu_to_le16((t_u16)num_probes);
1193 
1194 		ptlv_pos +=
1195 			sizeof(pnum_probes_tlv->header) +
1196 			pnum_probes_tlv->header.len;
1197 
1198 		pnum_probes_tlv->header.len =
1199 			wlan_cpu_to_le16(pnum_probes_tlv->header.len);
1200 	}
1201 
1202 	/* Append rates tlv */
1203 	memset(pmadapter, rates, 0, sizeof(rates));
1204 
1205 	rates_size = wlan_get_supported_rates(pmpriv, pmpriv->bss_mode,
1206 					      (pmpriv->bss_mode ==
1207 					       MLAN_BSS_MODE_INFRA) ? pmpriv->
1208 					      config_bands : pmadapter->
1209 					      adhoc_start_band, rates);
1210 
1211 	prates_tlv = (MrvlIEtypes_RatesParamSet_t *)ptlv_pos;
1212 	prates_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RATES);
1213 	prates_tlv->header.len = wlan_cpu_to_le16((t_u16)rates_size);
1214 	memcpy(pmadapter, prates_tlv->rates, rates, rates_size);
1215 	ptlv_pos += sizeof(prates_tlv->header) + rates_size;
1216 
1217 	PRINTM(MINFO, "SCAN_CMD: Rates size = %d\n", rates_size);
1218 
1219 	if (ISSUPP_11NENABLED(pmpriv->adapter->fw_cap_info)
1220 	    && (pmpriv->config_bands & BAND_GN
1221 		|| pmpriv->config_bands & BAND_AN)) {
1222 		pht_cap = (MrvlIETypes_HTCap_t *)ptlv_pos;
1223 		memset(pmadapter, pht_cap, 0, sizeof(MrvlIETypes_HTCap_t));
1224 		pht_cap->header.type = wlan_cpu_to_le16(HT_CAPABILITY);
1225 		pht_cap->header.len = sizeof(HTCap_t);
1226 		wlan_fill_ht_cap_tlv(pmpriv, pht_cap, pmpriv->config_bands,
1227 				     MTRUE);
1228 		HEXDUMP("SCAN: HT_CAPABILITIES IE", (t_u8 *)pht_cap,
1229 			sizeof(MrvlIETypes_HTCap_t));
1230 		ptlv_pos += sizeof(MrvlIETypes_HTCap_t);
1231 		pht_cap->header.len = wlan_cpu_to_le16(pht_cap->header.len);
1232 	}
1233 
1234 	if (wlan_is_ext_capa_support(pmpriv))
1235 		wlan_add_ext_capa_info_ie(pmpriv, &ptlv_pos);
1236 	if (pmpriv->adapter->ecsa_enable) {
1237 		t_u8 bandwidth = BW_20MHZ;
1238 		t_u8 oper_class = 1;
1239 		t_u32 usr_dot_11n_dev_cap;
1240 		if (pmpriv->media_connected) {
1241 			if (pmpriv->config_bands & BAND_A)
1242 				usr_dot_11n_dev_cap =
1243 					pmpriv->usr_dot_11n_dev_cap_a;
1244 			else
1245 				usr_dot_11n_dev_cap =
1246 					pmpriv->usr_dot_11n_dev_cap_bg;
1247 			if (usr_dot_11n_dev_cap & MBIT(17)) {
1248 				bandwidth = BW_40MHZ;
1249 			}
1250 			wlan_get_curr_oper_class(pmpriv,
1251 						 pmpriv->curr_bss_params.
1252 						 bss_descriptor.channel,
1253 						 bandwidth, &oper_class);
1254 		}
1255 		wlan_add_supported_oper_class_ie(pmpriv, &ptlv_pos, oper_class);
1256 	}
1257 	wlan_add_wps_probe_request_ie(pmpriv, &ptlv_pos);
1258 
1259 	if (puser_scan_in && puser_scan_in->proberesp_only) {
1260 		MrvlIEtypes_OnlyProberesp_t *proberesp_only =
1261 			(MrvlIEtypes_OnlyProberesp_t *) ptlv_pos;
1262 		memset(pmadapter, proberesp_only, 0,
1263 		       sizeof(MrvlIEtypes_OnlyProberesp_t));
1264 		proberesp_only->header.type =
1265 			wlan_cpu_to_le16(TLV_TYPE_ONLYPROBERESP);
1266 		proberesp_only->header.len = wlan_cpu_to_le16(sizeof(t_u8));
1267 		proberesp_only->proberesp_only = puser_scan_in->proberesp_only;
1268 		ptlv_pos += sizeof(MrvlIEtypes_OnlyProberesp_t);
1269 	}
1270 
1271 	/*
1272 	 * Set the output for the channel TLV to the address in the tlv buffer
1273 	 *   past any TLVs that were added in this function (SSID, num_probes).
1274 	 *   Channel TLVs will be added past this for each scan command,
1275 	 *   preserving the TLVs that were previously added.
1276 	 */
1277 	*ppchan_list_out = (MrvlIEtypes_ChanListParamSet_t *)ptlv_pos;
1278 
1279 	if (puser_scan_in && puser_scan_in->chan_list[0].chan_number) {
1280 
1281 		PRINTM(MINFO, "Scan: Using supplied channel list\n");
1282 
1283 		for (chan_idx = 0;
1284 		     chan_idx < WLAN_USER_SCAN_CHAN_MAX
1285 		     && puser_scan_in->chan_list[chan_idx].chan_number;
1286 		     chan_idx++) {
1287 
1288 			channel =
1289 				puser_scan_in->chan_list[chan_idx].chan_number;
1290 			(pscan_chan_list + chan_idx)->chan_number = channel;
1291 
1292 			radio_type =
1293 				puser_scan_in->chan_list[chan_idx].radio_type;
1294 			(pscan_chan_list + chan_idx)->bandcfg.chanBand =
1295 				radio_type;
1296 
1297 			scan_type =
1298 				puser_scan_in->chan_list[chan_idx].scan_type;
1299 			if (scan_type == MLAN_SCAN_TYPE_UNCHANGED)
1300 				scan_type = pmadapter->scan_type;
1301 
1302 			if (radio_type == BAND_5GHZ) {
1303 				if (pmadapter->fw_bands & BAND_A)
1304 					PRINTM(MINFO,
1305 					       "UserScan request for A Band channel %d!!\n",
1306 					       channel);
1307 				else {
1308 					PRINTM(MERROR,
1309 					       "Scan in A band is not allowed!!\n");
1310 					ret = MLAN_STATUS_FAILURE;
1311 					LEAVE();
1312 					return ret;
1313 
1314 				}
1315 			}
1316 
1317 			/* Prevent active scanning on a radar controlled channel */
1318 			if (radio_type == BAND_5GHZ) {
1319 				if (pmadapter->active_scan_triggered == MFALSE)
1320 					if (wlan_11h_radar_detect_required
1321 					    (pmpriv, channel)) {
1322 						scan_type =
1323 							MLAN_SCAN_TYPE_PASSIVE;
1324 					}
1325 			}
1326 			if (radio_type == BAND_2GHZ) {
1327 				if (pmadapter->active_scan_triggered == MFALSE)
1328 					if (wlan_bg_scan_type_is_passive
1329 					    (pmpriv, channel)) {
1330 						scan_type =
1331 							MLAN_SCAN_TYPE_PASSIVE;
1332 					}
1333 			}
1334 			if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
1335 				(pscan_chan_list +
1336 				 chan_idx)->chan_scan_mode.passive_scan = MTRUE;
1337 				(pscan_chan_list +
1338 				 chan_idx)->chan_scan_mode.hidden_ssid_report =
1339 		      MTRUE;
1340 			} else {
1341 				(pscan_chan_list +
1342 				 chan_idx)->chan_scan_mode.passive_scan =
1343 		      MFALSE;
1344 			}
1345 
1346 			if (puser_scan_in->chan_list[chan_idx].scan_time) {
1347 				scan_dur =
1348 					(t_u16)puser_scan_in->
1349 					chan_list[chan_idx].scan_time;
1350 			} else {
1351 				if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
1352 					scan_dur = pmadapter->passive_scan_time;
1353 				} else if (*pfiltered_scan) {
1354 					scan_dur =
1355 						pmadapter->specific_scan_time;
1356 				} else {
1357 					scan_dur = pmadapter->active_scan_time;
1358 				}
1359 			}
1360 			if (pmadapter->coex_scan &&
1361 			    pmadapter->coex_min_scan_time &&
1362 			    (pmadapter->coex_min_scan_time > scan_dur))
1363 				scan_dur = pmadapter->coex_min_scan_time;
1364 			(pscan_chan_list + chan_idx)->min_scan_time =
1365 				wlan_cpu_to_le16(scan_dur);
1366 			(pscan_chan_list + chan_idx)->max_scan_time =
1367 				wlan_cpu_to_le16(scan_dur);
1368 			if (*pfiltered_scan) {
1369 				(pscan_chan_list +
1370 				 chan_idx)->chan_scan_mode.disable_chan_filt =
1371 		      MTRUE;
1372 			}
1373 		}
1374 
1375 		/* Check if we are only scanning the current channel */
1376 		if ((chan_idx == 1)
1377 		    && (puser_scan_in->chan_list[0].chan_number
1378 			== pmpriv->curr_bss_params.bss_descriptor.channel)) {
1379 			*pscan_current_only = MTRUE;
1380 			PRINTM(MINFO, "Scan: Scanning current channel only\n");
1381 		}
1382 
1383 	} else {
1384 		PRINTM(MINFO, "Scan: Creating full region channel list\n");
1385 		wlan_scan_create_channel_list(pmpriv, puser_scan_in,
1386 					      pscan_chan_list, *pfiltered_scan);
1387 	}
1388 
1389 	LEAVE();
1390 	return ret;
1391 }
1392 
1393 /**
1394  *  @brief Inspect the scan response buffer for pointers to expected TLVs
1395  *
1396  *  TLVs can be included at the end of the scan response BSS information.
1397  *    Parse the data in the buffer for pointers to TLVs that can potentially
1398  *    be passed back in the response
1399  *
1400  *  @param pmadapter        Pointer to the mlan_adapter structure
1401  *  @param ptlv             Pointer to the start of the TLV buffer to parse
1402  *  @param tlv_buf_size     Size of the TLV buffer
1403  *  @param req_tlv_type     Request TLV's type
1404  *  @param pptlv            Output parameter: Pointer to the request TLV if found
1405  *
1406  *  @return                 N/A
1407  */
1408 static t_void
wlan_ret_802_11_scan_get_tlv_ptrs(IN pmlan_adapter pmadapter,IN MrvlIEtypes_Data_t * ptlv,IN t_u32 tlv_buf_size,IN t_u32 req_tlv_type,OUT MrvlIEtypes_Data_t ** pptlv)1409 wlan_ret_802_11_scan_get_tlv_ptrs(IN pmlan_adapter pmadapter,
1410 				  IN MrvlIEtypes_Data_t *ptlv,
1411 				  IN t_u32 tlv_buf_size,
1412 				  IN t_u32 req_tlv_type,
1413 				  OUT MrvlIEtypes_Data_t **pptlv)
1414 {
1415 	MrvlIEtypes_Data_t *pcurrent_tlv;
1416 	t_u32 tlv_buf_left;
1417 	t_u32 tlv_type;
1418 	t_u32 tlv_len;
1419 
1420 	ENTER();
1421 
1422 	pcurrent_tlv = ptlv;
1423 	tlv_buf_left = tlv_buf_size;
1424 	*pptlv = MNULL;
1425 
1426 	PRINTM(MINFO, "SCAN_RESP: tlv_buf_size = %d\n", tlv_buf_size);
1427 
1428 	while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
1429 
1430 		tlv_type = wlan_le16_to_cpu(pcurrent_tlv->header.type);
1431 		tlv_len = wlan_le16_to_cpu(pcurrent_tlv->header.len);
1432 
1433 		if (sizeof(ptlv->header) + tlv_len > tlv_buf_left) {
1434 			PRINTM(MERROR, "SCAN_RESP: TLV buffer corrupt\n");
1435 			break;
1436 		}
1437 
1438 		if (req_tlv_type == tlv_type) {
1439 			switch (tlv_type) {
1440 			case TLV_TYPE_TSFTIMESTAMP:
1441 				PRINTM(MINFO,
1442 				       "SCAN_RESP: TSF Timestamp TLV, len = %d\n",
1443 				       tlv_len);
1444 				*pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
1445 				break;
1446 			case TLV_TYPE_CHANNELBANDLIST:
1447 				PRINTM(MINFO,
1448 				       "SCAN_RESP: CHANNEL BAND LIST TLV, len = %d\n",
1449 				       tlv_len);
1450 				*pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
1451 				break;
1452 			case TLV_TYPE_CHANNEL_STATS:
1453 				PRINTM(MINFO,
1454 				       "SCAN_RESP: CHANNEL STATS TLV, len = %d\n",
1455 				       tlv_len);
1456 				*pptlv = (MrvlIEtypes_Data_t *)pcurrent_tlv;
1457 				break;
1458 			default:
1459 				PRINTM(MERROR,
1460 				       "SCAN_RESP: Unhandled TLV = %d\n",
1461 				       tlv_type);
1462 				/* Give up, this seems corrupted */
1463 				LEAVE();
1464 				return;
1465 			}
1466 		}
1467 
1468 		if (*pptlv) {
1469 			/* HEXDUMP("SCAN_RESP: TLV Buf", (t_u8 *)*pptlv+4, tlv_len); */
1470 			break;
1471 		}
1472 
1473 		tlv_buf_left -= (sizeof(ptlv->header) + tlv_len);
1474 		pcurrent_tlv =
1475 			(MrvlIEtypes_Data_t *)(pcurrent_tlv->data + tlv_len);
1476 
1477 	}			/* while */
1478 
1479 	LEAVE();
1480 }
1481 
1482 /**
1483  *  @brief Interpret a BSS scan response returned from the firmware
1484  *
1485  *  Parse the various fixed fields and IEs passed back for a BSS probe
1486  *   response or beacon from the scan command.  Record information as needed
1487  *   in the scan table BSSDescriptor_t for that entry.
1488  *
1489  *  @param pmadapter    A pointer to mlan_adapter structure
1490  *  @param pbss_entry   Output parameter: Pointer to the BSS Entry
1491  *  @param pbeacon_info Pointer to the Beacon information
1492  *  @param bytes_left   Number of bytes left to parse
1493  *  @param ext_scan     extended scan
1494  *
1495  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1496  */
1497 static mlan_status
wlan_interpret_bss_desc_with_ie(IN pmlan_adapter pmadapter,OUT BSSDescriptor_t * pbss_entry,IN t_u8 ** pbeacon_info,IN t_u32 * bytes_left,IN t_u8 ext_scan)1498 wlan_interpret_bss_desc_with_ie(IN pmlan_adapter pmadapter,
1499 				OUT BSSDescriptor_t *pbss_entry,
1500 				IN t_u8 **pbeacon_info,
1501 				IN t_u32 *bytes_left, IN t_u8 ext_scan)
1502 {
1503 	mlan_status ret = MLAN_STATUS_SUCCESS;
1504 	IEEEtypes_ElementId_e element_id;
1505 	IEEEtypes_FhParamSet_t *pfh_param_set;
1506 	IEEEtypes_DsParamSet_t *pds_param_set;
1507 	IEEEtypes_CfParamSet_t *pcf_param_set;
1508 	IEEEtypes_IbssParamSet_t *pibss_param_set;
1509 	IEEEtypes_CapInfo_t *pcap_info;
1510 	WLAN_802_11_FIXED_IEs fixed_ie;
1511 	t_u8 *pcurrent_ptr;
1512 	t_u8 *prate;
1513 	t_u8 element_len;
1514 	t_u16 total_ie_len;
1515 	t_u8 bytes_to_copy;
1516 	t_u8 rate_size;
1517 	t_u16 beacon_size;
1518 	t_u8 found_data_rate_ie;
1519 	t_u32 bytes_left_for_current_beacon;
1520 	IEEEtypes_ERPInfo_t *perp_info;
1521 
1522 	IEEEtypes_VendorSpecific_t *pvendor_ie;
1523 	const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
1524 	const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
1525 
1526 	IEEEtypes_CountryInfoSet_t *pcountry_info;
1527 
1528 	ENTER();
1529 
1530 	found_data_rate_ie = MFALSE;
1531 	rate_size = 0;
1532 	beacon_size = 0;
1533 
1534 	if (*bytes_left >= sizeof(beacon_size)) {
1535 		/* Extract & convert beacon size from the command buffer */
1536 		memcpy(pmadapter, &beacon_size, *pbeacon_info,
1537 		       sizeof(beacon_size));
1538 		beacon_size = wlan_le16_to_cpu(beacon_size);
1539 		*bytes_left -= sizeof(beacon_size);
1540 		*pbeacon_info += sizeof(beacon_size);
1541 	}
1542 
1543 	if (!beacon_size || beacon_size > *bytes_left) {
1544 
1545 		*pbeacon_info += *bytes_left;
1546 		*bytes_left = 0;
1547 
1548 		LEAVE();
1549 		return MLAN_STATUS_FAILURE;
1550 	}
1551 
1552 	/* Initialize the current working beacon pointer for this BSS iteration */
1553 	pcurrent_ptr = *pbeacon_info;
1554 
1555 	/* Advance the return beacon pointer past the current beacon */
1556 	*pbeacon_info += beacon_size;
1557 	*bytes_left -= beacon_size;
1558 
1559 	bytes_left_for_current_beacon = beacon_size;
1560 
1561 	if (bytes_left_for_current_beacon <
1562 	    (MLAN_MAC_ADDR_LENGTH + sizeof(t_u8) +
1563 	     sizeof(WLAN_802_11_FIXED_IEs))) {
1564 		PRINTM(MERROR, "InterpretIE: Not enough bytes left\n");
1565 		LEAVE();
1566 		return MLAN_STATUS_FAILURE;
1567 	}
1568 
1569 	memcpy(pmadapter, pbss_entry->mac_address, pcurrent_ptr,
1570 	       MLAN_MAC_ADDR_LENGTH);
1571 	PRINTM(MINFO, "InterpretIE: AP MAC Addr-" MACSTR "\n",
1572 	       MAC2STR(pbss_entry->mac_address));
1573 
1574 	pcurrent_ptr += MLAN_MAC_ADDR_LENGTH;
1575 	bytes_left_for_current_beacon -= MLAN_MAC_ADDR_LENGTH;
1576 
1577 	/*
1578 	 * Next 4 fields are RSSI (for legacy scan only), time stamp,
1579 	 *   beacon interval, and capability information
1580 	 */
1581 	if (!ext_scan) {
1582 		/* RSSI is 1 byte long */
1583 		pbss_entry->rssi = (t_s32)(*pcurrent_ptr);
1584 		PRINTM(MINFO, "InterpretIE: RSSI=%02X\n", *pcurrent_ptr);
1585 		pcurrent_ptr += 1;
1586 		bytes_left_for_current_beacon -= 1;
1587 	}
1588 
1589 	/*
1590 	 *  The RSSI is not part of the beacon/probe response.  After we have
1591 	 *    advanced pcurrent_ptr past the RSSI field, save the remaining
1592 	 *    data for use at the application layer
1593 	 */
1594 	pbss_entry->pbeacon_buf = pcurrent_ptr;
1595 	pbss_entry->beacon_buf_size = bytes_left_for_current_beacon;
1596 
1597 	/* Time stamp is 8 bytes long */
1598 	memcpy(pmadapter, fixed_ie.time_stamp, pcurrent_ptr, 8);
1599 	memcpy(pmadapter, pbss_entry->time_stamp, pcurrent_ptr, 8);
1600 	pcurrent_ptr += 8;
1601 	bytes_left_for_current_beacon -= 8;
1602 
1603 	/* Beacon interval is 2 bytes long */
1604 	memcpy(pmadapter, &fixed_ie.beacon_interval, pcurrent_ptr, 2);
1605 	pbss_entry->beacon_period = wlan_le16_to_cpu(fixed_ie.beacon_interval);
1606 	pcurrent_ptr += 2;
1607 	bytes_left_for_current_beacon -= 2;
1608 
1609 	/* Capability information is 2 bytes long */
1610 	memcpy(pmadapter, &fixed_ie.capabilities, pcurrent_ptr, 2);
1611 	PRINTM(MINFO, "InterpretIE: fixed_ie.capabilities=0x%X\n",
1612 	       fixed_ie.capabilities);
1613 	fixed_ie.capabilities = wlan_le16_to_cpu(fixed_ie.capabilities);
1614 	pcap_info = (IEEEtypes_CapInfo_t *)&fixed_ie.capabilities;
1615 	memcpy(pmadapter, &pbss_entry->cap_info, pcap_info,
1616 	       sizeof(IEEEtypes_CapInfo_t));
1617 	pcurrent_ptr += 2;
1618 	bytes_left_for_current_beacon -= 2;
1619 
1620 	/* Rest of the current buffer are IE's */
1621 	PRINTM(MINFO, "InterpretIE: IELength for this AP = %d\n",
1622 	       bytes_left_for_current_beacon);
1623 
1624 	HEXDUMP("InterpretIE: IE info", (t_u8 *)pcurrent_ptr,
1625 		bytes_left_for_current_beacon);
1626 
1627 	if (pcap_info->privacy) {
1628 		PRINTM(MINFO, "InterpretIE: AP WEP enabled\n");
1629 		pbss_entry->privacy = Wlan802_11PrivFilter8021xWEP;
1630 	} else {
1631 		pbss_entry->privacy = Wlan802_11PrivFilterAcceptAll;
1632 	}
1633 
1634 	if (pcap_info->ibss == 1)
1635 		pbss_entry->bss_mode = MLAN_BSS_MODE_IBSS;
1636 	else
1637 		pbss_entry->bss_mode = MLAN_BSS_MODE_INFRA;
1638 
1639 	if (pcap_info->spectrum_mgmt == 1) {
1640 		PRINTM(MINFO, "InterpretIE: 11h- Spectrum Management "
1641 		       "capability bit found\n");
1642 		pbss_entry->wlan_11h_bss_info.sensed_11h = 1;
1643 	}
1644 
1645 	/* Process variable IE */
1646 	while (bytes_left_for_current_beacon >= 2) {
1647 		element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
1648 		element_len = *((t_u8 *)pcurrent_ptr + 1);
1649 		total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
1650 
1651 		if (bytes_left_for_current_beacon < total_ie_len) {
1652 			PRINTM(MERROR, "InterpretIE: Error in processing IE, "
1653 			       "bytes left < IE length\n");
1654 			bytes_left_for_current_beacon = 0;
1655 			continue;
1656 		}
1657 
1658 		switch (element_id) {
1659 
1660 		case SSID:
1661 			if (element_len > MRVDRV_MAX_SSID_LENGTH) {
1662 				bytes_left_for_current_beacon = 0;
1663 				continue;
1664 			}
1665 			if (!pbss_entry->ssid.ssid_len) {
1666 				pbss_entry->ssid.ssid_len = element_len;
1667 				memcpy(pmadapter, pbss_entry->ssid.ssid,
1668 				       (pcurrent_ptr + 2), element_len);
1669 			}
1670 			PRINTM(MINFO, "InterpretIE: ssid: %-32s\n",
1671 			       pbss_entry->ssid.ssid);
1672 			break;
1673 
1674 		case SUPPORTED_RATES:
1675 			if (element_len > WLAN_SUPPORTED_RATES) {
1676 				bytes_left_for_current_beacon = 0;
1677 				continue;
1678 			}
1679 			memcpy(pmadapter, pbss_entry->data_rates,
1680 			       pcurrent_ptr + 2, element_len);
1681 			memcpy(pmadapter, pbss_entry->supported_rates,
1682 			       pcurrent_ptr + 2, element_len);
1683 			HEXDUMP("InterpretIE: SupportedRates:",
1684 				pbss_entry->supported_rates, element_len);
1685 			rate_size = element_len;
1686 			found_data_rate_ie = MTRUE;
1687 			break;
1688 
1689 		case FH_PARAM_SET:
1690 			pfh_param_set = (IEEEtypes_FhParamSet_t *)pcurrent_ptr;
1691 			pbss_entry->network_type_use = Wlan802_11FH;
1692 			memcpy(pmadapter,
1693 			       &pbss_entry->phy_param_set.fh_param_set,
1694 			       pfh_param_set, MIN(total_ie_len,
1695 						  sizeof
1696 						  (IEEEtypes_FhParamSet_t)));
1697 			pbss_entry->phy_param_set.fh_param_set.len =
1698 				MIN(element_len, (sizeof(IEEEtypes_FhParamSet_t)
1699 						  -
1700 						  sizeof(IEEEtypes_Header_t)));
1701 			pbss_entry->phy_param_set.fh_param_set.dwell_time =
1702 				wlan_le16_to_cpu(pbss_entry->phy_param_set.
1703 						 fh_param_set.dwell_time);
1704 			break;
1705 
1706 		case DS_PARAM_SET:
1707 			pds_param_set = (IEEEtypes_DsParamSet_t *)pcurrent_ptr;
1708 
1709 			pbss_entry->network_type_use = Wlan802_11DS;
1710 			pbss_entry->channel = pds_param_set->current_chan;
1711 
1712 			memcpy(pmadapter,
1713 			       &pbss_entry->phy_param_set.ds_param_set,
1714 			       pds_param_set, MIN(total_ie_len,
1715 						  sizeof
1716 						  (IEEEtypes_DsParamSet_t)));
1717 			pbss_entry->phy_param_set.ds_param_set.len =
1718 				MIN(element_len, (sizeof(IEEEtypes_DsParamSet_t)
1719 						  -
1720 						  sizeof(IEEEtypes_Header_t)));
1721 			break;
1722 
1723 		case CF_PARAM_SET:
1724 			pcf_param_set = (IEEEtypes_CfParamSet_t *)pcurrent_ptr;
1725 			memcpy(pmadapter,
1726 			       &pbss_entry->ss_param_set.cf_param_set,
1727 			       pcf_param_set, MIN(total_ie_len,
1728 						  sizeof
1729 						  (IEEEtypes_CfParamSet_t)));
1730 			pbss_entry->ss_param_set.cf_param_set.len =
1731 				MIN(element_len, (sizeof(IEEEtypes_CfParamSet_t)
1732 						  -
1733 						  sizeof(IEEEtypes_Header_t)));
1734 			break;
1735 
1736 		case IBSS_PARAM_SET:
1737 			pibss_param_set =
1738 				(IEEEtypes_IbssParamSet_t *)pcurrent_ptr;
1739 			pbss_entry->atim_window =
1740 				wlan_le16_to_cpu(pibss_param_set->atim_window);
1741 			memcpy(pmadapter,
1742 			       &pbss_entry->ss_param_set.ibss_param_set,
1743 			       pibss_param_set, MIN(total_ie_len,
1744 						    sizeof
1745 						    (IEEEtypes_IbssParamSet_t)));
1746 			pbss_entry->ss_param_set.ibss_param_set.len =
1747 				MIN(element_len,
1748 				    (sizeof(IEEEtypes_IbssParamSet_t)
1749 				     - sizeof(IEEEtypes_Header_t)));
1750 			break;
1751 
1752 			/* Handle Country Info IE */
1753 		case COUNTRY_INFO:
1754 			pcountry_info =
1755 				(IEEEtypes_CountryInfoSet_t *)pcurrent_ptr;
1756 
1757 			if (pcountry_info->len <
1758 			    sizeof(pcountry_info->country_code) ||
1759 			    (unsigned)(pcountry_info->len + 2) >
1760 			    sizeof(IEEEtypes_CountryInfoFullSet_t)) {
1761 				PRINTM(MERROR,
1762 				       "InterpretIE: 11D- Err "
1763 				       "country_info len =%d min=%d max=%d\n",
1764 				       pcountry_info->len,
1765 				       sizeof(pcountry_info->country_code),
1766 				       sizeof(IEEEtypes_CountryInfoFullSet_t));
1767 				LEAVE();
1768 				return MLAN_STATUS_FAILURE;
1769 			}
1770 
1771 			memcpy(pmadapter, &pbss_entry->country_info,
1772 			       pcountry_info, pcountry_info->len + 2);
1773 			HEXDUMP("InterpretIE: 11D- country_info:",
1774 				(t_u8 *)pcountry_info,
1775 				(t_u32)(pcountry_info->len + 2));
1776 			break;
1777 
1778 		case ERP_INFO:
1779 			perp_info = (IEEEtypes_ERPInfo_t *)pcurrent_ptr;
1780 			pbss_entry->erp_flags = perp_info->erp_flags;
1781 			break;
1782 
1783 		case POWER_CONSTRAINT:
1784 		case POWER_CAPABILITY:
1785 		case TPC_REPORT:
1786 		case CHANNEL_SWITCH_ANN:
1787 		case QUIET:
1788 		case IBSS_DFS:
1789 		case SUPPORTED_CHANNELS:
1790 		case TPC_REQUEST:
1791 			wlan_11h_process_bss_elem(pmadapter,
1792 						  &pbss_entry->
1793 						  wlan_11h_bss_info,
1794 						  pcurrent_ptr);
1795 			break;
1796 		case EXTENDED_SUPPORTED_RATES:
1797 			/*
1798 			 * Only process extended supported rate
1799 			 * if data rate is already found.
1800 			 * Data rate IE should come before
1801 			 * extended supported rate IE
1802 			 */
1803 			if (found_data_rate_ie) {
1804 				if ((element_len + rate_size) >
1805 				    WLAN_SUPPORTED_RATES) {
1806 					bytes_to_copy =
1807 						(WLAN_SUPPORTED_RATES -
1808 						 rate_size);
1809 				} else {
1810 					bytes_to_copy = element_len;
1811 				}
1812 
1813 				prate = (t_u8 *)pbss_entry->data_rates;
1814 				prate += rate_size;
1815 				memcpy(pmadapter, prate, pcurrent_ptr + 2,
1816 				       bytes_to_copy);
1817 
1818 				prate = (t_u8 *)pbss_entry->supported_rates;
1819 				prate += rate_size;
1820 				memcpy(pmadapter, prate, pcurrent_ptr + 2,
1821 				       bytes_to_copy);
1822 			}
1823 			HEXDUMP("InterpretIE: ExtSupportedRates:",
1824 				pbss_entry->supported_rates,
1825 				element_len + rate_size);
1826 			break;
1827 
1828 		case VENDOR_SPECIFIC_221:
1829 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
1830 
1831 			if (!memcmp
1832 			    (pmadapter, pvendor_ie->vend_hdr.oui, wpa_oui,
1833 			     sizeof(wpa_oui))) {
1834 				pbss_entry->pwpa_ie =
1835 					(IEEEtypes_VendorSpecific_t *)
1836 					pcurrent_ptr;
1837 				pbss_entry->wpa_offset =
1838 					(t_u16)(pcurrent_ptr -
1839 						pbss_entry->pbeacon_buf);
1840 				HEXDUMP("InterpretIE: Resp WPA_IE",
1841 					(t_u8 *)pbss_entry->pwpa_ie,
1842 					((*(pbss_entry->pwpa_ie)).vend_hdr.len +
1843 					 sizeof(IEEEtypes_Header_t)));
1844 			} else if (!memcmp
1845 				   (pmadapter, pvendor_ie->vend_hdr.oui,
1846 				    wmm_oui, sizeof(wmm_oui))) {
1847 				if (total_ie_len ==
1848 				    sizeof(IEEEtypes_WmmParameter_t)
1849 				    || total_ie_len ==
1850 				    sizeof(IEEEtypes_WmmInfo_t)) {
1851 
1852 					/*
1853 					 * Only accept and copy the WMM IE if
1854 					 * it matches the size expected for the
1855 					 * WMM Info IE or the WMM Parameter IE.
1856 					 */
1857 					memcpy(pmadapter,
1858 					       (t_u8 *)&pbss_entry->wmm_ie,
1859 					       pcurrent_ptr, total_ie_len);
1860 					HEXDUMP("InterpretIE: Resp WMM_IE",
1861 						(t_u8 *)&pbss_entry->wmm_ie,
1862 						total_ie_len);
1863 				}
1864 			}
1865 			break;
1866 		case RSN_IE:
1867 			pbss_entry->prsn_ie =
1868 				(IEEEtypes_Generic_t *)pcurrent_ptr;
1869 			pbss_entry->rsn_offset =
1870 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1871 			HEXDUMP("InterpretIE: Resp RSN_IE",
1872 				(t_u8 *)pbss_entry->prsn_ie,
1873 				(*(pbss_entry->prsn_ie)).ieee_hdr.len +
1874 				sizeof(IEEEtypes_Header_t));
1875 			break;
1876 		case WAPI_IE:
1877 			pbss_entry->pwapi_ie =
1878 				(IEEEtypes_Generic_t *)pcurrent_ptr;
1879 			pbss_entry->wapi_offset =
1880 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1881 			HEXDUMP("InterpretIE: Resp WAPI_IE",
1882 				(t_u8 *)pbss_entry->pwapi_ie,
1883 				(*(pbss_entry->pwapi_ie)).ieee_hdr.len +
1884 				sizeof(IEEEtypes_Header_t));
1885 			break;
1886 		case HT_CAPABILITY:
1887 			pbss_entry->pht_cap = (IEEEtypes_HTCap_t *)pcurrent_ptr;
1888 			pbss_entry->ht_cap_offset =
1889 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1890 			HEXDUMP("InterpretIE: Resp HTCAP_IE",
1891 				(t_u8 *)pbss_entry->pht_cap,
1892 				(*(pbss_entry->pht_cap)).ieee_hdr.len +
1893 				sizeof(IEEEtypes_Header_t));
1894 			break;
1895 		case HT_OPERATION:
1896 			pbss_entry->pht_info =
1897 				(IEEEtypes_HTInfo_t *)pcurrent_ptr;
1898 			pbss_entry->ht_info_offset =
1899 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1900 			HEXDUMP("InterpretIE: Resp HTINFO_IE",
1901 				(t_u8 *)pbss_entry->pht_info,
1902 				(*(pbss_entry->pht_info)).ieee_hdr.len +
1903 				sizeof(IEEEtypes_Header_t));
1904 			break;
1905 		case BSSCO_2040:
1906 			pbss_entry->pbss_co_2040 =
1907 				(IEEEtypes_2040BSSCo_t *)pcurrent_ptr;
1908 			pbss_entry->bss_co_2040_offset =
1909 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1910 			HEXDUMP("InterpretIE: Resp 2040BSSCOEXISTANCE_IE",
1911 				(t_u8 *)pbss_entry->pbss_co_2040,
1912 				(*(pbss_entry->pbss_co_2040)).ieee_hdr.len +
1913 				sizeof(IEEEtypes_Header_t));
1914 			break;
1915 		case EXT_CAPABILITY:
1916 			pbss_entry->pext_cap =
1917 				(IEEEtypes_ExtCap_t *)pcurrent_ptr;
1918 			pbss_entry->ext_cap_offset =
1919 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1920 			HEXDUMP("InterpretIE: Resp EXTCAP_IE",
1921 				(t_u8 *)pbss_entry->pext_cap,
1922 				(*(pbss_entry->pext_cap)).ieee_hdr.len +
1923 				sizeof(IEEEtypes_Header_t));
1924 			break;
1925 		case OVERLAPBSSSCANPARAM:
1926 			pbss_entry->poverlap_bss_scan_param =
1927 				(IEEEtypes_OverlapBSSScanParam_t *)pcurrent_ptr;
1928 			pbss_entry->overlap_bss_offset =
1929 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1930 			HEXDUMP("InterpretIE: Resp OBSS_IE",
1931 				(t_u8 *)pbss_entry->poverlap_bss_scan_param,
1932 				(*(pbss_entry->poverlap_bss_scan_param)).
1933 				ieee_hdr.len + sizeof(IEEEtypes_Header_t));
1934 			break;
1935 		case MOBILITY_DOMAIN:
1936 			PRINTM(MCMND, "Mobility Domain IE received in Scan\n");
1937 			pbss_entry->pmd_ie =
1938 				(IEEEtypes_MobilityDomain_t *)pcurrent_ptr;
1939 			pbss_entry->md_offset =
1940 				(t_u16)(pcurrent_ptr - pbss_entry->pbeacon_buf);
1941 			HEXDUMP("InterpretIE: Resp Mobility Domain IE",
1942 				(t_u8 *)pbss_entry->pmd_ie,
1943 				(*(pbss_entry->pmd_ie)).ieee_hdr.len +
1944 				sizeof(IEEEtypes_Header_t));
1945 			break;
1946 		default:
1947 			break;
1948 		}
1949 
1950 		pcurrent_ptr += element_len + 2;
1951 
1952 		/* Need to account for IE ID and IE Len */
1953 		bytes_left_for_current_beacon -= (element_len + 2);
1954 
1955 	}			/* while (bytes_left_for_current_beacon > 2) */
1956 
1957 	LEAVE();
1958 	return ret;
1959 }
1960 
1961 /**
1962  *  @brief Adjust ie's position in BSSDescriptor_t
1963  *
1964  *  @param pmpriv       A pointer to mlan_private structure
1965  *  @param pbss_entry   A pointer to BSSDescriptor_t structure
1966  *
1967  *  @return           N/A
1968  */
1969 static t_void
wlan_adjust_ie_in_bss_entry(IN mlan_private * pmpriv,IN BSSDescriptor_t * pbss_entry)1970 wlan_adjust_ie_in_bss_entry(IN mlan_private *pmpriv,
1971 			    IN BSSDescriptor_t *pbss_entry)
1972 {
1973 	ENTER();
1974 	if (pbss_entry->pbeacon_buf) {
1975 		if (pbss_entry->pwpa_ie) {
1976 			pbss_entry->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
1977 				(pbss_entry->pbeacon_buf +
1978 				 pbss_entry->wpa_offset);
1979 		}
1980 		if (pbss_entry->prsn_ie) {
1981 			pbss_entry->prsn_ie = (IEEEtypes_Generic_t *)
1982 				(pbss_entry->pbeacon_buf +
1983 				 pbss_entry->rsn_offset);
1984 		}
1985 		if (pbss_entry->pwapi_ie) {
1986 			pbss_entry->pwapi_ie = (IEEEtypes_Generic_t *)
1987 				(pbss_entry->pbeacon_buf +
1988 				 pbss_entry->wapi_offset);
1989 		}
1990 		if (pbss_entry->pmd_ie) {
1991 			pbss_entry->pmd_ie = (IEEEtypes_MobilityDomain_t *)
1992 				(pbss_entry->pbeacon_buf +
1993 				 pbss_entry->md_offset);
1994 		}
1995 		if (pbss_entry->pht_cap) {
1996 			pbss_entry->pht_cap = (IEEEtypes_HTCap_t *)
1997 				(pbss_entry->pbeacon_buf +
1998 				 pbss_entry->ht_cap_offset);
1999 		}
2000 		if (pbss_entry->pht_info) {
2001 			pbss_entry->pht_info = (IEEEtypes_HTInfo_t *)
2002 				(pbss_entry->pbeacon_buf +
2003 				 pbss_entry->ht_info_offset);
2004 		}
2005 		if (pbss_entry->pbss_co_2040) {
2006 			pbss_entry->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
2007 				(pbss_entry->pbeacon_buf +
2008 				 pbss_entry->bss_co_2040_offset);
2009 		}
2010 		if (pbss_entry->pext_cap) {
2011 			pbss_entry->pext_cap = (IEEEtypes_ExtCap_t *)
2012 				(pbss_entry->pbeacon_buf +
2013 				 pbss_entry->ext_cap_offset);
2014 		}
2015 		if (pbss_entry->poverlap_bss_scan_param) {
2016 			pbss_entry->poverlap_bss_scan_param =
2017 				(IEEEtypes_OverlapBSSScanParam_t *)
2018 				(pbss_entry->pbeacon_buf +
2019 				 pbss_entry->overlap_bss_offset);
2020 		}
2021 	} else {
2022 		pbss_entry->pwpa_ie = MNULL;
2023 		pbss_entry->wpa_offset = 0;
2024 		pbss_entry->prsn_ie = MNULL;
2025 		pbss_entry->rsn_offset = 0;
2026 		pbss_entry->pwapi_ie = MNULL;
2027 		pbss_entry->wapi_offset = 0;
2028 		pbss_entry->pmd_ie = MNULL;
2029 		pbss_entry->md_offset = 0;
2030 		pbss_entry->pht_cap = MNULL;
2031 		pbss_entry->ht_cap_offset = 0;
2032 		pbss_entry->pht_info = MNULL;
2033 		pbss_entry->ht_info_offset = 0;
2034 		pbss_entry->pbss_co_2040 = MNULL;
2035 		pbss_entry->bss_co_2040_offset = 0;
2036 		pbss_entry->pext_cap = MNULL;
2037 		pbss_entry->ext_cap_offset = 0;
2038 		pbss_entry->poverlap_bss_scan_param = MNULL;
2039 		pbss_entry->overlap_bss_offset = 0;
2040 	}
2041 	LEAVE();
2042 	return;
2043 }
2044 
2045 /**
2046  *  @brief Store a beacon or probe response for a BSS returned in the scan
2047  *
2048  *  Store a new scan response or an update for a previous scan response.  New
2049  *    entries need to verify that they do not exceed the total amount of
2050  *    memory allocated for the table.
2051 
2052  *  Replacement entries need to take into consideration the amount of space
2053  *    currently allocated for the beacon/probe response and adjust the entry
2054  *    as needed.
2055  *
2056  *  A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
2057  *    for an entry in case it is a beacon since a probe response for the
2058  *    network will by larger per the standard.  This helps to reduce the
2059  *    amount of memory copying to fit a new probe response into an entry
2060  *    already occupied by a network's previously stored beacon.
2061  *
2062  *  @param pmpriv       A pointer to mlan_private structure
2063  *  @param beacon_idx   Index in the scan table to store this entry; may be
2064  *                      replacing an older duplicate entry for this BSS
2065  *  @param num_of_ent   Number of entries currently in the table
2066  *  @param pnew_beacon  Pointer to the new beacon/probe response to save
2067  *
2068  *  @return           N/A
2069  */
2070 static t_void
wlan_ret_802_11_scan_store_beacon(IN mlan_private * pmpriv,IN t_u32 beacon_idx,IN t_u32 num_of_ent,IN BSSDescriptor_t * pnew_beacon)2071 wlan_ret_802_11_scan_store_beacon(IN mlan_private *pmpriv,
2072 				  IN t_u32 beacon_idx,
2073 				  IN t_u32 num_of_ent,
2074 				  IN BSSDescriptor_t *pnew_beacon)
2075 {
2076 	mlan_adapter *pmadapter = pmpriv->adapter;
2077 	t_u8 *pbcn_store;
2078 	t_u32 new_bcn_size;
2079 	t_u32 old_bcn_size;
2080 	t_u32 bcn_space;
2081 	t_u32 adj_idx;
2082 	mlan_status ret = MLAN_STATUS_SUCCESS;
2083 	t_u8 *tmp_buf;
2084 	t_u16 bcn_size = 0;
2085 	t_u32 bcn_offset = 0;
2086 
2087 	ENTER();
2088 
2089 	if (pmadapter->pscan_table[beacon_idx].pbeacon_buf) {
2090 
2091 		new_bcn_size = pnew_beacon->beacon_buf_size;
2092 		old_bcn_size =
2093 			pmadapter->pscan_table[beacon_idx].beacon_buf_size;
2094 		bcn_space =
2095 			pmadapter->pscan_table[beacon_idx].beacon_buf_size_max;
2096 		pbcn_store = pmadapter->pscan_table[beacon_idx].pbeacon_buf;
2097 
2098 		/* Set the max to be the same as current entry unless changed below */
2099 		pnew_beacon->beacon_buf_size_max = bcn_space;
2100 
2101 		if (new_bcn_size == old_bcn_size) {
2102 			/*
2103 			 * Beacon is the same size as the previous entry.
2104 			 *   Replace the previous contents with the scan result
2105 			 */
2106 			memcpy(pmadapter, pbcn_store,
2107 			       pnew_beacon->pbeacon_buf,
2108 			       pnew_beacon->beacon_buf_size);
2109 
2110 		} else if (new_bcn_size <= bcn_space) {
2111 			/*
2112 			 * New beacon size will fit in the amount of space
2113 			 *   we have previously allocated for it
2114 			 */
2115 
2116 			/* Copy the new beacon buffer entry over the old one */
2117 			memcpy(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
2118 			       new_bcn_size);
2119 
2120 			/*
2121 			 *  If the old beacon size was less than the
2122 			 *  maximum we had allotted for the entry, and
2123 			 *  the new entry is even smaller, reset the
2124 			 *  max size to the old beacon entry and compress
2125 			 *  the storage space (leaving a new pad space of
2126 			 *  (old_bcn_size - new_bcn_size).
2127 			 */
2128 			if (old_bcn_size < bcn_space &&
2129 			    new_bcn_size <= old_bcn_size) {
2130 				/*
2131 				 * Old Beacon size is smaller than the
2132 				 * allotted storage size. Shrink the
2133 				 * allotted storage space.
2134 				 */
2135 				PRINTM(MINFO,
2136 				       "AppControl: Smaller Duplicate Beacon (%d), "
2137 				       "old = %d, new = %d, space = %d, left = %d\n",
2138 				       beacon_idx, old_bcn_size, new_bcn_size,
2139 				       bcn_space,
2140 				       (pmadapter->bcn_buf_size -
2141 					(pmadapter->pbcn_buf_end -
2142 					 pmadapter->bcn_buf)));
2143 
2144 				/*
2145 				 * memmove (since the memory overlaps) the data
2146 				 * after the beacon we just stored to the end
2147 				 * of the current beacon.  This cleans up any
2148 				 * unused space the old larger beacon was using
2149 				 * in the buffer
2150 				 */
2151 				memmove(pmadapter,
2152 					(void *)((t_ptr)pbcn_store +
2153 						 (t_ptr)old_bcn_size),
2154 					(void *)((t_ptr)pbcn_store +
2155 						 (t_ptr)bcn_space),
2156 					(t_u32)((t_ptr)pmadapter->pbcn_buf_end -
2157 						((t_ptr)pbcn_store +
2158 						 (t_ptr)bcn_space)));
2159 
2160 				/*
2161 				 * Decrement the end pointer by the difference
2162 				 * between the old larger size and the new
2163 				 * smaller size since we are using less space
2164 				 * due to the new beacon being smaller
2165 				 */
2166 				pmadapter->pbcn_buf_end -=
2167 					(bcn_space - old_bcn_size);
2168 
2169 				/*
2170 				 * Set the maximum storage size to the old
2171 				 * beacon size
2172 				 */
2173 				pnew_beacon->beacon_buf_size_max = old_bcn_size;
2174 
2175 				/* Adjust beacon buffer pointers that are past the current */
2176 				for (adj_idx = 0; adj_idx < num_of_ent;
2177 				     adj_idx++) {
2178 					if (pmadapter->pscan_table[adj_idx].
2179 					    pbeacon_buf > pbcn_store) {
2180 						pmadapter->pscan_table[adj_idx].
2181 							pbeacon_buf -=
2182 							(bcn_space -
2183 							 old_bcn_size);
2184 						wlan_adjust_ie_in_bss_entry
2185 							(pmpriv,
2186 							 &pmadapter->
2187 							 pscan_table[adj_idx]);
2188 					}
2189 				}
2190 			}
2191 		} else if (pmadapter->pbcn_buf_end + (new_bcn_size - bcn_space)
2192 			   < (pmadapter->bcn_buf + pmadapter->bcn_buf_size)) {
2193 			/*
2194 			 * Beacon is larger than space previously allocated
2195 			 * (bcn_space) and there is enough space left in the
2196 			 * beaconBuffer to store the additional data
2197 			 */
2198 			PRINTM(MINFO,
2199 			       "AppControl: Larger Duplicate Beacon (%d), "
2200 			       "old = %d, new = %d, space = %d, left = %d\n",
2201 			       beacon_idx, old_bcn_size, new_bcn_size,
2202 			       bcn_space,
2203 			       (pmadapter->bcn_buf_size -
2204 				(pmadapter->pbcn_buf_end -
2205 				 pmadapter->bcn_buf)));
2206 
2207 			/*
2208 			 * memmove (since the memory overlaps) the data
2209 			 *  after the beacon we just stored to the end of
2210 			 *  the current beacon.  This moves the data for
2211 			 *  the beacons after this further in memory to
2212 			 *  make space for the new larger beacon we are
2213 			 *  about to copy in.
2214 			 */
2215 			memmove(pmadapter,
2216 				(void *)((t_ptr)pbcn_store +
2217 					 (t_ptr)new_bcn_size),
2218 				(void *)((t_ptr)pbcn_store + (t_ptr)bcn_space),
2219 				(t_u32)((t_ptr)pmadapter->pbcn_buf_end -
2220 					((t_ptr)pbcn_store +
2221 					 (t_ptr)bcn_space)));
2222 
2223 			/* Copy the new beacon buffer entry over the old one */
2224 			memcpy(pmadapter, pbcn_store, pnew_beacon->pbeacon_buf,
2225 			       new_bcn_size);
2226 
2227 			/*
2228 			 * Move the beacon end pointer by the amount of new
2229 			 * beacon data we are adding
2230 			 */
2231 			pmadapter->pbcn_buf_end += (new_bcn_size - bcn_space);
2232 
2233 			/*
2234 			 * This entry is bigger than the allotted max space
2235 			 *  previously reserved.  Increase the max space to
2236 			 *  be equal to the new beacon size
2237 			 */
2238 			pnew_beacon->beacon_buf_size_max = new_bcn_size;
2239 
2240 			/* Adjust beacon buffer pointers that are past the current */
2241 			for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
2242 				if (pmadapter->pscan_table[adj_idx].
2243 				    pbeacon_buf > pbcn_store) {
2244 					pmadapter->pscan_table[adj_idx].
2245 						pbeacon_buf +=
2246 						(new_bcn_size - bcn_space);
2247 					wlan_adjust_ie_in_bss_entry(pmpriv,
2248 								    &pmadapter->
2249 								    pscan_table
2250 								    [adj_idx]);
2251 				}
2252 			}
2253 		} else {
2254 			/*
2255 			 * Beacon is larger than the previously allocated
2256 			 * space, but there is not enough free space to
2257 			 * store the additional data
2258 			 */
2259 			PRINTM(MERROR,
2260 			       "AppControl: Failed: Larger Duplicate Beacon (%d),"
2261 			       " old = %d, new = %d, space = %d, left = %d\n",
2262 			       beacon_idx, old_bcn_size, new_bcn_size,
2263 			       bcn_space,
2264 			       (pmadapter->bcn_buf_size -
2265 				(pmadapter->pbcn_buf_end -
2266 				 pmadapter->bcn_buf)));
2267 
2268 			/* Storage failure, keep old beacon intact */
2269 			pnew_beacon->beacon_buf_size = old_bcn_size;
2270 			if (pnew_beacon->pwpa_ie)
2271 				pnew_beacon->wpa_offset =
2272 					pmadapter->pscan_table[beacon_idx].
2273 					wpa_offset;
2274 			if (pnew_beacon->prsn_ie)
2275 				pnew_beacon->rsn_offset =
2276 					pmadapter->pscan_table[beacon_idx].
2277 					rsn_offset;
2278 			if (pnew_beacon->pwapi_ie)
2279 				pnew_beacon->wapi_offset =
2280 					pmadapter->pscan_table[beacon_idx].
2281 					wapi_offset;
2282 			if (pnew_beacon->pmd_ie)
2283 				pnew_beacon->md_offset =
2284 					pmadapter->pscan_table[beacon_idx].
2285 					md_offset;
2286 			if (pnew_beacon->pht_cap)
2287 				pnew_beacon->ht_cap_offset =
2288 					pmadapter->pscan_table[beacon_idx].
2289 					ht_cap_offset;
2290 			if (pnew_beacon->pht_info)
2291 				pnew_beacon->ht_info_offset =
2292 					pmadapter->pscan_table[beacon_idx].
2293 					ht_info_offset;
2294 			if (pnew_beacon->pbss_co_2040)
2295 				pnew_beacon->bss_co_2040_offset =
2296 					pmadapter->pscan_table[beacon_idx].
2297 					bss_co_2040_offset;
2298 			if (pnew_beacon->pext_cap)
2299 				pnew_beacon->ext_cap_offset =
2300 					pmadapter->pscan_table[beacon_idx].
2301 					ext_cap_offset;
2302 			if (pnew_beacon->poverlap_bss_scan_param)
2303 				pnew_beacon->overlap_bss_offset =
2304 					pmadapter->pscan_table[beacon_idx].
2305 					overlap_bss_offset;
2306 		}
2307 		/* Point the new entry to its permanent storage space */
2308 		pnew_beacon->pbeacon_buf = pbcn_store;
2309 		wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
2310 	} else {
2311 		if ((pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
2312 		     SCAN_BEACON_ENTRY_PAD > (pmadapter->bcn_buf +
2313 					      pmadapter->bcn_buf_size)) &&
2314 		    (pmadapter->bcn_buf_size < MAX_SCAN_BEACON_BUFFER)) {
2315 			/* no space for this entry, realloc bcn buffer */
2316 			ret = pmadapter->callbacks.moal_malloc(pmadapter->
2317 							       pmoal_handle,
2318 							       pmadapter->
2319 							       bcn_buf_size +
2320 							       DEFAULT_SCAN_BEACON_BUFFER,
2321 							       MLAN_MEM_DEF,
2322 							       (t_u8 **)
2323 							       &tmp_buf);
2324 
2325 			if ((ret == MLAN_STATUS_SUCCESS) && (tmp_buf)) {
2326 				PRINTM(MCMND,
2327 				       "Realloc Beacon buffer, old size=%d, new_size=%d\n",
2328 				       pmadapter->bcn_buf_size,
2329 				       pmadapter->bcn_buf_size +
2330 				       DEFAULT_SCAN_BEACON_BUFFER);
2331 				bcn_size =
2332 					pmadapter->pbcn_buf_end -
2333 					pmadapter->bcn_buf;
2334 				memcpy(pmadapter, tmp_buf, pmadapter->bcn_buf,
2335 				       bcn_size);
2336 				/* Adjust beacon buffer pointers that are past the current */
2337 				for (adj_idx = 0; adj_idx < num_of_ent;
2338 				     adj_idx++) {
2339 					bcn_offset =
2340 						pmadapter->pscan_table[adj_idx].
2341 						pbeacon_buf -
2342 						pmadapter->bcn_buf;
2343 					pmadapter->pscan_table[adj_idx].
2344 						pbeacon_buf =
2345 						tmp_buf + bcn_offset;
2346 					wlan_adjust_ie_in_bss_entry(pmpriv,
2347 								    &pmadapter->
2348 								    pscan_table
2349 								    [adj_idx]);
2350 				}
2351 				pmadapter->pbcn_buf_end = tmp_buf + bcn_size;
2352 				pmadapter->callbacks.moal_mfree(pmadapter->
2353 								pmoal_handle,
2354 								(t_u8 *)
2355 								pmadapter->
2356 								bcn_buf);
2357 				pmadapter->bcn_buf = tmp_buf;
2358 				pmadapter->bcn_buf_size +=
2359 					DEFAULT_SCAN_BEACON_BUFFER;
2360 			}
2361 		}
2362 		/*
2363 		 * No existing beacon data exists for this entry, check to see
2364 		 *   if we can fit it in the remaining space
2365 		 */
2366 		if (pmadapter->pbcn_buf_end + pnew_beacon->beacon_buf_size +
2367 		    SCAN_BEACON_ENTRY_PAD < (pmadapter->bcn_buf +
2368 					     pmadapter->bcn_buf_size)) {
2369 
2370 			/*
2371 			 * Copy the beacon buffer data from the local entry
2372 			 * to the adapter dev struct buffer space used to
2373 			 * store the raw beacon data for each entry in the
2374 			 * scan table
2375 			 */
2376 			memcpy(pmadapter, pmadapter->pbcn_buf_end,
2377 			       pnew_beacon->pbeacon_buf,
2378 			       pnew_beacon->beacon_buf_size);
2379 
2380 			/*
2381 			 * Update the beacon ptr to point to the table
2382 			 * save area
2383 			 */
2384 			pnew_beacon->pbeacon_buf = pmadapter->pbcn_buf_end;
2385 			pnew_beacon->beacon_buf_size_max =
2386 				(pnew_beacon->beacon_buf_size +
2387 				 SCAN_BEACON_ENTRY_PAD);
2388 			wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
2389 
2390 			/* Increment the end pointer by the size reserved */
2391 			pmadapter->pbcn_buf_end +=
2392 				pnew_beacon->beacon_buf_size_max;
2393 
2394 			PRINTM(MINFO, "AppControl: Beacon[%02d] sz=%03d,"
2395 			       " used = %04d, left = %04d\n",
2396 			       beacon_idx,
2397 			       pnew_beacon->beacon_buf_size,
2398 			       (pmadapter->pbcn_buf_end - pmadapter->bcn_buf),
2399 			       (pmadapter->bcn_buf_size -
2400 				(pmadapter->pbcn_buf_end -
2401 				 pmadapter->bcn_buf)));
2402 		} else {
2403 			/*
2404 			 * No space for new beacon
2405 			 */
2406 			PRINTM(MCMND, "AppControl: No space beacon (%d): "
2407 			       MACSTR "; sz=%03d, left=%03d\n",
2408 			       beacon_idx,
2409 			       MAC2STR(pnew_beacon->mac_address),
2410 			       pnew_beacon->beacon_buf_size,
2411 			       (pmadapter->bcn_buf_size -
2412 				(pmadapter->pbcn_buf_end -
2413 				 pmadapter->bcn_buf)));
2414 
2415 			/*
2416 			 * Storage failure; clear storage records
2417 			 * for this bcn
2418 			 */
2419 			pnew_beacon->pbeacon_buf = MNULL;
2420 			pnew_beacon->beacon_buf_size = 0;
2421 			pnew_beacon->beacon_buf_size_max = 0;
2422 			wlan_adjust_ie_in_bss_entry(pmpriv, pnew_beacon);
2423 		}
2424 	}
2425 
2426 	LEAVE();
2427 }
2428 
2429 /**
2430  *  @brief update beacon buffer of the current bss descriptor
2431  *
2432  *  @param pmpriv       A pointer to mlan_private structure
2433  *
2434  *  @return             MLAN_STATUS_SUCCESS, otherwise failure
2435  */
2436 static mlan_status
wlan_update_curr_bcn(IN mlan_private * pmpriv)2437 wlan_update_curr_bcn(IN mlan_private *pmpriv)
2438 {
2439 	BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
2440 	mlan_status ret = MLAN_STATUS_SUCCESS;
2441 
2442 	ENTER();
2443 
2444 	if (pmpriv->pcurr_bcn_buf && pmpriv->curr_bcn_size) {
2445 		pcurr_bss->pbeacon_buf = pmpriv->pcurr_bcn_buf;
2446 		pcurr_bss->beacon_buf_size = pmpriv->curr_bcn_size;
2447 		pcurr_bss->beacon_buf_size_max = pmpriv->curr_bcn_size;
2448 
2449 		/* adjust the pointers in the current bss descriptor */
2450 		if (pcurr_bss->pwpa_ie) {
2451 			pcurr_bss->pwpa_ie = (IEEEtypes_VendorSpecific_t *)
2452 				(pcurr_bss->pbeacon_buf +
2453 				 pcurr_bss->wpa_offset);
2454 		}
2455 		if (pcurr_bss->prsn_ie) {
2456 			pcurr_bss->prsn_ie = (IEEEtypes_Generic_t *)
2457 				(pcurr_bss->pbeacon_buf +
2458 				 pcurr_bss->rsn_offset);
2459 		}
2460 		if (pcurr_bss->pmd_ie) {
2461 			pcurr_bss->pmd_ie = (IEEEtypes_MobilityDomain_t *)
2462 				(pcurr_bss->pbeacon_buf + pcurr_bss->md_offset);
2463 		}
2464 		if (pcurr_bss->pht_cap) {
2465 			pcurr_bss->pht_cap = (IEEEtypes_HTCap_t *)
2466 				(pcurr_bss->pbeacon_buf +
2467 				 pcurr_bss->ht_cap_offset);
2468 		}
2469 
2470 		if (pcurr_bss->pht_info) {
2471 			pcurr_bss->pht_info = (IEEEtypes_HTInfo_t *)
2472 				(pcurr_bss->pbeacon_buf +
2473 				 pcurr_bss->ht_info_offset);
2474 		}
2475 
2476 		if (pcurr_bss->pbss_co_2040) {
2477 			pcurr_bss->pbss_co_2040 = (IEEEtypes_2040BSSCo_t *)
2478 				(pcurr_bss->pbeacon_buf +
2479 				 pcurr_bss->bss_co_2040_offset);
2480 		}
2481 
2482 		if (pcurr_bss->pext_cap) {
2483 			pcurr_bss->pext_cap = (IEEEtypes_ExtCap_t *)
2484 				(pcurr_bss->pbeacon_buf +
2485 				 pcurr_bss->ext_cap_offset);
2486 		}
2487 
2488 		if (pcurr_bss->poverlap_bss_scan_param) {
2489 			pcurr_bss->poverlap_bss_scan_param =
2490 				(IEEEtypes_OverlapBSSScanParam_t *)
2491 				(pcurr_bss->pbeacon_buf +
2492 				 pcurr_bss->overlap_bss_offset);
2493 		}
2494 
2495 		PRINTM(MINFO, "current beacon restored %d\n",
2496 		       pmpriv->curr_bcn_size);
2497 	} else {
2498 		PRINTM(MERROR, "curr_bcn_buf not saved\n");
2499 		ret = MLAN_STATUS_FAILURE;
2500 	}
2501 
2502 	LEAVE();
2503 	return ret;
2504 }
2505 
2506 /**
2507  *  @brief Post process the scan table after a new scan command has completed
2508  *
2509  *  Inspect each entry of the scan table and try to find an entry that
2510  *    matches our current associated/joined network from the scan.  If
2511  *    one is found, update the stored copy of the BSSDescriptor for our
2512  *    current network.
2513  *
2514  *  Debug dump the current scan table contents if compiled accordingly.
2515  *
2516  *  @param pmpriv       A pointer to mlan_private structure
2517  *
2518  *  @return             N/A
2519  */
2520 static t_void
wlan_scan_process_results(IN mlan_private * pmpriv)2521 wlan_scan_process_results(IN mlan_private *pmpriv)
2522 {
2523 	mlan_adapter *pmadapter = pmpriv->adapter;
2524 	t_s32 j;
2525 	t_u32 i;
2526 	mlan_status ret = MLAN_STATUS_SUCCESS;
2527 	BSSDescriptor_t *bss_new_entry = MNULL;
2528 	pmlan_callbacks pcb = &pmadapter->callbacks;
2529 
2530 	ENTER();
2531 
2532 	if (pmpriv->media_connected == MTRUE) {
2533 
2534 		j = wlan_find_ssid_in_list(pmpriv,
2535 					   &pmpriv->curr_bss_params.
2536 					   bss_descriptor.ssid,
2537 					   pmpriv->curr_bss_params.
2538 					   bss_descriptor.mac_address,
2539 					   pmpriv->bss_mode);
2540 
2541 		if (j >= 0) {
2542 			pmadapter->callbacks.moal_spin_lock(pmadapter->
2543 							    pmoal_handle,
2544 							    pmpriv->
2545 							    curr_bcn_buf_lock);
2546 			pmpriv->curr_bss_params.bss_descriptor.pwpa_ie = MNULL;
2547 			pmpriv->curr_bss_params.bss_descriptor.wpa_offset = 0;
2548 			pmpriv->curr_bss_params.bss_descriptor.prsn_ie = MNULL;
2549 			pmpriv->curr_bss_params.bss_descriptor.rsn_offset = 0;
2550 			pmpriv->curr_bss_params.bss_descriptor.pwapi_ie = MNULL;
2551 			pmpriv->curr_bss_params.bss_descriptor.wapi_offset = 0;
2552 			pmpriv->curr_bss_params.bss_descriptor.pmd_ie = MNULL;
2553 			pmpriv->curr_bss_params.bss_descriptor.md_offset = 0;
2554 			pmpriv->curr_bss_params.bss_descriptor.pht_cap = MNULL;
2555 			pmpriv->curr_bss_params.bss_descriptor.ht_cap_offset =
2556 				0;
2557 			pmpriv->curr_bss_params.bss_descriptor.pht_info = MNULL;
2558 			pmpriv->curr_bss_params.bss_descriptor.ht_info_offset =
2559 				0;
2560 			pmpriv->curr_bss_params.bss_descriptor.pbss_co_2040 =
2561 				MNULL;
2562 			pmpriv->curr_bss_params.bss_descriptor.
2563 				bss_co_2040_offset = 0;
2564 			pmpriv->curr_bss_params.bss_descriptor.pext_cap = MNULL;
2565 			pmpriv->curr_bss_params.bss_descriptor.ext_cap_offset =
2566 				0;
2567 			pmpriv->curr_bss_params.bss_descriptor.
2568 				poverlap_bss_scan_param = MNULL;
2569 			pmpriv->curr_bss_params.bss_descriptor.
2570 				overlap_bss_offset = 0;
2571 			pmpriv->curr_bss_params.bss_descriptor.pbeacon_buf =
2572 				MNULL;
2573 			pmpriv->curr_bss_params.bss_descriptor.beacon_buf_size =
2574 				0;
2575 			pmpriv->curr_bss_params.bss_descriptor.
2576 				beacon_buf_size_max = 0;
2577 
2578 			PRINTM(MINFO,
2579 			       "Found current ssid/bssid in list @ index #%d\n",
2580 			       j);
2581 			/* Make a copy of current BSSID descriptor */
2582 			memcpy(pmadapter,
2583 			       &pmpriv->curr_bss_params.bss_descriptor,
2584 			       &pmadapter->pscan_table[j],
2585 			       sizeof(pmpriv->curr_bss_params.bss_descriptor));
2586 
2587 			pmadapter->callbacks.moal_spin_unlock(pmadapter->
2588 							      pmoal_handle,
2589 							      pmpriv->
2590 							      curr_bcn_buf_lock);
2591 			wlan_save_curr_bcn(pmpriv);
2592 		} else {
2593 			//Apend to the end of scan table
2594 			if (pmpriv->pcurr_bcn_buf && pmpriv->curr_bcn_size) {
2595 				ret = pcb->moal_malloc(pmadapter->pmoal_handle,
2596 						       sizeof(BSSDescriptor_t),
2597 						       MLAN_MEM_DEF,
2598 						       (t_u8 **)&bss_new_entry);
2599 				if (ret == MLAN_STATUS_SUCCESS && bss_new_entry) {
2600 					memcpy(pmadapter, bss_new_entry,
2601 					       &pmpriv->curr_bss_params.
2602 					       bss_descriptor,
2603 					       sizeof(pmpriv->curr_bss_params.
2604 						      bss_descriptor));
2605 					if (pmadapter->num_in_scan_table <
2606 					    MRVDRV_MAX_BSSID_LIST)
2607 						pmadapter->num_in_scan_table++;
2608 					pmadapter->pscan_table[pmadapter->
2609 							       num_in_scan_table
2610 							       -
2611 							       1].pbeacon_buf =
2612 						MNULL;
2613 					wlan_ret_802_11_scan_store_beacon
2614 						(pmpriv,
2615 						 pmadapter->num_in_scan_table -
2616 						 1,
2617 						 pmadapter->num_in_scan_table,
2618 						 bss_new_entry);
2619 					if (bss_new_entry->pbeacon_buf == MNULL)
2620 						pmadapter->num_in_scan_table--;
2621 					else
2622 						memcpy(pmadapter,
2623 						       &pmadapter->
2624 						       pscan_table[pmadapter->
2625 								   num_in_scan_table
2626 								   - 1],
2627 						       bss_new_entry,
2628 						       sizeof(BSSDescriptor_t));
2629 					pcb->moal_mfree(pmadapter->pmoal_handle,
2630 							(t_u8 *)bss_new_entry);
2631 				}
2632 			}
2633 		}
2634 
2635 	}
2636 
2637 	for (i = 0; i < pmadapter->num_in_scan_table; i++)
2638 		PRINTM(MINFO, "Scan:(%02d) " MACSTR ", "
2639 		       "RSSI[%03d], SSID[%s]\n",
2640 		       i,
2641 		       MAC2STR(pmadapter->pscan_table[i].mac_address),
2642 		       (t_s32)pmadapter->pscan_table[i].rssi,
2643 		       pmadapter->pscan_table[i].ssid.ssid);
2644 
2645 	/*
2646 	 * Prepares domain info from scan table and downloads the
2647 	 *   domain info command to the FW.
2648 	 */
2649 	wlan_11d_prepare_dnld_domain_info_cmd(pmpriv);
2650 	PRINTM(MMSG, "wlan: SCAN COMPLETED: scanned AP count=%d\n",
2651 	       pmadapter->num_in_scan_table);
2652 	LEAVE();
2653 }
2654 
2655 /**
2656  *  @brief Delete a specific indexed entry from the scan table.
2657  *
2658  *  Delete the scan table entry indexed by table_idx.  Compact the remaining
2659  *    entries and adjust any buffering of beacon/probe response data
2660  *    if needed.
2661  *
2662  *  @param pmpriv       A pointer to mlan_private structure
2663  *  @param table_idx    Scan table entry index to delete from the table
2664  *
2665  *  @return             N/A
2666  *
2667  *  @pre                table_idx must be an index to a valid entry
2668  */
2669 static t_void
wlan_scan_delete_table_entry(IN mlan_private * pmpriv,IN t_s32 table_idx)2670 wlan_scan_delete_table_entry(IN mlan_private *pmpriv, IN t_s32 table_idx)
2671 {
2672 	mlan_adapter *pmadapter = pmpriv->adapter;
2673 	t_u32 del_idx;
2674 	t_u32 beacon_buf_adj;
2675 	t_u8 *pbeacon_buf;
2676 
2677 	ENTER();
2678 
2679 	/*
2680 	 * Shift the saved beacon buffer data for the scan table back over the
2681 	 *   entry being removed.  Update the end of buffer pointer.  Save the
2682 	 *   deleted buffer allocation size for pointer adjustments for entries
2683 	 *   compacted after the deleted index.
2684 	 */
2685 	beacon_buf_adj = pmadapter->pscan_table[table_idx].beacon_buf_size_max;
2686 
2687 	PRINTM(MINFO,
2688 	       "Scan: Delete Entry %d, beacon buffer removal = %d bytes\n",
2689 	       table_idx, beacon_buf_adj);
2690 
2691 	/* Check if the table entry had storage allocated for its beacon */
2692 	if (beacon_buf_adj) {
2693 		pbeacon_buf = pmadapter->pscan_table[table_idx].pbeacon_buf;
2694 
2695 		/*
2696 		 * Remove the entry's buffer space, decrement the table
2697 		 * end pointer by the amount we are removing
2698 		 */
2699 		pmadapter->pbcn_buf_end -= beacon_buf_adj;
2700 
2701 		PRINTM(MINFO,
2702 		       "Scan: Delete Entry %d, compact data: %p <- %p (sz = %d)\n",
2703 		       table_idx,
2704 		       pbeacon_buf,
2705 		       pbeacon_buf + beacon_buf_adj,
2706 		       pmadapter->pbcn_buf_end - pbeacon_buf);
2707 
2708 		/*
2709 		 * Compact data storage.  Copy all data after the deleted entry's
2710 		 *   end address (pbeacon_buf + beacon_buf_adj) back to the original
2711 		 *   start address (pbeacon_buf).
2712 		 *
2713 		 * Scan table entries affected by the move will have their entry
2714 		 *   pointer adjusted below.
2715 		 *
2716 		 * Use memmove since the dest/src memory regions overlap.
2717 		 */
2718 		memmove(pmadapter, pbeacon_buf,
2719 			(void *)((t_ptr)pbeacon_buf + (t_ptr)beacon_buf_adj),
2720 			(t_u32)((t_ptr)pmadapter->pbcn_buf_end -
2721 				(t_ptr)pbeacon_buf));
2722 	}
2723 
2724 	PRINTM(MINFO, "Scan: Delete Entry %d, num_in_scan_table = %d\n",
2725 	       table_idx, pmadapter->num_in_scan_table);
2726 
2727 	/*
2728 	 * Shift all of the entries after the table_idx back by one, compacting
2729 	 * the table and removing the requested entry
2730 	 */
2731 	for (del_idx = table_idx; (del_idx + 1) < pmadapter->num_in_scan_table;
2732 	     del_idx++) {
2733 		/* Copy the next entry over this one */
2734 		memcpy(pmadapter, pmadapter->pscan_table + del_idx,
2735 		       pmadapter->pscan_table + del_idx + 1,
2736 		       sizeof(BSSDescriptor_t));
2737 
2738 		/*
2739 		 * Adjust this entry's pointer to its beacon buffer based on the
2740 		 *   removed/compacted entry from the deleted index.  Don't decrement
2741 		 *   if the buffer pointer is MNULL (no data stored for this entry).
2742 		 */
2743 		if (pmadapter->pscan_table[del_idx].pbeacon_buf) {
2744 			pmadapter->pscan_table[del_idx].pbeacon_buf -=
2745 				beacon_buf_adj;
2746 			if (pmadapter->pscan_table[del_idx].pwpa_ie) {
2747 				pmadapter->pscan_table[del_idx].pwpa_ie =
2748 					(IEEEtypes_VendorSpecific_t *)
2749 					(pmadapter->pscan_table[del_idx].
2750 					 pbeacon_buf +
2751 					 pmadapter->pscan_table[del_idx].
2752 					 wpa_offset);
2753 			}
2754 			if (pmadapter->pscan_table[del_idx].prsn_ie) {
2755 				pmadapter->pscan_table[del_idx].prsn_ie =
2756 					(IEEEtypes_Generic_t *)
2757 					(pmadapter->pscan_table[del_idx].
2758 					 pbeacon_buf +
2759 					 pmadapter->pscan_table[del_idx].
2760 					 rsn_offset);
2761 			}
2762 			if (pmadapter->pscan_table[del_idx].pwapi_ie) {
2763 				pmadapter->pscan_table[del_idx].pwapi_ie =
2764 					(IEEEtypes_Generic_t *)
2765 					(pmadapter->pscan_table[del_idx].
2766 					 pbeacon_buf +
2767 					 pmadapter->pscan_table[del_idx].
2768 					 wapi_offset);
2769 			}
2770 			if (pmadapter->pscan_table[del_idx].pmd_ie) {
2771 				pmadapter->pscan_table[del_idx].pmd_ie =
2772 					(IEEEtypes_MobilityDomain_t *)
2773 					(pmadapter->pscan_table[del_idx].
2774 					 pbeacon_buf +
2775 					 pmadapter->pscan_table[del_idx].
2776 					 md_offset);
2777 			}
2778 			if (pmadapter->pscan_table[del_idx].pht_cap) {
2779 				pmadapter->pscan_table[del_idx].pht_cap =
2780 					(IEEEtypes_HTCap_t *)(pmadapter->
2781 							      pscan_table
2782 							      [del_idx].
2783 							      pbeacon_buf +
2784 							      pmadapter->
2785 							      pscan_table
2786 							      [del_idx].
2787 							      ht_cap_offset);
2788 			}
2789 
2790 			if (pmadapter->pscan_table[del_idx].pht_info) {
2791 				pmadapter->pscan_table[del_idx].pht_info =
2792 					(IEEEtypes_HTInfo_t *)(pmadapter->
2793 							       pscan_table
2794 							       [del_idx].
2795 							       pbeacon_buf +
2796 							       pmadapter->
2797 							       pscan_table
2798 							       [del_idx].
2799 							       ht_info_offset);
2800 			}
2801 			if (pmadapter->pscan_table[del_idx].pbss_co_2040) {
2802 				pmadapter->pscan_table[del_idx].pbss_co_2040 =
2803 					(IEEEtypes_2040BSSCo_t *)(pmadapter->
2804 								  pscan_table
2805 								  [del_idx].
2806 								  pbeacon_buf +
2807 								  pmadapter->
2808 								  pscan_table
2809 								  [del_idx].
2810 								  bss_co_2040_offset);
2811 			}
2812 			if (pmadapter->pscan_table[del_idx].pext_cap) {
2813 				pmadapter->pscan_table[del_idx].pext_cap =
2814 					(IEEEtypes_ExtCap_t *)(pmadapter->
2815 							       pscan_table
2816 							       [del_idx].
2817 							       pbeacon_buf +
2818 							       pmadapter->
2819 							       pscan_table
2820 							       [del_idx].
2821 							       ext_cap_offset);
2822 			}
2823 			if (pmadapter->pscan_table[del_idx].
2824 			    poverlap_bss_scan_param) {
2825 				pmadapter->pscan_table[del_idx].
2826 					poverlap_bss_scan_param =
2827 					(IEEEtypes_OverlapBSSScanParam_t
2828 					 *)(pmadapter->pscan_table[del_idx].
2829 					    pbeacon_buf +
2830 					    pmadapter->pscan_table[del_idx].
2831 					    overlap_bss_offset);
2832 			}
2833 
2834 		}
2835 	}
2836 
2837 	/* The last entry is invalid now that it has been deleted or moved back */
2838 	memset(pmadapter,
2839 	       pmadapter->pscan_table + pmadapter->num_in_scan_table - 1, 0x00,
2840 	       sizeof(BSSDescriptor_t));
2841 
2842 	pmadapter->num_in_scan_table--;
2843 
2844 	LEAVE();
2845 }
2846 
2847 /**
2848  *  @brief Delete all occurrences of a given SSID from the scan table
2849  *
2850  *  Iterate through the scan table and delete all entries that match a given
2851  *    SSID.  Compact the remaining scan table entries.
2852  *
2853  *  @param pmpriv       A pointer to mlan_private structure
2854  *  @param pdel_ssid    Pointer to an SSID to be used in deleting all
2855  *                        matching SSIDs from the scan table
2856  *
2857  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2858  */
2859 static mlan_status
wlan_scan_delete_ssid_table_entry(IN mlan_private * pmpriv,IN mlan_802_11_ssid * pdel_ssid)2860 wlan_scan_delete_ssid_table_entry(IN mlan_private *pmpriv,
2861 				  IN mlan_802_11_ssid *pdel_ssid)
2862 {
2863 	mlan_status ret = MLAN_STATUS_FAILURE;
2864 	t_s32 table_idx;
2865 
2866 	ENTER();
2867 
2868 	PRINTM(MINFO, "Scan: Delete Ssid Entry: %-32s\n", pdel_ssid->ssid);
2869 
2870 	/*
2871 	 * If the requested SSID is found in the table, delete it.  Then keep
2872 	 * searching the table for multiple entries for the SSID until no
2873 	 * more are found
2874 	 */
2875 	while ((table_idx = wlan_find_ssid_in_list(pmpriv,
2876 						   pdel_ssid,
2877 						   MNULL,
2878 						   MLAN_BSS_MODE_AUTO)) >= 0) {
2879 		PRINTM(MINFO, "Scan: Delete SSID Entry: Found Idx = %d\n",
2880 		       table_idx);
2881 		ret = MLAN_STATUS_SUCCESS;
2882 		wlan_scan_delete_table_entry(pmpriv, table_idx);
2883 	}
2884 
2885 	LEAVE();
2886 	return ret;
2887 }
2888 
2889 /********************************************************
2890 			Global Functions
2891 ********************************************************/
2892 
2893 /**
2894  *  @brief Check if a scanned network compatible with the driver settings
2895  *
2896  *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
2897  * enabled enabled  enabled   AES     mode   Privacy  WPA  WPA2  Compatible
2898  *    0       0        0       0      NONE      0      0    0   yes No security
2899  *    0       1        0       0       x        1x     1    x   yes WPA (disable HT if no AES)
2900  *    0       0        1       0       x        1x     x    1   yes WPA2 (disable HT if no AES)
2901  *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
2902  *    1       0        0       0      NONE      1      0    0   yes Static WEP (disable HT)
2903  *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
2904  *
2905  *  @param pmpriv  A pointer to mlan_private
2906  *  @param index   Index in scan table to check against current driver settings
2907  *  @param mode    Network mode: Infrastructure or IBSS
2908  *
2909  *  @return        Index in ScanTable, or negative value if error
2910  */
2911 t_s32
wlan_is_network_compatible(IN mlan_private * pmpriv,IN t_u32 index,IN t_u32 mode)2912 wlan_is_network_compatible(IN mlan_private *pmpriv,
2913 			   IN t_u32 index, IN t_u32 mode)
2914 {
2915 	mlan_adapter *pmadapter = pmpriv->adapter;
2916 	BSSDescriptor_t *pbss_desc;
2917 
2918 	ENTER();
2919 
2920 	pbss_desc = &pmadapter->pscan_table[index];
2921 	/* Don't check for compatibility if roaming */
2922 	if ((pmpriv->media_connected == MTRUE)
2923 	    && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
2924 	    && (pbss_desc->bss_mode == MLAN_BSS_MODE_INFRA)) {
2925 		LEAVE();
2926 		return index;
2927 	}
2928 
2929 	pbss_desc->disable_11n = MFALSE;
2930 
2931 	if (pbss_desc->wlan_11h_bss_info.chan_switch_ann.element_id ==
2932 	    CHANNEL_SWITCH_ANN) {
2933 		PRINTM(MINFO,
2934 		       "Don't connect to AP with CHANNEL_SWITCH_ANN IE.\n");
2935 		LEAVE();
2936 		return -1;
2937 	}
2938 
2939 	if (pmpriv->wps.session_enable == MTRUE) {
2940 		PRINTM(MINFO, "Return success directly in WPS period\n");
2941 		LEAVE();
2942 		return index;
2943 	}
2944 
2945 	if ((pbss_desc->bss_mode == mode) &&
2946 	    (pmpriv->sec_info.ewpa_enabled == MTRUE
2947 #ifdef DRV_EMBEDDED_SUPPLICANT
2948 	     || supplicantIsEnabled(pmpriv->psapriv)
2949 #endif
2950 	    )) {
2951 		if (((pbss_desc->pwpa_ie) &&
2952 		     ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE)) ||
2953 		    ((pbss_desc->prsn_ie) &&
2954 		     ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE))) {
2955 			if (((pmpriv->adapter->config_bands & BAND_GN ||
2956 			      pmpriv->adapter->config_bands & BAND_AN) &&
2957 			     pbss_desc->pht_cap)
2958 			    && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
2959 			    && !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
2960 						   CIPHER_SUITE_CCMP)
2961 			    && !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
2962 						   CIPHER_SUITE_CCMP)) {
2963 
2964 				if (is_wpa_oui_present
2965 				    (pmpriv->adapter, pbss_desc,
2966 				     CIPHER_SUITE_TKIP)
2967 				    || is_rsn_oui_present(pmpriv->adapter,
2968 							  pbss_desc,
2969 							  CIPHER_SUITE_TKIP)) {
2970 					PRINTM(MINFO,
2971 					       "Disable 11n if AES is not supported by AP\n");
2972 					pbss_desc->disable_11n = MTRUE;
2973 				} else {
2974 					LEAVE();
2975 					return -1;
2976 				}
2977 			}
2978 			LEAVE();
2979 			return index;
2980 		} else {
2981 			PRINTM(MINFO,
2982 			       "ewpa_enabled: Ignore none WPA/WPA2 AP\n");
2983 			LEAVE();
2984 			return -1;
2985 		}
2986 	}
2987 
2988 	if (pmpriv->sec_info.wapi_enabled &&
2989 	    (pbss_desc->pwapi_ie &&
2990 	     ((*(pbss_desc->pwapi_ie)).ieee_hdr.element_id == WAPI_IE))) {
2991 		PRINTM(MINFO, "Return success for WAPI AP\n");
2992 		LEAVE();
2993 		return index;
2994 	}
2995 
2996 	if (pbss_desc->bss_mode == mode) {
2997 		if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
2998 		    && !pmpriv->sec_info.wpa_enabled
2999 		    && !pmpriv->sec_info.wpa2_enabled
3000 		    && ((!pbss_desc->pwpa_ie) ||
3001 			((*(pbss_desc->pwpa_ie)).vend_hdr.element_id != WPA_IE))
3002 		    && ((!pbss_desc->prsn_ie) ||
3003 			((*(pbss_desc->prsn_ie)).ieee_hdr.element_id != RSN_IE))
3004 		    && !pmpriv->adhoc_aes_enabled &&
3005 		    pmpriv->sec_info.encryption_mode ==
3006 		    MLAN_ENCRYPTION_MODE_NONE && !pbss_desc->privacy) {
3007 			/* No security */
3008 			LEAVE();
3009 			return index;
3010 		} else if (pmpriv->sec_info.wep_status == Wlan802_11WEPEnabled
3011 			   && !pmpriv->sec_info.wpa_enabled
3012 			   && !pmpriv->sec_info.wpa2_enabled
3013 			   && !pmpriv->adhoc_aes_enabled
3014 			   && pbss_desc->privacy) {
3015 			/* Static WEP enabled */
3016 			PRINTM(MINFO, "Disable 11n in WEP mode\n");
3017 			pbss_desc->disable_11n = MTRUE;
3018 			/* Reject the following cases: */
3019 			/*
3020 			 * case 1: RSN IE w/o WEP OUI and WPA IE w/o WEP OUI
3021 			 * case 2: RSN IE w/o WEP OUI and No WPA IE
3022 			 * case 3: WPA IE w/o WEP OUI and No RSN IE
3023 			 */
3024 			if (((pbss_desc->prsn_ie) &&
3025 			     ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
3026 			      RSN_IE)) || ((pbss_desc->pwpa_ie) &&
3027 					   ((*(pbss_desc->pwpa_ie)).vend_hdr.
3028 					    element_id == WPA_IE))) {
3029 				if (!is_rsn_oui_present
3030 				    (pmpriv->adapter, pbss_desc,
3031 				     CIPHER_SUITE_WEP40) &&
3032 				    !is_rsn_oui_present(pmpriv->adapter,
3033 							pbss_desc,
3034 							CIPHER_SUITE_WEP104) &&
3035 				    !is_wpa_oui_present(pmpriv->adapter,
3036 							pbss_desc,
3037 							CIPHER_SUITE_WEP40) &&
3038 				    !is_wpa_oui_present(pmpriv->adapter,
3039 							pbss_desc,
3040 							CIPHER_SUITE_WEP104))
3041 					index = -1;
3042 			}
3043 
3044 			LEAVE();
3045 			return index;
3046 		} else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
3047 			   && pmpriv->sec_info.wpa_enabled
3048 			   && !pmpriv->sec_info.wpa2_enabled
3049 			   && ((pbss_desc->pwpa_ie) &&
3050 			       ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id ==
3051 				WPA_IE))
3052 			   && !pmpriv->adhoc_aes_enabled
3053 			   /*
3054 			    * Privacy bit may NOT be set in some APs like
3055 			    * LinkSys WRT54G && pbss_desc->privacy
3056 			    */
3057 			) {
3058 			/* WPA enabled */
3059 			PRINTM(MINFO,
3060 			       "wlan_is_network_compatible() WPA: index=%d wpa_ie=%#x "
3061 			       "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
3062 			       "privacy=%#x\n", index,
3063 			       (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).
3064 			       vend_hdr.element_id : 0,
3065 			       (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).
3066 			       ieee_hdr.element_id : 0,
3067 			       (pmpriv->sec_info.wep_status ==
3068 				Wlan802_11WEPEnabled) ? "e" : "d",
3069 			       (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
3070 			       (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
3071 			       pmpriv->sec_info.encryption_mode,
3072 			       pbss_desc->privacy);
3073 			if (((pmpriv->adapter->config_bands & BAND_GN ||
3074 			      pmpriv->adapter->config_bands & BAND_AN) &&
3075 			     pbss_desc->pht_cap)
3076 			    && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
3077 			    && !is_wpa_oui_present(pmpriv->adapter, pbss_desc,
3078 						   CIPHER_SUITE_CCMP)) {
3079 				if (is_wpa_oui_present
3080 				    (pmpriv->adapter, pbss_desc,
3081 				     CIPHER_SUITE_TKIP)) {
3082 					PRINTM(MINFO,
3083 					       "Disable 11n if AES is not supported by AP\n");
3084 					pbss_desc->disable_11n = MTRUE;
3085 				} else {
3086 					LEAVE();
3087 					return -1;
3088 				}
3089 			}
3090 			LEAVE();
3091 			return index;
3092 		} else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
3093 			   && !pmpriv->sec_info.wpa_enabled
3094 			   && pmpriv->sec_info.wpa2_enabled
3095 			   && ((pbss_desc->prsn_ie) &&
3096 			       ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id ==
3097 				RSN_IE))
3098 			   && !pmpriv->adhoc_aes_enabled
3099 			   /*
3100 			    * Privacy bit may NOT be set in some APs like
3101 			    * LinkSys WRT54G && pbss_desc->privacy
3102 			    */
3103 			) {
3104 			/* WPA2 enabled */
3105 			PRINTM(MINFO,
3106 			       "wlan_is_network_compatible() WPA2: index=%d wpa_ie=%#x "
3107 			       "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x "
3108 			       "privacy=%#x\n", index,
3109 			       (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).
3110 			       vend_hdr.element_id : 0,
3111 			       (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).
3112 			       ieee_hdr.element_id : 0,
3113 			       (pmpriv->sec_info.wep_status ==
3114 				Wlan802_11WEPEnabled) ? "e" : "d",
3115 			       (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
3116 			       (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
3117 			       pmpriv->sec_info.encryption_mode,
3118 			       pbss_desc->privacy);
3119 			if (((pmpriv->adapter->config_bands & BAND_GN ||
3120 			      pmpriv->adapter->config_bands & BAND_AN) &&
3121 			     pbss_desc->pht_cap)
3122 			    && (pmpriv->bss_mode == MLAN_BSS_MODE_INFRA)
3123 			    && !is_rsn_oui_present(pmpriv->adapter, pbss_desc,
3124 						   CIPHER_SUITE_CCMP)) {
3125 				if (is_rsn_oui_present
3126 				    (pmpriv->adapter, pbss_desc,
3127 				     CIPHER_SUITE_TKIP)) {
3128 					PRINTM(MINFO,
3129 					       "Disable 11n if AES is not supported by AP\n");
3130 					pbss_desc->disable_11n = MTRUE;
3131 				} else {
3132 					LEAVE();
3133 					return -1;
3134 				}
3135 			}
3136 			LEAVE();
3137 			return index;
3138 		} else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
3139 			   && !pmpriv->sec_info.wpa_enabled
3140 			   && !pmpriv->sec_info.wpa2_enabled
3141 			   && ((!pbss_desc->pwpa_ie) ||
3142 			       ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id !=
3143 				WPA_IE))
3144 			   && ((!pbss_desc->prsn_ie) ||
3145 			       ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id !=
3146 				RSN_IE))
3147 			   && pmpriv->adhoc_aes_enabled &&
3148 			   pmpriv->sec_info.encryption_mode ==
3149 			   MLAN_ENCRYPTION_MODE_NONE && pbss_desc->privacy) {
3150 			/* Ad-hoc AES enabled */
3151 			LEAVE();
3152 			return index;
3153 		} else if (pmpriv->sec_info.wep_status == Wlan802_11WEPDisabled
3154 			   && !pmpriv->sec_info.wpa_enabled
3155 			   && !pmpriv->sec_info.wpa2_enabled
3156 			   && ((!pbss_desc->pwpa_ie) ||
3157 			       ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id !=
3158 				WPA_IE))
3159 			   && ((!pbss_desc->prsn_ie) ||
3160 			       ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id !=
3161 				RSN_IE))
3162 			   && !pmpriv->adhoc_aes_enabled &&
3163 			   pmpriv->sec_info.encryption_mode !=
3164 			   MLAN_ENCRYPTION_MODE_NONE && pbss_desc->privacy) {
3165 			/* Dynamic WEP enabled */
3166 			pbss_desc->disable_11n = MTRUE;
3167 			PRINTM(MINFO,
3168 			       "wlan_is_network_compatible() dynamic WEP: index=%d "
3169 			       "wpa_ie=%#x rsn_ie=%#x EncMode=%#x privacy=%#x\n",
3170 			       index,
3171 			       (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).
3172 			       vend_hdr.element_id : 0,
3173 			       (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).
3174 			       ieee_hdr.element_id : 0,
3175 			       pmpriv->sec_info.encryption_mode,
3176 			       pbss_desc->privacy);
3177 			LEAVE();
3178 			return index;
3179 		}
3180 
3181 		/* Security doesn't match */
3182 		PRINTM(MINFO,
3183 		       "wlan_is_network_compatible() FAILED: index=%d wpa_ie=%#x "
3184 		       "rsn_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
3185 		       index,
3186 		       (pbss_desc->pwpa_ie) ? (*(pbss_desc->pwpa_ie)).vend_hdr.
3187 		       element_id : 0,
3188 		       (pbss_desc->prsn_ie) ? (*(pbss_desc->prsn_ie)).ieee_hdr.
3189 		       element_id : 0,
3190 		       (pmpriv->sec_info.wep_status ==
3191 			Wlan802_11WEPEnabled) ? "e" : "d",
3192 		       (pmpriv->sec_info.wpa_enabled) ? "e" : "d",
3193 		       (pmpriv->sec_info.wpa2_enabled) ? "e" : "d",
3194 		       pmpriv->sec_info.encryption_mode, pbss_desc->privacy);
3195 		LEAVE();
3196 		return -1;
3197 	}
3198 
3199 	/* Mode doesn't match */
3200 	LEAVE();
3201 	return -1;
3202 }
3203 
3204 /**
3205  *  @brief Internal function used to flush the scan list
3206  *
3207  *  @param pmadapter    A pointer to mlan_adapter structure
3208  *
3209  *  @return             MLAN_STATUS_SUCCESS
3210  */
3211 mlan_status
wlan_flush_scan_table(IN pmlan_adapter pmadapter)3212 wlan_flush_scan_table(IN pmlan_adapter pmadapter)
3213 {
3214 	t_u8 i = 0;
3215 	ENTER();
3216 
3217 	PRINTM(MINFO, "Flushing scan table\n");
3218 
3219 	memset(pmadapter, pmadapter->pscan_table, 0,
3220 	       (sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST));
3221 	pmadapter->num_in_scan_table = 0;
3222 
3223 	memset(pmadapter, pmadapter->bcn_buf, 0, pmadapter->bcn_buf_size);
3224 	pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
3225 
3226 	for (i = 0; i < pmadapter->num_in_chan_stats; i++)
3227 		pmadapter->pchan_stats[i].cca_scan_duration = 0;
3228 	pmadapter->idx_chan_stats = 0;
3229 
3230 	LEAVE();
3231 	return MLAN_STATUS_SUCCESS;
3232 }
3233 
3234 /**
3235  *  @brief Internal function used to start a scan based on an input config
3236  *
3237  *  Use the input user scan configuration information when provided in
3238  *    order to send the appropriate scan commands to firmware to populate or
3239  *    update the internal driver scan table
3240  *
3241  *  @param pmpriv          A pointer to mlan_private structure
3242  *  @param pioctl_buf      A pointer to MLAN IOCTL Request buffer
3243  *  @param puser_scan_in   Pointer to the input configuration for the requested
3244  *                         scan.
3245  *
3246  *  @return              MLAN_STATUS_SUCCESS or < 0 if error
3247  */
3248 mlan_status
wlan_scan_networks(IN mlan_private * pmpriv,IN t_void * pioctl_buf,IN wlan_user_scan_cfg * puser_scan_in)3249 wlan_scan_networks(IN mlan_private *pmpriv,
3250 		   IN t_void *pioctl_buf, IN wlan_user_scan_cfg *puser_scan_in)
3251 {
3252 	mlan_status ret = MLAN_STATUS_SUCCESS;
3253 	mlan_adapter *pmadapter = pmpriv->adapter;
3254 	mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
3255 	cmd_ctrl_node *pcmd_node = MNULL;
3256 	pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
3257 
3258 	wlan_scan_cmd_config_tlv *pscan_cfg_out = MNULL;
3259 	MrvlIEtypes_ChanListParamSet_t *pchan_list_out;
3260 	t_u32 buf_size;
3261 	ChanScanParamSet_t *pscan_chan_list;
3262 
3263 	t_u8 keep_previous_scan;
3264 	t_u8 filtered_scan;
3265 	t_u8 scan_current_chan_only;
3266 	t_u8 max_chan_per_scan;
3267 	t_u8 i;
3268 
3269 	ENTER();
3270 
3271 	ret = pcb->moal_malloc(pmadapter->pmoal_handle,
3272 			       sizeof(wlan_scan_cmd_config_tlv), MLAN_MEM_DEF,
3273 			       (t_u8 **)&pscan_cfg_out);
3274 	if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg_out) {
3275 		PRINTM(MERROR, "Memory allocation for pscan_cfg_out failed!\n");
3276 		if (pioctl_req)
3277 			pioctl_req->status_code = MLAN_ERROR_NO_MEM;
3278 		LEAVE();
3279 		return MLAN_STATUS_FAILURE;
3280 	}
3281 
3282 	buf_size = sizeof(ChanScanParamSet_t) * WLAN_USER_SCAN_CHAN_MAX;
3283 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, buf_size, MLAN_MEM_DEF,
3284 			       (t_u8 **)&pscan_chan_list);
3285 	if (ret != MLAN_STATUS_SUCCESS || !pscan_chan_list) {
3286 		PRINTM(MERROR, "Failed to allocate scan_chan_list\n");
3287 		if (pscan_cfg_out)
3288 			pcb->moal_mfree(pmadapter->pmoal_handle,
3289 					(t_u8 *)pscan_cfg_out);
3290 		if (pioctl_req)
3291 			pioctl_req->status_code = MLAN_ERROR_NO_MEM;
3292 		LEAVE();
3293 		return MLAN_STATUS_FAILURE;
3294 	}
3295 
3296 	memset(pmadapter, pscan_chan_list, 0x00, buf_size);
3297 	memset(pmadapter, pscan_cfg_out, 0x00,
3298 	       sizeof(wlan_scan_cmd_config_tlv));
3299 
3300 	keep_previous_scan = MFALSE;
3301 
3302 	ret = wlan_scan_setup_scan_config(pmpriv,
3303 					  puser_scan_in,
3304 					  &pscan_cfg_out->config,
3305 					  &pchan_list_out,
3306 					  pscan_chan_list,
3307 					  &max_chan_per_scan,
3308 					  &filtered_scan,
3309 					  &scan_current_chan_only);
3310 	if (ret != MLAN_STATUS_SUCCESS) {
3311 
3312 		PRINTM(MERROR, "Failed to setup scan config\n");
3313 		if (pscan_cfg_out)
3314 			pcb->moal_mfree(pmadapter->pmoal_handle,
3315 					(t_u8 *)pscan_cfg_out);
3316 		if (pscan_chan_list)
3317 			pcb->moal_mfree(pmadapter->pmoal_handle,
3318 					(t_u8 *)pscan_chan_list);
3319 		if (pioctl_req)
3320 			pioctl_req->status_code = MLAN_ERROR_INVALID_PARAMETER;
3321 		LEAVE();
3322 		return MLAN_STATUS_FAILURE;
3323 	}
3324 
3325 	if (puser_scan_in)
3326 		keep_previous_scan = puser_scan_in->keep_previous_scan;
3327 
3328 	if (keep_previous_scan == MFALSE) {
3329 		memset(pmadapter, pmadapter->pscan_table, 0x00,
3330 		       sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST);
3331 		pmadapter->num_in_scan_table = 0;
3332 		pmadapter->pbcn_buf_end = pmadapter->bcn_buf;
3333 		for (i = 0; i < pmadapter->num_in_chan_stats; i++)
3334 			pmadapter->pchan_stats[i].cca_scan_duration = 0;
3335 		pmadapter->idx_chan_stats = 0;
3336 	}
3337 
3338 	ret = wlan_scan_channel_list(pmpriv,
3339 				     pioctl_buf,
3340 				     max_chan_per_scan,
3341 				     filtered_scan,
3342 				     &pscan_cfg_out->config,
3343 				     pchan_list_out, pscan_chan_list);
3344 
3345 	/* Get scan command from scan_pending_q and put to cmd_pending_q */
3346 	if (ret == MLAN_STATUS_SUCCESS) {
3347 		if (pmadapter->ext_scan && pmadapter->ext_scan_enh &&
3348 		    pmadapter->ext_scan_type == EXT_SCAN_ENHANCE) {
3349 			wlan_request_cmd_lock(pmadapter);
3350 			pmadapter->pscan_ioctl_req = pioctl_req;
3351 			pmadapter->scan_processing = MTRUE;
3352 			wlan_release_cmd_lock(pmadapter);
3353 		} else {
3354 			wlan_request_cmd_lock(pmadapter);
3355 			if (util_peek_list
3356 			    (pmadapter->pmoal_handle,
3357 			     &pmadapter->scan_pending_q, MNULL, MNULL)) {
3358 				pcmd_node =
3359 					(cmd_ctrl_node *)
3360 					util_dequeue_list(pmadapter->
3361 							  pmoal_handle,
3362 							  &pmadapter->
3363 							  scan_pending_q, MNULL,
3364 							  MNULL);
3365 				pmadapter->pscan_ioctl_req = pioctl_req;
3366 				pmadapter->scan_processing = MTRUE;
3367 				wlan_insert_cmd_to_pending_q(pmadapter,
3368 							     pcmd_node, MTRUE);
3369 			}
3370 			wlan_release_cmd_lock(pmadapter);
3371 		}
3372 	}
3373 	if (pscan_cfg_out)
3374 		pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pscan_cfg_out);
3375 
3376 	if (pscan_chan_list)
3377 		pcb->moal_mfree(pmadapter->pmoal_handle,
3378 				(t_u8 *)pscan_chan_list);
3379 
3380 	LEAVE();
3381 	return ret;
3382 }
3383 
3384 /**
3385  *  @brief Prepare a scan command to be sent to the firmware
3386  *
3387  *  Use the wlan_scan_cmd_config sent to the command processing module in
3388  *   the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN command
3389  *   struct to send to firmware.
3390  *
3391  *  The fixed fields specifying the BSS type and BSSID filters as well as a
3392  *   variable number/length of TLVs are sent in the command to firmware.
3393  *
3394  *  @param pmpriv     A pointer to mlan_private structure
3395  *  @param pcmd       A pointer to HostCmd_DS_COMMAND structure to be sent to
3396  *                    firmware with the HostCmd_DS_801_11_SCAN structure
3397  *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
3398  *                    to set the fields/TLVs for the command sent to firmware
3399  *
3400  *  @return           MLAN_STATUS_SUCCESS
3401  */
3402 mlan_status
wlan_cmd_802_11_scan(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * pcmd,IN t_void * pdata_buf)3403 wlan_cmd_802_11_scan(IN mlan_private *pmpriv,
3404 		     IN HostCmd_DS_COMMAND *pcmd, IN t_void *pdata_buf)
3405 {
3406 	HostCmd_DS_802_11_SCAN *pscan_cmd = &pcmd->params.scan;
3407 	wlan_scan_cmd_config *pscan_cfg;
3408 
3409 	ENTER();
3410 
3411 	pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
3412 
3413 	/* Set fixed field variables in scan command */
3414 	pscan_cmd->bss_mode = pscan_cfg->bss_mode;
3415 	memcpy(pmpriv->adapter, pscan_cmd->bssid, pscan_cfg->specific_bssid,
3416 	       sizeof(pscan_cmd->bssid));
3417 	memcpy(pmpriv->adapter, pscan_cmd->tlv_buffer, pscan_cfg->tlv_buf,
3418 	       pscan_cfg->tlv_buf_len);
3419 
3420 	pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN);
3421 
3422 	/* Size is equal to the sizeof(fixed portions) + the TLV len + header */
3423 	pcmd->size = (t_u16)wlan_cpu_to_le16((t_u16)(sizeof(pscan_cmd->bss_mode)
3424 						     + sizeof(pscan_cmd->bssid)
3425 						     + pscan_cfg->tlv_buf_len
3426 						     + S_DS_GEN));
3427 
3428 	LEAVE();
3429 	return MLAN_STATUS_SUCCESS;
3430 }
3431 
3432 /**
3433  *  @brief  Check if any hidden SSID found in passive scan channels
3434  *          and do specific SSID active scan for those channels
3435  *
3436  *  @param pmpriv       A pointer to mlan_private structure
3437  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
3438  *
3439  *  @return             MTRUE/MFALSE
3440  */
3441 
3442 t_bool
wlan_active_scan_req_for_passive_chan(IN mlan_private * pmpriv,IN mlan_ioctl_req * pioctl_buf)3443 wlan_active_scan_req_for_passive_chan(IN mlan_private *pmpriv,
3444 				      IN mlan_ioctl_req *pioctl_buf)
3445 {
3446 	t_bool ret = MFALSE;
3447 	mlan_adapter *pmadapter = pmpriv->adapter;
3448 	t_bool scan_reqd = MFALSE;
3449 	t_bool chan_listed = MFALSE;
3450 	t_u8 id = 0;
3451 	t_u32 bss_idx, i;
3452 	t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = { 0 };
3453 	mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
3454 	wlan_user_scan_cfg *user_scan_cfg;
3455 	mlan_ds_scan *pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
3456 	mlan_scan_req *pscan_req = MNULL;
3457 	wlan_user_scan_cfg *puser_scan_in = MNULL;
3458 
3459 	ENTER();
3460 
3461 	if (pscan->sub_command == MLAN_OID_SCAN_USER_CONFIG) {
3462 		puser_scan_in =
3463 			(wlan_user_scan_cfg *)pscan->param.user_scan.
3464 			scan_cfg_buf;
3465 		if (!puser_scan_in->ssid_filter)
3466 			goto done;
3467 	}
3468 
3469 	if (pmadapter->active_scan_triggered) {
3470 		pmadapter->active_scan_triggered = MFALSE;
3471 		goto done;
3472 	}
3473 
3474 	if ((pcb->
3475 	     moal_malloc(pmadapter->pmoal_handle, sizeof(wlan_user_scan_cfg),
3476 			 MLAN_MEM_DEF,
3477 			 (t_u8 **)&user_scan_cfg) != MLAN_STATUS_SUCCESS) ||
3478 	    !user_scan_cfg) {
3479 		PRINTM(MERROR, "Memory allocation for user_scan_cfg failed\n");
3480 		goto done;
3481 	}
3482 	memset(pmadapter, user_scan_cfg, 0, sizeof(wlan_user_scan_cfg));
3483 	for (bss_idx = 0; bss_idx < pmadapter->num_in_scan_table; bss_idx++) {
3484 		scan_reqd = MFALSE;
3485 		if (!memcmp
3486 		    (pmadapter, pmadapter->pscan_table[bss_idx].ssid.ssid,
3487 		     null_ssid,
3488 		     pmadapter->pscan_table[bss_idx].ssid.ssid_len)) {
3489 			if (puser_scan_in &&
3490 			    puser_scan_in->chan_list[0].chan_number) {
3491 				for (i = 0;
3492 				     i < WLAN_USER_SCAN_CHAN_MAX &&
3493 				     puser_scan_in->chan_list[i].chan_number;
3494 				     i++) {
3495 					if (puser_scan_in->chan_list[i].
3496 					    chan_number ==
3497 					    pmadapter->pscan_table[bss_idx].
3498 					    channel) {
3499 						if (puser_scan_in->chan_list[i].
3500 						    scan_type ==
3501 						    MLAN_SCAN_TYPE_PASSIVE)
3502 							scan_reqd = MTRUE;
3503 						break;
3504 					}
3505 				}
3506 			} else if (pmadapter->scan_type ==
3507 				   MLAN_SCAN_TYPE_PASSIVE) {
3508 				scan_reqd = MTRUE;
3509 			} else {
3510 				if ((pmadapter->pscan_table[bss_idx].
3511 				     bss_band & BAND_A) &&
3512 				    wlan_11h_radar_detect_required(pmpriv,
3513 								   pmadapter->
3514 								   pscan_table
3515 								   [bss_idx].
3516 								   channel))
3517 					scan_reqd = MTRUE;
3518 				if (pmadapter->pscan_table[bss_idx].
3519 				    bss_band & (BAND_B | BAND_G) &&
3520 				    wlan_bg_scan_type_is_passive(pmpriv,
3521 								 pmadapter->
3522 								 pscan_table
3523 								 [bss_idx].
3524 								 channel))
3525 					scan_reqd = MTRUE;
3526 			}
3527 
3528 			if (scan_reqd) {
3529 				chan_listed = MFALSE;
3530 				for (i = 0; i < id; i++) {
3531 					if ((user_scan_cfg->chan_list[i].
3532 					     chan_number ==
3533 					     pmadapter->pscan_table[bss_idx].
3534 					     channel)
3535 					    && (user_scan_cfg->chan_list[i].
3536 						radio_type & pmadapter->
3537 						pscan_table[bss_idx].
3538 						bss_band)) {
3539 						chan_listed = MTRUE;
3540 						break;
3541 					}
3542 				}
3543 				if (chan_listed == MTRUE)
3544 					continue;
3545 				user_scan_cfg->chan_list[id].chan_number =
3546 					pmadapter->pscan_table[bss_idx].channel;
3547 				if (pmadapter->pscan_table[bss_idx].
3548 				    bss_band & (BAND_B | BAND_G))
3549 					user_scan_cfg->chan_list[id].
3550 						radio_type = BAND_2GHZ;
3551 				if (pmadapter->pscan_table[bss_idx].
3552 				    bss_band & BAND_A)
3553 					user_scan_cfg->chan_list[id].
3554 						radio_type = BAND_5GHZ;
3555 				user_scan_cfg->chan_list[id].scan_type =
3556 					MLAN_SCAN_TYPE_ACTIVE;
3557 				id++;
3558 			}
3559 		}
3560 	}
3561 	if (id) {
3562 		pmadapter->active_scan_triggered = MTRUE;
3563 		if (pscan->sub_command == MLAN_OID_SCAN_USER_CONFIG) {
3564 			memcpy(pmpriv->adapter, user_scan_cfg->ssid_list,
3565 			       puser_scan_in->ssid_list,
3566 			       sizeof(user_scan_cfg->ssid_list));
3567 		} else {
3568 			pscan_req = &pscan->param.scan_req;
3569 			memcpy(pmpriv->adapter,
3570 			       user_scan_cfg->ssid_list[0].ssid,
3571 			       pscan_req->scan_ssid.ssid,
3572 			       pscan_req->scan_ssid.ssid_len);
3573 		}
3574 		user_scan_cfg->keep_previous_scan = MTRUE;
3575 		if (MLAN_STATUS_SUCCESS != wlan_scan_networks(pmpriv,
3576 							      pioctl_buf,
3577 							      user_scan_cfg)) {
3578 			goto done;
3579 		}
3580 		ret = MTRUE;
3581 	}
3582 	if (user_scan_cfg)
3583 		pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)user_scan_cfg);
3584 
3585 done:
3586 	LEAVE();
3587 	return ret;
3588 }
3589 
3590 /**
3591  *  @brief This function handles the command response of scan
3592  *
3593  *   The response buffer for the scan command has the following
3594  *      memory layout:
3595  *
3596  *     .-------------------------------------------------------------.
3597  *     |  Header (4 * sizeof(t_u16)):  Standard command response hdr |
3598  *     .-------------------------------------------------------------.
3599  *     |  BufSize (t_u16) : sizeof the BSS Description data          |
3600  *     .-------------------------------------------------------------.
3601  *     |  NumOfSet (t_u8) : Number of BSS Descs returned             |
3602  *     .-------------------------------------------------------------.
3603  *     |  BSSDescription data (variable, size given in BufSize)      |
3604  *     .-------------------------------------------------------------.
3605  *     |  TLV data (variable, size calculated using Header->Size,    |
3606  *     |            BufSize and sizeof the fixed fields above)       |
3607  *     .-------------------------------------------------------------.
3608  *
3609  *  @param pmpriv       A pointer to mlan_private structure
3610  *  @param resp         A pointer to HostCmd_DS_COMMAND
3611  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
3612  *
3613  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3614  */
3615 mlan_status
wlan_ret_802_11_scan(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * resp,IN t_void * pioctl_buf)3616 wlan_ret_802_11_scan(IN mlan_private *pmpriv,
3617 		     IN HostCmd_DS_COMMAND *resp, IN t_void *pioctl_buf)
3618 {
3619 	mlan_status ret = MLAN_STATUS_SUCCESS;
3620 	mlan_adapter *pmadapter = pmpriv->adapter;
3621 	mlan_callbacks *pcb = MNULL;
3622 	cmd_ctrl_node *pcmd_node = MNULL;
3623 	HostCmd_DS_802_11_SCAN_RSP *pscan_rsp = MNULL;
3624 	BSSDescriptor_t *bss_new_entry = MNULL;
3625 	MrvlIEtypes_Data_t *ptlv;
3626 	MrvlIEtypes_TsfTimestamp_t *ptsf_tlv = MNULL;
3627 	MrvlIEtypes_ChannelStats_t *pchanstats_tlv = MNULL;
3628 	t_u8 *pbss_info;
3629 	t_u32 scan_resp_size;
3630 	t_u32 bytes_left;
3631 	t_u32 num_in_table;
3632 	t_u32 bss_idx;
3633 	t_u32 idx;
3634 	t_u32 tlv_buf_size;
3635 	t_u64 tsf_val;
3636 	chan_freq_power_t *cfp;
3637 	MrvlIEtypes_ChanBandListParamSet_t *pchan_band_tlv = MNULL;
3638 	ChanBandParamSet_t *pchan_band;
3639 	t_u8 band;
3640 	t_u8 is_bgscan_resp;
3641 	t_u32 age_ts_usec;
3642 	t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = { 0 };
3643 	t_u32 status_code = 0;
3644 	pmlan_ioctl_req pscan_ioctl_req = MNULL;
3645 
3646 	ENTER();
3647 	pcb = (pmlan_callbacks)&pmadapter->callbacks;
3648 
3649 	is_bgscan_resp = (resp->command == HostCmd_CMD_802_11_BG_SCAN_QUERY);
3650 	if (is_bgscan_resp)
3651 		pscan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
3652 	else
3653 		pscan_rsp = &resp->params.scan_resp;
3654 
3655 	if (pscan_rsp->number_of_sets > MRVDRV_MAX_BSSID_LIST) {
3656 		PRINTM(MERROR,
3657 		       "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
3658 		       pscan_rsp->number_of_sets);
3659 		status_code = MLAN_ERROR_CMD_SCAN_FAIL;
3660 		ret = MLAN_STATUS_FAILURE;
3661 		goto done;
3662 	}
3663 
3664 	bytes_left = wlan_le16_to_cpu(pscan_rsp->bss_descript_size);
3665 	PRINTM(MINFO, "SCAN_RESP: bss_descript_size %d\n", bytes_left);
3666 
3667 	scan_resp_size = resp->size;
3668 
3669 	PRINTM(MINFO, "SCAN_RESP: returned %d APs before parsing\n",
3670 	       pscan_rsp->number_of_sets);
3671 
3672 	num_in_table = pmadapter->num_in_scan_table;
3673 	pbss_info = pscan_rsp->bss_desc_and_tlv_buffer;
3674 
3675 	/*
3676 	 * The size of the TLV buffer is equal to the entire command response
3677 	 *   size (scan_resp_size) minus the fixed fields (sizeof()'s), the
3678 	 *   BSS Descriptions (bss_descript_size as bytesLef) and the command
3679 	 *   response header (S_DS_GEN)
3680 	 */
3681 	tlv_buf_size = scan_resp_size - (bytes_left
3682 					 + sizeof(pscan_rsp->bss_descript_size)
3683 					 + sizeof(pscan_rsp->number_of_sets)
3684 					 + S_DS_GEN);
3685 	if (is_bgscan_resp)
3686 		tlv_buf_size -=
3687 			sizeof(resp->params.bg_scan_query_resp.
3688 			       report_condition);
3689 
3690 	ptlv = (MrvlIEtypes_Data_t *)(pscan_rsp->bss_desc_and_tlv_buffer +
3691 				      bytes_left);
3692 
3693 	/*
3694 	 * Search the TLV buffer space in the scan response
3695 	 * for any valid TLVs
3696 	 */
3697 	wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
3698 					  ptlv,
3699 					  tlv_buf_size,
3700 					  TLV_TYPE_TSFTIMESTAMP,
3701 					  (MrvlIEtypes_Data_t **)&ptsf_tlv);
3702 
3703 	/*
3704 	 * Search the TLV buffer space in the scan response
3705 	 * for any valid TLVs
3706 	 */
3707 	wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter,
3708 					  ptlv,
3709 					  tlv_buf_size,
3710 					  TLV_TYPE_CHANNELBANDLIST,
3711 					  (MrvlIEtypes_Data_t **)
3712 					  &pchan_band_tlv);
3713 	wlan_ret_802_11_scan_get_tlv_ptrs(pmadapter, ptlv, tlv_buf_size,
3714 					  TLV_TYPE_CHANNEL_STATS,
3715 					  (MrvlIEtypes_Data_t **)
3716 					  &pchanstats_tlv);
3717 
3718 	if (pchanstats_tlv)
3719 		wlan_update_chan_statistics(pmpriv, pchanstats_tlv);
3720 
3721 	/*
3722 	 * Process each scan response returned (pscan_rsp->number_of_sets).
3723 	 * Save the information in the bss_new_entry and then insert into
3724 	 * the driver scan table either as an update to an existing entry
3725 	 * or as an addition at the end of the table
3726 	 */
3727 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
3728 			       MLAN_MEM_DEF, (t_u8 **)&bss_new_entry);
3729 
3730 	if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
3731 		PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
3732 		status_code = MLAN_ERROR_NO_MEM;
3733 		ret = MLAN_STATUS_FAILURE;
3734 		goto done;
3735 	}
3736 
3737 	for (idx = 0; idx < pscan_rsp->number_of_sets && bytes_left; idx++) {
3738 		/* Zero out the bss_new_entry we are about to store info in */
3739 		memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
3740 
3741 		/* Process the data fields and IEs returned for this BSS */
3742 		if (wlan_interpret_bss_desc_with_ie(pmadapter,
3743 						    bss_new_entry,
3744 						    &pbss_info,
3745 						    &bytes_left,
3746 						    MFALSE) ==
3747 		    MLAN_STATUS_SUCCESS) {
3748 			PRINTM(MINFO, "SCAN_RESP: BSSID = " MACSTR "\n",
3749 			       MAC2STR(bss_new_entry->mac_address));
3750 
3751 			band = BAND_G;
3752 			if (pchan_band_tlv) {
3753 				pchan_band =
3754 					&pchan_band_tlv->chan_band_param[idx];
3755 				band = radio_type_to_band(pchan_band->bandcfg.
3756 							  chanBand);
3757 				if (!bss_new_entry->channel)
3758 					bss_new_entry->channel =
3759 						pchan_band->chan_number;
3760 			}
3761 			/*
3762 			 * Save the band designation for this entry
3763 			 * for use in join
3764 			 */
3765 			bss_new_entry->bss_band = band;
3766 
3767 			cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
3768 								(t_u8)
3769 								bss_new_entry->
3770 								bss_band,
3771 								(t_u16)
3772 								bss_new_entry->
3773 								channel);
3774 			if (cfp)
3775 				bss_new_entry->freq = cfp->freq;
3776 			else
3777 				bss_new_entry->freq = 0;
3778 
3779 			/* Skip entry if on blacklisted channel */
3780 			if (cfp && cfp->dynamic.blacklist) {
3781 				PRINTM(MINFO,
3782 				       "SCAN_RESP: dropping entry on blacklist channel.\n");
3783 				continue;
3784 			}
3785 
3786 			/*
3787 			 * Search the scan table for the same bssid
3788 			 */
3789 			for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
3790 				if (!memcmp
3791 				    (pmadapter, bss_new_entry->mac_address,
3792 				     pmadapter->pscan_table[bss_idx].
3793 				     mac_address,
3794 				     sizeof(bss_new_entry->mac_address))) {
3795 					/*
3796 					 * If the SSID matches as well, it is a
3797 					 * duplicate of this entry.  Keep the
3798 					 * bss_idx set to this entry so we
3799 					 * replace the old contents in the table
3800 					 */
3801 					if ((bss_new_entry->ssid.ssid_len ==
3802 					     pmadapter->pscan_table[bss_idx].
3803 					     ssid.ssid_len)
3804 					    &&
3805 					    (!memcmp
3806 					     (pmadapter,
3807 					      bss_new_entry->ssid.ssid,
3808 					      pmadapter->pscan_table[bss_idx].
3809 					      ssid.ssid,
3810 					      bss_new_entry->ssid.ssid_len))) {
3811 						PRINTM(MINFO,
3812 						       "SCAN_RESP: Duplicate of index: %d\n",
3813 						       bss_idx);
3814 
3815 						break;
3816 					}
3817 					/*
3818 					 * If the SSID is NULL for same BSSID
3819 					 * keep the bss_idx set to this entry
3820 					 * so we replace the old contents in
3821 					 * the table
3822 					 */
3823 					if (!memcmp
3824 					    (pmadapter,
3825 					     pmadapter->pscan_table[bss_idx].
3826 					     ssid.ssid, null_ssid,
3827 					     pmadapter->pscan_table[bss_idx].
3828 					     ssid.ssid_len)) {
3829 						PRINTM(MINFO,
3830 						       "SCAN_RESP: Duplicate of index: %d\n",
3831 						       bss_idx);
3832 						break;
3833 					}
3834 				}
3835 			}
3836 			/*
3837 			 * If the bss_idx is equal to the number of entries
3838 			 * in the table, the new entry was not a duplicate;
3839 			 * append it to the scan table
3840 			 */
3841 			if (bss_idx == num_in_table) {
3842 				/*
3843 				 * Range check the bss_idx, keep it limited
3844 				 * to the last entry
3845 				 */
3846 				if (bss_idx == MRVDRV_MAX_BSSID_LIST)
3847 					bss_idx--;
3848 				else
3849 					num_in_table++;
3850 			}
3851 
3852 			/*
3853 			 * Save the beacon/probe response returned for later
3854 			 * application retrieval. Duplicate beacon/probe
3855 			 * responses are updated if possible
3856 			 */
3857 			wlan_ret_802_11_scan_store_beacon(pmpriv,
3858 							  bss_idx,
3859 							  num_in_table,
3860 							  bss_new_entry);
3861 			if (bss_new_entry->pbeacon_buf == MNULL) {
3862 				PRINTM(MCMND,
3863 				       "No space for beacon, drop this entry\n");
3864 				num_in_table--;
3865 				continue;
3866 			}
3867 			/*
3868 			 * If the TSF TLV was appended to the scan results, save
3869 			 * this entry's TSF value in the networkTSF field.  The
3870 			 * networkTSF is the firmware's TSF value at the time
3871 			 * the beacon or probe response was received.
3872 			 */
3873 			if (ptsf_tlv) {
3874 				memcpy(pmpriv->adapter, &tsf_val,
3875 				       &ptsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
3876 				       sizeof(tsf_val));
3877 				tsf_val = wlan_le64_to_cpu(tsf_val);
3878 				memcpy(pmpriv->adapter,
3879 				       &bss_new_entry->network_tsf, &tsf_val,
3880 				       sizeof(bss_new_entry->network_tsf));
3881 			}
3882 
3883 			/* Copy the locally created bss_new_entry to the scan table */
3884 			memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
3885 			       bss_new_entry,
3886 			       sizeof(pmadapter->pscan_table[bss_idx]));
3887 
3888 		} else {
3889 			/* Error parsing/interpreting the scan response, skipped */
3890 			PRINTM(MERROR,
3891 			       "SCAN_RESP: wlan_interpret_bss_desc_with_ie returned error\n");
3892 		}
3893 	}
3894 
3895 	PRINTM(MINFO, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
3896 	       pscan_rsp->number_of_sets,
3897 	       num_in_table - pmadapter->num_in_scan_table, num_in_table);
3898 
3899 	/* Update the total number of BSSIDs in the scan table */
3900 	pmadapter->num_in_scan_table = num_in_table;
3901 	/* Update the age_in_second */
3902 	pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
3903 						  &pmadapter->age_in_secs,
3904 						  &age_ts_usec);
3905 	if (is_bgscan_resp)
3906 		goto done;
3907 	wlan_request_cmd_lock(pmadapter);
3908 	if (!util_peek_list
3909 	    (pmadapter->pmoal_handle, &pmadapter->scan_pending_q, MNULL,
3910 	     MNULL)) {
3911 		wlan_release_cmd_lock(pmadapter);
3912 		if (pmadapter->pscan_ioctl_req) {
3913 			if (((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)->
3914 			    sub_command == MLAN_OID_SCAN_SPECIFIC_SSID ||
3915 			    ((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)->
3916 			    sub_command == MLAN_OID_SCAN_USER_CONFIG) {
3917 				if (wlan_active_scan_req_for_passive_chan
3918 				    (pmpriv, pmadapter->pscan_ioctl_req)) {
3919 					goto done;
3920 				}
3921 			}
3922 		}
3923 		/*
3924 		 * Process the resulting scan table:
3925 		 *   - Remove any bad ssids
3926 		 *   - Update our current BSS information from scan data
3927 		 */
3928 		wlan_scan_process_results(pmpriv);
3929 
3930 		wlan_request_cmd_lock(pmadapter);
3931 		pmadapter->scan_processing = MFALSE;
3932 		pscan_ioctl_req = pmadapter->pscan_ioctl_req;
3933 		pmadapter->pscan_ioctl_req = MNULL;
3934 		/* Need to indicate IOCTL complete */
3935 		if (pscan_ioctl_req) {
3936 			pscan_ioctl_req->status_code = MLAN_ERROR_NO_ERROR;
3937 			/* Indicate ioctl complete */
3938 			pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
3939 						 (pmlan_ioctl_req)
3940 						 pscan_ioctl_req,
3941 						 MLAN_STATUS_SUCCESS);
3942 		}
3943 		wlan_release_cmd_lock(pmadapter);
3944 		pmadapter->bgscan_reported = MFALSE;
3945 		wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
3946 	} else {
3947 		/* If firmware not ready, do not issue any more scan commands */
3948 		if (pmadapter->hw_status != WlanHardwareStatusReady) {
3949 			wlan_release_cmd_lock(pmadapter);
3950 			status_code = MLAN_ERROR_FW_NOT_READY;
3951 			ret = MLAN_STATUS_FAILURE;
3952 			goto done;
3953 		} else {
3954 			/* Get scan command from scan_pending_q and put to cmd_pending_q */
3955 			pcmd_node =
3956 				(cmd_ctrl_node *)util_dequeue_list(pmadapter->
3957 								   pmoal_handle,
3958 								   &pmadapter->
3959 								   scan_pending_q,
3960 								   MNULL,
3961 								   MNULL);
3962 			wlan_insert_cmd_to_pending_q(pmadapter, pcmd_node,
3963 						     MTRUE);
3964 			wlan_release_cmd_lock(pmadapter);
3965 		}
3966 	}
3967 
3968 done:
3969 	if (bss_new_entry)
3970 		pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
3971 	if (ret) {
3972 		/* Flush all pending scan commands */
3973 		wlan_flush_scan_queue(pmadapter);
3974 		wlan_request_cmd_lock(pmadapter);
3975 		pmadapter->scan_processing = MFALSE;
3976 		pscan_ioctl_req = pmadapter->pscan_ioctl_req;
3977 		pmadapter->pscan_ioctl_req = MNULL;
3978 		if (pscan_ioctl_req) {
3979 			pscan_ioctl_req->status_code = status_code;
3980 			/* Indicate ioctl complete */
3981 			pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
3982 						 pscan_ioctl_req,
3983 						 MLAN_STATUS_FAILURE);
3984 		}
3985 		wlan_release_cmd_lock(pmadapter);
3986 	}
3987 	LEAVE();
3988 	return ret;
3989 }
3990 
3991 /**
3992  *  @brief Prepare an extended scan command to be sent to the firmware
3993  *
3994  *  Use the wlan_scan_cmd_config sent to the command processing module in
3995  *   the wlan_prepare_cmd to configure a HostCmd_DS_802_11_SCAN_EXT command
3996  *   struct to send to firmware.
3997  *
3998  *  @param pmpriv     A pointer to mlan_private structure
3999  *  @param pcmd       A pointer to HostCmd_DS_COMMAND structure to be sent to
4000  *                    firmware with the HostCmd_DS_802_11_SCAN_EXT structure
4001  *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
4002  *                    to set the fields/TLVs for the command sent to firmware
4003  *
4004  *  @return           MLAN_STATUS_SUCCESS
4005  */
4006 mlan_status
wlan_cmd_802_11_scan_ext(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * pcmd,IN t_void * pdata_buf)4007 wlan_cmd_802_11_scan_ext(IN mlan_private *pmpriv,
4008 			 IN HostCmd_DS_COMMAND *pcmd, IN t_void *pdata_buf)
4009 {
4010 	HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &pcmd->params.ext_scan;
4011 	wlan_scan_cmd_config *pscan_cfg = MNULL;
4012 
4013 	ENTER();
4014 
4015 	pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
4016 
4017 	if (pmpriv->adapter->ext_scan_enh == MTRUE) {
4018 		if (pdata_buf) {
4019 			if (pmpriv->adapter->ext_scan_type == EXT_SCAN_ENHANCE)
4020 				pext_scan_cmd->ext_scan_type = EXT_SCAN_ENHANCE;
4021 			else
4022 				pext_scan_cmd->ext_scan_type = EXT_SCAN_DEFAULT;
4023 		} else {
4024 			pcmd->size =
4025 				wlan_cpu_to_le16((t_u16)
4026 						 (sizeof
4027 						  (pext_scan_cmd->ext_scan_type)
4028 						  +
4029 						  (t_u16)(sizeof
4030 							  (pext_scan_cmd->
4031 							   reserved)) +
4032 						  S_DS_GEN));
4033 			pext_scan_cmd->ext_scan_type = EXT_SCAN_CANCEL;
4034 			LEAVE();
4035 			return MLAN_STATUS_SUCCESS;
4036 		}
4037 	}
4038 	pscan_cfg = (wlan_scan_cmd_config *)pdata_buf;
4039 
4040 	memcpy(pmpriv->adapter, pext_scan_cmd->tlv_buffer,
4041 	       pscan_cfg->tlv_buf, pscan_cfg->tlv_buf_len);
4042 
4043 	/* Size is equal to the sizeof(fixed portions) + the TLV len + header */
4044 	pcmd->size =
4045 		wlan_cpu_to_le16((t_u16)(sizeof(pext_scan_cmd->ext_scan_type)
4046 					 +
4047 					 (t_u16)sizeof(pext_scan_cmd->reserved)
4048 					 + pscan_cfg->tlv_buf_len + S_DS_GEN));
4049 
4050 	LEAVE();
4051 	return MLAN_STATUS_SUCCESS;
4052 }
4053 
4054 /**
4055  *  @brief This function handles the command response of extended scan
4056  *
4057  *  @param pmpriv       A pointer to mlan_private structure
4058  *  @param resp         A pointer to HostCmd_DS_COMMAND
4059  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
4060  *
4061  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4062  */
4063 mlan_status
wlan_ret_802_11_scan_ext(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * resp,IN t_void * pioctl_buf)4064 wlan_ret_802_11_scan_ext(IN mlan_private *pmpriv,
4065 			 IN HostCmd_DS_COMMAND *resp, IN t_void *pioctl_buf)
4066 {
4067 	HostCmd_DS_802_11_SCAN_EXT *pext_scan_cmd = &(resp->params.ext_scan);
4068 	MrvlIEtypesHeader_t *tlv = MNULL;
4069 	MrvlIEtypes_ChannelStats_t *tlv_chanstats = MNULL;
4070 	t_u16 tlv_buf_left = 0;
4071 	t_u16 tlv_type = 0;
4072 	t_u16 tlv_len = 0;
4073 	t_u32 ext_scan_type;
4074 	mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
4075 	pmlan_ioctl_req pioctl_req = (pmlan_ioctl_req)pioctl_buf;
4076 	mlan_adapter *pmadapter = pmpriv->adapter;
4077 	ENTER();
4078 
4079 	PRINTM(MINFO, "EXT scan returns successfully\n");
4080 	ext_scan_type = pext_scan_cmd->ext_scan_type;
4081 	if (ext_scan_type == EXT_SCAN_CANCEL) {
4082 		PRINTM(MCMND, "Cancle scan command completed!\n");
4083 		/* Need to indicate IOCTL complete */
4084 		if (pioctl_req != MNULL) {
4085 			pioctl_req->status_code = MLAN_STATUS_SUCCESS;
4086 			/* Indicate ioctl complete */
4087 			pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
4088 						 (pmlan_ioctl_req)pioctl_req,
4089 						 MLAN_STATUS_SUCCESS);
4090 		}
4091 		LEAVE();
4092 		return MLAN_STATUS_SUCCESS;
4093 	} else if (ext_scan_type == EXT_SCAN_ENHANCE) {
4094 		/* Setup the timer after scan command response */
4095 		pcb->moal_start_timer(pmpriv->adapter->pmoal_handle,
4096 				      pmpriv->adapter->pmlan_cmd_timer, MFALSE,
4097 				      MRVDRV_TIMER_10S * 2);
4098 		pmpriv->adapter->cmd_timer_is_set = MTRUE;
4099 		LEAVE();
4100 		return MLAN_STATUS_SUCCESS;
4101 	}
4102 	tlv = (MrvlIEtypesHeader_t *)pext_scan_cmd->tlv_buffer;
4103 	tlv_buf_left =
4104 		resp->size - (sizeof(HostCmd_DS_802_11_SCAN_EXT) - 1 +
4105 			      S_DS_GEN);
4106 	while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
4107 		tlv_type = wlan_le16_to_cpu(tlv->type);
4108 		tlv_len = wlan_le16_to_cpu(tlv->len);
4109 		if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
4110 			PRINTM(MERROR, "Error processing scan gap TLV\n");
4111 			break;
4112 		}
4113 		switch (tlv_type) {
4114 		case TLV_TYPE_CHANNEL_STATS:
4115 			tlv_chanstats = (MrvlIEtypes_ChannelStats_t *)tlv;
4116 			wlan_update_chan_statistics(pmpriv, tlv_chanstats);
4117 			break;
4118 		default:
4119 			break;
4120 		}
4121 		tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
4122 		tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
4123 					      sizeof(MrvlIEtypesHeader_t));
4124 	}
4125 	LEAVE();
4126 	return MLAN_STATUS_SUCCESS;
4127 }
4128 
4129 /**
4130  *  @brief This function parse and store the extended scan results
4131  *
4132  *  @param pmpriv           A pointer to mlan_private structure
4133  *  @param number_of_sets   Number of BSS
4134  *  @param pscan_resp       A pointer to scan response buffer
4135  *  @param scan_resp_size   Size of scan response buffer
4136  *
4137  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4138  */
4139 static mlan_status
wlan_parse_ext_scan_result(IN mlan_private * pmpriv,IN t_u8 number_of_sets,IN t_u8 * pscan_resp,IN t_u16 scan_resp_size)4140 wlan_parse_ext_scan_result(IN mlan_private *pmpriv,
4141 			   IN t_u8 number_of_sets,
4142 			   IN t_u8 *pscan_resp, IN t_u16 scan_resp_size)
4143 {
4144 	mlan_status ret = MLAN_STATUS_SUCCESS;
4145 	mlan_adapter *pmadapter = pmpriv->adapter;
4146 	mlan_callbacks *pcb = MNULL;
4147 	BSSDescriptor_t *bss_new_entry = MNULL;
4148 	t_u8 *pbss_info;
4149 	t_u32 bytes_left;
4150 	t_u32 bytes_left_for_tlv;
4151 	t_u32 num_in_table;
4152 	t_u32 bss_idx;
4153 	t_u32 idx;
4154 	t_u64 tsf_val;
4155 	chan_freq_power_t *cfp;
4156 	t_u16 tlv_type, tlv_len;
4157 	MrvlIEtypes_Data_t *ptlv = MNULL;
4158 	MrvlIEtypes_Bss_Scan_Rsp_t *pscan_rsp_tlv = MNULL;
4159 	MrvlIEtypes_Bss_Scan_Info_t *pscan_info_tlv = MNULL;
4160 	t_u8 band;
4161 	t_u32 age_ts_usec;
4162 	t_u8 null_ssid[MLAN_MAX_SSID_LENGTH] = { 0 };
4163 
4164 	ENTER();
4165 	pcb = (pmlan_callbacks)&pmadapter->callbacks;
4166 
4167 	if (number_of_sets > MRVDRV_MAX_BSSID_LIST) {
4168 		PRINTM(MERROR,
4169 		       "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
4170 		       number_of_sets);
4171 		ret = MLAN_STATUS_FAILURE;
4172 		goto done;
4173 	}
4174 
4175 	bytes_left = scan_resp_size;
4176 	PRINTM(MINFO, "EXT_SCAN: bss_descript_size %d\n", scan_resp_size);
4177 	PRINTM(MINFO, "EXT_SCAN: returned %d APs before parsing\n",
4178 	       number_of_sets);
4179 
4180 	num_in_table = pmadapter->num_in_scan_table;
4181 	ptlv = (MrvlIEtypes_Data_t *)pscan_resp;
4182 
4183 	/*
4184 	 *  Process each scan response returned number_of_sets. Save
4185 	 *    the information in the bss_new_entry and then insert into the
4186 	 *    driver scan table either as an update to an existing entry
4187 	 *    or as an addition at the end of the table
4188 	 */
4189 	ret = pcb->moal_malloc(pmadapter->pmoal_handle, sizeof(BSSDescriptor_t),
4190 			       MLAN_MEM_DEF, (t_u8 **)&bss_new_entry);
4191 
4192 	if (ret != MLAN_STATUS_SUCCESS || !bss_new_entry) {
4193 		PRINTM(MERROR, "Memory allocation for bss_new_entry failed!\n");
4194 		ret = MLAN_STATUS_FAILURE;
4195 		goto done;
4196 	}
4197 
4198 	for (idx = 0; idx < number_of_sets && bytes_left >
4199 	     sizeof(MrvlIEtypesHeader_t); idx++) {
4200 		tlv_type = wlan_le16_to_cpu(ptlv->header.type);
4201 		tlv_len = wlan_le16_to_cpu(ptlv->header.len);
4202 		if (bytes_left < sizeof(MrvlIEtypesHeader_t) + tlv_len) {
4203 			PRINTM(MERROR,
4204 			       "EXT_SCAN: Error bytes left < TLV length\n");
4205 			break;
4206 		}
4207 		pscan_rsp_tlv = MNULL;
4208 		pscan_info_tlv = MNULL;
4209 		bytes_left_for_tlv = bytes_left;
4210 		/*
4211 		 * BSS response TLV with beacon or probe response buffer
4212 		 * at the initial position of each descriptor
4213 		 */
4214 		if (tlv_type == TLV_TYPE_BSS_SCAN_RSP) {
4215 			pbss_info = (t_u8 *)ptlv;
4216 			pscan_rsp_tlv = (MrvlIEtypes_Bss_Scan_Rsp_t *)ptlv;
4217 			ptlv = (MrvlIEtypes_Data_t *)(ptlv->data + tlv_len);
4218 			bytes_left_for_tlv -=
4219 				(tlv_len + sizeof(MrvlIEtypesHeader_t));
4220 		} else
4221 			break;
4222 
4223 		/* Process variable TLV */
4224 		while (bytes_left_for_tlv >= sizeof(MrvlIEtypesHeader_t) &&
4225 		       wlan_le16_to_cpu(ptlv->header.type) !=
4226 		       TLV_TYPE_BSS_SCAN_RSP) {
4227 			tlv_type = wlan_le16_to_cpu(ptlv->header.type);
4228 			tlv_len = wlan_le16_to_cpu(ptlv->header.len);
4229 			if (bytes_left_for_tlv <
4230 			    sizeof(MrvlIEtypesHeader_t) + tlv_len) {
4231 				PRINTM(MERROR,
4232 				       "EXT_SCAN: Error in processing TLV, "
4233 				       "bytes left < TLV length\n");
4234 				pscan_rsp_tlv = MNULL;
4235 				bytes_left_for_tlv = 0;
4236 				continue;
4237 			}
4238 			switch (tlv_type) {
4239 			case TLV_TYPE_BSS_SCAN_INFO:
4240 				pscan_info_tlv =
4241 					(MrvlIEtypes_Bss_Scan_Info_t *)ptlv;
4242 				if (tlv_len !=
4243 				    sizeof(MrvlIEtypes_Bss_Scan_Info_t) -
4244 				    sizeof(MrvlIEtypesHeader_t)) {
4245 					bytes_left_for_tlv = 0;
4246 					continue;
4247 				}
4248 				break;
4249 			default:
4250 				break;
4251 			}
4252 			ptlv = (MrvlIEtypes_Data_t *)(ptlv->data + tlv_len);
4253 			bytes_left -= (tlv_len + sizeof(MrvlIEtypesHeader_t));
4254 			bytes_left_for_tlv -=
4255 				(tlv_len + sizeof(MrvlIEtypesHeader_t));
4256 		}
4257 		/* No BSS response TLV */
4258 		if (pscan_rsp_tlv == MNULL)
4259 			break;
4260 
4261 		/*
4262 		 * Advance pointer to the beacon buffer length and
4263 		 * update the bytes count so that the function
4264 		 * wlan_interpret_bss_desc_with_ie() can handle the
4265 		 * scan buffer withut any change
4266 		 */
4267 		pbss_info += sizeof(t_u16);
4268 		bytes_left -= sizeof(t_u16);
4269 
4270 		/* Zero out the bss_new_entry we are about to store info in */
4271 		memset(pmadapter, bss_new_entry, 0x00, sizeof(BSSDescriptor_t));
4272 
4273 		/* Process the data fields and IEs returned for this BSS */
4274 		if (wlan_interpret_bss_desc_with_ie(pmadapter,
4275 						    bss_new_entry,
4276 						    &pbss_info,
4277 						    &bytes_left,
4278 						    MTRUE) ==
4279 		    MLAN_STATUS_SUCCESS) {
4280 			PRINTM(MINFO, "EXT_SCAN: BSSID = " MACSTR "\n",
4281 			       MAC2STR(bss_new_entry->mac_address));
4282 
4283 			band = BAND_G;
4284 			/*
4285 			 * If the BSS info TLV was appended to the scan results,
4286 			 * save this entry's TSF value in the networkTSF field.
4287 			 * The networkTSF is the firmware's TSF value at the
4288 			 * time the beacon or probe response was received.
4289 			 */
4290 			if (pscan_info_tlv) {
4291 				/* RSSI is 2 byte long */
4292 				bss_new_entry->rssi =
4293 					-(t_s32)(wlan_le16_to_cpu
4294 						 (pscan_info_tlv->rssi));
4295 				PRINTM(MINFO, "EXT_SCAN: RSSI=%d\n",
4296 				       bss_new_entry->rssi);
4297 				memcpy(pmpriv->adapter, &tsf_val,
4298 				       &pscan_info_tlv->tsf, sizeof(tsf_val));
4299 				tsf_val = wlan_le64_to_cpu(tsf_val);
4300 				memcpy(pmpriv->adapter,
4301 				       &bss_new_entry->network_tsf, &tsf_val,
4302 				       sizeof(bss_new_entry->network_tsf));
4303 				band = radio_type_to_band(pscan_info_tlv->
4304 							  bandcfg.chanBand);
4305 			}
4306 			/* Save the band designation for this entry for use in join */
4307 			bss_new_entry->bss_band = band;
4308 
4309 			cfp = wlan_find_cfp_by_band_and_channel(pmadapter,
4310 								(t_u8)
4311 								bss_new_entry->
4312 								bss_band,
4313 								(t_u16)
4314 								bss_new_entry->
4315 								channel);
4316 			if (cfp)
4317 				bss_new_entry->freq = cfp->freq;
4318 			else
4319 				bss_new_entry->freq = 0;
4320 
4321 			/* Skip entry if on blacklisted channel */
4322 			if (cfp && cfp->dynamic.blacklist) {
4323 				PRINTM(MINFO,
4324 				       "EXT_SCAN: dropping entry on blacklist channel.\n");
4325 				continue;
4326 			}
4327 
4328 			/*
4329 			 * Search the scan table for the same bssid
4330 			 */
4331 			for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
4332 				if (!memcmp
4333 				    (pmadapter, bss_new_entry->mac_address,
4334 				     pmadapter->pscan_table[bss_idx].
4335 				     mac_address,
4336 				     sizeof(bss_new_entry->mac_address))) {
4337 					/*
4338 					 * If the SSID matches as well, it is a
4339 					 * duplicate of this entry.  Keep the
4340 					 * bss_idx set to this entry so we
4341 					 * replace the old contents in the table
4342 					 */
4343 					if ((bss_new_entry->ssid.ssid_len ==
4344 					     pmadapter->pscan_table[bss_idx].
4345 					     ssid.ssid_len)
4346 					    &&
4347 					    (!memcmp
4348 					     (pmadapter,
4349 					      bss_new_entry->ssid.ssid,
4350 					      pmadapter->pscan_table[bss_idx].
4351 					      ssid.ssid,
4352 					      bss_new_entry->ssid.ssid_len))) {
4353 						PRINTM(MINFO,
4354 						       "EXT_SCAN: Duplicate of index: %d\n",
4355 						       bss_idx);
4356 						break;
4357 					}
4358 					/*
4359 					 * If the SSID is NULL for same BSSID
4360 					 * keep the bss_idx set to this entry
4361 					 * so we replace the old contents in
4362 					 * the table
4363 					 */
4364 					if (!memcmp
4365 					    (pmadapter,
4366 					     pmadapter->pscan_table[bss_idx].
4367 					     ssid.ssid, null_ssid,
4368 					     pmadapter->pscan_table[bss_idx].
4369 					     ssid.ssid_len)) {
4370 						PRINTM(MINFO,
4371 						       "EXT_SCAN: Duplicate of index: %d\n",
4372 						       bss_idx);
4373 						break;
4374 					}
4375 				}
4376 			}
4377 			/*
4378 			 * If the bss_idx is equal to the number of entries
4379 			 * in the table, the new entry was not a duplicate;
4380 			 * append it to the scan table
4381 			 */
4382 			if (bss_idx == num_in_table) {
4383 				/* Range check the bss_idx, keep it limited to the last entry */
4384 				if (bss_idx == MRVDRV_MAX_BSSID_LIST)
4385 					bss_idx--;
4386 				else
4387 					num_in_table++;
4388 			}
4389 
4390 			/*
4391 			 * Save the beacon/probe response returned for later
4392 			 * application retrieval. Duplicate beacon/probe
4393 			 * responses are updated if possible
4394 			 */
4395 			wlan_ret_802_11_scan_store_beacon(pmpriv,
4396 							  bss_idx,
4397 							  num_in_table,
4398 							  bss_new_entry);
4399 			if (bss_new_entry->pbeacon_buf == MNULL) {
4400 				PRINTM(MCMND,
4401 				       "No space for beacon, drop this entry\n");
4402 				num_in_table--;
4403 				continue;
4404 			}
4405 
4406 			/* Copy the locally created bss_new_entry to the scan table */
4407 			memcpy(pmadapter, &pmadapter->pscan_table[bss_idx],
4408 			       bss_new_entry,
4409 			       sizeof(pmadapter->pscan_table[bss_idx]));
4410 		} else {
4411 			/* Error parsing/interpreting the scan response, skipped */
4412 			PRINTM(MERROR,
4413 			       "EXT_SCAN: wlan_interpret_bss_desc_with_ie returned error\n");
4414 		}
4415 	}
4416 
4417 	PRINTM(MINFO, "EXT_SCAN: Scanned %2d APs, %d valid, %d total\n",
4418 	       number_of_sets, num_in_table - pmadapter->num_in_scan_table,
4419 	       num_in_table);
4420 
4421 	/* Update the total number of BSSIDs in the scan table */
4422 	pmadapter->num_in_scan_table = num_in_table;
4423 	/* Update the age_in_second */
4424 	pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
4425 						  &pmadapter->age_in_secs,
4426 						  &age_ts_usec);
4427 
4428 done:
4429 	if (bss_new_entry)
4430 		pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)bss_new_entry);
4431 
4432 	LEAVE();
4433 	return ret;
4434 }
4435 
4436 /**
4437  *  @brief This function handles the event extended scan report
4438  *
4439  *  @param pmpriv       A pointer to mlan_private structure
4440  *  @param pmbuf        A pointer to mlan_buffer
4441  *
4442  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4443  */
4444 mlan_status
wlan_handle_event_ext_scan_report(IN mlan_private * pmpriv,IN mlan_buffer * pmbuf)4445 wlan_handle_event_ext_scan_report(IN mlan_private *pmpriv,
4446 				  IN mlan_buffer *pmbuf)
4447 {
4448 	mlan_adapter *pmadapter = pmpriv->adapter;
4449 	mlan_callbacks *pcb = &pmadapter->callbacks;
4450 	mlan_ioctl_req *pioctl_req = MNULL;
4451 	cmd_ctrl_node *pcmd_node = MNULL;
4452 	mlan_status ret = MLAN_STATUS_SUCCESS;
4453 
4454 	mlan_event_scan_result *pevent_scan = (pmlan_event_scan_result)
4455 		(pmbuf->pbuf + pmbuf->data_offset);
4456 	t_u8 *ptlv = (pmbuf->pbuf + pmbuf->data_offset
4457 		      + sizeof(mlan_event_scan_result));
4458 	t_u16 tlv_buf_left = wlan_le16_to_cpu(pevent_scan->buf_size);
4459 
4460 	DBG_HEXDUMP(MCMD_D, "EVENT EXT_SCAN", pmbuf->pbuf +
4461 		    pmbuf->data_offset, pmbuf->data_len);
4462 	wlan_parse_ext_scan_result(pmpriv, pevent_scan->num_of_set,
4463 				   ptlv, tlv_buf_left);
4464 	if (!pevent_scan->more_event
4465 	    && (pmadapter->ext_scan_type != EXT_SCAN_ENHANCE)
4466 		) {
4467 		wlan_request_cmd_lock(pmadapter);
4468 		if (!util_peek_list(pmadapter->pmoal_handle,
4469 				    &pmadapter->scan_pending_q, MNULL, MNULL)) {
4470 			wlan_release_cmd_lock(pmadapter);
4471 			if (pmadapter->pscan_ioctl_req) {
4472 				if (((mlan_ds_scan *)pmadapter->
4473 				     pscan_ioctl_req->pbuf)->sub_command ==
4474 				    MLAN_OID_SCAN_SPECIFIC_SSID ||
4475 				    ((mlan_ds_scan *)pmadapter->
4476 				     pscan_ioctl_req->pbuf)->sub_command ==
4477 				    MLAN_OID_SCAN_USER_CONFIG) {
4478 					if (wlan_active_scan_req_for_passive_chan(pmpriv, pmadapter->pscan_ioctl_req)) {
4479 						LEAVE();
4480 						return ret;
4481 					}
4482 				}
4483 			}
4484 			/*
4485 			 * Process the resulting scan table:
4486 			 *   - Remove any bad ssids
4487 			 *   - Update our current BSS information from scan data
4488 			 */
4489 			wlan_scan_process_results(pmpriv);
4490 			wlan_request_cmd_lock(pmadapter);
4491 			pmadapter->scan_processing = MFALSE;
4492 			pioctl_req = pmadapter->pscan_ioctl_req;
4493 			pmadapter->pscan_ioctl_req = MNULL;
4494 			/* Need to indicate IOCTL complete */
4495 			if (pioctl_req != MNULL) {
4496 				pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
4497 				/* Indicate ioctl complete */
4498 				pcb->moal_ioctl_complete(pmadapter->
4499 							 pmoal_handle,
4500 							 (pmlan_ioctl_req)
4501 							 pioctl_req,
4502 							 MLAN_STATUS_SUCCESS);
4503 			}
4504 			wlan_release_cmd_lock(pmadapter);
4505 
4506 			pmadapter->bgscan_reported = MFALSE;
4507 			wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT,
4508 					MNULL);
4509 		} else {
4510 
4511 			/* If firmware not ready, do not issue any more scan commands */
4512 			if (pmadapter->hw_status != WlanHardwareStatusReady) {
4513 				wlan_release_cmd_lock(pmadapter);
4514 				/* Flush all pending scan commands */
4515 				wlan_flush_scan_queue(pmadapter);
4516 				wlan_request_cmd_lock(pmadapter);
4517 				pmadapter->scan_processing = MFALSE;
4518 				pioctl_req = pmadapter->pscan_ioctl_req;
4519 				pmadapter->pscan_ioctl_req = MNULL;
4520 				/* Indicate IOCTL complete */
4521 				if (pioctl_req != MNULL) {
4522 					pioctl_req->status_code =
4523 						MLAN_ERROR_FW_NOT_READY;
4524 
4525 					/* Indicate ioctl complete */
4526 					pcb->moal_ioctl_complete(pmadapter->
4527 								 pmoal_handle,
4528 								 (pmlan_ioctl_req)
4529 								 pioctl_req,
4530 								 MLAN_STATUS_FAILURE);
4531 				}
4532 				wlan_release_cmd_lock(pmadapter);
4533 			} else {
4534 				/* Get scan command from scan_pending_q and put to cmd_pending_q */
4535 				pcmd_node =
4536 					(cmd_ctrl_node *)
4537 					util_dequeue_list(pmadapter->
4538 							  pmoal_handle,
4539 							  &pmadapter->
4540 							  scan_pending_q, MNULL,
4541 							  MNULL);
4542 				wlan_insert_cmd_to_pending_q(pmadapter,
4543 							     pcmd_node, MTRUE);
4544 				wlan_release_cmd_lock(pmadapter);
4545 			}
4546 		}
4547 	}
4548 	LEAVE();
4549 	return ret;
4550 }
4551 
4552 /**
4553  *  @brief This function handles the event extended scan status
4554  *
4555  *  @param pmpriv       A pointer to mlan_private structure
4556  *  @param pmbuf        A pointer to mlan_buffer
4557  *
4558  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
4559  */
4560 mlan_status
wlan_handle_event_ext_scan_status(IN mlan_private * pmpriv,IN mlan_buffer * pmbuf)4561 wlan_handle_event_ext_scan_status(IN mlan_private *pmpriv,
4562 				  IN mlan_buffer *pmbuf)
4563 {
4564 	mlan_adapter *pmadapter = pmpriv->adapter;
4565 	mlan_status ret = MLAN_STATUS_SUCCESS;
4566 	mlan_event_scan_status *scan_event;
4567 	mlan_ioctl_req *pioctl_req;
4568 	mlan_callbacks *pcb = (mlan_callbacks *)&pmadapter->callbacks;
4569 	t_u16 tlv_buf_left, tlv_len, tlv_type;
4570 	MrvlIEtypesHeader_t *tlv;
4571 	MrvlIEtypes_ChannelStats_t *tlv_chan_stats;
4572 	t_u8 status;
4573 
4574 	ENTER();
4575 
4576 	if (pmbuf->data_len < sizeof(mlan_event_scan_status)) {
4577 		PRINTM(MERROR, "Wrong ext scan status event data length\n");
4578 		ret = MLAN_STATUS_FAILURE;
4579 		goto done;
4580 	}
4581 
4582 	scan_event =
4583 		(pmlan_event_scan_status) (pmbuf->pbuf + pmbuf->data_offset);
4584 	DBG_HEXDUMP(MCMD_D, "EVENT: Ext_Scan_Status", scan_event,
4585 		    pmbuf->data_len);
4586 	status = scan_event->scan_status;
4587 	PRINTM(MEVENT, "ext_scan_status: status %d (scan %s), buf_len %d\n",
4588 	       status, status ? "cancelled" : "success", scan_event->buf_len);
4589 
4590 	tlv = (MrvlIEtypesHeader_t *)scan_event->event_buf;
4591 	tlv_buf_left = pmbuf->data_len - sizeof(mlan_event_scan_status);
4592 	while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
4593 		tlv_type = wlan_le16_to_cpu(tlv->type);
4594 		tlv_len = wlan_le16_to_cpu(tlv->len);
4595 		if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
4596 			PRINTM(MERROR,
4597 			       "Error process scan gap tlv: length %d type 0x%x\n",
4598 			       tlv_len, tlv_type);
4599 			ret = MLAN_STATUS_FAILURE;
4600 			goto done;
4601 		}
4602 		switch (tlv_type) {
4603 		case TLV_TYPE_CHANNEL_STATS:
4604 			tlv_chan_stats = (MrvlIEtypes_ChannelStats_t *)tlv;
4605 			wlan_update_chan_statistics(pmpriv, tlv_chan_stats);
4606 			break;
4607 		default:
4608 			break;
4609 		}
4610 		tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
4611 		tlv = (MrvlIEtypesHeader_t *)((t_u8 *)(tlv + tlv_len +
4612 						       sizeof
4613 						       (MrvlIEtypesHeader_t)));
4614 	}
4615 
4616 done:
4617 	/* Now we got response from FW, cancel the command timer */
4618 	if (!pmadapter->curr_cmd && pmadapter->cmd_timer_is_set) {
4619 		/* Cancel command timeout timer */
4620 		pcb->moal_stop_timer(pmadapter->pmoal_handle,
4621 				     pmadapter->pmlan_cmd_timer);
4622 		/* Cancel command timeout timer */
4623 		pmadapter->cmd_timer_is_set = MFALSE;
4624 	}
4625 	if (pmadapter->pscan_ioctl_req) {
4626 		if (((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)->
4627 		    sub_command == MLAN_OID_SCAN_SPECIFIC_SSID ||
4628 		    ((mlan_ds_scan *)pmadapter->pscan_ioctl_req->pbuf)->
4629 		    sub_command == MLAN_OID_SCAN_USER_CONFIG) {
4630 			if (wlan_active_scan_req_for_passive_chan
4631 			    (pmpriv, pmadapter->pscan_ioctl_req)) {
4632 				LEAVE();
4633 				return ret;
4634 			}
4635 		}
4636 	}
4637 	/*
4638 	 * Process the resulting scan table:
4639 	 *   - Remove any bad ssids
4640 	 *   - Update our current BSS information from scan data
4641 	 */
4642 	wlan_scan_process_results(pmpriv);
4643     /** Complete scan ioctl */
4644 	wlan_request_cmd_lock(pmadapter);
4645 	pmadapter->scan_processing = MFALSE;
4646 	pmadapter->ext_scan_type = EXT_SCAN_DEFAULT;
4647 	pioctl_req = pmadapter->pscan_ioctl_req;
4648 	pmadapter->pscan_ioctl_req = MNULL;
4649 	/* Need to indicate IOCTL complete */
4650 	if (pioctl_req != MNULL) {
4651 		pioctl_req->status_code = MLAN_ERROR_NO_ERROR;
4652 		/* Indicate ioctl complete */
4653 		pcb->moal_ioctl_complete(pmadapter->pmoal_handle,
4654 					 pioctl_req, MLAN_STATUS_SUCCESS);
4655 	}
4656 	wlan_release_cmd_lock(pmadapter);
4657 	pmadapter->bgscan_reported = MFALSE;
4658 	wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_SCAN_REPORT, MNULL);
4659 	LEAVE();
4660 	return ret;
4661 }
4662 
4663 /**
4664  *  @brief This function prepares command of bg_scan_query.
4665  *
4666  *  @param pmpriv     A pointer to mlan_private structure
4667  *  @param pcmd       A pointer to HostCmd_DS_COMMAND structure
4668  *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
4669  *                    to set the fields/TLVs for the command sent to firmware
4670  *
4671  *  @return           MLAN_STATUS_SUCCESS
4672  */
4673 mlan_status
wlan_cmd_802_11_bg_scan_query(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * pcmd,IN t_void * pdata_buf)4674 wlan_cmd_802_11_bg_scan_query(IN mlan_private *pmpriv,
4675 			      IN HostCmd_DS_COMMAND *pcmd, IN t_void *pdata_buf)
4676 {
4677 	HostCmd_DS_802_11_BG_SCAN_QUERY *bg_query = &pcmd->params.bg_scan_query;
4678 
4679 	ENTER();
4680 
4681 	pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
4682 	pcmd->size =
4683 		wlan_cpu_to_le16(sizeof(HostCmd_DS_802_11_BG_SCAN_QUERY) +
4684 				 S_DS_GEN);
4685 
4686 	bg_query->flush = MTRUE;
4687 
4688 	LEAVE();
4689 	return MLAN_STATUS_SUCCESS;
4690 }
4691 
4692 /**
4693  *  @brief Create a channel list for the driver to scan based on region info
4694  *
4695  *  Use the driver region/band information to construct a comprehensive list
4696  *    of channels to scan.  This routine is used for any scan that is not
4697  *    provided a specific channel list to scan.
4698  *
4699  *  @param pmpriv           A pointer to mlan_private structure
4700  *  @param pbg_scan_in      pointer to scan configuration parameters
4701  *  @param tlv_chan_list    A pointer to structure MrvlIEtypes_ChanListParamSet_t
4702  *
4703  *  @return                 channel number
4704  */
4705 static t_u8
wlan_bgscan_create_channel_list(IN mlan_private * pmpriv,IN const wlan_bgscan_cfg * pbg_scan_in,MrvlIEtypes_ChanListParamSet_t * tlv_chan_list)4706 wlan_bgscan_create_channel_list(IN mlan_private *pmpriv,
4707 				IN const wlan_bgscan_cfg *pbg_scan_in,
4708 				MrvlIEtypes_ChanListParamSet_t *tlv_chan_list)
4709 {
4710 	mlan_adapter *pmadapter = pmpriv->adapter;
4711 	region_chan_t *pscan_region;
4712 	chan_freq_power_t *cfp;
4713 	t_u32 region_idx;
4714 	t_u32 chan_idx = 0;
4715 	t_u32 next_chan;
4716 	t_u8 scan_type;
4717 	t_u8 radio_type;
4718 
4719 	ENTER();
4720 
4721 	for (region_idx = 0;
4722 	     region_idx < NELEMENTS(pmadapter->region_channel); region_idx++) {
4723 
4724 		if (wlan_11d_is_enabled(pmpriv) &&
4725 		    pmpriv->media_connected != MTRUE) {
4726 			/* Scan all the supported chan for the first scan */
4727 			if (!pmadapter->universal_channel[region_idx].valid)
4728 				continue;
4729 			pscan_region =
4730 				&pmadapter->universal_channel[region_idx];
4731 		} else {
4732 			if (!pmadapter->region_channel[region_idx].valid)
4733 				continue;
4734 			pscan_region = &pmadapter->region_channel[region_idx];
4735 		}
4736 
4737 		if (pbg_scan_in && !pbg_scan_in->chan_list[0].chan_number &&
4738 		    pbg_scan_in->chan_list[0].radio_type & BAND_SPECIFIED) {
4739 			radio_type =
4740 				pbg_scan_in->chan_list[0].
4741 				radio_type & ~BAND_SPECIFIED;
4742 			if (!radio_type && (pscan_region->band != BAND_B) &&
4743 			    (pscan_region->band != BAND_G))
4744 				continue;
4745 			if (radio_type && (pscan_region->band != BAND_A))
4746 				continue;
4747 		}
4748 		if (!wlan_is_band_compatible
4749 		    (pmpriv->config_bands | pmadapter->adhoc_start_band,
4750 		     pscan_region->band))
4751 			continue;
4752 		for (next_chan = 0;
4753 		     next_chan < pscan_region->num_cfp;
4754 		     next_chan++, chan_idx++) {
4755 			if (chan_idx >= WLAN_BG_SCAN_CHAN_MAX)
4756 				break;
4757 			/*
4758 			 * Set the default scan type to ACTIVE SCAN type, will
4759 			 * later be changed to passive on a per channel basis
4760 			 * if restricted by regulatory requirements (11d or 11h)
4761 			 */
4762 			scan_type = MLAN_SCAN_TYPE_ACTIVE;
4763 			cfp = pscan_region->pcfp + next_chan;
4764 
4765 			switch (pscan_region->band) {
4766 			case BAND_A:
4767 				tlv_chan_list->chan_scan_param[chan_idx].
4768 					bandcfg.chanBand = BAND_5GHZ;
4769 				/* Passive scan on DFS channels */
4770 				if (wlan_11h_radar_detect_required
4771 				    (pmpriv, (t_u8)cfp->channel))
4772 					scan_type = MLAN_SCAN_TYPE_PASSIVE;
4773 				break;
4774 			case BAND_B:
4775 			case BAND_G:
4776 				if (wlan_bg_scan_type_is_passive
4777 				    (pmpriv, (t_u8)cfp->channel))
4778 					scan_type = MLAN_SCAN_TYPE_PASSIVE;
4779 				tlv_chan_list->chan_scan_param[chan_idx].
4780 					bandcfg.chanBand = BAND_2GHZ;
4781 				break;
4782 			default:
4783 				tlv_chan_list->chan_scan_param[chan_idx].
4784 					bandcfg.chanBand = BAND_2GHZ;
4785 				break;
4786 			}
4787 
4788 			if (pbg_scan_in && pbg_scan_in->chan_list[0].scan_time) {
4789 				tlv_chan_list->chan_scan_param[chan_idx].
4790 					max_scan_time =
4791 					wlan_cpu_to_le16((t_u16)pbg_scan_in->
4792 							 chan_list[0].
4793 							 scan_time);
4794 				tlv_chan_list->chan_scan_param[chan_idx].
4795 					min_scan_time =
4796 					wlan_cpu_to_le16((t_u16)pbg_scan_in->
4797 							 chan_list[0].
4798 							 scan_time);
4799 			} else if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
4800 				tlv_chan_list->chan_scan_param[chan_idx].
4801 					max_scan_time =
4802 					wlan_cpu_to_le16(pmadapter->
4803 							 passive_scan_time);
4804 				tlv_chan_list->chan_scan_param[chan_idx].
4805 					min_scan_time =
4806 					wlan_cpu_to_le16(pmadapter->
4807 							 passive_scan_time);
4808 			} else {
4809 				tlv_chan_list->chan_scan_param[chan_idx].
4810 					max_scan_time =
4811 					wlan_cpu_to_le16(pmadapter->
4812 							 specific_scan_time);
4813 				tlv_chan_list->chan_scan_param[chan_idx].
4814 					min_scan_time =
4815 					wlan_cpu_to_le16(pmadapter->
4816 							 specific_scan_time);
4817 			}
4818 
4819 			if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
4820 				tlv_chan_list->chan_scan_param[chan_idx].
4821 					chan_scan_mode.passive_scan = MTRUE;
4822 			} else {
4823 				tlv_chan_list->chan_scan_param[chan_idx].
4824 					chan_scan_mode.passive_scan = MFALSE;
4825 			}
4826 
4827 			tlv_chan_list->chan_scan_param[chan_idx].chan_number =
4828 				(t_u8)cfp->channel;
4829 			tlv_chan_list->chan_scan_param[chan_idx].chan_scan_mode.
4830 				disable_chan_filt = MTRUE;
4831 		}
4832 	}
4833 
4834 	LEAVE();
4835 	return chan_idx;
4836 }
4837 
4838 /**
4839  *  @brief This function prepares command of bg_scan_config
4840  *
4841  *  @param pmpriv     A pointer to mlan_private structure
4842  *  @param pcmd       A pointer to HostCmd_DS_COMMAND structure
4843  *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
4844  *                    to set the fields/TLVs for the command sent to firmware
4845  *
4846  *  @return           MLAN_STATUS_SUCCESS
4847  */
4848 mlan_status
wlan_cmd_bgscan_config(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * pcmd,IN t_void * pdata_buf)4849 wlan_cmd_bgscan_config(IN mlan_private *pmpriv,
4850 		       IN HostCmd_DS_COMMAND *pcmd, IN t_void *pdata_buf)
4851 {
4852 	mlan_adapter *pmadapter = pmpriv->adapter;
4853 	HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan =
4854 		&pcmd->params.bg_scan_config;
4855 	wlan_bgscan_cfg *bg_scan_in = (wlan_bgscan_cfg *)pdata_buf;
4856 	t_u16 cmd_size = 0;
4857 	MrvlIEtypes_NumProbes_t *pnum_probes_tlv = MNULL;
4858 	MrvlIEtypes_BeaconLowRssiThreshold_t *rssi_tlv = MNULL;
4859 	MrvlIEtypes_BeaconLowSnrThreshold_t *snr_tlv = MNULL;
4860 	MrvlIEtypes_WildCardSsIdParamSet_t *pwildcard_ssid_tlv = MNULL;
4861 	MrvlIEtypes_ChanListParamSet_t *tlv_chan_list = MNULL;
4862 	MrvlIEtypes_StartLater_t *tlv_start_later = MNULL;
4863 	MrvlIEtypes_RepeatCount_t *tlv_repeat = MNULL;
4864 	t_u8 *tlv = MNULL;
4865 	t_u16 num_probes = 0;
4866 	t_u32 ssid_idx;
4867 	t_u32 ssid_len = 0;
4868 	t_u32 chan_idx;
4869 	t_u32 chan_num;
4870 	t_u8 radio_type;
4871 	t_u16 scan_dur;
4872 	t_u8 scan_type;
4873 
4874 	ENTER();
4875 
4876 	pcmd->command = wlan_cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
4877 	bg_scan->action = wlan_cpu_to_le16(bg_scan_in->action);
4878 	bg_scan->enable = bg_scan_in->enable;
4879 	bg_scan->bss_type = bg_scan_in->bss_type;
4880 	cmd_size = sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG) + S_DS_GEN;
4881 	if (bg_scan_in->scan_interval)
4882 		bg_scan->scan_interval =
4883 			wlan_cpu_to_le32(bg_scan_in->scan_interval);
4884 	else
4885 		bg_scan->scan_interval =
4886 			wlan_cpu_to_le32(DEFAULT_BGSCAN_INTERVAL);
4887 	bg_scan->report_condition =
4888 		wlan_cpu_to_le32(bg_scan_in->report_condition);
4889 
4890 	if ((bg_scan_in->action == BG_SCAN_ACT_GET) ||
4891 	    (bg_scan_in->action == BG_SCAN_ACT_GET_PPS_UAPSD) ||
4892 	    (!bg_scan->enable))
4893 		goto done;
4894 
4895 	tlv = (t_u8 *)bg_scan + sizeof(HostCmd_DS_802_11_BG_SCAN_CONFIG);
4896 	num_probes = (bg_scan_in->num_probes ? bg_scan_in->num_probes :
4897 		      pmadapter->scan_probes);
4898 	if (num_probes) {
4899 		pnum_probes_tlv = (MrvlIEtypes_NumProbes_t *)tlv;
4900 		pnum_probes_tlv->header.type =
4901 			wlan_cpu_to_le16(TLV_TYPE_NUMPROBES);
4902 		pnum_probes_tlv->header.len =
4903 			wlan_cpu_to_le16(sizeof(pnum_probes_tlv->num_probes));
4904 		pnum_probes_tlv->num_probes =
4905 			wlan_cpu_to_le16((t_u16)num_probes);
4906 		tlv += sizeof(MrvlIEtypes_NumProbes_t);
4907 		cmd_size += sizeof(MrvlIEtypes_NumProbes_t);
4908 	}
4909 	if (bg_scan_in->rssi_threshold) {
4910 		rssi_tlv = (MrvlIEtypes_BeaconLowRssiThreshold_t *)tlv;
4911 		rssi_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_RSSI_LOW);
4912 		rssi_tlv->header.len =
4913 			wlan_cpu_to_le16(sizeof
4914 					 (MrvlIEtypes_BeaconLowRssiThreshold_t)
4915 					 - sizeof(MrvlIEtypesHeader_t));
4916 		rssi_tlv->value = bg_scan_in->rssi_threshold;
4917 		rssi_tlv->frequency = 0;
4918 		tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
4919 		cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
4920 	}
4921 	if (bg_scan_in->snr_threshold) {
4922 		snr_tlv = (MrvlIEtypes_BeaconLowSnrThreshold_t *)tlv;
4923 		snr_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_SNR_LOW);
4924 		snr_tlv->header.len =
4925 			wlan_cpu_to_le16(sizeof
4926 					 (MrvlIEtypes_BeaconLowSnrThreshold_t) -
4927 					 sizeof(MrvlIEtypesHeader_t));
4928 		snr_tlv->value = bg_scan_in->snr_threshold;
4929 		snr_tlv->frequency = 0;
4930 		tlv += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
4931 		cmd_size += sizeof(MrvlIEtypes_BeaconLowRssiThreshold_t);
4932 	}
4933 	if (bg_scan_in->repeat_count) {
4934 		tlv_repeat = (MrvlIEtypes_RepeatCount_t *)tlv;
4935 		tlv_repeat->header.type =
4936 			wlan_cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
4937 		tlv_repeat->header.len =
4938 			wlan_cpu_to_le16(sizeof(MrvlIEtypes_RepeatCount_t) -
4939 					 sizeof(MrvlIEtypesHeader_t));
4940 		tlv_repeat->repeat_count =
4941 			wlan_cpu_to_le16(bg_scan_in->repeat_count);
4942 		tlv += sizeof(MrvlIEtypes_RepeatCount_t);
4943 		cmd_size += sizeof(MrvlIEtypes_RepeatCount_t);
4944 	}
4945 	for (ssid_idx = 0; ((ssid_idx < NELEMENTS(bg_scan_in->ssid_list))
4946 			    && (*bg_scan_in->ssid_list[ssid_idx].ssid ||
4947 				bg_scan_in->ssid_list[ssid_idx].max_len));
4948 	     ssid_idx++) {
4949 		ssid_len =
4950 			wlan_strlen((char *)bg_scan_in->ssid_list[ssid_idx].
4951 				    ssid);
4952 		pwildcard_ssid_tlv = (MrvlIEtypes_WildCardSsIdParamSet_t *)tlv;
4953 		pwildcard_ssid_tlv->header.type =
4954 			wlan_cpu_to_le16(TLV_TYPE_WILDCARDSSID);
4955 		pwildcard_ssid_tlv->header.len =
4956 			(t_u16)(ssid_len +
4957 				sizeof(pwildcard_ssid_tlv->max_ssid_length));
4958 		pwildcard_ssid_tlv->max_ssid_length =
4959 			bg_scan_in->ssid_list[ssid_idx].max_len;
4960 		memcpy(pmadapter, pwildcard_ssid_tlv->ssid,
4961 		       bg_scan_in->ssid_list[ssid_idx].ssid,
4962 		       MIN(MLAN_MAX_SSID_LENGTH, ssid_len));
4963 		tlv += sizeof(pwildcard_ssid_tlv->header) +
4964 			pwildcard_ssid_tlv->header.len;
4965 		cmd_size +=
4966 			sizeof(pwildcard_ssid_tlv->header) +
4967 			pwildcard_ssid_tlv->header.len;
4968 		pwildcard_ssid_tlv->header.len =
4969 			wlan_cpu_to_le16(pwildcard_ssid_tlv->header.len);
4970 		PRINTM(MINFO, "Scan: ssid_list[%d]: %s, %d\n", ssid_idx,
4971 		       pwildcard_ssid_tlv->ssid,
4972 		       pwildcard_ssid_tlv->max_ssid_length);
4973 	}
4974 	if (bg_scan_in->chan_list[0].chan_number) {
4975 		tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
4976 		PRINTM(MINFO, "Scan: Using supplied channel list\n");
4977 		chan_num = 0;
4978 		for (chan_idx = 0; chan_idx < WLAN_BG_SCAN_CHAN_MAX
4979 		     && bg_scan_in->chan_list[chan_idx].chan_number;
4980 		     chan_idx++) {
4981 			radio_type = bg_scan_in->chan_list[chan_idx].radio_type;
4982 			if (!wlan_is_band_compatible
4983 			    (pmpriv->config_bands | pmadapter->adhoc_start_band,
4984 			     radio_type_to_band(radio_type)))
4985 				continue;
4986 			scan_type = bg_scan_in->chan_list[chan_idx].scan_type;
4987 			/* Prevent active scanning on a radar controlled channel */
4988 			if (radio_type == BAND_5GHZ) {
4989 				if (wlan_11h_radar_detect_required
4990 				    (pmpriv,
4991 				     bg_scan_in->chan_list[chan_idx].
4992 				     chan_number)) {
4993 					scan_type = MLAN_SCAN_TYPE_PASSIVE;
4994 				}
4995 			}
4996 			if (radio_type == BAND_2GHZ) {
4997 				if (wlan_bg_scan_type_is_passive
4998 				    (pmpriv,
4999 				     bg_scan_in->chan_list[chan_idx].
5000 				     chan_number)) {
5001 					scan_type = MLAN_SCAN_TYPE_PASSIVE;
5002 				}
5003 			}
5004 			tlv_chan_list->chan_scan_param[chan_num].chan_number =
5005 				bg_scan_in->chan_list[chan_idx].chan_number;
5006 			tlv_chan_list->chan_scan_param[chan_num].bandcfg.
5007 				chanBand =
5008 				bg_scan_in->chan_list[chan_idx].radio_type;
5009 
5010 			if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
5011 				tlv_chan_list->chan_scan_param[chan_num].
5012 					chan_scan_mode.passive_scan = MTRUE;
5013 			} else {
5014 				tlv_chan_list->chan_scan_param[chan_num].
5015 					chan_scan_mode.passive_scan = MFALSE;
5016 			}
5017 			if (bg_scan_in->chan_list[chan_idx].scan_time) {
5018 				scan_dur =
5019 					(t_u16)bg_scan_in->chan_list[chan_idx].
5020 					scan_time;
5021 			} else {
5022 				if (scan_type == MLAN_SCAN_TYPE_PASSIVE) {
5023 					scan_dur = pmadapter->passive_scan_time;
5024 				} else {
5025 					scan_dur =
5026 						pmadapter->specific_scan_time;
5027 				}
5028 			}
5029 			tlv_chan_list->chan_scan_param[chan_num].min_scan_time =
5030 				wlan_cpu_to_le16(scan_dur);
5031 			tlv_chan_list->chan_scan_param[chan_num].max_scan_time =
5032 				wlan_cpu_to_le16(scan_dur);
5033 			chan_num++;
5034 		}
5035 		tlv_chan_list->header.type =
5036 			wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
5037 		tlv_chan_list->header.len =
5038 			wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
5039 		tlv += sizeof(MrvlIEtypesHeader_t) +
5040 			sizeof(ChanScanParamSet_t) * chan_num;
5041 		cmd_size +=
5042 			sizeof(MrvlIEtypesHeader_t) +
5043 			sizeof(ChanScanParamSet_t) * chan_num;
5044 	} else {
5045 		tlv_chan_list = (MrvlIEtypes_ChanListParamSet_t *)tlv;
5046 		chan_num =
5047 			wlan_bgscan_create_channel_list(pmpriv, bg_scan_in,
5048 							tlv_chan_list);
5049 		tlv_chan_list->header.type =
5050 			wlan_cpu_to_le16(TLV_TYPE_CHANLIST);
5051 		tlv_chan_list->header.len =
5052 			wlan_cpu_to_le16(sizeof(ChanScanParamSet_t) * chan_num);
5053 		tlv += sizeof(MrvlIEtypesHeader_t) +
5054 			sizeof(ChanScanParamSet_t) * chan_num;
5055 		cmd_size +=
5056 			sizeof(MrvlIEtypesHeader_t) +
5057 			sizeof(ChanScanParamSet_t) * chan_num;
5058 	}
5059 	if (bg_scan_in->chan_per_scan) {
5060 		bg_scan->chan_per_scan = bg_scan_in->chan_per_scan;
5061 	} else {
5062 		if (bg_scan_in->report_condition & BG_SCAN_WAIT_ALL_CHAN_DONE)
5063 			bg_scan->chan_per_scan = chan_num;
5064 		else
5065 			bg_scan->chan_per_scan =
5066 				MRVDRV_MAX_CHANNELS_PER_SPECIFIC_SCAN;
5067 	}
5068 
5069 	tlv_start_later = (MrvlIEtypes_StartLater_t *)tlv;
5070 	tlv_start_later->header.type =
5071 		wlan_cpu_to_le16(TLV_TYPE_STARTBGSCANLATER);
5072 	tlv_start_later->header.len =
5073 		wlan_cpu_to_le16(sizeof(MrvlIEtypes_StartLater_t) -
5074 				 sizeof(MrvlIEtypesHeader_t));
5075 	tlv_start_later->value = wlan_cpu_to_le16(bg_scan_in->start_later);
5076 	tlv += sizeof(MrvlIEtypes_StartLater_t);
5077 	cmd_size += sizeof(MrvlIEtypes_StartLater_t);
5078 
5079 done:
5080 	pcmd->size = wlan_cpu_to_le16(cmd_size);
5081 	LEAVE();
5082 	return MLAN_STATUS_SUCCESS;
5083 }
5084 
5085 /**
5086  *  @brief This function handles the command response of extended scan
5087  *
5088  *  @param pmpriv       A pointer to mlan_private structure
5089  *  @param resp         A pointer to HostCmd_DS_COMMAND
5090  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
5091  *
5092  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
5093  */
5094 mlan_status
wlan_ret_bgscan_config(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)5095 wlan_ret_bgscan_config(IN mlan_private *pmpriv,
5096 		       IN HostCmd_DS_COMMAND *resp,
5097 		       IN mlan_ioctl_req *pioctl_buf)
5098 {
5099 	mlan_ds_scan *pscan = MNULL;
5100 	HostCmd_DS_802_11_BG_SCAN_CONFIG *bg_scan =
5101 		&resp->params.bg_scan_config;
5102 	wlan_bgscan_cfg *bg_scan_out = MNULL;
5103 
5104 	ENTER();
5105 	if (pioctl_buf) {
5106 		pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
5107 		bg_scan_out =
5108 			(wlan_bgscan_cfg *)pscan->param.user_scan.scan_cfg_buf;
5109 		bg_scan_out->action = wlan_le16_to_cpu(bg_scan->action);
5110 		if ((bg_scan_out->action == BG_SCAN_ACT_GET) &&
5111 		    (bg_scan_out->action == BG_SCAN_ACT_GET_PPS_UAPSD)) {
5112 			bg_scan_out->enable = bg_scan->enable;
5113 			bg_scan_out->bss_type = bg_scan->bss_type;
5114 			bg_scan_out->chan_per_scan = bg_scan->chan_per_scan;
5115 			bg_scan_out->scan_interval =
5116 				wlan_le32_to_cpu(bg_scan->scan_interval);
5117 			bg_scan_out->report_condition =
5118 				wlan_le32_to_cpu(bg_scan->report_condition);
5119 			pioctl_buf->data_read_written =
5120 				sizeof(mlan_ds_scan) + MLAN_SUB_COMMAND_SIZE;
5121 		}
5122 	}
5123 	LEAVE();
5124 	return MLAN_STATUS_SUCCESS;
5125 }
5126 
5127 /**
5128  *  @brief This function handles the command response of bgscan_query
5129  *  @param pmpriv       A pointer to mlan_private structure
5130  *  @param resp         A pointer to HostCmd_DS_COMMAND
5131  *  @param pioctl_buf   A pointer to mlan_ioctl_req structure
5132  *
5133  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
5134  */
5135 mlan_status
wlan_ret_802_11_bgscan_query(IN mlan_private * pmpriv,IN HostCmd_DS_COMMAND * resp,IN mlan_ioctl_req * pioctl_buf)5136 wlan_ret_802_11_bgscan_query(IN mlan_private *pmpriv,
5137 			     IN HostCmd_DS_COMMAND *resp,
5138 			     IN mlan_ioctl_req *pioctl_buf)
5139 {
5140 	mlan_ds_scan *pscan = MNULL;
5141 	mlan_adapter *pmadapter = pmpriv->adapter;
5142 	ENTER();
5143 	wlan_ret_802_11_scan(pmpriv, resp, MNULL);
5144 	if (pioctl_buf) {
5145 		pscan = (mlan_ds_scan *)pioctl_buf->pbuf;
5146 		pscan->param.scan_resp.pscan_table =
5147 			(t_u8 *)pmadapter->pscan_table;
5148 		pscan->param.scan_resp.num_in_scan_table =
5149 			pmadapter->num_in_scan_table;
5150 		pscan->param.scan_resp.age_in_secs = pmadapter->age_in_secs;
5151 		pscan->param.scan_resp.pchan_stats =
5152 			(t_u8 *)pmadapter->pchan_stats;
5153 		pscan->param.scan_resp.num_in_chan_stats =
5154 			pmadapter->num_in_chan_stats;
5155 
5156 		pioctl_buf->data_read_written = sizeof(mlan_scan_resp) +
5157 			MLAN_SUB_COMMAND_SIZE;
5158 
5159 	}
5160 	LEAVE();
5161 	return MLAN_STATUS_SUCCESS;
5162 }
5163 
5164 /**
5165  *  @brief This function finds ssid in ssid list.
5166  *
5167  *  @param pmpriv       A pointer to mlan_private structure
5168  *  @param ssid         SSID to find in the list
5169  *  @param bssid        BSSID to qualify the SSID selection (if provided)
5170  *  @param mode         Network mode: Infrastructure or IBSS
5171  *
5172  *  @return             index in BSSID list or < 0 if error
5173  */
5174 t_s32
wlan_find_ssid_in_list(IN mlan_private * pmpriv,IN mlan_802_11_ssid * ssid,IN t_u8 * bssid,IN t_u32 mode)5175 wlan_find_ssid_in_list(IN mlan_private *pmpriv,
5176 		       IN mlan_802_11_ssid *ssid, IN t_u8 *bssid, IN t_u32 mode)
5177 {
5178 	mlan_adapter *pmadapter = pmpriv->adapter;
5179 	t_s32 net = -1, j;
5180 	t_u8 best_rssi = 0;
5181 	t_u32 i;
5182 
5183 	ENTER();
5184 	PRINTM(MINFO, "Num of entries in scan table = %d\n",
5185 	       pmadapter->num_in_scan_table);
5186 
5187 	/*
5188 	 * Loop through the table until the maximum is reached or until a match
5189 	 *   is found based on the bssid field comparison
5190 	 */
5191 	for (i = 0;
5192 	     i < pmadapter->num_in_scan_table && (!bssid || (bssid && net < 0));
5193 	     i++) {
5194 		if (!wlan_ssid_cmp
5195 		    (pmadapter, &pmadapter->pscan_table[i].ssid, ssid) &&
5196 		    (!bssid ||
5197 		     !memcmp(pmadapter, pmadapter->pscan_table[i].mac_address,
5198 			     bssid, MLAN_MAC_ADDR_LENGTH))) {
5199 
5200 			if ((mode == MLAN_BSS_MODE_INFRA) &&
5201 			    !wlan_is_band_compatible(pmpriv->config_bands,
5202 						     pmadapter->pscan_table[i].
5203 						     bss_band))
5204 				continue;
5205 
5206 			switch (mode) {
5207 			case MLAN_BSS_MODE_INFRA:
5208 			case MLAN_BSS_MODE_IBSS:
5209 				j = wlan_is_network_compatible(pmpriv, i, mode);
5210 
5211 				if (j >= 0) {
5212 					if (SCAN_RSSI
5213 					    (pmadapter->pscan_table[i].rssi) >
5214 					    best_rssi) {
5215 						best_rssi =
5216 							SCAN_RSSI(pmadapter->
5217 								  pscan_table
5218 								  [i].rssi);
5219 						net = i;
5220 					}
5221 				} else {
5222 					if (net == -1)
5223 						net = j;
5224 				}
5225 				break;
5226 			case MLAN_BSS_MODE_AUTO:
5227 			default:
5228 				/*
5229 				 * Do not check compatibility if the mode requested is
5230 				 *   Auto/Unknown.  Allows generic find to work without
5231 				 *   verifying against the Adapter security settings
5232 				 */
5233 				if (SCAN_RSSI(pmadapter->pscan_table[i].rssi) >
5234 				    best_rssi) {
5235 					best_rssi =
5236 						SCAN_RSSI(pmadapter->
5237 							  pscan_table[i].rssi);
5238 					net = i;
5239 				}
5240 				break;
5241 			}
5242 		}
5243 	}
5244 
5245 	LEAVE();
5246 	return net;
5247 }
5248 
5249 /**
5250  *  @brief This function finds a specific compatible BSSID in the scan list
5251  *
5252  *  @param pmpriv       A pointer to mlan_private structure
5253  *  @param bssid        BSSID to find in the scan list
5254  *  @param mode         Network mode: Infrastructure or IBSS
5255  *
5256  *  @return             index in BSSID list or < 0 if error
5257  */
5258 t_s32
wlan_find_bssid_in_list(IN mlan_private * pmpriv,IN t_u8 * bssid,IN t_u32 mode)5259 wlan_find_bssid_in_list(IN mlan_private *pmpriv, IN t_u8 *bssid, IN t_u32 mode)
5260 {
5261 	mlan_adapter *pmadapter = pmpriv->adapter;
5262 	t_s32 net = -1;
5263 	t_u32 i;
5264 
5265 	ENTER();
5266 
5267 	if (!bssid) {
5268 		LEAVE();
5269 		return -1;
5270 	}
5271 
5272 	PRINTM(MINFO, "FindBSSID: Num of BSSIDs = %d\n",
5273 	       pmadapter->num_in_scan_table);
5274 
5275 	/*
5276 	 * Look through the scan table for a compatible match. The ret return
5277 	 *   variable will be equal to the index in the scan table (greater
5278 	 *   than zero) if the network is compatible.  The loop will continue
5279 	 *   past a matched bssid that is not compatible in case there is an
5280 	 *   AP with multiple SSIDs assigned to the same BSSID
5281 	 */
5282 	for (i = 0; net < 0 && i < pmadapter->num_in_scan_table; i++) {
5283 		if (!memcmp
5284 		    (pmadapter, pmadapter->pscan_table[i].mac_address, bssid,
5285 		     MLAN_MAC_ADDR_LENGTH)) {
5286 			if ((mode == MLAN_BSS_MODE_INFRA) &&
5287 			    !wlan_is_band_compatible(pmpriv->config_bands,
5288 						     pmadapter->pscan_table[i].
5289 						     bss_band))
5290 				continue;
5291 			switch (mode) {
5292 			case MLAN_BSS_MODE_INFRA:
5293 			case MLAN_BSS_MODE_IBSS:
5294 				net = wlan_is_network_compatible(pmpriv, i,
5295 								 mode);
5296 				break;
5297 			default:
5298 				net = i;
5299 				break;
5300 			}
5301 		}
5302 	}
5303 
5304 	LEAVE();
5305 	return net;
5306 }
5307 
5308 /**
5309  *  @brief Compare two SSIDs
5310  *
5311  *  @param pmadapter A pointer to mlan_adapter structure
5312  *  @param ssid1     A pointer to ssid to compare
5313  *  @param ssid2     A pointer to ssid to compare
5314  *
5315  *  @return         0--ssid is same, otherwise is different
5316  */
5317 t_s32
wlan_ssid_cmp(IN pmlan_adapter pmadapter,IN mlan_802_11_ssid * ssid1,IN mlan_802_11_ssid * ssid2)5318 wlan_ssid_cmp(IN pmlan_adapter pmadapter,
5319 	      IN mlan_802_11_ssid *ssid1, IN mlan_802_11_ssid *ssid2)
5320 {
5321 	ENTER();
5322 
5323 	if (!ssid1 || !ssid2) {
5324 		LEAVE();
5325 		return -1;
5326 	}
5327 
5328 	if (ssid1->ssid_len != ssid2->ssid_len) {
5329 		LEAVE();
5330 		return -1;
5331 	}
5332 
5333 	LEAVE();
5334 	return memcmp(pmadapter, ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
5335 }
5336 
5337 /**
5338  *  @brief Find the AP with specific ssid in the scan list
5339  *
5340  *  @param pmpriv               A pointer to mlan_private structure
5341  *  @param preq_ssid_bssid      A pointer to AP's ssid returned
5342  *
5343  *  @return                     MLAN_STATUS_SUCCESS--success, otherwise--fail
5344  */
5345 mlan_status
wlan_find_best_network(IN mlan_private * pmpriv,OUT mlan_ssid_bssid * preq_ssid_bssid)5346 wlan_find_best_network(IN mlan_private *pmpriv,
5347 		       OUT mlan_ssid_bssid *preq_ssid_bssid)
5348 {
5349 	mlan_adapter *pmadapter = pmpriv->adapter;
5350 	mlan_status ret = MLAN_STATUS_SUCCESS;
5351 	BSSDescriptor_t *preq_bss;
5352 	t_s32 i;
5353 
5354 	ENTER();
5355 
5356 	memset(pmadapter, preq_ssid_bssid, 0, sizeof(mlan_ssid_bssid));
5357 
5358 	i = wlan_find_best_network_in_list(pmpriv);
5359 
5360 	if (i >= 0) {
5361 		preq_bss = &pmadapter->pscan_table[i];
5362 		memcpy(pmadapter, &preq_ssid_bssid->ssid, &preq_bss->ssid,
5363 		       sizeof(mlan_802_11_ssid));
5364 		memcpy(pmadapter, (t_u8 *)&preq_ssid_bssid->bssid,
5365 		       (t_u8 *)&preq_bss->mac_address, MLAN_MAC_ADDR_LENGTH);
5366 
5367 		/* Make sure we are in the right mode */
5368 		if (pmpriv->bss_mode == MLAN_BSS_MODE_AUTO)
5369 			pmpriv->bss_mode = preq_bss->bss_mode;
5370 		preq_ssid_bssid->channel = (t_u16)preq_bss->channel;
5371 		if (preq_bss->pmd_ie
5372 		    && wlan_ft_akm_is_used(pmpriv, (t_u8 *)preq_bss->prsn_ie)
5373 			) {
5374 			preq_ssid_bssid->ft_md = preq_bss->pmd_ie->mdid;
5375 			preq_ssid_bssid->ft_cap = preq_bss->pmd_ie->ft_cap;
5376 		}
5377 		preq_ssid_bssid->bss_band = preq_bss->bss_band;
5378 	}
5379 
5380 	if (!preq_ssid_bssid->ssid.ssid_len) {
5381 		ret = MLAN_STATUS_FAILURE;
5382 		goto done;
5383 	}
5384 
5385 	PRINTM(MINFO, "Best network found = [%s], "
5386 	       "[" MACSTR "]\n",
5387 	       preq_ssid_bssid->ssid.ssid, MAC2STR(preq_ssid_bssid->bssid));
5388 
5389 done:
5390 	LEAVE();
5391 	return ret;
5392 }
5393 
5394 /**
5395  *  @brief Send a scan command for all available channels filtered on a spec
5396  *
5397  *  @param pmpriv       A pointer to mlan_private structure
5398  *  @param pioctl_buf   A pointer to MLAN IOCTL Request buffer
5399  *  @param preq_ssid    A pointer to AP's ssid returned
5400  *
5401  *  @return             MLAN_STATUS_SUCCESS--success, otherwise--fail
5402  */
5403 mlan_status
wlan_scan_specific_ssid(IN mlan_private * pmpriv,IN t_void * pioctl_buf,IN mlan_802_11_ssid * preq_ssid)5404 wlan_scan_specific_ssid(IN mlan_private *pmpriv,
5405 			IN t_void *pioctl_buf, IN mlan_802_11_ssid *preq_ssid)
5406 {
5407 	mlan_status ret = MLAN_STATUS_SUCCESS;
5408 	mlan_callbacks *pcb = (mlan_callbacks *)&pmpriv->adapter->callbacks;
5409 	wlan_user_scan_cfg *pscan_cfg;
5410 	pmlan_ioctl_req pioctl_req = (mlan_ioctl_req *)pioctl_buf;
5411 
5412 	ENTER();
5413 
5414 	if (!preq_ssid) {
5415 		if (pioctl_req)
5416 			pioctl_req->status_code = MLAN_ERROR_CMD_SCAN_FAIL;
5417 		ret = MLAN_STATUS_FAILURE;
5418 		goto done;
5419 	}
5420 	wlan_scan_delete_ssid_table_entry(pmpriv, preq_ssid);
5421 
5422 	ret = pcb->moal_malloc(pmpriv->adapter->pmoal_handle,
5423 			       sizeof(wlan_user_scan_cfg), MLAN_MEM_DEF,
5424 			       (t_u8 **)&pscan_cfg);
5425 
5426 	if (ret != MLAN_STATUS_SUCCESS || !pscan_cfg) {
5427 		PRINTM(MERROR, "Memory allocation for pscan_cfg failed!\n");
5428 		if (pioctl_req)
5429 			pioctl_req->status_code = MLAN_ERROR_NO_MEM;
5430 		ret = MLAN_STATUS_FAILURE;
5431 		goto done;
5432 	}
5433 
5434 	memset(pmpriv->adapter, pscan_cfg, 0x00, sizeof(wlan_user_scan_cfg));
5435 
5436 	memcpy(pmpriv->adapter, pscan_cfg->ssid_list[0].ssid,
5437 	       preq_ssid->ssid, preq_ssid->ssid_len);
5438 	pscan_cfg->keep_previous_scan = MTRUE;
5439 
5440 	ret = wlan_scan_networks(pmpriv, pioctl_buf, pscan_cfg);
5441 
5442 	if (pscan_cfg)
5443 		pcb->moal_mfree(pmpriv->adapter->pmoal_handle,
5444 				(t_u8 *)pscan_cfg);
5445 
5446 done:
5447 	LEAVE();
5448 	return ret;
5449 }
5450 
5451 /**
5452  *  @brief Save a beacon buffer of the current bss descriptor
5453  *  Save the current beacon buffer to restore in the following cases that
5454  *  makes the bcn_buf not to contain the current ssid's beacon buffer.
5455  *    - the current ssid was not found somehow in the last scan.
5456  *    - the current ssid was the last entry of the scan table and overloaded.
5457  *
5458  *  @param pmpriv       A pointer to mlan_private structure
5459  *
5460  *  @return             N/A
5461  */
5462 t_void
wlan_save_curr_bcn(IN mlan_private * pmpriv)5463 wlan_save_curr_bcn(IN mlan_private *pmpriv)
5464 {
5465 	mlan_adapter *pmadapter = pmpriv->adapter;
5466 	mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
5467 	BSSDescriptor_t *pcurr_bss = &pmpriv->curr_bss_params.bss_descriptor;
5468 	mlan_status ret = MLAN_STATUS_SUCCESS;
5469 
5470 	ENTER();
5471 	pcb->moal_spin_lock(pmadapter->pmoal_handle, pmpriv->curr_bcn_buf_lock);
5472 	/* save the beacon buffer if it is not saved or updated */
5473 	if ((pmpriv->pcurr_bcn_buf == MNULL) ||
5474 	    (pmpriv->curr_bcn_size != pcurr_bss->beacon_buf_size) ||
5475 	    (memcmp
5476 	     (pmpriv->adapter, pmpriv->pcurr_bcn_buf, pcurr_bss->pbeacon_buf,
5477 	      pcurr_bss->beacon_buf_size))) {
5478 
5479 		if (pmpriv->pcurr_bcn_buf) {
5480 			pcb->moal_mfree(pmadapter->pmoal_handle,
5481 					pmpriv->pcurr_bcn_buf);
5482 			pmpriv->pcurr_bcn_buf = MNULL;
5483 		}
5484 		pmpriv->curr_bcn_size = pcurr_bss->beacon_buf_size;
5485 
5486 		if (pmpriv->curr_bcn_size) {
5487 			ret = pcb->moal_malloc(pmadapter->pmoal_handle,
5488 					       pcurr_bss->beacon_buf_size,
5489 					       MLAN_MEM_DEF,
5490 					       &pmpriv->pcurr_bcn_buf);
5491 
5492 			if ((ret == MLAN_STATUS_SUCCESS) &&
5493 			    pmpriv->pcurr_bcn_buf) {
5494 				memcpy(pmpriv->adapter, pmpriv->pcurr_bcn_buf,
5495 				       pcurr_bss->pbeacon_buf,
5496 				       pcurr_bss->beacon_buf_size);
5497 				PRINTM(MINFO, "current beacon saved %d\n",
5498 				       pmpriv->curr_bcn_size);
5499 			} else {
5500 				PRINTM(MERROR,
5501 				       "Fail to allocate curr_bcn_buf\n");
5502 			}
5503 		}
5504 	}
5505 	wlan_update_curr_bcn(pmpriv);
5506 	pcb->moal_spin_unlock(pmadapter->pmoal_handle,
5507 			      pmpriv->curr_bcn_buf_lock);
5508 
5509 	LEAVE();
5510 }
5511 
5512 /**
5513  *  @brief Free a beacon buffer of the current bss descriptor
5514  *
5515  *  @param pmpriv       A pointer to mlan_private structure
5516  *
5517  *  @return             N/A
5518  */
5519 t_void
wlan_free_curr_bcn(IN mlan_private * pmpriv)5520 wlan_free_curr_bcn(IN mlan_private *pmpriv)
5521 {
5522 	mlan_adapter *pmadapter = pmpriv->adapter;
5523 	mlan_callbacks *pcb = (pmlan_callbacks)&pmadapter->callbacks;
5524 
5525 	ENTER();
5526 	if (pmpriv->pcurr_bcn_buf) {
5527 		pcb->moal_mfree(pmadapter->pmoal_handle, pmpriv->pcurr_bcn_buf);
5528 		pmpriv->pcurr_bcn_buf = MNULL;
5529 	}
5530 	LEAVE();
5531 }
5532