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