xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/wl_escan.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 
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_v109_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_v109_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_v109_t * list,struct wl_bss_info * bss)208 static inline struct wl_bss_info *next_bss(wl_scan_results_v109_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_v109_t * bi)218 wl_escan_dump_bss(struct net_device *dev, struct wl_escan_info *escan,
219 	wl_bss_info_v109_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_v109_t *bss_list;
248 #ifndef BSSCACHE
249 	wl_bss_info_v109_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->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,
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_v1_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_v1_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_V1_FIXED_SIZE + 1 * sizeof(uint16);
313 	params = (wl_scan_params_v1_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_v1_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_v109_t * bss,removal_element_t * candidate)418 wl_escan_find_removal_candidate(struct wl_escan_info *escan,
419 	wl_bss_info_v109_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_v109_t * list,removal_element_t * candidate,wl_bss_info_v109_t * bi)437 wl_escan_remove_lowRSSI_info(struct net_device *dev, struct wl_escan_info *escan,
438 	wl_scan_results_v109_t *list, removal_element_t *candidate, wl_bss_info_v109_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_V109_FIXED_SIZE;
444 		wl_bss_info_v109_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_v109_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_v109_t *bi;
482 	wl_escan_result_v109_t *escan_result;
483 	wl_bss_info_v109_t *bss = NULL;
484 	wl_scan_results_v109_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_v109_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_V109_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_V109_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_v109_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_v109_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_v1_t *params = NULL;
701 	wl_scan_params_v2_t *params_v2 = NULL;
702 	u32 channel_offset = 0;
703 	u32 cur_offset;
704 	uint16 *chan_list = NULL;
705 
706 	results = wl_escan_get_buf(escan);
707 	results->version = 0;
708 	results->count = 0;
709 	results->buflen = WL_SCAN_RESULTS_V109_FIXED_SIZE;
710 	escan->escan_state = ESCAN_STATE_SCANING;
711 
712 	/* Arm scan timeout timer */
713 	mod_timer(&escan->scan_timeout, jiffies + msecs_to_jiffies(WL_ESCAN_TIMER_INTERVAL_MS));
714 
715 	if (escan->scan_params_v2) {
716 		params_v2 = (wl_scan_params_v2_t *)scan_params;
717 		channel_offset = offsetof(wl_scan_params_v2_t, channel_list);
718 	} else {
719 		params = (wl_scan_params_v1_t *)scan_params;
720 		channel_offset = offsetof(wl_scan_params_v1_t, channel_list);
721 	}
722 
723 	if (params_v2) {
724 		/* scan params ver2 */
725 		memcpy(&params_v2->bssid, &ether_bcast, ETHER_ADDR_LEN);
726 		params_v2->version = htod16(WL_SCAN_PARAMS_VERSION_V2);
727 		params_v2->length = htod16(sizeof(wl_scan_params_v2_t));
728 		params_v2->bss_type = DOT11_BSSTYPE_ANY;
729 		params_v2->scan_type = DOT11_SCANTYPE_ACTIVE;
730 		params_v2->nprobes = htod32(-1);
731 		if (scan_info->scan_time)
732 			params_v2->active_time = htod32(scan_info->scan_time);
733 		else
734 			params_v2->active_time = htod32(-1);
735 		params_v2->passive_time = htod32(-1);
736 		params_v2->home_time = htod32(-1);
737 		params_v2->channel_num = 0;
738 		bzero(&params_v2->ssid, sizeof(wlc_ssid_t));
739 		chan_list = params_v2->channel_list;
740 	} else {
741 		/* scan params ver 1 */
742 		memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
743 		params->bss_type = DOT11_BSSTYPE_ANY;
744 		params->scan_type = DOT11_SCANTYPE_ACTIVE;
745 		params->nprobes = htod32(-1);
746 		if (scan_info->scan_time)
747 			params->active_time = htod32(scan_info->scan_time);
748 		else
749 			params->active_time = htod32(-1);
750 		params->passive_time = htod32(-1);
751 		params->home_time = htod32(-1);
752 		params->channel_num = 0;
753 		bzero(&params->ssid, sizeof(wlc_ssid_t));
754 		chan_list = params->channel_list;
755 	}
756 
757 	cur_offset = channel_offset;
758 
759 	n_channels = list->count;
760 	/* Copy channel array if applicable */
761 	ESCAN_SCAN(dev->name, "### List of channelspecs to scan ###\n");
762 	if (n_channels > 0) {
763 		for (i = 0; i < n_channels; i++) {
764 			chanspec = list->element[i];
765 			if (chanspec == INVCHANSPEC) {
766 				ESCAN_ERROR(dev->name, "Invalid chanspec! Skipping channel\n");
767 				continue;
768 			}
769 			chan_list[j] = chanspec;
770 			ESCAN_SCAN(dev->name, "Chan : %d, Channel spec: %x\n",
771 				CHSPEC_CHANNEL(chanspec), chanspec);
772 			chan_list[j] = wl_chspec_host_to_driver(escan->ioctl_ver,
773 				chan_list[j]);
774 			j++;
775 		}
776 		cur_offset += (j * (sizeof(u16)));
777 		n_channels = j;
778 	} else {
779 		ESCAN_SCAN(dev->name, "Scanning all channels\n");
780 	}
781 
782 	if (scan_info->ssid.SSID_len) {
783 		/* Copy ssid array if applicable */
784 		ESCAN_SCAN(dev->name, "### List of SSIDs to scan ###\n");
785 		cur_offset = (u32) roundup(cur_offset, sizeof(u32));
786 		if (params_v2)
787 			ptr = (char*)params_v2 + cur_offset;
788 		else
789 			ptr = (char*)params + cur_offset;
790 
791 		if (scan_info->bcast_ssid) {
792 			n_ssids = 2;
793 			ESCAN_SCAN(dev->name, "0: Broadcast scan\n");
794 			memset(&ssid_tmp, 0, sizeof(wlc_ssid_t));
795 			ssid_tmp.SSID_len = 0;
796 			memcpy(ptr, &ssid_tmp, sizeof(wlc_ssid_t));
797 			ptr += sizeof(wlc_ssid_t);
798 		} else {
799 			n_ssids = 1;
800 		}
801 
802 		memset(&ssid_tmp, 0, sizeof(wlc_ssid_t));
803 		ssid_tmp.SSID_len = scan_info->ssid.SSID_len;
804 		memcpy(ssid_tmp.SSID, scan_info->ssid.SSID, scan_info->ssid.SSID_len);
805 		memcpy(ptr, &ssid_tmp, sizeof(wlc_ssid_t));
806 		ptr += sizeof(wlc_ssid_t);
807 		ESCAN_SCAN(dev->name, "1: scan for %s size=%d\n",
808 			ssid_tmp.SSID, ssid_tmp.SSID_len);
809 	}
810 	else {
811 		ESCAN_SCAN(dev->name, "Broadcast scan\n");
812 	}
813 
814 	if (n_ssids || n_channels) {
815 		u32 channel_num =
816 				htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
817 				(n_channels & WL_SCAN_PARAMS_COUNT_MASK));
818 		if (params_v2) {
819 			params_v2->channel_num = channel_num;
820 		} else {
821 			params->channel_num = channel_num;
822 		}
823 	}
824 
825 	return err;
826 }
827 
828 static int
wl_escan_reset(struct wl_escan_info * escan)829 wl_escan_reset(struct wl_escan_info *escan)
830 {
831 	if (timer_pending(&escan->scan_timeout))
832 		del_timer_sync(&escan->scan_timeout);
833 	escan->escan_state = ESCAN_STATE_IDLE;
834 
835 	return 0;
836 }
837 
838 static void
wl_escan_timeout(unsigned long data)839 wl_escan_timeout(unsigned long data)
840 {
841 	wl_event_msg_t msg;
842 	struct wl_escan_info *escan = (struct wl_escan_info *)data;
843 	wl_scan_results_v109_t *bss_list;
844 	struct wl_bss_info *bi = NULL;
845 	s32 i;
846 	u32 channel;
847 
848 	if (!escan->dev) {
849 		ESCAN_ERROR("wlan", "No dev present\n");
850 		return;
851 	}
852 
853 	bss_list = wl_escan_get_buf(escan);
854 	if (!bss_list) {
855 		ESCAN_ERROR(escan->dev->name,
856 			"bss_list is null. Didn't receive any partial scan results\n");
857 	} else {
858 		ESCAN_ERROR(escan->dev->name, "scanned AP count (%d)\n", bss_list->count);
859 		bi = next_bss(bss_list, bi);
860 		for_each_bss(bss_list, bi, i) {
861 			channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(escan->ioctl_ver,
862 				bi->chanspec));
863 			ESCAN_ERROR(escan->dev->name, "SSID :%s  Channel :%d\n", bi->SSID, channel);
864 		}
865 	}
866 
867 	bzero(&msg, sizeof(wl_event_msg_t));
868 	ESCAN_ERROR(escan->dev->name, "timer expired\n");
869 
870 	msg.ifidx = dhd_net2idx(escan->pub->info, escan->dev);
871 	msg.event_type = hton32(WLC_E_ESCAN_RESULT);
872 	msg.status = hton32(WLC_E_STATUS_TIMEOUT);
873 	msg.reason = 0xFFFFFFFF;
874 	wl_ext_event_send(escan->pub->event_params, &msg, NULL);
875 }
876 
877 int
wl_escan_set_scan(struct net_device * dev,wl_scan_info_t * scan_info)878 wl_escan_set_scan(struct net_device *dev, wl_scan_info_t *scan_info)
879 {
880 	struct dhd_pub *dhdp = dhd_get_pub(dev);
881 	struct wl_escan_info *escan = dhdp->escan;
882 	s32 err = BCME_OK;
883 	wl_escan_params_v1_t *eparams = NULL;
884 	wl_escan_params_v2_t *eparams_v2 = NULL;
885 	u8 *scan_params = NULL, *params = NULL;
886 	s32 params_size;
887 	u32 n_channels = 0;
888 	wl_uint32_list_t *list = NULL;
889 
890 	mutex_lock(&escan->usr_sync);
891 	if (escan->escan_state == ESCAN_STATE_DOWN) {
892 		ESCAN_ERROR(dev->name, "STATE is down\n");
893 		err = -EINVAL;
894 		goto exit2;
895 	}
896 
897 #if defined(WL_EXT_IAPSTA) && defined(WL_CFG80211)
898 	err = wl_ext_in4way_sync(dev, STA_NO_SCAN_IN4WAY, WL_EXT_STATUS_SCAN, NULL);
899 	if (err) {
900 		ESCAN_SCAN(dev->name, "scan busy %d\n", err);
901 		goto exit2;
902 	}
903 #endif
904 
905 	if (wl_ext_check_scan(dev, dhdp)) {
906 		err = -EBUSY;
907 		goto exit2;
908 	}
909 
910 	ESCAN_TRACE(dev->name, "Enter\n");
911 
912 	if (escan->scan_params_v2) {
913 		params_size = (WL_SCAN_PARAMS_V2_FIXED_SIZE +
914 			OFFSETOF(wl_escan_params_v2_t, params));
915 	} else {
916 		params_size = (WL_SCAN_PARAMS_V1_FIXED_SIZE +
917 			OFFSETOF(wl_escan_params_v1_t, params));
918 	}
919 
920 	/* if scan request is not empty parse scan request paramters */
921 	list = kzalloc(sizeof(u32)*(MAX_CTRL_CHANSPECS + 1), GFP_KERNEL);
922 	if (list == NULL) {
923 		ESCAN_ERROR(dev->name, "kzalloc failed\n");
924 		err = -ENOMEM;
925 		goto exit;
926 	}
927 
928 	if (scan_info->channels.count) {
929 		memcpy(list, &scan_info->channels, sizeof(wl_channel_list_t));
930 	} else {
931 		err = wl_construct_ctl_chanspec_list(dev, list);
932 		if (err != 0) {
933 			ESCAN_ERROR(dev->name, "get channels failed with %d\n", err);
934 			goto exit;
935 		}
936 	}
937 
938 	n_channels = list->count;
939 	/* Allocate space for populating ssids in wl_escan_params_v1_t struct */
940 	if (list->count % 2)
941 		/* If n_channels is odd, add a padd of u16 */
942 		params_size += sizeof(u16) * (n_channels + 1);
943 	else
944 		params_size += sizeof(u16) * n_channels;
945 	if (scan_info->ssid.SSID_len) {
946 		params_size += sizeof(struct wlc_ssid) * 2;
947 	}
948 
949 	params = kzalloc(params_size, GFP_KERNEL);
950 	if (params == NULL) {
951 		ESCAN_ERROR(dev->name, "kzalloc failed\n");
952 		err = -ENOMEM;
953 		goto exit;
954 	}
955 
956 	if (escan->scan_params_v2) {
957 		eparams_v2 = (wl_escan_params_v2_t *)params;
958 		scan_params = (u8 *)&eparams_v2->params;
959 		eparams_v2->version = htod32(ESCAN_REQ_VERSION_V2);
960 		eparams_v2->action =  htod16(WL_SCAN_ACTION_START);
961 		wl_escan_set_sync_id(eparams_v2->sync_id);
962 	} else {
963 		eparams = (wl_escan_params_v1_t *)params;
964 		scan_params = (u8 *)&eparams->params;
965 		eparams->version = htod32(ESCAN_REQ_VERSION_V1);
966 		eparams->action =  htod16(WL_SCAN_ACTION_START);
967 		wl_escan_set_sync_id(eparams->sync_id);
968 	}
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 (list)
990 		kfree(list);
991 	if (unlikely(err)) {
992 		wl_escan_reset(escan);
993 	}
994 exit2:
995 	mutex_unlock(&escan->usr_sync);
996 	return err;
997 }
998 
999 #if defined(WL_WIRELESS_EXT)
1000 static int
rssi_to_qual(int rssi)1001 rssi_to_qual(int rssi)
1002 {
1003 	if (rssi <= WL_IW_RSSI_NO_SIGNAL)
1004 		return 0;
1005 	else if (rssi <= WL_IW_RSSI_VERY_LOW)
1006 		return 1;
1007 	else if (rssi <= WL_IW_RSSI_LOW)
1008 		return 2;
1009 	else if (rssi <= WL_IW_RSSI_GOOD)
1010 		return 3;
1011 	else if (rssi <= WL_IW_RSSI_VERY_GOOD)
1012 		return 4;
1013 	else
1014 		return 5;
1015 }
1016 
1017 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_v109_t * bi,int * len,int max_size)1018 wl_escan_merge_scan_results(struct net_device *dev, struct wl_escan_info *escan,
1019 	struct iw_request_info *info, char *extra, wl_bss_info_v109_t *bi, int *len, int max_size)
1020 {
1021 	s32 err = BCME_OK;
1022 	struct iw_event	iwe;
1023 	int j;
1024 	char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
1025 	int16 rssi;
1026 	int channel;
1027 	chanspec_t chanspec;
1028 
1029 	/* overflow check cover fields before wpa IEs */
1030 	if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN +
1031 		IW_EV_QUAL_LEN >= end) {
1032 		err = -E2BIG;
1033 		goto exit;
1034 	}
1035 
1036 #if defined(RSSIAVG)
1037 	rssi = wl_get_avg_rssi(&escan->g_rssi_cache_ctrl, &bi->BSSID);
1038 	if (rssi == RSSI_MINVAL)
1039 		rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1040 #else
1041 	// terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
1042 	rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1043 #endif
1044 	chanspec = wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec);
1045 	channel = wf_chspec_ctlchan(chanspec);
1046 	ESCAN_SCAN(dev->name, "BSSID %pM, channel %3d(%3d %sMHz), rssi %3d, SSID \"%s\"\n",
1047 		&bi->BSSID, channel, CHSPEC_CHANNEL(chanspec),
1048 		CHSPEC_IS20(chanspec)?"20":
1049 		CHSPEC_IS40(chanspec)?"40":
1050 		CHSPEC_IS80(chanspec)?"80":"160",
1051 		rssi, bi->SSID);
1052 
1053 	/* First entry must be the BSSID */
1054 	iwe.cmd = SIOCGIWAP;
1055 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1056 	memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
1057 	event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
1058 
1059 	/* SSID */
1060 	iwe.u.data.length = dtoh32(bi->SSID_len);
1061 	iwe.cmd = SIOCGIWESSID;
1062 	iwe.u.data.flags = 1;
1063 	event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
1064 
1065 	/* Mode */
1066 	if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
1067 		iwe.cmd = SIOCGIWMODE;
1068 		if (dtoh16(bi->capability) & DOT11_CAP_ESS)
1069 			iwe.u.mode = IW_MODE_INFRA;
1070 		else
1071 			iwe.u.mode = IW_MODE_ADHOC;
1072 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
1073 	}
1074 
1075 	/* Channel */
1076 	iwe.cmd = SIOCGIWFREQ;
1077 #if 1
1078 	iwe.u.freq.m = wf_channel2mhz(channel, channel <= CH_MAX_2G_CHANNEL ?
1079 			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
1080 #else
1081 	iwe.u.freq.m = wf_channel2mhz(bi->n_cap ?
1082 			bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec),
1083 			CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
1084 			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
1085 #endif
1086 	iwe.u.freq.e = 6;
1087 	event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
1088 
1089 	/* Channel quality */
1090 	iwe.cmd = IWEVQUAL;
1091 	iwe.u.qual.qual = rssi_to_qual(rssi);
1092 	iwe.u.qual.level = 0x100 + rssi;
1093 	iwe.u.qual.noise = 0x100 + bi->phy_noise;
1094 	event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
1095 
1096 	wl_iw_handle_scanresults_ies(&event, end, info, bi);
1097 
1098 	/* Encryption */
1099 	iwe.cmd = SIOCGIWENCODE;
1100 	if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
1101 		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1102 	else
1103 		iwe.u.data.flags = IW_ENCODE_DISABLED;
1104 	iwe.u.data.length = 0;
1105 	event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
1106 
1107 	/* Rates */
1108 	if (bi->rateset.count <= sizeof(bi->rateset.rates)) {
1109 		if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end) {
1110 			err = -E2BIG;
1111 			goto exit;
1112 		}
1113 		value = event + IW_EV_LCP_LEN;
1114 		iwe.cmd = SIOCGIWRATE;
1115 		/* Those two flags are ignored... */
1116 		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
1117 		for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
1118 			iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
1119 			value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
1120 				IW_EV_PARAM_LEN);
1121 		}
1122 		event = value;
1123 	}
1124 	*len = event - extra;
1125 	if (*len < 0)
1126 		ESCAN_ERROR(dev->name, "==> Wrong size\n");
1127 
1128 exit:
1129 	return err;
1130 }
1131 
1132 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)1133 wl_escan_merge_scan_list(struct net_device *dev, u8 *cur_bssid,
1134 	struct iw_request_info *info, struct iw_point *dwrq, char *extra,
1135 	int *len_ret, int *bss_cnt)
1136 {
1137 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1138 	struct wl_escan_info *escan = dhdp->escan;
1139 	s32 err = BCME_OK;
1140 	int i = 0, cnt = 0;
1141 	int len_prep = 0;
1142 	wl_bss_info_v109_t *bi = NULL;
1143 	wl_scan_results_v109_t *bss_list;
1144 	__u16 buflen_from_user = dwrq->length;
1145 
1146 	bss_list = escan->bss_list;
1147 	bi = next_bss(bss_list, bi);
1148 	for_each_bss_wext(bss_list, bi, i)
1149 	{
1150 		if (!memcmp(&bi->BSSID, cur_bssid, ETHER_ADDR_LEN)) {
1151 			ESCAN_SCAN(dev->name, "skip connected AP %pM\n", cur_bssid);
1152 			continue;
1153 		}
1154 		len_prep = 0;
1155 		err = wl_escan_merge_scan_results(dev, escan, info, extra+*len_ret, bi,
1156 			&len_prep, buflen_from_user-*len_ret);
1157 		*len_ret += len_prep;
1158 		if (err)
1159 			goto exit;
1160 		cnt++;
1161 	}
1162 	*bss_cnt = cnt;
1163 
1164 exit:
1165 	return err;
1166 }
1167 
1168 #if defined(BSSCACHE)
1169 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)1170 wl_escan_merge_cache_list(struct net_device *dev, u8 *cur_bssid,
1171 	struct iw_request_info *info, struct iw_point *dwrq, char *extra,
1172 	int *len_ret, int *bss_cnt)
1173 {
1174 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1175 	struct wl_escan_info *escan = dhdp->escan;
1176 	s32 err = BCME_OK;
1177 	int i = 0, cnt = 0;
1178 	int len_prep = 0;
1179 	wl_bss_info_v109_t *bi = NULL;
1180 	wl_scan_results_v109_t *bss_list;
1181 	__u16 buflen_from_user = dwrq->length;
1182 	wl_bss_cache_t *node;
1183 
1184 	bss_list = &escan->g_bss_cache_ctrl.m_cache_head->results;
1185 	node = escan->g_bss_cache_ctrl.m_cache_head;
1186 	for (i=0; node && i<IW_MAX_AP; i++)
1187 	{
1188 		bi = node->results.bss_info;
1189 		if (node->dirty > 1) {
1190 			if (!memcmp(&bi->BSSID, cur_bssid, ETHER_ADDR_LEN)) {
1191 				ESCAN_SCAN(dev->name, "skip connected AP %pM\n", cur_bssid);
1192 				node = node->next;
1193 				continue;
1194 			}
1195 			len_prep = 0;
1196 			err = wl_escan_merge_scan_results(dev, escan, info, extra+*len_ret, bi,
1197 				&len_prep, buflen_from_user-*len_ret);
1198 			*len_ret += len_prep;
1199 			if (err)
1200 				goto exit;
1201 			cnt++;
1202 		}
1203 		node = node->next;
1204 	}
1205 	*bss_cnt = cnt;
1206 
1207 exit:
1208 	return err;
1209 }
1210 #endif
1211 
1212 int
wl_escan_get_scan(struct net_device * dev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1213 wl_escan_get_scan(struct net_device *dev,
1214 	struct iw_request_info *info, struct iw_point *dwrq, char *extra)
1215 {
1216 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1217 	struct wl_escan_info *escan = dhdp->escan;
1218 	s32 err = BCME_OK;
1219 	int scan_cnt = 0;
1220 #if defined(BSSCACHE)
1221 	int cache_cnt = 0;
1222 #endif
1223 	int len_prep = 0, len_ret = 0;
1224 	wl_bss_info_v109_t *bi = NULL;
1225 	__u16 buflen_from_user = dwrq->length;
1226 	char *buf = NULL;
1227 	struct ether_addr cur_bssid;
1228 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
1229 
1230 	if (!extra) {
1231 		ESCAN_TRACE(dev->name, "extra is null\n");
1232 		return -EINVAL;
1233 	}
1234 
1235 	mutex_lock(&escan->usr_sync);
1236 
1237 	/* Check for scan in progress */
1238 	if (escan->escan_state == ESCAN_STATE_SCANING) {
1239 		ESCAN_DBG(dev->name, "SIOCGIWSCAN GET still scanning\n");
1240 		err = -EAGAIN;
1241 		goto exit;
1242 	}
1243 	if (!escan->bss_list) {
1244 		ESCAN_ERROR(dev->name, "scan not ready\n");
1245 		err = -EAGAIN;
1246 		goto exit;
1247 	}
1248 	if (dev != escan->dev) {
1249 		ESCAN_ERROR(dev->name, "not my scan from %s\n", escan->dev->name);
1250 		err = -EINVAL;
1251 		goto exit;
1252 	}
1253 
1254 	ESCAN_SCAN(dev->name, "SIOCGIWSCAN, len=%d\n", dwrq->length);
1255 
1256 	wldev_iovar_getbuf(dev, "cur_etheraddr", NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, NULL);
1257 	err = wldev_ioctl(dev, WLC_GET_BSSID, &cur_bssid, sizeof(cur_bssid), false);
1258 	if (err != BCME_NOTASSOCIATED &&
1259 			memcmp(&ether_null, &cur_bssid, ETHER_ADDR_LEN) &&
1260 			memcmp(ioctl_buf, &cur_bssid, ETHER_ADDR_LEN)) {
1261 		// merge current connected bss
1262 		buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_ATOMIC);
1263 		if (!buf) {
1264 			ESCAN_ERROR(dev->name, "buffer alloc failed.\n");
1265 			err = BCME_NOMEM;
1266 			goto exit;
1267 		}
1268 		*(u32 *)buf = htod32(WL_EXTRA_BUF_MAX);
1269 		err = wldev_ioctl(dev, WLC_GET_BSS_INFO, buf, WL_EXTRA_BUF_MAX, false);
1270 		if (unlikely(err)) {
1271 			ESCAN_ERROR(dev->name, "Could not get bss info %d\n", err);
1272 			goto exit;
1273 		}
1274 		bi = (struct wl_bss_info *)(buf + 4);
1275 		len_prep = 0;
1276 		err = wl_escan_merge_scan_results(dev, escan, info, extra+len_ret, bi,
1277 			&len_prep, buflen_from_user-len_ret);
1278 		len_ret += len_prep;
1279 		if (err)
1280 			goto exit;
1281 		bi = NULL;
1282 	}
1283 
1284 	err = wl_escan_merge_scan_list(dev, (u8 *)&cur_bssid, info, dwrq, extra,
1285 		&len_ret, &scan_cnt);
1286 	if (err)
1287 		goto exit;
1288 #if defined(BSSCACHE)
1289 	err = wl_escan_merge_cache_list(dev, (u8 *)&cur_bssid, info, dwrq, extra,
1290 		&len_ret, &cache_cnt);
1291 	if (err)
1292 		goto exit;
1293 #endif
1294 
1295 	if ((len_ret + WE_ADD_EVENT_FIX) < dwrq->length)
1296 		dwrq->length = len_ret;
1297 
1298 	dwrq->flags = 0;	/* todo */
1299 	ESCAN_SCAN(dev->name, "scanned AP count (%d)\n", scan_cnt);
1300 #if defined(BSSCACHE)
1301 	ESCAN_SCAN(dev->name, "cached AP count (%d)\n", cache_cnt);
1302 #endif
1303 exit:
1304 	kfree(buf);
1305 	dwrq->length = len_ret;
1306 	mutex_unlock(&escan->usr_sync);
1307 	return err;
1308 }
1309 #endif /* WL_WIRELESS_EXT */
1310 
1311 #ifdef WLMESH
1312 bool
wl_escan_meshid_ie(u8 * parse,u32 len,wlc_ssid_t * mesh_id)1313 wl_escan_meshid_ie(u8 *parse, u32 len, wlc_ssid_t *mesh_id)
1314 {
1315 	bcm_tlv_t *ie;
1316 
1317 	if((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_MESH_ID)) != NULL) {
1318 		mesh_id->SSID_len = ie->len;
1319 		if (ie->len) {
1320 			strncpy(mesh_id->SSID, ie->data, ie->len);
1321 		}
1322 		return TRUE;
1323 	}
1324 	return FALSE;
1325 }
1326 
1327 bool
wl_escan_rsn_ie(u8 * parse,u32 len)1328 wl_escan_rsn_ie(u8 *parse, u32 len)
1329 {
1330 	if (bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_RSN_ID)) {
1331 		return TRUE;
1332 	}
1333 	return FALSE;
1334 }
1335 
1336 bool
wl_escan_mesh_info_ie(struct net_device * dev,u8 * parse,u32 len,struct wl_mesh_params * mesh_info)1337 wl_escan_mesh_info_ie(struct net_device *dev, u8 *parse, u32 len,
1338 	struct wl_mesh_params *mesh_info)
1339 {
1340 	bcm_tlv_t *ie;
1341 	uchar mesh_oui[]={0x00, 0x22, 0xf4};
1342 	int totl_len;
1343 	uint8 *pie;
1344 	uint max_len;
1345 	bool found = FALSE;
1346 
1347 	memset(mesh_info, 0, sizeof(struct wl_mesh_params));
1348 	if((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID)) != NULL) {
1349 		totl_len = ie->len;
1350 		if (!memcmp(ie->data, &mesh_oui, sizeof(mesh_oui))) {
1351 			pie = ie->data + sizeof(mesh_oui);
1352 			ie = (bcm_tlv_t *)pie;
1353 			totl_len -= sizeof(mesh_oui);
1354 			while (totl_len > 2 && ie->len) {
1355 				if (ie->id == MESH_INFO_MASTER_BSSID && ie->len == ETHER_ADDR_LEN) {
1356 					memcpy(&mesh_info->master_bssid, ie->data, ETHER_ADDR_LEN);
1357 				} else if (ie->id == MESH_INFO_MASTER_CHANNEL) {
1358 					mesh_info->master_channel = ie->data[0];
1359 					found = TRUE;
1360 				} else if (ie->id == MESH_INFO_HOP_CNT) {
1361 					mesh_info->hop_cnt = ie->data[0];
1362 				} else if (ie->id == MESH_INFO_PEER_BSSID) {
1363 					max_len = min(MAX_HOP_LIST*ETHER_ADDR_LEN, (int)ie->len);
1364 					memcpy(mesh_info->peer_bssid, ie->data, max_len);
1365 				}
1366 				totl_len -= (ie->len + 2);
1367 				pie = ie->data + ie->len;
1368 				ie = (bcm_tlv_t *)pie;
1369 			}
1370 		}
1371 	}
1372 
1373 	return found;
1374 }
1375 
1376 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)1377 wl_escan_mesh_info(struct net_device *dev, struct wl_escan_info *escan,
1378 	struct ether_addr *peer_bssid, struct wl_mesh_params *mesh_info)
1379 {
1380 	int i = 0;
1381 	wl_bss_info_v109_t *bi = NULL;
1382 	wl_scan_results_v109_t *bss_list;
1383 	int16 bi_rssi, bi_chan;
1384 	wlc_ssid_t bi_meshid;
1385 	bool is_mesh_peer = FALSE, found = FALSE;
1386 	struct wl_mesh_params peer_mesh_info;
1387 
1388 	mutex_lock(&escan->usr_sync);
1389 
1390 	/* Check for scan in progress */
1391 	if (escan->escan_state == ESCAN_STATE_SCANING) {
1392 		ESCAN_ERROR(dev->name, "SIOCGIWSCAN GET still scanning\n");
1393 		goto exit;
1394 	}
1395 	if (!escan->bss_list) {
1396 		ESCAN_ERROR(dev->name, "scan not ready\n");
1397 		goto exit;
1398 	}
1399 	if (dev != escan->dev) {
1400 		ESCAN_ERROR(dev->name, "not my scan from %s\n", escan->dev->name);
1401 		goto exit;
1402 	}
1403 
1404 	bss_list = escan->bss_list;
1405 	bi = next_bss(bss_list, bi);
1406 	ESCAN_SCAN(dev->name, "scanned AP/Mesh count (%d)\n", bss_list->count);
1407 	for_each_bss(bss_list, bi, i)
1408 	{
1409 		memset(&bi_meshid, 0, sizeof(bi_meshid));
1410 		is_mesh_peer = FALSE;
1411 		bi_chan = wf_chspec_ctlchan(
1412 			wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec));
1413 		bi_rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1414 		is_mesh_peer = wl_escan_meshid_ie(((u8*)bi)+bi->ie_offset,
1415 			bi->ie_length, &bi_meshid);
1416 		if (!(bi->capability & (DOT11_CAP_ESS|DOT11_CAP_IBSS)) && is_mesh_peer) {
1417 			bool bi_sae = FALSE, bss_found = FALSE, prefer = FALSE;
1418 			if (!memcmp(peer_bssid, &bi->BSSID, ETHER_ADDR_LEN)) {
1419 				bi_sae = wl_escan_rsn_ie(((u8*)bi)+bi->ie_offset, bi->ie_length);
1420 				bss_found = wl_escan_mesh_info_ie(dev, ((u8*)bi)+bi->ie_offset,
1421 					bi->ie_length, &peer_mesh_info);
1422 				if (bss_found) {
1423 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
1424 						ETHER_ADDR_LEN);
1425 					mesh_info->master_channel = peer_mesh_info.master_channel;
1426 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt;
1427 					memcpy(mesh_info->peer_bssid, peer_mesh_info.peer_bssid,
1428 						sizeof(peer_mesh_info.peer_bssid));
1429 					prefer = TRUE;
1430 					found = TRUE;
1431 				}
1432 			}
1433 			ESCAN_SCAN(dev->name,
1434 				"%s[Mesh] BSSID=%pM, channel=%d, RSSI=%d, sec=%s, "
1435 				"mbssid=%pM, mchannel=%d, hop=%d, pbssid=%pM, MeshID=\"%s\"\n",
1436 				prefer?"*":" ", &bi->BSSID, bi_chan, bi_rssi, bi_sae?"SAE":"OPEN",
1437 				&peer_mesh_info.master_bssid, peer_mesh_info.master_channel,
1438 				peer_mesh_info.hop_cnt, &peer_mesh_info.peer_bssid, bi_meshid.SSID);
1439 		}
1440 	}
1441 
1442 exit:
1443 	mutex_unlock(&escan->usr_sync);
1444 	return found;
1445 }
1446 
1447 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)1448 wl_escan_mesh_peer(struct net_device *dev, struct wl_escan_info *escan,
1449 	wlc_ssid_t *cur_ssid, uint16 cur_chan, bool sae,
1450 	struct wl_mesh_params *mesh_info)
1451 {
1452 	int i = 0;
1453 	wl_bss_info_v109_t *bi = NULL;
1454 	wl_scan_results_v109_t *bss_list;
1455 	int16 bi_rssi, bi_chan, max_rssi = -100;
1456 	uint min_hop_cnt = 255;
1457 	wlc_ssid_t bi_meshid;
1458 	bool is_mesh_peer = FALSE, chan_matched = FALSE, found = FALSE;
1459 	struct wl_mesh_params peer_mesh_info;
1460 
1461 	mutex_lock(&escan->usr_sync);
1462 
1463 	/* Check for scan in progress */
1464 	if (escan->escan_state == ESCAN_STATE_SCANING) {
1465 		ESCAN_ERROR(dev->name, "SIOCGIWSCAN GET still scanning\n");
1466 		goto exit;
1467 	}
1468 	if (!escan->bss_list) {
1469 		ESCAN_ERROR(dev->name, "scan not ready\n");
1470 		goto exit;
1471 	}
1472 	if (dev != escan->dev) {
1473 		ESCAN_ERROR(dev->name, "not my scan from %s\n", escan->dev->name);
1474 		goto exit;
1475 	}
1476 
1477 	bss_list = escan->bss_list;
1478 	bi = next_bss(bss_list, bi);
1479 	ESCAN_SCAN(dev->name, "scanned AP/Mesh count (%d)\n", bss_list->count);
1480 	for_each_bss(bss_list, bi, i)
1481 	{
1482 		memset(&bi_meshid, 0, sizeof(bi_meshid));
1483 		is_mesh_peer = FALSE;
1484 		bi_chan = wf_chspec_ctlchan(
1485 			wl_chspec_driver_to_host(escan->ioctl_ver, bi->chanspec));
1486 		bi_rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
1487 		is_mesh_peer = wl_escan_meshid_ie(((u8*)bi)+bi->ie_offset,
1488 			bi->ie_length, &bi_meshid);
1489 		if (!(bi->capability & (DOT11_CAP_ESS|DOT11_CAP_IBSS)) && is_mesh_peer) {
1490 			bool meshid_matched = FALSE, sec_matched = FALSE, bi_sae = FALSE,
1491 				bss_found = FALSE, prefer = FALSE;
1492 
1493 			if (cur_ssid->SSID_len && cur_ssid->SSID_len == bi_meshid.SSID_len &&
1494 					!memcmp(cur_ssid->SSID, bi_meshid.SSID, bi_meshid.SSID_len))
1495 				meshid_matched = TRUE;
1496 
1497 			bi_sae = wl_escan_rsn_ie(((u8*)bi)+bi->ie_offset, bi->ie_length);
1498 			if (bi_sae == sae)
1499 				sec_matched = TRUE;
1500 
1501 			bss_found = wl_escan_mesh_info_ie(dev, ((u8*)bi)+bi->ie_offset, bi->ie_length,
1502 				&peer_mesh_info);
1503 			if (meshid_matched && sec_matched && bss_found &&
1504 					(cur_chan == bi_chan)) {
1505 				if (peer_mesh_info.hop_cnt < min_hop_cnt) {
1506 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
1507 						ETHER_ADDR_LEN);
1508 					mesh_info->master_channel = peer_mesh_info.master_channel;
1509 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt;
1510 					memcpy(mesh_info->peer_bssid, peer_mesh_info.peer_bssid,
1511 						sizeof(peer_mesh_info.peer_bssid));
1512 					min_hop_cnt = peer_mesh_info.hop_cnt;
1513 					prefer = TRUE;
1514 					chan_matched = TRUE;
1515 					found = TRUE;
1516 				}
1517 			}
1518 			else if (meshid_matched && sec_matched && bss_found &&
1519 					(cur_chan != bi_chan) && !chan_matched) {
1520 				if (bi_rssi > max_rssi) {
1521 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
1522 						ETHER_ADDR_LEN);
1523 					mesh_info->master_channel = peer_mesh_info.master_channel;
1524 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt;
1525 					memcpy(mesh_info->peer_bssid, peer_mesh_info.peer_bssid,
1526 						sizeof(peer_mesh_info.peer_bssid));
1527 					max_rssi = bi_rssi;
1528 					prefer = TRUE;
1529 					found = TRUE;
1530 				}
1531 			}
1532 
1533 			ESCAN_SCAN(dev->name,
1534 				"%s[Mesh] BSSID=%pM, channel=%d, RSSI=%d, sec=%s, "
1535 				"mbssid=%pM, mchannel=%d, hop=%d, pbssid=%pM, MeshID=\"%s\"\n",
1536 				prefer?"*":" ", &bi->BSSID, bi_chan, bi_rssi, bi_sae?"SAE":"OPEN",
1537 				&peer_mesh_info.master_bssid, peer_mesh_info.master_channel,
1538 				peer_mesh_info.hop_cnt, &peer_mesh_info.peer_bssid, bi_meshid.SSID);
1539 		} else {
1540 			ESCAN_SCAN(dev->name,
1541 				"[AP] BSSID=%pM, channel=%d, RSSI=%d, SSID=\"%s\"\n",
1542 				&bi->BSSID, bi_chan, bi_rssi, bi->SSID);
1543 		}
1544 	}
1545 
1546 exit:
1547 	mutex_unlock(&escan->usr_sync);
1548 	return found;
1549 }
1550 #endif /* WLMESH */
1551 
1552 static void
wl_escan_deinit(struct net_device * dev,struct wl_escan_info * escan)1553 wl_escan_deinit(struct net_device *dev, struct wl_escan_info *escan)
1554 {
1555 	ESCAN_TRACE(dev->name, "Enter\n");
1556 
1557 	del_timer_sync(&escan->scan_timeout);
1558 	escan->escan_state = ESCAN_STATE_DOWN;
1559 
1560 #if defined(RSSIAVG)
1561 	wl_free_rssi_cache(&escan->g_rssi_cache_ctrl);
1562 #endif
1563 #if defined(BSSCACHE)
1564 	wl_free_bss_cache(&escan->g_bss_cache_ctrl);
1565 #endif
1566 }
1567 
1568 static s32
wl_escan_init(struct net_device * dev,struct wl_escan_info * escan)1569 wl_escan_init(struct net_device *dev, struct wl_escan_info *escan)
1570 {
1571 	ESCAN_TRACE(dev->name, "Enter\n");
1572 
1573 	/* Init scan_timeout timer */
1574 	init_timer_compat(&escan->scan_timeout, wl_escan_timeout, escan);
1575 	escan->escan_state = ESCAN_STATE_IDLE;
1576 
1577 	return 0;
1578 }
1579 
1580 void
wl_escan_down(struct net_device * dev)1581 wl_escan_down(struct net_device *dev)
1582 {
1583 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1584 	struct wl_escan_info *escan = dhdp->escan;
1585 
1586 	ESCAN_TRACE(dev->name, "Enter\n");
1587 	if (!escan) {
1588 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1589 		return;
1590 	}
1591 
1592 	escan->scan_params_v2 = false;
1593 
1594 	wl_escan_deinit(dev, escan);
1595 }
1596 
1597 int
wl_escan_up(struct net_device * dev)1598 wl_escan_up(struct net_device *dev)
1599 {
1600 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1601 	struct wl_escan_info *escan = dhdp->escan;
1602 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
1603 	s32 val = 0;
1604 	int ret = -1;
1605 
1606 	ESCAN_TRACE(dev->name, "Enter\n");
1607 	if (!escan) {
1608 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1609 		return ret;
1610 	}
1611 
1612 	ret = wl_escan_init(dev, escan);
1613 	if (ret) {
1614 		ESCAN_ERROR(dev->name, "wl_escan_init ret %d\n", ret);
1615 		return ret;
1616 	}
1617 
1618 	if (!escan->ioctl_ver) {
1619 		val = 1;
1620 		if ((ret = wldev_ioctl(dev, WLC_GET_VERSION, &val, sizeof(int), false) < 0)) {
1621 			ESCAN_ERROR(dev->name, "WLC_GET_VERSION failed, ret=%d\n", ret);
1622 			return ret;
1623 		}
1624 		val = dtoh32(val);
1625 		if (val != WLC_IOCTL_VERSION && val != 1) {
1626 			ESCAN_ERROR(dev->name,
1627 				"Version mismatch, please upgrade. Got %d, expected %d or 1\n",
1628 				val, WLC_IOCTL_VERSION);
1629 			return ret;
1630 		}
1631 		escan->ioctl_ver = val;
1632 	}
1633 
1634 	if ((ret = wldev_iovar_getbuf(dev, "scan_ver", NULL, 0,
1635 		ioctl_buf, sizeof(ioctl_buf), NULL)) == BCME_OK) {
1636 		ESCAN_TRACE(dev->name, "scan_params v2\n");
1637 		/* use scan_params ver2 */
1638 		escan->scan_params_v2 = true;
1639 	} else {
1640 		if (ret == BCME_UNSUPPORTED) {
1641 			ESCAN_TRACE(dev->name, "scan_ver, UNSUPPORTED\n");
1642 			ret = BCME_OK;
1643 		} else {
1644 			ESCAN_ERROR(dev->name, "get scan_ver err(%d)\n", ret);
1645 		}
1646 	}
1647 
1648 	return 0;
1649 }
1650 
1651 int
wl_escan_event_dettach(struct net_device * dev,int ifidx)1652 wl_escan_event_dettach(struct net_device *dev, int ifidx)
1653 {
1654 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1655 	struct wl_escan_info *escan = dhdp->escan;
1656 	int ret = -1;
1657 
1658 	if (!escan) {
1659 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1660 		return ret;
1661 	}
1662 
1663 	if (ifidx < DHD_MAX_IFS) {
1664 		wl_ext_event_deregister(dev, dhdp, WLC_E_ESCAN_RESULT, wl_escan_ext_handler);
1665 	}
1666 
1667 	return 0;
1668 }
1669 
1670 int
wl_escan_event_attach(struct net_device * dev,int ifidx)1671 wl_escan_event_attach(struct net_device *dev, int ifidx)
1672 {
1673 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1674 	struct wl_escan_info *escan = dhdp->escan;
1675 	int ret = -1;
1676 
1677 	if (!escan) {
1678 		ESCAN_ERROR(dev->name, "escan is NULL\n");
1679 		return ret;
1680 	}
1681 
1682 	if (ifidx < DHD_MAX_IFS) {
1683 		ret = wl_ext_event_register(dev, dhdp, WLC_E_ESCAN_RESULT, wl_escan_ext_handler,
1684 			escan, PRIO_EVENT_ESCAN);
1685 		if (ret) {
1686 			ESCAN_ERROR(dev->name, "wl_ext_event_register err %d\n", ret);
1687 		}
1688 	}
1689 
1690 	return ret;
1691 }
1692 
1693 void
wl_escan_detach(struct net_device * dev)1694 wl_escan_detach(struct net_device *dev)
1695 {
1696 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1697 	struct wl_escan_info *escan = dhdp->escan;
1698 
1699 	ESCAN_TRACE(dev->name, "Enter\n");
1700 
1701 	if (!escan)
1702 		return;
1703 
1704 	wl_escan_deinit(dev, escan);
1705 	if (escan->escan_ioctl_buf) {
1706 		kfree(escan->escan_ioctl_buf);
1707 		escan->escan_ioctl_buf = NULL;
1708 	}
1709 	wl_ext_event_deregister(dev, dhdp, WLC_E_ESCAN_RESULT, wl_escan_ext_handler);
1710 
1711 	DHD_OS_PREFREE(dhdp, escan, sizeof(struct wl_escan_info));
1712 	dhdp->escan = NULL;
1713 }
1714 
1715 int
wl_escan_attach(struct net_device * dev)1716 wl_escan_attach(struct net_device *dev)
1717 {
1718 	struct dhd_pub *dhdp = dhd_get_pub(dev);
1719 	struct wl_escan_info *escan = NULL;
1720 	int ret = 0;
1721 
1722 	ESCAN_TRACE(dev->name, "Enter\n");
1723 
1724 	escan = (struct wl_escan_info *)DHD_OS_PREALLOC(dhdp,
1725 		DHD_PREALLOC_WL_ESCAN, sizeof(struct wl_escan_info));
1726 	if (!escan)
1727 		return -ENOMEM;
1728 	memset(escan, 0, sizeof(struct wl_escan_info));
1729 
1730 	dhdp->escan = escan;
1731 
1732 	/* we only care about main interface so save a global here */
1733 	escan->pub = dhdp;
1734 	escan->escan_state = ESCAN_STATE_DOWN;
1735 
1736 	escan->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
1737 	if (unlikely(!escan->escan_ioctl_buf)) {
1738 		ESCAN_ERROR(dev->name, "Ioctl buf alloc failed\n");
1739 		ret = -ENOMEM;
1740 		goto exit;
1741 	}
1742 	ret = wl_escan_init(dev, escan);
1743 	if (ret) {
1744 		ESCAN_ERROR(dev->name, "wl_escan_init err %d\n", ret);
1745 		goto exit;
1746 	}
1747 	mutex_init(&escan->usr_sync);
1748 
1749 	return 0;
1750 
1751 exit:
1752 	wl_escan_detach(dev);
1753 	return ret;
1754 }
1755 
1756 #endif /* WL_ESCAN */
1757