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