xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/wl_android.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Linux cfg80211 driver - Android related functions
3  *
4  * Copyright (C) 2020, 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  *
21  * <<Broadcom-WL-IPTag/Dual:>>
22  */
23 
24 #include <linux/module.h>
25 #include <linux/netdevice.h>
26 #include <net/netlink.h>
27 #ifdef CONFIG_COMPAT
28 #include <linux/compat.h>
29 #endif
30 
31 #include <wl_android.h>
32 #include <wldev_common.h>
33 #include <wlioctl.h>
34 #include <wlioctl_utils.h>
35 #include <bcmutils.h>
36 #include <bcmstdlib_s.h>
37 #include <linux_osl.h>
38 #include <dhd_dbg.h>
39 #include <dngl_stats.h>
40 #include <dhd.h>
41 #include <dhd_config.h>
42 #include <bcmip.h>
43 #ifdef PNO_SUPPORT
44 #include <dhd_pno.h>
45 #endif
46 #ifdef BCMSDIO
47 #include <bcmsdbus.h>
48 #endif
49 #ifdef WL_CFG80211
50 #include <wl_cfg80211.h>
51 #include <wl_cfgscan.h>
52 #include <wl_cfgvif.h>
53 #endif
54 #ifdef WL_NAN
55 #include <wl_cfgnan.h>
56 #endif /* WL_NAN */
57 #ifdef DHDTCPACK_SUPPRESS
58 #include <dhd_ip.h>
59 #endif /* DHDTCPACK_SUPPRESS */
60 #include <bcmwifi_rspec.h>
61 #include <dhd_linux.h>
62 #include <bcmiov.h>
63 #ifdef DHD_PKT_LOGGING
64 #include <dhd_pktlog.h>
65 #endif /* DHD_PKT_LOGGING */
66 #ifdef WL_BCNRECV
67 #include <wl_cfgvendor.h>
68 #include <brcm_nl80211.h>
69 #endif /* WL_BCNRECV */
70 #ifdef WL_MBO
71 #include <mbo.h>
72 #endif /* WL_MBO */
73 #ifdef RTT_SUPPORT
74 #include <dhd_rtt.h>
75 #endif /* RTT_SUPPORT */
76 #ifdef DHD_EVENT_LOG_FILTER
77 #include <dhd_event_log_filter.h>
78 #endif /* DHD_EVENT_LOG_FILTER */
79 #ifdef WL_ESCAN
80 #include <wl_escan.h>
81 #endif
82 
83 #ifdef WL_TWT
84 #include <802.11ah.h>
85 #endif /* WL_TWT */
86 
87 #ifdef WL_STATIC_IF
88 #define WL_BSSIDX_MAX	16
89 #endif /* WL_STATIC_IF */
90 
91 #define ANDROID_ERROR_MSG(x, args...) \
92 	do { \
93 		if (android_msg_level & ANDROID_ERROR_LEVEL) { \
94 			printf("ANDROID-ERROR) " x, ## args); \
95 		} \
96 	} while (0)
97 #define ANDROID_TRACE_MSG(x, args...) \
98 	do { \
99 		if (android_msg_level & ANDROID_TRACE_LEVEL) { \
100 			printf("ANDROID-TRACE) " x, ## args); \
101 		} \
102 	} while (0)
103 #define ANDROID_INFO_MSG(x, args...) \
104 	do { \
105 		if (android_msg_level & ANDROID_INFO_LEVEL) { \
106 			printf("ANDROID-INFO) " x, ## args); \
107 		} \
108 	} while (0)
109 #define ANDROID_ERROR(x) ANDROID_ERROR_MSG x
110 #define ANDROID_TRACE(x) ANDROID_TRACE_MSG x
111 #define ANDROID_INFO(x) ANDROID_INFO_MSG x
112 
113 /*
114  * Android private command strings, PLEASE define new private commands here
115  * so they can be updated easily in the future (if needed)
116  */
117 
118 #define CMD_START		"START"
119 #define CMD_STOP		"STOP"
120 #define	CMD_SCAN_ACTIVE		"SCAN-ACTIVE"
121 #define	CMD_SCAN_PASSIVE	"SCAN-PASSIVE"
122 #define CMD_RSSI		"RSSI"
123 #define CMD_LINKSPEED		"LINKSPEED"
124 #define CMD_RXFILTER_START	"RXFILTER-START"
125 #define CMD_RXFILTER_STOP	"RXFILTER-STOP"
126 #define CMD_RXFILTER_ADD	"RXFILTER-ADD"
127 #define CMD_RXFILTER_REMOVE	"RXFILTER-REMOVE"
128 #define CMD_BTCOEXSCAN_START	"BTCOEXSCAN-START"
129 #define CMD_BTCOEXSCAN_STOP	"BTCOEXSCAN-STOP"
130 #define CMD_BTCOEXMODE		"BTCOEXMODE"
131 #define CMD_SETSUSPENDOPT	"SETSUSPENDOPT"
132 #define CMD_SETSUSPENDMODE      "SETSUSPENDMODE"
133 #define CMD_SETDTIM_IN_SUSPEND  "SET_DTIM_IN_SUSPEND"
134 #define CMD_MAXDTIM_IN_SUSPEND  "MAX_DTIM_IN_SUSPEND"
135 #define CMD_DISDTIM_IN_SUSPEND  "DISABLE_DTIM_IN_SUSPEND"
136 #define CMD_P2P_DEV_ADDR	"P2P_DEV_ADDR"
137 #define CMD_SETFWPATH		"SETFWPATH"
138 #define CMD_SETBAND		"SETBAND"
139 #define CMD_GETBAND		"GETBAND"
140 #define CMD_COUNTRY		"COUNTRY"
141 #define CMD_P2P_SET_NOA		"P2P_SET_NOA"
142 #if !defined WL_ENABLE_P2P_IF
143 #define CMD_P2P_GET_NOA			"P2P_GET_NOA"
144 #endif /* WL_ENABLE_P2P_IF */
145 #define CMD_P2P_SD_OFFLOAD		"P2P_SD_"
146 #define CMD_P2P_LISTEN_OFFLOAD		"P2P_LO_"
147 #define CMD_P2P_SET_PS		"P2P_SET_PS"
148 #define CMD_P2P_ECSA		"P2P_ECSA"
149 #define CMD_P2P_INC_BW		"P2P_INCREASE_BW"
150 #define CMD_SET_AP_WPS_P2P_IE 		"SET_AP_WPS_P2P_IE"
151 #define CMD_SETROAMMODE 	"SETROAMMODE"
152 #define CMD_SETIBSSBEACONOUIDATA	"SETIBSSBEACONOUIDATA"
153 #define CMD_MIRACAST		"MIRACAST"
154 #ifdef WL_NAN
155 #define CMD_NAN         "NAN_"
156 #endif /* WL_NAN */
157 #define CMD_COUNTRY_DELIMITER "/"
158 
159 #if defined (WL_SUPPORT_AUTO_CHANNEL)
160 #define CMD_GET_BEST_CHANNELS	"GET_BEST_CHANNELS"
161 #endif /* WL_SUPPORT_AUTO_CHANNEL */
162 
163 #define CMD_80211_MODE    "MODE"  /* 802.11 mode a/b/g/n/ac */
164 #define CMD_CHANSPEC      "CHANSPEC"
165 #define CMD_DATARATE      "DATARATE"
166 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
167 #define CMD_SET_CSA       "SETCSA"
168 #ifdef WL_SUPPORT_AUTO_CHANNEL
169 #define CMD_SET_HAPD_AUTO_CHANNEL	"HAPD_AUTO_CHANNEL"
170 #endif /* WL_SUPPORT_AUTO_CHANNEL */
171 #ifdef CUSTOMER_HW4_PRIVATE_CMD
172 #ifdef WL_WTC
173 #define CMD_WTC_CONFIG    "SETWTCMODE"
174 #endif /* WL_WTC */
175 #ifdef SUPPORT_HIDDEN_AP
176 /* Hostapd private command */
177 #define CMD_SET_HAPD_MAX_NUM_STA	"HAPD_MAX_NUM_STA"
178 #define CMD_SET_HAPD_SSID		"HAPD_SSID"
179 #define CMD_SET_HAPD_HIDE_SSID		"HAPD_HIDE_SSID"
180 #endif /* SUPPORT_HIDDEN_AP */
181 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
182 #define CMD_HAPD_STA_DISASSOC		"HAPD_STA_DISASSOC"
183 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
184 #ifdef SUPPORT_SET_LPC
185 #define CMD_HAPD_LPC_ENABLED		"HAPD_LPC_ENABLED"
186 #endif /* SUPPORT_SET_LPC */
187 #ifdef SUPPORT_TRIGGER_HANG_EVENT
188 #define CMD_TEST_FORCE_HANG		"TEST_FORCE_HANG"
189 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
190 #ifdef SUPPORT_LTECX
191 #define CMD_LTECX_SET		"LTECOEX"
192 #endif /* SUPPORT_LTECX */
193 #ifdef TEST_TX_POWER_CONTROL
194 #define CMD_TEST_SET_TX_POWER		"TEST_SET_TX_POWER"
195 #define CMD_TEST_GET_TX_POWER		"TEST_GET_TX_POWER"
196 #endif /* TEST_TX_POWER_CONTROL */
197 #define CMD_SARLIMIT_TX_CONTROL		"SET_TX_POWER_CALLING"
198 #ifdef SUPPORT_SET_TID
199 #define CMD_SET_TID		"SET_TID"
200 #define CMD_GET_TID		"GET_TID"
201 #endif /* SUPPORT_SET_TID */
202 #define CMD_ROAM_VSIE_ENAB_SET	"SET_ROAMING_REASON_ENABLED"
203 #define CMD_ROAM_VSIE_ENAB_GET	"GET_ROAMING_REASON_ENABLED"
204 #define CMD_BR_VSIE_ENAB_SET	"SET_BR_ERR_REASON_ENABLED"
205 #define CMD_BR_VSIE_ENAB_GET	"GET_BR_ERR_REASON_ENABLED"
206 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
207 #define CMD_KEEP_ALIVE          "KEEPALIVE"
208 
209 #ifdef PNO_SUPPORT
210 #define CMD_PNOSSIDCLR_SET	"PNOSSIDCLR"
211 #define CMD_PNOSETUP_SET	"PNOSETUP "
212 #define CMD_PNOENABLE_SET	"PNOFORCE"
213 #define CMD_PNODEBUG_SET	"PNODEBUG"
214 #define CMD_WLS_BATCHING	"WLS_BATCHING"
215 #endif /* PNO_SUPPORT */
216 
217 #define CMD_HAPD_SET_AX_MODE "HAPD_SET_AX_MODE"
218 
219 #define	CMD_HAPD_MAC_FILTER	"HAPD_MAC_FILTER"
220 
221 #if defined(SUPPORT_RANDOM_MAC_SCAN)
222 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
223 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
224 #endif /* SUPPORT_RANDOM_MAC_SCAN */
225 #define CMD_GET_FACTORY_MAC      "FACTORY_MAC"
226 #ifdef CUSTOMER_HW4_PRIVATE_CMD
227 
228 #ifdef ROAM_API
229 #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
230 #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
231 #define CMD_ROAMDELTA_SET "SETROAMDELTA"
232 #define CMD_ROAMDELTA_GET "GETROAMDELTA"
233 #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
234 #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
235 #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
236 #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
237 #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
238 #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
239 #endif /* ROAM_API */
240 
241 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
242 #define CMD_NAN_RANGING_SET_BW "NAN_RANGING_SET_BW"
243 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
244 
245 #ifdef WES_SUPPORT
246 #define CMD_GETSCANCHANNELTIMELEGACY "GETSCANCHANNELTIME_LEGACY"
247 #define CMD_SETSCANCHANNELTIMELEGACY "SETSCANCHANNELTIME_LEGACY"
248 #define CMD_GETSCANUNASSOCTIMELEGACY "GETSCANUNASSOCTIME_LEGACY"
249 #define CMD_SETSCANUNASSOCTIMELEGACY "SETSCANUNASSOCTIME_LEGACY"
250 #define CMD_GETSCANPASSIVETIMELEGACY "GETSCANPASSIVETIME_LEGACY"
251 #define CMD_SETSCANPASSIVETIMELEGACY "SETSCANPASSIVETIME_LEGACY"
252 #define CMD_GETSCANHOMETIMELEGACY "GETSCANHOMETIME_LEGACY"
253 #define CMD_SETSCANHOMETIMELEGACY "SETSCANHOMETIME_LEGACY"
254 #define CMD_GETSCANHOMEAWAYTIMELEGACY "GETSCANHOMEAWAYTIME_LEGACY"
255 #define CMD_SETSCANHOMEAWAYTIMELEGACY "SETSCANHOMEAWAYTIME_LEGACY"
256 #define CMD_GETROAMSCANCHLEGACY "GETROAMSCANCHANNELS_LEGACY"
257 #define CMD_ADDROAMSCANCHLEGACY "ADDROAMSCANCHANNELS_LEGACY"
258 #define CMD_GETROAMSCANFQLEGACY "GETROAMSCANFREQUENCIES_LEGACY"
259 #define CMD_ADDROAMSCANFQLEGACY "ADDROAMSCANFREQUENCIES_LEGACY"
260 #define CMD_GETROAMTRIGLEGACY "GETROAMTRIGGER_LEGACY"
261 #define CMD_SETROAMTRIGLEGACY "SETROAMTRIGGER_LEGACY"
262 #define CMD_REASSOCLEGACY "REASSOC_LEGACY"
263 
264 #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
265 #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
266 #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
267 #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
268 #define CMD_ADDROAMSCANCHANNELS "ADDROAMSCANCHANNELS"
269 #define CMD_GETROAMSCANFREQS "GETROAMSCANFREQUENCIES"
270 #define CMD_SETROAMSCANFREQS "SETROAMSCANFREQUENCIES"
271 #define CMD_ADDROAMSCANFREQS "ADDROAMSCANFREQUENCIES"
272 #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
273 #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
274 #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
275 #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
276 #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
277 #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
278 #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
279 #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
280 #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
281 #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
282 #define CMD_GETSCANNPROBES "GETSCANNPROBES"
283 #define CMD_SETSCANNPROBES "SETSCANNPROBES"
284 #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
285 #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
286 #define CMD_SETJOINPREFER "SETJOINPREFER"
287 
288 #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
289 #define CMD_REASSOC "REASSOC"
290 
291 #define CMD_GETWESMODE "GETWESMODE"
292 #define CMD_SETWESMODE "SETWESMODE"
293 #define CMD_GETNCHOMODE	"GETNCHOMODE"
294 #define CMD_SETNCHOMODE	"SETNCHOMODE"
295 
296 /* Customer requested to Remove OKCMODE command */
297 #define CMD_GETOKCMODE "GETOKCMODE"
298 #define CMD_SETOKCMODE "SETOKCMODE"
299 
300 #define CMD_OKC_SET_PMK         "SET_PMK"
301 #define CMD_OKC_ENABLE          "OKC_ENABLE"
302 
303 typedef struct android_wifi_reassoc_params {
304 	unsigned char bssid[18];
305 	int channel;
306 } android_wifi_reassoc_params_t;
307 
308 #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
309 
310 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
311 
312 typedef struct android_wifi_af_params {
313 	unsigned char bssid[18];
314 	int channel;
315 	int dwell_time;
316 	int len;
317 	unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
318 } android_wifi_af_params_t;
319 
320 #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
321 #endif /* WES_SUPPORT */
322 #ifdef SUPPORT_AMPDU_MPDU_CMD
323 #define CMD_AMPDU_MPDU		"AMPDU_MPDU"
324 #endif /* SUPPORT_AMPDU_MPDU_CMD */
325 
326 #define CMD_CHANGE_RL 	"CHANGE_RL"
327 #define CMD_RESTORE_RL  "RESTORE_RL"
328 
329 #define CMD_SET_RMC_ENABLE			"SETRMCENABLE"
330 #define CMD_SET_RMC_TXRATE			"SETRMCTXRATE"
331 #define CMD_SET_RMC_ACTPERIOD		"SETRMCACTIONPERIOD"
332 #define CMD_SET_RMC_IDLEPERIOD		"SETRMCIDLEPERIOD"
333 #define CMD_SET_RMC_LEADER			"SETRMCLEADER"
334 #define CMD_SET_RMC_EVENT			"SETRMCEVENT"
335 
336 #define CMD_SET_SCSCAN		"SETSINGLEANT"
337 #define CMD_GET_SCSCAN		"GETSINGLEANT"
338 #ifdef WLTDLS
339 #define CMD_TDLS_RESET "TDLS_RESET"
340 #endif /* WLTDLS */
341 
342 #ifdef CONFIG_SILENT_ROAM
343 #define CMD_SROAM_TURN_ON	"SROAMTURNON"
344 #define CMD_SROAM_SET_INFO	"SROAMSETINFO"
345 #define CMD_SROAM_GET_INFO	"SROAMGETINFO"
346 #endif /* CONFIG_SILENT_ROAM */
347 
348 #ifdef CONFIG_ROAM_RSSI_LIMIT
349 #define CMD_ROAM_RSSI_LMT	"ROAMRSSILIMIT"
350 #endif /* CONFIG_ROAM_RSSI_LIMIT */
351 #ifdef CONFIG_ROAM_MIN_DELTA
352 #define CMD_ROAM_MIN_DELTA	"ROAMMINSCOREDELTA"
353 #endif /* CONFIG_ROAM_MIN_DELTA */
354 
355 #define CMD_SET_DISCONNECT_IES  "SET_DISCONNECT_IES"
356 
357 #ifdef FCC_PWR_LIMIT_2G
358 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
359 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
360 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
361 #define CUSTOMER_HW4_ENABLE		0
362 #define CUSTOMER_HW4_DISABLE	-1
363 #endif /* FCC_PWR_LIMIT_2G */
364 #define CUSTOMER_HW4_EN_CONVERT(i)	(i += 1)
365 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
366 
367 #ifdef WLFBT
368 #define CMD_GET_FTKEY      "GET_FTKEY"
369 #endif
370 
371 #ifdef WLAIBSS
372 #define CMD_SETIBSSTXFAILEVENT		"SETIBSSTXFAILEVENT"
373 #define CMD_GET_IBSS_PEER_INFO		"GETIBSSPEERINFO"
374 #define CMD_GET_IBSS_PEER_INFO_ALL	"GETIBSSPEERINFOALL"
375 #define CMD_SETIBSSROUTETABLE		"SETIBSSROUTETABLE"
376 #define CMD_SETIBSSAMPDU			"SETIBSSAMPDU"
377 #define CMD_SETIBSSANTENNAMODE		"SETIBSSANTENNAMODE"
378 #endif /* WLAIBSS */
379 
380 #define CMD_ROAM_OFFLOAD			"SETROAMOFFLOAD"
381 #define CMD_INTERFACE_CREATE			"INTERFACE_CREATE"
382 #define CMD_INTERFACE_DELETE			"INTERFACE_DELETE"
383 #define CMD_GET_LINK_STATUS			"GETLINKSTATUS"
384 
385 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
386 #define CMD_GET_BSS_INFO            "GETBSSINFO"
387 #define CMD_GET_ASSOC_REJECT_INFO   "GETASSOCREJECTINFO"
388 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
389 #define CMD_GET_STA_INFO   "GETSTAINFO"
390 
391 /* related with CMD_GET_LINK_STATUS */
392 #define WL_ANDROID_LINK_VHT					0x01
393 #define WL_ANDROID_LINK_MIMO					0x02
394 #define WL_ANDROID_LINK_AP_VHT_SUPPORT		0x04
395 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT	0x08
396 
397 #ifdef P2PRESP_WFDIE_SRC
398 #define CMD_P2P_SET_WFDIE_RESP      "P2P_SET_WFDIE_RESP"
399 #define CMD_P2P_GET_WFDIE_RESP      "P2P_GET_WFDIE_RESP"
400 #endif /* P2PRESP_WFDIE_SRC */
401 
402 #define CMD_DFS_AP_MOVE			"DFS_AP_MOVE"
403 #define CMD_WBTEXT_ENABLE		"WBTEXT_ENABLE"
404 #define CMD_WBTEXT_PROFILE_CONFIG	"WBTEXT_PROFILE_CONFIG"
405 #define CMD_WBTEXT_WEIGHT_CONFIG	"WBTEXT_WEIGHT_CONFIG"
406 #define CMD_WBTEXT_TABLE_CONFIG		"WBTEXT_TABLE_CONFIG"
407 #define CMD_WBTEXT_DELTA_CONFIG		"WBTEXT_DELTA_CONFIG"
408 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD	"WBTEXT_BTM_TIMER_THRESHOLD"
409 #define CMD_WBTEXT_BTM_DELTA		"WBTEXT_BTM_DELTA"
410 #define CMD_WBTEXT_ESTM_ENABLE	"WBTEXT_ESTM_ENABLE"
411 
412 #ifdef WBTEXT
413 #define CMD_WBTEXT_PROFILE_CONFIG	"WBTEXT_PROFILE_CONFIG"
414 #define CMD_WBTEXT_WEIGHT_CONFIG	"WBTEXT_WEIGHT_CONFIG"
415 #define CMD_WBTEXT_TABLE_CONFIG		"WBTEXT_TABLE_CONFIG"
416 #define CMD_WBTEXT_DELTA_CONFIG		"WBTEXT_DELTA_CONFIG"
417 #define DEFAULT_WBTEXT_PROFILE_A_V2		"a -70 -75 70 10 -75 -128 0 10"
418 #define DEFAULT_WBTEXT_PROFILE_B_V2		"b -60 -75 70 10 -75 -128 0 10"
419 #define DEFAULT_WBTEXT_PROFILE_A_V3		"a -70 -75 70 10 -75 -128 0 10"
420 #define DEFAULT_WBTEXT_PROFILE_B_V3		"b -60 -75 70 10 -75 -128 0 10"
421 #define DEFAULT_WBTEXT_WEIGHT_RSSI_A	"RSSI a 65"
422 #define DEFAULT_WBTEXT_WEIGHT_RSSI_B	"RSSI b 65"
423 #define DEFAULT_WBTEXT_WEIGHT_CU_A	"CU a 35"
424 #define DEFAULT_WBTEXT_WEIGHT_CU_B	"CU b 35"
425 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A	"ESTM_DL a 70"
426 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B	"ESTM_DL b 70"
427 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_A	-70
428 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_B	-60
429 #ifdef WBTEXT_SCORE_V2
430 #define DEFAULT_WBTEXT_TABLE_RSSI_A	"RSSI a 0 55 100 55 60 90 \
431 60 70 60 70 80 20 80 90 0 90 128 0"
432 #define DEFAULT_WBTEXT_TABLE_RSSI_B	"RSSI b 0 55 100 55 60 90 \
433 60 70 60 70 80 20 80 90 0 90 128 0"
434 #define DEFAULT_WBTEXT_TABLE_CU_A	"CU a 0 30 100 30 80 20 \
435 80 100 20"
436 #define DEFAULT_WBTEXT_TABLE_CU_B	"CU b 0 10 100 10 70 20 \
437 70 100 20"
438 #else
439 #define DEFAULT_WBTEXT_TABLE_RSSI_A	"RSSI a 0 55 100 55 60 90 \
440 60 65 70 65 70 50 70 128 20"
441 #define DEFAULT_WBTEXT_TABLE_RSSI_B	"RSSI b 0 55 100 55 60 90 \
442 60 65 70 65 70 50 70 128 20"
443 #define DEFAULT_WBTEXT_TABLE_CU_A	"CU a 0 30 100 30 50 90 \
444 50 60 70 60 80 50 80 100 20"
445 #define DEFAULT_WBTEXT_TABLE_CU_B	"CU b 0 10 100 10 25 90 \
446 25 40 70 40 70 50 70 100 20"
447 #endif /* WBTEXT_SCORE_V2 */
448 #endif /* WBTEXT */
449 
450 #define BUFSZ 8
451 #define BUFSZN	BUFSZ + 1
452 
453 #define _S(x) #x
454 #define S(x) _S(x)
455 
456 #define  MAXBANDS    2  /**< Maximum #of bands */
457 #define BAND_2G_INDEX      1
458 #define BAND_5G_INDEX      0
459 
460 typedef union {
461 	wl_roam_prof_band_v1_t v1;
462 	wl_roam_prof_band_v2_t v2;
463 	wl_roam_prof_band_v3_t v3;
464 	wl_roam_prof_band_v4_t v4;
465 } wl_roamprof_band_t;
466 
467 #ifdef WLWFDS
468 #define CMD_ADD_WFDS_HASH	"ADD_WFDS_HASH"
469 #define CMD_DEL_WFDS_HASH	"DEL_WFDS_HASH"
470 #endif /* WLWFDS */
471 
472 #ifdef BT_WIFI_HANDOVER
473 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
474 #endif /* BT_WIFI_HANDOVER */
475 
476 #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
477 
478 #ifdef SUPPORT_RSSI_SUM_REPORT
479 #define CMD_SET_RSSI_LOGGING				"SET_RSSI_LOGGING"
480 #define CMD_GET_RSSI_LOGGING				"GET_RSSI_LOGGING"
481 #define CMD_GET_RSSI_PER_ANT				"GET_RSSI_PER_ANT"
482 #endif /* SUPPORT_RSSI_SUM_REPORT */
483 
484 #define CMD_GET_SNR							"GET_SNR"
485 
486 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
487 #define CMD_SET_AP_BEACONRATE				"SET_AP_BEACONRATE"
488 #define CMD_GET_AP_BASICRATE				"GET_AP_BASICRATE"
489 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
490 
491 #ifdef SUPPORT_AP_RADIO_PWRSAVE
492 #define CMD_SET_AP_RPS						"SET_AP_RPS"
493 #define CMD_GET_AP_RPS						"GET_AP_RPS"
494 #define CMD_SET_AP_RPS_PARAMS				"SET_AP_RPS_PARAMS"
495 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
496 
497 #ifdef SUPPORT_AP_SUSPEND
498 #define CMD_SET_AP_SUSPEND			"SET_AP_SUSPEND"
499 #endif /* SUPPORT_AP_SUSPEND */
500 
501 #ifdef SUPPORT_AP_BWCTRL
502 #define CMD_SET_AP_BW			"SET_AP_BW"
503 #define CMD_GET_AP_BW			"GET_AP_BW"
504 #endif /* SUPPORT_AP_BWCTRL */
505 
506 /* miracast related definition */
507 #define MIRACAST_MODE_OFF	0
508 #define MIRACAST_MODE_SOURCE	1
509 #define MIRACAST_MODE_SINK	2
510 
511 #ifdef CONNECTION_STATISTICS
512 #define CMD_GET_CONNECTION_STATS	"GET_CONNECTION_STATS"
513 
514 struct connection_stats {
515 	u32 txframe;
516 	u32 txbyte;
517 	u32 txerror;
518 	u32 rxframe;
519 	u32 rxbyte;
520 	u32 txfail;
521 	u32 txretry;
522 	u32 txretrie;
523 	u32 txrts;
524 	u32 txnocts;
525 	u32 txexptime;
526 	u32 txrate;
527 	u8	chan_idle;
528 };
529 #endif /* CONNECTION_STATISTICS */
530 
531 #ifdef SUPPORT_LQCM
532 #define CMD_SET_LQCM_ENABLE			"SET_LQCM_ENABLE"
533 #define CMD_GET_LQCM_REPORT			"GET_LQCM_REPORT"
534 #endif
535 
536 static LIST_HEAD(miracast_resume_list);
537 #ifdef WL_CFG80211
538 static u8 miracast_cur_mode;
539 #endif /* WL_CFG80211 */
540 
541 #ifdef DHD_LOG_DUMP
542 #define CMD_NEW_DEBUG_PRINT_DUMP	"DEBUG_DUMP"
543 #define SUBCMD_UNWANTED			"UNWANTED"
544 #define SUBCMD_DISCONNECTED		"DISCONNECTED"
545 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
546 #endif /* DHD_LOG_DUMP */
547 
548 #ifdef DHD_STATUS_LOGGING
549 #define CMD_DUMP_STATUS_LOG		"DUMP_STAT_LOG"
550 #define CMD_QUERY_STATUS_LOG		"QUERY_STAT_LOG"
551 #endif /* DHD_STATUS_LOGGING */
552 
553 #ifdef DHD_HANG_SEND_UP_TEST
554 #define CMD_MAKE_HANG  "MAKE_HANG"
555 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
556 #ifdef DHD_DEBUG_UART
557 extern bool dhd_debug_uart_is_running(struct net_device *dev);
558 #endif	/* DHD_DEBUG_UART */
559 
560 #ifdef RTT_GEOFENCE_INTERVAL
561 #if defined (RTT_SUPPORT) && defined(WL_NAN)
562 #define CMD_GEOFENCE_INTERVAL	"GEOFENCE_INT"
563 #endif /* RTT_SUPPORT && WL_NAN */
564 #endif /* RTT_GEOFENCE_INTERVAL */
565 
566 struct io_cfg {
567 	s8 *iovar;
568 	s32 param;
569 	u32 ioctl;
570 	void *arg;
571 	u32 len;
572 	struct list_head list;
573 };
574 
575 #if defined(BCMFW_ROAM_ENABLE)
576 #define CMD_SET_ROAMPREF	"SET_ROAMPREF"
577 
578 #define MAX_NUM_SUITES		10
579 #define WIDTH_AKM_SUITE		8
580 #define JOIN_PREF_RSSI_LEN		0x02
581 #define JOIN_PREF_RSSI_SIZE		4	/* RSSI pref header size in bytes */
582 #define JOIN_PREF_WPA_HDR_SIZE		4 /* WPA pref header size in bytes */
583 #define JOIN_PREF_WPA_TUPLE_SIZE	12	/* Tuple size in bytes */
584 #define JOIN_PREF_MAX_WPA_TUPLES	16
585 #define MAX_BUF_SIZE		(JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +	\
586 				           (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
587 #endif /* BCMFW_ROAM_ENABLE */
588 
589 #if defined(CONFIG_TIZEN)
590 /*
591  * adding these private commands corresponding to atd-server's implementation
592  * __atd_control_pm_state()
593  */
594 #define CMD_POWERSAVEMODE_SET "SETPOWERSAVEMODE"
595 #define CMD_POWERSAVEMODE_GET "GETPOWERSAVEMODE"
596 #endif /* CONFIG_TIZEN */
597 
598 #define CMD_DEBUG_VERBOSE          "DEBUG_VERBOSE"
599 #ifdef WL_NATOE
600 
601 #define CMD_NATOE		"NATOE"
602 
603 #define NATOE_MAX_PORT_NUM	65535
604 
605 /* natoe command info structure */
606 typedef struct wl_natoe_cmd_info {
607 	uint8  *command;        /* pointer to the actual command */
608 	uint16 tot_len;        /* total length of the command */
609 	uint16 bytes_written;  /* Bytes written for get response */
610 } wl_natoe_cmd_info_t;
611 
612 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
613 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
614 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
615 
616 struct wl_natoe_sub_cmd {
617 	char *name;
618 	uint8  version;              /* cmd  version */
619 	uint16 id;                   /* id for the dongle f/w switch/case */
620 	uint16 type;                 /* base type of argument */
621 	natoe_cmd_handler_t *handler; /* cmd handler  */
622 };
623 
624 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
625 static int wl_android_process_natoe_cmd(struct net_device *dev,
626 		char *command, int total_len);
627 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
628 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
629 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
630 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
631 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
632 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
633 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
634 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
635 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
636 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
637 
638 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
639 	/* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
640 	{"enable", 0x01, WL_NATOE_CMD_ENABLE,
641 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
642 	},
643 	{"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
644 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
645 	},
646 	{"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
647 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
648 	},
649 	{"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
650 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
651 	},
652 	{"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
653 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
654 	},
655 	{NULL, 0, 0, 0, NULL}
656 };
657 
658 #endif /* WL_NATOE */
659 
660 #ifdef SET_PCIE_IRQ_CPU_CORE
661 #define CMD_PCIE_IRQ_CORE	"PCIE_IRQ_CORE"
662 #endif /* SET_PCIE_IRQ_CPU_CORE */
663 
664 #ifdef WLADPS_PRIVATE_CMD
665 #define CMD_SET_ADPS	"SET_ADPS"
666 #define CMD_GET_ADPS	"GET_ADPS"
667 #ifdef WLADPS_ENERGY_GAIN
668 #define CMD_GET_GAIN_ADPS	"GET_GAIN_ADPS"
669 #define CMD_RESET_GAIN_ADPS	"RESET_GAIN_ADPS"
670 #ifndef ADPS_GAIN_2G_PM0_IDLE
671 #define ADPS_GAIN_2G_PM0_IDLE 0
672 #endif
673 #ifndef ADPS_GAIN_5G_PM0_IDLE
674 #define ADPS_GAIN_5G_PM0_IDLE 0
675 #endif
676 #ifndef ADPS_GAIN_2G_TX_PSPOLL
677 #define ADPS_GAIN_2G_TX_PSPOLL 0
678 #endif
679 #ifndef ADPS_GAIN_5G_TX_PSPOLL
680 #define ADPS_GAIN_5G_TX_PSPOLL 0
681 #endif
682 #endif	/* WLADPS_ENERGY_GAIN */
683 #endif /* WLADPS_PRIVATE_CMD */
684 
685 #ifdef DHD_PKT_LOGGING
686 #define CMD_PKTLOG_FILTER_ENABLE	"PKTLOG_FILTER_ENABLE"
687 #define CMD_PKTLOG_FILTER_DISABLE	"PKTLOG_FILTER_DISABLE"
688 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE	"PKTLOG_FILTER_PATTERN_ENABLE"
689 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE	"PKTLOG_FILTER_PATTERN_DISABLE"
690 #define CMD_PKTLOG_FILTER_ADD	"PKTLOG_FILTER_ADD"
691 #define CMD_PKTLOG_FILTER_DEL	"PKTLOG_FILTER_DEL"
692 #define CMD_PKTLOG_FILTER_INFO	"PKTLOG_FILTER_INFO"
693 #define CMD_PKTLOG_START	"PKTLOG_START"
694 #define CMD_PKTLOG_STOP		"PKTLOG_STOP"
695 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
696 #define CMD_PKTLOG_MINMIZE_ENABLE	"PKTLOG_MINMIZE_ENABLE"
697 #define CMD_PKTLOG_MINMIZE_DISABLE	"PKTLOG_MINMIZE_DISABLE"
698 #define CMD_PKTLOG_CHANGE_SIZE	"PKTLOG_CHANGE_SIZE"
699 #define CMD_PKTLOG_DEBUG_DUMP	"PKTLOG_DEBUG_DUMP"
700 #endif /* DHD_PKT_LOGGING */
701 
702 #ifdef DHD_EVENT_LOG_FILTER
703 #define CMD_EWP_FILTER		"EWP_FILTER"
704 #endif /* DHD_EVENT_LOG_FILTER */
705 
706 #ifdef WL_BCNRECV
707 #define CMD_BEACON_RECV "BEACON_RECV"
708 #endif /* WL_BCNRECV */
709 #ifdef WL_CAC_TS
710 #define CMD_CAC_TSPEC "CAC_TSPEC"
711 #endif /* WL_CAC_TS */
712 #ifdef WL_GET_CU
713 #define CMD_GET_CHAN_UTIL "GET_CU"
714 #endif /* WL_GET_CU */
715 
716 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
717 #define CMD_SET_SOFTAP_ELNA_BYPASS				"SET_SOFTAP_ELNA_BYPASS"
718 #define CMD_GET_SOFTAP_ELNA_BYPASS				"GET_SOFTAP_ELNA_BYPASS"
719 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
720 
721 #ifdef WL_NAN
722 #define CMD_GET_NAN_STATUS	"GET_NAN_STATUS"
723 #endif /* WL_NAN */
724 
725 #ifdef WL_TWT
726 #define CMD_TWT_SETUP		"TWT_SETUP"
727 #define CMD_TWT_TEARDOWN	"TWT_TEARDOWN"
728 #define CMD_TWT_INFO		"TWT_INFO_FRM"
729 #define CMD_TWT_STATUS_QUERY	"GET_TWT_STATUS"
730 #define CMD_TWT_CAPABILITY	"GET_TWT_CAP"
731 #define CMD_TWT_GET_STATS	"GET_TWT_STATISTICS"
732 #define CMD_TWT_CLR_STATS	"CLEAR_TWT_STATISTICS"
733 #define WL_TWT_CMD_INVAL	255
734 
735 /* setup command name to value conversion */
736 static struct {
737 	const char *name;
738 	uint8 val;
739 } setup_cmd_val[] = {
740 	{"request", TWT_SETUP_CMD_REQUEST_TWT},
741 	{"suggest", TWT_SETUP_CMD_SUGGEST_TWT},
742 	{"demand", TWT_SETUP_CMD_DEMAND_TWT},
743 	{"accept", TWT_SETUP_CMD_ACCEPT_TWT},
744 	{"alternate", TWT_SETUP_CMD_ALTER_TWT},
745 	{"reject", TWT_SETUP_CMD_REJECT_TWT}
746 };
747 #endif /* WL_TWT */
748 
749 /* drv command info structure */
750 typedef struct wl_drv_cmd_info {
751 	uint8  *command;        /* pointer to the actual command */
752 	uint16 tot_len;         /* total length of the command */
753 	uint16 bytes_written;   /* Bytes written for get response */
754 } wl_drv_cmd_info_t;
755 
756 typedef struct wl_drv_sub_cmd wl_drv_sub_cmd_t;
757 typedef int (drv_cmd_handler_t)(struct net_device *dev,
758 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
759 
760 struct wl_drv_sub_cmd {
761 	char *name;
762 	uint8  version;              /* cmd  version */
763 	uint16 id;                   /* id for the dongle f/w switch/case */
764 	uint16 type;                 /* base type of argument */
765 	drv_cmd_handler_t *handler;  /* cmd handler  */
766 };
767 
768 #ifdef WL_MBO
769 
770 #define CMD_MBO		"MBO"
771 enum {
772 	WL_MBO_CMD_NON_CHAN_PREF = 1,
773 	WL_MBO_CMD_CELL_DATA_CAP = 2
774 };
775 #define WL_ANDROID_MBO_FUNC(suffix) wl_android_mbo_subcmd_ ##suffix
776 
777 static int wl_android_process_mbo_cmd(struct net_device *dev,
778 		char *command, int total_len);
779 static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
780 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
781 static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
782 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
783 
784 static const wl_drv_sub_cmd_t mbo_cmd_list[] = {
785 	{"non_pref_chan", 0x01, WL_MBO_CMD_NON_CHAN_PREF,
786 	IOVT_BUFFER, WL_ANDROID_MBO_FUNC(non_pref_chan)
787 	},
788 	{"cell_data_cap", 0x01, WL_MBO_CMD_CELL_DATA_CAP,
789 	IOVT_BUFFER, WL_ANDROID_MBO_FUNC(cell_data_cap)
790 	},
791 	{NULL, 0, 0, 0, NULL}
792 };
793 
794 #endif /* WL_MBO */
795 
796 #ifdef WL_GENL
797 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
798 static int wl_genl_init(void);
799 static int wl_genl_deinit(void);
800 
801 extern struct net init_net;
802 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
803  * possible values defined in net/netlink.h
804  */
805 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
806 	[BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
807 	[BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
808 };
809 
810 #define WL_GENL_VER 1
811 /* family definition */
812 static struct genl_family wl_genl_family = {
813 	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
814 	.hdrsize = 0,
815 	.name = "bcm-genl",        /* Netlink I/F for Android */
816 	.version = WL_GENL_VER,     /* Version Number */
817 	.maxattr = BCM_GENL_ATTR_MAX,
818 };
819 
820 /* commands: mapping between the command enumeration and the actual function */
821 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
822 struct genl_ops wl_genl_ops[] = {
823 	{
824 	.cmd = BCM_GENL_CMD_MSG,
825 	.flags = 0,
826 	.policy = wl_genl_policy,
827 	.doit = wl_genl_handle_msg,
828 	.dumpit = NULL,
829 	},
830 };
831 #else
832 struct genl_ops wl_genl_ops = {
833 	.cmd = BCM_GENL_CMD_MSG,
834 	.flags = 0,
835 	.policy = wl_genl_policy,
836 	.doit = wl_genl_handle_msg,
837 	.dumpit = NULL,
838 
839 };
840 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
841 
842 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
843 static struct genl_multicast_group wl_genl_mcast[] = {
844 	 { .name = "bcm-genl-mcast", },
845 };
846 #else
847 static struct genl_multicast_group wl_genl_mcast = {
848 	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
849 	.name = "bcm-genl-mcast",
850 };
851 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
852 #endif /* WL_GENL */
853 
854 #ifdef SUPPORT_LQCM
855 #define LQCM_ENAB_MASK			0x000000FF	/* LQCM enable flag mask */
856 #define LQCM_TX_INDEX_MASK		0x0000FF00	/* LQCM tx index mask */
857 #define LQCM_RX_INDEX_MASK		0x00FF0000	/* LQCM rx index mask */
858 
859 #define LQCM_TX_INDEX_SHIFT		8	/* LQCM tx index shift */
860 #define LQCM_RX_INDEX_SHIFT		16	/* LQCM rx index shift */
861 #endif /* SUPPORT_LQCM */
862 
863 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
864 #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS	7
865 static int priv_cmd_errors = 0;
866 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
867 
868 #ifdef WL_P2P_6G
869 #define CMD_ENABLE_6G_P2P	"ENABLE_6G_P2P"
870 #endif /* WL_P2P_6G */
871 
872 /**
873  * Extern function declarations (TODO: move them to dhd_linux.h)
874  */
875 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
876 int dhd_dev_init_ioctl(struct net_device *dev);
877 #ifdef WL_CFG80211
878 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
879 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
880 #ifdef WES_SUPPORT
881 int wl_cfg80211_set_wes_mode(struct net_device *dev, int mode);
882 int wl_cfg80211_get_wes_mode(struct net_device *dev);
883 int wl_cfg80211_set_ncho_mode(struct net_device *dev, int mode);
884 int wl_cfg80211_get_ncho_mode(struct net_device *dev);
885 #endif /* WES_SUPPORT */
886 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)887 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
888 { return 0; }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)889 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
890 { return 0; }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)891 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
892 { return 0; }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)893 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
894 { return 0; }
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)895 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
896 { return 0; }
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)897 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
898 { return 0; }
899 #endif /* WL_CFG80211 */
900 #if defined(WL_WTC) && defined(CUSTOMER_HW4_PRIVATE_CMD)
901 static int wl_android_wtc_config(struct net_device *dev, char *command, int total_len);
902 #endif /* WL_WTC && CUSTOMER_HW4_PRIVATE_CMD */
903 #ifdef WBTEXT
904 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
905 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
906 	char *command, int total_len);
907 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
908 	char *command, int total_len);
909 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
910 	char *command, int total_len);
911 static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
912 	uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size);
913 #ifdef WES_SUPPORT
914 static int wl_android_wbtext_enable(struct net_device *dev, int mode);
915 #endif // WES_SUPPORT
916 #endif /* WBTEXT */
917 #ifdef WES_SUPPORT
918 /* wl_roam.c */
919 extern int get_roamscan_mode(struct net_device *dev, int *mode);
920 extern int set_roamscan_mode(struct net_device *dev, int mode);
921 extern int get_roamscan_chanspec_list(struct net_device *dev, chanspec_t *chanspecs);
922 extern int set_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
923 extern int add_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
924 
925 static char* legacy_cmdlist[] =
926 {
927 	CMD_GETROAMSCANCHLEGACY, CMD_ADDROAMSCANCHLEGACY,
928 	CMD_GETROAMSCANFQLEGACY, CMD_ADDROAMSCANFQLEGACY,
929 	CMD_GETROAMTRIGLEGACY, CMD_SETROAMTRIGLEGACY,
930 	CMD_REASSOCLEGACY,
931 	CMD_GETSCANCHANNELTIMELEGACY, CMD_SETSCANCHANNELTIMELEGACY,
932 	CMD_GETSCANUNASSOCTIMELEGACY, CMD_SETSCANUNASSOCTIMELEGACY,
933 	CMD_GETSCANPASSIVETIMELEGACY, CMD_SETSCANPASSIVETIMELEGACY,
934 	CMD_GETSCANHOMETIMELEGACY, CMD_SETSCANHOMETIMELEGACY,
935 	CMD_GETSCANHOMEAWAYTIMELEGACY, CMD_SETSCANHOMEAWAYTIMELEGACY,
936 	"\0"
937 };
938 
939 static char* ncho_cmdlist[] =
940 {
941 	CMD_ROAMTRIGGER_GET, CMD_ROAMTRIGGER_SET,
942 	CMD_ROAMDELTA_GET, CMD_ROAMDELTA_SET,
943 	CMD_ROAMSCANPERIOD_GET, CMD_ROAMSCANPERIOD_SET,
944 	CMD_FULLROAMSCANPERIOD_GET, CMD_FULLROAMSCANPERIOD_SET,
945 	CMD_COUNTRYREV_GET, CMD_COUNTRYREV_SET,
946 	CMD_GETROAMSCANCONTROL,	CMD_SETROAMSCANCONTROL,
947 	CMD_GETROAMSCANCHANNELS, CMD_SETROAMSCANCHANNELS, CMD_ADDROAMSCANCHANNELS,
948 	CMD_GETROAMSCANFREQS, CMD_SETROAMSCANFREQS, CMD_ADDROAMSCANFREQS,
949 	CMD_SENDACTIONFRAME,
950 	CMD_REASSOC,
951 	CMD_GETSCANCHANNELTIME,	CMD_SETSCANCHANNELTIME,
952 	CMD_GETSCANUNASSOCTIME,	CMD_SETSCANUNASSOCTIME,
953 	CMD_GETSCANPASSIVETIME,	CMD_SETSCANPASSIVETIME,
954 	CMD_GETSCANHOMETIME, CMD_SETSCANHOMETIME,
955 	CMD_GETSCANHOMEAWAYTIME, CMD_SETSCANHOMEAWAYTIME,
956 	CMD_GETSCANNPROBES, CMD_SETSCANNPROBES,
957 	CMD_GETDFSSCANMODE, CMD_SETDFSSCANMODE,
958 	CMD_SETJOINPREFER,
959 	CMD_GETWESMODE,	CMD_SETWESMODE,
960 	"\0"
961 };
962 #endif /* WES_SUPPORT */
963 #ifdef ROAM_CHANNEL_CACHE
964 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
965 #endif /* ROAM_CHANNEL_CACHE */
966 
967 int wl_android_priority_roam_enable(struct net_device *dev, int mode);
968 #ifdef CONFIG_SILENT_ROAM
969 int wl_android_sroam_turn_on(struct net_device *dev, int mode);
970 #endif /* CONFIG_SILENT_ROAM */
971 int wl_android_rcroam_turn_on(struct net_device *dev, int mode);
972 
973 #ifdef ENABLE_4335BT_WAR
974 extern int bcm_bt_lock(int cookie);
975 extern void bcm_bt_unlock(int cookie);
976 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24;	/* cookie is "WiFi" */
977 #endif /* ENABLE_4335BT_WAR */
978 
979 extern bool ap_fw_loaded;
980 extern char iface_name[IFNAMSIZ];
981 #ifdef DHD_PM_CONTROL_FROM_FILE
982 extern bool g_pm_control;
983 #endif	/* DHD_PM_CONTROL_FROM_FILE */
984 
985 /* private command support for restoring roam/scan parameters */
986 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
987 #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
988 
989 typedef int (*PRIV_CMD_HANDLER) (struct net_device *dev, char *command);
990 typedef int (*PRIV_CMD_HANDLER_WITH_LEN) (struct net_device *dev, char *command, int total_len);
991 
992 enum {
993 	RESTORE_TYPE_UNSPECIFIED = 0,
994 	RESTORE_TYPE_PRIV_CMD = 1,
995 	RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
996 };
997 
998 typedef struct android_restore_scan_params {
999 	char command[64];
1000 	int parameter;
1001 	int cmd_type;
1002 	union {
1003 		PRIV_CMD_HANDLER cmd_handler;
1004 		PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
1005 	};
1006 } android_restore_scan_params_t;
1007 
1008 /* function prototypes of private command handler */
1009 static int wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len);
1010 static int wl_android_set_roam_trigger(struct net_device *dev, char* command);
1011 int wl_android_set_roam_delta(struct net_device *dev, char* command);
1012 int wl_android_set_roam_scan_period(struct net_device *dev, char* command);
1013 int wl_android_set_full_roam_scan_period(struct net_device *dev, char* command);
1014 int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
1015 int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
1016 int wl_android_set_scan_home_time(struct net_device *dev, char *command);
1017 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
1018 int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
1019 static int wl_android_set_band(struct net_device *dev, char *command);
1020 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
1021 int wl_android_set_wes_mode(struct net_device *dev, char *command);
1022 int wl_android_set_okc_mode(struct net_device *dev, char *command);
1023 
1024 /* default values */
1025 #ifdef ROAM_API
1026 #define DEFAULT_ROAM_TIRGGER	-75
1027 #define DEFAULT_ROAM_DELTA	10
1028 #define DEFAULT_ROAMSCANPERIOD	10
1029 #define DEFAULT_FULLROAMSCANPERIOD_SET	120
1030 #endif /* ROAM_API */
1031 #ifdef WES_SUPPORT
1032 #define DEFAULT_ROAMSCANCONTROL	0
1033 #define DEFAULT_SCANCHANNELTIME	40
1034 #ifdef BCM4361_CHIP
1035 #define DEFAULT_SCANHOMETIME	60
1036 #else
1037 #define DEFAULT_SCANHOMETIME	45
1038 #endif /* BCM4361_CHIP */
1039 #define DEFAULT_SCANHOMEAWAYTIME	100
1040 #define DEFAULT_SCANPROBES	2
1041 #define DEFAULT_DFSSCANMODE	1
1042 #define DEFAULT_WESMODE		0
1043 #define DEFAULT_OKCMODE		1
1044 #endif /* WES_SUPPORT */
1045 #define DEFAULT_BAND		0
1046 #ifdef WBTEXT
1047 #define DEFAULT_WBTEXT_ENABLE	1
1048 #endif /* WBTEXT */
1049 
1050 /* restoring parameter list, please don't change order */
1051 static android_restore_scan_params_t restore_params[] =
1052 {
1053 /* wbtext need to be disabled while updating roam/scan parameters */
1054 #ifdef WBTEXT
1055 	{ CMD_WBTEXT_ENABLE, 0, RESTORE_TYPE_PRIV_CMD_WITH_LEN,
1056 		.cmd_handler_w_len = wl_android_wbtext},
1057 #endif /* WBTEXT */
1058 #ifdef ROAM_API
1059 	{ CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER,
1060 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_trigger},
1061 	{ CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA,
1062 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_delta},
1063 	{ CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD,
1064 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_period},
1065 	{ CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
1066 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_full_roam_scan_period},
1067 #endif /* ROAM_API */
1068 #ifdef WES_SUPPORT
1069 	{ CMD_SETROAMSCANCONTROL, DEFAULT_ROAMSCANCONTROL,
1070 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_control},
1071 	{ CMD_SETSCANCHANNELTIME, DEFAULT_SCANCHANNELTIME,
1072 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time},
1073 	{ CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME,
1074 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time},
1075 	{ CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME,
1076 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time},
1077 	{ CMD_SETSCANNPROBES, DEFAULT_SCANPROBES,
1078 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes},
1079 	{ CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE,
1080 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode},
1081 	{ CMD_SETWESMODE, DEFAULT_WESMODE,
1082 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode},
1083 #endif /* WES_SUPPORT */
1084 	{ CMD_SETBAND, DEFAULT_BAND,
1085 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band},
1086 #ifdef WBTEXT
1087 	{ CMD_WBTEXT_ENABLE, DEFAULT_WBTEXT_ENABLE,
1088 		RESTORE_TYPE_PRIV_CMD_WITH_LEN, .cmd_handler_w_len = wl_android_wbtext},
1089 #endif /* WBTEXT */
1090 	{ "\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}
1091 };
1092 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
1093 
1094 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1095 #define CMD_GET_LATENCY_CRITICAL_DATA	"GET_LATENCY_CRT_DATA"
1096 #define CMD_SET_LATENCY_CRITICAL_DATA	"SET_LATENCY_CRT_DATA"
1097 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
1098 
1099 typedef struct android_priv_cmd_log_cfg_table {
1100 	char command[64];
1101 	int  enable;
1102 } android_priv_cmd_log_cfg_table_t;
1103 
1104 static android_priv_cmd_log_cfg_table_t loging_params[] = {
1105 	{CMD_GET_SNR, FALSE},
1106 #ifdef SUPPORT_LQCM
1107 	{CMD_GET_LQCM_REPORT, FALSE},
1108 #endif
1109 #ifdef WL_GET_CU
1110 	{CMD_GET_CHAN_UTIL, FALSE},
1111 #endif
1112 	{"\0", FALSE}
1113 };
1114 
1115 /**
1116  * Local (static) functions and variables
1117  */
1118 
1119 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
1120  * time (only) in dhd_open, subsequential wifi on will be handled by
1121  * wl_android_wifi_on
1122  */
1123 int g_wifi_on = TRUE;
1124 
1125 /**
1126  * Local (static) function definitions
1127  */
1128 
wl_android_get_band_str(u16 band)1129 static char* wl_android_get_band_str(u16 band)
1130 {
1131 	switch (band) {
1132 #ifdef WL_6G_BAND
1133 		case WLC_BAND_6G:
1134 			return "6G";
1135 #endif /* WL_6G_BAND */
1136 		case WLC_BAND_5G:
1137 			return "5G";
1138 		case WLC_BAND_2G:
1139 			return "2G";
1140 		default:
1141 			ANDROID_ERROR(("Unkown band: %d \n", band));
1142 			return "Unknown band";
1143 	}
1144 }
1145 
1146 #ifdef WBTEXT
wl_android_bandstr_to_fwband(char * band,u8 * fw_band)1147 static int wl_android_bandstr_to_fwband(char *band, u8 *fw_band)
1148 {
1149 	int err = BCME_OK;
1150 
1151 	if (!strcasecmp(band, "a")) {
1152 		*fw_band = WLC_BAND_5G;
1153 	} else if (!strcasecmp(band, "b")) {
1154 		*fw_band = WLC_BAND_2G;
1155 #ifdef WL_6G_BAND
1156 	} else if (!strcasecmp(band, "6g")) {
1157 		*fw_band = WLC_BAND_6G;
1158 #endif /* WL_6G_BAND */
1159 	} else if (!strcasecmp(band, "all")) {
1160 		*fw_band = WLC_BAND_ALL;
1161 	} else {
1162 		err = BCME_BADBAND;
1163 	}
1164 
1165 	return err;
1166 }
1167 #endif /* WBTEXT */
1168 
1169 #ifdef WLWFDS
wl_android_set_wfds_hash(struct net_device * dev,char * command,bool enable)1170 static int wl_android_set_wfds_hash(
1171 	struct net_device *dev, char *command, bool enable)
1172 {
1173 	int error = 0;
1174 	wl_p2p_wfds_hash_t *wfds_hash = NULL;
1175 	char *smbuf = NULL;
1176 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1177 
1178 	smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
1179 	if (smbuf == NULL) {
1180 		ANDROID_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n",
1181 			WLC_IOCTL_MAXLEN));
1182 		return -ENOMEM;
1183 	}
1184 
1185 	if (enable) {
1186 		wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
1187 		error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
1188 			sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1189 	}
1190 	else {
1191 		wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
1192 		error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
1193 			sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1194 	}
1195 
1196 	if (error) {
1197 		ANDROID_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error));
1198 	}
1199 
1200 	if (smbuf) {
1201 		MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
1202 	}
1203 	return error;
1204 }
1205 #endif /* WLWFDS */
1206 
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)1207 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
1208 {
1209 	int link_speed;
1210 	int bytes_written;
1211 	int error;
1212 
1213 	error = wldev_get_link_speed(net, &link_speed);
1214 	if (error) {
1215 		ANDROID_ERROR(("Get linkspeed failed \n"));
1216 		return -1;
1217 	}
1218 
1219 	/* Convert Kbps to Android Mbps */
1220 	link_speed = link_speed / 1000;
1221 	bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
1222 	ANDROID_INFO(("wl_android_get_link_speed: command result is %s\n", command));
1223 	return bytes_written;
1224 }
1225 
wl_android_get_rssi(struct net_device * net,char * command,int total_len)1226 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
1227 {
1228 	wlc_ssid_t ssid = {0, {0}};
1229 	int bytes_written = 0;
1230 	int error = 0;
1231 	scb_val_t scbval;
1232 	char *delim = NULL;
1233 	struct net_device *target_ndev = net;
1234 #ifdef WL_VIRTUAL_APSTA
1235 	char *pos = NULL;
1236 	struct bcm_cfg80211 *cfg;
1237 #endif /* WL_VIRTUAL_APSTA */
1238 
1239 	delim = strchr(command, ' ');
1240 	/* For Ap mode rssi command would be
1241 	 * driver rssi <sta_mac_addr>
1242 	 * for STA/GC mode
1243 	 * driver rssi
1244 	*/
1245 	if (delim) {
1246 		/* Ap/GO mode
1247 		* driver rssi <sta_mac_addr>
1248 		*/
1249 		ANDROID_TRACE(("wl_android_get_rssi: cmd:%s\n", delim));
1250 		/* skip space from delim after finding char */
1251 		delim++;
1252 		if (!(bcm_ether_atoe((delim), &scbval.ea))) {
1253 			ANDROID_ERROR(("wl_android_get_rssi: address err\n"));
1254 			return -1;
1255 		}
1256 		scbval.val = htod32(0);
1257 		ANDROID_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet)));
1258 #ifdef WL_VIRTUAL_APSTA
1259 		/* RSDB AP may have another virtual interface
1260 		 * In this case, format of private command is as following,
1261 		 * DRIVER rssi <sta_mac_addr> <AP interface name>
1262 		 */
1263 
1264 		/* Current position is start of MAC address string */
1265 		pos = delim;
1266 		delim = strchr(pos, ' ');
1267 		if (delim) {
1268 			/* skip space from delim after finding char */
1269 			delim++;
1270 			if (strnlen(delim, IFNAMSIZ)) {
1271 				cfg = wl_get_cfg(net);
1272 				target_ndev = wl_get_ap_netdev(cfg, delim);
1273 				if (target_ndev == NULL)
1274 					target_ndev = net;
1275 			}
1276 		}
1277 #endif /* WL_VIRTUAL_APSTA */
1278 	}
1279 	else {
1280 		/* STA/GC mode */
1281 		bzero(&scbval, sizeof(scb_val_t));
1282 	}
1283 
1284 	error = wldev_get_rssi(target_ndev, &scbval);
1285 	if (error)
1286 		return -1;
1287 #if defined(RSSIOFFSET)
1288 	scbval.val = wl_update_rssi_offset(net, scbval.val);
1289 #endif
1290 
1291 	error = wldev_get_ssid(target_ndev, &ssid);
1292 	if (error)
1293 		return -1;
1294 	if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
1295 		ANDROID_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n"));
1296 	} else if (total_len <= ssid.SSID_len) {
1297 		return -ENOMEM;
1298 	} else {
1299 		memcpy(command, ssid.SSID, ssid.SSID_len);
1300 		bytes_written = ssid.SSID_len;
1301 	}
1302 	if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
1303 		return -ENOMEM;
1304 
1305 	bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
1306 		" rssi %d", scbval.val);
1307 	command[bytes_written] = '\0';
1308 
1309 	ANDROID_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written));
1310 	return bytes_written;
1311 }
1312 
wl_android_set_suspendopt(struct net_device * dev,char * command)1313 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
1314 {
1315 	int suspend_flag;
1316 	int ret_now;
1317 	int ret = 0;
1318 
1319 	suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
1320 
1321 	if (suspend_flag != 0) {
1322 		suspend_flag = 1;
1323 	}
1324 	ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1325 
1326 	if (ret_now != suspend_flag) {
1327 		if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
1328 			ANDROID_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n",
1329 				ret_now, suspend_flag));
1330 		} else {
1331 			ANDROID_ERROR(("wl_android_set_suspendopt: failed %d\n", ret));
1332 		}
1333 	}
1334 
1335 	return ret;
1336 }
1337 
wl_android_set_suspendmode(struct net_device * dev,char * command)1338 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
1339 {
1340 	int ret = 0;
1341 
1342 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
1343 	int suspend_flag;
1344 
1345 	suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
1346 	if (suspend_flag != 0)
1347 		suspend_flag = 1;
1348 
1349 	if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
1350 		ANDROID_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag));
1351 	else
1352 		ANDROID_ERROR(("wl_android_set_suspendmode: failed %d\n", ret));
1353 #endif
1354 
1355 	return ret;
1356 }
1357 
1358 #ifdef WL_CFG80211
wl_android_get_80211_mode(struct net_device * dev,char * command,int total_len)1359 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
1360 {
1361 	uint8 mode[5];
1362 	int  error = 0;
1363 	int bytes_written = 0;
1364 
1365 	error = wldev_get_mode(dev, mode, sizeof(mode));
1366 	if (error)
1367 		return -1;
1368 
1369 	ANDROID_INFO(("wl_android_get_80211_mode: mode:%s\n", mode));
1370 	bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
1371 	ANDROID_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command));
1372 	return bytes_written;
1373 
1374 }
1375 
1376 extern chanspec_t
1377 wl_chspec_driver_to_host(chanspec_t chanspec);
wl_android_get_chanspec(struct net_device * dev,char * command,int total_len)1378 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
1379 {
1380 	int error = 0;
1381 	int bytes_written = 0;
1382 	int chsp = {0};
1383 	uint16 band = 0;
1384 	uint16 bw = 0;
1385 	uint16 channel = 0;
1386 	u32 sb = 0;
1387 	chanspec_t chanspec;
1388 
1389 	/* command is
1390 	 * driver chanspec
1391 	 */
1392 	error = wldev_iovar_getint(dev, "chanspec", &chsp);
1393 	if (error)
1394 		return -1;
1395 
1396 	chanspec = wl_chspec_driver_to_host(chsp);
1397 	ANDROID_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec));
1398 
1399 	channel = chanspec & WL_CHANSPEC_CHAN_MASK;
1400 	band = chanspec & WL_CHANSPEC_BAND_MASK;
1401 	bw = chanspec & WL_CHANSPEC_BW_MASK;
1402 
1403 	ANDROID_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n",
1404 		channel, band, bw));
1405 
1406 	if (bw == WL_CHANSPEC_BW_160) {
1407 		bw = WL_CH_BANDWIDTH_160MHZ;
1408 	} else if (bw == WL_CHANSPEC_BW_80) {
1409 		bw = WL_CH_BANDWIDTH_80MHZ;
1410 	} else if (bw == WL_CHANSPEC_BW_40) {
1411 		bw = WL_CH_BANDWIDTH_40MHZ;
1412 	} else if (bw == WL_CHANSPEC_BW_20) {
1413 		bw = WL_CH_BANDWIDTH_20MHZ;
1414 	} else {
1415 		bw = WL_CH_BANDWIDTH_20MHZ;
1416 	}
1417 
1418 	if (bw == WL_CH_BANDWIDTH_40MHZ) {
1419 		if (CHSPEC_SB_UPPER(chanspec)) {
1420 			channel += CH_10MHZ_APART;
1421 		} else {
1422 			channel -= CH_10MHZ_APART;
1423 		}
1424 	}
1425 	else if (bw == WL_CH_BANDWIDTH_80MHZ) {
1426 		sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
1427 		if (sb == WL_CHANSPEC_CTL_SB_LL) {
1428 			channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
1429 		} else if (sb == WL_CHANSPEC_CTL_SB_LU) {
1430 			channel -= CH_10MHZ_APART;
1431 		} else if (sb == WL_CHANSPEC_CTL_SB_UL) {
1432 			channel += CH_10MHZ_APART;
1433 		} else {
1434 			/* WL_CHANSPEC_CTL_SB_UU */
1435 			channel += (CH_10MHZ_APART + CH_20MHZ_APART);
1436 		}
1437 	} else if (bw == WL_CH_BANDWIDTH_160MHZ) {
1438 		channel = wf_chspec_primary20_chan(chanspec);
1439 	}
1440 	bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
1441 		channel, wl_android_get_band_str(CHSPEC2WLC_BAND(chanspec)), bw);
1442 
1443 	ANDROID_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command));
1444 	return bytes_written;
1445 
1446 }
1447 #endif /* WL_CFG80211 */
1448 
1449 /* returns current datarate datarate returned from firmware are in 500kbps */
wl_android_get_datarate(struct net_device * dev,char * command,int total_len)1450 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
1451 {
1452 	int  error = 0;
1453 	int datarate = 0;
1454 	int bytes_written = 0;
1455 
1456 	error = wldev_get_datarate(dev, &datarate);
1457 	if (error)
1458 		return -1;
1459 
1460 	ANDROID_INFO(("wl_android_get_datarate: datarate:%d\n", datarate));
1461 
1462 	bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
1463 	return bytes_written;
1464 }
wl_android_get_assoclist(struct net_device * dev,char * command,int total_len)1465 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
1466 {
1467 	int  error = 0;
1468 	int bytes_written = 0;
1469 	uint i;
1470 	int len = 0;
1471 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
1472 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
1473 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1474 
1475 	ANDROID_TRACE(("wl_android_get_assoclist: ENTER\n"));
1476 
1477 	assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
1478 
1479 	error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
1480 	if (error)
1481 		return -1;
1482 
1483 	assoc_maclist->count = dtoh32(assoc_maclist->count);
1484 	bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
1485 		CMD_ASSOC_CLIENTS, assoc_maclist->count);
1486 
1487 	for (i = 0; i < assoc_maclist->count; i++) {
1488 		len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
1489 			MAC2STRDBG(assoc_maclist->ea[i].octet));
1490 		/* A return value of '(total_len - bytes_written)' or more means that the
1491 		 * output was truncated
1492 		 */
1493 		if ((len > 0) && (len < (total_len - bytes_written))) {
1494 			bytes_written += len;
1495 		} else {
1496 			ANDROID_ERROR(("wl_android_get_assoclist: Insufficient buffer %d,"
1497 				" bytes_written %d\n",
1498 				total_len, bytes_written));
1499 			bytes_written = -1;
1500 			break;
1501 		}
1502 	}
1503 	return bytes_written;
1504 }
1505 
1506 #ifdef WL_CFG80211
1507 extern chanspec_t
1508 wl_chspec_host_to_driver(chanspec_t chanspec);
wl_android_set_csa(struct net_device * dev,char * command)1509 static int wl_android_set_csa(struct net_device *dev, char *command)
1510 {
1511 	int error = 0;
1512 	char smbuf[WLC_IOCTL_SMLEN];
1513 	wl_chan_switch_t csa_arg;
1514 	u32 chnsp = 0;
1515 	int err = 0;
1516 
1517 	ANDROID_INFO(("wl_android_set_csa: command:%s\n", command));
1518 
1519 	command = (command + strlen(CMD_SET_CSA));
1520 	/* Order is mode, count channel */
1521 	if (!*++command) {
1522 		ANDROID_ERROR(("wl_android_set_csa:error missing arguments\n"));
1523 		return -1;
1524 	}
1525 	csa_arg.mode = bcm_atoi(command);
1526 
1527 	if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1528 		ANDROID_ERROR(("Invalid mode\n"));
1529 		return -1;
1530 	}
1531 
1532 	if (!*++command) {
1533 		ANDROID_ERROR(("wl_android_set_csa: error missing count\n"));
1534 		return -1;
1535 	}
1536 	command++;
1537 	csa_arg.count = bcm_atoi(command);
1538 
1539 	csa_arg.reg = 0;
1540 	csa_arg.chspec = 0;
1541 	command += 2;
1542 	if (!*command) {
1543 		ANDROID_ERROR(("wl_android_set_csa: error missing channel\n"));
1544 		return -1;
1545 	}
1546 
1547 	chnsp = wf_chspec_aton(command);
1548 	if (chnsp == 0)	{
1549 		ANDROID_ERROR(("wl_android_set_csa:chsp is not correct\n"));
1550 		return -1;
1551 	}
1552 	chnsp = wl_chspec_host_to_driver(chnsp);
1553 	csa_arg.chspec = chnsp;
1554 
1555 	if (chnsp & WL_CHANSPEC_BAND_5G) {
1556 		u32 chanspec = chnsp;
1557 		err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1558 		if (!err) {
1559 			if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1560 				ANDROID_ERROR(("Channel is radar sensitive\n"));
1561 				return -1;
1562 			}
1563 			if (chanspec == 0) {
1564 				ANDROID_ERROR(("Invalid hw channel\n"));
1565 				return -1;
1566 			}
1567 		} else  {
1568 			ANDROID_ERROR(("does not support per_chan_info\n"));
1569 			return -1;
1570 		}
1571 		ANDROID_INFO(("non radar sensitivity\n"));
1572 	}
1573 	error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
1574 		smbuf, sizeof(smbuf), NULL);
1575 	if (error) {
1576 		ANDROID_ERROR(("wl_android_set_csa:set csa failed:%d\n", error));
1577 		return -1;
1578 	}
1579 	return 0;
1580 }
1581 #endif /* WL_CFG80211 */
1582 
1583 static int
wl_android_set_bcn_li_dtim(struct net_device * dev,char * command)1584 wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1585 {
1586 	int ret = 0;
1587 	int dtim;
1588 
1589 	dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1590 
1591 	if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1592 		ANDROID_ERROR(("%s: failed, invalid dtim %d\n",
1593 			__FUNCTION__, dtim));
1594 		return BCME_ERROR;
1595 	}
1596 
1597 	if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1598 		ANDROID_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
1599 			__FUNCTION__, dtim));
1600 	} else {
1601 		ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1602 	}
1603 
1604 	return ret;
1605 }
1606 
1607 static int
wl_android_set_max_dtim(struct net_device * dev,char * command)1608 wl_android_set_max_dtim(struct net_device *dev, char *command)
1609 {
1610 	int ret = 0;
1611 	int dtim_flag;
1612 
1613 	dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1614 
1615 	if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1616 		ANDROID_TRACE(("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n",
1617 			(dtim_flag ? "Enable" : "Disable")));
1618 	} else {
1619 		ANDROID_ERROR(("wl_android_set_max_dtim: failed %d\n", ret));
1620 	}
1621 
1622 	return ret;
1623 }
1624 
1625 #ifdef DISABLE_DTIM_IN_SUSPEND
1626 static int
wl_android_set_disable_dtim_in_suspend(struct net_device * dev,char * command)1627 wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command)
1628 {
1629 	int ret = 0;
1630 	int dtim_flag;
1631 
1632 	dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
1633 
1634 	if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
1635 		ANDROID_TRACE(("wl_android_set_disable_dtim_in_suspend: "
1636 			"use Disable bcn_li_dtim in suspend %s\n",
1637 			(dtim_flag ? "Enable" : "Disable")));
1638 	} else {
1639 		ANDROID_ERROR(("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret));
1640 	}
1641 
1642 	return ret;
1643 }
1644 #endif /* DISABLE_DTIM_IN_SUSPEND */
1645 
wl_android_get_band(struct net_device * dev,char * command,int total_len)1646 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
1647 {
1648 	uint band;
1649 	int bytes_written;
1650 	int error = BCME_OK;
1651 
1652 	error = wldev_iovar_getint(dev, "if_band", &band);
1653 	if (error == BCME_UNSUPPORTED) {
1654 		error = wldev_get_band(dev, &band);
1655 		if (error) {
1656 			return error;
1657 		}
1658 	}
1659 	bytes_written = snprintf(command, total_len, "Band %d", band);
1660 	return bytes_written;
1661 }
1662 
1663 #ifdef WL_CFG80211
1664 static int
wl_android_set_band(struct net_device * dev,char * command)1665 wl_android_set_band(struct net_device *dev, char *command)
1666 {
1667 	int error = 0;
1668 	uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1669 #ifdef WL_HOST_BAND_MGMT
1670 	int ret = 0;
1671 	if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
1672 		if (ret == BCME_UNSUPPORTED) {
1673 			/* If roam_var is unsupported, fallback to the original method */
1674 			ANDROID_ERROR(("WL_HOST_BAND_MGMT defined, "
1675 				"but roam_band iovar unsupported in the firmware\n"));
1676 		} else {
1677 			error = -1;
1678 		}
1679 	}
1680 	if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
1681 		/* Apply if roam_band iovar is not supported or band setting is AUTO */
1682 		error = wldev_set_band(dev, band);
1683 	}
1684 #else
1685 	error = wl_cfg80211_set_if_band(dev, band);
1686 #endif /* WL_HOST_BAND_MGMT */
1687 #ifdef ROAM_CHANNEL_CACHE
1688 	wl_update_roamscan_cache_by_band(dev, band);
1689 #endif /* ROAM_CHANNEL_CACHE */
1690 	return error;
1691 }
1692 #endif /* WL_CFG80211 */
1693 
1694 #ifdef CUSTOMER_HW4_PRIVATE_CMD
1695 #ifdef ROAM_API
1696 static bool
wl_android_check_wbtext_policy(struct net_device * dev)1697 wl_android_check_wbtext_policy(struct net_device *dev)
1698 {
1699 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1700 	if (dhdp->wbtext_policy == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
1701 		return TRUE;
1702 	}
1703 
1704 	return FALSE;
1705 }
1706 
1707 static int
wl_android_set_roam_trigger(struct net_device * dev,char * command)1708 wl_android_set_roam_trigger(struct net_device *dev, char* command)
1709 {
1710 	int roam_trigger[2] = {0, 0};
1711 	int error;
1712 
1713 #ifdef WBTEXT
1714 	if (wl_android_check_wbtext_policy(dev)) {
1715 		ANDROID_ERROR(("blocked to set roam trigger. try with setting roam profile\n"));
1716 		return BCME_ERROR;
1717 	}
1718 #endif /* WBTEXT */
1719 
1720 	sscanf(command, "%*s %10d", &roam_trigger[0]);
1721 	if (roam_trigger[0] >= 0) {
1722 		ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1723 		return BCME_ERROR;
1724 	}
1725 
1726 	roam_trigger[1] = WLC_BAND_ALL;
1727 	error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1728 		sizeof(roam_trigger));
1729 	if (error != BCME_OK) {
1730 		ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1731 		return BCME_ERROR;
1732 	}
1733 
1734 	return BCME_OK;
1735 }
1736 
1737 static int
wl_android_get_roam_trigger(struct net_device * dev,char * command,int total_len)1738 wl_android_get_roam_trigger(struct net_device *dev, char *command, int total_len)
1739 {
1740 	int bytes_written, error;
1741 	int roam_trigger[2] = {0, 0};
1742 	uint16 band = 0;
1743 	int chsp = {0};
1744 	chanspec_t chanspec;
1745 #ifdef WBTEXT
1746 	int i;
1747 	wl_roamprof_band_t rp;
1748 	uint8 roam_prof_ver = 0, roam_prof_size = 0;
1749 #endif /* WBTEXT */
1750 
1751 	error = wldev_iovar_getint(dev, "chanspec", &chsp);
1752 	if (error != BCME_OK) {
1753 		ANDROID_ERROR(("failed to get chanspec (%d)\n", error));
1754 		return BCME_ERROR;
1755 	}
1756 
1757 	chanspec = wl_chspec_driver_to_host(chsp);
1758 	band = CHSPEC2WLC_BAND(chanspec);
1759 
1760 	if (wl_android_check_wbtext_policy(dev)) {
1761 #ifdef WBTEXT
1762 		memset_s(&rp, sizeof(rp), 0, sizeof(rp));
1763 		if ((error = wlc_wbtext_get_roam_prof(dev, &rp, band, &roam_prof_ver,
1764 			&roam_prof_size))) {
1765 			ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", error));
1766 			return -EINVAL;
1767 		}
1768 		switch (roam_prof_ver) {
1769 			case WL_ROAM_PROF_VER_1:
1770 			{
1771 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1772 					if (rp.v2.roam_prof[i].channel_usage == 0) {
1773 						roam_trigger[0] = rp.v2.roam_prof[i].roam_trigger;
1774 						break;
1775 					}
1776 				}
1777 			}
1778 			break;
1779 			case WL_ROAM_PROF_VER_2:
1780 			{
1781 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1782 					if (rp.v3.roam_prof[i].channel_usage == 0) {
1783 						roam_trigger[0] = rp.v3.roam_prof[i].roam_trigger;
1784 						break;
1785 					}
1786 				}
1787 			}
1788 			break;
1789 			case WL_ROAM_PROF_VER_3:
1790 			{
1791 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1792 					if (rp.v4.roam_prof[i].channel_usage == 0) {
1793 						roam_trigger[0] = rp.v4.roam_prof[i].roam_trigger;
1794 						break;
1795 					}
1796 				}
1797 			}
1798 			break;
1799 			default:
1800 				ANDROID_ERROR(("bad version = %d \n", roam_prof_ver));
1801 				return BCME_VERSION;
1802 		}
1803 #endif /* WBTEXT */
1804 		if (roam_trigger[0] == 0) {
1805 			ANDROID_ERROR(("roam trigger was not set properly\n"));
1806 			return BCME_ERROR;
1807 		}
1808 	} else {
1809 		roam_trigger[1] = band;
1810 		error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
1811 			sizeof(roam_trigger));
1812 		if (error != BCME_OK) {
1813 			ANDROID_ERROR(("failed to get roam trigger (%d)\n", error));
1814 			return BCME_ERROR;
1815 		}
1816 	}
1817 
1818 	bytes_written = snprintf(command, total_len, "%s %d",
1819 		CMD_ROAMTRIGGER_GET, roam_trigger[0]);
1820 
1821 	return bytes_written;
1822 }
1823 
1824 #ifdef WBTEXT
1825 s32
wl_cfg80211_wbtext_roam_trigger_config(struct net_device * ndev,int roam_trigger)1826 wl_cfg80211_wbtext_roam_trigger_config(struct net_device *ndev, int roam_trigger)
1827 {
1828 	char *commandp = NULL;
1829 	s32 ret = BCME_OK;
1830 	char *data;
1831 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1832 	uint8 bandidx = 0;
1833 
1834 	commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
1835 	if (unlikely(!commandp)) {
1836 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
1837 		ret =  -ENOMEM;
1838 		goto exit;
1839 	}
1840 
1841 	ANDROID_INFO(("roam trigger %d\n", roam_trigger));
1842 	if (roam_trigger > 0) {
1843 		ANDROID_ERROR(("Invalid roam trigger value %d\n", roam_trigger));
1844 		goto exit;
1845 	}
1846 
1847 	for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
1848 		char *band;
1849 		int tri0, tri1, low0, low1, cu0, cu1, dur0, dur1;
1850 		int tri0_dflt;
1851 		if (bandidx == BAND_5G_INDEX) {
1852 			band = "a";
1853 			tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_A;
1854 		} else {
1855 			band = "b";
1856 			tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_B;
1857 		}
1858 
1859 		/* Get ROAM Profile
1860 		 * WBTEXT_PROFILE_CONFIG band
1861 		 */
1862 		bzero(commandp, WLC_IOCTL_SMLEN);
1863 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
1864 			CMD_WBTEXT_PROFILE_CONFIG, band);
1865 		data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
1866 		wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1867 
1868 		/* Set ROAM Profile
1869 		 * WBTEXT_PROFILE_CONFIG band -70 roam_trigger 70 10 roam_trigger -128 0 10
1870 		 */
1871 		sscanf(commandp, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)"
1872 			"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
1873 			&tri0, &low0, &cu0, &dur0, &tri1, &low1, &cu1, &dur1);
1874 
1875 		if (tri0_dflt <= roam_trigger) {
1876 			tri0 = roam_trigger + 1;
1877 		} else {
1878 			tri0 = tri0_dflt;
1879 		}
1880 
1881 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
1882 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s %d %d %d %d %d %d %d %d",
1883 			CMD_WBTEXT_PROFILE_CONFIG, band,
1884 			tri0, roam_trigger, cu0, dur0, roam_trigger, low1, cu1, dur1);
1885 
1886 		ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1887 		if (ret != BCME_OK) {
1888 			ANDROID_ERROR(("Failed to set roam_prof %s error = %d\n", data, ret));
1889 			goto exit;
1890 		}
1891 	}
1892 
1893 exit:
1894 	if (commandp) {
1895 		MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
1896 	}
1897 	return ret;
1898 }
1899 #endif /* WBTEXT */
1900 
1901 static int
wl_android_set_roam_trigger_legacy(struct net_device * dev,char * command)1902 wl_android_set_roam_trigger_legacy(struct net_device *dev, char* command)
1903 {
1904 	int roam_trigger[2] = {0, 0};
1905 	int error;
1906 
1907 	sscanf(command, "%*s %10d", &roam_trigger[0]);
1908 	if (roam_trigger[0] >= 0) {
1909 		ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1910 		return BCME_ERROR;
1911 	}
1912 
1913 	if (wl_android_check_wbtext_policy(dev)) {
1914 #ifdef WBTEXT
1915 		error = wl_cfg80211_wbtext_roam_trigger_config(dev, roam_trigger[0]);
1916 		if (error != BCME_OK) {
1917 			ANDROID_ERROR(("failed to set roam prof trigger (%d)\n", error));
1918 			return BCME_ERROR;
1919 		}
1920 #endif /* WBTEXT */
1921 	} else {
1922 		if (roam_trigger[0] >= 0) {
1923 			ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1924 			return BCME_ERROR;
1925 		}
1926 
1927 		roam_trigger[1] = WLC_BAND_ALL;
1928 		error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1929 			sizeof(roam_trigger));
1930 		if (error != BCME_OK) {
1931 			ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1932 			return BCME_ERROR;
1933 		}
1934 	}
1935 
1936 	return BCME_OK;
1937 }
1938 
wl_android_set_roam_delta(struct net_device * dev,char * command)1939 int wl_android_set_roam_delta(
1940 	struct net_device *dev, char* command)
1941 {
1942 	int roam_delta[2];
1943 
1944 	sscanf(command, "%*s %10d", &roam_delta[0]);
1945 	roam_delta[1] = WLC_BAND_ALL;
1946 
1947 	return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
1948 		sizeof(roam_delta));
1949 }
1950 
wl_android_get_roam_delta(struct net_device * dev,char * command,int total_len)1951 static int wl_android_get_roam_delta(
1952 	struct net_device *dev, char *command, int total_len)
1953 {
1954 	int bytes_written;
1955 	int roam_delta[2] = {0, 0};
1956 
1957 	roam_delta[1] = WLC_BAND_2G;
1958 	if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1959 		sizeof(roam_delta))) {
1960 		roam_delta[1] = WLC_BAND_5G;
1961 #ifdef WL_6G_BAND
1962 		if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1963 			sizeof(roam_delta))) {
1964 			roam_delta[1] = WLC_BAND_6G;
1965 #endif /* WL_6G_BAND */
1966 			if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1967 				sizeof(roam_delta))) {
1968 				return -1;
1969 			}
1970 #ifdef WL_6G_BAND
1971 		}
1972 #endif /* WL_6G_BAND */
1973 	}
1974 
1975 	bytes_written = snprintf(command, total_len, "%s %d",
1976 		CMD_ROAMDELTA_GET, roam_delta[0]);
1977 
1978 	return bytes_written;
1979 }
1980 
wl_android_set_roam_scan_period(struct net_device * dev,char * command)1981 int wl_android_set_roam_scan_period(
1982 	struct net_device *dev, char* command)
1983 {
1984 	int roam_scan_period = 0;
1985 
1986 	sscanf(command, "%*s %10d", &roam_scan_period);
1987 	return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
1988 		sizeof(roam_scan_period));
1989 }
1990 
wl_android_get_roam_scan_period(struct net_device * dev,char * command,int total_len)1991 static int wl_android_get_roam_scan_period(
1992 	struct net_device *dev, char *command, int total_len)
1993 {
1994 	int bytes_written;
1995 	int roam_scan_period = 0;
1996 
1997 	if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
1998 		sizeof(roam_scan_period)))
1999 		return -1;
2000 
2001 	bytes_written = snprintf(command, total_len, "%s %d",
2002 		CMD_ROAMSCANPERIOD_GET, roam_scan_period);
2003 
2004 	return bytes_written;
2005 }
2006 
wl_android_set_full_roam_scan_period(struct net_device * dev,char * command)2007 int wl_android_set_full_roam_scan_period(
2008 	struct net_device *dev, char* command)
2009 {
2010 	int error = 0;
2011 	int full_roam_scan_period = 0;
2012 	char smbuf[WLC_IOCTL_SMLEN];
2013 
2014 	sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
2015 	WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
2016 
2017 	error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
2018 		sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
2019 	if (error) {
2020 		ANDROID_ERROR(("Failed to set full roam scan period, error = %d\n", error));
2021 	}
2022 
2023 	return error;
2024 }
2025 
wl_android_get_full_roam_scan_period(struct net_device * dev,char * command,int total_len)2026 static int wl_android_get_full_roam_scan_period(
2027 	struct net_device *dev, char *command, int total_len)
2028 {
2029 	int error;
2030 	int bytes_written;
2031 	int full_roam_scan_period = 0;
2032 
2033 	error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
2034 
2035 	if (error) {
2036 		ANDROID_ERROR(("%s: get full roam scan period failed code %d\n",
2037 			__func__, error));
2038 		return -1;
2039 	} else {
2040 		ANDROID_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
2041 	}
2042 
2043 	bytes_written = snprintf(command, total_len, "%s %d",
2044 		CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
2045 
2046 	return bytes_written;
2047 }
2048 
wl_android_set_country_rev(struct net_device * dev,char * command)2049 int wl_android_set_country_rev(
2050 	struct net_device *dev, char* command)
2051 {
2052 	int error = 0;
2053 	wl_country_t cspec = {{0}, 0, {0} };
2054 	char country_code[WLC_CNTRY_BUF_SZ];
2055 	char smbuf[WLC_IOCTL_SMLEN];
2056 	int rev = 0;
2057 
2058 	bzero(country_code, sizeof(country_code));
2059 	sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
2060 	WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
2061 
2062 	memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
2063 	memcpy(cspec.ccode, country_code, sizeof(country_code));
2064 	cspec.rev = rev;
2065 
2066 	error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
2067 		sizeof(cspec), smbuf, sizeof(smbuf), NULL);
2068 
2069 	if (error) {
2070 		ANDROID_ERROR(("wl_android_set_country_rev: set country '%s/%d' failed code %d\n",
2071 			cspec.ccode, cspec.rev, error));
2072 	} else {
2073 		dhd_bus_country_set(dev, &cspec, true);
2074 		ANDROID_INFO(("wl_android_set_country_rev: set country '%s/%d'\n",
2075 			cspec.ccode, cspec.rev));
2076 	}
2077 
2078 	return error;
2079 }
2080 
wl_android_get_country_rev(struct net_device * dev,char * command,int total_len)2081 static int wl_android_get_country_rev(
2082 	struct net_device *dev, char *command, int total_len)
2083 {
2084 	int error;
2085 	int bytes_written;
2086 	char smbuf[WLC_IOCTL_SMLEN];
2087 	wl_country_t cspec;
2088 
2089 	error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
2090 		sizeof(smbuf), NULL);
2091 
2092 	if (error) {
2093 		ANDROID_ERROR(("wl_android_get_country_rev: get country failed code %d\n",
2094 			error));
2095 		return -1;
2096 	} else {
2097 		memcpy(&cspec, smbuf, sizeof(cspec));
2098 		ANDROID_INFO(("wl_android_get_country_rev: get country '%c%c %d'\n",
2099 			cspec.ccode[0], cspec.ccode[1], cspec.rev));
2100 	}
2101 
2102 	bytes_written = snprintf(command, total_len, "%s %c%c %d",
2103 		CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
2104 
2105 	return bytes_written;
2106 }
2107 #endif /* ROAM_API */
2108 
2109 #ifdef WES_SUPPORT
wl_android_get_roam_scan_control(struct net_device * dev,char * command,int total_len)2110 int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
2111 {
2112 	int error = 0;
2113 	int bytes_written = 0;
2114 	int mode = 0;
2115 
2116 	error = get_roamscan_mode(dev, &mode);
2117 	if (error) {
2118 		ANDROID_ERROR(("wl_android_get_roam_scan_control: Failed to get Scan Control,"
2119 			" error = %d\n", error));
2120 		return -1;
2121 	}
2122 
2123 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
2124 
2125 	return bytes_written;
2126 }
2127 
wl_android_set_roam_scan_control(struct net_device * dev,char * command)2128 int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
2129 {
2130 	int error = 0;
2131 	int mode = 0;
2132 
2133 	if (sscanf(command, "%*s %d", &mode) != 1) {
2134 		ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to get Parameter\n"));
2135 		return -1;
2136 	}
2137 
2138 	error = set_roamscan_mode(dev, mode);
2139 	if (error) {
2140 		ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to set Scan Control %d,"
2141 		" error = %d\n",
2142 		 mode, error));
2143 		return -1;
2144 	}
2145 
2146 	return 0;
2147 }
2148 
2149 int
wl_android_get_roam_scan_channels(struct net_device * dev,char * command,int total_len,char * cmd)2150 wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len, char *cmd)
2151 {
2152 	int bytes_written = 0;
2153 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2154 	int nchan = 0, i = 0;
2155 	int buf_avail, len;
2156 
2157 	nchan = get_roamscan_chanspec_list(dev, chanspecs);
2158 	if (nchan < 0) {
2159 		ANDROID_ERROR(("Failed to Set roamscan channels, n_chan = %d\n", nchan));
2160 		return BCME_ERROR;
2161 	}
2162 
2163 	bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2164 
2165 	buf_avail = total_len - bytes_written;
2166 	for (i = 0; i < nchan; i++) {
2167 		/* A return value of 'buf_avail' or more means that the output was truncated */
2168 		len = snprintf(command + bytes_written, buf_avail, " %d",
2169 			CHSPEC_CHANNEL(chanspecs[i]));
2170 		if (len >= buf_avail) {
2171 			ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2172 			ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2173 			bytes_written = -1;
2174 			break;
2175 		}
2176 		/* 'buf_avail' decremented by number of bytes written */
2177 		buf_avail -= len;
2178 		bytes_written += len;
2179 	}
2180 	ANDROID_INFO(("%s\n", command));
2181 	return bytes_written;
2182 }
2183 
2184 #define CHANNEL_IDX	1
2185 int
wl_android_set_roam_scan_channels(struct net_device * dev,char * command)2186 wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
2187 {
2188 	int error = BCME_OK, i;
2189 	unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
2190 	uint16 nchan = 0, channel = 0;
2191 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2192 
2193 	nchan = p[0];
2194 	if (nchan > MAX_ROAM_CHANNEL) {
2195 		ANDROID_ERROR(("Failed to Set roamscan channnels, n_chan = %d\n", nchan));
2196 		return BCME_BADARG;
2197 	}
2198 
2199 	for (i = 0; i < nchan; i++) {
2200 		channel = p[i + CHANNEL_IDX];
2201 		/* Convert chanspec from channel */
2202 		chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2203 	}
2204 
2205 	error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2206 	if (error) {
2207 		ANDROID_ERROR(("Failed to Set Scan Channels %d, error = %d\n", p[0], error));
2208 		return error;
2209 	}
2210 
2211 	return error;
2212 }
2213 
2214 int
wl_android_add_roam_scan_channels(struct net_device * dev,char * command,uint cmdlen)2215 wl_android_add_roam_scan_channels(struct net_device *dev, char *command, uint cmdlen)
2216 {
2217 	int i, error = BCME_OK;
2218 	char *pcmd, *token;
2219 	uint16 nchan = 0, channel = 0;
2220 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2221 
2222 	pcmd = (command + cmdlen + 1);
2223 	/* Parse roam channel count */
2224 	token = bcmstrtok(&pcmd, " ", NULL);
2225 	if (!token) {
2226 		ANDROID_ERROR(("Bad argument!\n"));
2227 		return BCME_BADARG;
2228 	}
2229 	nchan = bcm_atoi(token);
2230 	if (nchan > MAX_ROAM_CHANNEL) {
2231 		ANDROID_ERROR(("Failed to Add roamscan channnels, n_chan = %d\n", nchan));
2232 		return BCME_BADARG;
2233 	}
2234 
2235 	for (i = 0; i < nchan; i++) {
2236 		/* Parse roam channel list */
2237 		token = bcmstrtok(&pcmd, " ", NULL);
2238 		if (!token) {
2239 			ANDROID_ERROR(("Bad argument!\n"));
2240 			return BCME_BADARG;
2241 		}
2242 		channel = bcm_atoi(token);
2243 		/* Convert chanspec from channel */
2244 		if (channel > 0) {
2245 			chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2246 		}
2247 	}
2248 
2249 	error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2250 	if (error) {
2251 		ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2252 	}
2253 
2254 	return error;
2255 }
2256 
2257 int
wl_android_get_roam_scan_freqs(struct net_device * dev,char * command,int total_len,char * cmd)2258 wl_android_get_roam_scan_freqs(struct net_device *dev, char *command, int total_len, char *cmd)
2259 {
2260 	int bytes_written = 0;
2261 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2262 	int nchan = 0, i = 0;
2263 	int buf_avail, len;
2264 	u32 freq = 0;
2265 	uint start_factor = 0;
2266 
2267 	nchan = get_roamscan_chanspec_list(dev, chanspecs);
2268 	if (nchan < 0) {
2269 		ANDROID_ERROR(("Failed to Get roamscan frequencies, n_chan = %d\n", nchan));
2270 		return BCME_ERROR;
2271 	}
2272 
2273 	bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2274 
2275 	buf_avail = total_len - bytes_written;
2276 	for (i = 0; i < nchan; i++) {
2277 		start_factor = WF_CHAN_FACTOR_2_4_G;
2278 		if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_5G) {
2279 			start_factor = WF_CHAN_FACTOR_5_G;
2280 		} else if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_6G) {
2281 			start_factor = WF_CHAN_FACTOR_6_G;
2282 		}
2283 		freq = wf_channel2mhz(CHSPEC_CHANNEL(chanspecs[i]), start_factor);
2284 		/* A return value of 'buf_avail' or more means that the output was truncated */
2285 		len = snprintf(command + bytes_written, buf_avail, " %d", freq);
2286 		if (len >= buf_avail) {
2287 			ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2288 			bytes_written = -1;
2289 			break;
2290 		}
2291 		/* 'buf_avail' decremented by number of bytes written */
2292 		buf_avail -= len;
2293 		bytes_written += len;
2294 	}
2295 	ANDROID_INFO(("%s\n", command));
2296 	return bytes_written;
2297 }
2298 
2299 int
wl_android_set_roam_scan_freqs(struct net_device * dev,char * command)2300 wl_android_set_roam_scan_freqs(struct net_device *dev, char *command)
2301 {
2302 	int error = BCME_OK, i;
2303 	char *pcmd, *token;
2304 	uint16 nchan = 0, freq = 0;
2305 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2306 
2307 	pcmd = (command + strlen(CMD_SETROAMSCANFREQS) + 1);
2308 	/* Parse roam channel count */
2309 	token = bcmstrtok(&pcmd, " ", NULL);
2310 	if (!token) {
2311 		ANDROID_ERROR(("Bad argument!\n"));
2312 		return BCME_BADARG;
2313 	}
2314 	nchan = bcm_atoi(token);
2315 	if (nchan > MAX_ROAM_CHANNEL) {
2316 		ANDROID_ERROR(("Failed to Set roamscan frequencies, n_chan = %d\n", nchan));
2317 		return BCME_BADARG;
2318 	}
2319 
2320 	for (i = 0; i < nchan; i++) {
2321 		/* Parse roam channel list */
2322 		token = bcmstrtok(&pcmd, " ", NULL);
2323 		if (!token) {
2324 			ANDROID_ERROR(("Bad argument!\n"));
2325 			return BCME_BADARG;
2326 		}
2327 		freq = bcm_atoi(token);
2328 		/* Convert chanspec from frequency */
2329 		chanspecs[i] = wl_freq_to_chanspec(freq);
2330 	}
2331 
2332 	error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2333 	if (error) {
2334 		ANDROID_ERROR(("Failed to set Scan Channels %d, error = %d\n", nchan, error));
2335 		return error;
2336 	}
2337 
2338 	return error;
2339 }
2340 
2341 int
wl_android_add_roam_scan_freqs(struct net_device * dev,char * command,uint cmdlen)2342 wl_android_add_roam_scan_freqs(struct net_device *dev, char *command, uint cmdlen)
2343 {
2344 	int i, error = BCME_OK;
2345 	char *pcmd, *token;
2346 	uint16 nchan = 0, freq = 0;
2347 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2348 
2349 	pcmd = (command + cmdlen + 1);
2350 	/* Parse roam channel count */
2351 	token = bcmstrtok(&pcmd, " ", NULL);
2352 	if (!token) {
2353 		ANDROID_ERROR(("Bad argument!\n"));
2354 		return BCME_BADARG;
2355 	}
2356 	nchan = bcm_atoi(token);
2357 	if (nchan > MAX_ROAM_CHANNEL) {
2358 		ANDROID_ERROR(("Failed to Add roamscan frequencies, n_chan = %d\n", nchan));
2359 		return BCME_BADARG;
2360 	}
2361 
2362 	for (i = 0; i < nchan; i++) {
2363 		/* Parse roam channel list */
2364 		token = bcmstrtok(&pcmd, " ", NULL);
2365 		if (!token) {
2366 			ANDROID_ERROR(("Bad argument!\n"));
2367 			return BCME_BADARG;
2368 		}
2369 		freq = bcm_atoi(token);
2370 		/* Convert chanspec from channel */
2371 		if (freq > 0) {
2372 			chanspecs[i] = wl_freq_to_chanspec(freq);
2373 		}
2374 	}
2375 
2376 	error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2377 	if (error) {
2378 		ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2379 	}
2380 
2381 	return error;
2382 }
2383 
2384 int
wl_android_get_scan_channel_time(struct net_device * dev,char * command,int total_len)2385 wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
2386 {
2387 	int error = BCME_OK;
2388 	int bytes_written = 0;
2389 	int time = 0;
2390 
2391 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2392 	if (error) {
2393 		ANDROID_ERROR(("Failed to get Scan Channel Time, error = %d\n", error));
2394 		return BCME_ERROR;
2395 	}
2396 
2397 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
2398 
2399 	return bytes_written;
2400 }
2401 
2402 int
wl_android_set_scan_channel_time(struct net_device * dev,char * command)2403 wl_android_set_scan_channel_time(struct net_device *dev, char *command)
2404 {
2405 	int error = BCME_OK;
2406 	int time = 0;
2407 
2408 	if (sscanf(command, "%*s %d", &time) != 1) {
2409 		ANDROID_ERROR(("Failed to get Parameter\n"));
2410 		return BCME_ERROR;
2411 	}
2412 
2413 	if (time == 0) {
2414 		/* Set default value when Private param is 0. */
2415 		time = DHD_SCAN_ASSOC_ACTIVE_TIME;
2416 	}
2417 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2418 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
2419 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2420 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2421 	if (error) {
2422 		ANDROID_ERROR(("Failed to set Scan Channel Time %d, error = %d\n", time, error));
2423 		return BCME_ERROR;
2424 	}
2425 
2426 	return error;
2427 }
2428 
2429 int
wl_android_get_scan_unassoc_time(struct net_device * dev,char * command,int total_len)2430 wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
2431 {
2432 	int error = BCME_OK;
2433 	int bytes_written = 0;
2434 	int time = 0;
2435 
2436 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2437 	if (error) {
2438 		ANDROID_ERROR(("Failed to get Scan Unassoc Time, error = %d\n", error));
2439 		return BCME_ERROR;
2440 	}
2441 
2442 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
2443 
2444 	return bytes_written;
2445 }
2446 
2447 int
wl_android_set_scan_unassoc_time(struct net_device * dev,char * command)2448 wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
2449 {
2450 	int error = BCME_OK;
2451 	int time = 0;
2452 
2453 	if (sscanf(command, "%*s %d", &time) != 1) {
2454 		ANDROID_ERROR(("Failed to get Parameter\n"));
2455 		return BCME_ERROR;
2456 	}
2457 	if (time == 0) {
2458 		/* Set default value when Private param is 0. */
2459 		time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
2460 	}
2461 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2462 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
2463 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2464 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2465 	if (error) {
2466 		ANDROID_ERROR(("Failed to set Scan Unassoc Time %d, error = %d\n", time, error));
2467 		return BCME_ERROR;
2468 	}
2469 
2470 	return error;
2471 }
2472 
2473 int
wl_android_get_scan_passive_time(struct net_device * dev,char * command,int total_len)2474 wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
2475 {
2476 	int error = BCME_OK;
2477 	int bytes_written = 0;
2478 	int time = 0;
2479 
2480 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2481 	if (error) {
2482 		ANDROID_ERROR(("Failed to get Scan Passive Time, error = %d\n", error));
2483 		return BCME_ERROR;
2484 	}
2485 
2486 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
2487 
2488 	return bytes_written;
2489 }
2490 
2491 int
wl_android_set_scan_passive_time(struct net_device * dev,char * command)2492 wl_android_set_scan_passive_time(struct net_device *dev, char *command)
2493 {
2494 	int error = BCME_OK;
2495 	int time = 0;
2496 
2497 	if (sscanf(command, "%*s %d", &time) != 1) {
2498 		ANDROID_ERROR(("Failed to get Parameter\n"));
2499 		return BCME_ERROR;
2500 	}
2501 	if (time == 0) {
2502 		/* Set default value when Private param is 0. */
2503 		time = DHD_SCAN_PASSIVE_TIME;
2504 	}
2505 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2506 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
2507 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2508 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2509 	if (error) {
2510 		ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n", time, error));
2511 		return BCME_ERROR;
2512 	}
2513 
2514 	return error;
2515 }
2516 
2517 int
wl_android_get_scan_home_time(struct net_device * dev,char * command,int total_len)2518 wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
2519 {
2520 	int error = BCME_OK;
2521 	int bytes_written = 0;
2522 	int time = 0;
2523 
2524 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
2525 	if (error) {
2526 		ANDROID_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
2527 		return BCME_ERROR;
2528 	}
2529 
2530 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
2531 
2532 	return bytes_written;
2533 }
2534 
wl_android_set_scan_home_time(struct net_device * dev,char * command)2535 int wl_android_set_scan_home_time(struct net_device *dev, char *command)
2536 {
2537 	int error = BCME_OK;
2538 	int time = 0;
2539 
2540 	if (sscanf(command, "%*s %d", &time) != 1) {
2541 		ANDROID_ERROR(("Failed to get Parameter\n"));
2542 		return BCME_ERROR;
2543 	}
2544 	if (time == 0) {
2545 		/* Set default value when Private param is 0. */
2546 		time = DHD_SCAN_HOME_TIME;
2547 	}
2548 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2549 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
2550 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
2551 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2552 	if (error) {
2553 		ANDROID_ERROR(("Failed to set Scan Home Time %d, error = %d\n", time, error));
2554 		return BCME_ERROR;
2555 	}
2556 
2557 	return error;
2558 }
2559 
2560 int
wl_android_get_scan_home_away_time(struct net_device * dev,char * command,int total_len)2561 wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
2562 {
2563 	int error = BCME_OK;
2564 	int bytes_written = 0;
2565 	int time = 0;
2566 
2567 	error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
2568 	if (error) {
2569 		ANDROID_ERROR(("Failed to get Scan Home Away Time, error = %d\n", error));
2570 		return BCME_ERROR;
2571 	}
2572 
2573 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
2574 
2575 	return bytes_written;
2576 }
2577 
2578 int
wl_android_set_scan_home_away_time(struct net_device * dev,char * command)2579 wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
2580 {
2581 	int error = BCME_OK;
2582 	int time = 0;
2583 
2584 	if (sscanf(command, "%*s %d", &time) != 1) {
2585 		ANDROID_ERROR(("Failed to get Parameter\n"));
2586 		return BCME_ERROR;
2587 	}
2588 	if (time == 0) {
2589 		/* Set default value when Private param is 0. */
2590 		time = DHD_SCAN_HOME_AWAY_TIME;
2591 	}
2592 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2593 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
2594 	error = wldev_iovar_setint(dev, "scan_home_away_time", time);
2595 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2596 	if (error) {
2597 		ANDROID_ERROR(("Failed to set Scan Home Away Time %d, error = %d\n",  time, error));
2598 		return BCME_ERROR;
2599 	}
2600 
2601 	return error;
2602 }
2603 
2604 int
wl_android_get_scan_nprobes(struct net_device * dev,char * command,int total_len)2605 wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
2606 {
2607 	int error = BCME_OK;
2608 	int bytes_written = 0;
2609 	int num = 0;
2610 
2611 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
2612 	if (error) {
2613 		ANDROID_ERROR(("Failed to get Scan NProbes, error = %d\n", error));
2614 		return BCME_ERROR;
2615 	}
2616 
2617 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
2618 
2619 	return bytes_written;
2620 }
2621 
2622 int
wl_android_set_scan_nprobes(struct net_device * dev,char * command)2623 wl_android_set_scan_nprobes(struct net_device *dev, char *command)
2624 {
2625 	int error = BCME_OK;
2626 	int num = 0;
2627 
2628 	if (sscanf(command, "%*s %d", &num) != 1) {
2629 		ANDROID_ERROR(("Failed to get Parameter\n"));
2630 		return BCME_ERROR;
2631 	}
2632 
2633 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
2634 	if (error) {
2635 		ANDROID_ERROR(("Failed to set Scan NProbes %d, error = %d\n", num, error));
2636 		return BCME_ERROR;
2637 	}
2638 
2639 	return error;
2640 }
2641 
2642 int
wl_android_get_scan_dfs_channel_mode(struct net_device * dev,char * command,int total_len)2643 wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
2644 {
2645 	int error = BCME_OK;
2646 	int bytes_written = 0;
2647 	int mode = 0;
2648 	int scan_passive_time = 0;
2649 
2650 	error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
2651 	if (error) {
2652 		ANDROID_ERROR(("Failed to get Passive Time, error = %d\n", error));
2653 		return BCME_ERROR;
2654 	}
2655 
2656 	if (scan_passive_time == 0) {
2657 		mode = 0;
2658 	} else {
2659 		mode = 1;
2660 	}
2661 
2662 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
2663 
2664 	return bytes_written;
2665 }
2666 
2667 int
wl_android_set_scan_dfs_channel_mode(struct net_device * dev,char * command)2668 wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
2669 {
2670 	int error = BCME_OK;
2671 	int mode = 0;
2672 	int scan_passive_time = 0;
2673 
2674 	if (sscanf(command, "%*s %d", &mode) != 1) {
2675 		ANDROID_ERROR(("Failed to get Parameter\n"));
2676 		return BCME_ERROR;
2677 	}
2678 
2679 	if (mode == 1) {
2680 		scan_passive_time = DHD_SCAN_PASSIVE_TIME;
2681 	} else if (mode == 0) {
2682 		scan_passive_time = 0;
2683 	} else {
2684 		ANDROID_ERROR(("Failed to set Scan DFS channel mode %d\n", mode));
2685 		return BCME_ERROR;
2686 	}
2687 	error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
2688 	if (error) {
2689 		ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n",
2690 			scan_passive_time, error));
2691 		return BCME_ERROR;
2692 	}
2693 
2694 	return error;
2695 }
2696 
2697 #define JOINPREFFER_BUF_SIZE 12
2698 
2699 static int
wl_android_set_join_prefer(struct net_device * dev,char * command)2700 wl_android_set_join_prefer(struct net_device *dev, char *command)
2701 {
2702 	int error = BCME_OK;
2703 	char smbuf[WLC_IOCTL_SMLEN];
2704 	uint8 buf[JOINPREFFER_BUF_SIZE];
2705 	char *pcmd;
2706 	int total_len_left;
2707 	int i;
2708 	char hex[] = "XX";
2709 #ifdef WBTEXT
2710 	int turn_on = OFF;
2711 	char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
2712 #endif /* WBTEXT */
2713 
2714 	pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
2715 	total_len_left = strlen(pcmd);
2716 
2717 	bzero(buf, sizeof(buf));
2718 
2719 	if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
2720 		ANDROID_ERROR(("wl_android_set_join_prefer: Failed to get Parameter\n"));
2721 		return BCME_ERROR;
2722 	}
2723 
2724 	/* Store the MSB first, as required by join_pref */
2725 	for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
2726 		hex[0] = *pcmd++;
2727 		hex[1] = *pcmd++;
2728 		buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
2729 	}
2730 
2731 #ifdef WBTEXT
2732 	/* Set WBTEXT mode */
2733 	turn_on = memcmp(buf, clear, sizeof(buf)) == 0 ? TRUE : FALSE;
2734 	error = wl_android_wbtext_enable(dev, turn_on);
2735 	if (error) {
2736 		ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2737 			error, (turn_on ? "Enable" : "Disable")));
2738 	}
2739 #endif /* WBTEXT */
2740 
2741 	prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
2742 	error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
2743 		smbuf, sizeof(smbuf), NULL);
2744 	if (error) {
2745 		ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
2746 	}
2747 
2748 	return error;
2749 }
2750 
wl_android_send_action_frame(struct net_device * dev,char * command,int total_len)2751 int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
2752 {
2753 	int error = -1;
2754 	android_wifi_af_params_t *params = NULL;
2755 	wl_action_frame_t *action_frame = NULL;
2756 	wl_af_params_t *af_params = NULL;
2757 	char *smbuf = NULL;
2758 	struct ether_addr tmp_bssid;
2759 	int tmp_channel = 0;
2760 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2761 
2762 	if (total_len <
2763 			(strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
2764 		ANDROID_ERROR(("wl_android_send_action_frame: Invalid parameters \n"));
2765 		goto send_action_frame_out;
2766 	}
2767 
2768 	params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
2769 
2770 	if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
2771 		ANDROID_ERROR(("wl_android_send_action_frame: Requested action frame len"
2772 			" was out of range(%d)\n",
2773 			params->len));
2774 		goto send_action_frame_out;
2775 	}
2776 
2777 	smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
2778 	if (smbuf == NULL) {
2779 		ANDROID_ERROR(("wl_android_send_action_frame: failed to allocated memory %d bytes\n",
2780 		WLC_IOCTL_MAXLEN));
2781 		goto send_action_frame_out;
2782 	}
2783 
2784 	af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
2785 	if (af_params == NULL) {
2786 		ANDROID_ERROR(("wl_android_send_action_frame: unable to allocate frame\n"));
2787 		goto send_action_frame_out;
2788 	}
2789 
2790 	bzero(&tmp_bssid, ETHER_ADDR_LEN);
2791 	if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
2792 		bzero(&tmp_bssid, ETHER_ADDR_LEN);
2793 
2794 		error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2795 		if (error) {
2796 			bzero(&tmp_bssid, ETHER_ADDR_LEN);
2797 			ANDROID_ERROR(("wl_android_send_action_frame: failed to get bssid,"
2798 				" error=%d\n", error));
2799 			goto send_action_frame_out;
2800 		}
2801 	}
2802 
2803 	if (params->channel < 0) {
2804 		struct channel_info ci;
2805 		bzero(&ci, sizeof(ci));
2806 		error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
2807 		if (error) {
2808 			ANDROID_ERROR(("wl_android_send_action_frame: failed to get channel,"
2809 				" error=%d\n", error));
2810 			goto send_action_frame_out;
2811 		}
2812 
2813 		tmp_channel = ci.hw_channel;
2814 	}
2815 	else {
2816 		tmp_channel = params->channel;
2817 	}
2818 
2819 	af_params->channel = tmp_channel;
2820 	af_params->dwell_time = params->dwell_time;
2821 	memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2822 	action_frame = &af_params->action_frame;
2823 
2824 	action_frame->packetId = 0;
2825 	memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
2826 	action_frame->len = (uint16)params->len;
2827 	memcpy(action_frame->data, params->data, action_frame->len);
2828 
2829 	error = wldev_iovar_setbuf(dev, "actframe", af_params,
2830 		sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
2831 	if (error) {
2832 		ANDROID_ERROR(("wl_android_send_action_frame: failed to set action frame,"
2833 			" error=%d\n", error));
2834 	}
2835 
2836 send_action_frame_out:
2837 	if (af_params) {
2838 		MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
2839 	}
2840 
2841 	if (smbuf) {
2842 		MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
2843 	}
2844 
2845 	if (error)
2846 		return -1;
2847 	else
2848 		return 0;
2849 }
2850 
2851 int
wl_android_reassoc(struct net_device * dev,char * command,int total_len)2852 wl_android_reassoc(struct net_device *dev, char *command, int total_len)
2853 {
2854 	int error = BCME_OK;
2855 	android_wifi_reassoc_params_t *params = NULL;
2856 	chanspec_t channel;
2857 	u32 params_size;
2858 	wl_reassoc_params_t reassoc_params;
2859 	char pcmd[WL_PRIV_CMD_LEN + 1];
2860 
2861 	sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s *", pcmd);
2862 	if (total_len < (strlen(pcmd) + 1 + sizeof(android_wifi_reassoc_params_t))) {
2863 		ANDROID_ERROR(("Invalid parameters %s\n", command));
2864 		return BCME_ERROR;
2865 	}
2866 	params = (android_wifi_reassoc_params_t *)(command + strlen(pcmd) + 1);
2867 
2868 	bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
2869 
2870 	if (bcm_ether_atoe((const char *)params->bssid,
2871 	(struct ether_addr *)&reassoc_params.bssid) == 0) {
2872 		ANDROID_ERROR(("Invalid bssid \n"));
2873 		return BCME_BADARG;
2874 	}
2875 
2876 	if (params->channel < 0) {
2877 		ANDROID_ERROR(("Invalid Channel %d\n", params->channel));
2878 		return BCME_BADARG;
2879 	}
2880 
2881 	reassoc_params.chanspec_num = 1;
2882 
2883 	channel = params->channel;
2884 	if (CHANNEL_IS_2G(channel) || CHANNEL_IS_5G(channel)) {
2885 		/* If reassoc Param is BSSID and Channel */
2886 		reassoc_params.chanspec_list[0] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2887 	} else {
2888 		/* If reassoc Param is BSSID and Frequency */
2889 		reassoc_params.chanspec_list[0] = wl_freq_to_chanspec(channel);
2890 	}
2891 	params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
2892 
2893 	error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
2894 	if (error) {
2895 		ANDROID_ERROR(("failed to reassoc, error=%d\n", error));
2896 		return error;
2897 	}
2898 	return error;
2899 }
2900 
wl_android_get_wes_mode(struct net_device * dev,char * command,int total_len)2901 int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
2902 {
2903 	int bytes_written = 0;
2904 	int mode = 0;
2905 
2906 	mode = wl_cfg80211_get_wes_mode(dev);
2907 
2908 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
2909 
2910 	return bytes_written;
2911 }
2912 
wl_android_set_wes_mode(struct net_device * dev,char * command)2913 int wl_android_set_wes_mode(struct net_device *dev, char *command)
2914 {
2915 	int error = 0;
2916 	int mode = 0;
2917 
2918 	if (sscanf(command, "%*s %d", &mode) != 1) {
2919 		ANDROID_ERROR(("wl_android_set_wes_mode: Failed to get Parameter\n"));
2920 		return -1;
2921 	}
2922 
2923 	error = wl_cfg80211_set_wes_mode(dev, mode);
2924 	if (error) {
2925 		ANDROID_ERROR(("wl_android_set_wes_mode: Failed to set WES Mode %d, error = %d\n",
2926 		mode, error));
2927 		return -1;
2928 	}
2929 
2930 	return 0;
2931 }
2932 
2933 int
wl_android_get_ncho_mode(struct net_device * dev,char * command,int total_len)2934 wl_android_get_ncho_mode(struct net_device *dev, char *command, int total_len)
2935 {
2936 	int bytes_written = 0;
2937 	int mode = 0;
2938 
2939 	mode = wl_cfg80211_get_ncho_mode(dev);
2940 
2941 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETNCHOMODE, mode);
2942 
2943 	return bytes_written;
2944 }
2945 
2946 int
wl_android_set_ncho_mode(struct net_device * dev,int mode)2947 wl_android_set_ncho_mode(struct net_device *dev, int mode)
2948 {
2949 	char cmd[WLC_IOCTL_SMLEN];
2950 	int error = BCME_OK;
2951 
2952 #ifdef WBTEXT
2953 	/* Set WBTEXT mode */
2954 	error = wl_android_wbtext_enable(dev, !mode);
2955 	if (error) {
2956 		ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2957 			error, (mode ? "Disable" : "Enable")));
2958 	}
2959 #endif /* WBTEXT */
2960 	/* Set Piority roam mode */
2961 	error = wl_android_priority_roam_enable(dev, !mode);
2962 	if (error) {
2963 		ANDROID_ERROR(("Failed to set Priority Roam(%d) = %s\n",
2964 			error, (mode ? "Disable" : "Enable")));
2965 	}
2966 #ifdef CONFIG_SILENT_ROAM
2967 	/* Set Silent roam  mode */
2968 	error = wl_android_sroam_turn_on(dev, !mode);
2969 	if (error) {
2970 		ANDROID_ERROR(("Failed to set SROAM(%d) = %s\n",
2971 			error, (mode ? "Disable" : "Enable")));
2972 	}
2973 #endif /* CONFIG_SILENT_ROAM */
2974 	/* Set RCROAM(ROAMEXT) mode */
2975 	error = wl_android_rcroam_turn_on(dev, !mode);
2976 	if (error) {
2977 		ANDROID_ERROR(("Failed to set RCROAM(%d) = %s\n",
2978 			error, (mode ? "Disable" : "Enable")));
2979 	}
2980 
2981 	if (mode == OFF) {
2982 		/* restore NCHO set parameters */
2983 		bzero(cmd, WLC_IOCTL_SMLEN);
2984 		snprintf(cmd, WLC_IOCTL_SMLEN, "%s", CMD_RESTORE_SCAN_PARAMS);
2985 		error = wl_android_default_set_scan_params(dev, cmd, WLC_IOCTL_SMLEN);
2986 		if (error) {
2987 			ANDROID_ERROR(("Failed to set RESTORE_SCAN_PARAMS(%d)\n", error));
2988 		}
2989 
2990 		wl_cfg80211_set_wes_mode(dev, OFF);
2991 		set_roamscan_mode(dev, ROAMSCAN_MODE_NORMAL);
2992 	}
2993 
2994 	error = wl_cfg80211_set_ncho_mode(dev, mode);
2995 	if (error) {
2996 		ANDROID_ERROR(("Failed to set NCHO Mode %d, error = %d\n", mode, error));
2997 	}
2998 
2999 	return error;
3000 }
3001 
3002 static int
wl_android_set_pmk(struct net_device * dev,char * command,int total_len)3003 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
3004 {
3005 	uchar pmk[33];
3006 	int error = 0;
3007 	char smbuf[WLC_IOCTL_SMLEN];
3008 	dhd_pub_t *dhdp;
3009 #ifdef OKC_DEBUG
3010 	int i = 0;
3011 #endif
3012 
3013 	if (total_len < (strlen("SET_PMK ") + 32)) {
3014 		ANDROID_ERROR(("wl_android_set_pmk: Invalid argument\n"));
3015 		return -1;
3016 	}
3017 
3018 	dhdp = wl_cfg80211_get_dhdp(dev);
3019 	if (!dhdp) {
3020 		ANDROID_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3021 		return -1;
3022 	}
3023 
3024 	bzero(pmk, sizeof(pmk));
3025 	DHD_STATLOG_CTRL(dhdp, ST(INSTALL_OKC_PMK), dhd_net2idx(dhdp->info, dev), 0);
3026 	memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
3027 	error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
3028 	if (error) {
3029 		ANDROID_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
3030 	}
3031 #ifdef OKC_DEBUG
3032 	ANDROID_ERROR(("PMK is "));
3033 	for (i = 0; i < 32; i++)
3034 		ANDROID_ERROR(("%02X ", pmk[i]));
3035 
3036 	ANDROID_ERROR(("\n"));
3037 #endif
3038 	return error;
3039 }
3040 
3041 static int
wl_android_okc_enable(struct net_device * dev,char * command)3042 wl_android_okc_enable(struct net_device *dev, char *command)
3043 {
3044 	int error = 0;
3045 	char okc_enable = 0;
3046 
3047 	okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
3048 	error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
3049 	if (error) {
3050 		ANDROID_ERROR(("Failed to %s OKC, error = %d\n",
3051 			okc_enable ? "enable" : "disable", error));
3052 	}
3053 
3054 	return error;
3055 }
3056 
3057 static int
wl_android_legacy_check_command(struct net_device * dev,char * command)3058 wl_android_legacy_check_command(struct net_device *dev, char *command)
3059 {
3060 	int cnt = 0;
3061 
3062 	while (strlen(legacy_cmdlist[cnt]) > 0) {
3063 		if (strnicmp(command, legacy_cmdlist[cnt], strlen(legacy_cmdlist[cnt])) == 0) {
3064 			char cmd[WL_PRIV_CMD_LEN + 1];
3065 			sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3066 			if (strlen(legacy_cmdlist[cnt]) == strlen(cmd)) {
3067 				return TRUE;
3068 			}
3069 		}
3070 		cnt++;
3071 	}
3072 	return FALSE;
3073 }
3074 
3075 static int
wl_android_legacy_private_command(struct net_device * net,char * command,int total_len)3076 wl_android_legacy_private_command(struct net_device *net, char *command, int total_len)
3077 {
3078 	int bytes_written = 0;
3079 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3080 
3081 	if (cfg->ncho_mode == ON) {
3082 		ANDROID_ERROR(("Enabled NCHO mode\n"));
3083 		/* In order to avoid Sequential error HANG event. */
3084 		return BCME_UNSUPPORTED;
3085 	}
3086 
3087 	/* ROAMSCAN CHANNELS Add, Get Command */
3088 	if (strnicmp(command, CMD_ADDROAMSCANCHLEGACY, strlen(CMD_ADDROAMSCANCHLEGACY)) == 0) {
3089 		bytes_written = wl_android_add_roam_scan_channels(net, command,
3090 			strlen(CMD_ADDROAMSCANCHLEGACY));
3091 	}
3092 	else if (strnicmp(command, CMD_GETROAMSCANCHLEGACY, strlen(CMD_GETROAMSCANCHLEGACY)) == 0) {
3093 		bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3094 			CMD_GETROAMSCANCHLEGACY);
3095 	}
3096 	/* ROAMSCAN FREQUENCIES Add, Get Command */
3097 	else if (strnicmp(command, CMD_ADDROAMSCANFQLEGACY, strlen(CMD_ADDROAMSCANFQLEGACY)) == 0) {
3098 		bytes_written = wl_android_add_roam_scan_freqs(net, command,
3099 			strlen(CMD_ADDROAMSCANFQLEGACY));
3100 	}
3101 	else if (strnicmp(command, CMD_GETROAMSCANFQLEGACY, strlen(CMD_GETROAMSCANFQLEGACY)) == 0) {
3102 		bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3103 			CMD_GETROAMSCANFQLEGACY);
3104 	}
3105 	else if (strnicmp(command, CMD_GETROAMTRIGLEGACY, strlen(CMD_GETROAMTRIGLEGACY)) == 0) {
3106 		bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3107 	}
3108 	else if (strnicmp(command, CMD_SETROAMTRIGLEGACY, strlen(CMD_SETROAMTRIGLEGACY)) == 0) {
3109 		bytes_written = wl_android_set_roam_trigger_legacy(net, command);
3110 	}
3111 	else if (strnicmp(command, CMD_REASSOCLEGACY, strlen(CMD_REASSOCLEGACY)) == 0) {
3112 		bytes_written = wl_android_reassoc(net, command, total_len);
3113 	}
3114 	else if (strnicmp(command, CMD_GETSCANCHANNELTIMELEGACY,
3115 		strlen(CMD_GETSCANCHANNELTIMELEGACY)) == 0) {
3116 		bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3117 	}
3118 	else if (strnicmp(command, CMD_SETSCANCHANNELTIMELEGACY,
3119 		strlen(CMD_SETSCANCHANNELTIMELEGACY)) == 0) {
3120 		bytes_written = wl_android_set_scan_channel_time(net, command);
3121 	}
3122 	else if (strnicmp(command, CMD_GETSCANUNASSOCTIMELEGACY,
3123 		strlen(CMD_GETSCANUNASSOCTIMELEGACY)) == 0) {
3124 		bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3125 	}
3126 	else if (strnicmp(command, CMD_SETSCANUNASSOCTIMELEGACY,
3127 		strlen(CMD_SETSCANUNASSOCTIMELEGACY)) == 0) {
3128 		bytes_written = wl_android_set_scan_unassoc_time(net, command);
3129 	}
3130 	else if (strnicmp(command, CMD_GETSCANPASSIVETIMELEGACY,
3131 		strlen(CMD_GETSCANPASSIVETIMELEGACY)) == 0) {
3132 		bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3133 	}
3134 	else if (strnicmp(command, CMD_SETSCANPASSIVETIMELEGACY,
3135 		strlen(CMD_SETSCANPASSIVETIMELEGACY)) == 0) {
3136 		bytes_written = wl_android_set_scan_passive_time(net, command);
3137 	}
3138 	else if (strnicmp(command, CMD_GETSCANHOMETIMELEGACY,
3139 		strlen(CMD_GETSCANHOMETIMELEGACY)) == 0) {
3140 		bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3141 	}
3142 	else if (strnicmp(command, CMD_SETSCANHOMETIMELEGACY,
3143 		strlen(CMD_SETSCANHOMETIMELEGACY)) == 0) {
3144 		bytes_written = wl_android_set_scan_home_time(net, command);
3145 	}
3146 	else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIMELEGACY,
3147 		strlen(CMD_GETSCANHOMEAWAYTIMELEGACY)) == 0) {
3148 		bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3149 	}
3150 	else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIMELEGACY,
3151 		strlen(CMD_SETSCANHOMEAWAYTIMELEGACY)) == 0) {
3152 		bytes_written = wl_android_set_scan_home_away_time(net, command);
3153 	}
3154 	else {
3155 		ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3156 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3157 	}
3158 
3159 	return bytes_written;
3160 }
3161 
3162 static int
wl_android_ncho_check_command(struct net_device * dev,char * command)3163 wl_android_ncho_check_command(struct net_device *dev, char *command)
3164 {
3165 	int cnt = 0;
3166 
3167 	while (strlen(ncho_cmdlist[cnt]) > 0) {
3168 		if (strnicmp(command, ncho_cmdlist[cnt], strlen(ncho_cmdlist[cnt])) == 0) {
3169 			char cmd[WL_PRIV_CMD_LEN + 1];
3170 			sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3171 			if (strlen(ncho_cmdlist[cnt]) == strlen(cmd)) {
3172 				return TRUE;
3173 			}
3174 		}
3175 		cnt++;
3176 	}
3177 	return FALSE;
3178 }
3179 
3180 static int
wl_android_ncho_private_command(struct net_device * net,char * command,int total_len)3181 wl_android_ncho_private_command(struct net_device *net, char *command, int total_len)
3182 {
3183 	int bytes_written = 0;
3184 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3185 
3186 	if (cfg->ncho_mode == OFF) {
3187 		ANDROID_ERROR(("Disable NCHO mode\n"));
3188 		/* In order to avoid Sequential error HANG event. */
3189 		return BCME_UNSUPPORTED;
3190 	}
3191 
3192 #ifdef ROAM_API
3193 	if (strnicmp(command, CMD_ROAMTRIGGER_SET, strlen(CMD_ROAMTRIGGER_SET)) == 0) {
3194 		bytes_written = wl_android_set_roam_trigger(net, command);
3195 	} else if (strnicmp(command, CMD_ROAMTRIGGER_GET, strlen(CMD_ROAMTRIGGER_GET)) == 0) {
3196 		bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3197 	} else if (strnicmp(command, CMD_ROAMDELTA_SET, strlen(CMD_ROAMDELTA_SET)) == 0) {
3198 		bytes_written = wl_android_set_roam_delta(net, command);
3199 	} else if (strnicmp(command, CMD_ROAMDELTA_GET, strlen(CMD_ROAMDELTA_GET)) == 0) {
3200 		bytes_written = wl_android_get_roam_delta(net, command, total_len);
3201 	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
3202 		strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
3203 		bytes_written = wl_android_set_roam_scan_period(net, command);
3204 	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
3205 		strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
3206 		bytes_written = wl_android_get_roam_scan_period(net, command, total_len);
3207 	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
3208 		strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
3209 		bytes_written = wl_android_set_full_roam_scan_period(net, command);
3210 	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
3211 		strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
3212 		bytes_written = wl_android_get_full_roam_scan_period(net, command, total_len);
3213 	} else if (strnicmp(command, CMD_COUNTRYREV_SET, strlen(CMD_COUNTRYREV_SET)) == 0) {
3214 		bytes_written = wl_android_set_country_rev(net, command);
3215 #ifdef FCC_PWR_LIMIT_2G
3216 		if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
3217 			ANDROID_ERROR(("fccpwrlimit2g deactivation is failed\n"));
3218 		} else {
3219 			ANDROID_ERROR(("fccpwrlimit2g is deactivated\n"));
3220 		}
3221 #endif /* FCC_PWR_LIMIT_2G */
3222 	} else if (strnicmp(command, CMD_COUNTRYREV_GET, strlen(CMD_COUNTRYREV_GET)) == 0) {
3223 		bytes_written = wl_android_get_country_rev(net, command, total_len);
3224 	} else
3225 #endif /* ROAM_API */
3226 	if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
3227 		bytes_written = wl_android_get_roam_scan_control(net, command, total_len);
3228 	}
3229 	else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
3230 		bytes_written = wl_android_set_roam_scan_control(net, command);
3231 	}
3232 	/* ROAMSCAN CHANNELS Add, Get, Set Command */
3233 	else if (strnicmp(command, CMD_ADDROAMSCANCHANNELS, strlen(CMD_ADDROAMSCANCHANNELS)) == 0) {
3234 		bytes_written = wl_android_add_roam_scan_channels(net, command,
3235 			strlen(CMD_ADDROAMSCANCHANNELS));
3236 	}
3237 	else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
3238 		bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3239 			CMD_GETROAMSCANCHANNELS);
3240 	}
3241 	else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
3242 		bytes_written = wl_android_set_roam_scan_channels(net, command);
3243 	}
3244 	/* ROAMSCAN FREQUENCIES Add, Get, Set Command */
3245 	else if (strnicmp(command, CMD_ADDROAMSCANFREQS, strlen(CMD_ADDROAMSCANFREQS)) == 0) {
3246 		bytes_written = wl_android_add_roam_scan_freqs(net, command,
3247 			strlen(CMD_ADDROAMSCANFREQS));
3248 	}
3249 	else if (strnicmp(command, CMD_GETROAMSCANFREQS, strlen(CMD_GETROAMSCANFREQS)) == 0) {
3250 		bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3251 			CMD_GETROAMSCANFREQS);
3252 	}
3253 	else if (strnicmp(command, CMD_SETROAMSCANFREQS, strlen(CMD_SETROAMSCANFREQS)) == 0) {
3254 		bytes_written = wl_android_set_roam_scan_freqs(net, command);
3255 	}
3256 	else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
3257 		bytes_written = wl_android_send_action_frame(net, command, total_len);
3258 	}
3259 	else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
3260 		bytes_written = wl_android_reassoc(net, command, total_len);
3261 	}
3262 	else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
3263 		bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3264 	}
3265 	else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
3266 		bytes_written = wl_android_set_scan_channel_time(net, command);
3267 	}
3268 	else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
3269 		bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3270 	}
3271 	else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
3272 		bytes_written = wl_android_set_scan_unassoc_time(net, command);
3273 	}
3274 	else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
3275 		bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3276 	}
3277 	else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
3278 		bytes_written = wl_android_set_scan_passive_time(net, command);
3279 	}
3280 	else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
3281 		bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3282 	}
3283 	else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
3284 		bytes_written = wl_android_set_scan_home_time(net, command);
3285 	}
3286 	else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
3287 		bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3288 	}
3289 	else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
3290 		bytes_written = wl_android_set_scan_home_away_time(net, command);
3291 	}
3292 	else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
3293 		bytes_written = wl_android_get_scan_nprobes(net, command, total_len);
3294 	}
3295 	else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
3296 		bytes_written = wl_android_set_scan_nprobes(net, command);
3297 	}
3298 	else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
3299 		bytes_written = wl_android_get_scan_dfs_channel_mode(net, command, total_len);
3300 	}
3301 	else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
3302 		bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
3303 	}
3304 	else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
3305 		bytes_written = wl_android_set_join_prefer(net, command);
3306 	}
3307 	else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
3308 		bytes_written = wl_android_get_wes_mode(net, command, total_len);
3309 	}
3310 	else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
3311 		bytes_written = wl_android_set_wes_mode(net, command);
3312 	}
3313 	else {
3314 		ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3315 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3316 	}
3317 
3318 	return bytes_written;
3319 }
3320 #endif /* WES_SUPPORT */
3321 
3322 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
3323 static int
wl_android_default_set_scan_params(struct net_device * dev,char * command,int total_len)3324 wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len)
3325 {
3326 	int error = 0;
3327 	uint error_cnt = 0;
3328 	int cnt = 0;
3329 	char restore_command[WLC_IOCTL_SMLEN];
3330 
3331 	while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) {
3332 		snprintf(restore_command, WLC_IOCTL_SMLEN, "%s %d",
3333 			restore_params[cnt].command, restore_params[cnt].parameter);
3334 		if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) {
3335 			error = restore_params[cnt].cmd_handler(dev, restore_command);
3336 		}  else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) {
3337 			error = restore_params[cnt].cmd_handler_w_len(dev,
3338 				restore_command, total_len);
3339 		} else {
3340 			ANDROID_ERROR(("Unknown restore command handler\n"));
3341 			error = -1;
3342 		}
3343 		if (error) {
3344 			ANDROID_ERROR(("Failed to restore scan parameters %s, error : %d\n",
3345 				restore_command, error));
3346 			error_cnt++;
3347 		}
3348 		cnt++;
3349 	}
3350 	if (error_cnt > 0) {
3351 		ANDROID_ERROR(("Got %d error(s) while restoring scan parameters\n",
3352 			error_cnt));
3353 		error = -1;
3354 	}
3355 	return error;
3356 }
3357 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT  */
3358 
3359 #ifdef WLTDLS
wl_android_tdls_reset(struct net_device * dev)3360 int wl_android_tdls_reset(struct net_device *dev)
3361 {
3362 	int ret = 0;
3363 	ret = dhd_tdls_enable(dev, false, false, NULL);
3364 	if (ret < 0) {
3365 		ANDROID_ERROR(("Disable tdls failed. %d\n", ret));
3366 		return ret;
3367 	}
3368 	ret = dhd_tdls_enable(dev, true, true, NULL);
3369 	if (ret < 0) {
3370 		ANDROID_ERROR(("enable tdls failed. %d\n", ret));
3371 		return ret;
3372 	}
3373 	return 0;
3374 }
3375 #endif /* WLTDLS */
3376 
3377 int
wl_android_rcroam_turn_on(struct net_device * dev,int rcroam_enab)3378 wl_android_rcroam_turn_on(struct net_device *dev, int rcroam_enab)
3379 {
3380 	int ret = BCME_OK;
3381 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3382 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3383 	wlc_rcroam_t *prcroam;
3384 	wlc_rcroam_info_v1_t *rcroam;
3385 	uint rcroamlen = sizeof(*rcroam) + RCROAM_HDRLEN;
3386 
3387 	ANDROID_INFO(("RCROAM mode %s\n", rcroam_enab ? "enable" : "disable"));
3388 
3389 	prcroam = (wlc_rcroam_t *)MALLOCZ(dhdp->osh, rcroamlen);
3390 	if (!prcroam) {
3391 		ANDROID_ERROR(("Fail to malloc buffer\n"));
3392 		return BCME_NOMEM;
3393 	}
3394 
3395 	/* Get RCROAM param */
3396 	ret = wldev_iovar_getbuf(dev, "rcroam", NULL, 0, prcroam, rcroamlen, NULL);
3397 	if (ret) {
3398 		ANDROID_ERROR(("Failed to get RCROAM info(%d)\n", ret));
3399 		goto done;
3400 	}
3401 
3402 	if (prcroam->ver != WLC_RC_ROAM_CUR_VER) {
3403 		ret = BCME_VERSION;
3404 		ANDROID_ERROR(("Ver(%d:%d). mismatch RCROAM info(%d)\n",
3405 			prcroam->ver, WLC_RC_ROAM_CUR_VER, ret));
3406 		goto done;
3407 	}
3408 
3409 	/* Set RCROAM param */
3410 	rcroam = (wlc_rcroam_info_v1_t *)prcroam->data;
3411 	prcroam->ver = WLC_RC_ROAM_CUR_VER;
3412 	prcroam->len = sizeof(*rcroam);
3413 	rcroam->enab = rcroam_enab;
3414 
3415 	ret = wldev_iovar_setbuf(dev, "rcroam", prcroam, rcroamlen,
3416 		ioctl_buf, sizeof(ioctl_buf), NULL);
3417 	if (ret) {
3418 		ANDROID_ERROR(("Failed to set RCROAM %s(%d)\n",
3419 			rcroam_enab ? "Enable" : "Disable", ret));
3420 		goto done;
3421 	}
3422 done:
3423 	if (prcroam) {
3424 		MFREE(dhdp->osh, prcroam, rcroamlen);
3425 	}
3426 
3427 	return ret;
3428 }
3429 
3430 #ifdef CONFIG_SILENT_ROAM
3431 int
wl_android_sroam_turn_on(struct net_device * dev,int sroam_mode)3432 wl_android_sroam_turn_on(struct net_device *dev, int sroam_mode)
3433 {
3434 	int ret = BCME_OK;
3435 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3436 
3437 	dhdp->sroam_turn_on = sroam_mode;
3438 	ANDROID_INFO(("%s Silent mode %s\n", __FUNCTION__,
3439 		sroam_mode ? "enable" : "disable"));
3440 
3441 	if (!sroam_mode) {
3442 		ret = dhd_sroam_set_mon(dhdp, FALSE);
3443 		if (ret) {
3444 			ANDROID_ERROR(("%s Failed to Set sroam %d\n",
3445 				__FUNCTION__, ret));
3446 		}
3447 	}
3448 
3449 	return ret;
3450 }
3451 
3452 int
wl_android_sroam_set_info(struct net_device * dev,char * data,char * command,int total_len)3453 wl_android_sroam_set_info(struct net_device *dev, char *data,
3454 	char *command, int total_len)
3455 {
3456 	int ret = BCME_OK;
3457 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3458 	size_t slen = strlen(data);
3459 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3460 	wlc_sroam_t *psroam;
3461 	wlc_sroam_info_t *sroam;
3462 	uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3463 
3464 	data[slen] = '\0';
3465 	psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3466 	if (!psroam) {
3467 		ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3468 		ret = BCME_NOMEM;
3469 		goto done;
3470 	}
3471 
3472 	psroam->ver = WLC_SILENT_ROAM_CUR_VER;
3473 	psroam->len = sizeof(*sroam);
3474 	sroam = (wlc_sroam_info_t *)psroam->data;
3475 
3476 	sroam->sroam_on = FALSE;
3477 	if (*data && *data != '\0') {
3478 		sroam->sroam_min_rssi = simple_strtol(data, &data, 10);
3479 		ANDROID_INFO(("1.Minimum RSSI %d\n", sroam->sroam_min_rssi));
3480 		data++;
3481 	}
3482 	if (*data && *data != '\0') {
3483 		sroam->sroam_rssi_range = simple_strtol(data, &data, 10);
3484 		ANDROID_INFO(("2.RSSI Range %d\n", sroam->sroam_rssi_range));
3485 		data++;
3486 	}
3487 	if (*data && *data != '\0') {
3488 		sroam->sroam_score_delta = simple_strtol(data, &data, 10);
3489 		ANDROID_INFO(("3.Score Delta %d\n", sroam->sroam_score_delta));
3490 		data++;
3491 	}
3492 	if (*data && *data != '\0') {
3493 		sroam->sroam_period_time = simple_strtol(data, &data, 10);
3494 		ANDROID_INFO(("4.Sroam period %d\n", sroam->sroam_period_time));
3495 		data++;
3496 	}
3497 	if (*data && *data != '\0') {
3498 		sroam->sroam_band = simple_strtol(data, &data, 10);
3499 		ANDROID_INFO(("5.Sroam Band %d\n", sroam->sroam_band));
3500 		data++;
3501 	}
3502 	if (*data && *data != '\0') {
3503 		sroam->sroam_inact_cnt = simple_strtol(data, &data, 10);
3504 		ANDROID_INFO(("6.Inactivity Count %d\n", sroam->sroam_inact_cnt));
3505 		data++;
3506 	}
3507 
3508 	if (*data != '\0') {
3509 		ret = BCME_BADARG;
3510 		goto done;
3511 	}
3512 
3513 	ret = wldev_iovar_setbuf(dev, "sroam", psroam, sroamlen, ioctl_buf,
3514 		sizeof(ioctl_buf), NULL);
3515 	if (ret) {
3516 		ANDROID_ERROR(("Failed to set silent roam info(%d)\n", ret));
3517 		goto done;
3518 	}
3519 done:
3520 	if (psroam) {
3521 		MFREE(dhdp->osh, psroam, sroamlen);
3522 	}
3523 
3524 	return ret;
3525 }
3526 
3527 int
wl_android_sroam_get_info(struct net_device * dev,char * command,int total_len)3528 wl_android_sroam_get_info(struct net_device *dev, char *command, int total_len)
3529 {
3530 	int ret = BCME_OK;
3531 	int bytes_written = 0;
3532 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3533 	wlc_sroam_t *psroam;
3534 	wlc_sroam_info_t *sroam;
3535 	uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3536 
3537 	psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3538 	if (!psroam) {
3539 		ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3540 		ret = BCME_NOMEM;
3541 		goto done;
3542 	}
3543 
3544 	ret = wldev_iovar_getbuf(dev, "sroam", NULL, 0, psroam, sroamlen, NULL);
3545 	if (ret) {
3546 		ANDROID_ERROR(("Failed to get silent roam info(%d)\n", ret));
3547 		goto done;
3548 	}
3549 
3550 	if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) {
3551 		ret = BCME_VERSION;
3552 		ANDROID_ERROR(("Ver(%d:%d). mismatch silent roam info(%d)\n",
3553 			psroam->ver, WLC_SILENT_ROAM_CUR_VER, ret));
3554 		goto done;
3555 	}
3556 
3557 	sroam = (wlc_sroam_info_t *)psroam->data;
3558 	bytes_written = snprintf(command, total_len,
3559 		"%s %d %d %d %d %d %d %d\n",
3560 		CMD_SROAM_GET_INFO, sroam->sroam_on, sroam->sroam_min_rssi, sroam->sroam_rssi_range,
3561 		sroam->sroam_score_delta, sroam->sroam_period_time, sroam->sroam_band,
3562 		sroam->sroam_inact_cnt);
3563 	ret = bytes_written;
3564 
3565 	ANDROID_INFO(("%s", command));
3566 done:
3567 	if (psroam) {
3568 		MFREE(dhdp->osh, psroam, sroamlen);
3569 	}
3570 
3571 	return ret;
3572 }
3573 #endif /* CONFIG_SILENT_ROAM */
3574 
3575 int
wl_android_priority_roam_enable(struct net_device * dev,int mode)3576 wl_android_priority_roam_enable(struct net_device *dev, int mode)
3577 {
3578 	int error = BCME_OK;
3579 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3580 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3581 	wl_prio_roam_prof_v1_t *prio_roam;
3582 	uint buf_len = sizeof(wl_prio_roam_prof_v1_t) + (uint)strlen("priority_roam") + 1;
3583 
3584 	prio_roam = (wl_prio_roam_prof_v1_t *)MALLOCZ(dhdp->osh, buf_len);
3585 	if (!prio_roam) {
3586 		ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3587 		error = BCME_NOMEM;
3588 		goto done;
3589 	}
3590 
3591 	error = wldev_iovar_getbuf(dev, "priority_roam", NULL, 0, prio_roam, buf_len, NULL);
3592 	if (error == BCME_UNSUPPORTED) {
3593 		ANDROID_ERROR(("Priority Roam Unsupport\n"));
3594 		error = BCME_OK;
3595 		goto done;
3596 	} else if (prio_roam->version != WL_PRIO_ROAM_PROF_V1) {
3597 		ANDROID_ERROR(("Priority Roam Version mismatch\n"));
3598 		goto done;
3599 	} else if (prio_roam->prio_roam_mode == mode) {
3600 		ANDROID_INFO(("Priority Roam already set(mode:%d)\n", mode));
3601 		goto done;
3602 	}
3603 
3604 	prio_roam->version = WL_PRIO_ROAM_PROF_V1;
3605 	prio_roam->length = sizeof(wl_prio_roam_prof_v1_t);
3606 	prio_roam->prio_roam_mode = mode;
3607 
3608 	error = wldev_iovar_setbuf(dev, "priority_roam", prio_roam,
3609 		sizeof(wl_prio_roam_prof_v1_t), ioctl_buf, sizeof(ioctl_buf), NULL);
3610 	if (error) {
3611 		ANDROID_ERROR(("Failed to set Priority Roam %s(%d)\n",
3612 			mode ? "Enable" : "Disable", error));
3613 		goto done;
3614 	}
3615 done:
3616 	if (prio_roam) {
3617 		MFREE(dhdp->osh, prio_roam, sizeof(wl_prio_roam_prof_v1_t));
3618 	}
3619 
3620 	return error;
3621 }
3622 
3623 #ifdef CONFIG_ROAM_RSSI_LIMIT
3624 int
wl_android_roam_rssi_limit(struct net_device * dev,char * command,int total_len)3625 wl_android_roam_rssi_limit(struct net_device *dev, char *command, int total_len)
3626 {
3627 	int ret = BCME_OK;
3628 	int argc, bytes_written = 0;
3629 	int lmt2g, lmt5g;
3630 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3631 
3632 	argc = sscanf(command, CMD_ROAM_RSSI_LMT " %d %d\n", &lmt2g, &lmt5g);
3633 
3634 	if (!argc) {
3635 		ret = dhd_roam_rssi_limit_get(dhdp, &lmt2g, &lmt5g);
3636 		if (ret) {
3637 			ANDROID_ERROR(("Failed to Get roam_rssi_limit (%d)\n", ret));
3638 			return ret;
3639 		}
3640 		bytes_written = snprintf(command, total_len, "%d, %d\n", lmt2g, lmt5g);
3641 		/* Get roam rssi limit */
3642 		return bytes_written;
3643 	} else {
3644 		/* Set roam rssi limit */
3645 		ret = dhd_roam_rssi_limit_set(dhdp, lmt2g, lmt5g);
3646 		if (ret) {
3647 			ANDROID_ERROR(("Failed to Set roam_rssi_limit (%d)\n", ret));
3648 			return ret;
3649 		}
3650 	}
3651 
3652 	return ret;
3653 }
3654 #endif /* CONFIG_ROAM_RSSI_LIMIT */
3655 
3656 #ifdef CONFIG_ROAM_MIN_DELTA
3657 int
wl_android_roam_min_delta(struct net_device * dev,char * command,int total_len)3658 wl_android_roam_min_delta(struct net_device *dev, char *command, int total_len)
3659 {
3660 	int ret = BCME_OK;
3661 	int argc, bytes_written = 0;
3662 	uint32 delta2g = 0, delta5g = 0, delta = 0;
3663 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3664 
3665 	argc = sscanf(command, CMD_ROAM_MIN_DELTA " %d\n", &delta);
3666 
3667 	if (!argc) {
3668 		/* Get Minimum ROAM score delta */
3669 		ret = dhd_roam_min_delta_get(dhdp, &delta2g, &delta5g);
3670 		if (ret) {
3671 			ANDROID_ERROR(("Failed to Get roam_min_delta (%d)\n", ret));
3672 			return ret;
3673 		}
3674 		bytes_written = snprintf(command, total_len, "%d, %d\n", delta2g, delta5g);
3675 		return bytes_written;
3676 	} else {
3677 		/* Set Minimum ROAM score delta
3678 		 * Framework set one parameter # wpa_cli driver ROAMMINSCOREDELTA <value>
3679 		 */
3680 		ret = dhd_roam_min_delta_set(dhdp, delta, delta);
3681 		if (ret) {
3682 			ANDROID_ERROR(("Failed to Set roam_min_delta (%d)\n", ret));
3683 			return ret;
3684 		}
3685 	}
3686 
3687 	return ret;
3688 }
3689 #endif /* CONFIG_ROAM_MIN_DELTA */
3690 
3691 static int
get_int_bytes(uchar * oui_str,uchar * oui,int len)3692 get_int_bytes(uchar *oui_str, uchar *oui, int len)
3693 {
3694 	int idx;
3695 	uchar val;
3696 	uchar *src, *dest;
3697 	char hexstr[3];
3698 
3699 	if ((oui_str == NULL) || (oui == NULL) || (len == 0)) {
3700 		return BCME_BADARG;
3701 	}
3702 	src = oui_str;
3703 	dest = oui;
3704 
3705 	for (idx = 0; idx < len; idx++) {
3706 		if (*src == '\0') {
3707 			*dest = '\0';
3708 			break;
3709 		}
3710 		hexstr[0] = src[0];
3711 		hexstr[1] = src[1];
3712 		hexstr[2] = '\0';
3713 
3714 		val = (uchar)bcm_strtoul(hexstr, NULL, 16);
3715 		if (val == (uchar)-1) {
3716 			return BCME_ERROR;
3717 		}
3718 		*dest++ = val;
3719 		src += 2;
3720 	}
3721 	return BCME_OK;
3722 }
3723 
3724 #define TAG_BYTE 0
3725 static int
wl_android_set_disconnect_ies(struct net_device * dev,char * command)3726 wl_android_set_disconnect_ies(struct net_device *dev, char *command)
3727 {
3728 	int cmd_prefix_len = 0;
3729 	char ie_len = 0;
3730 	int hex_ie_len = 0;
3731 	int total_len = 0;
3732 	int max_len = 0;
3733 	int cmd_len = 0;
3734 	uchar disassoc_ie[VNDR_IE_MAX_LEN] = {0};
3735 	s32 bssidx = 0;
3736 	struct bcm_cfg80211 *cfg = NULL;
3737 	s32 ret = 0;
3738 	cfg = wl_get_cfg(dev);
3739 
3740 	cmd_prefix_len = strlen("SET_DISCONNECT_IES ");
3741 	cmd_len = strlen(command);
3742 	/*
3743 	 * <CMD> + <IES in HEX format>
3744 	 * IES in hex format has to be in following format
3745 	 * First byte = Tag, Second Byte = len and rest of
3746 	 * bytes will be value. For ex: SET_DISCONNECT_IES dd0411223344
3747 	 * tag = dd, len =04. Total IEs len = len + 2
3748 	 */
3749 	ANDROID_INFO(("cmd recv = %s\n", command));
3750 	max_len = MIN(cmd_len, VNDR_IE_MAX_LEN);
3751 	/* Validate IEs len */
3752 	get_int_bytes(&command[cmd_prefix_len + 2], &ie_len, 1);
3753 	ANDROID_INFO(("ie_len = %d \n", ie_len));
3754 	if (ie_len <= 0 || ie_len > max_len) {
3755 		ret = BCME_BADLEN;
3756 		return ret;
3757 	}
3758 
3759 	/* Total len in hex is sum of double binary len, tag and len byte */
3760 	hex_ie_len = (ie_len * 2) + 4;
3761 	total_len = cmd_prefix_len + hex_ie_len;
3762 	if (command[total_len] != '\0' || (cmd_len != total_len)) {
3763 		ANDROID_ERROR(("command recv not matching with len, command = %s"
3764 			"total_len = %d, cmd_len = %d\n", command, total_len, cmd_len));
3765 		ret = BCME_BADARG;
3766 		return ret;
3767 	}
3768 
3769 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3770 		ANDROID_ERROR(("Find index failed\n"));
3771 		ret = -EINVAL;
3772 		return ret;
3773 	}
3774 
3775 	/* Tag and len bytes are also part of total len of ies in binary */
3776 	ie_len = ie_len + 2;
3777 	/* Convert IEs in binary */
3778 	get_int_bytes(&command[cmd_prefix_len], disassoc_ie, ie_len);
3779 	if (disassoc_ie[TAG_BYTE] != 0xdd) {
3780 		ANDROID_ERROR(("Wrong tag recv, tag = 0x%02x\n", disassoc_ie[TAG_BYTE]));
3781 		ret = BCME_UNSUPPORTED;
3782 		return ret;
3783 	}
3784 
3785 	ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
3786 		ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, disassoc_ie, ie_len);
3787 
3788 	return ret;
3789 }
3790 
3791 #ifdef FCC_PWR_LIMIT_2G
3792 int
wl_android_set_fcc_pwr_limit_2g(struct net_device * dev,char * command)3793 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
3794 {
3795 	int error = 0;
3796 	int enable = 0;
3797 
3798 	sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
3799 
3800 	if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
3801 		ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: Invalid data\n"));
3802 		return BCME_ERROR;
3803 	}
3804 
3805 	CUSTOMER_HW4_EN_CONVERT(enable);
3806 
3807 	ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g set (%d)\n", enable));
3808 	error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
3809 	if (error) {
3810 		ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g"
3811 			" set returned (%d)\n", error));
3812 		return BCME_ERROR;
3813 	}
3814 
3815 	return error;
3816 }
3817 
3818 int
wl_android_get_fcc_pwr_limit_2g(struct net_device * dev,char * command,int total_len)3819 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
3820 {
3821 	int error = 0;
3822 	int enable = 0;
3823 	int bytes_written = 0;
3824 
3825 	error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
3826 	if (error) {
3827 		ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get"
3828 			" error (%d)\n", error));
3829 		return BCME_ERROR;
3830 	}
3831 	ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get (%d)\n", enable));
3832 
3833 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
3834 
3835 	return bytes_written;
3836 }
3837 #endif /* FCC_PWR_LIMIT_2G */
3838 
3839 /* Additional format of sta_info
3840  * tx_pkts, tx_failures, tx_rate(kbps), rssi(main), rssi(aux), tx_pkts_retried,
3841  * tx_pkts_retry_exhausted, rx_lastpkt_rssi(main), rx_lastpkt_rssi(aux),
3842  * tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
3843  * tx_pkts_fw_retry_exhausted
3844  */
3845 #define STA_INFO_ADD_FMT	"%d %d %d %d %d %d %d %d %d %d %d %d %d %d"
3846 
3847 #ifdef BIGDATA_SOFTAP
3848 #define BIGDATA_SOFTAP_FMT	MACOUI " %d %s %d %d %d %d %d %d"
3849 #endif /* BIGDATA_SOFTAP */
3850 
3851 #define STAINFO_BAND_2G    0x0001
3852 #define STAINFO_BAND_5G    0x0002
3853 #define STAINFO_BAND_6G    0x0004
3854 #define STAINFO_BAND_60G   0x0008
3855 s32
wl_cfg80211_get_sta_info(struct net_device * dev,char * command,int total_len)3856 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
3857 {
3858 	int bytes_written = -1, ret = 0;
3859 	char *pos, *token, *cmdstr;
3860 	bool is_macaddr = FALSE;
3861 	sta_info_v4_t *sta = NULL;
3862 	struct ether_addr mac;
3863 	char *iovar_buf = NULL;
3864 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3865 	struct net_device *apdev = NULL;
3866 #ifdef BCMDONGLEHOST
3867 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3868 #endif /* BCMDONGLEHOST */
3869 
3870 #ifdef BIGDATA_SOFTAP
3871 	void *data = NULL;
3872 	wl_ap_sta_data_t *sta_data = NULL;
3873 #endif /* BIGDATA_SOFTAP */
3874 
3875 	/* Client information */
3876 	uint16 cap = 0;
3877 	uint32 rxrtry = 0, rxmulti = 0;
3878 	uint32 tx_pkts = 0, tx_failures = 0, tx_rate = 0;
3879 	uint32 tx_pkts_retried = 0, tx_pkts_retry_exhausted = 0;
3880 	uint32 tx_pkts_total = 0, tx_pkts_retries = 0;
3881 	uint32 tx_pkts_fw_total = 0, tx_pkts_fw_retries = 0;
3882 	uint32 tx_pkts_fw_retry_exhausted = 0;
3883 	int8 rssi[WL_STA_ANT_MAX] = {0};
3884 	int8 rx_lastpkt_rssi[WL_STA_ANT_MAX] = {0};
3885 	wl_if_stats_t *if_stats = NULL;
3886 	u16 bands = 0;
3887 	u32 sta_flags = 0;
3888 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
3889 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
3890 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
3891 
3892 	BCM_REFERENCE(if_stats);
3893 	/* This Command used during only SoftAP mode. */
3894 	ANDROID_INFO(("%s\n", command));
3895 
3896 	/* Check the current op_mode */
3897 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
3898 		ANDROID_ERROR(("unsupported op mode: %d\n", dhdp->op_mode));
3899 		return BCME_NOTAP;
3900 	}
3901 
3902 	/*
3903 	 * DRIVER GETSTAINFO [client MAC or ALL] [ifname]
3904 	 */
3905 	pos = command;
3906 
3907 	/* drop command */
3908 	token = bcmstrtok(&pos, " ", NULL);
3909 
3910 	/* Client MAC or ALL */
3911 	token = bcmstrtok(&pos, " ", NULL);
3912 	if (!token) {
3913 		ANDROID_ERROR(("GETSTAINFO subcmd not provided wl_cfg80211_get_sta_info\n"));
3914 		return -EINVAL;
3915 	}
3916 	cmdstr = token;
3917 
3918 	bzero(&mac, ETHER_ADDR_LEN);
3919 	if ((!strncmp(token, "all", 3)) || (!strncmp(token, "ALL", 3))) {
3920 		is_macaddr = FALSE;
3921 	} else if ((bcm_ether_atoe(token, &mac))) {
3922 		is_macaddr = TRUE;
3923 	} else {
3924 		ANDROID_ERROR(("Failed to get address\n"));
3925 		return -EINVAL;
3926 	}
3927 
3928 	/* get the interface name */
3929 	token = bcmstrtok(&pos, " ", NULL);
3930 	if (!token) {
3931 		/* assign requested dev for compatibility */
3932 		apdev = dev;
3933 	} else {
3934 		/* Find a net_device for SoftAP by interface name */
3935 		apdev = wl_get_ap_netdev(cfg, token);
3936 		if (!apdev) {
3937 			ANDROID_ERROR(("cannot find a net_device for SoftAP\n"));
3938 			return -EINVAL;
3939 		}
3940 	}
3941 
3942 	iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
3943 	if (!iovar_buf) {
3944 		ANDROID_ERROR(("Failed to allocated memory %d bytes\n",
3945 			WLC_IOCTL_MAXLEN));
3946 		return BCME_NOMEM;
3947 	}
3948 
3949 	if (is_macaddr) {
3950 		int cnt;
3951 
3952 		/* get the sta info */
3953 		ret = wldev_iovar_getbuf(apdev, "sta_info",
3954 			(struct ether_addr *)mac.octet, ETHER_ADDR_LEN,
3955 			iovar_buf, WLC_IOCTL_MAXLEN, NULL);
3956 		if (ret < 0) {
3957 			ANDROID_ERROR(("Get sta_info ERR %d\n", ret));
3958 
3959 #ifdef BIGDATA_SOFTAP
3960 			/* Customer wants to send basic client information
3961 			 * to the framework even if DHD cannot get the sta_info.
3962 			 */
3963 			goto get_bigdata;
3964 #endif /* BIGDATA_SOFTAP */
3965 
3966 #ifndef BIGDATA_SOFTAP
3967 			goto error;
3968 #endif /* BIGDATA_SOFTAP */
3969 		}
3970 
3971 		sta = (sta_info_v4_t *)iovar_buf;
3972 		if (dtoh16(sta->ver) != WL_STA_VER_4) {
3973 			ANDROID_ERROR(("sta_info struct version mismatch, "
3974 				"host ver : %d, fw ver : %d\n", WL_STA_VER_4,
3975 				dtoh16(sta->ver)));
3976 
3977 #ifdef BIGDATA_SOFTAP
3978 			/* Customer wants to send basic client information
3979 			 * to the framework even if DHD cannot get the sta_info.
3980 			 */
3981 			goto get_bigdata;
3982 #endif /* BIGDATA_SOFTAP */
3983 
3984 #ifndef BIGDATA_SOFTAP
3985 			goto error;
3986 #endif /* BIGDATA_SOFTAP */
3987 		}
3988 		cap = dtoh16(sta->cap);
3989 		rxrtry = dtoh32(sta->rx_pkts_retried);
3990 		rxmulti = dtoh32(sta->rx_mcast_pkts);
3991 		tx_pkts = dtoh32(sta->tx_pkts);
3992 		tx_failures = dtoh32(sta->tx_failures);
3993 		tx_rate = dtoh32(sta->tx_rate);
3994 		tx_pkts_retried = dtoh32(sta->tx_pkts_retried);
3995 		tx_pkts_retry_exhausted = dtoh32(sta->tx_pkts_retry_exhausted);
3996 		tx_pkts_total = dtoh32(sta->tx_pkts_total);
3997 		tx_pkts_retries = dtoh32(sta->tx_pkts_retries);
3998 		tx_pkts_fw_total = dtoh32(sta->tx_pkts_fw_total);
3999 		tx_pkts_fw_retries = dtoh32(sta->tx_pkts_fw_retries);
4000 		tx_pkts_fw_retry_exhausted = dtoh32(sta->tx_pkts_fw_retry_exhausted);
4001 		sta_flags = dtoh32(sta->flags);
4002 		if (sta_flags & WL_STA_IS_2G) {
4003 			bands |= STAINFO_BAND_2G;
4004 		}
4005 		if (sta_flags & WL_STA_IS_5G) {
4006 			bands |= STAINFO_BAND_5G;
4007 		}
4008 		if (sta_flags & WL_STA_IS_6G) {
4009 			bands |= STAINFO_BAND_6G;
4010 		}
4011 		for (cnt = WL_ANT_IDX_1; cnt < WL_RSSI_ANT_MAX; cnt++) {
4012 			rssi[cnt] = sta->rssi[cnt];
4013 			rx_lastpkt_rssi[cnt] = sta->rx_lastpkt_rssi[cnt];
4014 		}
4015 	} else {
4016 		int i;
4017 
4018 		/* Check if there is an associated STA or not */
4019 		assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
4020 		ret = wldev_ioctl_get(apdev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
4021 
4022 		if (ret < 0) {
4023 			ANDROID_ERROR(("Fail to get assoc list: %d\n", ret));
4024 			goto error;
4025 		}
4026 
4027 		assoc_maclist->count = dtoh32(assoc_maclist->count);
4028 		ANDROID_INFO(("Assoc count :  %d\n", assoc_maclist->count));
4029 
4030 		for (i = 0; i < assoc_maclist->count; i++) {
4031 			/* get the sta info */
4032 			ret = wldev_iovar_getbuf(apdev, "sta_info",
4033 				(struct ether_addr *)assoc_maclist->ea[i].octet, ETHER_ADDR_LEN,
4034 				iovar_buf, WLC_IOCTL_MAXLEN, NULL);
4035 
4036 			if (ret < 0) {
4037 				ANDROID_ERROR(("sta_info err : %d", ret));
4038 				continue;
4039 			}
4040 			sta = (sta_info_v4_t *)iovar_buf;
4041 			if (dtoh16(sta->ver) == WL_STA_VER_4) {
4042 				rxrtry += dtoh32(sta->rx_pkts_retried);
4043 				rxmulti += dtoh32(sta->rx_mcast_pkts);
4044 				tx_pkts += dtoh32(sta->tx_pkts);
4045 				tx_failures += dtoh32(sta->tx_failures);
4046 				tx_pkts_total += dtoh32(sta->tx_pkts_total);
4047 				tx_pkts_retries += dtoh32(sta->tx_pkts_retries);
4048 				tx_pkts_fw_total += dtoh32(sta->tx_pkts_fw_total);
4049 				tx_pkts_fw_retries += dtoh32(sta->tx_pkts_fw_retries);
4050 				tx_pkts_fw_retry_exhausted +=
4051 					dtoh32(sta->tx_pkts_fw_retry_exhausted);
4052 			}
4053 		}
4054 	}
4055 
4056 #ifdef BIGDATA_SOFTAP
4057 get_bigdata:
4058 
4059 	if (is_macaddr && wl_get_ap_stadata(cfg, &mac, &data) == BCME_OK) {
4060 		ANDROID_ERROR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
4061 		sta_data = (wl_ap_sta_data_t *)data;
4062 #ifdef STAINFO_LEGACY
4063 		bytes_written = snprintf(command, total_len,
4064 			"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4065 			"CAP=%04x " BIGDATA_SOFTAP_FMT " " STA_INFO_ADD_FMT
4066 			"\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4067 			MACOUI2STR((char*)&sta_data->mac),
4068 			sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4069 			sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4070 			sta_data->nss, sta_data->mimo, sta_data->reason_code,
4071 			tx_pkts, tx_failures, tx_rate,
4072 			(int32)rssi[WL_ANT_IDX_1], (int32)rssi[WL_ANT_IDX_2],
4073 			tx_pkts_retried, tx_pkts_retry_exhausted,
4074 			(int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4075 			(int32)rx_lastpkt_rssi[WL_ANT_IDX_2],
4076 			tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total,
4077 			tx_pkts_fw_retries, tx_pkts_fw_retry_exhausted);
4078 #else
4079 		bytes_written = snprintf(command, total_len,
4080 			"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4081 			"CAP=%04x " BIGDATA_SOFTAP_FMT " %d\n",
4082 			CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4083 			MACOUI2STR((char*)&sta_data->mac),
4084 			sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4085 			sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4086 			sta_data->nss, sta_data->mimo, sta_data->reason_code, bands);
4087 #endif /* STAINFO_LEGACY */
4088 	} else
4089 #endif /* BIGDATA_SOFTAP */
4090 	{
4091 		ANDROID_ERROR(("ALL\n"));
4092 		bytes_written = snprintf(command, total_len,
4093 			"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x "
4094 			STA_INFO_ADD_FMT "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4095 			tx_pkts, tx_failures, tx_rate, (int32)rssi[WL_ANT_IDX_1],
4096 			(int32)rssi[WL_ANT_IDX_2], tx_pkts_retried,
4097 			tx_pkts_retry_exhausted, (int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4098 			(int32)rx_lastpkt_rssi[WL_ANT_IDX_2], tx_pkts_total,
4099 			tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
4100 			tx_pkts_fw_retry_exhausted);
4101 	}
4102 	WL_ERR_KERN(("Command: %s", command));
4103 
4104 error:
4105 	if (iovar_buf) {
4106 		MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
4107 	}
4108 	if (if_stats) {
4109 		MFREE(cfg->osh, if_stats, sizeof(*if_stats));
4110 	}
4111 
4112 	return bytes_written;
4113 }
4114 
4115 #ifdef WL_WTC
4116 /*
4117  * CMD Format
4118  * Enable format for 3 band and 2 band respectively:
4119  * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G 6G>
4120  * DRIVER SETWTCMODE 0 1 -80 -70 -65 -60
4121  * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G>
4122  * DRIVER SETWTCMODE 0 1 -80 -70 -65
4123  * Disable format for 3 band and 2 band respectively:
4124  * DRIVER SETWTCMODE 1 0 0 0 0 0
4125  * DRIVER SETWTCMODE 1 0 0 0 0
4126  */
4127 #define WL_TRIBAND     3
4128 #define WL_DUALBAND    2
4129 
4130 /* For WTC disable, any value >= 1 */
4131 #define WL_WTC_ENABLE 0
4132 static int
wl_android_wtc_config(struct net_device * dev,char * command,int total_len)4133 wl_android_wtc_config(struct net_device *dev, char *command, int total_len)
4134 {
4135 	s32 bw;
4136 	char *token, *pos;
4137 	wlc_wtc_args_t *wtc_params;
4138 	wlc_wtcconfig_info_v1_t *wtc_config;
4139 	u32 i, wtc_paramslen, maxbands = WL_DUALBAND;
4140 	u8 buf[WLC_IOCTL_SMLEN] = {0};
4141 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4142 
4143 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
4144 #ifdef WL_6G_BAND
4145 	if (cfg->band_6g_supported) {
4146 		maxbands = WL_TRIBAND;
4147 	}
4148 #endif	/* WL_6G_BAND */
4149 	wtc_paramslen = sizeof(wlc_wtcconfig_info_v1_t) + WLC_WTC_ROAM_CONFIG_HDRLEN;
4150 	wtc_params = (wlc_wtc_args_t*)MALLOCZ(cfg->osh, wtc_paramslen);
4151 	if (!wtc_params) {
4152 		ANDROID_ERROR(("Error allocating wtc_params\n"));
4153 		return -ENOMEM;
4154 	}
4155 
4156 	wtc_config = (wlc_wtcconfig_info_v1_t *)wtc_params->data;
4157 	/* Get wtc config information and check version compatibility */
4158 	bw = wldev_iovar_getbuf(dev, "wnm_wbtext_wtc_config",
4159 		(char*)&wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, 0);
4160 	if (bw) {
4161 		ANDROID_ERROR(("Error querying wnm_wbtext_wtc_config: %d\n", bw));
4162 		goto exit;
4163 	}
4164 
4165 	(void)memcpy_s(wtc_params, wtc_paramslen, buf, wtc_paramslen);
4166 	if (wtc_params->ver != WLC_WTC_ROAM_VER_1) {
4167 		ANDROID_ERROR(("Wrong version:%d\n", wtc_params->ver));
4168 		bw = -EINVAL;
4169 		goto exit;
4170 	}
4171 
4172 	if (wtc_params->len != sizeof(wlc_wtcconfig_info_v1_t)) {
4173 		ANDROID_ERROR(("Bad len\n"));
4174 		bw = -EINVAL;
4175 		goto exit;
4176 	}
4177 
4178 	if (strlen(command) == strlen(CMD_WTC_CONFIG)) {
4179 		/* No additional arguments given. GET case  */
4180 		bw += scnprintf(command, (total_len - bw), "%u %u",
4181 			wtc_config->mode, wtc_config->scantype);
4182 		bw += scnprintf(command + bw, (total_len - bw), " %d",
4183 			wtc_config->rssithresh[0]);
4184 		for (i = 0; i < maxbands; i++) {
4185 			bw += scnprintf(command + bw, (total_len - bw), " %d",
4186 				wtc_config->ap_rssithresh[i]);
4187 		}
4188 		bw += scnprintf(command + bw, (total_len - bw), "\n");
4189 	} else {
4190 		/* SET */
4191 		pos = command + sizeof(CMD_WTC_CONFIG);
4192 
4193 		/* mode */
4194 		token = strsep((char**)&pos, " ");
4195 		if (!token) {
4196 			ANDROID_ERROR(("No mode present\n"));
4197 			bw = -EINVAL;
4198 			goto exit;
4199 		}
4200 		wtc_config->mode = (u8)bcm_atoi(token);
4201 
4202 		/* scantype */
4203 		token = strsep((char**)&pos, " ");
4204 		if (!token) {
4205 			ANDROID_ERROR(("No scantype present\n"));
4206 			bw = -EINVAL;
4207 			goto exit;
4208 		}
4209 		wtc_config->scantype = (u8)bcm_atoi(token);
4210 
4211 		/* rssithreshold */
4212 		token = strsep((char**)&pos, " ");
4213 		if (!token) {
4214 			ANDROID_ERROR(("Invalid arg for rssi threshold\n"));
4215 			bw = -EINVAL;
4216 			goto exit;
4217 		}
4218 		for (i = 0; i < maxbands; i++) {
4219 			wtc_config->rssithresh[i] = (s8)bcm_atoi(token);
4220 		}
4221 
4222 		/* AP rssithreshold */
4223 		for (i = 0; i < maxbands; i++) {
4224 			token = strsep((char**)&pos, " ");
4225 			if (!token) {
4226 				ANDROID_ERROR(("Invalid arg for ap threshold\n"));
4227 				bw = -EINVAL;
4228 				goto exit;
4229 			}
4230 			wtc_config->ap_rssithresh[i] = (s8)bcm_atoi(token);
4231 		}
4232 
4233 		bw = wldev_iovar_setbuf(dev, "wnm_wbtext_wtc_config",
4234 			(char*)wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, NULL);
4235 		if (bw) {
4236 			ANDROID_ERROR(("wtc config set failed. ret:%d\n", bw));
4237 		}
4238 	}
4239 
4240 exit:
4241 	if (wtc_params) {
4242 		MFREE(cfg->osh, wtc_params, wtc_paramslen);
4243 	}
4244 	return bw;
4245 }
4246 #endif /* WL_WTC */
4247 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4248 
4249 #ifdef WBTEXT
wl_android_wbtext(struct net_device * dev,char * command,int total_len)4250 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
4251 {
4252 	int error = BCME_OK, argc = 0;
4253 	int data, bytes_written;
4254 	int roam_trigger[2];
4255 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4256 
4257 	argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
4258 	if (!argc) {
4259 		error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
4260 		if (error) {
4261 			ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4262 				error));
4263 			return error;
4264 		}
4265 		bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
4266 				(data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
4267 				"ENABLED" : "DISABLED");
4268 		return bytes_written;
4269 	} else {
4270 		if (data) {
4271 			data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
4272 		}
4273 
4274 		if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
4275 			ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4276 				error));
4277 			return error;
4278 		}
4279 
4280 		if (data) {
4281 			/* reset roam_prof when wbtext is on */
4282 			if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
4283 				return error;
4284 			}
4285 		} else {
4286 			/* reset legacy roam trigger when wbtext is off */
4287 			roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
4288 			roam_trigger[1] = WLC_BAND_ALL;
4289 			if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
4290 					sizeof(roam_trigger))) != BCME_OK) {
4291 				ANDROID_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n",
4292 					error));
4293 				return error;
4294 			}
4295 		}
4296 		dhdp->wbtext_policy = data;
4297 	}
4298 	return error;
4299 }
4300 
4301 #ifdef WES_SUPPORT
wl_android_check_wbtext_support(struct net_device * dev)4302 static bool wl_android_check_wbtext_support(struct net_device *dev)
4303 {
4304 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4305 	return dhdp->wbtext_support;
4306 }
4307 
4308 static int
wl_android_wbtext_enable(struct net_device * dev,int mode)4309 wl_android_wbtext_enable(struct net_device *dev, int mode)
4310 {
4311 	int error = BCME_OK;
4312 	char commandp[WLC_IOCTL_SMLEN];
4313 
4314 	if (wl_android_check_wbtext_support(dev)) {
4315 		bzero(commandp, sizeof(commandp));
4316 		snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE %d", mode);
4317 		error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN);
4318 		if (error) {
4319 			ANDROID_ERROR(("Failed to set WBTEXT = %d\n", error));
4320 			return error;
4321 		}
4322 	}
4323 
4324 	return error;
4325 }
4326 #endif /* WES_SUPPORT */
4327 
wl_cfg80211_wbtext_btm_timer_threshold(struct net_device * dev,char * command,int total_len)4328 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
4329 	char *command, int total_len)
4330 {
4331 	int error = BCME_OK, argc = 0;
4332 	int data, bytes_written;
4333 
4334 	argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
4335 	if (!argc) {
4336 		error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
4337 		if (error) {
4338 			ANDROID_ERROR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
4339 			return error;
4340 		}
4341 		bytes_written = snprintf(command, total_len, "%d\n", data);
4342 		return bytes_written;
4343 	} else {
4344 		if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
4345 				data)) != BCME_OK) {
4346 			ANDROID_ERROR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
4347 			return error;
4348 		}
4349 	}
4350 	return error;
4351 }
4352 
wl_cfg80211_wbtext_btm_delta(struct net_device * dev,char * command,int total_len)4353 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
4354 	char *command, int total_len)
4355 {
4356 	int error = BCME_OK, argc = 0;
4357 	int data = 0, bytes_written;
4358 
4359 	argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
4360 	if (!argc) {
4361 		error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
4362 		if (error) {
4363 			ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4364 			return error;
4365 		}
4366 		bytes_written = snprintf(command, total_len, "%d\n", data);
4367 		return bytes_written;
4368 	} else {
4369 		if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
4370 				data)) != BCME_OK) {
4371 			ANDROID_ERROR(("Failed to set wnm_btmdelta (%d)\n", error));
4372 			return error;
4373 		}
4374 	}
4375 	return error;
4376 }
4377 
wl_cfg80211_wbtext_estm_enable(struct net_device * dev,char * command,int total_len)4378 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
4379 	char *command, int total_len)
4380 {
4381 	int error = BCME_OK;
4382 	int data = 0, bytes_written = 0;
4383 	int wnmmask = 0;
4384 	char *pcmd = command;
4385 
4386 	bcmstrtok(&pcmd, " ", NULL);
4387 
4388 	error = wldev_iovar_getint(dev, "wnm", &wnmmask);
4389 	if (error) {
4390 		ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4391 		return error;
4392 	}
4393 	ANDROID_INFO(("wnmmask %x\n", wnmmask));
4394 	if (*pcmd == WL_IOCTL_ACTION_GET) {
4395 		bytes_written = snprintf(command, total_len, "wbtext_estm_enable %d\n",
4396 			(wnmmask & WL_WNM_ESTM) ? 1:0);
4397 		return bytes_written;
4398 	} else {
4399 		data = bcm_atoi(pcmd);
4400 		if (data == 0) {
4401 			wnmmask &= ~WL_WNM_ESTM;
4402 		} else {
4403 			wnmmask |= WL_WNM_ESTM;
4404 		}
4405 		ANDROID_INFO(("wnmmask %x\n", wnmmask));
4406 		if ((error = wldev_iovar_setint(dev, "wnm", wnmmask)) != BCME_OK) {
4407 			ANDROID_ERROR(("Failed to set wnm mask (%d)\n", error));
4408 			return error;
4409 		}
4410 	}
4411 	return error;
4412 }
4413 #endif /* WBTEXT */
4414 
4415 #ifdef PNO_SUPPORT
4416 #define PNO_PARAM_SIZE 50
4417 #define VALUE_SIZE 50
4418 #define LIMIT_STR_FMT  ("%50s %50s")
4419 static int
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)4420 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
4421 {
4422 	int err = BCME_OK;
4423 	uint i, tokens, len_remain;
4424 	char *pos, *pos2, *token, *token2, *delim;
4425 	char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
4426 	struct dhd_pno_batch_params batch_params;
4427 
4428 	ANDROID_INFO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len));
4429 	len_remain = total_len;
4430 	if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
4431 		pos = command + strlen(CMD_WLS_BATCHING) + 1;
4432 		len_remain -= strlen(CMD_WLS_BATCHING) + 1;
4433 	} else {
4434 		ANDROID_ERROR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len));
4435 		err = BCME_ERROR;
4436 		goto exit;
4437 	}
4438 	bzero(&batch_params, sizeof(struct dhd_pno_batch_params));
4439 	if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
4440 		if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
4441 			pos += strlen(PNO_BATCHING_SET) + 1;
4442 		} else {
4443 			ANDROID_ERROR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n",
4444 				PNO_BATCHING_SET, total_len));
4445 			err = BCME_ERROR;
4446 			goto exit;
4447 		}
4448 		while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
4449 			bzero(param, sizeof(param));
4450 			bzero(value, sizeof(value));
4451 			if (token == NULL || !*token)
4452 				break;
4453 			if (*token == '\0')
4454 				continue;
4455 			delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
4456 			if (delim != NULL)
4457 				*delim = ' ';
4458 
4459 			tokens = sscanf(token, LIMIT_STR_FMT, param, value);
4460 			if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
4461 				batch_params.scan_fr = simple_strtol(value, NULL, 0);
4462 				ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
4463 			} else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
4464 				batch_params.bestn = simple_strtol(value, NULL, 0);
4465 				ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
4466 			} else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
4467 				batch_params.mscan = simple_strtol(value, NULL, 0);
4468 				ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
4469 			} else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
4470 				i = 0;
4471 				pos2 = value;
4472 				tokens = sscanf(value, "<%s>", value);
4473 				if (tokens != 1) {
4474 					err = BCME_ERROR;
4475 					ANDROID_ERROR(("wls_parse_batching_cmd: invalid format"
4476 					" for channel"
4477 					" <> params\n"));
4478 					goto exit;
4479 				}
4480 				while ((token2 = strsep(&pos2,
4481 						PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
4482 					if (token2 == NULL || !*token2)
4483 						break;
4484 					if (*token2 == '\0')
4485 						continue;
4486 					if (*token2 == 'A' || *token2 == 'B') {
4487 						batch_params.band = (*token2 == 'A')?
4488 							WLC_BAND_5G : WLC_BAND_2G;
4489 						ANDROID_INFO(("band : %s\n",
4490 							(*token2 == 'A')? "A" : "B"));
4491 					} else {
4492 						if ((batch_params.nchan >= WL_NUMCHANNELS) ||
4493 							(i >= WL_NUMCHANNELS)) {
4494 							ANDROID_ERROR(("Too many nchan %d\n",
4495 								batch_params.nchan));
4496 							err = BCME_BUFTOOSHORT;
4497 							goto exit;
4498 						}
4499 						batch_params.chan_list[i++] =
4500 							simple_strtol(token2, NULL, 0);
4501 						batch_params.nchan++;
4502 						ANDROID_INFO(("channel :%d\n",
4503 							batch_params.chan_list[i-1]));
4504 					}
4505 				 }
4506 			} else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
4507 				batch_params.rtt = simple_strtol(value, NULL, 0);
4508 				ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
4509 			} else {
4510 				ANDROID_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param));
4511 				err = BCME_ERROR;
4512 				goto exit;
4513 			}
4514 		}
4515 		err = dhd_dev_pno_set_for_batch(dev, &batch_params);
4516 		if (err < 0) {
4517 			ANDROID_ERROR(("failed to configure batch scan\n"));
4518 		} else {
4519 			bzero(command, total_len);
4520 			err = snprintf(command, total_len, "%d", err);
4521 		}
4522 	} else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
4523 		err = dhd_dev_pno_get_for_batch(dev, command, total_len);
4524 		if (err < 0) {
4525 			ANDROID_ERROR(("failed to getting batching results\n"));
4526 		} else {
4527 			err = strlen(command);
4528 		}
4529 	} else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
4530 		err = dhd_dev_pno_stop_for_batch(dev);
4531 		if (err < 0) {
4532 			ANDROID_ERROR(("failed to stop batching scan\n"));
4533 		} else {
4534 			bzero(command, total_len);
4535 			err = snprintf(command, total_len, "OK");
4536 		}
4537 	} else {
4538 		ANDROID_ERROR(("wls_parse_batching_cmd : unknown command\n"));
4539 		err = BCME_ERROR;
4540 		goto exit;
4541 	}
4542 exit:
4543 	return err;
4544 }
4545 
4546 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)4547 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
4548 {
4549 	wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
4550 	int res = -1;
4551 	int nssid = 0;
4552 	cmd_tlv_t *cmd_tlv_temp;
4553 	char *str_ptr;
4554 	int tlv_size_left;
4555 	int pno_time = 0;
4556 	int pno_repeat = 0;
4557 	int pno_freq_expo_max = 0;
4558 
4559 #ifdef PNO_SET_DEBUG
4560 	int i;
4561 	char pno_in_example[] = {
4562 		'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
4563 		'S', '1', '2', '0',
4564 		'S',
4565 		0x05,
4566 		'd', 'l', 'i', 'n', 'k',
4567 		'S',
4568 		0x04,
4569 		'G', 'O', 'O', 'G',
4570 		'T',
4571 		'0', 'B',
4572 		'R',
4573 		'2',
4574 		'M',
4575 		'2',
4576 		0x00
4577 		};
4578 #endif /* PNO_SET_DEBUG */
4579 	ANDROID_INFO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len));
4580 
4581 	if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
4582 		ANDROID_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len));
4583 		goto exit_proc;
4584 	}
4585 #ifdef PNO_SET_DEBUG
4586 	memcpy(command, pno_in_example, sizeof(pno_in_example));
4587 	total_len = sizeof(pno_in_example);
4588 #endif
4589 	str_ptr = command + strlen(CMD_PNOSETUP_SET);
4590 	tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
4591 
4592 	cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
4593 	bzero(ssids_local, sizeof(ssids_local));
4594 
4595 	if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
4596 		(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
4597 		(cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
4598 
4599 		str_ptr += sizeof(cmd_tlv_t);
4600 		tlv_size_left -= sizeof(cmd_tlv_t);
4601 
4602 		if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
4603 			MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
4604 			ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
4605 			goto exit_proc;
4606 		} else {
4607 			if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
4608 				ANDROID_ERROR(("wl_android_set_pno_setup: scan duration corrupted"
4609 					" field size %d\n",
4610 					tlv_size_left));
4611 				goto exit_proc;
4612 			}
4613 			str_ptr++;
4614 			pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
4615 			ANDROID_INFO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time));
4616 
4617 			if (str_ptr[0] != 0) {
4618 				if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
4619 					ANDROID_ERROR(("wl_android_set_pno_setup: pno repeat:"
4620 						" corrupted field\n"));
4621 					goto exit_proc;
4622 				}
4623 				str_ptr++;
4624 				pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
4625 				ANDROID_INFO(("wl_android_set_pno_setup: got pno_repeat=%d\n",
4626 					pno_repeat));
4627 				if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
4628 					ANDROID_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX"
4629 						" corrupted field size\n"));
4630 					goto exit_proc;
4631 				}
4632 				str_ptr++;
4633 				pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
4634 				ANDROID_INFO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n",
4635 					pno_freq_expo_max));
4636 			}
4637 		}
4638 	} else {
4639 		ANDROID_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n"));
4640 		goto exit_proc;
4641 	}
4642 
4643 	res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
4644 		pno_freq_expo_max, NULL, 0);
4645 exit_proc:
4646 	return res;
4647 }
4648 #endif /* !WL_SCHED_SCAN */
4649 #endif /* PNO_SUPPORT  */
4650 
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)4651 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
4652 {
4653 	int ret;
4654 	struct ether_addr p2pdev_addr;
4655 
4656 #define MAC_ADDR_STR_LEN 18
4657 	if (total_len < MAC_ADDR_STR_LEN) {
4658 		ANDROID_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n",
4659 			total_len));
4660 		return -1;
4661 	}
4662 
4663 	ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
4664 	if (ret) {
4665 		ANDROID_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n"));
4666 		return -1;
4667 	}
4668 	return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
4669 }
4670 
4671 int
wl_android_set_ap_mac_list(struct net_device * dev,int macmode,struct maclist * maclist)4672 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
4673 {
4674 	int i, j, match;
4675 	int ret	= 0;
4676 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
4677 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
4678 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
4679 
4680 	/* set filtering mode */
4681 	if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
4682 		ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret));
4683 		return ret;
4684 	}
4685 	if (macmode != MACLIST_MODE_DISABLED) {
4686 		/* set the MAC filter list */
4687 		if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
4688 			sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
4689 			ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret));
4690 			return ret;
4691 		}
4692 		/* get the current list of associated STAs */
4693 		assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
4694 		if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
4695 			sizeof(mac_buf))) != 0) {
4696 			ANDROID_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n",
4697 				ret));
4698 			return ret;
4699 		}
4700 		/* do we have any STA associated?  */
4701 		if (assoc_maclist->count) {
4702 			/* iterate each associated STA */
4703 			for (i = 0; i < assoc_maclist->count; i++) {
4704 				match = 0;
4705 				/* compare with each entry */
4706 				for (j = 0; j < maclist->count; j++) {
4707 					ANDROID_INFO(("wl_android_set_ap_mac_list: associated="MACDBG
4708 					"list = "MACDBG "\n",
4709 					MAC2STRDBG(assoc_maclist->ea[i].octet),
4710 					MAC2STRDBG(maclist->ea[j].octet)));
4711 					if (memcmp(assoc_maclist->ea[i].octet,
4712 						maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
4713 						match = 1;
4714 						break;
4715 					}
4716 				}
4717 				/* do conditional deauth */
4718 				/*   "if not in the allow list" or "if in the deny list" */
4719 				if ((macmode == MACLIST_MODE_ALLOW && !match) ||
4720 					(macmode == MACLIST_MODE_DENY && match)) {
4721 					scb_val_t scbval;
4722 
4723 					scbval.val = htod32(1);
4724 					memcpy(&scbval.ea, &assoc_maclist->ea[i],
4725 						ETHER_ADDR_LEN);
4726 					if ((ret = wldev_ioctl_set(dev,
4727 						WLC_SCB_DEAUTHENTICATE_FOR_REASON,
4728 						&scbval, sizeof(scb_val_t))) != 0)
4729 						ANDROID_ERROR(("wl_android_set_ap_mac_list:"
4730 							" WLC_SCB_DEAUTHENTICATE"
4731 							" error=%d\n",
4732 							ret));
4733 				}
4734 			}
4735 		}
4736 	}
4737 	return ret;
4738 }
4739 
4740 /*
4741  * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
4742  *
4743  */
4744 static int
wl_android_set_mac_address_filter(struct net_device * dev,char * str)4745 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
4746 {
4747 	int i;
4748 	int ret = 0;
4749 	int macnum = 0;
4750 	int macmode = MACLIST_MODE_DISABLED;
4751 	struct maclist *list;
4752 	char eabuf[ETHER_ADDR_STR_LEN];
4753 	const char *token;
4754 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4755 
4756 	/* string should look like below (macmode/macnum/maclist) */
4757 	/*   1 2 00:11:22:33:44:55 00:11:22:33:44:ff  */
4758 
4759 	/* get the MAC filter mode */
4760 	token = strsep((char**)&str, " ");
4761 	if (!token) {
4762 		return -1;
4763 	}
4764 	macmode = bcm_atoi(token);
4765 
4766 	if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
4767 		ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode));
4768 		return -1;
4769 	}
4770 
4771 	token = strsep((char**)&str, " ");
4772 	if (!token) {
4773 		return -1;
4774 	}
4775 	macnum = bcm_atoi(token);
4776 	if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
4777 		ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC"
4778 			" address entries %d\n",
4779 			macnum));
4780 		return -1;
4781 	}
4782 	/* allocate memory for the MAC list */
4783 	list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
4784 		sizeof(struct ether_addr) * macnum);
4785 	if (!list) {
4786 		ANDROID_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n"));
4787 		return -1;
4788 	}
4789 	/* prepare the MAC list */
4790 	list->count = htod32(macnum);
4791 	bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
4792 	for (i = 0; i < list->count; i++) {
4793 		token = strsep((char**)&str, " ");
4794 		if (token == NULL) {
4795 			ANDROID_ERROR(("wl_android_set_mac_address_filter : No mac address present\n"));
4796 			ret = -EINVAL;
4797 			goto exit;
4798 		}
4799 		strlcpy(eabuf, token, sizeof(eabuf));
4800 		if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
4801 			ANDROID_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d,"
4802 				" addr=%s\n",
4803 				i, eabuf));
4804 			list->count = i;
4805 			break;
4806 		}
4807 		ANDROID_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s",
4808 			i, list->count, eabuf));
4809 	}
4810 	if (i == 0)
4811 		goto exit;
4812 
4813 	/* set the list */
4814 	if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
4815 		ANDROID_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n",
4816 			ret));
4817 
4818 exit:
4819 	MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
4820 
4821 	return ret;
4822 }
4823 
wl_android_get_factory_mac_addr(struct net_device * ndev,char * command,int total_len)4824 static int wl_android_get_factory_mac_addr(struct net_device *ndev, char *command, int total_len)
4825 {
4826 	int ret;
4827 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
4828 
4829 	if (total_len < ETHER_ADDR_STR_LEN) {
4830 		ANDROID_ERROR(("wl_android_get_factory_mac_addr buflen %d"
4831 			"is less than factory mac addr\n", total_len));
4832 		return BCME_ERROR;
4833 	}
4834 	ret = snprintf(command, total_len, MACDBG,
4835 		MAC2STRDBG(bcmcfg_to_prmry_ndev(cfg)->perm_addr));
4836 	return ret;
4837 }
4838 
4839 #if defined(WLAN_ACCEL_BOOT)
wl_android_wifi_accel_on(struct net_device * dev,bool force_reg_on)4840 int wl_android_wifi_accel_on(struct net_device *dev, bool force_reg_on)
4841 {
4842 	int ret = 0;
4843 
4844 	ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4845 	if (!dev) {
4846 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4847 		return -EINVAL;
4848 	}
4849 
4850 	if (force_reg_on) {
4851 		/* First resume the bus if it is in suspended state */
4852 		ret = dhd_net_bus_resume(dev, 0);
4853 		if (ret) {
4854 			ANDROID_ERROR(("%s: dhd_net_bus_resume failed\n", __FUNCTION__));
4855 		}
4856 		/* Toggle wl_reg_on */
4857 		ret = wl_android_wifi_off(dev, TRUE);
4858 		if (ret) {
4859 			ANDROID_ERROR(("%s: wl_android_wifi_off failed\n", __FUNCTION__));
4860 		}
4861 		ret = wl_android_wifi_on(dev);
4862 		if (ret) {
4863 			ANDROID_ERROR(("%s: wl_android_wifi_on failed\n", __FUNCTION__));
4864 		}
4865 	} else {
4866 		ret = dhd_net_bus_resume(dev, 0);
4867 	}
4868 
4869 	return ret;
4870 }
4871 
wl_android_wifi_accel_off(struct net_device * dev,bool force_reg_on)4872 int wl_android_wifi_accel_off(struct net_device *dev, bool force_reg_on)
4873 {
4874 	int ret = 0;
4875 
4876 	ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4877 	if (!dev) {
4878 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4879 		return -EINVAL;
4880 	}
4881 
4882 	if (force_reg_on) {
4883 		ANDROID_ERROR(("%s: do nothing as wl_reg_on will be toggled in UP\n",
4884 			__FUNCTION__));
4885 	} else {
4886 		ret = dhd_net_bus_suspend(dev);
4887 	}
4888 
4889 	return ret;
4890 }
4891 #endif /* WLAN_ACCEL_BOOT */
4892 
4893 #ifdef WBRC
4894 extern int wbrc_wl2bt_reset(void);
4895 #endif /* WBRC */
4896 
4897 /**
4898  * Global function definitions (declared in wl_android.h)
4899  */
4900 
wl_android_wifi_on(struct net_device * dev)4901 int wl_android_wifi_on(struct net_device *dev)
4902 {
4903 	int ret = 0;
4904 	int retry = POWERUP_MAX_RETRY;
4905 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4906 
4907 	BCM_REFERENCE(dhdp);
4908 	if (!dev) {
4909 		ANDROID_ERROR(("wl_android_wifi_on: dev is null\n"));
4910 		return -EINVAL;
4911 	}
4912 
4913 	dhd_net_if_lock(dev);
4914 	WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on);
4915 	if (!g_wifi_on) {
4916 		do {
4917 			dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
4918 #ifdef BCMSDIO
4919 			ret = dhd_net_bus_resume(dev, 0);
4920 			if (ret)
4921 				goto retry_power;
4922 #endif /* BCMSDIO */
4923 			ret = dhd_net_bus_devreset(dev, FALSE);
4924 #ifdef WBRC
4925 			if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ONCE) {
4926 				ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4927 					__FUNCTION__, dhdp->dhd_induce_bh_error));
4928 				/* Forcefully set error */
4929 				ret = BCME_ERROR;
4930 				/* Clear the induced bh error */
4931 				dhdp->dhd_induce_bh_error = DHD_INDUCE_ERROR_CLEAR;
4932 			}
4933 			if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ALWAYS) {
4934 				ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4935 					__FUNCTION__, dhdp->dhd_induce_bh_error));
4936 				/* Forcefully set error */
4937 				ret = BCME_ERROR;
4938 			}
4939 #endif /* WBRC */
4940 			if (ret)
4941 				goto retry_power;
4942 #if defined(BCMSDIO) || defined(BCMDBUS)
4943 #ifdef BCMSDIO
4944 			dhd_net_bus_resume(dev, 1);
4945 #endif /* BCMSDIO */
4946 			ret = dhd_dev_init_ioctl(dev);
4947 			if (ret < 0) {
4948 				goto retry_bus;
4949 			}
4950 #endif /* BCMSDIO || BCMDBUS */
4951 			if (ret == 0) {
4952 				break;
4953 			}
4954 #if defined(BCMSDIO) || defined(BCMDBUS)
4955 retry_bus:
4956 #ifdef BCMSDIO
4957 			dhd_net_bus_suspend(dev);
4958 #endif /* BCMSDIO */
4959 #endif /* BCMSDIO || BCMDBUS */
4960 retry_power:
4961 			ANDROID_ERROR(("failed to power up wifi chip, retry again (%d left) **\n\n",
4962 				retry));
4963 			dhd_net_bus_devreset(dev, TRUE);
4964 			dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4965 #ifdef WBRC
4966 			/* Inform BT reset which will internally wait till BT reset is done */
4967 			if (wbrc_wl2bt_reset()) {
4968 				ANDROID_ERROR(("Failed to reset BT, nothing to be done!!!!\n"));
4969 			}
4970 #endif /* WBRC */
4971 		} while (retry-- > 0);
4972 		if (ret != 0) {
4973 			ANDROID_ERROR(("failed to power up wifi chip, max retry reached **\n\n"));
4974 #ifdef BCM_DETECT_TURN_ON_FAILURE
4975 			BUG_ON(1);
4976 #endif /* BCM_DETECT_TURN_ON_FAILURE */
4977 			goto exit;
4978 		}
4979 		g_wifi_on = TRUE;
4980 	}
4981 
4982 exit:
4983 	if (ret)
4984 		WL_MSG(dev->name, "Failed %d\n", ret);
4985 	else
4986 		WL_MSG(dev->name, "Success\n");
4987 	dhd_net_if_unlock(dev);
4988 	return ret;
4989 }
4990 
wl_android_wifi_off(struct net_device * dev,bool on_failure)4991 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
4992 {
4993 	int ret = 0;
4994 
4995 	if (!dev) {
4996 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4997 		return -EINVAL;
4998 	}
4999 
5000 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
5001 	ret = dhd_debug_uart_is_running(dev);
5002 	if (ret) {
5003 		ANDROID_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
5004 		return -EBUSY;
5005 	}
5006 #endif	/* BCMPCIE && DHD_DEBUG_UART */
5007 	dhd_net_if_lock(dev);
5008 	WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure);
5009 	if (g_wifi_on || on_failure) {
5010 #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
5011 		ret = dhd_net_bus_devreset(dev, TRUE);
5012 #ifdef BCMSDIO
5013 		dhd_net_bus_suspend(dev);
5014 #endif /* BCMSDIO */
5015 #endif /* BCMSDIO || BCMPCIE || BCMDBUS */
5016 		dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
5017 		g_wifi_on = FALSE;
5018 	}
5019 	WL_MSG(dev->name, "out\n");
5020 	dhd_net_if_unlock(dev);
5021 
5022 	return ret;
5023 }
5024 
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)5025 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
5026 {
5027 	if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
5028 		return -1;
5029 	return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
5030 }
5031 
5032 #ifdef CONNECTION_STATISTICS
5033 static int
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)5034 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
5035 {
5036 	int err;
5037 	wl_chanim_stats_t *list;
5038 	/* Parameter _and_ returned buffer of chanim_stats. */
5039 	wl_chanim_stats_t param;
5040 	u8 result[WLC_IOCTL_SMLEN];
5041 	chanim_stats_t *stats;
5042 
5043 	bzero(&param, sizeof(param));
5044 
5045 	param.buflen = htod32(sizeof(wl_chanim_stats_t));
5046 	param.count = htod32(WL_CHANIM_COUNT_ONE);
5047 
5048 	if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
5049 		(char*)result, sizeof(result), 0)) < 0) {
5050 		ANDROID_ERROR(("Failed to get chanim results %d \n", err));
5051 		return err;
5052 	}
5053 
5054 	list = (wl_chanim_stats_t*)result;
5055 
5056 	list->buflen = dtoh32(list->buflen);
5057 	list->version = dtoh32(list->version);
5058 	list->count = dtoh32(list->count);
5059 
5060 	if (list->buflen == 0) {
5061 		list->version = 0;
5062 		list->count = 0;
5063 	} else if (list->version != WL_CHANIM_STATS_VERSION) {
5064 		ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
5065 			"but driver supports only version %d.\n",
5066 				list->version, WL_CHANIM_STATS_VERSION));
5067 		list->buflen = 0;
5068 		list->count = 0;
5069 	}
5070 
5071 	stats = list->stats;
5072 	stats->glitchcnt = dtoh32(stats->glitchcnt);
5073 	stats->badplcp = dtoh32(stats->badplcp);
5074 	stats->chanspec = dtoh16(stats->chanspec);
5075 	stats->timestamp = dtoh32(stats->timestamp);
5076 	stats->chan_idle = dtoh32(stats->chan_idle);
5077 
5078 	ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
5079 		stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
5080 		stats->timestamp));
5081 
5082 	*chan_idle = stats->chan_idle;
5083 
5084 	return (err);
5085 }
5086 
5087 static int
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)5088 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
5089 {
5090 	static char iovar_buf[WLC_IOCTL_MAXLEN];
5091 	const wl_cnt_wlc_t* wlc_cnt = NULL;
5092 #ifndef DISABLE_IF_COUNTERS
5093 	wl_if_stats_t* if_stats = NULL;
5094 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5095 #ifdef BCMDONGLEHOST
5096 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
5097 #endif /* BCMDONGLEHOST */
5098 #endif /* DISABLE_IF_COUNTERS */
5099 
5100 	int link_speed = 0;
5101 	struct connection_stats *output;
5102 	unsigned int bufsize = 0;
5103 	int bytes_written = -1;
5104 	int ret = 0;
5105 
5106 	ANDROID_INFO(("wl_android_get_connection_stats: enter Get Connection Stats\n"));
5107 
5108 	if (total_len <= 0) {
5109 		ANDROID_ERROR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len));
5110 		goto error;
5111 	}
5112 
5113 	bufsize = total_len;
5114 	if (bufsize < sizeof(struct connection_stats)) {
5115 		ANDROID_ERROR(("wl_android_get_connection_stats: not enough buffer size, provided=%u,"
5116 			" requires=%zu\n",
5117 			bufsize,
5118 			sizeof(struct connection_stats)));
5119 		goto error;
5120 	}
5121 
5122 	output = (struct connection_stats *)command;
5123 
5124 #ifndef DISABLE_IF_COUNTERS
5125 	if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
5126 	if (if_stats == NULL) {
5127 		ANDROID_ERROR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
5128 		goto error;
5129 	}
5130 	bzero(if_stats, sizeof(*if_stats));
5131 
5132 #ifdef BCMDONGLEHOST
5133 	if (FW_SUPPORTED(dhdp, ifst)) {
5134 		ret = wl_cfg80211_ifstats_counters(dev, if_stats);
5135 	} else
5136 #endif /* BCMDONGLEHOST */
5137 	{
5138 		ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5139 			(char *)if_stats, sizeof(*if_stats), NULL);
5140 	}
5141 
5142 	ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5143 		(char *)if_stats, sizeof(*if_stats), NULL);
5144 	if (ret) {
5145 		ANDROID_ERROR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n",
5146 			ret));
5147 
5148 		/* In case if_stats IOVAR is not supported, get information from counters. */
5149 #endif /* DISABLE_IF_COUNTERS */
5150 		ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
5151 			iovar_buf, WLC_IOCTL_MAXLEN, NULL);
5152 		if (unlikely(ret)) {
5153 			ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
5154 			goto error;
5155 		}
5156 		ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
5157 		if (ret != BCME_OK) {
5158 			ANDROID_ERROR(("wl_android_get_connection_stats:"
5159 			" wl_cntbuf_to_xtlv_format ERR %d\n",
5160 			ret));
5161 			goto error;
5162 		}
5163 
5164 		if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
5165 			ANDROID_ERROR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
5166 			goto error;
5167 		}
5168 
5169 		output->txframe   = dtoh32(wlc_cnt->txframe);
5170 		output->txbyte    = dtoh32(wlc_cnt->txbyte);
5171 		output->txerror   = dtoh32(wlc_cnt->txerror);
5172 		output->rxframe   = dtoh32(wlc_cnt->rxframe);
5173 		output->rxbyte    = dtoh32(wlc_cnt->rxbyte);
5174 		output->txfail    = dtoh32(wlc_cnt->txfail);
5175 		output->txretry   = dtoh32(wlc_cnt->txretry);
5176 		output->txretrie  = dtoh32(wlc_cnt->txretrie);
5177 		output->txrts     = dtoh32(wlc_cnt->txrts);
5178 		output->txnocts   = dtoh32(wlc_cnt->txnocts);
5179 		output->txexptime = dtoh32(wlc_cnt->txexptime);
5180 #ifndef DISABLE_IF_COUNTERS
5181 	} else {
5182 		/* Populate from if_stats. */
5183 		if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
5184 			ANDROID_ERROR(("wl_android_get_connection_stats: incorrect version of"
5185 				" wl_if_stats_t,"
5186 				" expected=%u got=%u\n",
5187 				WL_IF_STATS_T_VERSION, if_stats->version));
5188 			goto error;
5189 		}
5190 
5191 		output->txframe   = (uint32)dtoh64(if_stats->txframe);
5192 		output->txbyte    = (uint32)dtoh64(if_stats->txbyte);
5193 		output->txerror   = (uint32)dtoh64(if_stats->txerror);
5194 		output->rxframe   = (uint32)dtoh64(if_stats->rxframe);
5195 		output->rxbyte    = (uint32)dtoh64(if_stats->rxbyte);
5196 		output->txfail    = (uint32)dtoh64(if_stats->txfail);
5197 		output->txretry   = (uint32)dtoh64(if_stats->txretry);
5198 		output->txretrie  = (uint32)dtoh64(if_stats->txretrie);
5199 		if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
5200 			output->txexptime = (uint32)dtoh64(if_stats->txexptime);
5201 			output->txrts     = (uint32)dtoh64(if_stats->txrts);
5202 			output->txnocts   = (uint32)dtoh64(if_stats->txnocts);
5203 		} else {
5204 			output->txexptime = 0;
5205 			output->txrts     = 0;
5206 			output->txnocts   = 0;
5207 		}
5208 	}
5209 #endif /* DISABLE_IF_COUNTERS */
5210 
5211 	/* link_speed is in kbps */
5212 	ret = wldev_get_link_speed(dev, &link_speed);
5213 	if (ret || link_speed < 0) {
5214 		ANDROID_ERROR(("wl_android_get_connection_stats: wldev_get_link_speed()"
5215 			" failed, ret=%d, speed=%d\n",
5216 			ret, link_speed));
5217 		goto error;
5218 	}
5219 
5220 	output->txrate    = link_speed;
5221 
5222 	/* Channel idle ratio. */
5223 	if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
5224 		output->chan_idle = 0;
5225 	};
5226 
5227 	bytes_written = sizeof(struct connection_stats);
5228 
5229 error:
5230 #ifndef DISABLE_IF_COUNTERS
5231 	if (if_stats) {
5232 		MFREE(cfg->osh, if_stats, sizeof(*if_stats));
5233 	}
5234 #endif /* DISABLE_IF_COUNTERS */
5235 
5236 	return bytes_written;
5237 }
5238 #endif /* CONNECTION_STATISTICS */
5239 
5240 #ifdef WL_NATOE
5241 static int
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)5242 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
5243 {
5244 	int ret = BCME_ERROR;
5245 	char *pcmd = command;
5246 	char *str = NULL;
5247 	wl_natoe_cmd_info_t cmd_info;
5248 	const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
5249 
5250 	/* skip to cmd name after "natoe" */
5251 	str = bcmstrtok(&pcmd, " ", NULL);
5252 
5253 	/* If natoe subcmd name is not provided, return error */
5254 	if (*pcmd == '\0') {
5255 		ANDROID_ERROR(("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
5256 		ret = -EINVAL;
5257 		return ret;
5258 	}
5259 
5260 	/* get the natoe command name to str */
5261 	str = bcmstrtok(&pcmd, " ", NULL);
5262 
5263 	while (natoe_cmd->name != NULL) {
5264 		if (strcmp(natoe_cmd->name, str) == 0)  {
5265 			/* dispacth cmd to appropriate handler */
5266 			if (natoe_cmd->handler) {
5267 				cmd_info.command = command;
5268 				cmd_info.tot_len = total_len;
5269 				ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
5270 			}
5271 			return ret;
5272 		}
5273 		natoe_cmd++;
5274 	}
5275 	return ret;
5276 }
5277 
5278 static int
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)5279 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
5280 {
5281 	int res = BCME_OK;
5282 	wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
5283 	uint8 *command = cmd_info->command;
5284 	uint16 total_len = cmd_info->tot_len;
5285 	uint16 bytes_written = 0;
5286 
5287 	UNUSED_PARAMETER(len);
5288 
5289 	switch (type) {
5290 
5291 	case WL_NATOE_XTLV_ENABLE:
5292 	{
5293 		bytes_written = snprintf(command, total_len, "natoe: %s\n",
5294 				*data?"enabled":"disabled");
5295 		cmd_info->bytes_written = bytes_written;
5296 		break;
5297 	}
5298 
5299 	case WL_NATOE_XTLV_CONFIG_IPS:
5300 	{
5301 		wl_natoe_config_ips_t *config_ips;
5302 		uint8 buf[16];
5303 
5304 		config_ips = (wl_natoe_config_ips_t *)data;
5305 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
5306 		bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
5307 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
5308 		bytes_written += snprintf(command + bytes_written, total_len,
5309 				"sta netmask: %s\n", buf);
5310 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
5311 		bytes_written += snprintf(command + bytes_written, total_len,
5312 				"sta router ip: %s\n", buf);
5313 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
5314 		bytes_written += snprintf(command + bytes_written, total_len,
5315 				"sta dns ip: %s\n", buf);
5316 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
5317 		bytes_written += snprintf(command + bytes_written, total_len,
5318 				"ap ip: %s\n", buf);
5319 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
5320 		bytes_written += snprintf(command + bytes_written, total_len,
5321 				"ap netmask: %s\n", buf);
5322 		cmd_info->bytes_written = bytes_written;
5323 		break;
5324 	}
5325 
5326 	case WL_NATOE_XTLV_CONFIG_PORTS:
5327 	{
5328 		wl_natoe_ports_config_t *ports_config;
5329 
5330 		ports_config = (wl_natoe_ports_config_t *)data;
5331 		bytes_written = snprintf(command, total_len, "starting port num: %d\n",
5332 				dtoh16(ports_config->start_port_num));
5333 		bytes_written += snprintf(command + bytes_written, total_len,
5334 				"number of ports: %d\n", dtoh16(ports_config->no_of_ports));
5335 		cmd_info->bytes_written = bytes_written;
5336 		break;
5337 	}
5338 
5339 	case WL_NATOE_XTLV_DBG_STATS:
5340 	{
5341 		char *stats_dump = (char *)data;
5342 
5343 		bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
5344 		cmd_info->bytes_written = bytes_written;
5345 		break;
5346 	}
5347 
5348 	case WL_NATOE_XTLV_TBL_CNT:
5349 	{
5350 		bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
5351 				dtoh32(*(uint32 *)data));
5352 		cmd_info->bytes_written = bytes_written;
5353 		break;
5354 	}
5355 
5356 	default:
5357 		/* ignore */
5358 		break;
5359 	}
5360 
5361 	return res;
5362 }
5363 
5364 /*
5365  *   --- common for all natoe get commands ----
5366  */
5367 static int
wl_natoe_get_ioctl(struct net_device * dev,wl_natoe_ioc_t * natoe_ioc,uint16 iocsz,uint8 * buf,uint16 buflen,wl_natoe_cmd_info_t * cmd_info)5368 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
5369 		uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
5370 {
5371 	/* for gets we only need to pass ioc header */
5372 	wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
5373 	int res;
5374 
5375 	/*  send getbuf natoe iovar */
5376 	res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
5377 			buflen, NULL);
5378 
5379 	/*  check the response buff  */
5380 	if ((res == BCME_OK)) {
5381 		/* scans ioctl tlvbuf f& invokes the cbfn for processing  */
5382 		res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
5383 				BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
5384 
5385 		if (res == BCME_OK) {
5386 			res = cmd_info->bytes_written;
5387 		}
5388 	}
5389 	else
5390 	{
5391 		ANDROID_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res));
5392 		res = BCME_ERROR;
5393 	}
5394 
5395 	return res;
5396 }
5397 
5398 static int
wl_android_natoe_subcmd_enable(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5399 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5400 		char *command, wl_natoe_cmd_info_t *cmd_info)
5401 {
5402 	int ret = BCME_OK;
5403 	wl_natoe_ioc_t *natoe_ioc;
5404 	char *pcmd = command;
5405 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5406 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5407 	bcm_xtlv_t *pxtlv = NULL;
5408 	char *ioctl_buf = NULL;
5409 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5410 
5411 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5412 	if (!ioctl_buf) {
5413 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5414 		return -ENOMEM;
5415 	}
5416 
5417 	/* alloc mem for ioctl headr + tlv data */
5418 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5419 	if (!natoe_ioc) {
5420 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5421 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5422 		return -ENOMEM;
5423 	}
5424 
5425 	/* make up natoe cmd ioctl header */
5426 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5427 	natoe_ioc->id = htod16(cmd->id);
5428 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5429 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5430 
5431 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5432 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5433 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5434 				WLC_IOCTL_MEDLEN, cmd_info);
5435 		if (ret != BCME_OK) {
5436 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
5437 			ret = -EINVAL;
5438 		}
5439 	} else {	/* set */
5440 		uint8 val = bcm_atoi(pcmd);
5441 
5442 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5443 		/* save buflen at start */
5444 		uint16 buflen_at_start = buflen;
5445 
5446 		/* we'll adjust final ioc size at the end */
5447 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5448 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5449 
5450 		if (ret != BCME_OK) {
5451 			ret = -EINVAL;
5452 			goto exit;
5453 		}
5454 
5455 		/* adjust iocsz to the end of last data record */
5456 		natoe_ioc->len = (buflen_at_start - buflen);
5457 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5458 
5459 		ret = wldev_iovar_setbuf(dev, "natoe",
5460 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5461 		if (ret != BCME_OK) {
5462 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5463 			ret = -EINVAL;
5464 		}
5465 	}
5466 
5467 exit:
5468 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5469 	MFREE(cfg->osh, natoe_ioc, iocsz);
5470 
5471 	return ret;
5472 }
5473 
5474 static int
wl_android_natoe_subcmd_config_ips(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5475 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
5476 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5477 {
5478 	int ret = BCME_OK;
5479 	wl_natoe_config_ips_t config_ips;
5480 	wl_natoe_ioc_t *natoe_ioc;
5481 	char *pcmd = command;
5482 	char *str;
5483 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5484 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5485 	bcm_xtlv_t *pxtlv = NULL;
5486 	char *ioctl_buf = NULL;
5487 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5488 
5489 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5490 	if (!ioctl_buf) {
5491 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5492 		return -ENOMEM;
5493 	}
5494 
5495 	/* alloc mem for ioctl headr + tlv data */
5496 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5497 	if (!natoe_ioc) {
5498 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5499 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5500 		return -ENOMEM;
5501 	}
5502 
5503 	/* make up natoe cmd ioctl header */
5504 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5505 	natoe_ioc->id = htod16(cmd->id);
5506 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5507 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5508 
5509 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5510 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5511 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5512 				WLC_IOCTL_MEDLEN, cmd_info);
5513 		if (ret != BCME_OK) {
5514 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
5515 			ret = -EINVAL;
5516 		}
5517 	} else {	/* set */
5518 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5519 		/* save buflen at start */
5520 		uint16 buflen_at_start = buflen;
5521 
5522 		bzero(&config_ips, sizeof(config_ips));
5523 
5524 		str = bcmstrtok(&pcmd, " ", NULL);
5525 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
5526 			ANDROID_ERROR(("Invalid STA IP addr %s\n", str));
5527 			ret = -EINVAL;
5528 			goto exit;
5529 		}
5530 
5531 		str = bcmstrtok(&pcmd, " ", NULL);
5532 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
5533 			ANDROID_ERROR(("Invalid STA netmask %s\n", str));
5534 			ret = -EINVAL;
5535 			goto exit;
5536 		}
5537 
5538 		str = bcmstrtok(&pcmd, " ", NULL);
5539 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
5540 			ANDROID_ERROR(("Invalid STA router IP addr %s\n", str));
5541 			ret = -EINVAL;
5542 			goto exit;
5543 		}
5544 
5545 		str = bcmstrtok(&pcmd, " ", NULL);
5546 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
5547 			ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str));
5548 			ret = -EINVAL;
5549 			goto exit;
5550 		}
5551 
5552 		str = bcmstrtok(&pcmd, " ", NULL);
5553 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
5554 			ANDROID_ERROR(("Invalid AP IP addr %s\n", str));
5555 			ret = -EINVAL;
5556 			goto exit;
5557 		}
5558 
5559 		str = bcmstrtok(&pcmd, " ", NULL);
5560 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
5561 			ANDROID_ERROR(("Invalid AP netmask %s\n", str));
5562 			ret = -EINVAL;
5563 			goto exit;
5564 		}
5565 
5566 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5567 				&buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
5568 				&config_ips, BCM_XTLV_OPTION_ALIGN32);
5569 
5570 		if (ret != BCME_OK) {
5571 			ret = -EINVAL;
5572 			goto exit;
5573 		}
5574 
5575 		/* adjust iocsz to the end of last data record */
5576 		natoe_ioc->len = (buflen_at_start - buflen);
5577 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5578 
5579 		ret = wldev_iovar_setbuf(dev, "natoe",
5580 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5581 		if (ret != BCME_OK) {
5582 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5583 			ret = -EINVAL;
5584 		}
5585 	}
5586 
5587 exit:
5588 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5589 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5590 
5591 	return ret;
5592 }
5593 
5594 static int
wl_android_natoe_subcmd_config_ports(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5595 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
5596 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5597 {
5598 	int ret = BCME_OK;
5599 	wl_natoe_ports_config_t ports_config;
5600 	wl_natoe_ioc_t *natoe_ioc;
5601 	char *pcmd = command;
5602 	char *str;
5603 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5604 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5605 	bcm_xtlv_t *pxtlv = NULL;
5606 	char *ioctl_buf = NULL;
5607 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5608 
5609 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5610 	if (!ioctl_buf) {
5611 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5612 		return -ENOMEM;
5613 	}
5614 
5615 	/* alloc mem for ioctl headr + tlv data */
5616 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5617 	if (!natoe_ioc) {
5618 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5619 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5620 		return -ENOMEM;
5621 	}
5622 
5623 	/* make up natoe cmd ioctl header */
5624 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5625 	natoe_ioc->id = htod16(cmd->id);
5626 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5627 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5628 
5629 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5630 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5631 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5632 				WLC_IOCTL_MEDLEN, cmd_info);
5633 		if (ret != BCME_OK) {
5634 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
5635 			ret = -EINVAL;
5636 		}
5637 	} else {	/* set */
5638 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5639 		/* save buflen at start */
5640 		uint16 buflen_at_start = buflen;
5641 
5642 		bzero(&ports_config, sizeof(ports_config));
5643 
5644 		str = bcmstrtok(&pcmd, " ", NULL);
5645 		if (!str) {
5646 			ANDROID_ERROR(("Invalid port string %s\n", str));
5647 			ret = -EINVAL;
5648 			goto exit;
5649 		}
5650 		ports_config.start_port_num = htod16(bcm_atoi(str));
5651 
5652 		str = bcmstrtok(&pcmd, " ", NULL);
5653 		if (!str) {
5654 			ANDROID_ERROR(("Invalid port string %s\n", str));
5655 			ret = -EINVAL;
5656 			goto exit;
5657 		}
5658 		ports_config.no_of_ports = htod16(bcm_atoi(str));
5659 
5660 		if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
5661 				NATOE_MAX_PORT_NUM) {
5662 			ANDROID_ERROR(("Invalid port configuration\n"));
5663 			ret = -EINVAL;
5664 			goto exit;
5665 		}
5666 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5667 				&buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
5668 				&ports_config, BCM_XTLV_OPTION_ALIGN32);
5669 
5670 		if (ret != BCME_OK) {
5671 			ret = -EINVAL;
5672 			goto exit;
5673 		}
5674 
5675 		/* adjust iocsz to the end of last data record */
5676 		natoe_ioc->len = (buflen_at_start - buflen);
5677 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5678 
5679 		ret = wldev_iovar_setbuf(dev, "natoe",
5680 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5681 		if (ret != BCME_OK) {
5682 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5683 			ret = -EINVAL;
5684 		}
5685 	}
5686 
5687 exit:
5688 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5689 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5690 
5691 	return ret;
5692 }
5693 
5694 static int
wl_android_natoe_subcmd_dbg_stats(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5695 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5696 		char *command, wl_natoe_cmd_info_t *cmd_info)
5697 {
5698 	int ret = BCME_OK;
5699 	wl_natoe_ioc_t *natoe_ioc;
5700 	char *pcmd = command;
5701 	uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5702 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
5703 	uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
5704 	bcm_xtlv_t *pxtlv = NULL;
5705 	char *ioctl_buf = NULL;
5706 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5707 
5708 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5709 	if (!ioctl_buf) {
5710 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5711 		return -ENOMEM;
5712 	}
5713 
5714 	/* alloc mem for ioctl headr + tlv data */
5715 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5716 	if (!natoe_ioc) {
5717 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5718 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5719 		return -ENOMEM;
5720 	}
5721 
5722 	/* make up natoe cmd ioctl header */
5723 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5724 	natoe_ioc->id = htod16(cmd->id);
5725 	natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
5726 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5727 
5728 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5729 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5730 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5731 				WLC_IOCTL_MAXLEN, cmd_info);
5732 		if (ret != BCME_OK) {
5733 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
5734 			ret = -EINVAL;
5735 		}
5736 	} else {	/* set */
5737 		uint8 val = bcm_atoi(pcmd);
5738 
5739 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5740 		/* save buflen at start */
5741 		uint16 buflen_at_start = buflen;
5742 
5743 		/* we'll adjust final ioc size at the end */
5744 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5745 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5746 
5747 		if (ret != BCME_OK) {
5748 			ret = -EINVAL;
5749 			goto exit;
5750 		}
5751 
5752 		/* adjust iocsz to the end of last data record */
5753 		natoe_ioc->len = (buflen_at_start - buflen);
5754 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5755 
5756 		ret = wldev_iovar_setbuf(dev, "natoe",
5757 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
5758 		if (ret != BCME_OK) {
5759 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5760 			ret = -EINVAL;
5761 		}
5762 	}
5763 
5764 exit:
5765 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5766 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
5767 
5768 	return ret;
5769 }
5770 
5771 static int
wl_android_natoe_subcmd_tbl_cnt(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5772 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5773 		char *command, wl_natoe_cmd_info_t *cmd_info)
5774 {
5775 	int ret = BCME_OK;
5776 	wl_natoe_ioc_t *natoe_ioc;
5777 	char *pcmd = command;
5778 	uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5779 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5780 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5781 	bcm_xtlv_t *pxtlv = NULL;
5782 	char *ioctl_buf = NULL;
5783 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5784 
5785 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5786 	if (!ioctl_buf) {
5787 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5788 		return -ENOMEM;
5789 	}
5790 
5791 	/* alloc mem for ioctl headr + tlv data */
5792 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5793 	if (!natoe_ioc) {
5794 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5795 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5796 		return -ENOMEM;
5797 	}
5798 
5799 	/* make up natoe cmd ioctl header */
5800 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5801 	natoe_ioc->id = htod16(cmd->id);
5802 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5803 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5804 
5805 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5806 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5807 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5808 				WLC_IOCTL_MEDLEN, cmd_info);
5809 		if (ret != BCME_OK) {
5810 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
5811 			ret = -EINVAL;
5812 		}
5813 	} else {	/* set */
5814 		uint32 val = bcm_atoi(pcmd);
5815 
5816 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5817 		/* save buflen at start */
5818 		uint16 buflen_at_start = buflen;
5819 
5820 		/* we'll adjust final ioc size at the end */
5821 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
5822 			sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
5823 
5824 		if (ret != BCME_OK) {
5825 			ret = -EINVAL;
5826 			goto exit;
5827 		}
5828 
5829 		/* adjust iocsz to the end of last data record */
5830 		natoe_ioc->len = (buflen_at_start - buflen);
5831 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5832 
5833 		ret = wldev_iovar_setbuf(dev, "natoe",
5834 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5835 		if (ret != BCME_OK) {
5836 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5837 			ret = -EINVAL;
5838 		}
5839 	}
5840 
5841 exit:
5842 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5843 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5844 
5845 	return ret;
5846 }
5847 
5848 #endif /* WL_NATOE */
5849 
5850 #ifdef WL_MBO
5851 static int
wl_android_process_mbo_cmd(struct net_device * dev,char * command,int total_len)5852 wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len)
5853 {
5854 	int ret = BCME_ERROR;
5855 	char *pcmd = command;
5856 	char *str = NULL;
5857 	wl_drv_cmd_info_t cmd_info;
5858 	const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
5859 
5860 	/* skip to cmd name after "mbo" */
5861 	str = bcmstrtok(&pcmd, " ", NULL);
5862 
5863 	/* If mbo subcmd name is not provided, return error */
5864 	if (*pcmd == '\0') {
5865 		ANDROID_ERROR(("mbo subcmd not provided %s\n", __FUNCTION__));
5866 		ret = -EINVAL;
5867 		return ret;
5868 	}
5869 
5870 	/* get the mbo command name to str */
5871 	str = bcmstrtok(&pcmd, " ", NULL);
5872 
5873 	while (mbo_cmd->name != NULL) {
5874 		if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
5875 			/* dispatch cmd to appropriate handler */
5876 			if (mbo_cmd->handler) {
5877 				cmd_info.command = command;
5878 				cmd_info.tot_len = total_len;
5879 				ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
5880 			}
5881 			return ret;
5882 		}
5883 		mbo_cmd++;
5884 	}
5885 	return ret;
5886 }
5887 
5888 static int
wl_android_send_wnm_notif(struct net_device * dev,bcm_iov_buf_t * iov_buf,uint16 iov_buf_len,uint8 * iov_resp,uint16 iov_resp_len,uint8 sub_elem_type)5889 wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf,
5890 	uint16 iov_buf_len, uint8 *iov_resp, uint16 iov_resp_len, uint8 sub_elem_type)
5891 {
5892 	int ret = BCME_OK;
5893 	uint8 *pxtlv = NULL;
5894 	uint16 iovlen = 0;
5895 	uint16 buflen = 0, buflen_start = 0;
5896 
5897 	memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
5898 	iov_buf->version = WL_MBO_IOV_VERSION;
5899 	iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
5900 	buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
5901 	pxtlv = (uint8 *)&iov_buf->data[0];
5902 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
5903 		sizeof(sub_elem_type), &sub_elem_type, BCM_XTLV_OPTION_ALIGN32);
5904 	if (ret != BCME_OK) {
5905 		return ret;
5906 	}
5907 	iov_buf->len = buflen_start - buflen;
5908 	iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5909 	ret = wldev_iovar_setbuf(dev, "mbo",
5910 			iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5911 	if (ret != BCME_OK) {
5912 		ANDROID_ERROR(("Fail to sent wnm notif %d\n", ret));
5913 	}
5914 	return ret;
5915 }
5916 
5917 static int
wl_android_mbo_resp_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5918 wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5919 {
5920 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
5921 	uint8 *command = cmd_info->command;
5922 	uint16 total_len = cmd_info->tot_len;
5923 	uint16 bytes_written = 0;
5924 
5925 	UNUSED_PARAMETER(len);
5926 	/* TODO: validate data value */
5927 	if (data == NULL) {
5928 		ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
5929 		return -EINVAL;
5930 	}
5931 	switch (type) {
5932 		case WL_MBO_XTLV_CELL_DATA_CAP:
5933 		{
5934 			bytes_written = snprintf(command, total_len, "cell_data_cap: %u\n", *data);
5935 			cmd_info->bytes_written = bytes_written;
5936 		}
5937 		break;
5938 		default:
5939 			ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
5940 	}
5941 	return BCME_OK;
5942 }
5943 
5944 static int
wl_android_mbo_subcmd_cell_data_cap(struct net_device * dev,const wl_drv_sub_cmd_t * cmd,char * command,wl_drv_cmd_info_t * cmd_info)5945 wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd_t *cmd,
5946 		char *command, wl_drv_cmd_info_t *cmd_info)
5947 {
5948 	int ret = BCME_OK;
5949 	uint8 *pxtlv = NULL;
5950 	uint16 buflen = 0, buflen_start = 0;
5951 	uint16 iovlen = 0;
5952 	char *pcmd = command;
5953 	bcm_iov_buf_t *iov_buf = NULL;
5954 	bcm_iov_buf_t *p_resp = NULL;
5955 	uint8 *iov_resp = NULL;
5956 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5957 	uint16 version;
5958 
5959 	/* first get the configured value */
5960 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5961 	if (iov_buf == NULL) {
5962 		ret = -ENOMEM;
5963 		ANDROID_ERROR(("iov buf memory alloc exited\n"));
5964 		goto exit;
5965 	}
5966 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5967 	if (iov_resp == NULL) {
5968 		ret = -ENOMEM;
5969 		ANDROID_ERROR(("iov resp memory alloc exited\n"));
5970 		goto exit;
5971 	}
5972 
5973 	/* fill header */
5974 	iov_buf->version = WL_MBO_IOV_VERSION;
5975 	iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
5976 
5977 	ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
5978 		WLC_IOCTL_MAXLEN,
5979 		NULL);
5980 	if (ret != BCME_OK) {
5981 		goto exit;
5982 	}
5983 	p_resp = (bcm_iov_buf_t *)iov_resp;
5984 
5985 	/* get */
5986 	if (*pcmd == WL_IOCTL_ACTION_GET) {
5987 		/* Check for version */
5988 		version = dtoh16(*(uint16 *)iov_resp);
5989 		if (version != WL_MBO_IOV_VERSION) {
5990 			ret = -EINVAL;
5991 		}
5992 		if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
5993 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
5994 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
5995 				wl_android_mbo_resp_parse_cbfn);
5996 			if (ret == BCME_OK) {
5997 				ret = cmd_info->bytes_written;
5998 			}
5999 		} else {
6000 			ret = -EINVAL;
6001 			ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
6002 			goto exit;
6003 		}
6004 	} else {
6005 		uint8 cell_cap = bcm_atoi(pcmd);
6006 		const uint8* old_cell_cap = NULL;
6007 		uint16 len = 0;
6008 
6009 		old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len,
6010 			WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32);
6011 		if (old_cell_cap && *old_cell_cap == cell_cap) {
6012 			ANDROID_ERROR(("No change is cellular data capability\n"));
6013 			/* No change in value */
6014 			goto exit;
6015 		}
6016 
6017 		buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
6018 
6019 		if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
6020 			cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
6021 			ANDROID_ERROR(("wrong value %u\n", cell_cap));
6022 			ret = -EINVAL;
6023 			goto exit;
6024 		}
6025 		pxtlv = (uint8 *)&iov_buf->data[0];
6026 		ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
6027 			sizeof(cell_cap), &cell_cap, BCM_XTLV_OPTION_ALIGN32);
6028 		if (ret != BCME_OK) {
6029 			goto exit;
6030 		}
6031 		iov_buf->len = buflen_start - buflen;
6032 		iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6033 		ret = wldev_iovar_setbuf(dev, "mbo",
6034 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6035 		if (ret != BCME_OK) {
6036 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6037 			ret = -EINVAL;
6038 			goto exit;
6039 		}
6040 		/* Skip for CUSTOMER_HW4 - WNM notification
6041 		 * for cellular data capability is handled by host
6042 		 */
6043 #if !defined(CUSTOMER_HW4)
6044 		/* send a WNM notification request to associated AP */
6045 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6046 			ANDROID_INFO(("Sending WNM Notif\n"));
6047 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6048 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP);
6049 			if (ret != BCME_OK) {
6050 				ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6051 				ret = -EINVAL;
6052 			}
6053 		}
6054 #endif /* CUSTOMER_HW4 */
6055 	}
6056 exit:
6057 	if (iov_buf) {
6058 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6059 	}
6060 	if (iov_resp) {
6061 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6062 	}
6063 	return ret;
6064 }
6065 
6066 static int
wl_android_mbo_non_pref_chan_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)6067 wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
6068 {
6069 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
6070 	uint8 *command = cmd_info->command + cmd_info->bytes_written;
6071 	uint16 total_len = cmd_info->tot_len;
6072 	uint16 bytes_written = 0;
6073 
6074 	ANDROID_INFO(("Total bytes written at begining %u\n", cmd_info->bytes_written));
6075 	UNUSED_PARAMETER(len);
6076 	if (data == NULL) {
6077 		ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
6078 		return -EINVAL;
6079 	}
6080 	switch (type) {
6081 		case WL_MBO_XTLV_OPCLASS:
6082 		{
6083 			bytes_written = snprintf(command, total_len, "%u:", *data);
6084 			ANDROID_ERROR(("wr %u %u\n", bytes_written, *data));
6085 			command += bytes_written;
6086 			cmd_info->bytes_written += bytes_written;
6087 		}
6088 		break;
6089 		case WL_MBO_XTLV_CHAN:
6090 		{
6091 			bytes_written = snprintf(command, total_len, "%u:", *data);
6092 			ANDROID_ERROR(("wr %u\n", bytes_written));
6093 			command += bytes_written;
6094 			cmd_info->bytes_written += bytes_written;
6095 		}
6096 		break;
6097 		case WL_MBO_XTLV_PREFERENCE:
6098 		{
6099 			bytes_written = snprintf(command, total_len, "%u:", *data);
6100 			ANDROID_ERROR(("wr %u\n", bytes_written));
6101 			command += bytes_written;
6102 			cmd_info->bytes_written += bytes_written;
6103 		}
6104 		break;
6105 		case WL_MBO_XTLV_REASON_CODE:
6106 		{
6107 			bytes_written = snprintf(command, total_len, "%u ", *data);
6108 			ANDROID_ERROR(("wr %u\n", bytes_written));
6109 			command += bytes_written;
6110 			cmd_info->bytes_written += bytes_written;
6111 		}
6112 		break;
6113 		default:
6114 			ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
6115 	}
6116 	ANDROID_INFO(("Total bytes written %u\n", cmd_info->bytes_written));
6117 	return BCME_OK;
6118 }
6119 
6120 static int
wl_android_mbo_subcmd_non_pref_chan(struct net_device * dev,const wl_drv_sub_cmd_t * cmd,char * command,wl_drv_cmd_info_t * cmd_info)6121 wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
6122 		const wl_drv_sub_cmd_t *cmd, char *command,
6123 		wl_drv_cmd_info_t *cmd_info)
6124 {
6125 	int ret = BCME_OK;
6126 	uint8 *pxtlv = NULL;
6127 	uint16 buflen = 0, buflen_start = 0;
6128 	uint16 iovlen = 0;
6129 	char *pcmd = command;
6130 	bcm_iov_buf_t *iov_buf = NULL;
6131 	bcm_iov_buf_t *p_resp = NULL;
6132 	uint8 *iov_resp = NULL;
6133 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6134 	uint16 version;
6135 
6136 	ANDROID_ERROR(("%s:%d\n", __FUNCTION__, __LINE__));
6137 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
6138 	if (iov_buf == NULL) {
6139 		ret = -ENOMEM;
6140 		ANDROID_ERROR(("iov buf memory alloc exited\n"));
6141 		goto exit;
6142 	}
6143 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6144 	if (iov_resp == NULL) {
6145 		ret = -ENOMEM;
6146 		ANDROID_ERROR(("iov resp memory alloc exited\n"));
6147 		goto exit;
6148 	}
6149 	/* get */
6150 	if (*pcmd == WL_IOCTL_ACTION_GET) {
6151 		/* fill header */
6152 		iov_buf->version = WL_MBO_IOV_VERSION;
6153 		iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
6154 
6155 		ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
6156 				WLC_IOCTL_MAXLEN, NULL);
6157 		if (ret != BCME_OK) {
6158 			goto exit;
6159 		}
6160 		p_resp = (bcm_iov_buf_t *)iov_resp;
6161 		/* Check for version */
6162 		version = dtoh16(*(uint16 *)iov_resp);
6163 		if (version != WL_MBO_IOV_VERSION) {
6164 			ANDROID_ERROR(("Version mismatch. returned ver %u expected %u\n",
6165 				version, WL_MBO_IOV_VERSION));
6166 			ret = -EINVAL;
6167 		}
6168 		if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
6169 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
6170 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
6171 				wl_android_mbo_non_pref_chan_parse_cbfn);
6172 			if (ret == BCME_OK) {
6173 				ret = cmd_info->bytes_written;
6174 			}
6175 		} else {
6176 			ret = -EINVAL;
6177 			ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
6178 			goto exit;
6179 		}
6180 	} else {
6181 		char *str = pcmd;
6182 		uint opcl = 0, ch = 0, pref = 0, rc = 0;
6183 
6184 		str = bcmstrtok(&pcmd, " ", NULL);
6185 		if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) {
6186 			/* delete all configurations */
6187 			iov_buf->version = WL_MBO_IOV_VERSION;
6188 			iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
6189 			iov_buf->len = 0;
6190 			iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6191 			ret = wldev_iovar_setbuf(dev, "mbo",
6192 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6193 			if (ret != BCME_OK) {
6194 				ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6195 				ret = -EINVAL;
6196 				goto exit;
6197 			}
6198 		} else {
6199 			ANDROID_ERROR(("Unknown command %s\n", str));
6200 			goto exit;
6201 		}
6202 		/* parse non pref channel list */
6203 		if (strnicmp(str, "set", 3) == 0) {
6204 			uint8 cnt = 0;
6205 			str = bcmstrtok(&pcmd, " ", NULL);
6206 			while (str != NULL) {
6207 				ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
6208 				ANDROID_ERROR(("buflen %u op %u, ch %u, pref %u rc %u\n",
6209 					buflen, opcl, ch, pref, rc));
6210 				if (ret != 4) {
6211 					ANDROID_ERROR(("Not all parameter presents\n"));
6212 					ret = -EINVAL;
6213 				}
6214 				/* TODO: add a validation check here */
6215 				memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
6216 				buflen = buflen_start = WLC_IOCTL_MEDLEN;
6217 				pxtlv = (uint8 *)&iov_buf->data[0];
6218 				/* opclass */
6219 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
6220 					sizeof(uint8), (uint8 *)&opcl, BCM_XTLV_OPTION_ALIGN32);
6221 				if (ret != BCME_OK) {
6222 					goto exit;
6223 				}
6224 				/* channel */
6225 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
6226 					sizeof(uint8), (uint8 *)&ch, BCM_XTLV_OPTION_ALIGN32);
6227 				if (ret != BCME_OK) {
6228 					goto exit;
6229 				}
6230 				/* preference */
6231 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
6232 					sizeof(uint8), (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
6233 				if (ret != BCME_OK) {
6234 					goto exit;
6235 				}
6236 				/* reason */
6237 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
6238 					sizeof(uint8), (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
6239 				if (ret != BCME_OK) {
6240 					goto exit;
6241 				}
6242 				ANDROID_ERROR(("len %u\n", (buflen_start - buflen)));
6243 				/* Now set the new non pref channels */
6244 				iov_buf->version = WL_MBO_IOV_VERSION;
6245 				iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
6246 				iov_buf->len = buflen_start - buflen;
6247 				iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6248 				ret = wldev_iovar_setbuf(dev, "mbo",
6249 					iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL);
6250 				if (ret != BCME_OK) {
6251 					ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6252 					ret = -EINVAL;
6253 					goto exit;
6254 				}
6255 				cnt++;
6256 				if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
6257 					break;
6258 				}
6259 				ANDROID_ERROR(("%d cnt %u\n", __LINE__, cnt));
6260 				str = bcmstrtok(&pcmd, " ", NULL);
6261 			}
6262 		}
6263 		/* send a WNM notification request to associated AP */
6264 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6265 			ANDROID_INFO(("Sending WNM Notif\n"));
6266 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6267 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT);
6268 			if (ret != BCME_OK) {
6269 				ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6270 				ret = -EINVAL;
6271 			}
6272 		}
6273 	}
6274 exit:
6275 	if (iov_buf) {
6276 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6277 	}
6278 	if (iov_resp) {
6279 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6280 	}
6281 	return ret;
6282 }
6283 #endif /* WL_MBO */
6284 
6285 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6286 #ifdef SUPPORT_AMPDU_MPDU_CMD
6287 /* CMD_AMPDU_MPDU */
6288 static int
wl_android_set_ampdu_mpdu(struct net_device * dev,const char * string_num)6289 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
6290 {
6291 	int err = 0;
6292 	int ampdu_mpdu;
6293 
6294 	ampdu_mpdu = bcm_atoi(string_num);
6295 
6296 	if (ampdu_mpdu > 32) {
6297 		ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n"));
6298 		return -1;
6299 	}
6300 
6301 	ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu));
6302 	err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
6303 	if (err < 0) {
6304 		ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err));
6305 		return -1;
6306 	}
6307 
6308 	return 0;
6309 }
6310 #endif /* SUPPORT_AMPDU_MPDU_CMD */
6311 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
6312 
6313 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6314 extern int wl_cfg80211_send_msg_to_ril(void);
6315 extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
6316 extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
6317 extern int g_mhs_chan_for_cpcoex;
6318 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6319 
6320 #if defined (WL_SUPPORT_AUTO_CHANNEL)
6321 static s32
wl_android_set_auto_channel_scan_state(struct net_device * ndev)6322 wl_android_set_auto_channel_scan_state(struct net_device *ndev)
6323 {
6324 	u32 val = 0;
6325 	s32 ret = BCME_ERROR;
6326 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6327 	/* Set interface up, explicitly. */
6328 	val = 1;
6329 
6330 	ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
6331 	if (ret < 0) {
6332 		ANDROID_ERROR(("set interface up failed, error = %d\n", ret));
6333 		goto done;
6334 	}
6335 
6336 	/* Stop all scan explicitly, till auto channel selection complete. */
6337 	wl_set_drv_status(cfg, SCANNING, ndev);
6338 	if (cfg->escan_info.ndev == NULL) {
6339 		ret = BCME_OK;
6340 		goto done;
6341 	}
6342 
6343 	wl_cfgscan_cancel_scan(cfg);
6344 
6345 done:
6346 	return ret;
6347 }
6348 
6349 s32
wl_android_get_freq_list_chanspecs(struct net_device * ndev,wl_uint32_list_t * list,s32 buflen,const char * cmd_str,int sta_channel,chanspec_band_t sta_acs_band)6350 wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *list,
6351 	s32 buflen, const char* cmd_str, int sta_channel, chanspec_band_t sta_acs_band)
6352 {
6353 	u32 freq = 0;
6354 	chanspec_t chanspec = 0;
6355 	s32 ret = BCME_OK;
6356 	int i = 0;
6357 	char *pcmd, *token;
6358 	int len = buflen;
6359 
6360 	pcmd = bcmstrstr(cmd_str, FREQ_STR);
6361 	pcmd += strlen(FREQ_STR);
6362 
6363 	len -= sizeof(list->count);
6364 
6365 	while ((token = strsep(&pcmd, ",")) != NULL) {
6366 		if (*token == '\0')
6367 			continue;
6368 
6369 		if (len < sizeof(list->element[i]))
6370 			break;
6371 
6372 		freq = bcm_atoi(token);
6373 		/* Convert chanspec from frequency */
6374 		if ((freq > 0) &&
6375 			((chanspec = wl_freq_to_chanspec(freq)) != INVCHANSPEC)) {
6376 			ANDROID_INFO(("Adding chanspec in list : 0x%x at the index %d\n", chanspec, i));
6377 			list->element[i] = chanspec;
6378 			len -= sizeof(list->element[i]);
6379 			i++;
6380 #ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN
6381 			/* Android includes 2g channels even for 5g band configuration. For
6382 			 * customers using only single channel 5G AP, set the channel and
6383 			 * return without doing ACS
6384 			 */
6385 			if (CHSPEC_BAND(chanspec) == WL_CHANSPEC_BAND_5G) {
6386 				ANDROID_INFO(("Pick default channnel from 5g\n"));
6387 				if (!sta_channel) {
6388 					list->element[0] = chanspec;
6389 					list->count = 1;
6390 					return ret;
6391 				}
6392 				break;
6393 			}
6394 #endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */
6395 		}
6396 	}
6397 
6398 	list->count = i;
6399 	/* valid chanspec present in the list */
6400 	if (list->count && sta_channel) {
6401 		/* STA associated case. Can't do ACS.
6402 		* Frequency list is order of lower to higher band.
6403 		* check with the highest band entry.
6404 		*/
6405 		chanspec = list->element[i-1];
6406 		if (CHSPEC_BAND(chanspec) == sta_acs_band) {
6407 			/* softap request is for same band. Use SCC
6408 			 * Convert sta channel to freq
6409 			 */
6410 			freq = wl_channel_to_frequency(sta_channel, sta_acs_band);
6411 			list->element[0] =
6412 				wl_freq_to_chanspec(freq);
6413 			ANDROID_INFO(("Softap on same band as STA."
6414 				"Use SCC. chanspec:0x%x\n", chanspec));
6415 		} else {
6416 			list->element[0] = chanspec;
6417 			ANDROID_INFO(("RSDB case chanspec:0x%x\n", chanspec));
6418 		}
6419 		list->count = 1;
6420 		return ret;
6421 	}
6422 	return ret;
6423 }
6424 
6425 s32
wl_android_get_band_chanspecs(struct net_device * ndev,void * buf,s32 buflen,chanspec_band_t band,bool acs_req)6426 wl_android_get_band_chanspecs(struct net_device *ndev, void *buf, s32 buflen,
6427 	chanspec_band_t band, bool acs_req)
6428 {
6429 	u32 channel = 0;
6430 	s32 ret = BCME_ERROR;
6431 	s32 i = 0;
6432 	s32 j = 0;
6433 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6434 	wl_uint32_list_t *list = NULL;
6435 	chanspec_t chanspec = 0;
6436 
6437 	if (band != 0xff) {
6438 		chanspec |= (band | WL_CHANSPEC_BW_20 |
6439 			WL_CHANSPEC_CTL_SB_NONE);
6440 		chanspec = wl_chspec_host_to_driver(chanspec);
6441 	}
6442 
6443 	ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
6444 		sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
6445 	if (ret < 0) {
6446 		ANDROID_ERROR(("get 'chanspecs' failed, error = %d\n", ret));
6447 		goto done;
6448 	}
6449 
6450 	list = (wl_uint32_list_t *)buf;
6451 	/* Skip DFS and inavlid P2P channel. */
6452 	for (i = 0, j = 0; i < dtoh32(list->count); i++) {
6453 		if (!CHSPEC_IS20(list->element[i])) {
6454 			continue;
6455 		}
6456 		chanspec = (chanspec_t) dtoh32(list->element[i]);
6457 		channel = chanspec | WL_CHANSPEC_BW_20;
6458 		channel = wl_chspec_host_to_driver(channel);
6459 
6460 		ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
6461 		if (ret < 0) {
6462 			ANDROID_ERROR(("get 'per_chan_info' failed, error = %d\n", ret));
6463 			goto done;
6464 		}
6465 
6466 		if (CHSPEC_IS5G(chanspec) && (CHANNEL_IS_RADAR(channel) ||
6467 #ifndef ALLOW_5G_ACS
6468 			((acs_req == true) && (CHSPEC_CHANNEL(chanspec) != APCS_DEFAULT_5G_CH)) ||
6469 #endif /* !ALLOW_5G_ACS */
6470 			(0))) {
6471 			continue;
6472 		} else if (!(CHSPEC_IS2G(chanspec) || CHSPEC_IS5G(chanspec)) &&
6473 			!(CHSPEC_IS_6G_PSC(chanspec))) {
6474 			continue;
6475 		}
6476 		else {
6477 			list->element[j] = list->element[i];
6478 			ANDROID_INFO(("Adding chanspec in list : %x\n", list->element[j]));
6479 		}
6480 
6481 		j++;
6482 	}
6483 
6484 	list->count = j;
6485 
6486 done:
6487 	return ret;
6488 }
6489 
6490 static s32
wl_android_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)6491 wl_android_get_best_channel(struct net_device *ndev, void *buf, int buflen,
6492 	int *channel)
6493 {
6494 	s32 ret = BCME_ERROR;
6495 	int chosen = 0;
6496 	int retry = 0;
6497 
6498 	/* Start auto channel selection scan. */
6499 	ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0);
6500 	if (ret < 0) {
6501 		ANDROID_ERROR(("can't start auto channel scan, error = %d\n", ret));
6502 		*channel = 0;
6503 		goto done;
6504 	}
6505 
6506 	/* Wait for auto channel selection, worst case possible delay is 5250ms. */
6507 	retry = CHAN_SEL_RETRY_COUNT;
6508 
6509 	while (retry--) {
6510 		OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
6511 		chosen = 0;
6512 		ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6513 		if ((ret == 0) && (dtoh32(chosen) != 0)) {
6514 			*channel = (u16)(chosen & 0x00FF);
6515 			ANDROID_INFO(("selected channel = %d\n", *channel));
6516 			break;
6517 		}
6518 		ANDROID_INFO(("attempt = %d, ret = %d, chosen = %d\n",
6519 			(CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
6520 	}
6521 
6522 	if (retry <= 0)	{
6523 		ANDROID_ERROR(("failure, auto channel selection timed out\n"));
6524 		*channel = 0;
6525 		ret = BCME_ERROR;
6526 	}
6527 
6528 done:
6529 	return ret;
6530 }
6531 
6532 static s32
wl_android_restore_auto_channel_scan_state(struct net_device * ndev)6533 wl_android_restore_auto_channel_scan_state(struct net_device *ndev)
6534 {
6535 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6536 	/* Clear scan stop driver status. */
6537 	wl_clr_drv_status(cfg, SCANNING, ndev);
6538 
6539 	return BCME_OK;
6540 }
6541 
6542 s32
wl_android_get_best_channels(struct net_device * dev,char * cmd,int total_len)6543 wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len)
6544 {
6545 	int channel = 0;
6546 	s32 ret = BCME_ERROR;
6547 	u8 *buf = NULL;
6548 	char *pos = cmd;
6549 	struct bcm_cfg80211 *cfg = NULL;
6550 	struct net_device *ndev = NULL;
6551 
6552 	bzero(cmd, total_len);
6553 	cfg = wl_get_cfg(dev);
6554 
6555 	buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
6556 	if (buf == NULL) {
6557 		ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6558 		return -ENOMEM;
6559 	}
6560 
6561 	/*
6562 	 * Always use primary interface, irrespective of interface on which
6563 	 * command came.
6564 	 */
6565 	ndev = bcmcfg_to_prmry_ndev(cfg);
6566 
6567 	/*
6568 	 * Make sure that FW and driver are in right state to do auto channel
6569 	 * selection scan.
6570 	 */
6571 	ret = wl_android_set_auto_channel_scan_state(ndev);
6572 	if (ret < 0) {
6573 		ANDROID_ERROR(("can't set auto channel scan state, error = %d\n", ret));
6574 		goto done;
6575 	}
6576 
6577 	/* Best channel selection in 2.4GHz band. */
6578 	ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6579 		WL_CHANSPEC_BAND_2G, false);
6580 	if (ret < 0) {
6581 		ANDROID_ERROR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
6582 		goto done;
6583 	}
6584 
6585 	ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6586 		&channel);
6587 	if (ret < 0) {
6588 		ANDROID_ERROR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
6589 		goto done;
6590 	}
6591 
6592 	if (CHANNEL_IS_2G(channel)) {
6593 		channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
6594 	} else {
6595 		ANDROID_ERROR(("invalid 2.4GHz channel, channel = %d\n", channel));
6596 		channel = 0;
6597 	}
6598 
6599 	pos += snprintf(pos, total_len, "%04d ", channel);
6600 
6601 	/* Best channel selection in 5GHz band. */
6602 	ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6603 		WL_CHANSPEC_BAND_5G, false);
6604 	if (ret < 0) {
6605 		ANDROID_ERROR(("can't get chanspecs in 5GHz, error = %d\n", ret));
6606 		goto done;
6607 	}
6608 
6609 	ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6610 		&channel);
6611 	if (ret < 0) {
6612 		ANDROID_ERROR(("can't select best channel scan in 5GHz, error = %d\n", ret));
6613 		goto done;
6614 	}
6615 
6616 	if (CHANNEL_IS_5G(channel)) {
6617 		channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
6618 	} else {
6619 		ANDROID_ERROR(("invalid 5GHz channel, channel = %d\n", channel));
6620 		channel = 0;
6621 	}
6622 
6623 	pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6624 
6625 	/* Set overall best channel same as 5GHz best channel. */
6626 	pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6627 
6628 done:
6629 	if (NULL != buf) {
6630 		MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
6631 	}
6632 
6633 	/* Restore FW and driver back to normal state. */
6634 	ret = wl_android_restore_auto_channel_scan_state(ndev);
6635 	if (ret < 0) {
6636 		ANDROID_ERROR(("can't restore auto channel scan state, error = %d\n", ret));
6637 	}
6638 
6639 	return (pos - cmd);
6640 }
6641 
6642 int
wl_android_set_spect(struct net_device * dev,int spect)6643 wl_android_set_spect(struct net_device *dev, int spect)
6644 {
6645 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6646 	int wlc_down = 1;
6647 	int wlc_up = 1;
6648 	int err = BCME_OK;
6649 
6650 	if (!wl_get_drv_status_all(cfg, CONNECTED)) {
6651 		err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
6652 		if (err) {
6653 			ANDROID_ERROR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
6654 			return err;
6655 		}
6656 
6657 		err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
6658 		if (err) {
6659 			ANDROID_ERROR(("%s: error setting spect: code: %d\n", __func__, err));
6660 			return err;
6661 		}
6662 
6663 		err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
6664 		if (err) {
6665 			ANDROID_ERROR(("%s: WLC_UP failed: code: %d\n", __func__, err));
6666 			return err;
6667 		}
6668 	}
6669 	return err;
6670 }
6671 
6672 static int
wl_android_get_sta_channel(struct bcm_cfg80211 * cfg)6673 wl_android_get_sta_channel(struct bcm_cfg80211 *cfg)
6674 {
6675 	chanspec_t *sta_chanspec = NULL;
6676 	u32 channel = 0;
6677 
6678 	if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
6679 		if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
6680 			bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) {
6681 			channel = wf_chspec_ctlchan(*sta_chanspec);
6682 		}
6683 	}
6684 	return channel;
6685 }
6686 
6687 static int
wl_cfg80211_get_acs_band(int band)6688 wl_cfg80211_get_acs_band(int band)
6689 {
6690 	chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6691 	switch (band) {
6692 		case WLC_BAND_AUTO:
6693 			ANDROID_INFO(("ACS full channel scan \n"));
6694 			/* Restricting band to 2G in case of hw_mode any */
6695 			acs_band = WL_CHANSPEC_BAND_2G;
6696 			break;
6697 #ifdef WL_6G_BAND
6698 		case WLC_BAND_6G:
6699 			ANDROID_INFO(("ACS 6G band scan \n"));
6700 			acs_band = WL_CHANSPEC_BAND_6G;
6701 			break;
6702 #endif /* WL_6G_BAND */
6703 		case WLC_BAND_5G:
6704 			ANDROID_INFO(("ACS 5G band scan \n"));
6705 			acs_band = WL_CHANSPEC_BAND_5G;
6706 			break;
6707 		case WLC_BAND_2G:
6708 			/*
6709 			 * If channel argument is not provided/ argument 20 is provided,
6710 			 * Restrict channel to 2GHz, 20MHz BW, No SB
6711 			 */
6712 			ANDROID_INFO(("ACS 2G band scan \n"));
6713 			acs_band = WL_CHANSPEC_BAND_2G;
6714 			break;
6715 		default:
6716 			ANDROID_ERROR(("ACS: No band chosen\n"));
6717 			break;
6718 	}
6719 	ANDROID_INFO(("%s: ACS: band = %d, acs_band = 0x%x\n", __FUNCTION__, band, acs_band));
6720 	return acs_band;
6721 }
6722 
6723 /* SoftAP feature */
6724 static int
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)6725 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
6726 	char* command, int total_len)
6727 {
6728 	int channel = 0, sta_channel = 0;
6729 	int chosen = 0;
6730 	int retry = 0;
6731 	int ret = 0;
6732 	int spect = 0;
6733 	u8 *reqbuf = NULL;
6734 	uint32 band = WLC_BAND_INVALID, sta_band = WLC_BAND_INVALID;
6735 	chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6736 	uint32 buf_size;
6737 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6738 	bool acs_freq_list_present = false;
6739 	char *pcmd;
6740 
6741 	if (cmd_str) {
6742 		ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
6743 		pcmd = bcmstrstr(cmd_str, FREQ_STR);
6744 		if (pcmd) {
6745 			acs_freq_list_present = true;
6746 			ANDROID_INFO(("ACS has freq list\n"));
6747 		} else if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
6748 			band = WLC_BAND_AUTO;
6749 #ifdef WL_6G_BAND
6750 		} else if (strnicmp(cmd_str, APCS_BAND_6G, strlen(APCS_BAND_6G)) == 0) {
6751 			band = WLC_BAND_6G;
6752 #endif /* WL_6G_BAND */
6753 		} else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
6754 			band = WLC_BAND_5G;
6755 		} else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
6756 			band = WLC_BAND_2G;
6757 		} else {
6758 			/*
6759 			 * For backward compatibility: Some platforms used to issue argument 20 or 0
6760 			 * to enforce the 2G channel selection
6761 			 */
6762 			channel = bcm_atoi(cmd_str);
6763 			if ((channel == APCS_BAND_2G_LEGACY1) ||
6764 				(channel == APCS_BAND_2G_LEGACY2)) {
6765 				band = WLC_BAND_2G;
6766 			} else {
6767 				ANDROID_ERROR(("Invalid argument\n"));
6768 				return -EINVAL;
6769 			}
6770 		}
6771 	} else {
6772 		/* If no argument is provided, default to 2G */
6773 		ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
6774 		band = WLC_BAND_2G;
6775 	}
6776 	ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
6777 
6778 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6779 	wl_cfg80211_register_dev_ril_bridge_event_notifier();
6780 	if (band == WLC_BAND_2G) {
6781 		wl_cfg80211_send_msg_to_ril();
6782 
6783 		if (g_mhs_chan_for_cpcoex) {
6784 			channel = g_mhs_chan_for_cpcoex;
6785 			g_mhs_chan_for_cpcoex = 0;
6786 			goto done2;
6787 		}
6788 	}
6789 	wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
6790 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6791 
6792 	/* If STA is connected, return is STA channel, else ACS can be issued,
6793 	 * set spect to 0 and proceed with ACS
6794 	 */
6795 	sta_channel = wl_android_get_sta_channel(cfg);
6796 	sta_band = WL_GET_BAND(sta_channel);
6797 	if (sta_channel && (band != WLC_BAND_INVALID)) {
6798 		switch (sta_band) {
6799 			case (WLC_BAND_5G):
6800 #ifdef WL_6G_BAND
6801 			case (WLC_BAND_6G):
6802 #endif /* WL_6G_BAND */
6803 			{
6804 				if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
6805 					channel = APCS_DEFAULT_2G_CH;
6806 				} else if (band == WLC_BAND_5G) {
6807 					channel = sta_channel;
6808 				}
6809 				break;
6810 			}
6811 			case (WLC_BAND_2G): {
6812 				if (band == WLC_BAND_5G) {
6813 					channel = APCS_DEFAULT_5G_CH;
6814 				} else if (band == WLC_BAND_2G) {
6815 					channel = sta_channel;
6816 				}
6817 #ifdef WL_6G_BAND
6818 				else if (band == WLC_BAND_6G) {
6819 					channel = APCS_DEFAULT_6G_CH;
6820 				}
6821 #endif /* WL_6G_BAND */
6822 				break;
6823 			}
6824 			default:
6825 				/* Intentional fall through to use same sta channel for softap */
6826 				channel = sta_channel;
6827 				break;
6828 		}
6829 		WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel);
6830 		goto done2;
6831 	}
6832 
6833 	/* If AP is started on wlan0 iface,
6834 	 * do not issue any iovar to fw and choose default ACS channel for softap
6835 	 */
6836 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6837 		if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
6838 			ANDROID_INFO(("Softap started on primary iface\n"));
6839 			goto done;
6840 		}
6841 	}
6842 
6843 	chosen = wl_ext_autochannel(dev, ACS_DRV_BIT, band);
6844 	channel = wf_chspec_ctlchan(chosen);
6845 	if (channel) {
6846 		acs_band = CHSPEC_BAND(channel);
6847 		goto done2;
6848 	} else
6849 		goto done;
6850 
6851 	ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
6852 	if (ret) {
6853 		ANDROID_ERROR(("ACS: error getting the spect, ret=%d\n", ret));
6854 		goto done;
6855 	}
6856 
6857 	if (spect > 0) {
6858 		ret = wl_android_set_spect(dev, 0);
6859 		if (ret < 0) {
6860 			ANDROID_ERROR(("ACS: error while setting spect, ret=%d\n", ret));
6861 			goto done;
6862 		}
6863 	}
6864 
6865 	reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
6866 	if (reqbuf == NULL) {
6867 		ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6868 		return -ENOMEM;
6869 	}
6870 
6871 	if (acs_freq_list_present) {
6872 		wl_uint32_list_t *list = NULL;
6873 		bzero(reqbuf, sizeof(*reqbuf));
6874 		list = (wl_uint32_list_t *)reqbuf;
6875 
6876 		ret = wl_android_get_freq_list_chanspecs(dev, list, CHANSPEC_BUF_SIZE,
6877 			cmd_str, sta_channel, wl_cfg80211_get_acs_band(sta_band));
6878 		if (ret < 0) {
6879 			ANDROID_ERROR(("ACS chanspec set failed!\n"));
6880 			goto done;
6881 		}
6882 
6883 		/* skip ACS for single channel case */
6884 		if (list->count == 1) {
6885 			cfg->acs_chspec = (chanspec_t)list->element[0];
6886 			channel = wf_chspec_ctlchan((chanspec_t)list->element[0]);
6887 			acs_band = CHSPEC_BAND((chanspec_t)list->element[0]);
6888 			goto done2;
6889 		}
6890 	} else {
6891 		acs_band = wl_cfg80211_get_acs_band(band);
6892 		if (acs_band == WLC_ACS_BAND_INVALID) {
6893 			ANDROID_ERROR(("ACS: No band chosen\n"));
6894 			goto done2;
6895 		}
6896 
6897 		if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE,
6898 			acs_band, true)) < 0) {
6899 			ANDROID_ERROR(("ACS chanspec retrieval failed! \n"));
6900 			goto done;
6901 		}
6902 	}
6903 
6904 	buf_size = CHANSPEC_BUF_SIZE;
6905 	ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
6906 		buf_size);
6907 	if (ret < 0) {
6908 		ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
6909 		channel = 0;
6910 		goto done;
6911 	}
6912 
6913 	/* Wait for auto channel selection, max 3000 ms */
6914 	if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) {
6915 		OSL_SLEEP(500);
6916 	} else {
6917 		/*
6918 		 * Full channel scan at the minimum takes 1.2secs
6919 		 * even with parallel scan. max wait time: 3500ms
6920 		 */
6921 		OSL_SLEEP(1000);
6922 	}
6923 
6924 	retry = APCS_MAX_RETRY;
6925 	while (retry--) {
6926 		ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
6927 			sizeof(chosen));
6928 		if (ret < 0) {
6929 			chosen = 0;
6930 		} else {
6931 			chosen = dtoh32(chosen);
6932 		}
6933 
6934 		if (chosen) {
6935 			/* Update chanspec which can be used during softAP bringup with right BW */
6936 			cfg->acs_chspec = chosen;
6937 			channel = wf_chspec_ctlchan(chosen);
6938 			acs_band = CHSPEC_BAND(chosen);
6939 			break;
6940 		}
6941 		ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x, acs_band = 0x%x\n",
6942 			(APCS_MAX_RETRY - retry), ret, chosen, acs_band));
6943 		OSL_SLEEP(250);
6944 	}
6945 
6946 done:
6947 	if ((retry == 0) || (ret < 0)) {
6948 		/* On failure, fallback to a default channel */
6949 		if (band == WLC_BAND_5G) {
6950 			channel = APCS_DEFAULT_5G_CH;
6951 #ifdef WL_6G_BAND
6952 		} else if (band == WLC_BAND_6G) {
6953 			channel = APCS_DEFAULT_6G_CH;
6954 #endif /* WL_6G_BAND */
6955 		} else {
6956 			channel = APCS_DEFAULT_2G_CH;
6957 		}
6958 		ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel));
6959 	}
6960 done2:
6961 	if (spect > 0) {
6962 		if ((ret = wl_android_set_spect(dev, spect) < 0)) {
6963 			ANDROID_ERROR(("ACS: error while setting spect\n"));
6964 		}
6965 	}
6966 
6967 	if (reqbuf) {
6968 		MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
6969 	}
6970 
6971 	if (channel) {
6972 		ret = snprintf(command, total_len, "%d", channel);
6973 		ANDROID_INFO(("command result is %s \n", command));
6974 	}
6975 
6976 	return ret;
6977 }
6978 #endif /* WL_SUPPORT_AUTO_CHANNEL */
6979 
6980 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6981 static int
wl_android_set_roam_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)6982 wl_android_set_roam_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
6983 {
6984 	s32 err = BCME_OK;
6985 	u32 roam_vsie_enable = 0;
6986 	u32 cmd_str_len = (u32)strlen(CMD_ROAM_VSIE_ENAB_SET);
6987 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6988 
6989 	/* <CMD><SPACE><VAL> */
6990 	if (!cmd || (cmd_len < (cmd_str_len + 1))) {
6991 		ANDROID_ERROR(("wrong arg\n"));
6992 		err = -EINVAL;
6993 		goto exit;
6994 	}
6995 
6996 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6997 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
6998 		err = -ENODEV;
6999 		goto exit;
7000 	}
7001 
7002 	roam_vsie_enable = cmd[(cmd_str_len + 1)] - '0';
7003 	if (roam_vsie_enable > 1) {
7004 		roam_vsie_enable = 1;
7005 	}
7006 
7007 	WL_DBG_MEM(("set roam vsie %d\n", roam_vsie_enable));
7008 	err = wldev_iovar_setint(dev, "roam_vsie", roam_vsie_enable);
7009 	if (unlikely(err)) {
7010 		ANDROID_ERROR(("set roam vsie enable failed. ret:%d\n", err));
7011 	}
7012 
7013 exit:
7014 	return err;
7015 }
7016 
7017 static int
wl_android_get_roam_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7018 wl_android_get_roam_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7019 {
7020 	s32 err = BCME_OK;
7021 	u32 roam_vsie_enable = 0;
7022 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7023 	int bytes_written;
7024 
7025 	/* <CMD> */
7026 	if (!cmd) {
7027 		ANDROID_ERROR(("wrong arg\n"));
7028 		return -1;
7029 	}
7030 
7031 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7032 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7033 		return -1;
7034 	}
7035 
7036 	err = wldev_iovar_getint(dev, "roam_vsie", &roam_vsie_enable);
7037 	if (unlikely(err)) {
7038 		ANDROID_ERROR(("get roam vsie enable failed. ret:%d\n", err));
7039 		return -1;
7040 	}
7041 	ANDROID_INFO(("get roam vsie %d\n", roam_vsie_enable));
7042 
7043 	bytes_written = snprintf(cmd, cmd_len, "%s %d",
7044 		CMD_ROAM_VSIE_ENAB_GET, roam_vsie_enable);
7045 
7046 	return bytes_written;
7047 }
7048 
7049 static int
wl_android_set_bcn_rpt_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)7050 wl_android_set_bcn_rpt_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
7051 {
7052 	s32 err;
7053 	u32 bcn_vsie_enable = 0;
7054 	u32 cmd_str_len = (u32)strlen(CMD_BR_VSIE_ENAB_SET);
7055 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7056 
7057 	/* <CMD><SPACE><VAL> */
7058 	if (!cmd || (cmd_len < (cmd_str_len + 1))) {
7059 		ANDROID_ERROR(("invalid arg\n"));
7060 		err = -EINVAL;
7061 		goto exit;
7062 	}
7063 
7064 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7065 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7066 		err = -ENODEV;
7067 		goto exit;
7068 	}
7069 
7070 	bcn_vsie_enable = cmd[cmd_str_len + 1] - '0';
7071 	if (bcn_vsie_enable > 1) {
7072 		bcn_vsie_enable = 1;
7073 	}
7074 
7075 	WL_DBG_MEM(("set bcn report vsie %d\n", bcn_vsie_enable));
7076 	err = wldev_iovar_setint(dev, "bcnrpt_vsie_en", bcn_vsie_enable);
7077 	if (unlikely(err)) {
7078 		ANDROID_ERROR(("set bcn vsie failed. ret:%d\n", err));
7079 	}
7080 
7081 exit:
7082 	return err;
7083 }
7084 
7085 static int
wl_android_get_bcn_rpt_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7086 wl_android_get_bcn_rpt_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7087 {
7088 	s32 err = BCME_OK;
7089 	u32 bcn_vsie_enable = 0;
7090 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7091 	int bytes_written;
7092 
7093 	/* <CMD> */
7094 	if (!cmd) {
7095 		ANDROID_ERROR(("wrong arg\n"));
7096 		return -1;
7097 	}
7098 
7099 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7100 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7101 		return -1;
7102 	}
7103 
7104 	err = wldev_iovar_getint(dev, "bcnrpt_vsie_en", &bcn_vsie_enable);
7105 	if (unlikely(err)) {
7106 		ANDROID_ERROR(("get bcn vsie failed. ret:%d\n", err));
7107 		return -1;
7108 	}
7109 	ANDROID_INFO(("get bcn report vsie %d\n", bcn_vsie_enable));
7110 
7111 	bytes_written = snprintf(cmd, cmd_len, "%s %d",
7112 		CMD_BR_VSIE_ENAB_GET, bcn_vsie_enable);
7113 
7114 	return bytes_written;
7115 }
7116 
7117 #ifdef SUPPORT_HIDDEN_AP
7118 static int
wl_android_set_max_num_sta(struct net_device * dev,const char * string_num)7119 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
7120 {
7121 	int err = BCME_ERROR;
7122 	int max_assoc;
7123 
7124 	max_assoc = bcm_atoi(string_num);
7125 	ANDROID_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc));
7126 
7127 	err = wldev_iovar_setint(dev, "maxassoc", max_assoc);
7128 	if (err < 0) {
7129 		ANDROID_ERROR(("failed to set maxassoc, error:%d\n", err));
7130 	}
7131 
7132 	return err;
7133 }
7134 
7135 static int
wl_android_set_ssid(struct net_device * dev,const char * hapd_ssid)7136 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
7137 {
7138 	wlc_ssid_t ssid;
7139 	s32 ret;
7140 
7141 	ssid.SSID_len = strlen(hapd_ssid);
7142 	if (ssid.SSID_len == 0) {
7143 		ANDROID_ERROR(("wl_android_set_ssids : No SSID\n"));
7144 		return -1;
7145 	}
7146 	if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
7147 		ssid.SSID_len = DOT11_MAX_SSID_LEN;
7148 		ANDROID_ERROR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid)));
7149 	}
7150 	bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
7151 	ANDROID_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID));
7152 	ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
7153 	if (ret < 0) {
7154 		ANDROID_ERROR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret));
7155 	}
7156 	return 1;
7157 
7158 }
7159 
7160 static int
wl_android_set_hide_ssid(struct net_device * dev,const char * string_num)7161 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
7162 {
7163 	int hide_ssid;
7164 	int enable = 0;
7165 	int err = BCME_ERROR;
7166 
7167 	hide_ssid = bcm_atoi(string_num);
7168 	ANDROID_INFO(("wl_android_set_hide_ssid: HAPD_HIDE_SSID = %d\n", hide_ssid));
7169 	if (hide_ssid) {
7170 		enable = 1;
7171 	}
7172 
7173 	err = wldev_iovar_setint(dev, "closednet", enable);
7174 	if (err < 0) {
7175 		ANDROID_ERROR(("failed to set closednet, error:%d\n", err));
7176 	}
7177 
7178 	return err;
7179 }
7180 #endif /* SUPPORT_HIDDEN_AP */
7181 
7182 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
7183 static int
wl_android_sta_diassoc(struct net_device * dev,const char * straddr)7184 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
7185 {
7186 	scb_val_t scbval;
7187 	int error  = 0;
7188 
7189 	ANDROID_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr));
7190 
7191 	/* Unspecified reason */
7192 	scbval.val = htod32(1);
7193 
7194 	if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
7195 		ANDROID_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n"));
7196 		return -1;
7197 	}
7198 
7199 	ANDROID_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n",
7200 		MAC2STRDBG(scbval.ea.octet), scbval.val));
7201 
7202 	error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
7203 		sizeof(scb_val_t));
7204 	if (error) {
7205 		ANDROID_ERROR(("Fail to DEAUTH station, error = %d\n", error));
7206 	}
7207 
7208 	return 1;
7209 }
7210 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
7211 
7212 #ifdef SUPPORT_SET_LPC
7213 static int
wl_android_set_lpc(struct net_device * dev,const char * string_num)7214 wl_android_set_lpc(struct net_device *dev, const char* string_num)
7215 {
7216 	int lpc_enabled, ret;
7217 	s32 val = 1;
7218 
7219 	lpc_enabled = bcm_atoi(string_num);
7220 	ANDROID_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled));
7221 
7222 	ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
7223 	if (ret < 0)
7224 		ANDROID_ERROR(("WLC_DOWN error %d\n", ret));
7225 
7226 	wldev_iovar_setint(dev, "lpc", lpc_enabled);
7227 
7228 	ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
7229 	if (ret < 0)
7230 		ANDROID_ERROR(("WLC_UP error %d\n", ret));
7231 
7232 	return 1;
7233 }
7234 #endif /* SUPPORT_SET_LPC */
7235 
7236 static int
wl_android_ch_res_rl(struct net_device * dev,bool change)7237 wl_android_ch_res_rl(struct net_device *dev, bool change)
7238 {
7239 	int error = 0;
7240 	s32 srl = 7;
7241 	s32 lrl = 4;
7242 	ANDROID_ERROR(("wl_android_ch_res_rl: enter\n"));
7243 	if (change) {
7244 		srl = 4;
7245 		lrl = 2;
7246 	}
7247 
7248 	BCM_REFERENCE(lrl);
7249 
7250 	error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
7251 	if (error) {
7252 		ANDROID_ERROR(("Failed to set SRL, error = %d\n", error));
7253 	}
7254 #ifndef CUSTOM_LONG_RETRY_LIMIT
7255 	error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
7256 	if (error) {
7257 		ANDROID_ERROR(("Failed to set LRL, error = %d\n", error));
7258 	}
7259 #endif /* CUSTOM_LONG_RETRY_LIMIT */
7260 	return error;
7261 }
7262 
7263 #ifdef SUPPORT_LTECX
7264 #define DEFAULT_WLANRX_PROT	1
7265 #define DEFAULT_LTERX_PROT	0
7266 #define DEFAULT_LTETX_ADV	1200
7267 
7268 static int
wl_android_set_ltecx(struct net_device * dev,const char * string_num)7269 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
7270 {
7271 	uint16 chan_bitmap;
7272 	int ret;
7273 
7274 	chan_bitmap = bcm_strtoul(string_num, NULL, 16);
7275 
7276 	ANDROID_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap));
7277 
7278 	if (chan_bitmap) {
7279 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7280 		if (ret < 0) {
7281 			ANDROID_ERROR(("mws_coex_bitmap error %d\n", ret));
7282 		}
7283 
7284 		ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
7285 		if (ret < 0) {
7286 			ANDROID_ERROR(("mws_wlanrx_prot error %d\n", ret));
7287 		}
7288 
7289 		ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
7290 		if (ret < 0) {
7291 			ANDROID_ERROR(("mws_lterx_prot error %d\n", ret));
7292 		}
7293 
7294 		ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
7295 		if (ret < 0) {
7296 			ANDROID_ERROR(("mws_ltetx_adv error %d\n", ret));
7297 		}
7298 	} else {
7299 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7300 		if (ret < 0) {
7301 			if (ret == BCME_UNSUPPORTED) {
7302 				ANDROID_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
7303 			} else {
7304 				ANDROID_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
7305 			}
7306 		}
7307 	}
7308 	return 1;
7309 }
7310 #endif /* SUPPORT_LTECX */
7311 
7312 #ifdef WL_RELMCAST
7313 static int
wl_android_rmc_enable(struct net_device * net,int rmc_enable)7314 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
7315 {
7316 	int err;
7317 
7318 	err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
7319 	if (err != BCME_OK) {
7320 		ANDROID_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err));
7321 	}
7322 	return err;
7323 }
7324 
7325 static int
wl_android_rmc_set_leader(struct net_device * dev,const char * straddr)7326 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
7327 {
7328 	int error  = BCME_OK;
7329 	char smbuf[WLC_IOCTL_SMLEN];
7330 	wl_rmc_entry_t rmc_entry;
7331 	ANDROID_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr));
7332 
7333 	bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7334 	if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
7335 		if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
7336 			ANDROID_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n"));
7337 			bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7338 		} else {
7339 			ANDROID_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n"));
7340 			return BCME_ERROR;
7341 		}
7342 	}
7343 
7344 	error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
7345 		smbuf, sizeof(smbuf), NULL);
7346 
7347 	if (error != BCME_OK) {
7348 		ANDROID_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n",
7349 			error));
7350 	}
7351 
7352 	return error;
7353 }
7354 
wl_android_set_rmc_event(struct net_device * dev,char * command)7355 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
7356 {
7357 	int err = 0;
7358 	int pid = 0;
7359 
7360 	if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
7361 		ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
7362 		return -1;
7363 	}
7364 
7365 	/* set pid, and if the event was happened, let's send a notification through netlink */
7366 	wl_cfg80211_set_rmc_pid(dev, pid);
7367 
7368 	ANDROID_INFO(("RMC pid=%d\n", pid));
7369 
7370 	return err;
7371 }
7372 #endif /* WL_RELMCAST */
7373 
wl_android_get_singlecore_scan(struct net_device * dev,char * command,int total_len)7374 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
7375 {
7376 	int error = 0;
7377 	int bytes_written = 0;
7378 	int mode = 0;
7379 
7380 	error = wldev_iovar_getint(dev, "scan_ps", &mode);
7381 	if (error) {
7382 		ANDROID_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode,"
7383 			" error = %d\n",
7384 			error));
7385 		return -1;
7386 	}
7387 
7388 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
7389 
7390 	return bytes_written;
7391 }
7392 
wl_android_set_singlecore_scan(struct net_device * dev,char * command)7393 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
7394 {
7395 	int error = 0;
7396 	int mode = 0;
7397 
7398 	if (sscanf(command, "%*s %d", &mode) != 1) {
7399 		ANDROID_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n"));
7400 		return -1;
7401 	}
7402 
7403 	error = wldev_iovar_setint(dev, "scan_ps", mode);
7404 	if (error) {
7405 		ANDROID_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n",
7406 		mode, error));
7407 		return -1;
7408 	}
7409 
7410 	return error;
7411 }
7412 #ifdef TEST_TX_POWER_CONTROL
7413 static int
wl_android_set_tx_power(struct net_device * dev,const char * string_num)7414 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
7415 {
7416 	int err = 0;
7417 	s32 dbm;
7418 	enum nl80211_tx_power_setting type;
7419 
7420 	dbm = bcm_atoi(string_num);
7421 
7422 	if (dbm < -1) {
7423 		ANDROID_ERROR(("wl_android_set_tx_power: dbm is negative...\n"));
7424 		return -EINVAL;
7425 	}
7426 
7427 	if (dbm == -1)
7428 		type = NL80211_TX_POWER_AUTOMATIC;
7429 	else
7430 		type = NL80211_TX_POWER_FIXED;
7431 
7432 	err = wl_set_tx_power(dev, type, dbm);
7433 	if (unlikely(err)) {
7434 		ANDROID_ERROR(("wl_android_set_tx_power: error (%d)\n", err));
7435 		return err;
7436 	}
7437 
7438 	return 1;
7439 }
7440 
7441 static int
wl_android_get_tx_power(struct net_device * dev,char * command,int total_len)7442 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
7443 {
7444 	int err;
7445 	int bytes_written;
7446 	s32 dbm = 0;
7447 
7448 	err = wl_get_tx_power(dev, &dbm);
7449 	if (unlikely(err)) {
7450 		ANDROID_ERROR(("wl_android_get_tx_power: error (%d)\n", err));
7451 		return err;
7452 	}
7453 
7454 	bytes_written = snprintf(command, total_len, "%s %d",
7455 		CMD_TEST_GET_TX_POWER, dbm);
7456 
7457 	ANDROID_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm));
7458 
7459 	return bytes_written;
7460 }
7461 #endif /* TEST_TX_POWER_CONTROL */
7462 
7463 static int
wl_android_set_sarlimit_txctrl(struct net_device * dev,const char * string_num)7464 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
7465 {
7466 	int err = BCME_ERROR;
7467 	int setval = 0;
7468 	s32 mode = bcm_atoi(string_num);
7469 	s32 mode_bit = 0;
7470 	int enab = 0;
7471 
7472 	/* As Samsung specific and their requirement,
7473 	 * the mode set as the following form.
7474 	 * -1 : HEAD SAR disabled
7475 	 *  0 : HEAD SAR enabled
7476 	 *  1 : GRIP SAR disabled
7477 	 *  2 : GRIP SAR enabled
7478 	 *  3 : NR mmWave SAR disabled
7479 	 *  4 : NR mmWave SAR enabled
7480 	 *  5 : NR Sub6 SAR disabled
7481 	 *  6 : NR Sub6 SAR enabled
7482 	 *  7 : SAR BACKOFF disabled all
7483 	 * The 'SAR BACKOFF disabled all' index should be the end of the mode.
7484 	 */
7485 	if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) {
7486 		ANDROID_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num)));
7487 		err = BCME_RANGE;
7488 		goto error;
7489 	}
7490 
7491 	mode_bit = mode + 1;
7492 	enab = mode_bit % 2;
7493 	mode_bit = mode_bit / 2;
7494 
7495 	err = wldev_iovar_getint(dev, "sar_enable", &setval);
7496 	if (unlikely(err)) {
7497 		ANDROID_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err));
7498 		goto error;
7499 	}
7500 
7501 	if (mode == SAR_BACKOFF_DISABLE_ALL) {
7502 		ANDROID_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__));
7503 		setval = 0;
7504 	} else {
7505 		ANDROID_ERROR(("%s: SAR limit control mode %d enab %d\n",
7506 			__FUNCTION__, mode_bit, enab));
7507 		if (enab) {
7508 			setval |= (1 << mode_bit);
7509 		} else {
7510 			setval &= ~(1 << mode_bit);
7511 		}
7512 	}
7513 
7514 	err = wldev_iovar_setint(dev, "sar_enable", setval);
7515 	if (unlikely(err)) {
7516 		ANDROID_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
7517 		goto error;
7518 	}
7519 	err = BCME_OK;
7520 error:
7521 	return err;
7522 }
7523 
7524 #ifdef SUPPORT_SET_TID
7525 static int
wl_android_set_tid(struct net_device * dev,char * command)7526 wl_android_set_tid(struct net_device *dev, char* command)
7527 {
7528 	int err = BCME_ERROR;
7529 	char *pos = command;
7530 	char *token = NULL;
7531 	uint8 mode = 0;
7532 	uint32 uid = 0;
7533 	uint8 prio = 0;
7534 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7535 
7536 	if (!dhdp) {
7537 		ANDROID_ERROR(("dhd is NULL\n"));
7538 		return err;
7539 	}
7540 
7541 	ANDROID_INFO(("%s: command[%s]\n", __FUNCTION__, command));
7542 
7543 	/* drop command */
7544 	token = bcmstrtok(&pos, " ", NULL);
7545 
7546 	token = bcmstrtok(&pos, " ", NULL);
7547 	if (!token) {
7548 		ANDROID_ERROR(("Invalid arguments\n"));
7549 		return err;
7550 	}
7551 
7552 	mode = bcm_atoi(token);
7553 
7554 	if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
7555 		ANDROID_ERROR(("Invalid arguments, mode %d\n", mode));
7556 			return err;
7557 	}
7558 
7559 	if (mode) {
7560 		token = bcmstrtok(&pos, " ", NULL);
7561 		if (!token) {
7562 			ANDROID_ERROR(("Invalid arguments for target uid\n"));
7563 			return err;
7564 		}
7565 
7566 		uid = bcm_atoi(token);
7567 
7568 		token = bcmstrtok(&pos, " ", NULL);
7569 		if (!token) {
7570 			ANDROID_ERROR(("Invalid arguments for target tid\n"));
7571 			return err;
7572 		}
7573 
7574 		prio = bcm_atoi(token);
7575 		if (prio >= 0 && prio <= MAXPRIO) {
7576 			dhdp->tid_mode = mode;
7577 			dhdp->target_uid = uid;
7578 			dhdp->target_tid = prio;
7579 		} else {
7580 			ANDROID_ERROR(("Invalid arguments, prio %d\n", prio));
7581 			return err;
7582 		}
7583 	} else {
7584 		dhdp->tid_mode = SET_TID_OFF;
7585 		dhdp->target_uid = 0;
7586 		dhdp->target_tid = 0;
7587 	}
7588 
7589 	ANDROID_INFO(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
7590 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
7591 
7592 	err = BCME_OK;
7593 	return err;
7594 }
7595 
7596 static int
wl_android_get_tid(struct net_device * dev,char * command,int total_len)7597 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
7598 {
7599 	int bytes_written = BCME_ERROR;
7600 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7601 
7602 	if (!dhdp) {
7603 		ANDROID_ERROR(("dhd is NULL\n"));
7604 		return bytes_written;
7605 	}
7606 
7607 	bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
7608 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
7609 
7610 	ANDROID_INFO(("%s: command results %s\n", __FUNCTION__, command));
7611 
7612 	return bytes_written;
7613 }
7614 #endif /* SUPPORT_SET_TID */
7615 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7616 
wl_android_set_roam_mode(struct net_device * dev,char * command)7617 int wl_android_set_roam_mode(struct net_device *dev, char *command)
7618 {
7619 	int error = 0;
7620 	int mode = 0;
7621 
7622 	if (sscanf(command, "%*s %d", &mode) != 1) {
7623 		ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7624 		return -1;
7625 	}
7626 
7627 	error = wldev_iovar_setint(dev, "roam_off", mode);
7628 	if (error) {
7629 		ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
7630 		__FUNCTION__, mode, error));
7631 		return -1;
7632 	}
7633 	else
7634 		ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
7635 		__FUNCTION__, mode, error));
7636 	return 0;
7637 }
7638 
7639 #ifdef WL_CFG80211
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)7640 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
7641 {
7642 	char ie_buf[VNDR_IE_MAX_LEN];
7643 	char *ioctl_buf = NULL;
7644 	char hex[] = "XX";
7645 	char *pcmd = NULL;
7646 	int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
7647 	vndr_ie_setbuf_t *vndr_ie = NULL;
7648 	s32 iecount;
7649 	uint32 pktflag;
7650 	s32 err = BCME_OK, bssidx;
7651 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7652 
7653 	/* Check the VSIE (Vendor Specific IE) which was added.
7654 	 *  If exist then send IOVAR to delete it
7655 	 */
7656 	if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
7657 		return -EINVAL;
7658 	}
7659 
7660 	if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
7661 		ANDROID_ERROR(("error. total_len:%d\n", total_len));
7662 		return -EINVAL;
7663 	}
7664 
7665 	pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
7666 	for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
7667 		if (*pcmd == '\0') {
7668 			ANDROID_ERROR(("error while parsing OUI.\n"));
7669 			return -EINVAL;
7670 		}
7671 		hex[0] = *pcmd++;
7672 		hex[1] = *pcmd++;
7673 		ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
7674 	}
7675 	pcmd++;
7676 	while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
7677 		hex[0] = *pcmd++;
7678 		hex[1] = *pcmd++;
7679 		ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
7680 		datalen++;
7681 	}
7682 
7683 	if (datalen <= 0) {
7684 		ANDROID_ERROR(("error. vndr ie len:%d\n", datalen));
7685 		return -EINVAL;
7686 	}
7687 
7688 	tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
7689 	vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
7690 	if (!vndr_ie) {
7691 		ANDROID_ERROR(("IE memory alloc failed\n"));
7692 		return -ENOMEM;
7693 	}
7694 	/* Copy the vndr_ie SET command ("add"/"del") to the buffer */
7695 	strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
7696 
7697 	/* Set the IE count - the buffer contains only 1 IE */
7698 	iecount = htod32(1);
7699 	memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
7700 
7701 	/* Set packet flag to indicate that BEACON's will contain this IE */
7702 	pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
7703 	memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
7704 		sizeof(u32));
7705 	/* Set the IE ID */
7706 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
7707 
7708 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
7709 		DOT11_OUI_LEN);
7710 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
7711 		&ie_buf[DOT11_OUI_LEN], datalen);
7712 
7713 	ielen = DOT11_OUI_LEN + datalen;
7714 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
7715 
7716 	ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
7717 	if (!ioctl_buf) {
7718 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
7719 		if (vndr_ie) {
7720 			MFREE(cfg->osh, vndr_ie, tot_len);
7721 		}
7722 		return -ENOMEM;
7723 	}
7724 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);	/* init the buffer */
7725 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7726 		ANDROID_ERROR(("Find index failed\n"));
7727 		err = BCME_ERROR;
7728 		goto end;
7729 	}
7730 	err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
7731 			WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
7732 end:
7733 	if (err != BCME_OK) {
7734 		err = -EINVAL;
7735 		if (vndr_ie) {
7736 			MFREE(cfg->osh, vndr_ie, tot_len);
7737 		}
7738 	}
7739 	else {
7740 		/* do NOT free 'vndr_ie' for the next process */
7741 		wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
7742 	}
7743 
7744 	if (ioctl_buf) {
7745 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
7746 	}
7747 
7748 	return err;
7749 }
7750 #endif /* WL_CFG80211 */
7751 
7752 #if defined(BCMFW_ROAM_ENABLE)
7753 static int
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)7754 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
7755 {
7756 	int error = 0;
7757 	char smbuf[WLC_IOCTL_SMLEN];
7758 	uint8 buf[MAX_BUF_SIZE];
7759 	uint8 *pref = buf;
7760 	char *pcmd;
7761 	int num_ucipher_suites = 0;
7762 	int num_akm_suites = 0;
7763 	wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
7764 	wpa_suite_t akm_suites[MAX_NUM_SUITES];
7765 	int num_tuples = 0;
7766 	int total_bytes = 0;
7767 	int total_len_left;
7768 	int i, j;
7769 	char hex[] = "XX";
7770 
7771 	pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
7772 	total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
7773 
7774 	num_akm_suites = simple_strtoul(pcmd, NULL, 16);
7775 	if (num_akm_suites > MAX_NUM_SUITES) {
7776 		ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites));
7777 		return -1;
7778 	}
7779 
7780 	/* Increment for number of AKM suites field + space */
7781 	pcmd += 3;
7782 	total_len_left -= 3;
7783 
7784 	/* check to make sure pcmd does not overrun */
7785 	if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
7786 		return -1;
7787 
7788 	bzero(buf, sizeof(buf));
7789 	bzero(akm_suites, sizeof(akm_suites));
7790 	bzero(ucipher_suites, sizeof(ucipher_suites));
7791 
7792 	/* Save the AKM suites passed in the command */
7793 	for (i = 0; i < num_akm_suites; i++) {
7794 		/* Store the MSB first, as required by join_pref */
7795 		for (j = 0; j < 4; j++) {
7796 			hex[0] = *pcmd++;
7797 			hex[1] = *pcmd++;
7798 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7799 		}
7800 		memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
7801 	}
7802 
7803 	total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
7804 	num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
7805 	/* Increment for number of cipher suites field + space */
7806 	pcmd += 3;
7807 	total_len_left -= 3;
7808 
7809 	if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
7810 		return -1;
7811 
7812 	/* Save the cipher suites passed in the command */
7813 	for (i = 0; i < num_ucipher_suites; i++) {
7814 		/* Store the MSB first, as required by join_pref */
7815 		for (j = 0; j < 4; j++) {
7816 			hex[0] = *pcmd++;
7817 			hex[1] = *pcmd++;
7818 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7819 		}
7820 		memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
7821 	}
7822 
7823 	/* Join preference for RSSI
7824 	 * Type	  : 1 byte (0x01)
7825 	 * Length : 1 byte (0x02)
7826 	 * Value  : 2 bytes	(reserved)
7827 	 */
7828 	*pref++ = WL_JOIN_PREF_RSSI;
7829 	*pref++ = JOIN_PREF_RSSI_LEN;
7830 	*pref++ = 0;
7831 	*pref++ = 0;
7832 
7833 	/* Join preference for WPA
7834 	 * Type	  : 1 byte (0x02)
7835 	 * Length : 1 byte (not used)
7836 	 * Value  : (variable length)
7837 	 *		reserved: 1 byte
7838 	 *      count	: 1 byte (no of tuples)
7839 	 *		Tuple1	: 12 bytes
7840 	 *			akm[4]
7841 	 *			ucipher[4]
7842 	 *			mcipher[4]
7843 	 *		Tuple2	: 12 bytes
7844 	 *		Tuplen	: 12 bytes
7845 	 */
7846 	num_tuples = num_akm_suites * num_ucipher_suites;
7847 	if (num_tuples != 0) {
7848 		if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
7849 			*pref++ = WL_JOIN_PREF_WPA;
7850 			*pref++ = 0;
7851 			*pref++ = 0;
7852 			*pref++ = (uint8)num_tuples;
7853 			total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
7854 				(JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
7855 		} else {
7856 			ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
7857 			return -1;
7858 		}
7859 	} else {
7860 		/* No WPA config, configure only RSSI preference */
7861 		total_bytes = JOIN_PREF_RSSI_SIZE;
7862 	}
7863 
7864 	/* akm-ucipher-mcipher tuples in the format required for join_pref */
7865 	for (i = 0; i < num_ucipher_suites; i++) {
7866 		for (j = 0; j < num_akm_suites; j++) {
7867 			memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
7868 			pref += WPA_SUITE_LEN;
7869 			memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
7870 			pref += WPA_SUITE_LEN;
7871 			/* Set to 0 to match any available multicast cipher */
7872 			bzero(pref, WPA_SUITE_LEN);
7873 			pref += WPA_SUITE_LEN;
7874 		}
7875 	}
7876 
7877 	prhex("join pref", (uint8 *)buf, total_bytes);
7878 	error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
7879 	if (error) {
7880 		ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
7881 	}
7882 	return error;
7883 }
7884 #endif /* defined(BCMFW_ROAM_ENABLE */
7885 
7886 #ifdef WL_CFG80211
7887 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)7888 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
7889 {
7890 	struct io_cfg *resume_cfg;
7891 	s32 ret;
7892 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7893 
7894 	resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
7895 	if (!resume_cfg)
7896 		return -ENOMEM;
7897 
7898 	if (config->iovar) {
7899 		ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
7900 		if (ret) {
7901 			ANDROID_ERROR(("%s: Failed to get current %s value\n",
7902 				__FUNCTION__, config->iovar));
7903 			goto error;
7904 		}
7905 
7906 		ret = wldev_iovar_setint(dev, config->iovar, config->param);
7907 		if (ret) {
7908 			ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7909 				config->iovar, config->param));
7910 			goto error;
7911 		}
7912 
7913 		resume_cfg->iovar = config->iovar;
7914 	} else {
7915 		resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
7916 		if (!resume_cfg->arg) {
7917 			ret = -ENOMEM;
7918 			goto error;
7919 		}
7920 		ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
7921 		if (ret) {
7922 			ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
7923 				config->ioctl));
7924 			goto error;
7925 		}
7926 		ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
7927 		if (ret) {
7928 			ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7929 				config->iovar, config->param));
7930 			goto error;
7931 		}
7932 		if (config->ioctl + 1 == WLC_SET_PM)
7933 			wl_cfg80211_update_power_mode(dev);
7934 		resume_cfg->ioctl = config->ioctl;
7935 		resume_cfg->len = config->len;
7936 	}
7937 
7938 	/* assuming only one active user and no list protection */
7939 	list_add(&resume_cfg->list, head);
7940 
7941 	return 0;
7942 error:
7943 	MFREE(cfg->osh, resume_cfg->arg, config->len);
7944 	MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
7945 	return ret;
7946 }
7947 
7948 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)7949 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
7950 {
7951 	struct io_cfg *config;
7952 	struct list_head *cur, *q;
7953 	s32 ret = 0;
7954 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7955 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7956 	list_for_each_safe(cur, q, head) {
7957 		config = list_entry(cur, struct io_cfg, list);
7958 		GCC_DIAGNOSTIC_POP();
7959 		if (config->iovar) {
7960 			if (!ret)
7961 				ret = wldev_iovar_setint(dev, config->iovar,
7962 					config->param);
7963 		} else {
7964 			if (!ret)
7965 				ret = wldev_ioctl_set(dev, config->ioctl + 1,
7966 					config->arg, config->len);
7967 			if (config->ioctl + 1 == WLC_SET_PM)
7968 				wl_cfg80211_update_power_mode(dev);
7969 			MFREE(cfg->osh, config->arg, config->len);
7970 		}
7971 		list_del(cur);
7972 		MFREE(cfg->osh, config, sizeof(struct io_cfg));
7973 	}
7974 }
7975 
7976 static int
wl_android_set_miracast(struct net_device * dev,char * command)7977 wl_android_set_miracast(struct net_device *dev, char *command)
7978 {
7979 	int mode, val = 0;
7980 	int ret = 0;
7981 	struct io_cfg config;
7982 
7983 	if (sscanf(command, "%*s %d", &mode) != 1) {
7984 		ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7985 		return -1;
7986 	}
7987 
7988 	ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
7989 
7990 	if (miracast_cur_mode == mode) {
7991 		return 0;
7992 	}
7993 
7994 	wl_android_iolist_resume(dev, &miracast_resume_list);
7995 	miracast_cur_mode = MIRACAST_MODE_OFF;
7996 
7997 	bzero((void *)&config, sizeof(config));
7998 	switch (mode) {
7999 	case MIRACAST_MODE_SOURCE:
8000 #ifdef MIRACAST_MCHAN_ALGO
8001 		/* setting mchan_algo to platform specific value */
8002 		config.iovar = "mchan_algo";
8003 
8004 		/* check for station's beacon interval(BI)
8005 		 * If BI is over 100ms, don't use mchan_algo
8006 		 */
8007 		ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
8008 		if (!ret && val > 100) {
8009 			config.param = 0;
8010 			ANDROID_ERROR(("%s: Connected station's beacon interval: "
8011 				"%d and set mchan_algo to %d \n",
8012 				__FUNCTION__, val, config.param));
8013 		} else {
8014 			config.param = MIRACAST_MCHAN_ALGO;
8015 		}
8016 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8017 		if (ret) {
8018 			goto resume;
8019 		}
8020 #endif /* MIRACAST_MCHAN_ALGO */
8021 
8022 #ifdef MIRACAST_MCHAN_BW
8023 		/* setting mchan_bw to platform specific value */
8024 		config.iovar = "mchan_bw";
8025 		config.param = MIRACAST_MCHAN_BW;
8026 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8027 		if (ret) {
8028 			goto resume;
8029 		}
8030 #endif /* MIRACAST_MCHAN_BW */
8031 
8032 #ifdef MIRACAST_AMPDU_SIZE
8033 		/* setting apmdu to platform specific value */
8034 		config.iovar = "ampdu_mpdu";
8035 		config.param = MIRACAST_AMPDU_SIZE;
8036 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8037 		if (ret) {
8038 			goto resume;
8039 		}
8040 #endif /* MIRACAST_AMPDU_SIZE */
8041 		/* FALLTROUGH */
8042 		/* Source mode shares most configurations with sink mode.
8043 		 * Fall through here to avoid code duplication
8044 		 */
8045 	case MIRACAST_MODE_SINK:
8046 		/* disable internal roaming */
8047 		config.iovar = "roam_off";
8048 		config.param = 1;
8049 		config.arg = NULL;
8050 		config.len = 0;
8051 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8052 		if (ret) {
8053 			goto resume;
8054 		}
8055 
8056 #ifdef CUSTOMER_HW10
8057 		/* [CSP#812738] Change scan engine parameters to reduce scan time
8058 		 * and guarantee more times to mirroring.
8059 		 */
8060 		val = 10;
8061 		config.iovar = NULL;
8062 		config.ioctl = WLC_GET_SCAN_CHANNEL_TIME;
8063 		config.arg = &val;
8064 		config.len = sizeof(int);
8065 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8066 		if (ret)
8067 			goto resume;
8068 
8069 		val = 180;
8070 		config.iovar = NULL;
8071 		config.ioctl = WLC_GET_SCAN_HOME_TIME;
8072 		config.arg = &val;
8073 		config.len = sizeof(int);
8074 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8075 		if (ret)
8076 			goto resume;
8077 
8078 #if defined(BCM4339_CHIP)
8079 		config.iovar = "phy_watchdog";
8080 		config.param = 0;
8081 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8082 		ANDROID_INFO(("%s: do iovar cmd=%s (ret=%d)\n",
8083 			__FUNCTION__, config.iovar, ret));
8084 #endif
8085 #endif /* CUSTOMER_HW10 */
8086 
8087 #ifndef CUSTOMER_HW10
8088 
8089 		/* tunr off pm */
8090 		ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
8091 		if (ret) {
8092 			goto resume;
8093 		}
8094 
8095 		if (val != PM_OFF) {
8096 			val = PM_OFF;
8097 			config.iovar = NULL;
8098 			config.ioctl = WLC_GET_PM;
8099 			config.arg = &val;
8100 			config.len = sizeof(int);
8101 			ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8102 			if (ret) {
8103 				goto resume;
8104 			}
8105 		}
8106 #endif /* CUSTOMER_HW10 */
8107 		break;
8108 	case MIRACAST_MODE_OFF:
8109 	default:
8110 		break;
8111 	}
8112 	miracast_cur_mode = mode;
8113 
8114 	return 0;
8115 
8116 resume:
8117 	ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
8118 	wl_android_iolist_resume(dev, &miracast_resume_list);
8119 	return ret;
8120 }
8121 #endif /* WL_CFG80211 */
8122 
8123 #ifdef WL_RELMCAST
8124 #define NETLINK_OXYGEN     30
8125 #define AIBSS_BEACON_TIMEOUT	10
8126 
8127 static struct sock *nl_sk = NULL;
8128 
wl_netlink_recv(struct sk_buff * skb)8129 static void wl_netlink_recv(struct sk_buff *skb)
8130 {
8131 	ANDROID_ERROR(("netlink_recv called\n"));
8132 }
8133 
wl_netlink_init(void)8134 static int wl_netlink_init(void)
8135 {
8136 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8137 	struct netlink_kernel_cfg cfg = {
8138 		.input	= wl_netlink_recv,
8139 	};
8140 #endif
8141 
8142 	if (nl_sk != NULL) {
8143 		ANDROID_ERROR(("nl_sk already exist\n"));
8144 		return BCME_ERROR;
8145 	}
8146 
8147 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
8148 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
8149 		0, wl_netlink_recv, NULL, THIS_MODULE);
8150 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
8151 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
8152 #else
8153 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
8154 #endif
8155 
8156 	if (nl_sk == NULL) {
8157 		ANDROID_ERROR(("nl_sk is not ready\n"));
8158 		return BCME_ERROR;
8159 	}
8160 
8161 	return BCME_OK;
8162 }
8163 
wl_netlink_deinit(void)8164 static void wl_netlink_deinit(void)
8165 {
8166 	if (nl_sk) {
8167 		netlink_kernel_release(nl_sk);
8168 		nl_sk = NULL;
8169 	}
8170 }
8171 
8172 s32
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)8173 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
8174 {
8175 	struct sk_buff *skb = NULL;
8176 	struct nlmsghdr *nlh = NULL;
8177 	int ret = -1;
8178 
8179 	if (nl_sk == NULL) {
8180 		ANDROID_ERROR(("nl_sk was not initialized\n"));
8181 		goto nlmsg_failure;
8182 	}
8183 
8184 	skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
8185 	if (skb == NULL) {
8186 		ANDROID_ERROR(("failed to allocate memory\n"));
8187 		goto nlmsg_failure;
8188 	}
8189 
8190 	nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
8191 	if (nlh == NULL) {
8192 		ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
8193 			skb_tailroom(skb), nlmsg_total_size(size)));
8194 		dev_kfree_skb(skb);
8195 		goto nlmsg_failure;
8196 	}
8197 
8198 	memcpy(nlmsg_data(nlh), data, size);
8199 	nlh->nlmsg_seq = seq;
8200 	nlh->nlmsg_type = type;
8201 
8202 	/* netlink_unicast() takes ownership of the skb and frees it itself. */
8203 	ret = netlink_unicast(nl_sk, skb, pid, 0);
8204 	ANDROID_INFO(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
8205 
8206 nlmsg_failure:
8207 	return ret;
8208 }
8209 #endif /* WL_RELMCAST */
8210 
8211 #ifdef WLAIBSS
wl_android_set_ibss_txfail_event(struct net_device * dev,char * command,int total_len)8212 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
8213 {
8214 	int err = 0;
8215 	int retry = 0;
8216 	int pid = 0;
8217 	aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
8218 	char smbuf[WLC_IOCTL_SMLEN];
8219 
8220 	if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
8221 		ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
8222 		return -1;
8223 	}
8224 
8225 	/* set pid, and if the event was happened, let's send a notification through netlink */
8226 	wl_cfg80211_set_txfail_pid(dev, pid);
8227 
8228 #ifdef WL_RELMCAST
8229 	/* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
8230 	wl_cfg80211_set_rmc_pid(dev, pid);
8231 #endif /* WL_RELMCAST */
8232 
8233 	/* If retry value is 0, it disables the functionality for TX Fail. */
8234 	if (retry > 0) {
8235 		txfail_config.max_tx_retry = retry;
8236 		txfail_config.bcn_timeout = 0;	/* 0 : disable tx fail from beacon */
8237 	}
8238 	txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
8239 	txfail_config.len = sizeof(txfail_config);
8240 
8241 	err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
8242 		sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
8243 	ANDROID_INFO(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
8244 
8245 	return ((err == 0)?total_len:err);
8246 }
8247 
wl_android_get_ibss_peer_info(struct net_device * dev,char * command,int total_len,bool bAll)8248 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
8249 	int total_len, bool bAll)
8250 {
8251 	int error;
8252 	int bytes_written = 0;
8253 	void *buf = NULL;
8254 	bss_peer_list_info_t peer_list_info;
8255 	bss_peer_info_t *peer_info;
8256 	int i;
8257 	bool found = false;
8258 	struct ether_addr mac_ea;
8259 	char *str = command;
8260 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8261 
8262 	ANDROID_INFO(("get ibss peer info(%s)\n", bAll?"true":"false"));
8263 
8264 	if (!bAll) {
8265 		if (bcmstrtok(&str, " ", NULL) == NULL) {
8266 			ANDROID_ERROR(("invalid command\n"));
8267 			return -1;
8268 		}
8269 
8270 		if (!str || !bcm_ether_atoe(str, &mac_ea)) {
8271 			ANDROID_ERROR(("invalid MAC address\n"));
8272 			return -1;
8273 		}
8274 	}
8275 
8276 	if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) {
8277 		ANDROID_ERROR(("kmalloc failed\n"));
8278 		return -1;
8279 	}
8280 
8281 	error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
8282 	if (unlikely(error)) {
8283 		ANDROID_ERROR(("could not get ibss peer info (%d)\n", error));
8284 		MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8285 		return -1;
8286 	}
8287 
8288 	memcpy(&peer_list_info, buf, sizeof(peer_list_info));
8289 	peer_list_info.version = htod16(peer_list_info.version);
8290 	peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
8291 	peer_list_info.count = htod32(peer_list_info.count);
8292 
8293 	ANDROID_INFO(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
8294 		peer_list_info.bss_peer_info_len, peer_list_info.count));
8295 
8296 	if (peer_list_info.count > 0) {
8297 		if (bAll)
8298 			bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
8299 				peer_list_info.count);
8300 
8301 		peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
8302 
8303 		for (i = 0; i < peer_list_info.count; i++) {
8304 
8305 			ANDROID_INFO(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
8306 				peer_info->tx_rate, peer_info->rx_rate));
8307 
8308 			if (!bAll &&
8309 				memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
8310 				found = true;
8311 			}
8312 
8313 			if (bAll || found) {
8314 				bytes_written += snprintf(&command[bytes_written],
8315 					total_len - bytes_written,
8316 					MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
8317 					peer_info->tx_rate/1000, peer_info->rssi);
8318 				if (bytes_written >= total_len) {
8319 					ANDROID_ERROR(("wl_android_get_ibss_peer_info: Insufficient"
8320 						" memory, %d bytes\n",
8321 						total_len));
8322 					bytes_written = -1;
8323 					break;
8324 				}
8325 			}
8326 
8327 			if (found)
8328 				break;
8329 
8330 			peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
8331 		}
8332 	}
8333 	else {
8334 		ANDROID_ERROR(("could not get ibss peer info : no item\n"));
8335 	}
8336 	ANDROID_INFO(("command(%u):%s\n", total_len, command));
8337 	ANDROID_INFO(("bytes_written:%d\n", bytes_written));
8338 
8339 	MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8340 	return bytes_written;
8341 }
8342 
wl_android_set_ibss_routetable(struct net_device * dev,char * command)8343 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
8344 {
8345 
8346 	char *pcmd = command;
8347 	char *str = NULL;
8348 	ibss_route_tbl_t *route_tbl = NULL;
8349 	char *ioctl_buf = NULL;
8350 	s32 err = BCME_OK;
8351 	uint32 route_tbl_len;
8352 	uint32 entries;
8353 	char *endptr;
8354 	uint32 i = 0;
8355 	struct ipv4_addr  dipaddr;
8356 	struct ether_addr ea;
8357 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8358 
8359 	route_tbl_len = sizeof(ibss_route_tbl_t) +
8360 		(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
8361 	route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
8362 	if (!route_tbl) {
8363 		ANDROID_ERROR(("Route TBL alloc failed\n"));
8364 		return -ENOMEM;
8365 	}
8366 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
8367 	if (!ioctl_buf) {
8368 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
8369 		if (route_tbl) {
8370 			MFREE(cfg->osh, route_tbl, route_tbl_len);
8371 		}
8372 		return -ENOMEM;
8373 	}
8374 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);
8375 
8376 	/* drop command */
8377 	str = bcmstrtok(&pcmd, " ", NULL);
8378 
8379 	/* get count */
8380 	str = bcmstrtok(&pcmd, " ",  NULL);
8381 	if (!str) {
8382 		ANDROID_ERROR(("Invalid number parameter %s\n", str));
8383 		err = -EINVAL;
8384 		goto exit;
8385 	}
8386 	entries = bcm_strtoul(str, &endptr, 0);
8387 	if (*endptr != '\0') {
8388 		ANDROID_ERROR(("Invalid number parameter %s\n", str));
8389 		err = -EINVAL;
8390 		goto exit;
8391 	}
8392 	if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
8393 		ANDROID_ERROR(("Invalid entries number %u\n", entries));
8394 		err = -EINVAL;
8395 		goto exit;
8396 	}
8397 
8398 	ANDROID_INFO(("Routing table count:%u\n", entries));
8399 	route_tbl->num_entry = entries;
8400 
8401 	for (i = 0; i < entries; i++) {
8402 		str = bcmstrtok(&pcmd, " ", NULL);
8403 		if (!str || !bcm_atoipv4(str, &dipaddr)) {
8404 			ANDROID_ERROR(("Invalid ip string %s\n", str));
8405 			err = -EINVAL;
8406 			goto exit;
8407 		}
8408 
8409 		str = bcmstrtok(&pcmd, " ", NULL);
8410 		if (!str || !bcm_ether_atoe(str, &ea)) {
8411 			ANDROID_ERROR(("Invalid ethernet string %s\n", str));
8412 			err = -EINVAL;
8413 			goto exit;
8414 		}
8415 		bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
8416 		bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
8417 	}
8418 
8419 	route_tbl_len = sizeof(ibss_route_tbl_t) +
8420 		((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
8421 	err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
8422 		route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
8423 	if (err != BCME_OK) {
8424 		ANDROID_ERROR(("Fail to set iovar %d\n", err));
8425 		err = -EINVAL;
8426 	}
8427 
8428 exit:
8429 	if (route_tbl) {
8430 		MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
8431 			(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
8432 	}
8433 	if (ioctl_buf) {
8434 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
8435 	}
8436 	return err;
8437 
8438 }
8439 
8440 int
wl_android_set_ibss_ampdu(struct net_device * dev,char * command,int total_len)8441 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
8442 {
8443 	char *pcmd = command;
8444 	char *str = NULL, *endptr = NULL;
8445 	struct ampdu_aggr aggr;
8446 	char smbuf[WLC_IOCTL_SMLEN];
8447 	int idx;
8448 	int err = 0;
8449 	int wme_AC2PRIO[AC_COUNT][2] = {
8450 		{PRIO_8021D_VO, PRIO_8021D_NC},		/* AC_VO - 3 */
8451 		{PRIO_8021D_CL, PRIO_8021D_VI},		/* AC_VI - 2 */
8452 		{PRIO_8021D_BK, PRIO_8021D_NONE},	/* AC_BK - 1 */
8453 		{PRIO_8021D_BE, PRIO_8021D_EE}};	/* AC_BE - 0 */
8454 
8455 	ANDROID_INFO(("set ibss ampdu:%s\n", command));
8456 
8457 	bzero(&aggr, sizeof(aggr));
8458 	/* Cofigure all priorities */
8459 	aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
8460 
8461 	/* acquire parameters */
8462 	/* drop command */
8463 	str = bcmstrtok(&pcmd, " ", NULL);
8464 
8465 	for (idx = 0; idx < AC_COUNT; idx++) {
8466 		bool on;
8467 		str = bcmstrtok(&pcmd, " ", NULL);
8468 		if (!str) {
8469 			ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8470 			return -EINVAL;
8471 		}
8472 		on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
8473 		if (*endptr != '\0') {
8474 			ANDROID_ERROR(("Invalid number format %s\n", str));
8475 			return -EINVAL;
8476 		}
8477 		if (on) {
8478 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
8479 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
8480 		}
8481 	}
8482 
8483 	err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
8484 	sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
8485 
8486 	return ((err == 0) ? total_len : err);
8487 }
8488 
wl_android_set_ibss_antenna(struct net_device * dev,char * command,int total_len)8489 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
8490 {
8491 	char *pcmd = command;
8492 	char *str = NULL;
8493 	int txchain, rxchain;
8494 	int err = 0;
8495 
8496 	ANDROID_INFO(("set ibss antenna:%s\n", command));
8497 
8498 	/* acquire parameters */
8499 	/* drop command */
8500 	str = bcmstrtok(&pcmd, " ", NULL);
8501 
8502 	/* TX chain */
8503 	str = bcmstrtok(&pcmd, " ", NULL);
8504 	if (!str) {
8505 		ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8506 		return -EINVAL;
8507 	}
8508 	txchain = bcm_atoi(str);
8509 
8510 	/* RX chain */
8511 	str = bcmstrtok(&pcmd, " ", NULL);
8512 	if (!str) {
8513 		ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8514 		return -EINVAL;
8515 	}
8516 	rxchain = bcm_atoi(str);
8517 
8518 	err = wldev_iovar_setint(dev, "txchain", txchain);
8519 	if (err != 0)
8520 		return err;
8521 	err = wldev_iovar_setint(dev, "rxchain", rxchain);
8522 	return ((err == 0)?total_len:err);
8523 }
8524 #endif /* WLAIBSS */
8525 
wl_keep_alive_set(struct net_device * dev,char * extra)8526 int wl_keep_alive_set(struct net_device *dev, char* extra)
8527 {
8528 	wl_mkeep_alive_pkt_t	mkeep_alive_pkt;
8529 	int ret;
8530 	uint period_msec = 0;
8531 	char *buf;
8532 	dhd_pub_t *dhd = dhd_get_pub(dev);
8533 
8534 	if (extra == NULL) {
8535 		 ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
8536 		 return -1;
8537 	}
8538 	if (sscanf(extra, "%d", &period_msec) != 1) {
8539 		 ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
8540 		 return -EINVAL;
8541 	}
8542 	ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
8543 
8544 	bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
8545 
8546 	mkeep_alive_pkt.period_msec = period_msec;
8547 	mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
8548 	mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
8549 
8550 	/* Setup keep alive zero for null packet generation */
8551 	mkeep_alive_pkt.keep_alive_id = 0;
8552 	mkeep_alive_pkt.len_bytes = 0;
8553 
8554 	buf = (char *)MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
8555 	if (!buf) {
8556 		ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
8557 		return BCME_NOMEM;
8558 	}
8559 	ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
8560 			WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8561 	if (ret < 0)
8562 		ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
8563 	else
8564 		ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
8565 	MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
8566 	return ret;
8567 }
8568 
8569 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)8570 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
8571 {
8572 	int error = 0;
8573 	int bytes_written = 0;
8574 	int only_resp_wfdsrc = 0;
8575 
8576 	error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
8577 	if (error) {
8578 		ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
8579 			__FUNCTION__, error));
8580 		return -1;
8581 	}
8582 
8583 	bytes_written = snprintf(command, total_len, "%s %d",
8584 		CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
8585 
8586 	return bytes_written;
8587 }
8588 
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)8589 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
8590 {
8591 	int error = 0;
8592 
8593 	error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
8594 	if (error) {
8595 		ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
8596 			__FUNCTION__, only_resp_wfdsrc, error));
8597 		return -1;
8598 	}
8599 
8600 	return 0;
8601 }
8602 #endif /* P2PRESP_WFDIE_SRC */
8603 
8604 #ifdef BT_WIFI_HANDOVER
8605 static int
wl_tbow_teardown(struct net_device * dev)8606 wl_tbow_teardown(struct net_device *dev)
8607 {
8608 	int err = BCME_OK;
8609 	char buf[WLC_IOCTL_SMLEN];
8610 	tbow_setup_netinfo_t netinfo;
8611 	bzero(&netinfo, sizeof(netinfo));
8612 	netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
8613 
8614 	err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
8615 			sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
8616 	if (err < 0) {
8617 		ANDROID_ERROR(("tbow_doho iovar error %d\n", err));
8618 		return err;
8619 	}
8620 	return err;
8621 }
8622 #endif /* BT_WIFI_HANOVER */
8623 
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)8624 static int wl_android_get_link_status(struct net_device *dev, char *command,
8625 	int total_len)
8626 {
8627 	int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
8628 	uint32 rspec;
8629 	uint encode, txexp;
8630 	wl_bss_info_t *bi;
8631 	int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
8632 	char buf[WLC_IOCTL_SMLEN];
8633 
8634 	if (datalen > WLC_IOCTL_SMLEN) {
8635 		ANDROID_ERROR(("data too big\n"));
8636 		return -1;
8637 	}
8638 
8639 	bzero(buf, datalen);
8640 	/* get BSS information */
8641 	*(u32 *) buf = htod32(datalen);
8642 	error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
8643 	if (unlikely(error)) {
8644 		ANDROID_ERROR(("Could not get bss info %d\n", error));
8645 		return -1;
8646 	}
8647 
8648 	bi = (wl_bss_info_t*) (buf + sizeof(uint32));
8649 
8650 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
8651 		if (bi->BSSID.octet[i] > 0) {
8652 			break;
8653 		}
8654 	}
8655 
8656 	if (i == ETHER_ADDR_LEN) {
8657 		ANDROID_INFO(("No BSSID\n"));
8658 		return -1;
8659 	}
8660 
8661 	/* check VHT capability at beacon */
8662 	if (bi->vht_cap) {
8663 		if (CHSPEC_IS5G(bi->chanspec)) {
8664 			result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
8665 		}
8666 	}
8667 
8668 	/* get a rspec (radio spectrum) rate */
8669 	error = wldev_iovar_getint(dev, "nrate", &rspec);
8670 	if (unlikely(error) || rspec == 0) {
8671 		ANDROID_ERROR(("get link status error (%d)\n", error));
8672 		return -1;
8673 	}
8674 
8675 	/* referred wl_nrate_print() for the calculation */
8676 	encode = (rspec & WL_RSPEC_ENCODING_MASK);
8677 	txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
8678 
8679 	switch (encode) {
8680 	case WL_RSPEC_ENCODE_HT:
8681 		/* check Rx MCS Map for HT */
8682 		for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
8683 			int8 bitmap = 0xFF;
8684 			if (i == MAX_STREAMS_SUPPORTED-1) {
8685 				bitmap = 0x7F;
8686 			}
8687 			if (bi->basic_mcs[i] & bitmap) {
8688 				nss++;
8689 			}
8690 		}
8691 		break;
8692 	case WL_RSPEC_ENCODE_VHT:
8693 		/* check Rx MCS Map for VHT */
8694 		for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
8695 			mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
8696 			if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
8697 				nss++;
8698 			}
8699 		}
8700 		break;
8701 	}
8702 
8703 	/* check MIMO capability with nss in beacon */
8704 	if (nss > 1) {
8705 		result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
8706 	}
8707 
8708 	/* Legacy rates WL_RSPEC_ENCODE_RATE are single stream, and
8709 	 * HT rates for mcs 0-7 are single stream.
8710 	 * In case of VHT NSS comes from rspec.
8711 	 */
8712 	single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
8713 		((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
8714 		((encode == WL_RSPEC_ENCODE_VHT) &&
8715 		((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
8716 
8717 	if (txexp == 0) {
8718 		if ((rspec & WL_RSPEC_STBC) && single_stream) {
8719 			stf = OLD_NRATE_STF_STBC;
8720 		} else {
8721 			stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
8722 		}
8723 	} else if (txexp == 1 && single_stream) {
8724 		stf = OLD_NRATE_STF_CDD;
8725 	}
8726 
8727 	/* check 11ac (VHT) */
8728 	if (encode == WL_RSPEC_ENCODE_VHT) {
8729 		if (CHSPEC_IS5G(bi->chanspec)) {
8730 			result |= WL_ANDROID_LINK_VHT;
8731 		}
8732 	}
8733 
8734 	/* check MIMO */
8735 	if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
8736 		switch (stf) {
8737 		case OLD_NRATE_STF_SISO:
8738 			break;
8739 		case OLD_NRATE_STF_CDD:
8740 		case OLD_NRATE_STF_STBC:
8741 			result |= WL_ANDROID_LINK_MIMO;
8742 			break;
8743 		case OLD_NRATE_STF_SDM:
8744 			if (!single_stream) {
8745 				result |= WL_ANDROID_LINK_MIMO;
8746 			}
8747 			break;
8748 		}
8749 	}
8750 
8751 	ANDROID_INFO(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
8752 		__FUNCTION__, result, stf, single_stream, nss));
8753 
8754 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
8755 
8756 	return bytes_written;
8757 }
8758 
8759 #ifdef P2P_LISTEN_OFFLOADING
8760 
8761 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 * cfg)8762 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
8763 {
8764 	s32 bssidx;
8765 	int ret = 0;
8766 	int p2plo_pause = 0;
8767 	dhd_pub_t *dhd = NULL;
8768 	if (!cfg || !cfg->p2p) {
8769 		ANDROID_ERROR(("Wl %p or cfg->p2p %p is null\n",
8770 			cfg, cfg ? cfg->p2p : 0));
8771 		return 0;
8772 	}
8773 
8774 	dhd =  (dhd_pub_t *)(cfg->pub);
8775 	if (!dhd->up) {
8776 		ANDROID_ERROR(("bus is already down\n"));
8777 		return ret;
8778 	}
8779 
8780 	bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8781 	ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
8782 			"p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
8783 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
8784 	if (ret < 0) {
8785 		ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8786 	}
8787 
8788 	return  ret;
8789 }
8790 s32
wl_cfg80211_p2plo_listen_start(struct net_device * dev,u8 * buf,int len)8791 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
8792 {
8793 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8794 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8795 	wl_p2plo_listen_t p2plo_listen;
8796 	int ret = -EAGAIN;
8797 	int channel = 0;
8798 	int period = 0;
8799 	int interval = 0;
8800 	int count = 0;
8801 	if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
8802 		ANDROID_ERROR(("Sending Action Frames. Try it again.\n"));
8803 		goto exit;
8804 	}
8805 
8806 	if (wl_get_drv_status_all(cfg, SCANNING)) {
8807 		ANDROID_ERROR(("Scanning already\n"));
8808 		goto exit;
8809 	}
8810 
8811 	if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
8812 		ANDROID_ERROR(("Scanning being aborted\n"));
8813 		goto exit;
8814 	}
8815 
8816 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8817 		ANDROID_ERROR(("p2p listen offloading already running\n"));
8818 		goto exit;
8819 	}
8820 
8821 	/* Just in case if it is not enabled */
8822 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
8823 		ANDROID_ERROR(("cfgp2p_enable discovery failed"));
8824 		goto exit;
8825 	}
8826 
8827 	bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
8828 
8829 	if (len) {
8830 		sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
8831 		if ((channel == 0) || (period == 0) ||
8832 				(interval == 0) || (count == 0)) {
8833 			ANDROID_ERROR(("Wrong argument %d/%d/%d/%d \n",
8834 				channel, period, interval, count));
8835 			ret = -EAGAIN;
8836 			goto exit;
8837 		}
8838 		p2plo_listen.period = period;
8839 		p2plo_listen.interval = interval;
8840 		p2plo_listen.count = count;
8841 
8842 		ANDROID_ERROR(("channel:%d period:%d, interval:%d count:%d\n",
8843 			channel, period, interval, count));
8844 	} else {
8845 		ANDROID_ERROR(("Argument len is wrong.\n"));
8846 		ret = -EAGAIN;
8847 		goto exit;
8848 	}
8849 
8850 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
8851 			sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8852 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8853 		ANDROID_ERROR(("p2po_listen_channel Failed :%d\n", ret));
8854 		goto exit;
8855 	}
8856 
8857 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
8858 			sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8859 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8860 		ANDROID_ERROR(("p2po_listen Failed :%d\n", ret));
8861 		goto exit;
8862 	}
8863 
8864 	wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
8865 exit :
8866 	return ret;
8867 }
8868 s32
wl_cfg80211_p2plo_listen_stop(struct net_device * dev)8869 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
8870 {
8871 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8872 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8873 	int ret = -EAGAIN;
8874 
8875 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
8876 			0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8877 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8878 		ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8879 		goto exit;
8880 	}
8881 
8882 exit:
8883 	return ret;
8884 }
8885 
8886 s32
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)8887 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
8888 {
8889 	int ret = 0;
8890 
8891 	ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len));
8892 
8893 	if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
8894 		ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
8895 	} else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
8896 		ret = wl_cfg80211_p2plo_listen_stop(dev);
8897 	} else {
8898 		ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf));
8899 		ret = -EINVAL;
8900 	}
8901 	return ret;
8902 }
8903 void
wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 * cfg)8904 wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
8905 {
8906 	struct wireless_dev *wdev;
8907 	if (!cfg) {
8908 		return;
8909 	}
8910 
8911 	wdev = bcmcfg_to_p2p_wdev(cfg);
8912 
8913 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8914 		ANDROID_INFO(("P2P_FIND: Discovery offload is already in progress."
8915 					"it aborted\n"));
8916 		wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
8917 		if (wdev != NULL) {
8918 #if defined(WL_CFG80211_P2P_DEV_IF)
8919 			cfg80211_remain_on_channel_expired(wdev,
8920 					cfg->last_roc_id,
8921 					&cfg->remain_on_chan, GFP_KERNEL);
8922 #else
8923 			cfg80211_remain_on_channel_expired(wdev,
8924 					cfg->last_roc_id,
8925 					&cfg->remain_on_chan,
8926 					cfg->remain_on_chan_type, GFP_KERNEL);
8927 #endif /* WL_CFG80211_P2P_DEV_IF */
8928 		}
8929 		wl_cfg80211_p2plo_deinit(cfg);
8930 	}
8931 }
8932 #endif /* P2P_LISTEN_OFFLOADING */
8933 
8934 #ifdef WL_MURX
8935 int
wl_android_murx_bfe_cap(struct net_device * dev,int val)8936 wl_android_murx_bfe_cap(struct net_device *dev, int val)
8937 {
8938 	int err = BCME_OK;
8939 	int iface_count = wl_cfg80211_iface_count(dev);
8940 	struct ether_addr bssid;
8941 	wl_reassoc_params_t params;
8942 
8943 	if (iface_count > 1) {
8944 		ANDROID_ERROR(("murx_bfe_cap change is not allowed when "
8945 				"there are multiple interfaces\n"));
8946 		return -EINVAL;
8947 	}
8948 	/* Now there is only single interface */
8949 	err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
8950 	if (unlikely(err)) {
8951 		ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d,"
8952 				"error %d\n", val, err));
8953 		return err;
8954 	}
8955 
8956 	/* If successful intiate a reassoc */
8957 	bzero(&bssid, ETHER_ADDR_LEN);
8958 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
8959 		ANDROID_ERROR(("Failed to get bssid, error=%d\n", err));
8960 		return err;
8961 	}
8962 
8963 	bzero(&params, sizeof(wl_reassoc_params_t));
8964 	memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
8965 
8966 	if ((err = wldev_ioctl_set(dev, WLC_REASSOC, &params,
8967 		sizeof(wl_reassoc_params_t))) < 0) {
8968 		ANDROID_ERROR(("reassoc failed err:%d \n", err));
8969 	} else {
8970 		ANDROID_INFO(("reassoc issued successfully\n"));
8971 	}
8972 
8973 	return err;
8974 }
8975 #endif /* WL_MURX */
8976 
8977 #ifdef SUPPORT_RSSI_SUM_REPORT
8978 int
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)8979 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
8980 {
8981 	wl_rssi_ant_mimo_t rssi_ant_mimo;
8982 	char *ifname = NULL;
8983 	char *peer_mac = NULL;
8984 	char *mimo_cmd = "mimo";
8985 	char *pos, *token;
8986 	int err = BCME_OK;
8987 	int bytes_written = 0;
8988 	bool mimo_rssi = FALSE;
8989 
8990 	bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
8991 	/*
8992 	 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
8993 	 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
8994 	 */
8995 	pos = command;
8996 
8997 	/* drop command */
8998 	token = bcmstrtok(&pos, " ", NULL);
8999 
9000 	/* get the interface name */
9001 	token = bcmstrtok(&pos, " ", NULL);
9002 	if (!token) {
9003 		ANDROID_ERROR(("Invalid arguments\n"));
9004 		return -EINVAL;
9005 	}
9006 	ifname = token;
9007 
9008 	/* Optional: Check the MIMO RSSI mode or peer MAC address */
9009 	token = bcmstrtok(&pos, " ", NULL);
9010 	if (token) {
9011 		/* Check the MIMO RSSI mode */
9012 		if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9013 			mimo_rssi = TRUE;
9014 		} else {
9015 			peer_mac = token;
9016 		}
9017 	}
9018 
9019 	/* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
9020 	token = bcmstrtok(&pos, " ", NULL);
9021 	if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9022 		mimo_rssi = TRUE;
9023 	}
9024 
9025 	err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
9026 	if (unlikely(err)) {
9027 		ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err));
9028 		return err;
9029 	}
9030 
9031 	/* Parse the results */
9032 	ANDROID_INFO(("ifname %s, version %d, count %d, mimo rssi %d\n",
9033 		ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
9034 	if (mimo_rssi) {
9035 		ANDROID_INFO(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
9036 		bytes_written = snprintf(command, total_len, "%s MIMO %d",
9037 			CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
9038 	} else {
9039 		int cnt;
9040 		bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
9041 		for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
9042 			ANDROID_INFO(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
9043 			bytes_written = snprintf(command, total_len, "%d ",
9044 				rssi_ant_mimo.rssi_ant[cnt]);
9045 		}
9046 	}
9047 
9048 	return bytes_written;
9049 }
9050 
9051 int
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)9052 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
9053 {
9054 	rssilog_set_param_t set_param;
9055 	char *pos, *token;
9056 	int err = BCME_OK;
9057 
9058 	bzero(&set_param, sizeof(rssilog_set_param_t));
9059 	/*
9060 	 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
9061 	 */
9062 	pos = command;
9063 
9064 	/* drop command */
9065 	token = bcmstrtok(&pos, " ", NULL);
9066 
9067 	/* enable/disable */
9068 	token = bcmstrtok(&pos, " ", NULL);
9069 	if (!token) {
9070 		ANDROID_ERROR(("Invalid arguments\n"));
9071 		return -EINVAL;
9072 	}
9073 	set_param.enable = bcm_atoi(token);
9074 
9075 	/* RSSI Threshold */
9076 	token = bcmstrtok(&pos, " ", NULL);
9077 	if (!token) {
9078 		ANDROID_ERROR(("Invalid arguments\n"));
9079 		return -EINVAL;
9080 	}
9081 	set_param.rssi_threshold = bcm_atoi(token);
9082 
9083 	/* Time Threshold */
9084 	token = bcmstrtok(&pos, " ", NULL);
9085 	if (!token) {
9086 		ANDROID_ERROR(("Invalid arguments\n"));
9087 		return -EINVAL;
9088 	}
9089 	set_param.time_threshold = bcm_atoi(token);
9090 
9091 	ANDROID_INFO(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
9092 		set_param.rssi_threshold, set_param.time_threshold));
9093 
9094 	err = wl_set_rssi_logging(dev, (void *)&set_param);
9095 	if (unlikely(err)) {
9096 		ANDROID_ERROR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
9097 			" Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
9098 			set_param.time_threshold));
9099 	}
9100 
9101 	return err;
9102 }
9103 
9104 int
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)9105 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
9106 {
9107 	rssilog_get_param_t get_param;
9108 	int err = BCME_OK;
9109 	int bytes_written = 0;
9110 
9111 	err = wl_get_rssi_logging(dev, (void *)&get_param);
9112 	if (unlikely(err)) {
9113 		ANDROID_ERROR(("Failed to get RSSI logging info\n"));
9114 		return BCME_ERROR;
9115 	}
9116 
9117 	ANDROID_INFO(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
9118 		get_param.report_count, get_param.enable, get_param.rssi_threshold,
9119 		get_param.time_threshold));
9120 
9121 	/* Parse the parameter */
9122 	if (!get_param.enable) {
9123 		ANDROID_INFO(("RSSI LOGGING: Feature is disables\n"));
9124 		bytes_written = snprintf(command, total_len,
9125 			"%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
9126 	} else if (get_param.enable &
9127 		(RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
9128 		if (!get_param.report_count) {
9129 			ANDROID_INFO(("[PASS] RSSI difference across antennas is within"
9130 				" threshold limits\n"));
9131 			bytes_written = snprintf(command, total_len, "%s PASS\n",
9132 				CMD_GET_RSSI_LOGGING);
9133 		} else {
9134 			ANDROID_INFO(("[FAIL] RSSI difference across antennas found "
9135 				"to be greater than %3d dB\n", get_param.rssi_threshold));
9136 			ANDROID_INFO(("[FAIL] RSSI difference check have failed for "
9137 				"%d out of %d times\n", get_param.report_count,
9138 				get_param.time_threshold));
9139 			ANDROID_INFO(("[FAIL] RSSI difference is being monitored once "
9140 				"per second, for a %d secs window\n", get_param.time_threshold));
9141 			bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
9142 				"%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
9143 				get_param.rssi_threshold, get_param.report_count,
9144 				get_param.time_threshold);
9145 		}
9146 	} else {
9147 		ANDROID_INFO(("[BUSY] Reprot is not ready\n"));
9148 		bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
9149 			CMD_GET_RSSI_LOGGING);
9150 	}
9151 
9152 	return bytes_written;
9153 }
9154 #endif /* SUPPORT_RSSI_SUM_REPORT */
9155 
9156 #ifdef SET_PCIE_IRQ_CPU_CORE
9157 void
wl_android_set_irq_cpucore(struct net_device * net,int affinity_cmd)9158 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
9159 {
9160 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9161 	if (!dhdp) {
9162 		ANDROID_ERROR(("dhd is NULL\n"));
9163 		return;
9164 	}
9165 
9166 	dhd_set_irq_cpucore(dhdp, affinity_cmd);
9167 }
9168 #endif /* SET_PCIE_IRQ_CPU_CORE */
9169 
9170 #ifdef SUPPORT_LQCM
9171 static int
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)9172 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
9173 {
9174 	int err = 0;
9175 
9176 	err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
9177 	if (err != BCME_OK) {
9178 		ANDROID_ERROR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
9179 		return -EIO;
9180 	}
9181 	return err;
9182 }
9183 
9184 static int
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)9185 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
9186 {
9187 	int bytes_written, err = 0;
9188 	uint32 lqcm_report = 0;
9189 	uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
9190 
9191 	err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
9192 	if (err != BCME_OK) {
9193 		ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err));
9194 		return -EIO;
9195 	}
9196 	lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
9197 	tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
9198 	rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
9199 
9200 	ANDROID_INFO(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
9201 
9202 	bytes_written = snprintf(command, total_len, "%s %d",
9203 			CMD_GET_LQCM_REPORT, lqcm_report);
9204 
9205 	return bytes_written;
9206 }
9207 #endif /* SUPPORT_LQCM */
9208 
9209 int
wl_android_get_snr(struct net_device * dev,char * command,int total_len)9210 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
9211 {
9212 	int bytes_written, error = 0;
9213 	s32 snr = 0;
9214 
9215 	error = wldev_iovar_getint(dev, "snr", &snr);
9216 	if (error) {
9217 		ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n",
9218 			__FUNCTION__, snr, error));
9219 		return -EIO;
9220 	}
9221 
9222 	bytes_written = snprintf(command, total_len, "snr %d", snr);
9223 	ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
9224 	return bytes_written;
9225 }
9226 
9227 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
9228 int
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)9229 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
9230 {
9231 	int rate = 0;
9232 	char *pos, *token;
9233 	char *ifname = NULL;
9234 	int err = BCME_OK;
9235 
9236 	/*
9237 	 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
9238 	 */
9239 	pos = command;
9240 
9241 	/* drop command */
9242 	token = bcmstrtok(&pos, " ", NULL);
9243 
9244 	/* Rate */
9245 	token = bcmstrtok(&pos, " ", NULL);
9246 	if (!token)
9247 		return -EINVAL;
9248 	rate = bcm_atoi(token);
9249 
9250 	/* get the interface name */
9251 	token = bcmstrtok(&pos, " ", NULL);
9252 	if (!token)
9253 		return -EINVAL;
9254 	ifname = token;
9255 
9256 	ANDROID_INFO(("rate %d, ifacename %s\n", rate, ifname));
9257 
9258 	err = wl_set_ap_beacon_rate(dev, rate, ifname);
9259 	if (unlikely(err)) {
9260 		ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
9261 	}
9262 
9263 	return err;
9264 }
9265 
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)9266 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
9267 {
9268 	char *pos, *token;
9269 	char *ifname = NULL;
9270 	int bytes_written = 0;
9271 	/*
9272 	 * DRIVER GET_AP_BASICRATE <ifname>
9273 	 */
9274 	pos = command;
9275 
9276 	/* drop command */
9277 	token = bcmstrtok(&pos, " ", NULL);
9278 
9279 	/* get the interface name */
9280 	token = bcmstrtok(&pos, " ", NULL);
9281 	if (!token)
9282 		return -EINVAL;
9283 	ifname = token;
9284 
9285 	ANDROID_INFO(("ifacename %s\n", ifname));
9286 
9287 	bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
9288 	if (bytes_written < 1) {
9289 		ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written));
9290 		return -EPROTO;
9291 	}
9292 
9293 	return bytes_written;
9294 }
9295 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
9296 
9297 #ifdef SUPPORT_AP_RADIO_PWRSAVE
9298 int
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)9299 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
9300 {
9301 	char *pos, *token;
9302 	char *ifname = NULL;
9303 	int bytes_written = 0;
9304 	char name[IFNAMSIZ];
9305 	/*
9306 	 * DRIVER GET_AP_RPS <ifname>
9307 	 */
9308 	pos = command;
9309 
9310 	/* drop command */
9311 	token = bcmstrtok(&pos, " ", NULL);
9312 
9313 	/* get the interface name */
9314 	token = bcmstrtok(&pos, " ", NULL);
9315 	if (!token)
9316 		return -EINVAL;
9317 	ifname = token;
9318 
9319 	strlcpy(name, ifname, sizeof(name));
9320 	ANDROID_INFO(("ifacename %s\n", name));
9321 
9322 	bytes_written = wl_get_ap_rps(dev, command, name, total_len);
9323 	if (bytes_written < 1) {
9324 		ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written));
9325 		return -EPROTO;
9326 	}
9327 
9328 	return bytes_written;
9329 
9330 }
9331 
9332 int
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)9333 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
9334 {
9335 	int enable = 0;
9336 	char *pos, *token;
9337 	char *ifname = NULL;
9338 	int err = BCME_OK;
9339 	char name[IFNAMSIZ];
9340 
9341 	/*
9342 	 * DRIVER SET_AP_RPS <0/1> <ifname>
9343 	 */
9344 	pos = command;
9345 
9346 	/* drop command */
9347 	token = bcmstrtok(&pos, " ", NULL);
9348 
9349 	/* Enable */
9350 	token = bcmstrtok(&pos, " ", NULL);
9351 	if (!token)
9352 		return -EINVAL;
9353 	enable = bcm_atoi(token);
9354 
9355 	/* get the interface name */
9356 	token = bcmstrtok(&pos, " ", NULL);
9357 	if (!token)
9358 		return -EINVAL;
9359 	ifname = token;
9360 
9361 	strlcpy(name, ifname, sizeof(name));
9362 	ANDROID_INFO(("enable %d, ifacename %s\n", enable, name));
9363 
9364 	err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
9365 	if (unlikely(err)) {
9366 		ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err));
9367 	}
9368 
9369 	return err;
9370 }
9371 
9372 int
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)9373 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
9374 {
9375 	ap_rps_info_t rps;
9376 	char *pos, *token;
9377 	char *ifname = NULL;
9378 	int err = BCME_OK;
9379 	char name[IFNAMSIZ];
9380 
9381 	bzero(&rps, sizeof(rps));
9382 	/*
9383 	 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
9384 	 */
9385 	pos = command;
9386 
9387 	/* drop command */
9388 	token = bcmstrtok(&pos, " ", NULL);
9389 
9390 	/* pps */
9391 	token = bcmstrtok(&pos, " ", NULL);
9392 	if (!token)
9393 		return -EINVAL;
9394 	rps.pps = bcm_atoi(token);
9395 
9396 	/* level */
9397 	token = bcmstrtok(&pos, " ", NULL);
9398 	if (!token)
9399 		return -EINVAL;
9400 	rps.level = bcm_atoi(token);
9401 
9402 	/* quiettime */
9403 	token = bcmstrtok(&pos, " ", NULL);
9404 	if (!token)
9405 		return -EINVAL;
9406 	rps.quiet_time = bcm_atoi(token);
9407 
9408 	/* sta assoc check */
9409 	token = bcmstrtok(&pos, " ", NULL);
9410 	if (!token)
9411 		return -EINVAL;
9412 	rps.sta_assoc_check = bcm_atoi(token);
9413 
9414 	/* get the interface name */
9415 	token = bcmstrtok(&pos, " ", NULL);
9416 	if (!token)
9417 		return -EINVAL;
9418 	ifname = token;
9419 	strlcpy(name, ifname, sizeof(name));
9420 
9421 	ANDROID_INFO(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
9422 		"ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
9423 		rps.sta_assoc_check, name));
9424 
9425 	err = wl_update_ap_rps_params(dev, &rps, name);
9426 	if (unlikely(err)) {
9427 		ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, "
9428 			"sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
9429 			rps.sta_assoc_check, err));
9430 	}
9431 
9432 	return err;
9433 }
9434 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
9435 
9436 #if defined(DHD_HANG_SEND_UP_TEST)
9437 void
wl_android_make_hang_with_reason(struct net_device * dev,const char * string_num)9438 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
9439 {
9440 	dhd_make_hang_with_reason(dev, string_num);
9441 }
9442 #endif /* DHD_HANG_SEND_UP_TEST */
9443 
9444 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
9445 static void
wl_android_check_priv_cmd_errors(struct net_device * dev)9446 wl_android_check_priv_cmd_errors(struct net_device *dev)
9447 {
9448 	dhd_pub_t *dhdp;
9449 	int memdump_mode;
9450 
9451 	if (!dev) {
9452 		ANDROID_ERROR(("dev is NULL\n"));
9453 		return;
9454 	}
9455 
9456 	dhdp = wl_cfg80211_get_dhdp(dev);
9457 	if (!dhdp) {
9458 		ANDROID_ERROR(("dhdp is NULL\n"));
9459 		return;
9460 	}
9461 
9462 #ifdef DHD_FW_COREDUMP
9463 	memdump_mode = dhdp->memdump_enabled;
9464 #else
9465 	/* Default enable if DHD doesn't support SOCRAM dump */
9466 	memdump_mode = 1;
9467 #endif /* DHD_FW_COREDUMP */
9468 
9469 	if (report_hang_privcmd_err) {
9470 		priv_cmd_errors++;
9471 	} else {
9472 		priv_cmd_errors = 0;
9473 	}
9474 
9475 	/* Trigger HANG event only if memdump mode is enabled
9476 	 * due to customer's request
9477 	 */
9478 	if (memdump_mode == DUMP_MEMFILE_BUGON &&
9479 		(priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
9480 		ANDROID_ERROR(("Send HANG event due to sequential private cmd errors\n"));
9481 		priv_cmd_errors = 0;
9482 #ifdef DHD_FW_COREDUMP
9483 		/* Take a SOCRAM dump */
9484 		dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
9485 		dhd_common_socram_dump(dhdp);
9486 #endif /* DHD_FW_COREDUMP */
9487 		/* Send the HANG event to upper layer */
9488 		dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
9489 		dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
9490 	}
9491 }
9492 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
9493 
9494 #ifdef DHD_PKT_LOGGING
9495 static int
wl_android_pktlog_filter_enable(struct net_device * dev,char * command,int total_len)9496 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
9497 {
9498 	int bytes_written = 0;
9499 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9500 	dhd_pktlog_filter_t *filter;
9501 	int err = BCME_OK;
9502 
9503 	if (!dhdp || !dhdp->pktlog) {
9504 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9505 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9506 		return -EINVAL;
9507 	}
9508 
9509 	filter = dhdp->pktlog->pktlog_filter;
9510 
9511 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
9512 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
9513 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
9514 
9515 	if (err == BCME_OK) {
9516 		bytes_written = snprintf(command, total_len, "OK");
9517 		ANDROID_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
9518 	} else {
9519 		ANDROID_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
9520 		return BCME_ERROR;
9521 	}
9522 
9523 	return bytes_written;
9524 }
9525 
9526 static int
wl_android_pktlog_filter_disable(struct net_device * dev,char * command,int total_len)9527 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
9528 {
9529 	int bytes_written = 0;
9530 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9531 	dhd_pktlog_filter_t *filter;
9532 	int err = BCME_OK;
9533 
9534 	if (!dhdp || !dhdp->pktlog) {
9535 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9536 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9537 		return -EINVAL;
9538 	}
9539 
9540 	filter = dhdp->pktlog->pktlog_filter;
9541 
9542 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
9543 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
9544 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
9545 
9546 	if (err == BCME_OK) {
9547 		bytes_written = snprintf(command, total_len, "OK");
9548 		ANDROID_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
9549 	} else {
9550 		ANDROID_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
9551 		return BCME_ERROR;
9552 	}
9553 
9554 	return bytes_written;
9555 }
9556 
9557 static int
wl_android_pktlog_filter_pattern_enable(struct net_device * dev,char * command,int total_len)9558 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
9559 {
9560 	int bytes_written = 0;
9561 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9562 	dhd_pktlog_filter_t *filter;
9563 	int err = BCME_OK;
9564 
9565 	if (!dhdp || !dhdp->pktlog) {
9566 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9567 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9568 		return -EINVAL;
9569 	}
9570 
9571 	filter = dhdp->pktlog->pktlog_filter;
9572 
9573 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
9574 		return BCME_ERROR;
9575 	}
9576 
9577 	err = dhd_pktlog_filter_pattern_enable(filter,
9578 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
9579 
9580 	if (err == BCME_OK) {
9581 		bytes_written = snprintf(command, total_len, "OK");
9582 		ANDROID_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
9583 	} else {
9584 		ANDROID_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
9585 		return BCME_ERROR;
9586 	}
9587 
9588 	return bytes_written;
9589 }
9590 
9591 static int
wl_android_pktlog_filter_pattern_disable(struct net_device * dev,char * command,int total_len)9592 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
9593 {
9594 	int bytes_written = 0;
9595 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9596 	dhd_pktlog_filter_t *filter;
9597 	int err = BCME_OK;
9598 
9599 	if (!dhdp || !dhdp->pktlog) {
9600 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9601 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9602 		return -EINVAL;
9603 	}
9604 
9605 	filter = dhdp->pktlog->pktlog_filter;
9606 
9607 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
9608 		return BCME_ERROR;
9609 	}
9610 
9611 	err = dhd_pktlog_filter_pattern_enable(filter,
9612 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
9613 
9614 	if (err == BCME_OK) {
9615 		bytes_written = snprintf(command, total_len, "OK");
9616 		ANDROID_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
9617 	} else {
9618 		ANDROID_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
9619 		return BCME_ERROR;
9620 	}
9621 
9622 	return bytes_written;
9623 }
9624 
9625 static int
wl_android_pktlog_filter_add(struct net_device * dev,char * command,int total_len)9626 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
9627 {
9628 	int bytes_written = 0;
9629 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9630 	dhd_pktlog_filter_t *filter;
9631 	int err = BCME_OK;
9632 
9633 	if (!dhdp || !dhdp->pktlog) {
9634 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9635 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9636 		return -EINVAL;
9637 	}
9638 
9639 	filter = dhdp->pktlog->pktlog_filter;
9640 
9641 	if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
9642 		return BCME_ERROR;
9643 	}
9644 
9645 	err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
9646 
9647 	if (err == BCME_OK) {
9648 		bytes_written = snprintf(command, total_len, "OK");
9649 		ANDROID_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
9650 	} else {
9651 		ANDROID_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
9652 		return BCME_ERROR;
9653 	}
9654 
9655 	return bytes_written;
9656 }
9657 
9658 static int
wl_android_pktlog_filter_del(struct net_device * dev,char * command,int total_len)9659 wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_len)
9660 {
9661 	int bytes_written = 0;
9662 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9663 	dhd_pktlog_filter_t *filter;
9664 	int err = BCME_OK;
9665 
9666 	if (!dhdp || !dhdp->pktlog) {
9667 		ANDROID_ERROR(("%s(): dhdp=%p pktlog=%p\n",
9668 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9669 		return -EINVAL;
9670 	}
9671 
9672 	filter = dhdp->pktlog->pktlog_filter;
9673 
9674 	if (strlen(CMD_PKTLOG_FILTER_DEL) + 1 > total_len) {
9675 		DHD_PKT_LOG(("%s(): wrong cmd length %d found\n",
9676 			__FUNCTION__, (int)strlen(CMD_PKTLOG_FILTER_DEL)));
9677 		return BCME_ERROR;
9678 	}
9679 
9680 	err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1);
9681 	if (err == BCME_OK) {
9682 		bytes_written = snprintf(command, total_len, "OK");
9683 		ANDROID_ERROR(("%s: pktlog filter del success\n", __FUNCTION__));
9684 	} else {
9685 		ANDROID_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__));
9686 		return BCME_ERROR;
9687 	}
9688 
9689 	return bytes_written;
9690 }
9691 
9692 static int
wl_android_pktlog_filter_info(struct net_device * dev,char * command,int total_len)9693 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
9694 {
9695 	int bytes_written = 0;
9696 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9697 	dhd_pktlog_filter_t *filter;
9698 	int err = BCME_OK;
9699 
9700 	if (!dhdp || !dhdp->pktlog) {
9701 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9702 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9703 		return -EINVAL;
9704 	}
9705 
9706 	filter = dhdp->pktlog->pktlog_filter;
9707 
9708 	err = dhd_pktlog_filter_info(filter);
9709 
9710 	if (err == BCME_OK) {
9711 		bytes_written = snprintf(command, total_len, "OK");
9712 		ANDROID_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
9713 	} else {
9714 		ANDROID_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
9715 		return BCME_ERROR;
9716 	}
9717 
9718 	return bytes_written;
9719 }
9720 
9721 static int
wl_android_pktlog_start(struct net_device * dev,char * command,int total_len)9722 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
9723 {
9724 	int bytes_written = 0;
9725 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9726 
9727 	if (!dhdp || !dhdp->pktlog) {
9728 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9729 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9730 		return -EINVAL;
9731 	}
9732 
9733 	if (!dhdp->pktlog->pktlog_ring) {
9734 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9735 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9736 		return -EINVAL;
9737 	}
9738 
9739 	atomic_set(&dhdp->pktlog->pktlog_ring->start, TRUE);
9740 
9741 	bytes_written = snprintf(command, total_len, "OK");
9742 
9743 	ANDROID_ERROR(("%s: pktlog start success\n", __FUNCTION__));
9744 
9745 	return bytes_written;
9746 }
9747 
9748 static int
wl_android_pktlog_stop(struct net_device * dev,char * command,int total_len)9749 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
9750 {
9751 	int bytes_written = 0;
9752 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9753 
9754 	if (!dhdp || !dhdp->pktlog) {
9755 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9756 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9757 		return -EINVAL;
9758 	}
9759 
9760 	if (!dhdp->pktlog->pktlog_ring) {
9761 		DHD_PKT_LOG(("%s(): _pktlog_ring=%p\n",
9762 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9763 		return -EINVAL;
9764 	}
9765 
9766 	atomic_set(&dhdp->pktlog->pktlog_ring->start, FALSE);
9767 
9768 	bytes_written = snprintf(command, total_len, "OK");
9769 
9770 	ANDROID_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
9771 
9772 	return bytes_written;
9773 }
9774 
9775 static int
wl_android_pktlog_filter_exist(struct net_device * dev,char * command,int total_len)9776 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
9777 {
9778 	int bytes_written = 0;
9779 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9780 	dhd_pktlog_filter_t *filter;
9781 	uint32 id;
9782 	bool exist = FALSE;
9783 
9784 	if (!dhdp || !dhdp->pktlog) {
9785 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9786 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9787 		return -EINVAL;
9788 	}
9789 
9790 	filter = dhdp->pktlog->pktlog_filter;
9791 
9792 	if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
9793 		return BCME_ERROR;
9794 	}
9795 
9796 	exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
9797 			&id);
9798 
9799 	if (exist) {
9800 		bytes_written = snprintf(command, total_len, "TRUE");
9801 		ANDROID_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
9802 	} else {
9803 		bytes_written = snprintf(command, total_len, "FALSE");
9804 		ANDROID_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
9805 	}
9806 
9807 	return bytes_written;
9808 }
9809 
9810 static int
wl_android_pktlog_minmize_enable(struct net_device * dev,char * command,int total_len)9811 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
9812 {
9813 	int bytes_written = 0;
9814 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9815 
9816 	if (!dhdp || !dhdp->pktlog) {
9817 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9818 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9819 		return -EINVAL;
9820 	}
9821 
9822 	if (!dhdp->pktlog->pktlog_ring) {
9823 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9824 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9825 		return -EINVAL;
9826 	}
9827 
9828 	dhdp->pktlog->pktlog_ring->pktlog_minmize = TRUE;
9829 
9830 	bytes_written = snprintf(command, total_len, "OK");
9831 
9832 	ANDROID_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
9833 
9834 	return bytes_written;
9835 }
9836 
9837 static int
wl_android_pktlog_minmize_disable(struct net_device * dev,char * command,int total_len)9838 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
9839 {
9840 	int bytes_written = 0;
9841 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9842 
9843 	if (!dhdp || !dhdp->pktlog) {
9844 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9845 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9846 		return -EINVAL;
9847 	}
9848 
9849 	if (!dhdp->pktlog->pktlog_ring) {
9850 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9851 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9852 		return -EINVAL;
9853 	}
9854 
9855 	dhdp->pktlog->pktlog_ring->pktlog_minmize = FALSE;
9856 
9857 	bytes_written = snprintf(command, total_len, "OK");
9858 
9859 	ANDROID_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
9860 
9861 	return bytes_written;
9862 }
9863 
9864 static int
wl_android_pktlog_change_size(struct net_device * dev,char * command,int total_len)9865 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
9866 {
9867 	int bytes_written = 0;
9868 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9869 	int err = BCME_OK;
9870 	int size;
9871 
9872 	if (!dhdp || !dhdp->pktlog) {
9873 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9874 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9875 		return -EINVAL;
9876 	}
9877 
9878 	if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
9879 		return BCME_ERROR;
9880 	}
9881 
9882 	size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
9883 
9884 	dhdp->pktlog->pktlog_ring =
9885 		dhd_pktlog_ring_change_size(dhdp->pktlog->pktlog_ring, size);
9886 	if (!dhdp->pktlog->pktlog_ring) {
9887 		err = BCME_ERROR;
9888 	}
9889 
9890 	if (err == BCME_OK) {
9891 		bytes_written = snprintf(command, total_len, "OK");
9892 		ANDROID_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
9893 	} else {
9894 		ANDROID_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
9895 		return BCME_ERROR;
9896 	}
9897 
9898 	return bytes_written;
9899 }
9900 
9901 static int
wl_android_pktlog_dbg_dump(struct net_device * dev,char * command,int total_len)9902 wl_android_pktlog_dbg_dump(struct net_device *dev, char *command, int total_len)
9903 {
9904 	int bytes_written = 0;
9905 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9906 	int err = BCME_OK;
9907 
9908 	if (!dhdp || !dhdp->pktlog) {
9909 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9910 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9911 		return -EINVAL;
9912 	}
9913 
9914 	if (strlen(CMD_PKTLOG_DEBUG_DUMP) + 1 > total_len) {
9915 		return BCME_ERROR;
9916 	}
9917 
9918 	err = dhd_pktlog_debug_dump(dhdp);
9919 	if (err == BCME_OK) {
9920 		bytes_written = snprintf(command, total_len, "OK");
9921 		ANDROID_INFO(("%s: pktlog dbg dump success\n", __FUNCTION__));
9922 	} else {
9923 		ANDROID_ERROR(("%s: pktlog dbg dump fail\n", __FUNCTION__));
9924 		return BCME_ERROR;
9925 	}
9926 
9927 	return bytes_written;
9928 }
9929 #endif /* DHD_PKT_LOGGING */
9930 
9931 #if defined(CONFIG_TIZEN)
wl_android_set_powersave_mode(struct net_device * dev,char * command,int total_len)9932 static int wl_android_set_powersave_mode(
9933 	struct net_device *dev, char* command, int total_len)
9934 {
9935 	int pm;
9936 
9937 	int err = BCME_OK;
9938 #ifdef DHD_PM_OVERRIDE
9939 	extern bool g_pm_override;
9940 #endif /* DHD_PM_OVERRIDE */
9941 	sscanf(command, "%*s %10d", &pm);
9942 	if (pm < PM_OFF || pm > PM_FAST) {
9943 		ANDROID_ERROR(("check pm=%d\n", pm));
9944 		return BCME_ERROR;
9945 	}
9946 
9947 #ifdef DHD_PM_OVERRIDE
9948 	if (pm > PM_OFF) {
9949 		g_pm_override = FALSE;
9950 	}
9951 #endif /* DHD_PM_OVERRIDE */
9952 
9953 	err =  wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
9954 
9955 #ifdef DHD_PM_OVERRIDE
9956 	if (pm == PM_OFF) {
9957 		g_pm_override = TRUE;
9958 	}
9959 
9960 	ANDROID_ERROR(("%s: PM:%d, pm_override=%d\n", __FUNCTION__, pm, g_pm_override));
9961 #endif /* DHD_PM_OVERRIDE */
9962 	return err;
9963 }
9964 
wl_android_get_powersave_mode(struct net_device * dev,char * command,int total_len)9965 static int wl_android_get_powersave_mode(
9966 	struct net_device *dev, char *command, int total_len)
9967 {
9968 	int err, bytes_written;
9969 	int pm;
9970 
9971 	err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
9972 	if (err != BCME_OK) {
9973 		ANDROID_ERROR(("failed to get pm (%d)", err));
9974 		return err;
9975 	}
9976 
9977 	bytes_written = snprintf(command, total_len, "%s %d",
9978 		CMD_POWERSAVEMODE_GET, pm);
9979 
9980 	return bytes_written;
9981 }
9982 #endif /* CONFIG_TIZEN */
9983 
9984 #ifdef DHD_EVENT_LOG_FILTER
9985 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
9986 
9987 #ifdef DHD_EWPR_VER2
9988 uint32 dhd_event_log_filter_serialize_bit(dhd_pub_t *dhdp, char *buf, uint32 tot_len,
9989 	int index1, int index2, int index3);
9990 #endif
9991 
9992 static int
wl_android_ewp_filter(struct net_device * dev,char * command,uint32 tot_len)9993 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
9994 {
9995 	uint32 bytes_written = 0;
9996 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9997 #ifdef DHD_EWPR_VER2
9998 	int index1 = 0, index2 = 0, index3 = 0;
9999 	unsigned char *index_str = (unsigned char *)(command +
10000 		strlen(CMD_EWP_FILTER) + 1);
10001 #else
10002 	int type = 0;
10003 #endif
10004 
10005 	if (!dhdp || !command) {
10006 		ANDROID_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
10007 		return -EINVAL;
10008 	}
10009 
10010 	if (!FW_SUPPORTED(dhdp, ecounters)) {
10011 		ANDROID_ERROR(("does not support ecounters!\n"));
10012 		return BCME_UNSUPPORTED;
10013 	}
10014 
10015 #ifdef DHD_EWPR_VER2
10016 	if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) {
10017 		sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3);
10018 		ANDROID_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__,
10019 			index1, index2, index3));
10020 	}
10021 	bytes_written += dhd_event_log_filter_serialize_bit(dhdp,
10022 		&command[bytes_written], tot_len - bytes_written, index1, index2, index3);
10023 #else
10024 	/* NEED TO GET TYPE if EXIST */
10025 	type = 0;
10026 
10027 	bytes_written += dhd_event_log_filter_serialize(dhdp,
10028 		&command[bytes_written], tot_len - bytes_written, type);
10029 #endif
10030 
10031 	return (int)bytes_written;
10032 }
10033 #endif /* DHD_EVENT_LOG_FILTER */
10034 
10035 #ifdef SUPPORT_AP_SUSPEND
10036 int
wl_android_set_ap_suspend(struct net_device * dev,char * command,int total_len)10037 wl_android_set_ap_suspend(struct net_device *dev, char *command, int total_len)
10038 {
10039 	int suspend = 0;
10040 	char *pos, *token;
10041 	char *ifname = NULL;
10042 	int err = BCME_OK;
10043 	char name[IFNAMSIZ];
10044 
10045 	/*
10046 	 * DRIVER SET_AP_SUSPEND <0/1> <ifname>
10047 	 */
10048 	pos = command;
10049 
10050 	/* drop command */
10051 	token = bcmstrtok(&pos, " ", NULL);
10052 
10053 	/* Enable */
10054 	token = bcmstrtok(&pos, " ", NULL);
10055 	if (!token) {
10056 		return -EINVAL;
10057 	}
10058 	suspend = bcm_atoi(token);
10059 
10060 	/* get the interface name */
10061 	token = bcmstrtok(&pos, " ", NULL);
10062 	if (!token) {
10063 		return -EINVAL;
10064 	}
10065 	ifname = token;
10066 
10067 	strlcpy(name, ifname, sizeof(name));
10068 	ANDROID_INFO(("suspend %d, ifacename %s\n", suspend, name));
10069 
10070 	err = wl_set_ap_suspend(dev, suspend? TRUE: FALSE, name);
10071 	if (unlikely(err)) {
10072 		ANDROID_ERROR(("Failed to set suspend, suspend %d, error = %d\n", suspend, err));
10073 	}
10074 
10075 	return err;
10076 }
10077 #endif /* SUPPORT_AP_SUSPEND */
10078 
10079 #ifdef SUPPORT_AP_BWCTRL
10080 int
wl_android_set_ap_bw(struct net_device * dev,char * command,int total_len)10081 wl_android_set_ap_bw(struct net_device *dev, char *command, int total_len)
10082 {
10083 	int bw = DOT11_OPER_MODE_20MHZ;
10084 	char *pos, *token;
10085 	char *ifname = NULL;
10086 	int err = BCME_OK;
10087 	char name[IFNAMSIZ];
10088 
10089 	/*
10090 	 * DRIVER SET_AP_BW <0/1/2> <ifname>
10091 	 * 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10092 	 * This is from operating mode field
10093 	 * in 8.4.1.50 of 802.11ac-2013
10094 	 */
10095 	pos = command;
10096 
10097 	/* drop command */
10098 	token = bcmstrtok(&pos, " ", NULL);
10099 
10100 	/* BW */
10101 	token = bcmstrtok(&pos, " ", NULL);
10102 	if (!token) {
10103 		return -EINVAL;
10104 	}
10105 	bw = bcm_atoi(token);
10106 
10107 	/* get the interface name */
10108 	token = bcmstrtok(&pos, " ", NULL);
10109 	if (!token) {
10110 		return -EINVAL;
10111 	}
10112 	ifname = token;
10113 
10114 	strlcpy(name, ifname, sizeof(name));
10115 	ANDROID_INFO(("bw %d, ifacename %s\n", bw, name));
10116 
10117 	err = wl_set_ap_bw(dev, bw, name);
10118 	if (unlikely(err)) {
10119 		ANDROID_ERROR(("Failed to set bw, bw %d, error = %d\n", bw, err));
10120 	}
10121 
10122 	return err;
10123 }
10124 
10125 int
wl_android_get_ap_bw(struct net_device * dev,char * command,int total_len)10126 wl_android_get_ap_bw(struct net_device *dev, char *command, int total_len)
10127 {
10128 	char *pos, *token;
10129 	char *ifname = NULL;
10130 	int bytes_written = 0;
10131 	char name[IFNAMSIZ];
10132 
10133 	/*
10134 	 * DRIVER GET_AP_BW <ifname>
10135 	 * returns 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10136 	 * This is from operating mode field
10137 	 * in 8.4.1.50 of 802.11ac-2013
10138 	 */
10139 	pos = command;
10140 
10141 	/* drop command */
10142 	token = bcmstrtok(&pos, " ", NULL);
10143 
10144 	/* get the interface name */
10145 	token = bcmstrtok(&pos, " ", NULL);
10146 	if (!token) {
10147 		return -EINVAL;
10148 	}
10149 	ifname = token;
10150 
10151 	strlcpy(name, ifname, sizeof(name));
10152 	ANDROID_INFO(("ifacename %s\n", name));
10153 
10154 	bytes_written = wl_get_ap_bw(dev, command, name, total_len);
10155 	if (bytes_written < 1) {
10156 		ANDROID_ERROR(("Failed to get bw, error = %d\n", bytes_written));
10157 		return -EPROTO;
10158 	}
10159 
10160 	return bytes_written;
10161 
10162 }
10163 #endif /* SUPPORT_AP_BWCTRL */
10164 
10165 static int
wl_android_priv_cmd_log_enable_check(char * cmd)10166 wl_android_priv_cmd_log_enable_check(char* cmd)
10167 {
10168 	int cnt = 0;
10169 
10170 	while (strlen(loging_params[cnt].command) > 0) {
10171 		if (!strnicmp(cmd, loging_params[cnt].command,
10172 			strlen(loging_params[cnt].command))) {
10173 			return loging_params[cnt].enable;
10174 		}
10175 
10176 		cnt++;
10177 	}
10178 
10179 	return FALSE;
10180 }
10181 
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr)10182 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
10183 {
10184 #define PRIVATE_COMMAND_MAX_LEN	8192
10185 #define PRIVATE_COMMAND_DEF_LEN	4096
10186 	int ret = 0;
10187 	char *command = NULL;
10188 	int bytes_written = 0;
10189 	android_wifi_priv_cmd priv_cmd;
10190 	int buf_size = 0;
10191 	dhd_pub_t *dhd = dhd_get_pub(net);
10192 
10193 	net_os_wake_lock(net);
10194 
10195 	if (!capable(CAP_NET_ADMIN)) {
10196 		ret = -EPERM;
10197 		goto exit;
10198 	}
10199 
10200 	if (!ifr->ifr_data) {
10201 		ret = -EINVAL;
10202 		goto exit;
10203 	}
10204 
10205 #ifdef CONFIG_COMPAT
10206 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
10207 	if (in_compat_syscall())
10208 #else
10209 	if (is_compat_task())
10210 #endif
10211 	{
10212 		compat_android_wifi_priv_cmd compat_priv_cmd;
10213 		if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
10214 			sizeof(compat_android_wifi_priv_cmd))) {
10215 			ret = -EFAULT;
10216 			goto exit;
10217 
10218 		}
10219 		priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
10220 		priv_cmd.used_len = compat_priv_cmd.used_len;
10221 		priv_cmd.total_len = compat_priv_cmd.total_len;
10222 	} else
10223 #endif /* CONFIG_COMPAT */
10224 	{
10225 		if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
10226 			ret = -EFAULT;
10227 			goto exit;
10228 		}
10229 	}
10230 	if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
10231 		ANDROID_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
10232 			priv_cmd.total_len));
10233 		ret = -EINVAL;
10234 		goto exit;
10235 	}
10236 
10237 	buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
10238 	command = (char *)MALLOC(dhd->osh, (buf_size + 1));
10239 	if (!command) {
10240 		ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
10241 		ret = -ENOMEM;
10242 		goto exit;
10243 	}
10244 	if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
10245 		ret = -EFAULT;
10246 		goto exit;
10247 	}
10248 	command[priv_cmd.total_len] = '\0';
10249 
10250 	if (wl_android_priv_cmd_log_enable_check(command)) {
10251 		ANDROID_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__,
10252 			command, ifr->ifr_name));
10253 	}
10254 	else {
10255 		ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
10256 
10257 	}
10258 
10259 	bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
10260 	if (bytes_written >= 0) {
10261 		if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
10262 			command[0] = '\0';
10263 		}
10264 		if (bytes_written >= priv_cmd.total_len) {
10265 			ANDROID_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
10266 				__FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
10267 
10268 			ret = BCME_BUFTOOSHORT;
10269 			goto exit;
10270 		}
10271 		bytes_written++;
10272 		priv_cmd.used_len = bytes_written;
10273 		if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
10274 			ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
10275 			ret = -EFAULT;
10276 		}
10277 	}
10278 	else {
10279 		/* Propagate the error */
10280 		ret = bytes_written;
10281 	}
10282 
10283 exit:
10284 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
10285 	if (ret) {
10286 		/* Avoid incrementing priv_cmd_errors in case of unsupported feature
10287 		* or BUSY state specific to TWT commands
10288 		*/
10289 		if (
10290 #ifdef WL_TWT
10291 			((ret != BCME_BUSY) &&
10292 			((strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) ||
10293 			(strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) ||
10294 			(strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0))) ||
10295 #endif /* WL_TWT */
10296 			(ret != BCME_UNSUPPORTED)) {
10297 			wl_android_check_priv_cmd_errors(net);
10298 		}
10299 	} else {
10300 		priv_cmd_errors = 0;
10301 	}
10302 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
10303 	net_os_wake_unlock(net);
10304 	MFREE(dhd->osh, command, (buf_size + 1));
10305 	return ret;
10306 }
10307 
10308 #ifdef WLADPS_PRIVATE_CMD
10309 static int
wl_android_set_adps_mode(struct net_device * dev,const char * string_num)10310 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
10311 {
10312 	int err = 0, adps_mode;
10313 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10314 #ifdef DHD_PM_CONTROL_FROM_FILE
10315 	if (g_pm_control) {
10316 		return -EPERM;
10317 	}
10318 #endif	/* DHD_PM_CONTROL_FROM_FILE */
10319 
10320 	adps_mode = bcm_atoi(string_num);
10321 	ANDROID_ERROR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
10322 
10323 	if (!(adps_mode == 0 || adps_mode == 1)) {
10324 		ANDROID_ERROR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode));
10325 		return -EINVAL;
10326 	}
10327 
10328 	err = dhd_enable_adps(dhdp, adps_mode);
10329 	if (err != BCME_OK) {
10330 		ANDROID_ERROR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
10331 		return -EIO;
10332 	}
10333 	return err;
10334 }
10335 static int
wl_android_get_adps_mode(struct net_device * dev,char * command,int total_len)10336 wl_android_get_adps_mode(
10337 	struct net_device *dev, char *command, int total_len)
10338 {
10339 	int bytes_written, err = 0;
10340 	uint len;
10341 	char buf[WLC_IOCTL_SMLEN];
10342 
10343 	bcm_iov_buf_t iov_buf;
10344 	bcm_iov_buf_t *ptr = NULL;
10345 	wl_adps_params_v1_t *data = NULL;
10346 
10347 	uint8 *pdata = NULL;
10348 	uint8 band, mode = 0;
10349 
10350 	bzero(&iov_buf, sizeof(iov_buf));
10351 
10352 	len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
10353 
10354 	iov_buf.version = WL_ADPS_IOV_VER;
10355 	iov_buf.len = sizeof(band);
10356 	iov_buf.id = WL_ADPS_IOV_MODE;
10357 
10358 	pdata = (uint8 *)&iov_buf.data;
10359 
10360 	for (band = 1; band <= MAX_BANDS; band++) {
10361 		pdata[0] = band;
10362 		err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
10363 			buf, WLC_IOCTL_SMLEN, NULL);
10364 		if (err != BCME_OK) {
10365 			ANDROID_ERROR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n",
10366 					band, err));
10367 			return -EIO;
10368 		}
10369 		ptr = (bcm_iov_buf_t *) buf;
10370 		data = (wl_adps_params_v1_t *) ptr->data;
10371 		mode = data->mode;
10372 		if (mode != OFF) {
10373 			break;
10374 		}
10375 	}
10376 
10377 	bytes_written = snprintf(command, total_len, "%s %d",
10378 		CMD_GET_ADPS, mode);
10379 	return bytes_written;
10380 }
10381 
10382 #ifdef WLADPS_ENERGY_GAIN
10383 static int
wl_android_get_gain_adps(struct net_device * dev,char * command,int total_len)10384 wl_android_get_gain_adps(
10385 	struct net_device *dev, char *command, int total_len)
10386 {
10387 	int bytes_written;
10388 
10389 	int ret = 0;
10390 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10391 
10392 	ret = dhd_event_log_filter_adps_energy_gain(dhdp);
10393 	if (ret < 0) {
10394 		return ret;
10395 	}
10396 
10397 	ANDROID_INFO(("%s ADPS Energy Gain: %d uAh\n", __FUNCTION__, ret));
10398 
10399 	bytes_written = snprintf(command, total_len, "%s %d uAm",
10400 		CMD_GET_GAIN_ADPS, ret);
10401 
10402 	return bytes_written;
10403 }
10404 
10405 static int
wl_android_reset_gain_adps(struct net_device * dev,char * command)10406 wl_android_reset_gain_adps(
10407 	struct net_device *dev, char *command)
10408 {
10409 	int ret = BCME_OK;
10410 
10411 	bcm_iov_buf_t iov_buf;
10412 	char buf[WLC_IOCTL_SMLEN] = {0, };
10413 
10414 	iov_buf.version = WL_ADPS_IOV_VER;
10415 	iov_buf.id = WL_ADPS_IOV_RESET_GAIN;
10416 	iov_buf.len = 0;
10417 
10418 	if ((ret = wldev_iovar_setbuf(dev, "adps", &iov_buf, sizeof(iov_buf),
10419 		buf, sizeof(buf), NULL)) < 0) {
10420 		ANDROID_ERROR(("%s fail to reset adps gain (%d)\n", __FUNCTION__, ret));
10421 	}
10422 
10423 	return ret;
10424 }
10425 #endif	/* WLADPS_ENERGY_GAIN */
10426 #endif /* WLADPS_PRIVATE_CMD */
10427 
10428 #ifdef WL_BCNRECV
10429 #define BCNRECV_ATTR_HDR_LEN 30
10430 int
wl_android_bcnrecv_event(struct net_device * ndev,uint attr_type,uint status,uint reason,uint8 * data,uint data_len)10431 wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
10432 		uint status, uint reason, uint8 *data, uint data_len)
10433 {
10434 	s32 err = BCME_OK;
10435 	struct sk_buff *skb;
10436 	gfp_t kflags;
10437 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10438 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10439 	uint len;
10440 
10441 	len = BCNRECV_ATTR_HDR_LEN + data_len;
10442 
10443 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10444 	skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
10445 		BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
10446 	if (!skb) {
10447 		ANDROID_ERROR(("skb alloc failed"));
10448 		return -ENOMEM;
10449 	}
10450 	if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
10451 		/* send bcn info to upper layer */
10452 		nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
10453 	} else if (attr_type == BCNRECV_ATTR_STATUS) {
10454 		nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
10455 		if (reason) {
10456 			nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
10457 		}
10458 	} else {
10459 		ANDROID_ERROR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
10460 		kfree_skb(skb);
10461 		return -EINVAL;
10462 	}
10463 	cfg80211_vendor_event(skb, kflags);
10464 	return err;
10465 }
10466 
10467 static int
_wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool user_trigger)10468 _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
10469 {
10470 	s32 err = BCME_OK;
10471 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10472 
10473 	/* check any scan is in progress before beacon recv scan trigger IOVAR */
10474 	if (wl_get_drv_status_all(cfg, SCANNING)) {
10475 		err = BCME_UNSUPPORTED;
10476 		ANDROID_ERROR(("Scan in progress, Aborting beacon recv start, "
10477 			"error:%d\n", err));
10478 		goto exit;
10479 	}
10480 
10481 	if (wl_get_p2p_status(cfg, SCANNING)) {
10482 		err = BCME_UNSUPPORTED;
10483 		ANDROID_ERROR(("P2P Scan in progress, Aborting beacon recv start, "
10484 			"error:%d\n", err));
10485 		goto exit;
10486 	}
10487 
10488 	if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
10489 		err = BCME_UNSUPPORTED;
10490 		ANDROID_ERROR(("P2P remain on channel, Aborting beacon recv start, "
10491 			"error:%d\n", err));
10492 		goto exit;
10493 	}
10494 
10495 	/* check STA is in connected state, Beacon recv required connected state
10496 	 * else exit from beacon recv scan
10497 	 */
10498 	if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
10499 		err = BCME_UNSUPPORTED;
10500 		ANDROID_ERROR(("STA is in not associated state error:%d\n", err));
10501 		goto exit;
10502 	}
10503 
10504 #ifdef WL_NAN
10505 	/* Check NAN is enabled, if enabled exit else continue */
10506 	if (wl_cfgnan_is_enabled(cfg)) {
10507 		err = BCME_UNSUPPORTED;
10508 		ANDROID_ERROR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
10509 		goto exit;
10510 	}
10511 #endif /* WL_NAN */
10512 
10513 	/* Triggering an sendup_bcn iovar */
10514 	err = wldev_iovar_setint(pdev, "sendup_bcn", 1);
10515 	if (unlikely(err)) {
10516 		ANDROID_ERROR(("sendup_bcn failed to set, error:%d\n", err));
10517 	} else {
10518 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
10519 		ANDROID_INFO(("bcnrecv started. user_trigger:%d ifindex:%d\n",
10520 			user_trigger, ndev->ifindex));
10521 		if (user_trigger) {
10522 			if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS,
10523 					WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
10524 				ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10525 			}
10526 		}
10527 	}
10528 exit:
10529 	/*
10530 	 * BCNRECV start request can be rejected from dongle
10531 	 * in various conditions.
10532 	 * Error code need to be overridden to BCME_UNSUPPORTED
10533 	 * to avoid hang event from continous private
10534 	 * command error
10535 	 */
10536 	if (err) {
10537 		err = BCME_UNSUPPORTED;
10538 	}
10539 	return err;
10540 }
10541 
10542 int
_wl_android_bcnrecv_stop(struct bcm_cfg80211 * cfg,struct net_device * ndev,uint reason)10543 _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
10544 {
10545 	s32 err = BCME_OK;
10546 	u32 status;
10547 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10548 
10549 	/* Stop bcnrx except for fw abort event case */
10550 	if (reason != WL_BCNRECV_ROAMABORT) {
10551 		err = wldev_iovar_setint(pdev, "sendup_bcn", 0);
10552 		if (unlikely(err)) {
10553 			ANDROID_ERROR(("sendup_bcn failed to set error:%d\n", err));
10554 			goto exit;
10555 		}
10556 	}
10557 
10558 	/* Send notification for all cases */
10559 	if (reason == WL_BCNRECV_SUSPEND) {
10560 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
10561 		status = WL_BCNRECV_SUSPENDED;
10562 	} else {
10563 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
10564 		ANDROID_INFO(("bcnrecv stopped. reason:%d ifindex:%d\n",
10565 			reason, ndev->ifindex));
10566 		if (reason == WL_BCNRECV_USER_TRIGGER) {
10567 			status = WL_BCNRECV_STOPPED;
10568 		} else {
10569 			status = WL_BCNRECV_ABORTED;
10570 		}
10571 	}
10572 	if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, status,
10573 			reason, NULL, 0)) != BCME_OK) {
10574 		ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10575 	}
10576 exit:
10577 	return err;
10578 }
10579 
10580 static int
wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev)10581 wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
10582 {
10583 	s32 err = BCME_OK;
10584 
10585 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10586 	mutex_lock(&cfg->scan_sync);
10587 	mutex_lock(&cfg->bcn_sync);
10588 	err = _wl_android_bcnrecv_start(cfg, ndev, true);
10589 	mutex_unlock(&cfg->bcn_sync);
10590 	mutex_unlock(&cfg->scan_sync);
10591 	return err;
10592 }
10593 
10594 int
wl_android_bcnrecv_stop(struct net_device * ndev,uint reason)10595 wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
10596 {
10597 	s32 err = BCME_OK;
10598 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10599 
10600 	mutex_lock(&cfg->bcn_sync);
10601 	if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
10602 	   (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
10603 		err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
10604 	}
10605 	mutex_unlock(&cfg->bcn_sync);
10606 	return err;
10607 }
10608 
10609 int
wl_android_bcnrecv_suspend(struct net_device * ndev)10610 wl_android_bcnrecv_suspend(struct net_device *ndev)
10611 {
10612 	s32 ret = BCME_OK;
10613 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10614 
10615 	mutex_lock(&cfg->bcn_sync);
10616 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
10617 		ANDROID_INFO(("bcnrecv suspend\n"));
10618 		ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
10619 	}
10620 	mutex_unlock(&cfg->bcn_sync);
10621 	return ret;
10622 }
10623 
10624 int
wl_android_bcnrecv_resume(struct net_device * ndev)10625 wl_android_bcnrecv_resume(struct net_device *ndev)
10626 {
10627 	s32 ret = BCME_OK;
10628 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10629 
10630 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10631 	mutex_lock(&cfg->scan_sync);
10632 	mutex_lock(&cfg->bcn_sync);
10633 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
10634 		ANDROID_INFO(("bcnrecv resume\n"));
10635 		ret = _wl_android_bcnrecv_start(cfg, ndev, false);
10636 	}
10637 	mutex_unlock(&cfg->bcn_sync);
10638 	mutex_unlock(&cfg->scan_sync);
10639 	return ret;
10640 }
10641 
10642 /* Beacon recv functionality code implementation */
10643 int
wl_android_bcnrecv_config(struct net_device * ndev,char * cmd_argv,int total_len)10644 wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
10645 {
10646 	struct bcm_cfg80211 *cfg = NULL;
10647 	uint err = BCME_OK;
10648 
10649 	if (!ndev) {
10650 		ANDROID_ERROR(("ndev is NULL\n"));
10651 		return -EINVAL;
10652 	}
10653 
10654 	cfg = wl_get_cfg(ndev);
10655 	if (!cfg) {
10656 		ANDROID_ERROR(("cfg is NULL\n"));
10657 		return -EINVAL;
10658 	}
10659 
10660 	/* sync commands from user space */
10661 	mutex_lock(&cfg->usr_sync);
10662 	if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
10663 		ANDROID_INFO(("BCNRECV start\n"));
10664 		err = wl_android_bcnrecv_start(cfg, ndev);
10665 		if (err != BCME_OK) {
10666 			ANDROID_ERROR(("Failed to process the start command, error:%d\n", err));
10667 			goto exit;
10668 		}
10669 	} else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
10670 		ANDROID_INFO(("BCNRECV stop\n"));
10671 		err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
10672 		if (err != BCME_OK) {
10673 			ANDROID_ERROR(("Failed to stop the bcn recv, error:%d\n", err));
10674 			goto exit;
10675 		}
10676 	} else {
10677 		err = BCME_ERROR;
10678 	}
10679 exit:
10680 	mutex_unlock(&cfg->usr_sync);
10681 	return err;
10682 }
10683 #endif /* WL_BCNRECV */
10684 
10685 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
10686 static int
wl_android_set_latency_crt_data(struct net_device * dev,int mode)10687 wl_android_set_latency_crt_data(struct net_device *dev, int mode)
10688 {
10689 	int ret;
10690 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10691 	dhd_pub_t *dhdp = NULL;
10692 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10693 	if (mode >= LATENCY_CRT_DATA_MODE_LAST) {
10694 		return BCME_BADARG;
10695 	}
10696 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10697 	dhdp = wl_cfg80211_get_dhdp(dev);
10698 	if (mode != LATENCY_CRT_DATA_MODE_OFF) {
10699 		ANDROID_ERROR(("Not permitted GRO by framework\n"));
10700 		dhdp->permitted_gro = FALSE;
10701 	} else {
10702 		ANDROID_ERROR(("Permitted GRO by framework\n"));
10703 		dhdp->permitted_gro = TRUE;
10704 	}
10705 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10706 	ret = wldev_iovar_setint(dev, "latency_critical_data", mode);
10707 	if (ret != BCME_OK) {
10708 		ANDROID_ERROR(("failed to set latency_critical_data mode %d, error = %d\n",
10709 			mode, ret));
10710 		return ret;
10711 	}
10712 
10713 	return ret;
10714 }
10715 
10716 static int
wl_android_get_latency_crt_data(struct net_device * dev,char * command,int total_len)10717 wl_android_get_latency_crt_data(struct net_device *dev, char *command, int total_len)
10718 {
10719 	int ret;
10720 	int mode = LATENCY_CRT_DATA_MODE_OFF;
10721 	int bytes_written;
10722 
10723 	ret = wldev_iovar_getint(dev, "latency_critical_data", &mode);
10724 	if (ret != BCME_OK) {
10725 		ANDROID_ERROR(("failed to get latency_critical_data error = %d\n", ret));
10726 		return ret;
10727 	}
10728 
10729 	bytes_written = snprintf(command, total_len, "%s %d",
10730 		CMD_GET_LATENCY_CRITICAL_DATA, mode);
10731 
10732 	return bytes_written;
10733 }
10734 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
10735 
10736 #ifdef WL_CAC_TS
10737 /* CAC TSPEC functionality code implementation */
10738 static void
wl_android_update_tsinfo(uint8 access_category,tspec_arg_t * tspec_arg)10739 wl_android_update_tsinfo(uint8 access_category, tspec_arg_t *tspec_arg)
10740 {
10741 	uint8 tspec_id;
10742 	/* Using direction as bidirectional by default */
10743 	uint8 direction = TSPEC_BI_DIRECTION;
10744 	/* Using U-APSD as the default power save mode */
10745 	uint8 user_psb = TSPEC_UAPSD_PSB;
10746 	uint8 ADDTS_AC2PRIO[4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI, PRIO_8021D_VO};
10747 
10748 	/* Map tspec_id from access category */
10749 	tspec_id = ADDTS_AC2PRIO[access_category];
10750 
10751 	/* Update the tsinfo */
10752 	tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
10753 		(tspec_id << TSPEC_TSINFO_TID_SHIFT));
10754 	tspec_arg->tsinfo.octets[1] = (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) |
10755 		user_psb);
10756 	tspec_arg->tsinfo.octets[2] = 0x00;
10757 }
10758 
10759 static s32
wl_android_handle_cac_action(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * argv)10760 wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev, char * argv)
10761 {
10762 	tspec_arg_t tspec_arg;
10763 	s32 err = BCME_ERROR;
10764 	u8 ts_cmd[12] = "cac_addts";
10765 	uint8 access_category;
10766 	s32 bssidx;
10767 
10768 	/* Following handling is done only for the primary interface */
10769 	memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
10770 	if (strncmp(argv, "addts", strlen("addts")) == 0) {
10771 		tspec_arg.version = TSPEC_ARG_VERSION;
10772 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10773 		/* Read the params passed */
10774 		sscanf(argv, "%*s %hhu %hu %hu", &access_category,
10775 			&tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
10776 		if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
10777 			((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
10778 			(tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
10779 			(tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
10780 			ANDROID_ERROR(("Invalid params access_category %hhu nom_msdu_size %hu"
10781 				" surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size,
10782 				tspec_arg.surplus_bw));
10783 			return BCME_USAGE_ERROR;
10784 		}
10785 
10786 		/* Update tsinfo */
10787 		wl_android_update_tsinfo(access_category, &tspec_arg);
10788 		/* Update other tspec parameters */
10789 		tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
10790 		tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
10791 		tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
10792 	} else if (strncmp(argv, "delts", strlen("delts")) == 0) {
10793 		snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
10794 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10795 		tspec_arg.version = TSPEC_ARG_VERSION;
10796 		/* Read the params passed */
10797 		sscanf(argv, "%*s %hhu", &access_category);
10798 
10799 		if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
10800 			ANDROID_INFO(("Invalide param, access_category %hhu\n", access_category));
10801 			return BCME_USAGE_ERROR;
10802 		}
10803 		/* Update tsinfo */
10804 		wl_android_update_tsinfo(access_category, &tspec_arg);
10805 	}
10806 
10807 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
10808 		ANDROID_ERROR(("Find index failed\n"));
10809 		err = BCME_ERROR;
10810 		return err;
10811 	}
10812 	err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
10813 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
10814 	if (unlikely(err)) {
10815 		ANDROID_ERROR(("%s error (%d)\n", ts_cmd, err));
10816 	}
10817 
10818 	return err;
10819 }
10820 
10821 static s32
wl_android_cac_ts_config(struct net_device * ndev,char * cmd_argv,int total_len)10822 wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len)
10823 {
10824 	struct bcm_cfg80211 *cfg = NULL;
10825 	s32 err = BCME_OK;
10826 
10827 	if (!ndev) {
10828 		ANDROID_ERROR(("ndev is NULL\n"));
10829 		return -EINVAL;
10830 	}
10831 
10832 	cfg = wl_get_cfg(ndev);
10833 	if (!cfg) {
10834 		ANDROID_ERROR(("cfg is NULL\n"));
10835 		return -EINVAL;
10836 	}
10837 
10838 	/* Request supported only for primary interface */
10839 	if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
10840 		ANDROID_ERROR(("Request on non-primary interface\n"));
10841 		return -1;
10842 	}
10843 
10844 	/* sync commands from user space */
10845 	mutex_lock(&cfg->usr_sync);
10846 	err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
10847 	mutex_unlock(&cfg->usr_sync);
10848 
10849 	return err;
10850 }
10851 #endif /* WL_CAC_TS */
10852 
10853 #ifdef WL_GET_CU
10854 /* Implementation to get channel usage from framework */
10855 static s32
wl_android_get_channel_util(struct net_device * ndev,char * command,int total_len)10856 wl_android_get_channel_util(struct net_device *ndev, char *command, int total_len)
10857 {
10858 	s32 bytes_written, err = 0;
10859 	wl_bssload_t bssload;
10860 	u8 smbuf[WLC_IOCTL_SMLEN];
10861 	u8 chan_use_percentage = 0;
10862 
10863 	if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL,
10864 		0, smbuf, WLC_IOCTL_SMLEN, NULL))) {
10865 		ANDROID_ERROR(("Getting bssload report failed with err=%d \n", err));
10866 		return err;
10867 	}
10868 
10869 	(void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
10870 	/* Convert channel usage to percentage value */
10871 	chan_use_percentage = (bssload.chan_util * 100) / 255;
10872 
10873 	bytes_written = snprintf(command, total_len, "CU %hhu",
10874 		chan_use_percentage);
10875 	ANDROID_INFO(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage));
10876 
10877 	return bytes_written;
10878 }
10879 #endif /* WL_GET_CU */
10880 
10881 #ifdef RTT_GEOFENCE_INTERVAL
10882 #if defined (RTT_SUPPORT) && defined(WL_NAN)
10883 static void
wl_android_set_rtt_geofence_interval(struct net_device * ndev,char * command)10884 wl_android_set_rtt_geofence_interval(struct net_device *ndev, char *command)
10885 {
10886 	int rtt_interval = 0;
10887 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
10888 	char *rtt_intp = command + strlen(CMD_GEOFENCE_INTERVAL) + 1;
10889 
10890 	rtt_interval = bcm_atoi(rtt_intp);
10891 	dhd_rtt_set_geofence_rtt_interval(dhdp, rtt_interval);
10892 }
10893 #endif /* RTT_SUPPORT && WL_NAN */
10894 #endif /* RTT_GEOFENCE_INTERVAL */
10895 
10896 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
10897 int
wl_android_set_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10898 wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10899 {
10900 	char *ifname = NULL;
10901 	char *pos, *token;
10902 	int err = BCME_OK;
10903 	int enable = FALSE;
10904 
10905 	/*
10906 	 * STA/AP/GO I/F: DRIVER SET_SOFTAP_ELNA_BYPASS <ifname> <enable/disable>
10907 	 * the enable/disable format follows Samsung specific rules as following
10908 	 * Enable : 0
10909 	 * Disable :-1
10910 	 */
10911 	pos = command;
10912 
10913 	/* drop command */
10914 	token = bcmstrtok(&pos, " ", NULL);
10915 
10916 	/* get the interface name */
10917 	token = bcmstrtok(&pos, " ", NULL);
10918 	if (!token) {
10919 		ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10920 		return -EINVAL;
10921 	}
10922 	ifname = token;
10923 
10924 	/* get enable/disable flag */
10925 	token = bcmstrtok(&pos, " ", NULL);
10926 	if (!token) {
10927 		ANDROID_ERROR(("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__));
10928 		return -EINVAL;
10929 	}
10930 	enable = bcm_atoi(token);
10931 
10932 	CUSTOMER_HW4_EN_CONVERT(enable);
10933 	err = wl_set_softap_elna_bypass(dev, ifname, enable);
10934 	if (unlikely(err)) {
10935 		ANDROID_ERROR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n",
10936 			__FUNCTION__, err));
10937 		return err;
10938 	}
10939 
10940 	return err;
10941 }
10942 
10943 int
wl_android_get_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10944 wl_android_get_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10945 {
10946 	char *ifname = NULL;
10947 	char *pos, *token;
10948 	int err = BCME_OK;
10949 	int bytes_written = 0;
10950 	int softap_elnabypass = 0;
10951 
10952 	/*
10953 	 * STA/AP/GO I/F: DRIVER GET_SOFTAP_ELNA_BYPASS <ifname>
10954 	 */
10955 	pos = command;
10956 
10957 	/* drop command */
10958 	token = bcmstrtok(&pos, " ", NULL);
10959 
10960 	/* get the interface name */
10961 	token = bcmstrtok(&pos, " ", NULL);
10962 	if (!token) {
10963 		ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10964 		return -EINVAL;
10965 	}
10966 	ifname = token;
10967 
10968 	err = wl_get_softap_elna_bypass(dev, ifname, &softap_elnabypass);
10969 	if (unlikely(err)) {
10970 		ANDROID_ERROR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n",
10971 			__FUNCTION__, err));
10972 		return err;
10973 	} else {
10974 		softap_elnabypass--; //Convert format to Customer HW4
10975 		ANDROID_INFO(("%s: eLNA Bypass feature enable status is %d\n",
10976 			__FUNCTION__, softap_elnabypass));
10977 		bytes_written = snprintf(command, total_len, "%s %d",
10978 			CMD_GET_SOFTAP_ELNA_BYPASS, softap_elnabypass);
10979 	}
10980 
10981 	return bytes_written;
10982 }
10983 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
10984 
10985 #ifdef WL_NAN
10986 int
wl_android_get_nan_status(struct net_device * dev,char * command,int total_len)10987 wl_android_get_nan_status(struct net_device *dev, char *command, int total_len)
10988 {
10989 	int bytes_written = 0;
10990 	int error = BCME_OK;
10991 	wl_nan_conf_status_t nstatus;
10992 
10993 	error = wl_cfgnan_get_status(dev, &nstatus);
10994 	if (error) {
10995 		ANDROID_ERROR(("Failed to get nan status (%d)\n", error));
10996 		return error;
10997 	}
10998 
10999 	bytes_written = snprintf(command, total_len,
11000 			"EN:%d Role:%d EM:%d CID:"MACF" NMI:"MACF" SC(2G):%d SC(5G):%d "
11001 			"MR:"NMRSTR" AMR:"NMRSTR" IMR:"NMRSTR
11002 			"HC:%d AMBTT:%04x TSF[%04x:%04x]\n",
11003 			nstatus.enabled,
11004 			nstatus.role,
11005 			nstatus.election_mode,
11006 			ETHERP_TO_MACF(&(nstatus.cid)),
11007 			ETHERP_TO_MACF(&(nstatus.nmi)),
11008 			nstatus.social_chans[0],
11009 			nstatus.social_chans[1],
11010 			NMR2STR(nstatus.mr),
11011 			NMR2STR(nstatus.amr),
11012 			NMR2STR(nstatus.imr),
11013 			nstatus.hop_count,
11014 			nstatus.ambtt,
11015 			nstatus.cluster_tsf_h,
11016 			nstatus.cluster_tsf_l);
11017 	return bytes_written;
11018 }
11019 #endif /* WL_NAN */
11020 
11021 #ifdef SUPPORT_NAN_RANGING_TEST_BW
11022 enum {
11023 	NAN_RANGING_5G_BW20 = 1,
11024 	NAN_RANGING_5G_BW40,
11025 	NAN_RANGING_5G_BW80
11026 };
11027 
11028 int
wl_nan_ranging_bw(struct net_device * net,int bw,char * command)11029 wl_nan_ranging_bw(struct net_device *net, int bw, char *command)
11030 {
11031 	int bytes_written, err = BCME_OK;
11032 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
11033 	s32 val = 1;
11034 	struct {
11035 		u32 band;
11036 		u32 bw_cap;
11037 	} param = {0, 0};
11038 
11039 	if (bw < NAN_RANGING_5G_BW20 || bw > NAN_RANGING_5G_BW80) {
11040 		ANDROID_ERROR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__));
11041 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11042 		return bytes_written;
11043 	}
11044 
11045 	switch (bw) {
11046 		case NAN_RANGING_5G_BW20:
11047 			ANDROID_ERROR(("NAN_RANGING 5G/BW20\n"));
11048 			param.band = WLC_BAND_5G;
11049 			param.bw_cap = 0x1;
11050 			break;
11051 		case NAN_RANGING_5G_BW40:
11052 			ANDROID_ERROR(("NAN_RANGING 5G/BW40\n"));
11053 			param.band = WLC_BAND_5G;
11054 			param.bw_cap = 0x3;
11055 			break;
11056 		case NAN_RANGING_5G_BW80:
11057 			ANDROID_ERROR(("NAN_RANGING 5G/BW80\n"));
11058 			param.band = WLC_BAND_5G;
11059 			param.bw_cap = 0x7;
11060 			break;
11061 	}
11062 
11063 	err = wldev_ioctl_set(net, WLC_DOWN, &val, sizeof(s32));
11064 	if (err) {
11065 		ANDROID_ERROR(("WLC_DOWN error %d\n", err));
11066 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11067 	} else {
11068 		err = wldev_iovar_setbuf(net, "bw_cap", &param, sizeof(param),
11069 			ioctl_buf, sizeof(ioctl_buf), NULL);
11070 
11071 		if (err) {
11072 			ANDROID_ERROR(("BW set failed\n"));
11073 			bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11074 		} else {
11075 			ANDROID_ERROR(("BW set done\n"));
11076 			bytes_written = scnprintf(command, sizeof("OK"), "OK");
11077 		}
11078 
11079 		err = wldev_ioctl_set(net, WLC_UP, &val, sizeof(s32));
11080 		if (err < 0) {
11081 			ANDROID_ERROR(("WLC_UP error %d\n", err));
11082 			bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11083 		}
11084 	}
11085 	return bytes_written;
11086 }
11087 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
11088 
11089 static int
wl_android_set_softap_ax_mode(struct net_device * dev,const char * cmd_str)11090 wl_android_set_softap_ax_mode(struct net_device *dev, const char* cmd_str)
11091 {
11092 	int enable = 0;
11093 	int err = 0;
11094 	s32 bssidx = 0;
11095 	struct bcm_cfg80211 *cfg = NULL;
11096 
11097 	if (!dev) {
11098 		err = -EINVAL;
11099 		goto exit;
11100 	}
11101 
11102 	cfg = wl_get_cfg(dev);
11103 	if (!cfg) {
11104 		err = -EINVAL;
11105 		goto exit;
11106 	}
11107 
11108 	if (cmd_str) {
11109 		enable = bcm_atoi(cmd_str);
11110 	} else {
11111 		ANDROID_ERROR(("failed due to wrong received parameter\n"));
11112 		err = -EINVAL;
11113 		goto exit;
11114 	}
11115 
11116 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11117 		ANDROID_ERROR(("find softap index from wdev failed\n"));
11118 		err = -EINVAL;
11119 		goto exit;
11120 	}
11121 
11122 	ANDROID_INFO(("HAPD_SET_AX_MODE = %d\n", enable));
11123 	err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, (bool)enable);
11124 	if (err) {
11125 		ANDROID_ERROR(("failed to set softap ax mode(%d)\n", enable));
11126 
11127 	}
11128 exit :
11129 	return err;
11130 }
11131 
11132 #ifdef WL_P2P_6G
11133 #define WL_HE_FEATURES_P2P_6G	0x0200u
11134 static int
wl_android_enable_p2p_6g(struct net_device * dev,int enable)11135 wl_android_enable_p2p_6g(struct net_device *dev, int enable)
11136 {
11137 	s32 err = 0;
11138 	s32 bssidx = 0;
11139 	struct bcm_cfg80211 *cfg = NULL;
11140 
11141 	if (!dev) {
11142 		err = -EINVAL;
11143 		return err;
11144 	}
11145 
11146 	cfg = wl_get_cfg(dev);
11147 	if (!cfg) {
11148 		err = -EINVAL;
11149 		return err;
11150 	}
11151 
11152 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11153 		ANDROID_ERROR(("find softap index from wdev failed\n"));
11154 		err = -EINVAL;
11155 		return err;
11156 	}
11157 
11158 	/* Enable/disable for P2P 6G, both P2P and P2P_6G needs to be handled together */
11159 	err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, (WL_HE_FEATURES_HE_P2P |
11160 		WL_HE_FEATURES_P2P_6G), (bool)enable);
11161 	if (err == BCME_OK) {
11162 		/* Set P2P 6G support flag */
11163 		if (enable) {
11164 			cfg->p2p_6g_enabled = TRUE;
11165 		} else {
11166 			cfg->p2p_6g_enabled = FALSE;
11167 		}
11168 	}
11169 
11170 	return err;
11171 }
11172 #endif /* WL_P2P_6G */
11173 
11174 #ifdef WL_TWT
11175 
11176 static uint8
wl_twt_cmd2val(const char * name)11177 wl_twt_cmd2val(const char *name)
11178 {
11179 	uint i;
11180 
11181 	for (i = 0; i < ARRAYSIZE(setup_cmd_val); i ++) {
11182 		if (strcmp(name, setup_cmd_val[i].name) == 0) {
11183 			return setup_cmd_val[i].val;
11184 		}
11185 	}
11186 
11187 	return WL_TWT_CMD_INVAL;
11188 }
11189 
11190 static int
wl_android_twt_setup(struct net_device * ndev,char * command,int total_len)11191 wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
11192 {
11193 	wl_twt_setup_t val;
11194 	s32 bw = 0;
11195 	char *token, *pos;
11196 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11197 	u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
11198 	uint8 *rem = mybuf;
11199 	uint16 rem_len = sizeof(mybuf);
11200 	uint8 tmp;
11201 
11202 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11203 
11204 	if (strlen(command) == strlen(CMD_TWT_SETUP)) {
11205 		ANDROID_ERROR(("Error, twt_setup cmd  missing params\n"));
11206 		bw = -EINVAL;
11207 		goto exit;
11208 	}
11209 
11210 	bzero(&val, sizeof(val));
11211 	val.version = WL_TWT_SETUP_VER;
11212 	val.length = sizeof(val.version) + sizeof(val.length);
11213 
11214 	val.desc.bid = WL_TWT_INV_BCAST_ID;
11215 	val.desc.flow_id = WL_TWT_INV_FLOW_ID;
11216 	val.desc.btwt_persistence = WL_TWT_INFINITE_BTWT_PERSIST;
11217 	val.desc.wake_type = WL_TWT_TIME_TYPE_AUTO;
11218 
11219 	pos = command + sizeof(CMD_TWT_SETUP);
11220 
11221 	/* setup_cmd */
11222 	token = strsep((char**)&pos, " ");
11223 	if (!token) {
11224 		ANDROID_ERROR(("Mandaory param setup_cmd not present\n"));
11225 		bw = -EINVAL;
11226 		goto exit;
11227 	}
11228 
11229 	val.desc.setup_cmd = wl_twt_cmd2val(token);
11230 	if (val.desc.setup_cmd == WL_TWT_CMD_INVAL) {
11231 		ANDROID_ERROR(("Unrecognized TWT Setup command '%s'\n", token));
11232 	}
11233 	ANDROID_INFO(("TWT_SETUP val.desc.setup_cmd %s\n", token));
11234 
11235 	/* negotiation_type */
11236 	token = strsep((char**)&pos, " ");
11237 	if (!token) {
11238 		ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11239 		bw = -EINVAL;
11240 		goto exit;
11241 	}
11242 	val.desc.negotiation_type = htod32((u32)bcm_atoi(token));
11243 	ANDROID_INFO(("TWT_SETUP val.desc.negotiation_type %d\n", val.desc.negotiation_type));
11244 
11245 	if (pos != NULL) {
11246 		ANDROID_INFO(("TWT_SETUP string %s\n", pos));
11247 		while ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11248 			ANDROID_INFO(("TWT_SETUP token is %s\n", token));
11249 
11250 			if (!strnicmp(token, "u", 1)) {
11251 				val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED;
11252 			}
11253 			else if (!strnicmp(token, "t", 1)) {
11254 				val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER;
11255 			}
11256 			else if (!strnicmp(token, "n", 1)) {
11257 				val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNSOLICITED;
11258 			}
11259 			else if (!strnicmp(token, "p", 1)) {
11260 				token++;
11261 				val.desc.btwt_persistence = (int)simple_strtol(token, NULL, 0);
11262 				ANDROID_INFO(("TWT_SETUP broadcast persistence %d\n",
11263 					val.desc.btwt_persistence));
11264 			}
11265 			/* Wake Duration */
11266 			else if (!strnicmp(token, "-d", 2)) {
11267 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11268 					val.desc.wake_dur = (int)simple_strtol(token, NULL, 0);
11269 					ANDROID_INFO(("TWT_SETUP val.desc.wake_dur %d\n",
11270 						val.desc.wake_dur));
11271 				}
11272 			}
11273 			/* Wake Interval */
11274 			else if (!strnicmp(token, "-i", 2)) {
11275 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11276 					val.desc.wake_int = (int)simple_strtol(token, NULL, 0);
11277 					ANDROID_INFO(("TWT_SETUP val.desc.wake_int %d\n",
11278 						val.desc.wake_int));
11279 				}
11280 			}
11281 			/* flow id */
11282 			else if (!strnicmp(token, "-f", 2)) {
11283 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11284 					val.desc.flow_id = (int)simple_strtol(token, NULL, 0);
11285 					ANDROID_INFO(("TWT_SETUP val.desc.flow_id %d\n",
11286 						val.desc.flow_id));
11287 				}
11288 			}
11289 			else if (!strnicmp(token, "-b", 2)) {
11290 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11291 					val.desc.bid = (int)simple_strtol(token, NULL, 0);
11292 					ANDROID_INFO(("TWT_SETUP val.desc.bid %d\n", val.desc.bid));
11293 				}
11294 			}
11295 			else if (!strnicmp(token, "-r", 2)) {
11296 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11297 					tmp = (int)simple_strtol(token, NULL, 0);
11298 					if (tmp > TWT_BCAST_FRAME_RECOMM_3) {
11299 						bw = -EINVAL;
11300 						goto exit;
11301 					}
11302 					val.desc.bid = tmp;
11303 					ANDROID_INFO(("TWT_SETUP frame recommendation %d\n",
11304 						val.desc.frame_recomm));
11305 				}
11306 			}
11307 			else if (!strnicmp(token, "-s", 2)) {
11308 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11309 					val.desc.duty_cycle_min =
11310 						(int)simple_strtol(token, NULL, 0);
11311 					ANDROID_INFO(("TWT_SETUP duty_cycle_min %d\n",
11312 						val.desc.duty_cycle_min));
11313 				}
11314 			}
11315 			else if (!strnicmp(token, "-v", 2)) {
11316 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11317 					val.desc.wake_int_max = (int)simple_strtol(token, NULL, 0);
11318 					ANDROID_INFO(("TWT_SETUP wake_int_max %d\n",
11319 						val.desc.wake_int_max));
11320 				}
11321 			}
11322 			/* a peer_address */
11323 			else if (!strnicmp(token, "-a", 2)) {
11324 				if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11325 					if (!bcm_ether_atoe(token, &val.peer)) {
11326 						ANDROID_ERROR(("%s : Malformed peer addr\n",
11327 							__FUNCTION__));
11328 						bw = -EINVAL;
11329 						goto exit;
11330 					}
11331 				}
11332 			}
11333 		}
11334 	}
11335 
11336 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_SETUP,
11337 			sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11338 	if (bw != BCME_OK) {
11339 		goto exit;
11340 	}
11341 
11342 	bw = wldev_iovar_setbuf(ndev, "twt",
11343 		mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
11344 	if (bw < 0) {
11345 		ANDROID_ERROR(("twt setup failed. ret:%d\n", bw));
11346 	}
11347 exit:
11348 	return bw;
11349 }
11350 
11351 static int
wl_android_twt_display_cap(wl_twt_cap_t * result,char * command,int total_len)11352 wl_android_twt_display_cap(wl_twt_cap_t *result, char *command, int total_len)
11353 {
11354 	int rem_len = 0, bytes_written = 0;
11355 
11356 	rem_len = total_len;
11357 	bytes_written = scnprintf(command, rem_len, "Device TWT Capabilities:\n");
11358 	command += bytes_written;
11359 	rem_len -= bytes_written;
11360 
11361 	bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11362 			!!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11363 	command += bytes_written;
11364 	rem_len -= bytes_written;
11365 
11366 	bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11367 			!!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11368 	command += bytes_written;
11369 	rem_len -= bytes_written;
11370 
11371 	bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11372 			!!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11373 	command += bytes_written;
11374 	rem_len -= bytes_written;
11375 
11376 	bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11377 			!!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11378 	command += bytes_written;
11379 	rem_len -= bytes_written;
11380 
11381 	bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11382 			!!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11383 	command += bytes_written;
11384 	rem_len -= bytes_written;
11385 
11386 	/* Peer capabilities */
11387 	bytes_written = scnprintf(command, rem_len, "\nPeer TWT Capabilities:\n");
11388 	command += bytes_written;
11389 	rem_len -= bytes_written;
11390 
11391 	bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11392 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11393 	command += bytes_written;
11394 	rem_len -= bytes_written;
11395 
11396 	bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11397 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11398 	command += bytes_written;
11399 	rem_len -= bytes_written;
11400 
11401 	bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11402 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11403 	command += bytes_written;
11404 	rem_len -= bytes_written;
11405 
11406 	bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11407 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11408 	command += bytes_written;
11409 	rem_len -= bytes_written;
11410 
11411 	bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11412 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11413 	command += bytes_written;
11414 	rem_len -= bytes_written;
11415 
11416 	bytes_written = scnprintf(command, rem_len, "\t------------"
11417 		"---------------------------------------------------\n\n");
11418 	command += bytes_written;
11419 	rem_len -= bytes_written;
11420 	ANDROID_INFO(("Device TWT Capabilities:\n"));
11421 	ANDROID_INFO(("Requester Support %d, \t",
11422 		!!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11423 	ANDROID_INFO(("Responder Support %d, \t",
11424 		!!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11425 	ANDROID_INFO(("Broadcast TWT Support %d, \t",
11426 		!!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11427 	ANDROID_INFO(("Flexible TWT Support %d, \t",
11428 		!!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11429 	ANDROID_INFO(("TWT Required by peer %d, \n",
11430 		!!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11431 	/* Peer capabilities */
11432 	ANDROID_INFO(("\nPeer TWT Capabilities:\n"));
11433 	ANDROID_INFO(("Requester Support %d, \t",
11434 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11435 	ANDROID_INFO(("Responder Support %d, \t",
11436 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11437 	ANDROID_INFO(("Broadcast TWT Support %d, \t",
11438 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11439 	ANDROID_INFO(("Flexible TWT Support %d, \t",
11440 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11441 	ANDROID_INFO(("TWT Required by peer %d, \n",
11442 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11443 	ANDROID_INFO(("\t-----------------------------------------------------------------\n\n"));
11444 
11445 	if ((total_len - rem_len) > 0) {
11446 		return (total_len - rem_len);
11447 	} else {
11448 		return BCME_ERROR;
11449 	}
11450 }
11451 
11452 static int
wl_android_twt_cap(struct net_device * dev,char * command,int total_len)11453 wl_android_twt_cap(struct net_device *dev, char *command, int total_len)
11454 {
11455 	int ret = BCME_OK;
11456 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11457 	uint8 *pxtlv = NULL;
11458 	uint8 *iovresp = NULL;
11459 	wl_twt_cap_cmd_t cmd_cap;
11460 	wl_twt_cap_t result;
11461 
11462 	uint16 buflen = 0, bufstart = 0;
11463 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11464 
11465 	bzero(&cmd_cap, sizeof(cmd_cap));
11466 
11467 	cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
11468 	cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
11469 
11470 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11471 	if (iovresp == NULL) {
11472 		ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11473 		goto exit;
11474 	}
11475 
11476 	buflen = bufstart = WLC_IOCTL_SMLEN;
11477 	pxtlv = (uint8 *)iovbuf;
11478 
11479 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
11480 			sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
11481 	if (ret != BCME_OK) {
11482 		ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11483 		goto exit;
11484 	}
11485 
11486 	if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11487 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11488 		ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11489 		goto exit;
11490 	}
11491 	if (ret) {
11492 		ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11493 	}
11494 
11495 	(void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11496 
11497 	if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
11498 		ANDROID_ERROR(("capability ver %d, \n", dtoh16(result.version)));
11499 		ret = wl_android_twt_display_cap(&result, command, total_len);
11500 		return ret;
11501 	} else {
11502 		ret = BCME_UNSUPPORTED;
11503 		ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11504 		goto exit;
11505 	}
11506 
11507 exit:
11508 	if (iovresp) {
11509 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11510 	}
11511 
11512 	return ret;
11513 }
11514 
11515 static int
wl_android_twt_status_display_v1(wl_twt_status_v1_t * status,char * command,int total_len)11516 wl_android_twt_status_display_v1(wl_twt_status_v1_t *status, char *command, int total_len)
11517 {
11518 	uint i;
11519 	wl_twt_sdesc_t *desc = NULL;
11520 	int rem_len = 0, bytes_written = 0;
11521 
11522 	rem_len = total_len;
11523 
11524 	ANDROID_ERROR(("\nNumber of Individual TWTs: %d\n", status->num_fid));
11525 	bytes_written = scnprintf(command, rem_len,
11526 			"\nNumber of Individual TWTs: %d\n", status->num_fid);
11527 	command += bytes_written;
11528 	rem_len -= bytes_written;
11529 	bytes_written = scnprintf(command, rem_len,
11530 			"Number of Broadcast TWTs: %d\n", status->num_bid);
11531 	command += bytes_written;
11532 	rem_len -= bytes_written;
11533 	bytes_written = scnprintf(command, rem_len,
11534 			"TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11535 			!!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11536 			!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11537 			!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE));
11538 	command += bytes_written;
11539 	rem_len -= bytes_written;
11540 	ANDROID_INFO(("Number of Broadcast TWTs: %d\n", status->num_bid));
11541 	ANDROID_INFO(("TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11542 		!!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11543 		!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11544 		!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE)));
11545 	ANDROID_INFO(("\t---------------- Individual TWT list-------------------\n"));
11546 	bytes_written = scnprintf(command, rem_len,
11547 			"\t---------------- Individual TWT list-------------------\n");
11548 	command += bytes_written;
11549 	rem_len -= bytes_written;
11550 
11551 	for (i = 0; i < WL_TWT_MAX_ITWT; i ++) {
11552 		if ((status->itwt_status[i].state == WL_TWT_ACTIVE) ||
11553 			(status->itwt_status[i].state == WL_TWT_SUSPEND)) {
11554 			desc = &status->itwt_status[i].desc;
11555 			bytes_written = scnprintf(command, rem_len, "\tFlow ID %d \tState %d\t",
11556 					desc->flow_id,
11557 					status->itwt_status[i].state);
11558 			command += bytes_written;
11559 			rem_len -= bytes_written;
11560 
11561 			bytes_written = scnprintf(command, rem_len,
11562 					"peer: "MACF"\n",
11563 					ETHER_TO_MACF(status->itwt_status[i].peer));
11564 			command += bytes_written;
11565 			rem_len -= bytes_written;
11566 
11567 			bytes_written = scnprintf(command, rem_len,
11568 					"Unannounced %d\tTriggered %d\tProtection %d\t"
11569 					"Info Frame Disabled %d\n",
11570 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11571 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11572 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11573 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11574 			command += bytes_written;
11575 			rem_len -= bytes_written;
11576 
11577 			bytes_written = scnprintf(command, rem_len,
11578 					"target wake time: 0x%08x%08x\t",
11579 					desc->wake_time_h, desc->wake_time_l);
11580 			command += bytes_written;
11581 			rem_len -= bytes_written;
11582 
11583 			bytes_written = scnprintf(command, rem_len,
11584 					"wake duration: %u\t", desc->wake_dur);
11585 			command += bytes_written;
11586 			rem_len -= bytes_written;
11587 
11588 			bytes_written = scnprintf(command, rem_len,
11589 					"wake interval: %u\t", desc->wake_int);
11590 			command += bytes_written;
11591 			rem_len -= bytes_written;
11592 
11593 			bytes_written = scnprintf(command, rem_len,
11594 					"TWT channel: %u\n", desc->channel);
11595 			command += bytes_written;
11596 			rem_len -= bytes_written;
11597 			ANDROID_INFO(("\tFlow ID %d \tState %d\t",
11598 				desc->flow_id,
11599 				status->itwt_status[i].state));
11600 			ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->itwt_status[i].peer)));
11601 			ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11602 				"Info Frame Disabled %d\n",
11603 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11604 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11605 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11606 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11607 			ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11608 				desc->wake_time_h, desc->wake_time_l));
11609 			ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11610 			ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11611 			ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11612 		}
11613 	}
11614 
11615 	ANDROID_INFO(("\t---------------- Broadcast TWT list-------------------\n"));
11616 	bytes_written = scnprintf(command, rem_len,
11617 			"\t---------------- Broadcast TWT list-------------------\n");
11618 	command += bytes_written;
11619 	rem_len -= bytes_written;
11620 	for (i = 0; i < WL_TWT_MAX_BTWT; i ++) {
11621 		if ((status->btwt_status[i].state == WL_TWT_ACTIVE) ||
11622 			(status->btwt_status[i].state == WL_TWT_SUSPEND)) {
11623 			desc = &status->btwt_status[i].desc;
11624 			bytes_written = scnprintf(command, rem_len,
11625 					"Broadcast ID %d \tState %d\t",
11626 					desc->bid, status->btwt_status[i].state);
11627 			command += bytes_written;
11628 			rem_len -= bytes_written;
11629 
11630 			bytes_written = scnprintf(command, rem_len,
11631 					"peer: "MACF"\n",
11632 					ETHER_TO_MACF(status->btwt_status[i].peer));
11633 			command += bytes_written;
11634 			rem_len -= bytes_written;
11635 
11636 			bytes_written = scnprintf(command, rem_len,
11637 					"Unannounced %d\tTriggered %d\tProtection %d\t"
11638 					"Info Frame Disabled %d\t",
11639 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11640 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11641 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11642 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11643 			command += bytes_written;
11644 			rem_len -= bytes_written;
11645 
11646 			bytes_written = scnprintf(command, rem_len,
11647 					"Frame Recommendation %d\tBTWT Persistence %d\n",
11648 					desc->frame_recomm, desc->btwt_persistence);
11649 			command += bytes_written;
11650 			rem_len -= bytes_written;
11651 
11652 			bytes_written = scnprintf(command, rem_len,
11653 					"target wake time: 0x%08x%08x\t",
11654 					desc->wake_time_h, desc->wake_time_l);
11655 			command += bytes_written;
11656 			rem_len -= bytes_written;
11657 			bytes_written = scnprintf(command, rem_len,
11658 					"wake duration: %u\t", desc->wake_dur);
11659 			command += bytes_written;
11660 			rem_len -= bytes_written;
11661 
11662 			bytes_written = scnprintf(command, rem_len,
11663 					"wake interval: %u\t", desc->wake_int);
11664 			command += bytes_written;
11665 			rem_len -= bytes_written;
11666 
11667 			bytes_written = scnprintf(command, rem_len,
11668 					"TWT channel: %u\n", desc->channel);
11669 			command += bytes_written;
11670 			rem_len -= bytes_written;
11671 			ANDROID_INFO(("Broadcast ID %d \tState %d\t",
11672 				desc->bid, status->btwt_status[i].state));
11673 			ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->btwt_status[i].peer)));
11674 			ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11675 				"Info Frame Disabled %d\t",
11676 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11677 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11678 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11679 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11680 			ANDROID_INFO(("Frame Recommendation %d\tBTWT Persistence %d\n",
11681 				desc->frame_recomm, desc->btwt_persistence));
11682 			ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11683 				desc->wake_time_h, desc->wake_time_l));
11684 			ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11685 			ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11686 			ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11687 		}
11688 	}
11689 
11690 	if ((total_len - rem_len) > 0) {
11691 		return (total_len - rem_len);
11692 	} else {
11693 		return BCME_ERROR;
11694 	}
11695 }
11696 
11697 static int
wl_android_twt_status_query(struct net_device * dev,char * command,int total_len)11698 wl_android_twt_status_query(struct net_device *dev, char *command, int total_len)
11699 {
11700 	int ret = BCME_OK;
11701 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11702 	uint8 *pxtlv = NULL;
11703 	uint8 *iovresp = NULL;
11704 	wl_twt_status_cmd_v1_t status_cmd;
11705 	wl_twt_status_v1_t result;
11706 
11707 	uint16 buflen = 0, bufstart = 0;
11708 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11709 
11710 	bzero(&status_cmd, sizeof(status_cmd));
11711 
11712 	status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1;
11713 	status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer);
11714 
11715 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11716 	if (iovresp == NULL) {
11717 		ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11718 		goto exit;
11719 	}
11720 
11721 	buflen = bufstart = WLC_IOCTL_SMLEN;
11722 	pxtlv = (uint8 *)iovbuf;
11723 
11724 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS,
11725 			sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32);
11726 	if (ret != BCME_OK) {
11727 		ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11728 		goto exit;
11729 	}
11730 
11731 	if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11732 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11733 		ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11734 		goto exit;
11735 	}
11736 	if (ret) {
11737 		ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11738 	}
11739 
11740 	(void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11741 
11742 	if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) {
11743 		ANDROID_ERROR(("status query ver %d, \n", dtoh16(result.version)));
11744 		ret = wl_android_twt_status_display_v1(&result, command, total_len);
11745 		return ret;
11746 	} else {
11747 		ret = BCME_UNSUPPORTED;
11748 		ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11749 		goto exit;
11750 	}
11751 
11752 exit:
11753 	if (iovresp) {
11754 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11755 	}
11756 
11757 	return ret;
11758 }
11759 
11760 static int
wl_android_twt_info(struct net_device * ndev,char * command,int total_len)11761 wl_android_twt_info(struct net_device *ndev, char *command, int total_len)
11762 {
11763 	wl_twt_info_t val;
11764 	s32 bw;
11765 	char *token, *pos;
11766 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11767 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11768 	u64 twt;
11769 	uint8 *rem = mybuf;
11770 	uint16 rem_len = sizeof(mybuf);
11771 	int32 val32;
11772 
11773 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11774 
11775 	if (strlen(command) == strlen(CMD_TWT_INFO)) {
11776 		ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11777 		bw = -EINVAL;
11778 		goto exit;
11779 	}
11780 
11781 	bzero(&val, sizeof(val));
11782 	val.version = WL_TWT_INFO_VER;
11783 	val.length = sizeof(val.version) + sizeof(val.length);
11784 
11785 	/* Default values, Overide Below */
11786 	val.infodesc.flow_id = 0xFF;
11787 	val.desc.next_twt_h = 0xFFFFFFFF;
11788 	val.desc.next_twt_l = 0xFFFFFFFF;
11789 
11790 	pos = command + sizeof(CMD_TWT_TEARDOWN);
11791 
11792 	/* (all TWT) */
11793 	token = strsep((char**)&pos, " ");
11794 	if (!token) {
11795 		ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11796 		bw = -EINVAL;
11797 		goto exit;
11798 	}
11799 	if (htod32((u32)bcm_atoi(token)) == 1) {
11800 		val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
11801 	}
11802 
11803 	/* Flow ID */
11804 	token = strsep((char**)&pos, " ");
11805 	if (!token) {
11806 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11807 	} else {
11808 		val32 = htod32((u32)bcm_atoi(token));
11809 		if (val32 != -1) {
11810 			val.infodesc.flow_id = htod32((u32)bcm_atoi(token));
11811 		}
11812 	}
11813 
11814 	/* resume offset */
11815 	token = strsep((char**)&pos, " ");
11816 	if (!token) {
11817 		ANDROID_ERROR(("resume offset not provided, using default\n"));
11818 	} else {
11819 		twt = (u64)bcm_atoi(token);
11820 		val32 = htod32((u32)(twt >> 32));
11821 		if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11822 			val.infodesc.next_twt_h = htod32((u32)(twt >> 32));
11823 			val.infodesc.next_twt_l = htod32((u32)twt);
11824 			val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
11825 		}
11826 	}
11827 
11828 	/* peer_address */
11829 	token = strsep((char**)&pos, " ");
11830 	if (!token) {
11831 		ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11832 	} else {
11833 		/* get peer mac */
11834 		if (!bcm_ether_atoe(token, &val.peer)) {
11835 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11836 			bw = BCME_ERROR;
11837 			goto exit;
11838 		}
11839 	}
11840 
11841 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
11842 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11843 	if (bw != BCME_OK) {
11844 		goto exit;
11845 	}
11846 
11847 	bw = wldev_iovar_setbuf(ndev, "twt",
11848 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11849 	if (bw < 0) {
11850 		ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11851 	}
11852 exit:
11853 	return bw;
11854 
11855 }
11856 
11857 static int
wl_android_twt_teardown(struct net_device * ndev,char * command,int total_len)11858 wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len)
11859 {
11860 	wl_twt_teardown_t val;
11861 	s32 bw;
11862 	char *token, *pos;
11863 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11864 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11865 	uint8 *rem = mybuf;
11866 	uint16 rem_len = sizeof(mybuf);
11867 	int32 val32;
11868 
11869 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11870 
11871 	if (strlen(command) == strlen(CMD_TWT_TEARDOWN)) {
11872 		ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11873 		bw = -EINVAL;
11874 		goto exit;
11875 	}
11876 
11877 	bzero(&val, sizeof(val));
11878 	val.version = WL_TWT_TEARDOWN_VER;
11879 	val.length = sizeof(val.version) + sizeof(val.length);
11880 
11881 	/* Default values, Overide Below */
11882 	val.teardesc.flow_id = 0xFF;
11883 	val.teardesc.bid = 0xFF;
11884 
11885 	pos = command + sizeof(CMD_TWT_TEARDOWN);
11886 
11887 	/* negotiation_type */
11888 	token = strsep((char**)&pos, " ");
11889 	if (!token) {
11890 		ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11891 		bw = -EINVAL;
11892 		goto exit;
11893 	}
11894 	val.teardesc.negotiation_type  = htod32((u32)bcm_atoi(token));
11895 
11896 	/* (all TWT) */
11897 	token = strsep((char**)&pos, " ");
11898 	if (!token) {
11899 		ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11900 		bw = -EINVAL;
11901 		goto exit;
11902 	}
11903 	val.teardesc.alltwt = htod32((u32)bcm_atoi(token));
11904 
11905 	/* Flow ID */
11906 	token = strsep((char**)&pos, " ");
11907 	if (!token) {
11908 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11909 	} else {
11910 		val32 = htod32((u32)bcm_atoi(token));
11911 		if (val32 != -1) {
11912 			val.teardesc.flow_id = htod32((u32)bcm_atoi(token));
11913 		}
11914 	}
11915 
11916 	/* Broadcas ID */
11917 	token = strsep((char**)&pos, " ");
11918 	if (!token) {
11919 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11920 	} else {
11921 		val32 = htod32((u32)bcm_atoi(token));
11922 		if (val32 != -1) {
11923 			val.teardesc.bid = htod32((u32)bcm_atoi(token));
11924 		}
11925 	}
11926 
11927 	/* peer_address */
11928 	token = strsep((char**)&pos, " ");
11929 	if (!token) {
11930 		ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11931 	} else {
11932 		/* get peer mac */
11933 		if (!bcm_ether_atoe(token, &val.peer)) {
11934 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11935 			bw = BCME_ERROR;
11936 			goto exit;
11937 		}
11938 	}
11939 
11940 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
11941 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11942 	if (bw != BCME_OK) {
11943 		goto exit;
11944 	}
11945 
11946 	bw = wldev_iovar_setbuf(ndev, "twt",
11947 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11948 	if (bw < 0) {
11949 		ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11950 	}
11951 exit:
11952 	return bw;
11953 }
11954 
11955 /* wl twt stats result display version 2 */
11956 static int
wl_android_twt_stats_display_v2(wl_twt_stats_v2_t * stats,char * command,int total_len)11957 wl_android_twt_stats_display_v2(wl_twt_stats_v2_t *stats, char *command, int total_len)
11958 {
11959 	u32 i;
11960 	wl_twt_peer_stats_v2_t *peer_stats;
11961 	int rem_len = 0, bytes_written = 0;
11962 
11963 	rem_len = total_len;
11964 	for (i = 0; i < stats->num_stats; i++) {
11965 		peer_stats = &stats->peer_stats_list[i];
11966 
11967 		bytes_written = scnprintf(command, rem_len,
11968 			"%u %u %u %u %u",
11969 			peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg,
11970 			peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg);
11971 		CHECK_SCNPRINTF_RET_VAL(bytes_written);
11972 		command += bytes_written;
11973 		rem_len -= bytes_written;
11974 	}
11975 
11976 	if ((total_len - rem_len) > 0) {
11977 		return (total_len - rem_len);
11978 	} else {
11979 		return BCME_ERROR;
11980 	}
11981 }
11982 
11983 static int
wl_android_twt_stats(struct net_device * ndev,char * command,int total_len)11984 wl_android_twt_stats(struct net_device *ndev, char *command, int total_len)
11985 {
11986 	wl_twt_stats_cmd_v1_t query;
11987 	wl_twt_stats_v2_t stats_v2;
11988 	int ret = BCME_OK;
11989 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11990 	uint8 *pxtlv = NULL;
11991 	uint8 *iovresp = NULL;
11992 	char *token, *pos;
11993 	uint16 buflen = 0, bufstart = 0;
11994 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11995 
11996 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11997 
11998 	bzero(&query, sizeof(query));
11999 	query.version = WL_TWT_STATS_CMD_VERSION_1;
12000 	query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer);
12001 
12002 	/* Default values, Overide Below */
12003 	query.num_bid = 0xFF;
12004 	query.num_fid = 0xFF;
12005 
12006 	if (!(strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)))) {
12007 		query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET;
12008 		pos = command + sizeof(CMD_TWT_CLR_STATS);
12009 	} else if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) {
12010 		pos = command + sizeof(CMD_TWT_GET_STATS);
12011 	}
12012 
12013 	/* Config ID */
12014 	token = strsep((char**)&pos, " ");
12015 	if (!token) {
12016 		ANDROID_ERROR(("Mandatory param config ID not present\n"));
12017 		ret = -EINVAL;
12018 		goto exit;
12019 	}
12020 	query.configID = (u8)bcm_atoi(token);
12021 
12022 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
12023 	if (iovresp == NULL) {
12024 		ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
12025 		goto exit;
12026 	}
12027 
12028 	buflen = bufstart = WLC_IOCTL_SMLEN;
12029 	pxtlv = (uint8 *)iovbuf;
12030 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS,
12031 			sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
12032 	if (ret != BCME_OK) {
12033 		ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
12034 		goto exit;
12035 	}
12036 
12037 	if ((ret = wldev_iovar_getbuf(ndev, "twt", iovbuf, bufstart-buflen,
12038 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
12039 		ANDROID_ERROR(("twt status failed with err=%d \n", ret));
12040 		goto exit;
12041 	}
12042 
12043 	(void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2));
12044 
12045 	if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) {
12046 		if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) {
12047 			ANDROID_ERROR(("stats query ver %d, \n", dtoh16(stats_v2.version)));
12048 			ret = wl_android_twt_stats_display_v2((wl_twt_stats_v2_t*)iovresp,
12049 				command, total_len);
12050 		}
12051 	} else {
12052 		ret = BCME_UNSUPPORTED;
12053 		ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version)));
12054 		goto exit;
12055 	}
12056 
12057 exit:
12058 	if (iovresp) {
12059 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
12060 	}
12061 
12062 	return ret;
12063 }
12064 #endif /* WL_TWT */
12065 
12066 int
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)12067 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
12068 {
12069 	int bytes_written = 0;
12070 	android_wifi_priv_cmd priv_cmd;
12071 
12072 	bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
12073 	priv_cmd.total_len = cmd_len;
12074 
12075 	if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
12076 		ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
12077 #ifdef SUPPORT_DEEP_SLEEP
12078 		trigger_deep_sleep = 1;
12079 #else
12080 #ifdef  BT_OVER_SDIO
12081 		bytes_written = dhd_net_bus_get(net);
12082 #else
12083 		bytes_written = wl_android_wifi_on(net);
12084 #endif /* BT_OVER_SDIO */
12085 #endif /* SUPPORT_DEEP_SLEEP */
12086 	}
12087 	else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
12088 		bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
12089 	}
12090 
12091 	if (!g_wifi_on) {
12092 		ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
12093 			__FUNCTION__, command));
12094 		return 0;
12095 	}
12096 
12097 	if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
12098 #ifdef SUPPORT_DEEP_SLEEP
12099 		trigger_deep_sleep = 1;
12100 #else
12101 #ifdef  BT_OVER_SDIO
12102 		bytes_written = dhd_net_bus_put(net);
12103 #else
12104 		bytes_written = wl_android_wifi_off(net, FALSE);
12105 #endif /* BT_OVER_SDIO */
12106 #endif /* SUPPORT_DEEP_SLEEP */
12107 	}
12108 #ifdef WL_CFG80211
12109 	else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
12110 		wl_cfg80211_set_passive_scan(net, command);
12111 	}
12112 	else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
12113 		wl_cfg80211_set_passive_scan(net, command);
12114 	}
12115 #endif /* WL_CFG80211 */
12116 	else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
12117 		bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
12118 	}
12119 	else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
12120 		bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
12121 	}
12122 #ifdef PKT_FILTER_SUPPORT
12123 	else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
12124 		bytes_written = net_os_enable_packet_filter(net, 1);
12125 	}
12126 	else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
12127 		bytes_written = net_os_enable_packet_filter(net, 0);
12128 	}
12129 	else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
12130 		int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
12131 		bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
12132 	}
12133 	else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
12134 		int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
12135 		bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
12136 	}
12137 #endif /* PKT_FILTER_SUPPORT */
12138 	else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
12139 		/* TBD: BTCOEXSCAN-START */
12140 	}
12141 	else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
12142 		/* TBD: BTCOEXSCAN-STOP */
12143 	}
12144 	else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
12145 #ifdef WL_CFG80211
12146 		void *dhdp = wl_cfg80211_get_dhdp(net);
12147 		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
12148 #else
12149 #ifdef PKT_FILTER_SUPPORT
12150 		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
12151 
12152 		if (mode == 1)
12153 			net_os_enable_packet_filter(net, 0); /* DHCP starts */
12154 		else
12155 			net_os_enable_packet_filter(net, 1); /* DHCP ends */
12156 #endif /* PKT_FILTER_SUPPORT */
12157 #endif /* WL_CFG80211 */
12158 	}
12159 	else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
12160 		bytes_written = wl_android_set_suspendopt(net, command);
12161 	}
12162 	else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
12163 		bytes_written = wl_android_set_suspendmode(net, command);
12164 	}
12165 	else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
12166 		bytes_written = wl_android_set_bcn_li_dtim(net, command);
12167 	}
12168 	else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
12169 		bytes_written = wl_android_set_max_dtim(net, command);
12170 	}
12171 #ifdef DISABLE_DTIM_IN_SUSPEND
12172 	else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
12173 		bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
12174 	}
12175 #endif /* DISABLE_DTIM_IN_SUSPEND */
12176 #ifdef WL_CFG80211
12177 	else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
12178 		bytes_written = wl_android_set_band(net, command);
12179 	}
12180 #endif /* WL_CFG80211 */
12181 	else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
12182 		bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
12183 	}
12184 #ifdef WL_CFG80211
12185 	else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
12186 		bytes_written = wl_android_set_csa(net, command);
12187 	} else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
12188 		bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
12189 	} else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
12190 		bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
12191 	}
12192 #endif /* WL_CFG80211 */
12193 #ifndef CUSTOMER_SET_COUNTRY
12194 	/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
12195 	else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
12196 		/*
12197 		 * Usage examples:
12198 		 * DRIVER COUNTRY US
12199 		 * DRIVER COUNTRY US/7
12200 		 * Wrong revinfo should be filtered:
12201 		 * DRIVER COUNTRY US/-1
12202 		 */
12203 		char *country_code = command + strlen(CMD_COUNTRY) + 1;
12204 		char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
12205 		int revinfo = -1;
12206 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12207 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12208 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12209 		if ((rev_info_delim) &&
12210 			(strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
12211 			strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
12212 			(rev_info_delim + 1)) {
12213 			revinfo  = bcm_atoi(rev_info_delim + 1);
12214 		} else {
12215 			revinfo = 0;
12216 		}
12217 
12218 		if (revinfo < 0) {
12219 			ANDROID_ERROR(("%s:failed due to wrong revinfo %d\n", __FUNCTION__, revinfo));
12220 			return BCME_BADARG;
12221 		}
12222 
12223 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12224 		if (dhdp->is_blob) {
12225 			revinfo = 0;
12226 		}
12227 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12228 
12229 #ifdef WL_CFG80211
12230 		bytes_written = wl_cfg80211_set_country_code(net, country_code,
12231 				true, true, revinfo);
12232 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12233 #ifdef FCC_PWR_LIMIT_2G
12234 		if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
12235 			ANDROID_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
12236 		} else {
12237 			ANDROID_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
12238 		}
12239 #endif /* FCC_PWR_LIMIT_2G */
12240 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12241 #else
12242 		bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
12243 #endif /* WL_CFG80211 */
12244 	}
12245 #endif /* CUSTOMER_SET_COUNTRY */
12246 	else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
12247 		bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
12248 	} else if (strnicmp(command, CMD_ASSOC_CLIENTS,	strlen(CMD_ASSOC_CLIENTS)) == 0) {
12249 		bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
12250 	}
12251 
12252 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12253 	else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_SET, strlen(CMD_ROAM_VSIE_ENAB_SET)) == 0) {
12254 		bytes_written = wl_android_set_roam_vsie_enab(net, command, priv_cmd.total_len);
12255 	} else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_GET, strlen(CMD_ROAM_VSIE_ENAB_GET)) == 0) {
12256 		bytes_written = wl_android_get_roam_vsie_enab(net, command, priv_cmd.total_len);
12257 	} else if (strnicmp(command, CMD_BR_VSIE_ENAB_SET, strlen(CMD_BR_VSIE_ENAB_SET)) == 0) {
12258 		bytes_written = wl_android_set_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12259 	} else if (strnicmp(command, CMD_BR_VSIE_ENAB_GET, strlen(CMD_BR_VSIE_ENAB_GET)) == 0) {
12260 		bytes_written = wl_android_get_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12261 	}
12262 #ifdef WES_SUPPORT
12263 	else if (strnicmp(command, CMD_GETNCHOMODE, strlen(CMD_GETNCHOMODE)) == 0) {
12264 		bytes_written = wl_android_get_ncho_mode(net, command, priv_cmd.total_len);
12265 	}
12266 	else if (strnicmp(command, CMD_SETNCHOMODE, strlen(CMD_SETNCHOMODE)) == 0) {
12267 		int mode;
12268 		sscanf(command, "%*s %d", &mode);
12269 		bytes_written = wl_android_set_ncho_mode(net, mode);
12270 	}
12271 	else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
12272 		bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
12273 	}
12274 	else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
12275 		bytes_written = wl_android_okc_enable(net, command);
12276 	}
12277 	else if (wl_android_legacy_check_command(net, command)) {
12278 		bytes_written = wl_android_legacy_private_command(net, command, priv_cmd.total_len);
12279 	}
12280 	else if (wl_android_ncho_check_command(net, command)) {
12281 		bytes_written = wl_android_ncho_private_command(net, command, priv_cmd.total_len);
12282 	}
12283 #endif /* WES_SUPPORT */
12284 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
12285 	else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
12286 		bytes_written = wl_android_default_set_scan_params(net, command,
12287 			priv_cmd.total_len);
12288 	}
12289 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
12290 #ifdef WLTDLS
12291 	else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
12292 		bytes_written = wl_android_tdls_reset(net);
12293 	}
12294 #endif /* WLTDLS */
12295 #ifdef CONFIG_SILENT_ROAM
12296 	else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) {
12297 		int mode = *(command + strlen(CMD_SROAM_TURN_ON) + 1) - '0';
12298 		bytes_written = wl_android_sroam_turn_on(net, mode);
12299 	}
12300 	else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) {
12301 		char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1);
12302 		bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len);
12303 	}
12304 	else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) {
12305 		bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len);
12306 	}
12307 #endif /* CONFIG_SILENT_ROAM */
12308 #ifdef CONFIG_ROAM_RSSI_LIMIT
12309 	else if (strnicmp(command, CMD_ROAM_RSSI_LMT, strlen(CMD_ROAM_RSSI_LMT)) == 0) {
12310 		bytes_written = wl_android_roam_rssi_limit(net, command, priv_cmd.total_len);
12311 	}
12312 #endif /* CONFIG_ROAM_RSSI_LIMIT */
12313 #ifdef CONFIG_ROAM_MIN_DELTA
12314 	else if (strnicmp(command, CMD_ROAM_MIN_DELTA, strlen(CMD_ROAM_MIN_DELTA)) == 0) {
12315 		bytes_written = wl_android_roam_min_delta(net, command, priv_cmd.total_len);
12316 	}
12317 #endif /* CONFIG_ROAM_MIN_DELTA */
12318 	else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) {
12319 		bytes_written = wl_android_set_disconnect_ies(net, command);
12320 	}
12321 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12322 
12323 #ifdef PNO_SUPPORT
12324 	else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
12325 		bytes_written = dhd_dev_pno_stop_for_ssid(net);
12326 	}
12327 #ifndef WL_SCHED_SCAN
12328 	else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
12329 		bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
12330 	}
12331 #endif /* !WL_SCHED_SCAN */
12332 	else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
12333 		int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
12334 		bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
12335 	}
12336 	else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
12337 		bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
12338 	}
12339 #endif /* PNO_SUPPORT */
12340 	else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
12341 		bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
12342 	}
12343 	else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
12344 		int skip = strlen(CMD_P2P_SET_NOA) + 1;
12345 		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
12346 			priv_cmd.total_len - skip);
12347 	}
12348 #ifdef WL_SDO
12349 	else if (strnicmp(command, CMD_P2P_SD_OFFLOAD, strlen(CMD_P2P_SD_OFFLOAD)) == 0) {
12350 		u8 *buf = command;
12351 		u8 *cmd_id = NULL;
12352 		int len;
12353 
12354 		cmd_id = strsep((char **)&buf, " ");
12355 		if (!cmd_id) {
12356 			/* Propagate the error */
12357 			bytes_written = -EINVAL;
12358 		} else {
12359 			/* if buf == NULL, means no arg */
12360 			if (buf == NULL) {
12361 				len = 0;
12362 			} else {
12363 				len = strlen(buf);
12364 			}
12365 			bytes_written = wl_cfg80211_sd_offload(net, cmd_id, buf, len);
12366 		}
12367 	}
12368 #endif /* WL_SDO */
12369 #ifdef P2P_LISTEN_OFFLOADING
12370 	else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
12371 		u8 *sub_command = strchr(command, ' ');
12372 		bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
12373 				sub_command ? strlen(sub_command) : 0);
12374 	}
12375 #endif /* P2P_LISTEN_OFFLOADING */
12376 #if !defined WL_ENABLE_P2P_IF
12377 	else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
12378 		bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
12379 	}
12380 #endif /* WL_ENABLE_P2P_IF */
12381 	else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
12382 		int skip = strlen(CMD_P2P_SET_PS) + 1;
12383 		bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
12384 			priv_cmd.total_len - skip);
12385 	}
12386 	else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
12387 		int skip = strlen(CMD_P2P_ECSA) + 1;
12388 		bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
12389 			priv_cmd.total_len - skip);
12390 	}
12391 	/* This command is not for normal VSDB operation but for only specific P2P operation.
12392 	 * Ex) P2P OTA backup operation
12393 	 */
12394 	else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
12395 		int skip = strlen(CMD_P2P_INC_BW) + 1;
12396 		bytes_written = wl_cfg80211_increase_p2p_bw(net,
12397 				command + skip, priv_cmd.total_len - skip);
12398 	}
12399 #ifdef WL_CFG80211
12400 	else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
12401 		strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
12402 		int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
12403 		bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
12404 			priv_cmd.total_len - skip, *(command + skip - 2) - '0');
12405 	}
12406 #ifdef WLFBT
12407 	else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
12408 		bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
12409 	}
12410 #endif /* WLFBT */
12411 #endif /* WL_CFG80211 */
12412 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12413 	else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
12414 		strlen(CMD_GET_BEST_CHANNELS)) == 0) {
12415 		bytes_written = wl_android_get_best_channels(net, command,
12416 			priv_cmd.total_len);
12417 	}
12418 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12419 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12420 	else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
12421 		strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
12422 		int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
12423 		bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
12424 			priv_cmd.total_len);
12425 	}
12426 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12427 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12428 #ifdef SUPPORT_AMPDU_MPDU_CMD
12429 	/* CMD_AMPDU_MPDU */
12430 	else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
12431 		int skip = strlen(CMD_AMPDU_MPDU) + 1;
12432 		bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
12433 	}
12434 #endif /* SUPPORT_AMPDU_MPDU_CMD */
12435 #if defined (SUPPORT_HIDDEN_AP)
12436 	else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
12437 		strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
12438 		int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
12439 		wl_android_set_max_num_sta(net, (const char*)command+skip);
12440 	}
12441 	else if (strnicmp(command, CMD_SET_HAPD_SSID,
12442 		strlen(CMD_SET_HAPD_SSID)) == 0) {
12443 		int skip = strlen(CMD_SET_HAPD_SSID) + 3;
12444 		wl_android_set_ssid(net, (const char*)command+skip);
12445 	}
12446 	else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
12447 		strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
12448 		int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
12449 		wl_android_set_hide_ssid(net, (const char*)command+skip);
12450 	}
12451 #endif /* SUPPORT_HIDDEN_AP */
12452 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
12453 	else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
12454 		strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
12455 		int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
12456 		wl_android_sta_diassoc(net, (const char*)command+skip);
12457 	}
12458 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
12459 #ifdef SUPPORT_SET_LPC
12460 	else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
12461 		strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
12462 		int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
12463 		wl_android_set_lpc(net, (const char*)command+skip);
12464 	}
12465 #endif /* SUPPORT_SET_LPC */
12466 #ifdef SUPPORT_TRIGGER_HANG_EVENT
12467 	else if (strnicmp(command, CMD_TEST_FORCE_HANG,
12468 		strlen(CMD_TEST_FORCE_HANG)) == 0) {
12469 		int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
12470 		net_os_send_hang_message_reason(net, (const char*)command+skip);
12471 	}
12472 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
12473 	else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
12474 		bytes_written = wl_android_ch_res_rl(net, true);
12475 	else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
12476 		bytes_written = wl_android_ch_res_rl(net, false);
12477 #ifdef SUPPORT_LTECX
12478 	else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
12479 		int skip = strlen(CMD_LTECX_SET) + 1;
12480 		bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
12481 	}
12482 #endif /* SUPPORT_LTECX */
12483 #ifdef WL_RELMCAST
12484 	else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
12485 		int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
12486 		bytes_written = wl_android_rmc_enable(net, rmc_enable);
12487 	}
12488 	else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
12489 		int rmc_txrate;
12490 		sscanf(command, "%*s %10d", &rmc_txrate);
12491 		bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
12492 	}
12493 	else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
12494 		int actperiod;
12495 		sscanf(command, "%*s %10d", &actperiod);
12496 		bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
12497 	}
12498 	else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
12499 		int acktimeout;
12500 		sscanf(command, "%*s %10d", &acktimeout);
12501 		acktimeout *= 1000;
12502 		bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
12503 	}
12504 	else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
12505 		int skip = strlen(CMD_SET_RMC_LEADER) + 1;
12506 		bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
12507 	}
12508 	else if (strnicmp(command, CMD_SET_RMC_EVENT,
12509 		strlen(CMD_SET_RMC_EVENT)) == 0) {
12510 		bytes_written = wl_android_set_rmc_event(net, command);
12511 	}
12512 #endif /* WL_RELMCAST */
12513 	else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
12514 		bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
12515 	}
12516 	else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
12517 		bytes_written = wl_android_set_singlecore_scan(net, command);
12518 	}
12519 #ifdef TEST_TX_POWER_CONTROL
12520 	else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
12521 		strlen(CMD_TEST_SET_TX_POWER)) == 0) {
12522 		int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
12523 		wl_android_set_tx_power(net, (const char*)command+skip);
12524 	}
12525 	else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
12526 		strlen(CMD_TEST_GET_TX_POWER)) == 0) {
12527 		wl_android_get_tx_power(net, command, priv_cmd.total_len);
12528 	}
12529 #endif /* TEST_TX_POWER_CONTROL */
12530 	else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
12531 		strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
12532 		int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
12533 		bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
12534 	}
12535 #ifdef SUPPORT_SET_TID
12536 	else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
12537 		bytes_written = wl_android_set_tid(net, command);
12538 	}
12539 	else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
12540 		bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
12541 	}
12542 #endif /* SUPPORT_SET_TID */
12543 #ifdef WL_WTC
12544 	else if (strnicmp(command, CMD_WTC_CONFIG, strlen(CMD_WTC_CONFIG)) == 0) {
12545 		bytes_written = wl_android_wtc_config(net, command, priv_cmd.total_len);
12546 	}
12547 #endif /* WL_WTC */
12548 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12549 	else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
12550 		int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
12551 		wl_android_set_mac_address_filter(net, command+skip);
12552 	}
12553 	else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
12554 		bytes_written = wl_android_set_roam_mode(net, command);
12555 #if defined(BCMFW_ROAM_ENABLE)
12556 	else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
12557 		bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
12558 	}
12559 #endif /* BCMFW_ROAM_ENABLE */
12560 #ifdef WL_CFG80211
12561 	else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
12562 		bytes_written = wl_android_set_miracast(net, command);
12563 	else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
12564 		bytes_written = wl_android_set_ibss_beacon_ouidata(net,
12565 		command, priv_cmd.total_len);
12566 #endif /* WL_CFG80211 */
12567 #ifdef WLAIBSS
12568 	else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
12569 		strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
12570 		bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
12571 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
12572 		strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
12573 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12574 			TRUE);
12575 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
12576 		strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
12577 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12578 			FALSE);
12579 	else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
12580 		strlen(CMD_SETIBSSROUTETABLE)) == 0)
12581 		bytes_written = wl_android_set_ibss_routetable(net, command);
12582 	else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
12583 		bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
12584 	else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
12585 		bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
12586 #endif /* WLAIBSS */
12587 	else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
12588 		int skip = strlen(CMD_KEEP_ALIVE) + 1;
12589 		bytes_written = wl_keep_alive_set(net, command + skip);
12590 	}
12591 #ifdef WL_CFG80211
12592 	else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
12593 		int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
12594 		bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
12595 	}
12596 	else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
12597 		char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
12598 		ANDROID_INFO(("Creating %s interface\n", name));
12599 		if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
12600 				name, NULL) == NULL) {
12601 			bytes_written = -ENODEV;
12602 		} else {
12603 			/* Return success */
12604 			bytes_written = 0;
12605 		}
12606 	}
12607 	else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
12608 		char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
12609 		ANDROID_INFO(("Deleteing %s interface\n", name));
12610 		bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
12611 	}
12612 #endif /* WL_CFG80211 */
12613 	else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
12614 		bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
12615 	}
12616 #ifdef P2PRESP_WFDIE_SRC
12617 	else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
12618 		strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
12619 		int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
12620 		bytes_written = wl_android_set_wfdie_resp(net, mode);
12621 	} else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
12622 		strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
12623 		bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
12624 	}
12625 #endif /* P2PRESP_WFDIE_SRC */
12626 #ifdef WL_CFG80211
12627 	else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
12628 		char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
12629 		bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
12630 	}
12631 #endif /* WL_CFG80211 */
12632 #ifdef WBTEXT
12633 	else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
12634 		bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
12635 	}
12636 	else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
12637 			strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
12638 		char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
12639 		bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
12640 	}
12641 	else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
12642 			strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
12643 		char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
12644 		bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
12645 				command, priv_cmd.total_len);
12646 	}
12647 	else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
12648 			strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
12649 		char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
12650 		bytes_written = wl_cfg80211_wbtext_table_config(net, data,
12651 				command, priv_cmd.total_len);
12652 	}
12653 	else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
12654 			strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
12655 		char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
12656 		bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
12657 				command, priv_cmd.total_len);
12658 	}
12659 	else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
12660 			strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
12661 		bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
12662 			priv_cmd.total_len);
12663 	}
12664 	else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
12665 			strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
12666 		bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
12667 			priv_cmd.total_len);
12668 	}
12669 	else if (strnicmp(command, CMD_WBTEXT_ESTM_ENABLE,
12670 			strlen(CMD_WBTEXT_ESTM_ENABLE)) == 0) {
12671 		bytes_written = wl_cfg80211_wbtext_estm_enable(net, command,
12672 			priv_cmd.total_len);
12673 	}
12674 #endif /* WBTEXT */
12675 #ifdef WLWFDS
12676 	else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
12677 		bytes_written = wl_android_set_wfds_hash(net, command, 1);
12678 	}
12679 	else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
12680 		bytes_written = wl_android_set_wfds_hash(net, command, 0);
12681 	}
12682 #endif /* WLWFDS */
12683 #ifdef BT_WIFI_HANDOVER
12684 	else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
12685 	    bytes_written = wl_tbow_teardown(net);
12686 	}
12687 #endif /* BT_WIFI_HANDOVER */
12688 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12689 #ifdef FCC_PWR_LIMIT_2G
12690 	else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
12691 		strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
12692 		bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
12693 	}
12694 	else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
12695 		strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
12696 		bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
12697 	}
12698 #endif /* FCC_PWR_LIMIT_2G */
12699 	else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
12700 		bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
12701 	}
12702 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12703 	else if (strnicmp(command, CMD_MURX_BFE_CAP,
12704 			strlen(CMD_MURX_BFE_CAP)) == 0) {
12705 #ifdef WL_MURX
12706 		uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
12707 		bytes_written = wl_android_murx_bfe_cap(net, val);
12708 #else
12709 		return BCME_UNSUPPORTED;
12710 #endif /* WL_MURX */
12711 	}
12712 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
12713 	else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
12714 		bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
12715 	}
12716 	else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
12717 		bytes_written = wl_android_set_ap_beaconrate(net, command);
12718 	}
12719 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
12720 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12721 	else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
12722 		bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
12723 	}
12724 	else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
12725 		bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
12726 	}
12727 	else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
12728 		bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
12729 	}
12730 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12731 #ifdef SUPPORT_AP_SUSPEND
12732 	else if (strnicmp(command, CMD_SET_AP_SUSPEND, strlen(CMD_SET_AP_SUSPEND)) == 0) {
12733 		bytes_written = wl_android_set_ap_suspend(net, command, priv_cmd.total_len);
12734 	}
12735 #endif /* SUPPORT_AP_SUSPEND */
12736 #ifdef SUPPORT_AP_BWCTRL
12737 	else if (strnicmp(command, CMD_SET_AP_BW, strlen(CMD_SET_AP_BW)) == 0) {
12738 		bytes_written = wl_android_set_ap_bw(net, command, priv_cmd.total_len);
12739 	}
12740 	else if (strnicmp(command, CMD_GET_AP_BW, strlen(CMD_GET_AP_BW)) == 0) {
12741 		bytes_written = wl_android_get_ap_bw(net, command, priv_cmd.total_len);
12742 	}
12743 #endif /* SUPPORT_AP_BWCTRL */
12744 #ifdef SUPPORT_RSSI_SUM_REPORT
12745 	else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
12746 		bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
12747 	}
12748 	else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
12749 		bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
12750 	}
12751 	else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
12752 		bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
12753 	}
12754 #endif /* SUPPORT_RSSI_SUM_REPORT */
12755 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
12756 	else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
12757 		bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
12758 	}
12759 	else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
12760 			== 0) {
12761 		bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
12762 				priv_cmd.total_len);
12763 	}
12764 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
12765 #if defined(SUPPORT_RANDOM_MAC_SCAN)
12766 	else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
12767 		bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
12768 	} else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
12769 		bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
12770 	}
12771 #endif /* SUPPORT_RANDOM_MAC_SCAN */
12772 #ifdef WL_NATOE
12773 	else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
12774 		bytes_written = wl_android_process_natoe_cmd(net, command,
12775 				priv_cmd.total_len);
12776 	}
12777 #endif /* WL_NATOE */
12778 #ifdef CONNECTION_STATISTICS
12779 	else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
12780 		strlen(CMD_GET_CONNECTION_STATS)) == 0) {
12781 		bytes_written = wl_android_get_connection_stats(net, command,
12782 			priv_cmd.total_len);
12783 	}
12784 #endif
12785 #ifdef DHD_LOG_DUMP
12786 	else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
12787 		strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
12788 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12789 		/* check whether it has more command */
12790 		if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
12791 			/* compare unwanted/disconnected command */
12792 			if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12793 				SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
12794 				dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
12795 			} else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12796 				SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
12797 				dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
12798 			} else {
12799 				dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12800 			}
12801 		} else {
12802 			dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12803 		}
12804 	}
12805 #endif /* DHD_LOG_DUMP */
12806 #ifdef DHD_STATUS_LOGGING
12807 	else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) {
12808 		dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
12809 	}
12810 	else if (strnicmp(command, CMD_QUERY_STATUS_LOG, strlen(CMD_QUERY_STATUS_LOG)) == 0) {
12811 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12812 		bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
12813 	}
12814 #endif /* DHD_STATUS_LOGGING */
12815 #if defined(CONFIG_TIZEN)
12816 	else if (strnicmp(command, CMD_POWERSAVEMODE_SET,
12817 			strlen(CMD_POWERSAVEMODE_SET)) == 0) {
12818 		bytes_written = wl_android_set_powersave_mode(net, command,
12819 			priv_cmd.total_len);
12820 	}
12821 	else if (strnicmp(command, CMD_POWERSAVEMODE_GET,
12822 			strlen(CMD_POWERSAVEMODE_GET)) == 0) {
12823 		bytes_written = wl_android_get_powersave_mode(net, command,
12824 			priv_cmd.total_len);
12825 	}
12826 #endif /* CONFIG_TIZEN */
12827 #ifdef SET_PCIE_IRQ_CPU_CORE
12828 	else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
12829 		int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
12830 		wl_android_set_irq_cpucore(net, affinity_cmd);
12831 	}
12832 #endif /* SET_PCIE_IRQ_CPU_CORE */
12833 #if defined(DHD_HANG_SEND_UP_TEST)
12834 	else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
12835 		int skip = strlen(CMD_MAKE_HANG) + 1;
12836 		wl_android_make_hang_with_reason(net, (const char*)command+skip);
12837 	}
12838 #endif /* DHD_HANG_SEND_UP_TEST */
12839 #ifdef SUPPORT_LQCM
12840 	else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
12841 		int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
12842 		bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
12843 	}
12844 	else if (strnicmp(command, CMD_GET_LQCM_REPORT,
12845 			strlen(CMD_GET_LQCM_REPORT)) == 0) {
12846 		bytes_written = wl_android_get_lqcm_report(net, command,
12847 			priv_cmd.total_len);
12848 	}
12849 #endif
12850 	else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
12851 		bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
12852 	}
12853 #ifdef WLADPS_PRIVATE_CMD
12854 	else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
12855 		int skip = strlen(CMD_SET_ADPS) + 1;
12856 		bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
12857 	}
12858 	else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
12859 		bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
12860 	}
12861 #ifdef WLADPS_ENERGY_GAIN
12862 	else if (strnicmp(command, CMD_GET_GAIN_ADPS, strlen(CMD_GET_GAIN_ADPS)) == 0) {
12863 		bytes_written = wl_android_get_gain_adps(net, command, priv_cmd.total_len);
12864 	}
12865 	else if (strnicmp(command, CMD_RESET_GAIN_ADPS, strlen(CMD_RESET_GAIN_ADPS)) == 0) {
12866 		bytes_written = wl_android_reset_gain_adps(net, command);
12867 	}
12868 #endif	/* WLADPS_ENERGY_GAIN */
12869 #endif /* WLADPS_PRIVATE_CMD */
12870 #ifdef DHD_PKT_LOGGING
12871 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
12872 		strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
12873 		bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
12874 	}
12875 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
12876 		strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
12877 		bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
12878 	}
12879 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
12880 		strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
12881 		bytes_written =
12882 			wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
12883 	}
12884 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
12885 		strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
12886 		bytes_written =
12887 			wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
12888 	}
12889 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
12890 		bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
12891 	}
12892 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DEL, strlen(CMD_PKTLOG_FILTER_DEL)) == 0) {
12893 		bytes_written = wl_android_pktlog_filter_del(net, command, priv_cmd.total_len);
12894 	}
12895 	else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
12896 		bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
12897 	}
12898 	else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
12899 		bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
12900 	}
12901 	else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
12902 		bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
12903 	}
12904 	else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
12905 		bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
12906 	}
12907 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
12908 		strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
12909 		bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
12910 	}
12911 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
12912 		strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
12913 		bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
12914 	}
12915 	else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
12916 		strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
12917 		bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
12918 	}
12919 	else if (strnicmp(command, CMD_PKTLOG_DEBUG_DUMP, strlen(CMD_PKTLOG_DEBUG_DUMP)) == 0) {
12920 		bytes_written = wl_android_pktlog_dbg_dump(net, command, priv_cmd.total_len);
12921 	}
12922 #endif /* DHD_PKT_LOGGING */
12923 #ifdef WL_CFG80211
12924 	else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
12925 		int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
12926 		bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
12927 	}
12928 #endif /* WL_CFG80211 */
12929 #ifdef DHD_EVENT_LOG_FILTER
12930 	else if (strnicmp(command, CMD_EWP_FILTER,
12931 		strlen(CMD_EWP_FILTER)) == 0) {
12932 		bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
12933 	}
12934 #endif /* DHD_EVENT_LOG_FILTER */
12935 #ifdef WL_BCNRECV
12936 	else if (strnicmp(command, CMD_BEACON_RECV,
12937 		strlen(CMD_BEACON_RECV)) == 0) {
12938 		char *data = (command + strlen(CMD_BEACON_RECV) + 1);
12939 		bytes_written = wl_android_bcnrecv_config(net,
12940 				data, priv_cmd.total_len);
12941 	}
12942 #endif /* WL_BCNRECV */
12943 #ifdef WL_MBO
12944 	else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
12945 		bytes_written = wl_android_process_mbo_cmd(net, command,
12946 			priv_cmd.total_len);
12947 	}
12948 #endif /* WL_MBO */
12949 #ifdef WL_CAC_TS
12950 	else if (strnicmp(command, CMD_CAC_TSPEC,
12951 		strlen(CMD_CAC_TSPEC)) == 0) {
12952 		char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
12953 		bytes_written = wl_android_cac_ts_config(net,
12954 				data, priv_cmd.total_len);
12955 	}
12956 #endif /* WL_CAC_TS */
12957 #ifdef WL_GET_CU
12958 	else if (strnicmp(command, CMD_GET_CHAN_UTIL,
12959 		strlen(CMD_GET_CHAN_UTIL)) == 0) {
12960 		bytes_written = wl_android_get_channel_util(net,
12961 			command, priv_cmd.total_len);
12962 	}
12963 #endif /* WL_GET_CU */
12964 #ifdef RTT_GEOFENCE_INTERVAL
12965 #if defined (RTT_SUPPORT) && defined(WL_NAN)
12966 	else if (strnicmp(command, CMD_GEOFENCE_INTERVAL,
12967 			strlen(CMD_GEOFENCE_INTERVAL)) == 0) {
12968 		(void)wl_android_set_rtt_geofence_interval(net, command);
12969 	}
12970 #endif /* RTT_SUPPORT && WL_NAN */
12971 #endif /* RTT_GEOFENCE_INTERVAL */
12972 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
12973 	else if (strnicmp(command, CMD_SET_SOFTAP_ELNA_BYPASS,
12974 			strlen(CMD_SET_SOFTAP_ELNA_BYPASS)) == 0) {
12975 		bytes_written =
12976 			wl_android_set_softap_elna_bypass(net, command, priv_cmd.total_len);
12977 	}
12978 	else if (strnicmp(command, CMD_GET_SOFTAP_ELNA_BYPASS,
12979 			strlen(CMD_GET_SOFTAP_ELNA_BYPASS)) == 0) {
12980 		bytes_written =
12981 			wl_android_get_softap_elna_bypass(net, command, priv_cmd.total_len);
12982 	}
12983 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
12984 #ifdef WL_NAN
12985 	else if (strnicmp(command, CMD_GET_NAN_STATUS,
12986 			strlen(CMD_GET_NAN_STATUS)) == 0) {
12987 		bytes_written =
12988 			wl_android_get_nan_status(net, command, priv_cmd.total_len);
12989 	}
12990 #endif /* WL_NAN */
12991 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
12992 	else if (strnicmp(command, CMD_NAN_RANGING_SET_BW, strlen(CMD_NAN_RANGING_SET_BW)) == 0) {
12993 		int bw_cmd = *(command + strlen(CMD_NAN_RANGING_SET_BW) + 1) - '0';
12994 		bytes_written = wl_nan_ranging_bw(net, bw_cmd, command);
12995 	}
12996 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
12997 	else if (strnicmp(command, CMD_GET_FACTORY_MAC, strlen(CMD_GET_FACTORY_MAC)) == 0) {
12998 		bytes_written = wl_android_get_factory_mac_addr(net, command, priv_cmd.total_len);
12999 	}
13000 	else if (strnicmp(command, CMD_HAPD_SET_AX_MODE, strlen(CMD_HAPD_SET_AX_MODE)) == 0) {
13001 		int skip = strlen(CMD_HAPD_SET_AX_MODE) + 1;
13002 		bytes_written = wl_android_set_softap_ax_mode(net, command + skip);
13003 	}
13004 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
13005 	else if (strnicmp(command, CMD_SET_LATENCY_CRITICAL_DATA,
13006 		strlen(CMD_SET_LATENCY_CRITICAL_DATA)) == 0) {
13007 		int enable = *(command + strlen(CMD_SET_LATENCY_CRITICAL_DATA) + 1) - '0';
13008 		bytes_written = wl_android_set_latency_crt_data(net, enable);
13009 	}
13010 	else if  (strnicmp(command, CMD_GET_LATENCY_CRITICAL_DATA,
13011 		strlen(CMD_GET_LATENCY_CRITICAL_DATA)) == 0) {
13012 		bytes_written = wl_android_get_latency_crt_data(net, command, priv_cmd.total_len);
13013 	}
13014 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
13015 #ifdef WL_TWT
13016 	else if (strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) {
13017 		bytes_written = wl_android_twt_setup(net, command, priv_cmd.total_len);
13018 	}
13019 	else if (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) {
13020 		bytes_written = wl_android_twt_teardown(net, command, priv_cmd.total_len);
13021 	}
13022 	else if (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0) {
13023 		bytes_written = wl_android_twt_info(net, command, priv_cmd.total_len);
13024 	}
13025 	else if (strnicmp(command, CMD_TWT_STATUS_QUERY, strlen(CMD_TWT_STATUS_QUERY)) == 0) {
13026 		bytes_written = wl_android_twt_status_query(net, command, priv_cmd.total_len);
13027 	}
13028 	else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) {
13029 		bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len);
13030 	}
13031 	else if ((strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)) == 0) ||
13032 		(strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)) == 0)) {
13033 		bytes_written = wl_android_twt_stats(net, command, priv_cmd.total_len);
13034 	}
13035 #endif /* WL_TWT */
13036 #ifdef WL_P2P_6G
13037 	else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) {
13038 		int enable = *(command + strlen(CMD_ENABLE_6G_P2P) + 1) - '0';
13039 		bytes_written = wl_android_enable_p2p_6g(net, enable);
13040 	}
13041 #endif /* WL_P2P_6G */
13042 	else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len, &bytes_written) == 0) {
13043 	}
13044 	else {
13045 		ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
13046 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
13047 	}
13048 
13049 	return bytes_written;
13050 }
13051 
13052 /*
13053 * ENABLE_INSMOD_NO_FW_LOAD	X O O O
13054 * ENABLE_INSMOD_NO_POWER_OFF	X X O O
13055 * NO_POWER_OFF_AFTER_OPEN	X X X O
13056 * after insmod					H L H H
13057 * wlan0 down					H L L H
13058 * fw trap trigger wlan0 down		H L L L
13059 */
13060 
wl_android_init(void)13061 int wl_android_init(void)
13062 {
13063 	int ret = 0;
13064 
13065 #ifdef ENABLE_INSMOD_NO_POWER_OFF
13066 	dhd_download_fw_on_driverload = TRUE;
13067 #elif defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE)
13068 	dhd_download_fw_on_driverload = FALSE;
13069 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
13070 	if (!iface_name[0]) {
13071 		bzero(iface_name, IFNAMSIZ);
13072 		bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
13073 	}
13074 
13075 #ifdef CUSTOMER_HW4_DEBUG
13076 	/* No Kernel Panic from ASSERT() on customer platform. */
13077 	g_assert_type = 1;
13078 #endif /* CUSTOMER_HW4_DEBUG */
13079 
13080 #ifdef WL_GENL
13081 	wl_genl_init();
13082 #endif
13083 #ifdef WL_RELMCAST
13084 	wl_netlink_init();
13085 #endif /* WL_RELMCAST */
13086 
13087 	return ret;
13088 }
13089 
wl_android_exit(void)13090 int wl_android_exit(void)
13091 {
13092 	int ret = 0;
13093 	struct io_cfg *cur, *q;
13094 
13095 #ifdef WL_GENL
13096 	wl_genl_deinit();
13097 #endif /* WL_GENL */
13098 #ifdef WL_RELMCAST
13099 	wl_netlink_deinit();
13100 #endif /* WL_RELMCAST */
13101 
13102 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
13103 	list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
13104 		GCC_DIAGNOSTIC_POP();
13105 		list_del(&cur->list);
13106 		kfree(cur);
13107 	}
13108 
13109 	return ret;
13110 }
13111 
wl_android_post_init(void)13112 void wl_android_post_init(void)
13113 {
13114 
13115 #ifdef ENABLE_4335BT_WAR
13116 	bcm_bt_unlock(lock_cookie_wifi);
13117 	ANDROID_ERROR(("%s: btlock released\n", __FUNCTION__));
13118 #endif /* ENABLE_4335BT_WAR */
13119 
13120 	if (!dhd_download_fw_on_driverload) {
13121 		g_wifi_on = FALSE;
13122 	}
13123 }
13124 
13125 #ifdef WL_GENL
13126 /* Generic Netlink Initializaiton */
wl_genl_init(void)13127 static int wl_genl_init(void)
13128 {
13129 	int ret;
13130 
13131 	ANDROID_INFO(("GEN Netlink Init\n\n"));
13132 
13133 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13134 	/* register new family */
13135 	ret = genl_register_family(&wl_genl_family);
13136 	if (ret != 0)
13137 		goto failure;
13138 
13139 	/* register functions (commands) of the new family */
13140 	ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
13141 	if (ret != 0) {
13142 		ANDROID_ERROR(("register ops failed: %i\n", ret));
13143 		genl_unregister_family(&wl_genl_family);
13144 		goto failure;
13145 	}
13146 
13147 	ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
13148 #else
13149 	ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
13150 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
13151 	if (ret != 0) {
13152 		ANDROID_ERROR(("register mc_group failed: %i\n", ret));
13153 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13154 		genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
13155 #endif
13156 		genl_unregister_family(&wl_genl_family);
13157 		goto failure;
13158 	}
13159 
13160 	return 0;
13161 
13162 failure:
13163 	ANDROID_ERROR(("Registering Netlink failed!!\n"));
13164 	return -1;
13165 }
13166 
13167 /* Generic netlink deinit */
wl_genl_deinit(void)13168 static int wl_genl_deinit(void)
13169 {
13170 
13171 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13172 	if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
13173 		ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13174 #endif
13175 	if (genl_unregister_family(&wl_genl_family) < 0)
13176 		ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13177 
13178 	return 0;
13179 }
13180 
wl_event_to_bcm_event(u16 event_type)13181 s32 wl_event_to_bcm_event(u16 event_type)
13182 {
13183 	/* When you add any new event, please mention the
13184 	 * version of BCM supplicant supporting it
13185 	 */
13186 	u16 event = -1;
13187 
13188 	switch (event_type) {
13189 		case WLC_E_SERVICE_FOUND:
13190 			event = BCM_E_SVC_FOUND;
13191 			break;
13192 		case WLC_E_P2PO_ADD_DEVICE:
13193 			event = BCM_E_DEV_FOUND;
13194 			break;
13195 		case WLC_E_P2PO_DEL_DEVICE:
13196 			event = BCM_E_DEV_LOST;
13197 			break;
13198 	/* Above events are supported from BCM Supp ver 47 Onwards */
13199 #ifdef BT_WIFI_HANDOVER
13200 		case WLC_E_BT_WIFI_HANDOVER_REQ:
13201 			event = BCM_E_DEV_BT_WIFI_HO_REQ;
13202 			break;
13203 #endif /* BT_WIFI_HANDOVER */
13204 
13205 		default:
13206 			ANDROID_ERROR(("Event not supported\n"));
13207 	}
13208 
13209 	return event;
13210 }
13211 
13212 s32
wl_genl_send_msg(struct net_device * ndev,u32 event_type,const u8 * buf,u16 len,u8 * subhdr,u16 subhdr_len)13213 wl_genl_send_msg(
13214 	struct net_device *ndev,
13215 	u32 event_type,
13216 	const u8 *buf,
13217 	u16 len,
13218 	u8 *subhdr,
13219 	u16 subhdr_len)
13220 {
13221 	int ret = 0;
13222 	struct sk_buff *skb;
13223 	void *msg;
13224 	u32 attr_type = 0;
13225 	bcm_event_hdr_t *hdr = NULL;
13226 	int mcast = 1; /* By default sent as mutlicast type */
13227 	int pid = 0;
13228 	u8 *ptr = NULL, *p = NULL;
13229 	u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
13230 	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13231 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13232 
13233 	ANDROID_INFO(("Enter \n"));
13234 
13235 	/* Decide between STRING event and Data event */
13236 	if (event_type == 0)
13237 		attr_type = BCM_GENL_ATTR_STRING;
13238 	else
13239 		attr_type = BCM_GENL_ATTR_MSG;
13240 
13241 	skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
13242 	if (skb == NULL) {
13243 		ret = -ENOMEM;
13244 		goto out;
13245 	}
13246 
13247 	msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
13248 	if (msg == NULL) {
13249 		ret = -ENOMEM;
13250 		goto out;
13251 	}
13252 
13253 	if (attr_type == BCM_GENL_ATTR_STRING) {
13254 		/* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
13255 		 * make sure it is null terminated
13256 		 */
13257 		if (subhdr || subhdr_len) {
13258 			ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n"));
13259 			ret =  -EINVAL;
13260 			goto out;
13261 		}
13262 
13263 		ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
13264 		if (ret != 0) {
13265 			ANDROID_ERROR(("nla_put_string failed\n"));
13266 			goto out;
13267 		}
13268 	} else {
13269 		/* ATTR_MSG */
13270 
13271 		/* Create a single buffer for all */
13272 		p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
13273 		if (!ptr) {
13274 			ret = -ENOMEM;
13275 			ANDROID_ERROR(("ENOMEM!!\n"));
13276 			goto out;
13277 		}
13278 
13279 		/* Include the bcm event header */
13280 		hdr = (bcm_event_hdr_t *)ptr;
13281 		hdr->event_type = wl_event_to_bcm_event(event_type);
13282 		hdr->len = len + subhdr_len;
13283 		ptr += sizeof(bcm_event_hdr_t);
13284 
13285 		/* Copy subhdr (if any) */
13286 		if (subhdr && subhdr_len) {
13287 			memcpy(ptr, subhdr, subhdr_len);
13288 			ptr += subhdr_len;
13289 		}
13290 
13291 		/* Copy the data */
13292 		if (buf && len) {
13293 			memcpy(ptr, buf, len);
13294 		}
13295 
13296 		ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
13297 		if (ret != 0) {
13298 			ANDROID_ERROR(("nla_put_string failed\n"));
13299 			goto out;
13300 		}
13301 	}
13302 
13303 	if (mcast) {
13304 		int err = 0;
13305 		/* finalize the message */
13306 		genlmsg_end(skb, msg);
13307 		/* NETLINK_CB(skb).dst_group = 1; */
13308 
13309 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
13310 		if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
13311 #else
13312 		if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
13313 #endif
13314 			ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
13315 				attr_type, err));
13316 		else
13317 			ANDROID_INFO(("Multicast msg sent successfully. attr_type:%d len:%d \n",
13318 				attr_type, tot_len));
13319 	} else {
13320 		NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
13321 
13322 		/* finalize the message */
13323 		genlmsg_end(skb, msg);
13324 
13325 		/* send the message back */
13326 		if (genlmsg_unicast(&init_net, skb, pid) < 0)
13327 			ANDROID_ERROR(("genlmsg_unicast failed\n"));
13328 	}
13329 
13330 out:
13331 	if (p) {
13332 		MFREE(cfg->osh, p, tot_len);
13333 	}
13334 	if (ret)
13335 		nlmsg_free(skb);
13336 
13337 	return ret;
13338 }
13339 
13340 static s32
wl_genl_handle_msg(struct sk_buff * skb,struct genl_info * info)13341 wl_genl_handle_msg(
13342 	struct sk_buff *skb,
13343 	struct genl_info *info)
13344 {
13345 	struct nlattr *na;
13346 	u8 *data = NULL;
13347 
13348 	ANDROID_INFO(("Enter \n"));
13349 
13350 	if (info == NULL) {
13351 		return -EINVAL;
13352 	}
13353 
13354 	na = info->attrs[BCM_GENL_ATTR_MSG];
13355 	if (!na) {
13356 		ANDROID_ERROR(("nlattribute NULL\n"));
13357 		return -EINVAL;
13358 	}
13359 
13360 	data = (char *)nla_data(na);
13361 	if (!data) {
13362 		ANDROID_ERROR(("Invalid data\n"));
13363 		return -EINVAL;
13364 	} else {
13365 		/* Handle the data */
13366 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || \
13367 	defined(WL_COMPAT_WIRELESS)
13368 		ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13369 			info->snd_pid));
13370 #else
13371 		ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13372 			info->snd_portid));
13373 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
13374 	}
13375 
13376 	return 0;
13377 }
13378 #endif /* WL_GENL */
13379 
wl_fatal_error(void * wl,int rc)13380 int wl_fatal_error(void * wl, int rc)
13381 {
13382 	return FALSE;
13383 }
13384 
13385 void
wl_android_set_wifi_on_flag(bool enable)13386 wl_android_set_wifi_on_flag(bool enable)
13387 {
13388 	ANDROID_ERROR(("%s: %d\n", __FUNCTION__, enable));
13389 	g_wifi_on = enable;
13390 }
13391 
13392 #ifdef WL_STATIC_IF
13393 #include <dhd_linux_priv.h>
13394 struct net_device *
wl_cfg80211_register_static_if(struct bcm_cfg80211 * cfg,u16 iftype,char * ifname,int static_ifidx)13395 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname,
13396 	int static_ifidx)
13397 {
13398 #if defined(CUSTOM_MULTI_MAC) || defined(WL_EXT_IAPSTA)
13399 	dhd_pub_t *dhd = cfg->pub;
13400 #endif
13401 	struct net_device *ndev;
13402 	struct wireless_dev *wdev = NULL;
13403 	int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
13404 	u8 mac_addr[ETH_ALEN];
13405 	struct net_device *primary_ndev;
13406 #ifdef DHD_USE_RANDMAC
13407 	struct ether_addr ea_addr;
13408 #endif /* DHD_USE_RANDMAC */
13409 #ifdef CUSTOM_MULTI_MAC
13410 	char hw_ether[62];
13411 #endif
13412 
13413 	ANDROID_INFO(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
13414 
13415 	if (!cfg) {
13416 		ANDROID_ERROR(("cfg null\n"));
13417 		return NULL;
13418 	}
13419 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13420 
13421 	ifidx += static_ifidx;
13422 #ifdef DHD_USE_RANDMAC
13423 	wl_cfg80211_generate_mac_addr(&ea_addr);
13424 	(void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN);
13425 #else
13426 #if defined(CUSTOM_MULTI_MAC)
13427 	if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) {
13428 		(void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN);
13429 	} else
13430 #endif
13431 	{
13432 		/* Use primary mac with locally admin bit set */
13433 		(void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
13434 		mac_addr[0] |= 0x02;
13435 #ifdef WL_EXT_IAPSTA
13436 		wl_ext_iapsta_get_vif_macaddr(dhd, static_ifidx+1, mac_addr);
13437 #endif
13438 	}
13439 #endif /* DHD_USE_RANDMAC */
13440 
13441 	ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
13442 		WL_BSSIDX_MAX, NULL);
13443 	if (unlikely(!ndev)) {
13444 		ANDROID_ERROR(("Failed to allocate static_if\n"));
13445 		goto fail;
13446 	}
13447 	wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
13448 	if (unlikely(!wdev)) {
13449 		ANDROID_ERROR(("Failed to allocate wdev for static_if\n"));
13450 		goto fail;
13451 	}
13452 
13453 	wdev->wiphy = cfg->wdev->wiphy;
13454 	wdev->iftype = iftype;
13455 
13456 	ndev->ieee80211_ptr = wdev;
13457 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
13458 	wdev->netdev = ndev;
13459 
13460 	if (wl_cfg80211_register_if(cfg, ifidx,
13461 		ndev, TRUE) != BCME_OK) {
13462 		ANDROID_ERROR(("ndev registration failed!\n"));
13463 		goto fail;
13464 	}
13465 
13466 	cfg->static_ndev[static_ifidx] = ndev;
13467 	cfg->static_ndev_state[static_ifidx] = NDEV_STATE_OS_IF_CREATED;
13468 	wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
13469 		ifname, NDEV_STATE_OS_IF_CREATED);
13470 	ANDROID_INFO(("Static I/F (%s) Registered\n", ndev->name));
13471 	return ndev;
13472 
13473 fail:
13474 	wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
13475 	return NULL;
13476 }
13477 
13478 void
wl_cfg80211_unregister_static_if(struct bcm_cfg80211 * cfg)13479 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
13480 {
13481 	int i;
13482 
13483 	ANDROID_INFO(("[STATIC_IF] Enter\n"));
13484 	if (!cfg) {
13485 		ANDROID_ERROR(("invalid input\n"));
13486 		return;
13487 	}
13488 
13489 	/* wdev free will happen from notifier context */
13490 	/* free_netdev(cfg->static_ndev);
13491 	*/
13492 	for (i=0; i<DHD_MAX_STATIC_IFS; i++) {
13493 		if (cfg->static_ndev[i])
13494 			unregister_netdev(cfg->static_ndev[i]);
13495 	}
13496 }
13497 
13498 s32
wl_cfg80211_static_if_open(struct net_device * net)13499 wl_cfg80211_static_if_open(struct net_device *net)
13500 {
13501 	struct wireless_dev *wdev = NULL;
13502 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13503 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13504 	u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
13505 	u16 wl_iftype, wl_mode;
13506 #ifdef CUSTOM_MULTI_MAC
13507 	dhd_pub_t *dhd = dhd_get_pub(net);
13508 	char hw_ether[62];
13509 #endif
13510 	int static_ifidx;
13511 
13512 	ANDROID_INFO(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
13513 	static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
13514 	ASSERT(static_ifidx >= 0);
13515 
13516 	if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) <  0) {
13517 		return BCME_ERROR;
13518 	}
13519 	if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) {
13520 #ifdef CUSTOM_MULTI_MAC
13521 		if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1))
13522 			dev_addr_set(net, hw_ether);
13523 #endif
13524 		wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr);
13525 		if (!wdev) {
13526 			ANDROID_ERROR(("[STATIC_IF] wdev is NULL, can't proceed\n"));
13527 			return BCME_ERROR;
13528 		}
13529 	} else {
13530 		ANDROID_INFO(("Fw IF for static netdev already created\n"));
13531 	}
13532 
13533 	return BCME_OK;
13534 }
13535 
13536 s32
wl_cfg80211_static_if_close(struct net_device * net)13537 wl_cfg80211_static_if_close(struct net_device *net)
13538 {
13539 	int ret = BCME_OK;
13540 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13541 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13542 	int static_ifidx;
13543 
13544 	static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
13545 
13546 	if (cfg->static_ndev_state[static_ifidx] == NDEV_STATE_FW_IF_CREATED) {
13547 		if (mutex_is_locked(&cfg->if_sync) == TRUE) {
13548 			ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13549 		} else {
13550 			ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13551 		}
13552 
13553 		if (unlikely(ret)) {
13554 			ANDROID_ERROR(("Del iface failed for static_if %d\n", ret));
13555 		}
13556 	}
13557 
13558 	return ret;
13559 }
13560 struct net_device *
wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 * cfg,wl_if_event_info * event,u8 * addr,s32 iface_type,int static_ifidx)13561 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
13562 	wl_if_event_info *event, u8 *addr, s32 iface_type, int static_ifidx)
13563 {
13564 	struct net_device *new_ndev = NULL;
13565 	struct wireless_dev *wdev = NULL;
13566 
13567 	ANDROID_INFO(("Updating static iface after Fw IF create \n"));
13568 	new_ndev = cfg->static_ndev[static_ifidx];
13569 
13570 	if (new_ndev) {
13571 		wdev = new_ndev->ieee80211_ptr;
13572 		ASSERT(wdev);
13573 		wdev->iftype = iface_type;
13574 		dev_addr_set(new_ndev, addr);
13575 	}
13576 
13577 	cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED;
13578 	wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
13579 		event->name, NDEV_STATE_FW_IF_CREATED);
13580 	return new_ndev;
13581 }
13582 s32
wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 * cfg,struct net_device * ndev)13583 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13584 {
13585 	int static_ifidx;
13586 	int ifidx = WL_STATIC_IFIDX;
13587 
13588 	static_ifidx = wl_cfg80211_static_ifidx(cfg, ndev);
13589 	ifidx += static_ifidx;
13590 	cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_DELETED;
13591 	wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL,
13592 		WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
13593 	wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
13594 	wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
13595 	return BCME_OK;
13596 }
13597 #endif /* WL_STATIC_IF */
13598 
13599 #ifdef WBTEXT
13600 static int
wlc_wbtext_get_roam_prof(struct net_device * ndev,wl_roamprof_band_t * rp,uint8 band,uint8 * roam_prof_ver,uint8 * roam_prof_size)13601 wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
13602 	uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size)
13603 {
13604 	int err = BCME_OK;
13605 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13606 	u8 *ioctl_buf = NULL;
13607 
13608 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13609 	if (unlikely(!ioctl_buf)) {
13610 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13611 		err =  -ENOMEM;
13612 		goto exit;
13613 	}
13614 	rp->v1.band = band;
13615 	rp->v1.len = 0;
13616 	/* Getting roam profile from fw */
13617 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13618 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13619 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13620 		goto exit;
13621 	}
13622 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13623 	/* roam_prof version get */
13624 	if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13625 		ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13626 		err = BCME_VERSION;
13627 		goto exit;
13628 	}
13629 	switch (rp->v1.ver) {
13630 		case WL_ROAM_PROF_VER_0:
13631 		{
13632 			*roam_prof_size = sizeof(wl_roam_prof_v1_t);
13633 			*roam_prof_ver = WL_ROAM_PROF_VER_0;
13634 		}
13635 		break;
13636 		case WL_ROAM_PROF_VER_1:
13637 		{
13638 			*roam_prof_size = sizeof(wl_roam_prof_v2_t);
13639 			*roam_prof_ver = WL_ROAM_PROF_VER_1;
13640 		}
13641 		break;
13642 		case WL_ROAM_PROF_VER_2:
13643 		{
13644 			*roam_prof_size = sizeof(wl_roam_prof_v3_t);
13645 			*roam_prof_ver = WL_ROAM_PROF_VER_2;
13646 		}
13647 		break;
13648 		case WL_ROAM_PROF_VER_3:
13649 		{
13650 			*roam_prof_size = sizeof(wl_roam_prof_v4_t);
13651 			*roam_prof_ver = WL_ROAM_PROF_VER_3;
13652 		}
13653 		break;
13654 		default:
13655 			ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13656 			err = BCME_VERSION;
13657 			goto exit;
13658 	}
13659 	ANDROID_INFO(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size));
13660 	if ((rp->v1.len % *roam_prof_size) != 0) {
13661 		ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13662 		err = BCME_BADLEN;
13663 	}
13664 exit:
13665 	if (ioctl_buf) {
13666 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13667 	}
13668 	return err;
13669 }
13670 
13671 s32
wl_cfg80211_wbtext_set_default(struct net_device * ndev)13672 wl_cfg80211_wbtext_set_default(struct net_device *ndev)
13673 {
13674 	char *commandp = NULL;
13675 	s32 ret = BCME_OK;
13676 	char *data;
13677 	u8 *ioctl_buf = NULL;
13678 	wl_roamprof_band_t rp;
13679 	uint8 bandidx = 0;
13680 	int wnmmask = 0;
13681 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13682 
13683 	ANDROID_INFO(("set wbtext to default\n"));
13684 
13685 	commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13686 	if (unlikely(!commandp)) {
13687 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13688 		ret =  -ENOMEM;
13689 		goto exit;
13690 	}
13691 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13692 	if (unlikely(!ioctl_buf)) {
13693 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13694 		ret =  -ENOMEM;
13695 		goto exit;
13696 	}
13697 
13698 	rp.v1.band = WLC_BAND_2G;
13699 	rp.v1.len = 0;
13700 	/* Getting roam profile from fw */
13701 	if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp),
13702 		ioctl_buf, WLC_IOCTL_SMLEN, NULL))) {
13703 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", ret));
13704 		goto exit;
13705 	}
13706 	memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp));
13707 	for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
13708 		switch (rp.v1.ver) {
13709 			case WL_ROAM_PROF_VER_1:
13710 			{
13711 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13712 				if (bandidx == BAND_5G_INDEX) {
13713 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13714 						CMD_WBTEXT_PROFILE_CONFIG,
13715 						DEFAULT_WBTEXT_PROFILE_A_V2);
13716 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13717 				} else {
13718 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13719 						CMD_WBTEXT_PROFILE_CONFIG,
13720 						DEFAULT_WBTEXT_PROFILE_B_V2);
13721 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13722 				}
13723 			}
13724 			break;
13725 			case WL_ROAM_PROF_VER_2:
13726 			case WL_ROAM_PROF_VER_3:
13727 			{
13728 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13729 				if (bandidx == BAND_5G_INDEX) {
13730 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13731 						CMD_WBTEXT_PROFILE_CONFIG,
13732 						DEFAULT_WBTEXT_PROFILE_A_V3);
13733 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13734 				} else {
13735 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13736 						CMD_WBTEXT_PROFILE_CONFIG,
13737 						DEFAULT_WBTEXT_PROFILE_B_V3);
13738 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13739 				}
13740 			}
13741 			break;
13742 			default:
13743 				ANDROID_ERROR(("No Support for roam prof ver = %d \n", rp.v1.ver));
13744 				ret = -EINVAL;
13745 				goto exit;
13746 		}
13747 		/* set roam profile */
13748 		ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13749 		if (ret != BCME_OK) {
13750 			ANDROID_ERROR(("%s: Failed to set roam_prof %s error = %d\n",
13751 				__FUNCTION__, data, ret));
13752 			goto exit;
13753 		}
13754 	}
13755 
13756 	/* wbtext code for backward compatibility. Newer firmwares set default value
13757 	* from fw init
13758 	*/
13759 	/* set RSSI weight */
13760 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13761 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13762 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
13763 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13764 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13765 	if (ret != BCME_OK) {
13766 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13767 			__FUNCTION__, data, ret));
13768 		goto exit;
13769 	}
13770 
13771 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13772 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13773 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
13774 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13775 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13776 	if (ret != BCME_OK) {
13777 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13778 			__FUNCTION__, data, ret));
13779 		goto exit;
13780 	}
13781 
13782 	/* set CU weight */
13783 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13784 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13785 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
13786 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13787 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13788 	if (ret != BCME_OK) {
13789 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13790 			__FUNCTION__, data, ret));
13791 		goto exit;
13792 	}
13793 
13794 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13795 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13796 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
13797 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13798 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13799 	if (ret != BCME_OK) {
13800 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13801 			__FUNCTION__, data, ret));
13802 		goto exit;
13803 	}
13804 
13805 	ret = wldev_iovar_getint(ndev, "wnm", &wnmmask);
13806 	if (ret != BCME_OK) {
13807 		ANDROID_ERROR(("%s: Failed to get wnmmask error = %d\n", __func__, ret));
13808 		goto exit;
13809 	}
13810 	/* set ESTM DL weight. */
13811 	if (wnmmask & WL_WNM_ESTM) {
13812 		ANDROID_ERROR(("Setting ESTM wt\n"));
13813 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13814 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13815 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A);
13816 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13817 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13818 		if (ret != BCME_OK) {
13819 			ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13820 				__FUNCTION__, data, ret));
13821 			goto exit;
13822 		}
13823 
13824 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13825 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13826 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B);
13827 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13828 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13829 		if (ret != BCME_OK) {
13830 			ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13831 				__FUNCTION__, data, ret));
13832 			goto exit;
13833 		}
13834 	}
13835 
13836 	/* set RSSI table */
13837 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13838 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13839 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
13840 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13841 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13842 	if (ret != BCME_OK) {
13843 		ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13844 			__FUNCTION__, data, ret));
13845 		goto exit;
13846 	}
13847 
13848 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13849 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13850 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
13851 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13852 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13853 	if (ret != BCME_OK) {
13854 		ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13855 			__FUNCTION__, data, ret));
13856 		goto exit;
13857 	}
13858 
13859 	/* set CU table */
13860 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13861 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13862 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
13863 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13864 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13865 	if (ret != BCME_OK) {
13866 		ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13867 			__FUNCTION__, data, ret));
13868 		goto exit;
13869 	}
13870 
13871 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13872 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13873 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
13874 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13875 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13876 	if (ret != BCME_OK) {
13877 		ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13878 			__FUNCTION__, data, ret));
13879 		goto exit;
13880 	}
13881 
13882 exit:
13883 	if (commandp) {
13884 		MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
13885 	}
13886 	if (ioctl_buf) {
13887 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_SMLEN);
13888 	}
13889 	return ret;
13890 }
13891 
13892 s32
wl_cfg80211_wbtext_config(struct net_device * ndev,char * data,char * command,int total_len)13893 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
13894 {
13895 	uint i = 0;
13896 	long int rssi_lower, roam_trigger;
13897 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13898 	wl_roamprof_band_t *rp = NULL;
13899 	int err = -EINVAL, bytes_written = 0;
13900 	size_t len = strlen(data);
13901 	int rp_len = 0;
13902 	u8 *ioctl_buf = NULL;
13903 	uint8 roam_prof_size = 0, roam_prof_ver = 0, fs_per = 0, prof_cnt = 0;
13904 
13905 	data[len] = '\0';
13906 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13907 	if (unlikely(!ioctl_buf)) {
13908 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13909 		err =  -ENOMEM;
13910 		goto exit;
13911 	}
13912 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
13913 	if (unlikely(!rp)) {
13914 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13915 		err =  -ENOMEM;
13916 		goto exit;
13917 	}
13918 	if (*data && (!strncmp(data, "b", 1))) {
13919 		rp->v1.band = WLC_BAND_2G;
13920 	} else if (*data && (!strncmp(data, "a", 1))) {
13921 		rp->v1.band = WLC_BAND_5G;
13922 	} else {
13923 		err = snprintf(command, total_len, "Missing band\n");
13924 		goto exit;
13925 	}
13926 	data++;
13927 	rp->v1.len = 0;
13928 	/* Getting roam profile from fw */
13929 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13930 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13931 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13932 		goto exit;
13933 	}
13934 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13935 	/* roam_prof version get */
13936 	if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13937 		ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13938 		err = -EINVAL;
13939 		goto exit;
13940 	}
13941 	switch (rp->v1.ver) {
13942 		case WL_ROAM_PROF_VER_0:
13943 		{
13944 			roam_prof_size = sizeof(wl_roam_prof_v1_t);
13945 			roam_prof_ver = WL_ROAM_PROF_VER_0;
13946 		}
13947 		break;
13948 		case WL_ROAM_PROF_VER_1:
13949 		{
13950 			roam_prof_size = sizeof(wl_roam_prof_v2_t);
13951 			roam_prof_ver = WL_ROAM_PROF_VER_1;
13952 		}
13953 		break;
13954 		case WL_ROAM_PROF_VER_2:
13955 		{
13956 			roam_prof_size = sizeof(wl_roam_prof_v3_t);
13957 			roam_prof_ver = WL_ROAM_PROF_VER_2;
13958 		}
13959 		break;
13960 		case WL_ROAM_PROF_VER_3:
13961 		{
13962 			roam_prof_size = sizeof(wl_roam_prof_v4_t);
13963 			roam_prof_ver = WL_ROAM_PROF_VER_3;
13964 		}
13965 		break;
13966 		default:
13967 			ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13968 			goto exit;
13969 	}
13970 	ANDROID_INFO(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size));
13971 	if ((rp->v1.len % roam_prof_size) != 0) {
13972 		ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13973 		err = -EINVAL;
13974 		goto exit;
13975 	}
13976 	for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13977 		/* printing contents of roam profile data from fw and exits
13978 		 * if code hits any of one of the below condtion. If remaining
13979 		 * length of buffer is less than roam profile size or
13980 		 * if there is no valid entry.
13981 		 */
13982 		if (((i * roam_prof_size) > rp->v1.len)) {
13983 			break;
13984 		}
13985 		if (roam_prof_ver == WL_ROAM_PROF_VER_0) {
13986 			fs_per = rp->v1.roam_prof[i].fullscan_period;
13987 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13988 			fs_per = rp->v2.roam_prof[i].fullscan_period;
13989 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13990 			fs_per = rp->v3.roam_prof[i].fullscan_period;
13991 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13992 			fs_per = rp->v4.roam_prof[i].fullscan_period;
13993 		}
13994 		if (fs_per == 0) {
13995 			break;
13996 		}
13997 		prof_cnt++;
13998 	}
13999 
14000 	if (!*data) {
14001 		for (i = 0; (i < prof_cnt) && (i < WL_MAX_ROAM_PROF_BRACKETS); i++) {
14002 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14003 				bytes_written += scnprintf(command+bytes_written,
14004 					total_len - bytes_written,
14005 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
14006 					rp->v2.roam_prof[i].roam_trigger,
14007 					rp->v2.roam_prof[i].rssi_lower,
14008 					rp->v2.roam_prof[i].channel_usage,
14009 					rp->v2.roam_prof[i].cu_avg_calc_dur);
14010 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14011 				bytes_written += scnprintf(command+bytes_written,
14012 					total_len - bytes_written,
14013 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
14014 					rp->v3.roam_prof[i].roam_trigger,
14015 					rp->v3.roam_prof[i].rssi_lower,
14016 					rp->v3.roam_prof[i].channel_usage,
14017 					rp->v3.roam_prof[i].cu_avg_calc_dur);
14018 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14019 				bytes_written += snprintf(command+bytes_written,
14020 					total_len - bytes_written,
14021 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
14022 					rp->v4.roam_prof[i].roam_trigger,
14023 					rp->v4.roam_prof[i].rssi_lower,
14024 					rp->v4.roam_prof[i].channel_usage,
14025 					rp->v4.roam_prof[i].cu_avg_calc_dur);
14026 			}
14027 		}
14028 		bytes_written += scnprintf(command+bytes_written, total_len - bytes_written, "\n");
14029 		err = bytes_written;
14030 		goto exit;
14031 	} else {
14032 		/* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
14033 		if (prof_cnt != 2) {
14034 			ANDROID_ERROR(("FW must have 2 rows to fill roam_prof\n"));
14035 			err = -EINVAL;
14036 			goto exit;
14037 		}
14038 		/* setting roam profile to fw */
14039 		data++;
14040 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
14041 			roam_trigger = simple_strtol(data, &data, 10);
14042 			if (roam_trigger >= 0) {
14043 				ANDROID_ERROR(("roam trigger[%d] value must be negative\n", i));
14044 				err = -EINVAL;
14045 				goto exit;
14046 			}
14047 			data++;
14048 			rssi_lower = simple_strtol(data, &data, 10);
14049 			if (rssi_lower >= 0) {
14050 				ANDROID_ERROR(("rssi lower[%d] value must be negative\n", i));
14051 				err = -EINVAL;
14052 				goto exit;
14053 			}
14054 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14055 				rp->v2.roam_prof[i].roam_trigger = roam_trigger;
14056 				rp->v2.roam_prof[i].rssi_lower = rssi_lower;
14057 				data++;
14058 				rp->v2.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
14059 				data++;
14060 				rp->v2.roam_prof[i].cu_avg_calc_dur =
14061 					simple_strtol(data, &data, 10);
14062 			}
14063 			if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14064 				rp->v3.roam_prof[i].roam_trigger = roam_trigger;
14065 				rp->v3.roam_prof[i].rssi_lower = rssi_lower;
14066 				data++;
14067 				rp->v3.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
14068 				data++;
14069 				rp->v3.roam_prof[i].cu_avg_calc_dur =
14070 					simple_strtol(data, &data, 10);
14071 			}
14072 			if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14073 				rp->v4.roam_prof[i].roam_trigger = roam_trigger;
14074 				rp->v4.roam_prof[i].rssi_lower = rssi_lower;
14075 				data++;
14076 				rp->v4.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
14077 				data++;
14078 				rp->v4.roam_prof[i].cu_avg_calc_dur =
14079 					simple_strtol(data, &data, 10);
14080 			}
14081 
14082 			rp_len += roam_prof_size;
14083 
14084 			if (*data == '\0') {
14085 				break;
14086 			}
14087 			data++;
14088 		}
14089 		if (i != 1) {
14090 			ANDROID_ERROR(("Only two roam_prof rows supported.\n"));
14091 			err = -EINVAL;
14092 			goto exit;
14093 		}
14094 		rp->v1.len = rp_len;
14095 		if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
14096 				sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
14097 				&cfg->ioctl_buf_sync)) < 0) {
14098 			ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
14099 		}
14100 	}
14101 exit:
14102 	if (rp) {
14103 		MFREE(cfg->osh, rp, sizeof(*rp));
14104 	}
14105 	if (ioctl_buf) {
14106 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
14107 	}
14108 	return err;
14109 }
14110 
wl_cfg80211_wbtext_weight_config(struct net_device * ndev,char * data,char * command,int total_len)14111 int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
14112 		char *command, int total_len)
14113 {
14114 	int bytes_written = 0, err = -EINVAL, argc = 0;
14115 	char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
14116 	char *endptr = NULL;
14117 	wnm_bss_select_weight_cfg_t *bwcfg;
14118 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
14119 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14120 
14121 	bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
14122 	if (unlikely(!bwcfg)) {
14123 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14124 		err = -ENOMEM;
14125 		goto exit;
14126 	}
14127 	bwcfg->version =  WNM_BSSLOAD_MONITOR_VERSION;
14128 	bwcfg->type = 0;
14129 	bwcfg->weight = 0;
14130 
14131 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
14132 
14133 	if (!strcasecmp(rssi, "rssi"))
14134 		bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
14135 	else if (!strcasecmp(rssi, "cu"))
14136 		bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
14137 	else if (!strcasecmp(rssi, "estm_dl"))
14138 		bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL;
14139 	else {
14140 		/* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu/estm_dl> <band> <weight> */
14141 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
14142 		goto exit;
14143 	}
14144 
14145 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &bwcfg->band)) {
14146 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
14147 		goto exit;
14148 	}
14149 
14150 	if (argc == 2) {
14151 		/* If there is no data after band, getting wnm_bss_select_weight from fw */
14152 		if (bwcfg->band == WLC_BAND_ALL) {
14153 			ANDROID_ERROR(("band option \"all\" is for set only, not get\n"));
14154 			goto exit;
14155 		}
14156 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
14157 				sizeof(*bwcfg),
14158 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14159 			ANDROID_ERROR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
14160 			goto exit;
14161 		}
14162 		memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
14163 		bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
14164 			(bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" :
14165 			(bwcfg->type == WNM_BSS_SELECT_TYPE_CU) ? "CU": "ESTM_DL",
14166 			wl_android_get_band_str(bwcfg->band), bwcfg->weight);
14167 		err = bytes_written;
14168 		goto exit;
14169 	} else {
14170 		/* if weight is non integer returns command usage error */
14171 		bwcfg->weight = simple_strtol(weight, &endptr, 0);
14172 		if (*endptr != '\0') {
14173 			ANDROID_ERROR(("%s: Command usage error", __func__));
14174 			goto exit;
14175 		}
14176 		/* setting weight for iovar wnm_bss_select_weight to fw */
14177 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
14178 				sizeof(*bwcfg),
14179 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14180 			ANDROID_ERROR(("setting wnm_bss_select_weight failed with err=%d\n", err));
14181 		}
14182 	}
14183 exit:
14184 	if (bwcfg) {
14185 		MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
14186 	}
14187 	return err;
14188 }
14189 
14190 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
14191 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
14192 
wl_cfg80211_wbtext_table_config(struct net_device * ndev,char * data,char * command,int total_len)14193 int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
14194 	char *command, int total_len)
14195 {
14196 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14197 	int bytes_written = 0, err = -EINVAL;
14198 	char rssi[BUFSZN], band[BUFSZN];
14199 	int btcfg_len = 0, i = 0, parsed_len = 0;
14200 	wnm_bss_select_factor_cfg_t *btcfg;
14201 	size_t slen = strlen(data);
14202 	char *start_addr = NULL;
14203 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
14204 
14205 	data[slen] = '\0';
14206 	btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
14207 		(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14208 	if (unlikely(!btcfg)) {
14209 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14210 		err = -ENOMEM;
14211 		goto exit;
14212 	}
14213 
14214 	btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
14215 	btcfg->band = WLC_BAND_AUTO;
14216 	btcfg->type = 0;
14217 	btcfg->count = 0;
14218 
14219 	sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
14220 
14221 	if (!strcasecmp(rssi, "rssi")) {
14222 		btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
14223 	}
14224 	else if (!strcasecmp(rssi, "cu")) {
14225 		btcfg->type = WNM_BSS_SELECT_TYPE_CU;
14226 	}
14227 	else {
14228 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
14229 		goto exit;
14230 	}
14231 
14232 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &btcfg->band)) {
14233 		ANDROID_ERROR(("%s: Command usage, Wrong band\n", __func__));
14234 		goto exit;
14235 	}
14236 
14237 	if ((slen - 1) == (strlen(rssi) + strlen(band))) {
14238 		/* Getting factor table using iovar 'wnm_bss_select_table' from fw */
14239 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
14240 				sizeof(*btcfg),
14241 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14242 			ANDROID_ERROR(("Getting wnm_bss_select_table failed with err=%d \n", err));
14243 			goto exit;
14244 		}
14245 		memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
14246 		memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
14247 
14248 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14249 					"No of entries in table: %d\n", btcfg->count);
14250 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14251 				"%s factor table\n",
14252 				(btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
14253 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14254 					"low\thigh\tfactor\n");
14255 		for (i = 0; i <= btcfg->count-1; i++) {
14256 			bytes_written += snprintf(command + bytes_written,
14257 				total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
14258 				btcfg->params[i].high, btcfg->params[i].factor);
14259 		}
14260 		err = bytes_written;
14261 		goto exit;
14262 	} else {
14263 		uint16 len = (sizeof(wnm_bss_select_factor_params_t) * WL_FACTOR_TABLE_MAX_LIMIT);
14264 		memset_s(btcfg->params, len, 0, len);
14265 		data += (strlen(rssi) + strlen(band) + 2);
14266 		start_addr = data;
14267 		slen = slen - (strlen(rssi) + strlen(band) + 2);
14268 		for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
14269 			if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
14270 				btcfg->params[i].low = simple_strtol(data, &data, 10);
14271 				data++;
14272 				btcfg->params[i].high = simple_strtol(data, &data, 10);
14273 				data++;
14274 				btcfg->params[i].factor = simple_strtol(data, &data, 10);
14275 				btcfg->count++;
14276 				if (*data == '\0') {
14277 					break;
14278 				}
14279 				data++;
14280 				parsed_len = data - start_addr;
14281 			} else {
14282 				ANDROID_ERROR(("%s:Command usage:less no of args\n", __func__));
14283 				goto exit;
14284 			}
14285 		}
14286 		btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
14287 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
14288 				cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
14289 			ANDROID_ERROR(("seting wnm_bss_select_table failed with err %d\n", err));
14290 			goto exit;
14291 		}
14292 	}
14293 exit:
14294 	if (btcfg) {
14295 		MFREE(cfg->osh, btcfg,
14296 			(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14297 	}
14298 	return err;
14299 }
14300 
14301 s32
wl_cfg80211_wbtext_delta_config(struct net_device * ndev,char * data,char * command,int total_len)14302 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
14303 {
14304 	uint i = 0;
14305 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14306 	int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
14307 	char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
14308 	wl_roamprof_band_t *rp = NULL;
14309 	uint8 band_val = 0, roam_prof_size = 0, roam_prof_ver = 0;
14310 
14311 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
14312 	if (unlikely(!rp)) {
14313 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14314 		err = -ENOMEM;
14315 		goto exit;
14316 	}
14317 
14318 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
14319 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &band_val)) {
14320 		ANDROID_ERROR(("%s: Missing band\n", __func__));
14321 		goto exit;
14322 	}
14323 	if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver,
14324 		&roam_prof_size))) {
14325 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
14326 		err = -EINVAL;
14327 		goto exit;
14328 	}
14329 	if (argc == 2) {
14330 		/* if delta is non integer returns command usage error */
14331 		val = simple_strtol(delta, &endptr, 0);
14332 		if (*endptr != '\0') {
14333 			ANDROID_ERROR(("%s: Command usage error", __func__));
14334 			goto exit;
14335 		}
14336 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
14337 		/*
14338 		 * Checking contents of roam profile data from fw and exits
14339 		 * if code hits below condtion. If remaining length of buffer is
14340 		 * less than roam profile size or if there is no valid entry.
14341 		 */
14342 			if (len >= rp->v1.len) {
14343 				break;
14344 			}
14345 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14346 				if (rp->v2.roam_prof[i].fullscan_period == 0) {
14347 					break;
14348 				}
14349 				if (rp->v2.roam_prof[i].channel_usage != 0) {
14350 					rp->v2.roam_prof[i].roam_delta = val;
14351 				}
14352 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14353 				if (rp->v3.roam_prof[i].fullscan_period == 0) {
14354 					break;
14355 				}
14356 				if (rp->v3.roam_prof[i].channel_usage != 0) {
14357 					rp->v3.roam_prof[i].roam_delta = val;
14358 				}
14359 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14360 				if (rp->v4.roam_prof[i].fullscan_period == 0) {
14361 					break;
14362 				}
14363 				if (rp->v4.roam_prof[i].channel_usage != 0) {
14364 					rp->v4.roam_prof[i].roam_delta = val;
14365 				}
14366 			}
14367 			len += roam_prof_size;
14368 		}
14369 	}
14370 	else {
14371 		if (rp->v2.roam_prof[0].channel_usage != 0) {
14372 			bytes_written = snprintf(command, total_len,
14373 				"%s Delta %d\n", wl_android_get_band_str(rp->v1.band),
14374 				rp->v2.roam_prof[0].roam_delta);
14375 		}
14376 		err = bytes_written;
14377 		goto exit;
14378 	}
14379 	rp->v1.len = len;
14380 	if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
14381 			sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
14382 			&cfg->ioctl_buf_sync)) < 0) {
14383 		ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
14384 	}
14385 exit :
14386 	if (rp) {
14387 		MFREE(cfg->osh, rp, sizeof(*rp));
14388 	}
14389 	return err;
14390 }
14391 #endif /* WBTEXT */
14392