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