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