• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params->bssid, &ether_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, &params_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(&params->bssid, &ether_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, &params->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(&ether_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