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