• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #if defined(WL_ESCAN)
4 #include <bcmendian.h>
5 #include <linux/if_arp.h>
6 #include <linux/uaccess.h>
7 #include <wl_android.h>
8 #include <wl_escan.h>
9 #include <dhd_config.h>
10 
11 #define ESCAN_ERROR(name, arg1, args...) \
12 	do { \
13 		if (android_msg_level & ANDROID_ERROR_LEVEL) { \
14 			printk(KERN_ERR DHD_LOG_PREFIX "[%s] ESCAN-ERROR) %s : " arg1, name, __func__, ## args); \
15 		} \
16 	} while (0)
17 #define ESCAN_TRACE(name, arg1, args...) \
18 	do { \
19 		if (android_msg_level & ANDROID_TRACE_LEVEL) { \
20 			printk(KERN_INFO DHD_LOG_PREFIX "[%s] ESCAN-TRACE) %s : " arg1, name, __func__, ## args); \
21 		} \
22 	} while (0)
23 #define ESCAN_SCAN(name, arg1, args...) \
24 	do { \
25 		if (android_msg_level & ANDROID_SCAN_LEVEL) { \
26 			printk(KERN_INFO DHD_LOG_PREFIX "[%s] ESCAN-SCAN) %s : " arg1, name, __func__, ## args); \
27 		} \
28 	} while (0)
29 #define ESCAN_DBG(name, arg1, args...) \
30 	do { \
31 		if (android_msg_level & ANDROID_DBG_LEVEL) { \
32 			printk(KERN_INFO DHD_LOG_PREFIX "[%s] ESCAN-DBG) %s : " arg1, name, __func__, ## args); \
33 		} \
34 	} while (0)
35 
36 /* IOCTL swapping mode for Big Endian host with Little Endian dongle.  Default to off */
37 #define htod32(i) (i)
38 #define htod16(i) (i)
39 #define dtoh32(i) (i)
40 #define dtoh16(i) (i)
41 #define htodchanspec(i) (i)
42 #define dtohchanspec(i) (i)
43 #define WL_EXTRA_BUF_MAX 2048
44 
45 #define wl_escan_get_buf(a) ((wl_scan_results_t *) (a)->escan_buf)
46 
47 #define for_each_bss(list, bss, __i)	\
48 	for (__i = 0; __i < list->count && __i < IW_MAX_AP; __i++, bss = next_bss(list, bss))
49 
50 #define wl_escan_set_sync_id(a) ((a) = htod16(0x1234))
51 
52 #ifdef ESCAN_BUF_OVERFLOW_MGMT
53 #define BUF_OVERFLOW_MGMT_COUNT 3
54 typedef struct {
55 	int RSSI;
56 	int length;
57 	struct ether_addr BSSID;
58 } removal_element_t;
59 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
60 
61 /* Return a new chanspec given a legacy chanspec
62  * Returns INVCHANSPEC on error
63  */
64 static chanspec_t
wl_chspec_from_legacy(chanspec_t legacy_chspec)65 wl_chspec_from_legacy(chanspec_t legacy_chspec)
66 {
67 	chanspec_t chspec;
68 
69 	/* get the channel number */
70 	chspec = LCHSPEC_CHANNEL(legacy_chspec);
71 
72 	/* convert the band */
73 	if (LCHSPEC_IS2G(legacy_chspec)) {
74 		chspec |= WL_CHANSPEC_BAND_2G;
75 	} else {
76 		chspec |= WL_CHANSPEC_BAND_5G;
77 	}
78 
79 	/* convert the bw and sideband */
80 	if (LCHSPEC_IS20(legacy_chspec)) {
81 		chspec |= WL_CHANSPEC_BW_20;
82 	} else {
83 		chspec |= WL_CHANSPEC_BW_40;
84 		if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
85 			chspec |= WL_CHANSPEC_CTL_SB_L;
86 		} else {
87 			chspec |= WL_CHANSPEC_CTL_SB_U;
88 		}
89 	}
90 
91 	if (wf_chspec_malformed(chspec)) {
92 		ESCAN_ERROR("wlan", "wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
93 			chspec);
94 		return INVCHANSPEC;
95 	}
96 
97 	return chspec;
98 }
99 
100 /* Return a legacy chanspec given a new chanspec
101  * Returns INVCHANSPEC on error
102  */
103 static chanspec_t
wl_chspec_to_legacy(chanspec_t chspec)104 wl_chspec_to_legacy(chanspec_t chspec)
105 {
106 	chanspec_t lchspec;
107 
108 	if (wf_chspec_malformed(chspec)) {
109 		ESCAN_ERROR("wlan", "wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
110 			chspec);
111 		return INVCHANSPEC;
112 	}
113 
114 	/* get the channel number */
115 	lchspec = CHSPEC_CHANNEL(chspec);
116 
117 	/* convert the band */
118 	if (CHSPEC_IS2G(chspec)) {
119 		lchspec |= WL_LCHANSPEC_BAND_2G;
120 	} else {
121 		lchspec |= WL_LCHANSPEC_BAND_5G;
122 	}
123 
124 	/* convert the bw and sideband */
125 	if (CHSPEC_IS20(chspec)) {
126 		lchspec |= WL_LCHANSPEC_BW_20;
127 		lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
128 	} else if (CHSPEC_IS40(chspec)) {
129 		lchspec |= WL_LCHANSPEC_BW_40;
130 		if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
131 			lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
132 		} else {
133 			lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
134 		}
135 	} else {
136 		/* cannot express the bandwidth */
137 		char chanbuf[CHANSPEC_STR_LEN];
138 		ESCAN_ERROR("wlan", "wl_chspec_to_legacy: unable to convert chanspec %s "
139 			"(0x%04X) to pre-11ac format\n",
140 			wf_chspec_ntoa(chspec, chanbuf), chspec);
141 		return INVCHANSPEC;
142 	}
143 
144 	return lchspec;
145 }
146 
147 /* given a chanspec value from the driver, do the endian and chanspec version conversion to
148  * a chanspec_t value
149  * Returns INVCHANSPEC on error
150  */
151 static chanspec_t
wl_chspec_driver_to_host(int ioctl_ver,chanspec_t chanspec)152 wl_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
153 {
154 	chanspec = dtohchanspec(chanspec);
155 	if (ioctl_ver == 1) {
156 		chanspec = wl_chspec_from_legacy(chanspec);
157 	}
158 
159 	return chanspec;
160 }
161 
162 /* given a chanspec value, do the endian and chanspec version conversion to
163  * a chanspec_t value
164  * Returns INVCHANSPEC on error
165  */
166 static chanspec_t
wl_chspec_host_to_driver(int ioctl_ver,chanspec_t chanspec)167 wl_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
168 {
169 	if (ioctl_ver == 1) {
170 		chanspec = wl_chspec_to_legacy(chanspec);
171 		if (chanspec == INVCHANSPEC) {
172 			return chanspec;
173 		}
174 	}
175 	chanspec = htodchanspec(chanspec);
176 
177 	return chanspec;
178 }
179 
180 /* given a channel value, do the endian and chanspec version conversion to
181  * a chanspec_t value
182  * Returns INVCHANSPEC on error
183  */
184 static chanspec_t
wl_ch_host_to_driver(int ioctl_ver,u16 channel)185 wl_ch_host_to_driver(int ioctl_ver, u16 channel)
186 {
187 	chanspec_t chanspec;
188 
189 	chanspec = channel & WL_CHANSPEC_CHAN_MASK;
190 
191 	if (channel <= CH_MAX_2G_CHANNEL)
192 		chanspec |= WL_CHANSPEC_BAND_2G;
193 	else
194 		chanspec |= WL_CHANSPEC_BAND_5G;
195 
196 	chanspec |= WL_CHANSPEC_BW_20;
197 
198 	chanspec |= WL_CHANSPEC_CTL_SB_NONE;
199 
200 	return wl_chspec_host_to_driver(ioctl_ver, chanspec);
201 }
202 
next_bss(wl_scan_results_t * list,struct wl_bss_info * bss)203 static inline struct wl_bss_info *next_bss(wl_scan_results_t *list,
204 	struct wl_bss_info *bss)
205 {
206 	return bss = bss ?
207 		(struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
208 }
209 
210 #if defined(ESCAN_RESULT_PATCH)
211 static void
wl_escan_dump_bss(struct net_device * dev,struct wl_escan_info * escan,wl_bss_info_t * bi)212 wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan,
213 	wl_bss_info_t *bi)
214 {
215 	int16 rssi;
216 	int channel;
217 	chanspec_t chanspec;
218 
219 #if defined(RSSIAVG)
220 	rssi = wl_get_avg_rssi(dev, &bi->BSSID, FALSE);
221 	if (rssi == RSSI_MINVAL)
222 		rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
223 #else
224 	// terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
225 	rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
226 #endif
227 	chanspec = wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec);
228 	channel = wf_chspec_ctlchan(chanspec);
229 	ESCAN_SCAN(dev->name, "BSSID %pM, channel %3d(%3d %sMHz), rssi %3d, SSID \"%s\"\n",
230 		&bi->BSSID, channel, CHSPEC_CHANNEL(chanspec),
231 		CHSPEC_IS20(chanspec)?"20":
232 		CHSPEC_IS40(chanspec)?"40":
233 		CHSPEC_IS80(chanspec)?"80":"160",
234 		rssi, bi->SSID);
235 }
236 
237 static s32
wl_escan_inform_bss(struct net_device * dev,struct wl_escan_info * escan)238 wl_escan_inform_bss(struct net_device *dev, struct wl_escan_info *escan)
239 {
240 	wl_scan_results_t *bss_list;
241 	wl_bss_info_t *bi = NULL;	/* must be initialized */
242 	s32 i;
243 	s32 err = 0;
244 #if defined(RSSIAVG)
245 	int rssi;
246 #endif
247 
248 	bss_list = escan->bss_list;
249 
250 	ESCAN_SCAN(dev->name, "scanned AP count (%d)\n", bss_list->count);
251 
252 	/* Update cache */
253 #if defined(RSSIAVG)
254 	wl_update_rssi_cache(&escan->g_rssi_cache_ctrl, bss_list);
255 	if (!in_atomic())
256 		wl_update_connected_rssi_cache(dev, &escan->g_rssi_cache_ctrl, &rssi);
257 #endif
258 #if defined(BSSCACHE)
259 	wl_update_bss_cache(&escan->g_bss_cache_ctrl,
260 #if defined(RSSIAVG)
261 		&escan->g_rssi_cache_ctrl,
262 #endif
263 		bss_list);
264 #endif
265 
266 	/* delete dirty cache */
267 #if defined(RSSIAVG)
268 	wl_delete_dirty_rssi_cache(&escan->g_rssi_cache_ctrl);
269 	wl_reset_rssi_cache(&escan->g_rssi_cache_ctrl);
270 #endif
271 #if defined(BSSCACHE)
272 	wl_delete_dirty_bss_cache(&escan->g_bss_cache_ctrl);
273 	wl_reset_bss_cache(&escan->g_bss_cache_ctrl);
274 	if (escan->autochannel)
275 		wl_ext_get_best_channel(dev, &escan->g_bss_cache_ctrl,
276 			escan->ioctl_ver, &escan->best_2g_ch, &escan->best_5g_ch);
277 #else
278 	bi = next_bss(bss_list, bi);
279 	for_each_bss(bss_list, bi, i) {
280 		wl_escan_dump_bss(dev, escan, bi);
281 	}
282 	if (escan->autochannel)
283 		wl_ext_get_best_channel(dev, bss_list, escan->ioctl_ver,
284 			&escan->best_2g_ch, &escan->best_5g_ch);
285 #endif
286 
287 	return err;
288 }
289 #endif /* ESCAN_RESULT_PATCH */
290 
291 static wl_scan_params_t *
wl_escan_alloc_params(struct net_device * dev,struct wl_escan_info * escan,int channel,int nprobes,int * out_params_size)292 wl_escan_alloc_params(struct net_device *dev, struct wl_escan_info *escan,
293 	int channel, int nprobes, int *out_params_size)
294 {
295 	wl_scan_params_t *params;
296 	int params_size;
297 	int num_chans;
298 
299 	*out_params_size = 0;
300 
301 	/* Our scan params only need space for 1 channel and 0 ssids */
302 	params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
303 	params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
304 	if (params == NULL) {
305 		ESCAN_ERROR(dev->name, "mem alloc failed (%d bytes)\n", params_size);
306 		return params;
307 	}
308 	memset(params, 0, params_size);
309 	params->nprobes = nprobes;
310 
311 	num_chans = (channel == 0) ? 0 : 1;
312 
313 	memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
314 	params->bss_type = DOT11_BSSTYPE_ANY;
315 	params->scan_type = DOT11_SCANTYPE_ACTIVE;
316 	params->nprobes = htod32(1);
317 	params->active_time = htod32(-1);
318 	params->passive_time = htod32(-1);
319 	params->home_time = htod32(10);
320 	if (channel == -1)
321 		params->channel_list[0] = htodchanspec(channel);
322 	else
323 		params->channel_list[0] = wl_ch_host_to_driver(escan->ioctl_ver, channel);
324 
325 	/* Our scan params have 1 channel and 0 ssids */
326 	params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
327 		(num_chans & WL_SCAN_PARAMS_COUNT_MASK));
328 
329 	*out_params_size = params_size;	/* rtn size to the caller */
330 	return params;
331 }
332 
333 static void
wl_escan_abort(struct net_device * dev,struct wl_escan_info * escan)334 wl_escan_abort(struct net_device *dev, struct wl_escan_info *escan)
335 {
336 	wl_scan_params_t *params = NULL;
337 	s32 params_size = 0;
338 	s32 err = BCME_OK;
339 	if (!in_atomic()) {
340 		/* Our scan params only need space for 1 channel and 0 ssids */
341 		params = wl_escan_alloc_params(dev, escan, -1, 0, &params_size);
342 		if (params == NULL) {
343 			ESCAN_ERROR(dev->name, "scan params allocation failed \n");
344 			err = -ENOMEM;
345 		} else {
346 			/* Do a scan abort to stop the driver's scan engine */
347 			err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
348 			if (err < 0) {
349 				ESCAN_ERROR(dev->name, "scan abort  failed \n");
350 			}
351 			kfree(params);
352 		}
353 	}
354 }
355 
356 static s32
wl_escan_notify_complete(struct net_device * dev,struct wl_escan_info * escan,bool fw_abort)357 wl_escan_notify_complete(struct net_device *dev,
358 	struct wl_escan_info *escan, bool fw_abort)
359 {
360 	s32 err = BCME_OK;
361 #if defined(WL_WIRELESS_EXT)
362 	int cmd = 0;
363 #if WIRELESS_EXT > 13
364 	union iwreq_data wrqu;
365 	char extra[IW_CUSTOM_MAX + 1];
366 #endif
367 #endif
368 	struct dhd_pub *dhd = dhd_get_pub(dev);
369 
370 	ESCAN_TRACE(dev->name, "Enter\n");
371 
372 	if (fw_abort && !in_atomic())
373 		wl_escan_abort(dev, escan);
374 
375 	if (timer_pending(&escan->scan_timeout))
376 		del_timer_sync(&escan->scan_timeout);
377 
378 #if defined(ESCAN_RESULT_PATCH)
379 	escan->bss_list = wl_escan_get_buf(escan);
380 	wl_escan_inform_bss(dev, escan);
381 #endif /* ESCAN_RESULT_PATCH */
382 
383 	escan->escan_state = ESCAN_STATE_IDLE;
384 	wake_up_interruptible(&dhd->conf->event_complete);
385 
386 #if defined(WL_WIRELESS_EXT)
387 #if WIRELESS_EXT > 13
388 #if WIRELESS_EXT > 14
389 	cmd = SIOCGIWSCAN;
390 #endif
391 	// terence 20150224: fix "wlan0: (WE) : Wireless Event too big (65306)"
392 	memset(&wrqu, 0, sizeof(wrqu));
393 	memset(extra, 0, sizeof(extra));
394 	if (cmd) {
395 		if (cmd == SIOCGIWSCAN) {
396 			wireless_send_event(dev, cmd, &wrqu, NULL);
397 		} else
398 			wireless_send_event(dev, cmd, &wrqu, extra);
399 	}
400 #endif
401 #endif
402 
403 	return err;
404 }
405 
406 #ifdef ESCAN_BUF_OVERFLOW_MGMT
407 static void
wl_escan_find_removal_candidate(struct wl_escan_info * escan,wl_bss_info_t * bss,removal_element_t * candidate)408 wl_escan_find_removal_candidate(struct wl_escan_info *escan,
409 	wl_bss_info_t *bss, removal_element_t *candidate)
410 {
411 	int idx;
412 	for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
413 		int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1;
414 		if (bss->RSSI < candidate[idx].RSSI) {
415 			if (len)
416 				memcpy(&candidate[idx + 1], &candidate[idx],
417 					sizeof(removal_element_t) * len);
418 			candidate[idx].RSSI = bss->RSSI;
419 			candidate[idx].length = bss->length;
420 			memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN);
421 			return;
422 		}
423 	}
424 }
425 
426 static void
wl_escan_remove_lowRSSI_info(struct net_device * dev,struct wl_escan_info * escan,wl_scan_results_t * list,removal_element_t * candidate,wl_bss_info_t * bi)427 wl_escan_remove_lowRSSI_info(struct net_device *dev, struct wl_escan_info *escan,
428 	wl_scan_results_t *list, removal_element_t *candidate, wl_bss_info_t *bi)
429 {
430 	int idx1, idx2;
431 	int total_delete_len = 0;
432 	for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
433 		int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
434 		wl_bss_info_t *bss = NULL;
435 		if (candidate[idx1].RSSI >= bi->RSSI)
436 			continue;
437 		for (idx2 = 0; idx2 < list->count; idx2++) {
438 			bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
439 				list->bss_info;
440 			if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
441 				candidate[idx1].RSSI == bss->RSSI &&
442 				candidate[idx1].length == dtoh32(bss->length)) {
443 				u32 delete_len = dtoh32(bss->length);
444 				ESCAN_DBG(dev->name,
445 					"delete scan info of %pM to add new AP\n", &bss->BSSID);
446 				if (idx2 < list->count -1) {
447 					memmove((u8 *)bss, (u8 *)bss + delete_len,
448 						list->buflen - cur_len - delete_len);
449 				}
450 				list->buflen -= delete_len;
451 				list->count--;
452 				total_delete_len += delete_len;
453 				/* if delete_len is greater than or equal to result length */
454 				if (total_delete_len >= bi->length) {
455 					return;
456 				}
457 				break;
458 			}
459 			cur_len += dtoh32(bss->length);
460 		}
461 	}
462 }
463 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
464 
465 static s32
wl_escan_handler(struct net_device * dev,void * escan_void,const wl_event_msg_t * e,void * data)466 wl_escan_handler(struct net_device *dev, void *escan_void,
467 	const wl_event_msg_t *e, void *data)
468 {
469 	s32 err = BCME_OK;
470 	s32 status = ntoh32(e->status);
471 	wl_bss_info_t *bi;
472 	wl_escan_result_t *escan_result;
473 	wl_bss_info_t *bss = NULL;
474 	wl_scan_results_t *list;
475 	u32 bi_length;
476 	u32 i;
477 	u16 channel;
478 	struct wl_escan_info *escan = (struct wl_escan_info *)escan_void;
479 
480 	mutex_lock(&escan->usr_sync);
481 	escan_result = (wl_escan_result_t *)data;
482 
483 	if (escan->escan_state != ESCAN_STATE_SCANING) {
484 		ESCAN_DBG(dev->name, "Not my scan\n");
485 		goto exit;
486 	}
487 
488 	ESCAN_DBG(dev->name, "enter event type : %d, status : %d \n",
489 		ntoh32(e->event_type), ntoh32(e->status));
490 
491 	if (status == WLC_E_STATUS_PARTIAL) {
492 		ESCAN_DBG(dev->name, "WLC_E_STATUS_PARTIAL \n");
493 		if (!escan_result) {
494 			ESCAN_ERROR(dev->name, "Invalid escan result (NULL pointer)\n");
495 			goto exit;
496 		}
497 		if (dtoh16(escan_result->bss_count) != 1) {
498 			ESCAN_ERROR(dev->name, "Invalid bss_count %d: ignoring\n",
499 				escan_result->bss_count);
500 			goto exit;
501 		}
502 		bi = escan_result->bss_info;
503 		if (!bi) {
504 			ESCAN_ERROR(dev->name, "Invalid escan bss info (NULL pointer)\n");
505 			goto exit;
506 		}
507 		bi_length = dtoh32(bi->length);
508 		if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
509 			ESCAN_ERROR(dev->name, "Invalid bss_info length %d: ignoring\n",
510 				bi_length);
511 			goto exit;
512 		}
513 
514 		/* +++++ terence 20130524: skip invalid bss */
515 		channel =
516 			bi->ctl_ch ? bi->ctl_ch :
517 			CHSPEC_CHANNEL(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec));
518 		if (!dhd_conf_match_channel(escan->pub, channel))
519 			goto exit;
520 		/* ----- terence 20130524: skip invalid bss */
521 
522 		{
523 			int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
524 #ifdef ESCAN_BUF_OVERFLOW_MGMT
525 			removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
526 			int remove_lower_rssi = FALSE;
527 
528 			bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT);
529 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
530 
531 			list = wl_escan_get_buf(escan);
532 #ifdef ESCAN_BUF_OVERFLOW_MGMT
533 			if (bi_length > ESCAN_BUF_SIZE - list->buflen)
534 				remove_lower_rssi = TRUE;
535 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
536 
537 			ESCAN_DBG(dev->name, "%s(%pM) RSSI %d flags 0x%x length %d\n",
538 				bi->SSID, &bi->BSSID, bi->RSSI, bi->flags, bi->length);
539 			for (i = 0; i < list->count; i++) {
540 				bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
541 					: list->bss_info;
542 #ifdef ESCAN_BUF_OVERFLOW_MGMT
543 				ESCAN_DBG(dev->name,
544 					"%s(%pM), i=%d bss: RSSI %d list->count %d\n",
545 					bss->SSID, &bss->BSSID, i, bss->RSSI, list->count);
546 
547 				if (remove_lower_rssi)
548 					wl_escan_find_removal_candidate(escan, bss, candidate);
549 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
550 				if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
551 						(CHSPEC_BAND(wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec))
552 						== CHSPEC_BAND(wl_chspec_driver_to_host(escan->ioctl_ver, bss->chanspec))) &&
553 						bi->SSID_len == bss->SSID_len &&
554 						!bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
555 
556 					/* do not allow beacon data to update
557 					*the data recd from a probe response
558 					*/
559 					if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) &&
560 						(bi->flags & WL_BSS_FLAGS_FROM_BEACON))
561 						goto exit;
562 
563 					ESCAN_DBG(dev->name,
564 						"%s(%pM), i=%d prev: RSSI %d flags 0x%x, "
565 						"new: RSSI %d flags 0x%x\n",
566 						bss->SSID, &bi->BSSID, i, bss->RSSI, bss->flags,
567 						bi->RSSI, bi->flags);
568 
569 					if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
570 						(bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) {
571 						/* preserve max RSSI if the measurements are
572 						* both on-channel or both off-channel
573 						*/
574 						ESCAN_DBG(dev->name,
575 							"%s(%pM), same onchan, RSSI: prev %d new %d\n",
576 							bss->SSID, &bi->BSSID, bss->RSSI, bi->RSSI);
577 						bi->RSSI = MAX(bss->RSSI, bi->RSSI);
578 					} else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
579 						(bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) {
580 						/* preserve the on-channel rssi measurement
581 						* if the new measurement is off channel
582 						*/
583 						ESCAN_DBG(dev->name,
584 							"%s(%pM), prev onchan, RSSI: prev %d new %d\n",
585 							bss->SSID, &bi->BSSID, bss->RSSI, bi->RSSI);
586 						bi->RSSI = bss->RSSI;
587 						bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
588 					}
589 					if (dtoh32(bss->length) != bi_length) {
590 						u32 prev_len = dtoh32(bss->length);
591 
592 						ESCAN_DBG(dev->name,
593 							"bss info replacement occured(bcast:%d->probresp%d)\n",
594 							bss->ie_length, bi->ie_length);
595 						ESCAN_DBG(dev->name,
596 							"%s(%pM), replacement!(%d -> %d)\n",
597 							bss->SSID, &bi->BSSID, prev_len, bi_length);
598 
599 						if (list->buflen - prev_len + bi_length	> ESCAN_BUF_SIZE) {
600 							ESCAN_ERROR(dev->name,
601 								"Buffer is too small: keep the previous result "
602 								"of this AP\n");
603 							/* Only update RSSI */
604 							bss->RSSI = bi->RSSI;
605 							bss->flags |= (bi->flags
606 								& WL_BSS_FLAGS_RSSI_ONCHANNEL);
607 							goto exit;
608 						}
609 
610 						if (i < list->count - 1) {
611 							/* memory copy required by this case only */
612 							memmove((u8 *)bss + bi_length,
613 								(u8 *)bss + prev_len,
614 								list->buflen - cur_len - prev_len);
615 						}
616 						list->buflen -= prev_len;
617 						list->buflen += bi_length;
618 					}
619 					list->version = dtoh32(bi->version);
620 					memcpy((u8 *)bss, (u8 *)bi, bi_length);
621 					goto exit;
622 				}
623 				cur_len += dtoh32(bss->length);
624 			}
625 			if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
626 #ifdef ESCAN_BUF_OVERFLOW_MGMT
627 				wl_escan_remove_lowRSSI_info(dev, escan, list, candidate, bi);
628 				if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
629 					ESCAN_DBG(dev->name,
630 						"RSSI(%pM) is too low(%d) to add Buffer\n",
631 						&bi->BSSID, bi->RSSI);
632 					goto exit;
633 				}
634 #else
635 				ESCAN_ERROR(dev->name, "Buffer is too small: ignoring\n");
636 				goto exit;
637 #endif /* ESCAN_BUF_OVERFLOW_MGMT */
638 			}
639 
640 			memcpy(&(((char *)list)[list->buflen]), bi, bi_length);
641 			list->version = dtoh32(bi->version);
642 			list->buflen += bi_length;
643 			list->count++;
644 		}
645 	}
646 	else if (status == WLC_E_STATUS_SUCCESS) {
647 		ESCAN_DBG(dev->name, "ESCAN COMPLETED\n");
648 		escan->bss_list = wl_escan_get_buf(escan);
649 		ESCAN_DBG(dev->name, "SCAN COMPLETED: scanned AP count=%d\n",
650 			escan->bss_list->count);
651 		wl_escan_notify_complete(dev, escan, false);
652 	} else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
653 		(status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
654 		(status == WLC_E_STATUS_NEWASSOC)) {
655 		/* Handle all cases of scan abort */
656 		ESCAN_DBG(dev->name, "ESCAN ABORT reason: %d\n", status);
657 		escan->bss_list = wl_escan_get_buf(escan);
658 		ESCAN_DBG(dev->name, "SCAN ABORT: scanned AP count=%d\n",
659 			escan->bss_list->count);
660 		wl_escan_notify_complete(dev, escan, false);
661 	} else if (status == WLC_E_STATUS_TIMEOUT) {
662 		ESCAN_ERROR(dev->name, "WLC_E_STATUS_TIMEOUT\n");
663 		ESCAN_ERROR(dev->name, "reason[0x%x]\n", e->reason);
664 		if (e->reason == 0xFFFFFFFF) {
665 			wl_escan_notify_complete(dev, escan, true);
666 		}
667 	} else {
668 		ESCAN_ERROR(dev->name, "unexpected Escan Event %d : abort\n", status);
669 		escan->bss_list = wl_escan_get_buf(escan);
670 		ESCAN_DBG(dev->name, "SCAN ABORTED(UNEXPECTED): scanned AP count=%d\n",
671 			escan->bss_list->count);
672 		wl_escan_notify_complete(dev, escan, false);
673 	}
674 exit:
675 	mutex_unlock(&escan->usr_sync);
676 	return err;
677 }
678 
679 static int
wl_escan_prep(struct net_device * dev,struct wl_escan_info * escan,wl_uint32_list_t * list,void * scan_params,wlc_ssid_t * ssid,bool bcast)680 wl_escan_prep(struct net_device *dev, struct wl_escan_info *escan,
681 	wl_uint32_list_t *list, void *scan_params, wlc_ssid_t *ssid, bool bcast)
682 {
683 	int err = 0;
684 	wl_scan_results_t *results;
685 	char *ptr;
686 	int i = 0, j = 0;
687 	wlc_ssid_t ssid_tmp;
688 	u32 n_channels = 0;
689 	uint channel;
690 	chanspec_t chanspec;
691 	u32 n_ssids = 0;
692 	wl_scan_params_t *params = NULL;
693 	wl_scan_params_v2_t *params_v2 = NULL;
694 	u32 scan_param_size = 0;
695 	u32 channel_offset = 0;
696 	u32 cur_offset;
697 	uint16 *chan_list = NULL;
698 
699 	results = wl_escan_get_buf(escan);
700 	results->version = 0;
701 	results->count = 0;
702 	results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
703 	escan->escan_state = ESCAN_STATE_SCANING;
704 
705 	/* Arm scan timeout timer */
706 	mod_timer(&escan->scan_timeout, jiffies + msecs_to_jiffies(WL_ESCAN_TIMER_INTERVAL_MS));
707 
708 	if (escan->scan_params_v2) {
709 		params_v2 = (wl_scan_params_v2_t *)scan_params;
710 		scan_param_size = sizeof(wl_scan_params_v2_t);
711 		channel_offset = offsetof(wl_scan_params_v2_t, channel_list);
712 	} else {
713 		params = (wl_scan_params_t *)scan_params;
714 		scan_param_size = sizeof(wl_scan_params_t);
715 		channel_offset = offsetof(wl_scan_params_t, channel_list);
716 	}
717 
718 	if (params_v2) {
719 		/* scan params ver2 */
720 		memcpy(&params_v2->bssid, &ether_bcast, ETHER_ADDR_LEN);
721 		params_v2->version = htod16(WL_SCAN_PARAMS_VERSION_V2);
722 		params_v2->length = htod16(sizeof(wl_scan_params_v2_t));
723 		params_v2->bss_type = DOT11_BSSTYPE_ANY;
724 		params_v2->scan_type = DOT11_SCANTYPE_ACTIVE;
725 		params_v2->nprobes = htod32(-1);
726 		params_v2->active_time = htod32(-1);
727 		params_v2->passive_time = htod32(-1);
728 		params_v2->home_time = htod32(-1);
729 		params_v2->channel_num = 0;
730 		bzero(&params_v2->ssid, sizeof(wlc_ssid_t));
731 		chan_list = params_v2->channel_list;
732 	} else {
733 		/* scan params ver 1 */
734 		memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
735 		params->bss_type = DOT11_BSSTYPE_ANY;
736 		params->scan_type = DOT11_SCANTYPE_ACTIVE;
737 		params->nprobes = htod32(-1);
738 		params->active_time = htod32(-1);
739 		params->passive_time = htod32(-1);
740 		params->home_time = htod32(-1);
741 		params->channel_num = 0;
742 		bzero(&params->ssid, sizeof(wlc_ssid_t));
743 		chan_list = params->channel_list;
744 	}
745 
746 	cur_offset = channel_offset;
747 
748 	n_channels = dtoh32(list->count);
749 	/* Copy channel array if applicable */
750 	ESCAN_SCAN(dev->name, "### List of channelspecs to scan ###\n");
751 	if (n_channels > 0) {
752 		for (i = 0; i < n_channels; i++) {
753 			channel = dtoh32(list->element[i]);
754 			if (!dhd_conf_match_channel(escan->pub, channel))
755 				continue;
756 			chanspec = WL_CHANSPEC_BW_20;
757 			if (chanspec == INVCHANSPEC) {
758 				ESCAN_ERROR(dev->name, "Invalid chanspec! Skipping channel\n");
759 				continue;
760 			}
761 			if (channel <= CH_MAX_2G_CHANNEL) {
762 				chanspec |= WL_CHANSPEC_BAND_2G;
763 			} else {
764 				chanspec |= WL_CHANSPEC_BAND_5G;
765 			}
766 			chan_list[j] = channel;
767 			chan_list[j] &= WL_CHANSPEC_CHAN_MASK;
768 			chan_list[j] |= chanspec;
769 			ESCAN_SCAN(dev->name, "Chan : %d, Channel spec: %x\n",
770 				channel, chan_list[j]);
771 			chan_list[j] = wl_chspec_host_to_driver(escan->ioctl_ver,
772 				chan_list[j]);
773 			j++;
774 		}
775 		cur_offset += (j * (sizeof(u16)));
776 	} else {
777 		ESCAN_SCAN(dev->name, "Scanning all channels\n");
778 	}
779 
780 	if (ssid && ssid->SSID_len) {
781 		/* Copy ssid array if applicable */
782 		ESCAN_SCAN(dev->name, "### List of SSIDs to scan ###\n");
783 		cur_offset = (u32) roundup(cur_offset, sizeof(u32));
784 		ptr = (char*)params + cur_offset;
785 
786 		if (bcast) {
787 			n_ssids = 2;
788 			ESCAN_SCAN(dev->name, "0: Broadcast scan\n");
789 			memset(&ssid_tmp, 0, sizeof(wlc_ssid_t));
790 			ssid_tmp.SSID_len = 0;
791 			memcpy(ptr, &ssid_tmp, sizeof(wlc_ssid_t));
792 			ptr += sizeof(wlc_ssid_t);
793 		} else {
794 			n_ssids = 1;
795 		}
796 
797 		memset(&ssid_tmp, 0, sizeof(wlc_ssid_t));
798 		ssid_tmp.SSID_len = ssid->SSID_len;
799 		memcpy(ssid_tmp.SSID, ssid->SSID, ssid->SSID_len);
800 		memcpy(ptr, &ssid_tmp, sizeof(wlc_ssid_t));
801 		ptr += sizeof(wlc_ssid_t);
802 		ESCAN_SCAN(dev->name, "1: scan for %s size=%d\n",
803 			ssid_tmp.SSID, ssid_tmp.SSID_len);
804 	}
805 	else {
806 		ESCAN_SCAN(dev->name, "Broadcast scan\n");
807 	}
808 
809 	if (n_ssids || n_channels) {
810 		u32 channel_num =
811 				htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
812 				(n_channels & WL_SCAN_PARAMS_COUNT_MASK));
813 		if (params_v2) {
814 			params_v2->channel_num = channel_num;
815 		} else {
816 			params->channel_num = channel_num;
817 		}
818 	}
819 
820 	return err;
821 }
822 
823 static int
wl_escan_reset(struct wl_escan_info * escan)824 wl_escan_reset(struct wl_escan_info *escan)
825 {
826 	if (timer_pending(&escan->scan_timeout))
827 		del_timer_sync(&escan->scan_timeout);
828 	escan->escan_state = ESCAN_STATE_IDLE;
829 
830 	return 0;
831 }
832 
833 static void
wl_escan_timeout(unsigned long data)834 wl_escan_timeout(unsigned long data)
835 {
836 	wl_event_msg_t msg;
837 	struct wl_escan_info *escan = (struct wl_escan_info *)data;
838 	wl_scan_results_t *bss_list;
839 	struct wl_bss_info *bi = NULL;
840 	s32 i;
841 	u32 channel;
842 
843 	if (!escan->dev) {
844 		ESCAN_ERROR("wlan", "No dev present\n");
845 		return;
846 	}
847 
848 	bss_list = wl_escan_get_buf(escan);
849 	if (!bss_list) {
850 		ESCAN_ERROR(escan->dev->name,
851 			"bss_list is null. Didn't receive any partial scan results\n");
852 	} else {
853 		ESCAN_ERROR(escan->dev->name, "scanned AP count (%d)\n", bss_list->count);
854 		bi = next_bss(bss_list, bi);
855 		for_each_bss(bss_list, bi, i) {
856 			channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(escan->ioctl_ver,
857 				bi->chanspec));
858 			ESCAN_ERROR(escan->dev->name, "SSID :%s  Channel :%d\n", bi->SSID, channel);
859 		}
860 	}
861 
862 	bzero(&msg, sizeof(wl_event_msg_t));
863 	ESCAN_ERROR(escan->dev->name, "timer expired\n");
864 
865 	msg.ifidx = dhd_net2idx(escan->pub->info, escan->dev);
866 	msg.event_type = hton32(WLC_E_ESCAN_RESULT);
867 	msg.status = hton32(WLC_E_STATUS_TIMEOUT);
868 	msg.reason = 0xFFFFFFFF;
869 	wl_ext_event_send(escan->pub->event_params, &msg, NULL);
870 }
871 
872 int
wl_escan_set_scan(struct net_device * dev,dhd_pub_t * dhdp,wlc_ssid_t * ssid,uint16 channel,bool bcast)873 wl_escan_set_scan(struct net_device *dev, dhd_pub_t *dhdp,
874 	wlc_ssid_t *ssid, uint16 channel, bool bcast)
875 {
876 	struct wl_escan_info *escan = dhdp->escan;
877 	s32 err = BCME_OK;
878 	wl_escan_params_t *eparams = NULL;
879 	wl_escan_params_v2_t *eparams_v2 = NULL;
880 	u8 *scan_params = NULL;
881 	s32 params_size;
882 	wl_escan_params_t *params = NULL;
883 	scb_val_t scbval;
884 	static int cnt = 0;
885 	u32 n_channels = 0;
886 	wl_uint32_list_t *list;
887 	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
888 
889 	mutex_lock(&escan->usr_sync);
890 	if (escan->escan_state == ESCAN_STATE_DOWN) {
891 		ESCAN_ERROR(dev->name, "STATE is down\n");
892 		err = -EINVAL;
893 		goto exit2;
894 	}
895 
896 	if (wl_ext_check_scan(dev, dhdp)) {
897 		err = -EBUSY;
898 		goto exit;
899 	}
900 
901 	ESCAN_TRACE(dev->name, "Enter \n");
902 
903 	if (escan->scan_params_v2) {
904 		params_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE +
905 				OFFSETOF(wl_escan_params_v2_t, params));
906 	} else {
907 		params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
908 	}
909 
910 	/* if scan request is not empty parse scan request paramters */
911 	memset(valid_chan_list, 0, sizeof(valid_chan_list));
912 	list = (wl_uint32_list_t *)(void *) valid_chan_list;
913 
914 	if (channel) {
915 		list->count = htod32(1);
916 		list->element[0] = htod32(channel);
917 	} else {
918 		list->count = htod32(WL_NUMCHANNELS);
919 		err = wldev_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
920 			sizeof(valid_chan_list), false);
921 		if (err != 0) {
922 			ESCAN_ERROR(dev->name, "get channels failed with %d\n", err);
923 			goto exit;
924 		}
925 	}
926 
927 	n_channels = dtoh32(list->count);
928 	/* Allocate space for populating ssids in wl_escan_params_t struct */
929 	if (dtoh32(list->count) % 2)
930 		/* If n_channels is odd, add a padd of u16 */
931 		params_size += sizeof(u16) * (n_channels + 1);
932 	else
933 		params_size += sizeof(u16) * n_channels;
934 	if (ssid && ssid->SSID_len) {
935 		params_size += sizeof(struct wlc_ssid) * 2;
936 	}
937 
938 	params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
939 	if (params == NULL) {
940 		err = -ENOMEM;
941 		goto exit;
942 	}
943 
944 	if (escan->scan_params_v2) {
945 		eparams_v2 = (wl_escan_params_v2_t *)params;
946 		scan_params = (u8 *)&eparams_v2->params;
947 		eparams_v2->version = htod32(ESCAN_REQ_VERSION_V2);
948 		eparams_v2->action =  htod16(WL_SCAN_ACTION_START);
949 	} else {
950 		eparams = (wl_escan_params_t *)params;
951 		scan_params = (u8 *)&eparams->params;
952 		eparams->version = htod32(ESCAN_REQ_VERSION);
953 		eparams->action =  htod16(WL_SCAN_ACTION_START);
954 	}
955 	wl_escan_set_sync_id(params->sync_id);
956 
957 	wl_escan_prep(dev, escan, list, scan_params, ssid, bcast);
958 
959 	if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
960 		ESCAN_ERROR(dev->name, "ioctl buffer length not sufficient\n");
961 		kfree(params);
962 		err = -ENOMEM;
963 		goto exit;
964 	}
965 	ESCAN_SCAN(dev->name, "scan_type %d\n", params->params.scan_type);
966 
967 	WL_MSG(dev->name, "LEGACY_SCAN\n");
968 	err = wldev_iovar_setbuf(dev, "escan", params, params_size,
969 		escan->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
970 	if (unlikely(err)) {
971 		if (err == BCME_EPERM)
972 			/* Scan Not permitted at this point of time */
973 			ESCAN_TRACE(dev->name, "Escan not permitted at this time (%d)\n", err);
974 		else
975 			ESCAN_ERROR(dev->name, "Escan set error (%d)\n", err);
976 	}
977 	kfree(params);
978 
979 	if (unlikely(err)) {
980 		/* Don't print Error incase of Scan suppress */
981 		if (err == BCME_EPERM)
982 			ESCAN_TRACE(dev->name, "Escan failed: Scan Suppressed\n");
983 		else {
984 			cnt++;
985 			ESCAN_ERROR(dev->name, "error (%d), cnt=%d\n", err, cnt);
986 			// terence 20140111: send disassoc to firmware
987 			if (cnt >= 4) {
988 				memset(&scbval, 0, sizeof(scb_val_t));
989 				wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true);
990 				ESCAN_ERROR(dev->name, "Send disassoc to break the busy\n");
991 				cnt = 0;
992 			}
993 		}
994 	} else {
995 		cnt = 0;
996 		escan->dev = dev;
997 	}
998 exit:
999 	if (unlikely(err)) {
1000 		wl_escan_reset(escan);
1001 	}
1002 exit2:
1003 	mutex_unlock(&escan->usr_sync);
1004 	return err;
1005 }
1006 
1007 #if defined(WL_WIRELESS_EXT)
1008 static int
rssi_to_qual(int rssi)1009 rssi_to_qual(int rssi)
1010 {
1011 	if (rssi <= WL_IW_RSSI_NO_SIGNAL)
1012 		return 0;
1013 	else if (rssi <= WL_IW_RSSI_VERY_LOW)
1014 		return 1;
1015 	else if (rssi <= WL_IW_RSSI_LOW)
1016 		return 2;
1017 	else if (rssi <= WL_IW_RSSI_GOOD)
1018 		return 3;
1019 	else if (rssi <= WL_IW_RSSI_VERY_GOOD)
1020 		return 4;
1021 	else
1022 		return 5;
1023 }
1024 
1025 static int
wl_escan_merge_scan_results(struct net_device * dev,struct wl_escan_info * escan,struct iw_request_info * info,char * extra,wl_bss_info_t * bi,int * len,int max_size)1026 wl_escan_merge_scan_results(struct net_device *dev, struct wl_escan_info *escan,
1027 	struct iw_request_info *info, char *extra, wl_bss_info_t *bi, int *len, int max_size)
1028 {
1029 	s32 err = BCME_OK;
1030 	struct iw_event	iwe;
1031 	int j;
1032 	char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
1033 	int16 rssi;
1034 	int channel;
1035 	chanspec_t chanspec;
1036 
1037 	/* overflow check cover fields before wpa IEs */
1038 	if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN +
1039 		IW_EV_QUAL_LEN >= end) {
1040 		err = -E2BIG;
1041 		goto exit;
1042 	}
1043 
1044 #if defined(RSSIAVG)
1045 	rssi = wl_get_avg_rssi(&escan->g_rssi_cache_ctrl, &bi->BSSID);
1046 	if (rssi == RSSI_MINVAL)
1047 		rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1048 #else
1049 	// terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
1050 	rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1051 #endif
1052 	chanspec = wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec);
1053 	channel = wf_chspec_ctlchan(chanspec);
1054 	ESCAN_SCAN(dev->name, "BSSID %pM, channel %3d(%3d %sMHz), rssi %3d, SSID \"%s\"\n",
1055 		&bi->BSSID, channel, CHSPEC_CHANNEL(chanspec),
1056 		CHSPEC_IS20(chanspec)?"20":
1057 		CHSPEC_IS40(chanspec)?"40":
1058 		CHSPEC_IS80(chanspec)?"80":"160",
1059 		rssi, bi->SSID);
1060 
1061 	/* First entry must be the BSSID */
1062 	iwe.cmd = SIOCGIWAP;
1063 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1064 	memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
1065 	event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
1066 
1067 	/* SSID */
1068 	iwe.u.data.length = dtoh32(bi->SSID_len);
1069 	iwe.cmd = SIOCGIWESSID;
1070 	iwe.u.data.flags = 1;
1071 	event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
1072 
1073 	/* Mode */
1074 	if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
1075 		iwe.cmd = SIOCGIWMODE;
1076 		if (dtoh16(bi->capability) & DOT11_CAP_ESS)
1077 			iwe.u.mode = IW_MODE_INFRA;
1078 		else
1079 			iwe.u.mode = IW_MODE_ADHOC;
1080 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
1081 	}
1082 
1083 	/* Channel */
1084 	iwe.cmd = SIOCGIWFREQ;
1085 #if 1
1086 	iwe.u.freq.m = wf_channel2mhz(channel, channel <= CH_MAX_2G_CHANNEL ?
1087 			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
1088 #else
1089 	iwe.u.freq.m = wf_channel2mhz(bi->n_cap ?
1090 			bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec),
1091 			CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
1092 			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
1093 #endif
1094 	iwe.u.freq.e = 6;
1095 	event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
1096 
1097 	/* Channel quality */
1098 	iwe.cmd = IWEVQUAL;
1099 	iwe.u.qual.qual = rssi_to_qual(rssi);
1100 	iwe.u.qual.level = 0x100 + rssi;
1101 	iwe.u.qual.noise = 0x100 + bi->phy_noise;
1102 	event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
1103 
1104 	wl_iw_handle_scanresults_ies(&event, end, info, bi);
1105 
1106 	/* Encryption */
1107 	iwe.cmd = SIOCGIWENCODE;
1108 	if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
1109 		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1110 	else
1111 		iwe.u.data.flags = IW_ENCODE_DISABLED;
1112 	iwe.u.data.length = 0;
1113 	event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
1114 
1115 	/* Rates */
1116 	if (bi->rateset.count <= sizeof(bi->rateset.rates)) {
1117 		if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) {
1118 			err = -E2BIG;
1119 			goto exit;
1120 		}
1121 		value = event + IW_EV_LCP_LEN;
1122 		iwe.cmd = SIOCGIWRATE;
1123 		/* Those two flags are ignored... */
1124 		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
1125 		for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
1126 			iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
1127 			value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
1128 				IW_EV_PARAM_LEN);
1129 		}
1130 		event = value;
1131 	}
1132 	*len = event - extra;
1133 	if (*len < 0)
1134 		ESCAN_ERROR(dev->name, "==> Wrong size\n");
1135 
1136 exit:
1137 	return err;
1138 }
1139 
1140 int
wl_escan_get_scan(struct net_device * dev,dhd_pub_t * dhdp,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1141 wl_escan_get_scan(struct net_device *dev, dhd_pub_t *dhdp,
1142 	struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1143 {
1144 	struct wl_escan_info *escan = dhdp->escan;
1145 	s32 err = BCME_OK;
1146 	int i = 0;
1147 	int len_prep = 0, len_ret = 0;
1148 	wl_bss_info_t *bi = NULL;
1149 	wl_scan_results_t *bss_list;
1150 	__u16 buflen_from_user = dwrq->length;
1151 #if defined(BSSCACHE)
1152 	wl_bss_cache_t *node;
1153 #endif
1154 	char *buf = NULL;
1155 	struct ether_addr cur_bssid;
1156 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
1157 
1158 	if (!extra) {
1159 		ESCAN_TRACE(dev->name, "extra is null\n");
1160 		return -EINVAL;
1161 	}
1162 
1163 	mutex_lock(&escan->usr_sync);
1164 
1165 	/* Check for scan in progress */
1166 	if (escan->escan_state == ESCAN_STATE_SCANING) {
1167 		ESCAN_DBG(dev->name, "SIOCGIWSCAN GET still scanning\n");
1168 		err = -EAGAIN;
1169 		goto exit;
1170 	}
1171 	if (!escan->bss_list) {
1172 		ESCAN_ERROR(dev->name, "scan not ready\n");
1173 		err = -EAGAIN;
1174 		goto exit;
1175 	}
1176 	if (dev != escan->dev) {
1177 		ESCAN_ERROR(dev->name, "not my scan from %s\n", escan->dev->name);
1178 		err = -EINVAL;
1179 		goto exit;
1180 	}
1181 
1182 	ESCAN_SCAN(dev->name, "SIOCGIWSCAN, len=%d\n", dwrq->length);
1183 
1184 	wldev_iovar_getbuf(dev, "cur_etheraddr", NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, NULL);
1185 	err = wldev_ioctl(dev, WLC_GET_BSSID, &cur_bssid, sizeof(cur_bssid), false);
1186 	if (err != BCME_NOTASSOCIATED &&
1187 			memcmp(&ether_null, &cur_bssid, ETHER_ADDR_LEN) &&
1188 			memcmp(ioctl_buf, &cur_bssid, ETHER_ADDR_LEN)) {
1189 		// merge current connected bss
1190 		buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC);
1191 		if (!buf) {
1192 			ESCAN_ERROR(dev->name, "buffer alloc failed.\n");
1193 			err = BCME_NOMEM;
1194 			goto exit;
1195 		}
1196 		*(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1197 		err = wldev_ioctl(dev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX, false);
1198 		if (unlikely(err)) {
1199 			ESCAN_ERROR(dev->name, "Could not get bss info %d\n", err);
1200 			goto exit;
1201 		}
1202 		bi = (struct wl_bss_info *)(buf + 4);
1203 		len_prep = 0;
1204 		err = wl_escan_merge_scan_results(dev, escan, info, extra+len_ret, bi,
1205 			&len_prep, buflen_from_user-len_ret);
1206 		len_ret += len_prep;
1207 		if (err)
1208 			goto exit;
1209 		bi = NULL;
1210 	}
1211 
1212 #if defined(BSSCACHE)
1213 	bss_list = &escan->g_bss_cache_ctrl.m_cache_head->results;
1214 	node = escan->g_bss_cache_ctrl.m_cache_head;
1215 	for (i=0; node && i<IW_MAX_AP; i++)
1216 #else
1217 	bss_list = escan->bss_list;
1218 	bi = next_bss(bss_list, bi);
1219 	for_each_bss(bss_list, bi, i)
1220 #endif
1221 	{
1222 #if defined(BSSCACHE)
1223 		bi = node->results.bss_info;
1224 #endif
1225 		if (!memcmp(&bi->BSSID, &cur_bssid, ETHER_ADDR_LEN)) {
1226 			ESCAN_SCAN(dev->name, "skip connected AP %pM\n", &cur_bssid);
1227 #if defined(BSSCACHE)
1228 			node = node->next;
1229 #endif
1230 			continue;
1231 		}
1232 		len_prep = 0;
1233 		err = wl_escan_merge_scan_results(dev, escan, info, extra+len_ret, bi,
1234 			&len_prep, buflen_from_user-len_ret);
1235 		len_ret += len_prep;
1236 		if (err)
1237 			goto exit;
1238 #if defined(BSSCACHE)
1239 		node = node->next;
1240 #endif
1241 	}
1242 
1243 	if ((len_ret + WE_ADD_EVENT_FIX) < dwrq->length)
1244 		dwrq->length = len_ret;
1245 
1246 	dwrq->flags = 0;	/* todo */
1247 	ESCAN_SCAN(dev->name, "scanned AP count (%d)\n", i);
1248 exit:
1249 	kfree(buf);
1250 	dwrq->length = len_ret;
1251 	mutex_unlock(&escan->usr_sync);
1252 	return err;
1253 }
1254 #endif /* WL_WIRELESS_EXT */
1255 
1256 #ifdef WLMESH
1257 bool
wl_escan_meshid_ie(u8 * parse,u32 len,wlc_ssid_t * mesh_id)1258 wl_escan_meshid_ie(u8 *parse, u32 len, wlc_ssid_t *mesh_id)
1259 {
1260 	bcm_tlv_t *ie;
1261 
1262 	if((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_MESH_ID)) != NULL) {
1263 		mesh_id->SSID_len = ie->len;
1264 		if (ie->len) {
1265 			strncpy(mesh_id->SSID, ie->data, ie->len);
1266 		}
1267 		return TRUE;
1268 	}
1269 	return FALSE;
1270 }
1271 
1272 bool
wl_escan_rsn_ie(u8 * parse,u32 len)1273 wl_escan_rsn_ie(u8 *parse, u32 len)
1274 {
1275 	if (bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_RSN_ID)) {
1276 		return TRUE;
1277 	}
1278 	return FALSE;
1279 }
1280 
1281 bool
wl_escan_mesh_info_ie(struct net_device * dev,u8 * parse,u32 len,struct wl_mesh_params * mesh_info)1282 wl_escan_mesh_info_ie(struct net_device *dev, u8 *parse, u32 len,
1283 	struct wl_mesh_params *mesh_info)
1284 {
1285 	bcm_tlv_t *ie;
1286 	uchar mesh_oui[]={0x00, 0x22, 0xf4};
1287 	int totl_len;
1288 	uint8 *pie;
1289 	uint max_len;
1290 	bool found = FALSE;
1291 
1292 	memset(mesh_info, 0, sizeof(struct wl_mesh_params));
1293 	if((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID)) != NULL) {
1294 		totl_len = ie->len;
1295 		if (!memcmp(ie->data, &mesh_oui, sizeof(mesh_oui))) {
1296 			pie = ie->data + sizeof(mesh_oui);
1297 			ie = (bcm_tlv_t *)pie;
1298 			totl_len -= sizeof(mesh_oui);
1299 			while (totl_len > 2 && ie->len) {
1300 				if (ie->id == MESH_INFO_MASTER_BSSID && ie->len == ETHER_ADDR_LEN) {
1301 					memcpy(&mesh_info->master_bssid, ie->data, ETHER_ADDR_LEN);
1302 				} else if (ie->id == MESH_INFO_MASTER_CHANNEL) {
1303 					mesh_info->master_channel = ie->data[0];
1304 					found = TRUE;
1305 				} else if (ie->id == MESH_INFO_HOP_CNT) {
1306 					mesh_info->hop_cnt = ie->data[0];
1307 				} else if (ie->id == MESH_INFO_PEER_BSSID) {
1308 					max_len = min(MAX_HOP_LIST*ETHER_ADDR_LEN, (int)ie->len);
1309 					memcpy(mesh_info->peer_bssid, ie->data, max_len);
1310 				}
1311 				totl_len -= (ie->len + 2);
1312 				pie = ie->data + ie->len;
1313 				ie = (bcm_tlv_t *)pie;
1314 			}
1315 		}
1316 	}
1317 
1318 	return found;
1319 }
1320 
1321 bool
wl_escan_mesh_info(struct net_device * dev,struct wl_escan_info * escan,struct ether_addr * peer_bssid,struct wl_mesh_params * mesh_info)1322 wl_escan_mesh_info(struct net_device *dev, struct wl_escan_info *escan,
1323 	struct ether_addr *peer_bssid, struct wl_mesh_params *mesh_info)
1324 {
1325 	int i = 0;
1326 	wl_bss_info_t *bi = NULL;
1327 	wl_scan_results_t *bss_list;
1328 	int16 bi_rssi, bi_chan;
1329 	wlc_ssid_t bi_meshid;
1330 	bool is_mesh_peer = FALSE, found = FALSE;
1331 	struct wl_mesh_params peer_mesh_info;
1332 
1333 	mutex_lock(&escan->usr_sync);
1334 
1335 	/* Check for scan in progress */
1336 	if (escan->escan_state == ESCAN_STATE_SCANING) {
1337 		ESCAN_ERROR(dev->name, "SIOCGIWSCAN GET still scanning\n");
1338 		goto exit;
1339 	}
1340 	if (!escan->bss_list) {
1341 		ESCAN_ERROR(dev->name, "scan not ready\n");
1342 		goto exit;
1343 	}
1344 	if (dev != escan->dev) {
1345 		ESCAN_ERROR(dev->name, "not my scan from %s\n", escan->dev->name);
1346 		goto exit;
1347 	}
1348 
1349 	bss_list = escan->bss_list;
1350 	bi = next_bss(bss_list, bi);
1351 	ESCAN_SCAN(dev->name, "scanned AP/Mesh count (%d)\n", bss_list->count);
1352 	for_each_bss(bss_list, bi, i)
1353 	{
1354 		memset(&bi_meshid, 0, sizeof(bi_meshid));
1355 		is_mesh_peer = FALSE;
1356 		bi_chan = wf_chspec_ctlchan(
1357 			wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec));
1358 		bi_rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1359 		is_mesh_peer = wl_escan_meshid_ie(((u8*)bi)+bi->ie_offset,
1360 			bi->ie_length, &bi_meshid);
1361 		if (!(bi->capability & (DOT11_CAP_ESS|DOT11_CAP_IBSS)) && is_mesh_peer) {
1362 			bool bi_sae = FALSE, bss_found = FALSE, prefer = FALSE;
1363 			if (!memcmp(peer_bssid, &bi->BSSID, ETHER_ADDR_LEN)) {
1364 				bi_sae = wl_escan_rsn_ie(((u8*)bi)+bi->ie_offset, bi->ie_length);
1365 				bss_found = wl_escan_mesh_info_ie(dev, ((u8*)bi)+bi->ie_offset,
1366 					bi->ie_length, &peer_mesh_info);
1367 				if (bss_found) {
1368 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
1369 						ETHER_ADDR_LEN);
1370 					mesh_info->master_channel = peer_mesh_info.master_channel;
1371 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt;
1372 					memcpy(mesh_info->peer_bssid, peer_mesh_info.peer_bssid,
1373 						sizeof(peer_mesh_info.peer_bssid));
1374 					prefer = TRUE;
1375 					found = TRUE;
1376 				}
1377 			}
1378 			ESCAN_SCAN(dev->name,
1379 				"%s[Mesh] BSSID=%pM, channel=%d, RSSI=%d, sec=%s, "
1380 				"mbssid=%pM, mchannel=%d, hop=%d, pbssid=%pM, MeshID=\"%s\"\n",
1381 				prefer?"*":" ", &bi->BSSID, bi_chan, bi_rssi, bi_sae?"SAE":"OPEN",
1382 				&peer_mesh_info.master_bssid, peer_mesh_info.master_channel,
1383 				peer_mesh_info.hop_cnt, &peer_mesh_info.peer_bssid, bi_meshid.SSID);
1384 		}
1385 	}
1386 
1387 exit:
1388 	mutex_unlock(&escan->usr_sync);
1389 	return found;
1390 }
1391 
1392 bool
wl_escan_mesh_peer(struct net_device * dev,struct wl_escan_info * escan,wlc_ssid_t * cur_ssid,uint16 cur_chan,bool sae,struct wl_mesh_params * mesh_info)1393 wl_escan_mesh_peer(struct net_device *dev, struct wl_escan_info *escan,
1394 	wlc_ssid_t *cur_ssid, uint16 cur_chan, bool sae,
1395 	struct wl_mesh_params *mesh_info)
1396 {
1397 	int i = 0;
1398 	wl_bss_info_t *bi = NULL;
1399 	wl_scan_results_t *bss_list;
1400 	int16 bi_rssi, bi_chan, max_rssi = -100;
1401 	uint min_hop_cnt = 255;
1402 	wlc_ssid_t bi_meshid;
1403 	bool is_mesh_peer = FALSE, chan_matched = FALSE, found = FALSE;
1404 	struct wl_mesh_params peer_mesh_info;
1405 
1406 	mutex_lock(&escan->usr_sync);
1407 
1408 	/* Check for scan in progress */
1409 	if (escan->escan_state == ESCAN_STATE_SCANING) {
1410 		ESCAN_ERROR(dev->name, "SIOCGIWSCAN GET still scanning\n");
1411 		goto exit;
1412 	}
1413 	if (!escan->bss_list) {
1414 		ESCAN_ERROR(dev->name, "scan not ready\n");
1415 		goto exit;
1416 	}
1417 	if (dev != escan->dev) {
1418 		ESCAN_ERROR(dev->name, "not my scan from %s\n", escan->dev->name);
1419 		goto exit;
1420 	}
1421 
1422 	bss_list = escan->bss_list;
1423 	bi = next_bss(bss_list, bi);
1424 	ESCAN_SCAN(dev->name, "scanned AP/Mesh count (%d)\n", bss_list->count);
1425 	for_each_bss(bss_list, bi, i)
1426 	{
1427 		memset(&bi_meshid, 0, sizeof(bi_meshid));
1428 		is_mesh_peer = FALSE;
1429 		bi_chan = wf_chspec_ctlchan(
1430 			wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec));
1431 		bi_rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1432 		is_mesh_peer = wl_escan_meshid_ie(((u8*)bi)+bi->ie_offset,
1433 			bi->ie_length, &bi_meshid);
1434 		if (!(bi->capability & (DOT11_CAP_ESS|DOT11_CAP_IBSS)) && is_mesh_peer) {
1435 			bool meshid_matched = FALSE, sec_matched = FALSE, bi_sae = FALSE,
1436 				bss_found = FALSE, prefer = FALSE;
1437 
1438 			if (cur_ssid->SSID_len && cur_ssid->SSID_len == bi_meshid.SSID_len &&
1439 					!memcmp(cur_ssid->SSID, bi_meshid.SSID, bi_meshid.SSID_len))
1440 				meshid_matched = TRUE;
1441 
1442 			bi_sae = wl_escan_rsn_ie(((u8*)bi)+bi->ie_offset, bi->ie_length);
1443 			if (bi_sae == sae)
1444 				sec_matched = TRUE;
1445 
1446 			bss_found = wl_escan_mesh_info_ie(dev, ((u8*)bi)+bi->ie_offset, bi->ie_length,
1447 				&peer_mesh_info);
1448 			if (meshid_matched && sec_matched && bss_found &&
1449 					(cur_chan == bi_chan)) {
1450 				if (peer_mesh_info.hop_cnt < min_hop_cnt) {
1451 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
1452 						ETHER_ADDR_LEN);
1453 					mesh_info->master_channel = peer_mesh_info.master_channel;
1454 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt;
1455 					memcpy(mesh_info->peer_bssid, peer_mesh_info.peer_bssid,
1456 						sizeof(peer_mesh_info.peer_bssid));
1457 					min_hop_cnt = peer_mesh_info.hop_cnt;
1458 					prefer = TRUE;
1459 					chan_matched = TRUE;
1460 					found = TRUE;
1461 				}
1462 			}
1463 			else if (meshid_matched && sec_matched && bss_found &&
1464 					(cur_chan != bi_chan) && !chan_matched) {
1465 				if (bi_rssi > max_rssi) {
1466 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
1467 						ETHER_ADDR_LEN);
1468 					mesh_info->master_channel = peer_mesh_info.master_channel;
1469 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt;
1470 					memcpy(mesh_info->peer_bssid, peer_mesh_info.peer_bssid,
1471 						sizeof(peer_mesh_info.peer_bssid));
1472 					max_rssi = bi_rssi;
1473 					prefer = TRUE;
1474 					found = TRUE;
1475 				}
1476 			}
1477 
1478 			ESCAN_SCAN(dev->name,
1479 				"%s[Mesh] BSSID=%pM, channel=%d, RSSI=%d, sec=%s, "
1480 				"mbssid=%pM, mchannel=%d, hop=%d, pbssid=%pM, MeshID=\"%s\"\n",
1481 				prefer?"*":" ", &bi->BSSID, bi_chan, bi_rssi, bi_sae?"SAE":"OPEN",
1482 				&peer_mesh_info.master_bssid, peer_mesh_info.master_channel,
1483 				peer_mesh_info.hop_cnt, &peer_mesh_info.peer_bssid, bi_meshid.SSID);
1484 		} else {
1485 			ESCAN_SCAN(dev->name,
1486 				"[AP] BSSID=%pM, channel=%d, RSSI=%d, SSID=\"%s\"\n",
1487 				&bi->BSSID, bi_chan, bi_rssi, bi->SSID);
1488 		}
1489 	}
1490 
1491 exit:
1492 	mutex_unlock(&escan->usr_sync);
1493 	return found;
1494 }
1495 #endif /* WLMESH */
1496 
1497 static void
wl_escan_deinit(struct net_device * dev,struct wl_escan_info * escan)1498 wl_escan_deinit(struct net_device *dev, struct wl_escan_info *escan)
1499 {
1500 	ESCAN_TRACE(dev->name, "Enter\n");
1501 
1502 	del_timer_sync(&escan->scan_timeout);
1503 	escan->escan_state = ESCAN_STATE_DOWN;
1504 
1505 #if defined(RSSIAVG)
1506 	wl_free_rssi_cache(&escan->g_rssi_cache_ctrl);
1507 #endif
1508 #if defined(BSSCACHE)
1509 	wl_free_bss_cache(&escan->g_bss_cache_ctrl);
1510 #endif
1511 }
1512 
1513 static s32
wl_escan_init(struct net_device * dev,struct wl_escan_info * escan)1514 wl_escan_init(struct net_device *dev, struct wl_escan_info *escan)
1515 {
1516 	ESCAN_TRACE(dev->name, "Enter\n");
1517 
1518 	/* Init scan_timeout timer */
1519 	init_timer_compat(&escan->scan_timeout, wl_escan_timeout, escan);
1520 	escan->escan_state = ESCAN_STATE_IDLE;
1521 
1522 	return 0;
1523 }
1524 
1525 void
wl_escan_down(struct net_device * dev,dhd_pub_t * dhdp)1526 wl_escan_down(struct net_device *dev, dhd_pub_t *dhdp)
1527 {
1528 	struct wl_escan_info *escan = dhdp->escan;
1529 
1530 	ESCAN_TRACE(dev->name, "Enter\n");
1531 	if (!escan) {
1532 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1533 		return;
1534 	}
1535 
1536 	escan->scan_params_v2 = false;
1537 
1538 	wl_escan_deinit(dev, escan);
1539 }
1540 
1541 int
wl_escan_up(struct net_device * dev,dhd_pub_t * dhdp)1542 wl_escan_up(struct net_device *dev, dhd_pub_t *dhdp)
1543 {
1544 	struct wl_escan_info *escan = dhdp->escan;
1545 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
1546 	s32 val = 0;
1547 	int ret = -1;
1548 
1549 	ESCAN_TRACE(dev->name, "Enter\n");
1550 	if (!escan) {
1551 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1552 		return ret;
1553 	}
1554 
1555 	ret = wl_escan_init(dev, escan);
1556 	if (ret) {
1557 		ESCAN_ERROR(dev->name, "wl_escan_init ret %d\n", ret);
1558 		return ret;
1559 	}
1560 
1561 	if (!escan->ioctl_ver) {
1562 		val = 1;
1563 		if ((ret = wldev_ioctl(dev, WLC_GET_VERSION, &val, sizeof(int), false) < 0)) {
1564 			ESCAN_ERROR(dev->name, "WLC_GET_VERSION failed, ret=%d\n", ret);
1565 			return ret;
1566 		}
1567 		val = dtoh32(val);
1568 		if (val != WLC_IOCTL_VERSION && val != 1) {
1569 			ESCAN_ERROR(dev->name,
1570 				"Version mismatch, please upgrade. Got %d, expected %d or 1\n",
1571 				val, WLC_IOCTL_VERSION);
1572 			return ret;
1573 		}
1574 		escan->ioctl_ver = val;
1575 	}
1576 
1577 	if ((ret = wldev_iovar_getbuf(dev, "scan_ver", NULL, 0,
1578 		ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) {
1579 		ESCAN_TRACE(dev->name, "scan_params v2\n");
1580 		/* use scan_params ver2 */
1581 		escan->scan_params_v2 = true;
1582 	} else {
1583 		if (ret == BCME_UNSUPPORTED) {
1584 			ESCAN_TRACE(dev->name, "scan_ver, UNSUPPORTED\n");
1585 			ret = BCME_OK;
1586 		} else {
1587 			ESCAN_ERROR(dev->name, "get scan_ver err(%d)\n", ret);
1588 		}
1589 	}
1590 
1591 	return 0;
1592 }
1593 
1594 int
wl_escan_event_dettach(struct net_device * dev,dhd_pub_t * dhdp)1595 wl_escan_event_dettach(struct net_device *dev, dhd_pub_t *dhdp)
1596 {
1597 	struct wl_escan_info *escan = dhdp->escan;
1598 	int ret = -1;
1599 
1600 	if (!escan) {
1601 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1602 		return ret;
1603 	}
1604 
1605 	wl_ext_event_deregister(dev, dhdp, WLC_E_ESCAN_RESULT, wl_escan_handler);
1606 
1607 	return 0;
1608 }
1609 
1610 int
wl_escan_event_attach(struct net_device * dev,dhd_pub_t * dhdp)1611 wl_escan_event_attach(struct net_device *dev, dhd_pub_t *dhdp)
1612 {
1613 	struct wl_escan_info *escan = dhdp->escan;
1614 	int ret = -1;
1615 
1616 	if (!escan) {
1617 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1618 		return ret;
1619 	}
1620 
1621 	ret = wl_ext_event_register(dev, dhdp, WLC_E_ESCAN_RESULT, wl_escan_handler,
1622 		escan, PRIO_EVENT_ESCAN);
1623 	if (ret) {
1624 		ESCAN_ERROR(dev->name, "wl_ext_event_register err %d\n", ret);
1625 	}
1626 
1627 	return ret;
1628 }
1629 
1630 void
wl_escan_detach(struct net_device * dev,dhd_pub_t * dhdp)1631 wl_escan_detach(struct net_device *dev, dhd_pub_t *dhdp)
1632 {
1633 	struct wl_escan_info *escan = dhdp->escan;
1634 
1635 	ESCAN_TRACE(dev->name, "Enter\n");
1636 
1637 	if (!escan)
1638 		return;
1639 
1640 	wl_escan_deinit(dev, escan);
1641 	if (escan->escan_ioctl_buf) {
1642 		kfree(escan->escan_ioctl_buf);
1643 		escan->escan_ioctl_buf = NULL;
1644 	}
1645 	wl_ext_event_deregister(dev, dhdp, WLC_E_ESCAN_RESULT, wl_escan_handler);
1646 
1647 	DHD_OS_PREFREE(dhdp, escan, sizeof(struct wl_escan_info));
1648 	dhdp->escan = NULL;
1649 }
1650 
1651 int
wl_escan_attach(struct net_device * dev,dhd_pub_t * dhdp)1652 wl_escan_attach(struct net_device *dev, dhd_pub_t *dhdp)
1653 {
1654 	struct wl_escan_info *escan = NULL;
1655 	int ret = 0;
1656 
1657 	ESCAN_TRACE(dev->name, "Enter\n");
1658 
1659 	escan = (struct wl_escan_info *)DHD_OS_PREALLOC(dhdp,
1660 		DHD_PREALLOC_WL_ESCAN, sizeof(struct wl_escan_info));
1661 	if (!escan)
1662 		return -ENOMEM;
1663 	memset(escan, 0, sizeof(struct wl_escan_info));
1664 
1665 	dhdp->escan = escan;
1666 
1667 	/* we only care about main interface so save a global here */
1668 	escan->pub = dhdp;
1669 	escan->escan_state = ESCAN_STATE_DOWN;
1670 
1671 	escan->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
1672 	if (unlikely(!escan->escan_ioctl_buf)) {
1673 		ESCAN_ERROR(dev->name, "Ioctl buf alloc failed\n");
1674 		ret = -ENOMEM;
1675 		goto exit;
1676 	}
1677 	ret = wl_escan_init(dev, escan);
1678 	if (ret) {
1679 		ESCAN_ERROR(dev->name, "wl_escan_init err %d\n", ret);
1680 		goto exit;
1681 	}
1682 	mutex_init(&escan->usr_sync);
1683 
1684 	return 0;
1685 
1686 exit:
1687 	wl_escan_detach(dev, dhdp);
1688 	return ret;
1689 }
1690 
1691 #endif /* WL_ESCAN */
1692 
1693