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