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