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