wireless: fix all kind of warnings
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / drivers / net / wireless / bcmdhd4361 / wl_bam.c
CommitLineData
1cac41cb
MB
1/*
2 * Bad AP Manager for ADPS
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_bam.c 790523 2018-11-26 08:24:06Z $
28 */
29#include <bcmiov.h>
30#include <linux/time.h>
31#include <linux/list_sort.h>
32#include <wl_cfg80211.h>
33#include <wlioctl.h>
34#include <wldev_common.h>
35#include <wl_bam.h>
36
37static int
38wl_bad_ap_mngr_add_entry(wl_bad_ap_mngr_t *bad_ap_mngr, wl_bad_ap_info_t *bad_ap_info)
39{
40 unsigned long flags;
41 wl_bad_ap_info_entry_t *entry;
42
43 entry = MALLOCZ(bad_ap_mngr->osh, sizeof(*entry));
44 if (entry == NULL) {
45 WL_ERR(("%s: allocation for list failed\n", __FUNCTION__));
46 return BCME_NOMEM;
47 }
48
49 memcpy(&entry->bad_ap, bad_ap_info, sizeof(entry->bad_ap));
50 INIT_LIST_HEAD(&entry->list);
51 spin_lock_irqsave(&bad_ap_mngr->lock, flags);
52 list_add_tail(&entry->list, &bad_ap_mngr->list);
53 spin_unlock_irqrestore(&bad_ap_mngr->lock, flags);
54
55 bad_ap_mngr->num++;
56
57 return BCME_OK;
58}
59
60#if !defined(DHD_ADPS_BAM_EXPORT)
61#define WL_BAD_AP_INFO_FILE_PATH WL_BAM_FILE_PATH".bad_ap_list.info"
62#define WL_BAD_AP_MAX_BUF_SIZE 1024u
63
64/* Bad AP information data format
65 *
66 * Status and Reason: come from event
67 * Connection count: Increase connecting Bad AP
68 *
69 * BSSID,year-month-day hour:min:sec,Status,Reason,Connection count
70 * ex) XX:XX:XX:XX:XX:XX,1970-01-01 00:00:00,1,2,1
71 *
72 */
73#define WL_BAD_AP_INFO_FMT \
74 "%02x:%02x:%02x:%02x:%02x:%02x,%04ld-%02d-%02d %02d:%02d:%02d,%u,%u,%u\n"
75#define WL_BAD_AP_INFO_FMT_ITEM_CNT 15u
76
77static inline void
78wl_bad_ap_mngr_tm2ts(struct timespec *ts, const struct tm tm)
79{
80 ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
81 ts->tv_nsec = 0;
82}
83
84static int
85wl_bad_ap_mngr_timecmp(void *priv, struct list_head *a, struct list_head *b)
86{
87 int ret;
88
89 struct timespec ts1;
90 struct timespec ts2;
91
92 wl_bad_ap_info_entry_t *e1 = container_of(a, wl_bad_ap_info_entry_t, list);
93 wl_bad_ap_info_entry_t *e2 = container_of(b, wl_bad_ap_info_entry_t, list);
94
95 wl_bad_ap_mngr_tm2ts(&ts1, e1->bad_ap.tm);
96 wl_bad_ap_mngr_tm2ts(&ts2, e2->bad_ap.tm);
97
98 ret = timespec_compare((const struct timespec *)&ts1, (const struct timespec *)&ts2);
99
100 return ret;
101}
102
103static void
104wl_bad_ap_mngr_update(struct bcm_cfg80211 *cfg, wl_bad_ap_info_t *bad_ap_info)
105{
106 wl_bad_ap_info_entry_t *entry;
107 unsigned long flags;
108
109 if (list_empty(&cfg->bad_ap_mngr.list)) {
110 return;
111 }
112
113 spin_lock_irqsave(&cfg->bad_ap_mngr.lock, flags);
114 /* sort by timestamp */
115 list_sort(NULL, &cfg->bad_ap_mngr.list, wl_bad_ap_mngr_timecmp);
116
117 /* update entry with the latest bad ap information */
118 entry = list_first_entry(&cfg->bad_ap_mngr.list, wl_bad_ap_info_entry_t, list);
119 if (entry != NULL) {
120 memcpy(&entry->bad_ap, bad_ap_info, sizeof(entry->bad_ap));
121 }
122 spin_unlock_irqrestore(&cfg->bad_ap_mngr.lock, flags);
123}
124
125static inline int
126wl_bad_ap_mngr_fread_bad_ap_info(char *buf, int buf_len, wl_bad_ap_info_t *bad_ap)
127{
128 return snprintf(buf, buf_len, WL_BAD_AP_INFO_FMT,
129 bad_ap->bssid.octet[0], bad_ap->bssid.octet[1],
130 bad_ap->bssid.octet[2], bad_ap->bssid.octet[3],
131 bad_ap->bssid.octet[4], bad_ap->bssid.octet[5],
132 bad_ap->tm.tm_year + 1900, bad_ap->tm.tm_mon + 1, bad_ap->tm.tm_mday,
133 bad_ap->tm.tm_hour, bad_ap->tm.tm_min, bad_ap->tm.tm_sec,
134 bad_ap->status, bad_ap->reason, bad_ap->connect_count);
135}
136
137static int
138wl_bad_ap_mngr_fparse(struct bcm_cfg80211 *cfg, struct file *fp)
139{
140 int len;
141 int pos = 0;
142 char tmp[128];
143 int ret = BCME_ERROR;
144
145 wl_bad_ap_info_t bad_ap;
146 char *buf = NULL;
147
148 buf = MALLOCZ(cfg->osh, WL_BAD_AP_MAX_BUF_SIZE);
149 if (buf == NULL) {
150 WL_ERR(("%s: allocation for buf failed\n", __FUNCTION__));
151 return BCME_NOMEM;
152 }
153
154 ret = vfs_read(fp, buf, WL_BAD_AP_MAX_BUF_SIZE, &fp->f_pos);
155 if (ret < 0) {
156 WL_ERR(("%s: file read failed (%d)\n", __FUNCTION__, ret));
157 goto fail;
158 }
159
160 len = ret;
161 do {
162 ret = sscanf(&buf[pos], WL_BAD_AP_INFO_FMT,
163 (uint32 *)&bad_ap.bssid.octet[0], (uint32 *)&bad_ap.bssid.octet[1],
164 (uint32 *)&bad_ap.bssid.octet[2], (uint32 *)&bad_ap.bssid.octet[3],
165 (uint32 *)&bad_ap.bssid.octet[4], (uint32 *)&bad_ap.bssid.octet[5],
166 (long int *)&bad_ap.tm.tm_year, (uint32 *)&bad_ap.tm.tm_mon,
167 (uint32 *)&bad_ap.tm.tm_mday, (uint32 *)&bad_ap.tm.tm_hour,
168 (uint32 *)&bad_ap.tm.tm_min, (uint32 *)&bad_ap.tm.tm_sec,
169 (uint32 *)&bad_ap.status, (uint32 *)&bad_ap.reason,
170 (uint32 *)&bad_ap.connect_count);
171 if (ret != WL_BAD_AP_INFO_FMT_ITEM_CNT) {
172 WL_ERR(("%s: file parse failed(expected: %d actual: %d)\n",
173 __FUNCTION__, WL_BAD_AP_INFO_FMT_ITEM_CNT, ret));
174 ret = BCME_ERROR;
175 goto fail;
176 }
177
178 /* convert struct tm format */
179 bad_ap.tm.tm_year -= 1900;
180 bad_ap.tm.tm_mon -= 1;
181
182 ret = wl_bad_ap_mngr_add(&cfg->bad_ap_mngr, &bad_ap);
183 if (ret < 0) {
184 WL_ERR(("%s: bad ap add failed\n", __FUNCTION__));
185 goto fail;
186 }
187
188 ret = wl_bad_ap_mngr_fread_bad_ap_info(tmp, sizeof(tmp), &bad_ap);
189 if (ret < 0) {
190 WL_ERR(("%s: wl_bad_ap_mngr_fread_bad_ap_info failed (%d)\n",
191 __FUNCTION__, ret));
192 goto fail;
193 }
194
195 if (cfg->bad_ap_mngr.num >= WL_BAD_AP_MAX_ENTRY_NUM) {
196 break;
197 }
198
199 len -= ret;
200 pos += ret;
201 } while (len > 0);
202
203 ret = BCME_OK;
204
205fail:
206 if (buf) {
207 MFREE(cfg->osh, buf, WL_BAD_AP_MAX_BUF_SIZE);
208 }
209
210 return ret;
211}
212
213static int
214wl_bad_ap_mngr_fread(struct bcm_cfg80211 *cfg, const char *fname)
215{
216 int ret = BCME_ERROR;
217
218 mm_segment_t fs;
219 struct file *fp = NULL;
220
221 if (fname == NULL) {
222 WL_ERR(("%s: fname is NULL\n", __FUNCTION__));
223 return ret;
224 }
225 mutex_lock(&cfg->bad_ap_mngr.fs_lock);
226
227 fs = get_fs();
228 set_fs(KERNEL_DS);
229
230 fp = filp_open(fname, O_RDONLY, 0);
231 if (IS_ERR(fp)) {
232 fp = NULL;
233 WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret));
234 goto fail;
235 }
236
237 if ((ret = wl_bad_ap_mngr_fparse(cfg, fp)) < 0) {
238 goto fail;
239 }
240fail:
241 if (fp) {
242 filp_close(fp, NULL);
243 }
244 set_fs(fs);
245
246 mutex_unlock(&cfg->bad_ap_mngr.fs_lock);
247
248 return ret;
249}
250
251static int
252wl_bad_ap_mngr_fwrite(struct bcm_cfg80211 *cfg, const char *fname)
253{
254 int ret = BCME_ERROR;
255
256 mm_segment_t fs;
257 struct file *fp = NULL;
258
259 int len = 0;
260 char tmp[WL_BAD_AP_MAX_BUF_SIZE];
261 wl_bad_ap_info_t *bad_ap;
262 wl_bad_ap_info_entry_t *entry;
263
264 if (list_empty(&cfg->bad_ap_mngr.list)) {
265 return BCME_ERROR;
266 }
267
268 if (fname == NULL) {
269 return BCME_NOTFOUND;
270 }
271
272 mutex_lock(&cfg->bad_ap_mngr.fs_lock);
273
274 fs = get_fs();
275 set_fs(KERNEL_DS);
276
277 fp = filp_open(fname, O_CREAT | O_RDWR | O_TRUNC, 0666);
278 if (IS_ERR(fp)) {
279 ret = PTR_ERR(fp);
280 WL_ERR(("%s: file open failed(%d)\n", __FUNCTION__, ret));
281 fp = NULL;
282 goto fail;
283 }
284
285 memset(tmp, 0, sizeof(tmp));
286#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
287#pragma GCC diagnostic push
288#pragma GCC diagnostic ignored "-Wcast-qual"
289#endif // endif
290 list_for_each_entry(entry, &cfg->bad_ap_mngr.list, list) {
291 bad_ap = &entry->bad_ap;
292 ret = wl_bad_ap_mngr_fread_bad_ap_info(&tmp[len], sizeof(tmp) - len, bad_ap);
293 if (ret < 0) {
294 WL_ERR(("%s: snprintf failed(%d)\n", __FUNCTION__, ret));
295 goto fail;
296 }
297
298 len += ret;
299 }
300#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
301#pragma GCC diagnostic pop
302#endif // endif
303
304 ret = vfs_write(fp, tmp, len, &fp->f_pos);
305 if (ret < 0) {
306 WL_ERR(("%s: file write failed(%d)\n", __FUNCTION__, ret));
307 goto fail;
308 }
309 /* Sync file from filesystem to physical media */
310 ret = vfs_fsync(fp, 0);
311 if (ret < 0) {
312 WL_ERR(("%s: sync file failed(%d)\n", __FUNCTION__, ret));
313 goto fail;
314 }
315 ret = BCME_OK;
316fail:
317 if (fp) {
318 filp_close(fp, NULL);
319 }
320 set_fs(fs);
321 mutex_unlock(&cfg->bad_ap_mngr.fs_lock);
322
323 return ret;
324}
325#else
326extern wl_bad_ap_mngr_t *g_bad_ap_mngr;
327#endif /* DHD_ADPS_BAM_EXPORT */
328
329wl_bad_ap_info_entry_t*
330wl_bad_ap_mngr_find(wl_bad_ap_mngr_t *bad_ap_mngr, const struct ether_addr *bssid)
331{
332 wl_bad_ap_info_entry_t *entry;
333 unsigned long flags;
334
335#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
336#pragma GCC diagnostic push
337#pragma GCC diagnostic ignored "-Wcast-qual"
338#endif // endif
339 spin_lock_irqsave(&bad_ap_mngr->lock, flags);
340 list_for_each_entry(entry, &bad_ap_mngr->list, list) {
341 if (!memcmp(&entry->bad_ap.bssid.octet, bssid->octet, ETHER_ADDR_LEN)) {
342 spin_unlock_irqrestore(&bad_ap_mngr->lock, flags);
343 return entry;
344 }
345 }
346 spin_unlock_irqrestore(&bad_ap_mngr->lock, flags);
347#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
348#pragma GCC diagnostic pop
349#endif // endif
350 return NULL;
351}
352
353int
354wl_bad_ap_mngr_add(wl_bad_ap_mngr_t *bad_ap_mngr, wl_bad_ap_info_t *bad_ap_info)
355{
356 int ret;
357 wl_bad_ap_info_entry_t *entry;
358 unsigned long flags;
359
360 BCM_REFERENCE(entry);
361 BCM_REFERENCE(flags);
362
363#if !defined(DHD_ADPS_BAM_EXPORT)
364 ret = wl_bad_ap_mngr_add_entry(bad_ap_mngr, bad_ap_info);
365#else
366 if (bad_ap_mngr->num == WL_BAD_AP_MAX_ENTRY_NUM) {
367 /* Remove the oldest entry if entry list is full */
368 spin_lock_irqsave(&bad_ap_mngr->lock, flags);
369 list_del(bad_ap_mngr->list.next);
370 bad_ap_mngr->num--;
371 spin_unlock_irqrestore(&bad_ap_mngr->lock, flags);
372 }
373
374 /* delete duplicated entry to update it at tail to keep the odrer */
375 entry = wl_bad_ap_mngr_find(bad_ap_mngr, &bad_ap_info->bssid);
376 if (entry != NULL) {
377 spin_lock_irqsave(&bad_ap_mngr->lock, flags);
378 list_del(&entry->list);
379 bad_ap_mngr->num--;
380 spin_unlock_irqrestore(&bad_ap_mngr->lock, flags);
381 }
382
383 ret = wl_bad_ap_mngr_add_entry(bad_ap_mngr, bad_ap_info);
384 if (ret < 0) {
385 WL_ERR(("%s - fail to add bad ap data(%d)\n", __FUNCTION__, ret));
386 return ret;
387 }
388#endif /* DHD_ADPS_BAM_EXPORT */
389 return ret;
390}
391
392void
393wl_bad_ap_mngr_deinit(struct bcm_cfg80211 *cfg)
394{
395 wl_bad_ap_info_entry_t *entry;
396 unsigned long flags;
397
398#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
399#pragma GCC diagnostic push
400#pragma GCC diagnostic ignored "-Wcast-qual"
401#endif // endif
402 spin_lock_irqsave(&cfg->bad_ap_mngr.lock, flags);
403 while (!list_empty(&cfg->bad_ap_mngr.list)) {
404 entry = list_entry(cfg->bad_ap_mngr.list.next, wl_bad_ap_info_entry_t, list);
405 if (entry) {
406 list_del(&cfg->bad_ap_mngr.list);
407 MFREE(cfg->osh, entry, sizeof(*entry));
408 }
409 }
410 spin_unlock_irqrestore(&cfg->bad_ap_mngr.lock, flags);
411#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
412#pragma GCC diagnostic pop
413#endif // endif
414#if !defined(DHD_ADPS_BAM_EXPORT)
415 mutex_destroy(&cfg->bad_ap_mngr.fs_lock);
416#endif /* !DHD_ADPS_BAM_EXPORT */
417}
418
419void
420wl_bad_ap_mngr_init(struct bcm_cfg80211 *cfg)
421{
422 cfg->bad_ap_mngr.osh = cfg->osh;
423 cfg->bad_ap_mngr.num = 0;
424
425 spin_lock_init(&cfg->bad_ap_mngr.lock);
426 INIT_LIST_HEAD(&cfg->bad_ap_mngr.list);
427
428#if !defined(DHD_ADPS_BAM_EXPORT)
429 mutex_init(&cfg->bad_ap_mngr.fs_lock);
430#else
431 g_bad_ap_mngr = &cfg->bad_ap_mngr;
432#endif /* !DHD_ADPS_BAM_EXPORT */
433}
434
435static int
436wl_event_adps_bad_ap_mngr(struct bcm_cfg80211 *cfg, void *data)
437{
438 int ret = BCME_OK;
439
440 wl_event_adps_t *event_data = (wl_event_adps_t *)data;
441 wl_event_adps_bad_ap_t *bad_ap_data;
442
443 wl_bad_ap_info_entry_t *entry;
444 wl_bad_ap_info_t temp;
445#if !defined(DHD_ADPS_BAM_EXPORT)
446 struct timespec ts;
447#endif /* !DHD_ADPS_BAM_EXPORT */
448
449 if (event_data->version != WL_EVENT_ADPS_VER_1) {
450 return BCME_VERSION;
451 }
452
453 if (event_data->length != (OFFSETOF(wl_event_adps_t, data) + sizeof(*bad_ap_data))) {
454 return BCME_ERROR;
455 }
456
457 BCM_REFERENCE(ret);
458 BCM_REFERENCE(entry);
459 bad_ap_data = (wl_event_adps_bad_ap_t *)event_data->data;
460
461#if !defined(DHD_ADPS_BAM_EXPORT)
462 /* Update Bad AP list */
463 if (list_empty(&cfg->bad_ap_mngr.list)) {
464 wl_bad_ap_mngr_fread(cfg, WL_BAD_AP_INFO_FILE_PATH);
465 }
466
467 getnstimeofday(&ts);
468 entry = wl_bad_ap_mngr_find(&cfg->bad_ap_mngr, &bad_ap_data->ea);
469 if (entry != NULL) {
470 time_to_tm((ts.tv_sec - (sys_tz.tz_minuteswest * 60)), 0, &entry->bad_ap.tm);
471 entry->bad_ap.status = bad_ap_data->status;
472 entry->bad_ap.reason = bad_ap_data->reason;
473 entry->bad_ap.connect_count++;
474 }
475 else {
476 time_to_tm((ts.tv_sec - (sys_tz.tz_minuteswest * 60)), 0, &temp.tm);
477 temp.status = bad_ap_data->status;
478 temp.reason = bad_ap_data->reason;
479 temp.connect_count = 1;
480 memcpy(temp.bssid.octet, &bad_ap_data->ea.octet, ETHER_ADDR_LEN);
481
482 if (cfg->bad_ap_mngr.num < WL_BAD_AP_MAX_ENTRY_NUM) {
483 wl_bad_ap_mngr_add(&cfg->bad_ap_mngr, &temp);
484 }
485 else {
486 wl_bad_ap_mngr_update(cfg, &temp);
487 }
488 }
489
490 wl_bad_ap_mngr_fwrite(cfg, WL_BAD_AP_INFO_FILE_PATH);
491#else
492 memcpy(temp.bssid.octet, &bad_ap_data->ea.octet, ETHER_ADDR_LEN);
493 ret = wl_bad_ap_mngr_add(&cfg->bad_ap_mngr, &temp);
494#endif /* !DHD_ADPS_BAM_EXPORT */
495
496 return ret;
497}
498
499/*
500 * Return value:
501 * Disabled: 0
502 * Enabled: WLC_BAND_2G, WLC_BAND_5G, WLC_BAND_ALL
503 *
504 */
505int
506wl_adps_enabled(struct bcm_cfg80211 *cfg, struct net_device *ndev)
507{
508 int len;
509 int ret = 0;
510
511 uint8 i;
512 uint8 band;
513 uint8 *pdata;
514 char buf[WLC_IOCTL_SMLEN];
515
516 bcm_iov_buf_t iov_buf;
517 bcm_iov_buf_t *resp;
518 wl_adps_params_v1_t *data = NULL;
519
520 memset(&iov_buf, 0, sizeof(iov_buf));
521 len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
522
523 iov_buf.version = WL_ADPS_IOV_VER;
524 iov_buf.len = sizeof(band);
525 iov_buf.id = WL_ADPS_IOV_MODE;
526
527 band = 0;
528 pdata = (uint8 *)iov_buf.data;
529 for (i = 1; i <= MAX_BANDS; i++) {
530 *pdata = i;
531 ret = wldev_iovar_getbuf(ndev, "adps", &iov_buf, len, buf, WLC_IOCTL_SMLEN, NULL);
532 if (ret < 0) {
533 WL_ERR(("%s - fail to get adps for band %d (%d)\n",
534 __FUNCTION__, i, ret));
535 return 0;
536 }
537 resp = (bcm_iov_buf_t *)buf;
538 data = (wl_adps_params_v1_t *)resp->data;
539
540 if (data->mode) {
92faf122 541 if (data->band == NL80211_BAND_2GHZ) {
1cac41cb
MB
542 band += WLC_BAND_2G;
543 }
92faf122 544 else if (data->band == NL80211_BAND_5GHZ) {
1cac41cb
MB
545 band += WLC_BAND_5G;
546 }
547 }
548 }
549
550 return band;
551}
552
553int
554wl_adps_set_suspend(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint8 suspend)
555{
556 int ret = BCME_OK;
557
558 int buf_len;
559 bcm_iov_buf_t *iov_buf = NULL;
560 wl_adps_suspend_v1_t *data = NULL;
561
562 buf_len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(*data);
563 iov_buf = MALLOCZ(cfg->osh, buf_len);
564 if (iov_buf == NULL) {
565 WL_ERR(("%s - failed to alloc %d bytes for iov_buf\n",
566 __FUNCTION__, buf_len));
567 ret = BCME_NOMEM;
568 goto exit;
569 }
570
571 iov_buf->version = WL_ADPS_IOV_VER;
572 iov_buf->len = buf_len;
573 iov_buf->id = WL_ADPS_IOV_SUSPEND;
574
575 data = (wl_adps_suspend_v1_t *)iov_buf->data;
576 data->version = ADPS_SUB_IOV_VERSION_1;
577 data->length = sizeof(*data);
578 data->suspend = suspend;
579
580 ret = wldev_iovar_setbuf(ndev, "adps", (char *)iov_buf, buf_len,
581 cfg->ioctl_buf, WLC_IOCTL_SMLEN, NULL);
582 if (ret < 0) {
583 if (ret == BCME_UNSUPPORTED) {
584 WL_ERR(("%s - adps suspend is not supported\n", __FUNCTION__));
585 ret = BCME_OK;
586 }
587 else {
588 WL_ERR(("%s - fail to set adps suspend %d (%d)\n",
589 __FUNCTION__, suspend, ret));
590 }
591 goto exit;
592 }
593 WL_INFORM_MEM(("[%s] Detect BAD AP and Suspend ADPS\n", ndev->name));
594exit:
595 if (iov_buf) {
596 MFREE(cfg->osh, iov_buf, buf_len);
597 }
598 return ret;
599}
600
601bool
602wl_adps_bad_ap_check(struct bcm_cfg80211 *cfg, const struct ether_addr *bssid)
603{
604#if !defined(DHD_ADPS_BAM_EXPORT)
605 /* Update Bad AP list */
606 if (list_empty(&cfg->bad_ap_mngr.list)) {
607 wl_bad_ap_mngr_fread(cfg, WL_BAD_AP_INFO_FILE_PATH);
608 }
609#endif /* DHD_ADPS_BAM_EXPORT */
610
611 if (wl_bad_ap_mngr_find(&cfg->bad_ap_mngr, bssid) != NULL)
612 return TRUE;
613
614 return FALSE;
615}
616
617s32
618wl_adps_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
619 const wl_event_msg_t *e, void *data)
620{
621 int ret = BCME_OK;
622 wl_event_adps_t *event_data = (wl_event_adps_t *)data;
623
624 switch (event_data->type) {
625 case WL_E_TYPE_ADPS_BAD_AP:
626 ret = wl_event_adps_bad_ap_mngr(cfg, data);
627 break;
628 default:
629 break;
630 }
631
632 return ret;
633}