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