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(¶ms->bssid, ðer_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, ¶ms_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(¶ms_v2->bssid, ðer_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(¶ms_v2->ssid, sizeof(wlc_ssid_t));
742 chan_list = params_v2->channel_list;
743 } else {
744 /* scan params ver 1 */
745 memcpy(¶ms->bssid, ðer_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(¶ms->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(ðer_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