xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rkwifi/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 uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL;
92 
93 #define ANDROID_ERROR_MSG(x, args...) \
94 	do { \
95 		if (android_msg_level & ANDROID_ERROR_LEVEL) { \
96 			printf("ANDROID-ERROR) " x, ## args); \
97 		} \
98 	} while (0)
99 #define ANDROID_TRACE_MSG(x, args...) \
100 	do { \
101 		if (android_msg_level & ANDROID_TRACE_LEVEL) { \
102 			printf("ANDROID-TRACE) " x, ## args); \
103 		} \
104 	} while (0)
105 #define ANDROID_INFO_MSG(x, args...) \
106 	do { \
107 		if (android_msg_level & ANDROID_INFO_LEVEL) { \
108 			printf("ANDROID-INFO) " x, ## args); \
109 		} \
110 	} while (0)
111 #define ANDROID_ERROR(x) ANDROID_ERROR_MSG x
112 #define ANDROID_TRACE(x) ANDROID_TRACE_MSG x
113 #define ANDROID_INFO(x) ANDROID_INFO_MSG x
114 
115 /*
116  * Android private command strings, PLEASE define new private commands here
117  * so they can be updated easily in the future (if needed)
118  */
119 
120 #define CMD_START		"START"
121 #define CMD_STOP		"STOP"
122 #define	CMD_SCAN_ACTIVE		"SCAN-ACTIVE"
123 #define	CMD_SCAN_PASSIVE	"SCAN-PASSIVE"
124 #define CMD_RSSI		"RSSI"
125 #define CMD_LINKSPEED		"LINKSPEED"
126 #define CMD_RXFILTER_START	"RXFILTER-START"
127 #define CMD_RXFILTER_STOP	"RXFILTER-STOP"
128 #define CMD_RXFILTER_ADD	"RXFILTER-ADD"
129 #define CMD_RXFILTER_REMOVE	"RXFILTER-REMOVE"
130 #define CMD_BTCOEXSCAN_START	"BTCOEXSCAN-START"
131 #define CMD_BTCOEXSCAN_STOP	"BTCOEXSCAN-STOP"
132 #define CMD_BTCOEXMODE		"BTCOEXMODE"
133 #define CMD_SETSUSPENDOPT	"SETSUSPENDOPT"
134 #define CMD_SETSUSPENDMODE      "SETSUSPENDMODE"
135 #define CMD_SETDTIM_IN_SUSPEND  "SET_DTIM_IN_SUSPEND"
136 #define CMD_MAXDTIM_IN_SUSPEND  "MAX_DTIM_IN_SUSPEND"
137 #define CMD_DISDTIM_IN_SUSPEND  "DISABLE_DTIM_IN_SUSPEND"
138 #define CMD_P2P_DEV_ADDR	"P2P_DEV_ADDR"
139 #define CMD_SETFWPATH		"SETFWPATH"
140 #define CMD_SETBAND		"SETBAND"
141 #define CMD_GETBAND		"GETBAND"
142 #define CMD_COUNTRY		"COUNTRY"
143 #define CMD_P2P_SET_NOA		"P2P_SET_NOA"
144 #if !defined WL_ENABLE_P2P_IF
145 #define CMD_P2P_GET_NOA			"P2P_GET_NOA"
146 #endif /* WL_ENABLE_P2P_IF */
147 #define CMD_P2P_SD_OFFLOAD		"P2P_SD_"
148 #define CMD_P2P_LISTEN_OFFLOAD		"P2P_LO_"
149 #define CMD_P2P_SET_PS		"P2P_SET_PS"
150 #define CMD_P2P_ECSA		"P2P_ECSA"
151 #define CMD_P2P_INC_BW		"P2P_INCREASE_BW"
152 #define CMD_SET_AP_WPS_P2P_IE 		"SET_AP_WPS_P2P_IE"
153 #define CMD_SETROAMMODE 	"SETROAMMODE"
154 #define CMD_SETIBSSBEACONOUIDATA	"SETIBSSBEACONOUIDATA"
155 #define CMD_MIRACAST		"MIRACAST"
156 #ifdef WL_NAN
157 #define CMD_NAN         "NAN_"
158 #endif /* WL_NAN */
159 #define CMD_COUNTRY_DELIMITER "/"
160 
161 #if defined (WL_SUPPORT_AUTO_CHANNEL)
162 #define CMD_GET_BEST_CHANNELS	"GET_BEST_CHANNELS"
163 #endif /* WL_SUPPORT_AUTO_CHANNEL */
164 
165 #define CMD_80211_MODE    "MODE"  /* 802.11 mode a/b/g/n/ac */
166 #define CMD_CHANSPEC      "CHANSPEC"
167 #define CMD_DATARATE      "DATARATE"
168 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
169 #define CMD_SET_CSA       "SETCSA"
170 #ifdef WL_SUPPORT_AUTO_CHANNEL
171 #define CMD_SET_HAPD_AUTO_CHANNEL	"HAPD_AUTO_CHANNEL"
172 #endif /* WL_SUPPORT_AUTO_CHANNEL */
173 #ifdef CUSTOMER_HW4_PRIVATE_CMD
174 #ifdef WL_WTC
175 #define CMD_WTC_CONFIG    "SETWTCMODE"
176 #endif /* WL_WTC */
177 #ifdef SUPPORT_HIDDEN_AP
178 /* Hostapd private command */
179 #define CMD_SET_HAPD_MAX_NUM_STA	"HAPD_MAX_NUM_STA"
180 #define CMD_SET_HAPD_SSID		"HAPD_SSID"
181 #define CMD_SET_HAPD_HIDE_SSID		"HAPD_HIDE_SSID"
182 #endif /* SUPPORT_HIDDEN_AP */
183 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
184 #define CMD_HAPD_STA_DISASSOC		"HAPD_STA_DISASSOC"
185 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
186 #ifdef SUPPORT_SET_LPC
187 #define CMD_HAPD_LPC_ENABLED		"HAPD_LPC_ENABLED"
188 #endif /* SUPPORT_SET_LPC */
189 #ifdef SUPPORT_TRIGGER_HANG_EVENT
190 #define CMD_TEST_FORCE_HANG		"TEST_FORCE_HANG"
191 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
192 #ifdef SUPPORT_LTECX
193 #define CMD_LTECX_SET		"LTECOEX"
194 #endif /* SUPPORT_LTECX */
195 #ifdef TEST_TX_POWER_CONTROL
196 #define CMD_TEST_SET_TX_POWER		"TEST_SET_TX_POWER"
197 #define CMD_TEST_GET_TX_POWER		"TEST_GET_TX_POWER"
198 #endif /* TEST_TX_POWER_CONTROL */
199 #define CMD_SARLIMIT_TX_CONTROL		"SET_TX_POWER_CALLING"
200 #ifdef SUPPORT_SET_TID
201 #define CMD_SET_TID		"SET_TID"
202 #define CMD_GET_TID		"GET_TID"
203 #endif /* SUPPORT_SET_TID */
204 #define CMD_ROAM_VSIE_ENAB_SET	"SET_ROAMING_REASON_ENABLED"
205 #define CMD_ROAM_VSIE_ENAB_GET	"GET_ROAMING_REASON_ENABLED"
206 #define CMD_BR_VSIE_ENAB_SET	"SET_BR_ERR_REASON_ENABLED"
207 #define CMD_BR_VSIE_ENAB_GET	"GET_BR_ERR_REASON_ENABLED"
208 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
209 #define CMD_KEEP_ALIVE          "KEEPALIVE"
210 
211 #ifdef PNO_SUPPORT
212 #define CMD_PNOSSIDCLR_SET	"PNOSSIDCLR"
213 #define CMD_PNOSETUP_SET	"PNOSETUP "
214 #define CMD_PNOENABLE_SET	"PNOFORCE"
215 #define CMD_PNODEBUG_SET	"PNODEBUG"
216 #define CMD_WLS_BATCHING	"WLS_BATCHING"
217 #endif /* PNO_SUPPORT */
218 
219 #define CMD_HAPD_SET_AX_MODE "HAPD_SET_AX_MODE"
220 
221 #define	CMD_HAPD_MAC_FILTER	"HAPD_MAC_FILTER"
222 
223 #if defined(SUPPORT_RANDOM_MAC_SCAN)
224 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
225 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
226 #endif /* SUPPORT_RANDOM_MAC_SCAN */
227 #define CMD_GET_FACTORY_MAC      "FACTORY_MAC"
228 #ifdef CUSTOMER_HW4_PRIVATE_CMD
229 
230 #ifdef ROAM_API
231 #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
232 #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
233 #define CMD_ROAMDELTA_SET "SETROAMDELTA"
234 #define CMD_ROAMDELTA_GET "GETROAMDELTA"
235 #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
236 #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
237 #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
238 #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
239 #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
240 #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
241 #endif /* ROAM_API */
242 
243 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
244 #define CMD_NAN_RANGING_SET_BW "NAN_RANGING_SET_BW"
245 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
246 
247 #ifdef WES_SUPPORT
248 #define CMD_GETSCANCHANNELTIMELEGACY "GETSCANCHANNELTIME_LEGACY"
249 #define CMD_SETSCANCHANNELTIMELEGACY "SETSCANCHANNELTIME_LEGACY"
250 #define CMD_GETSCANUNASSOCTIMELEGACY "GETSCANUNASSOCTIME_LEGACY"
251 #define CMD_SETSCANUNASSOCTIMELEGACY "SETSCANUNASSOCTIME_LEGACY"
252 #define CMD_GETSCANPASSIVETIMELEGACY "GETSCANPASSIVETIME_LEGACY"
253 #define CMD_SETSCANPASSIVETIMELEGACY "SETSCANPASSIVETIME_LEGACY"
254 #define CMD_GETSCANHOMETIMELEGACY "GETSCANHOMETIME_LEGACY"
255 #define CMD_SETSCANHOMETIMELEGACY "SETSCANHOMETIME_LEGACY"
256 #define CMD_GETSCANHOMEAWAYTIMELEGACY "GETSCANHOMEAWAYTIME_LEGACY"
257 #define CMD_SETSCANHOMEAWAYTIMELEGACY "SETSCANHOMEAWAYTIME_LEGACY"
258 #define CMD_GETROAMSCANCHLEGACY "GETROAMSCANCHANNELS_LEGACY"
259 #define CMD_ADDROAMSCANCHLEGACY "ADDROAMSCANCHANNELS_LEGACY"
260 #define CMD_GETROAMSCANFQLEGACY "GETROAMSCANFREQUENCIES_LEGACY"
261 #define CMD_ADDROAMSCANFQLEGACY "ADDROAMSCANFREQUENCIES_LEGACY"
262 #define CMD_GETROAMTRIGLEGACY "GETROAMTRIGGER_LEGACY"
263 #define CMD_SETROAMTRIGLEGACY "SETROAMTRIGGER_LEGACY"
264 #define CMD_REASSOCLEGACY "REASSOC_LEGACY"
265 
266 #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
267 #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
268 #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
269 #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
270 #define CMD_ADDROAMSCANCHANNELS "ADDROAMSCANCHANNELS"
271 #define CMD_GETROAMSCANFREQS "GETROAMSCANFREQUENCIES"
272 #define CMD_SETROAMSCANFREQS "SETROAMSCANFREQUENCIES"
273 #define CMD_ADDROAMSCANFREQS "ADDROAMSCANFREQUENCIES"
274 #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
275 #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
276 #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
277 #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
278 #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
279 #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
280 #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
281 #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
282 #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
283 #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
284 #define CMD_GETSCANNPROBES "GETSCANNPROBES"
285 #define CMD_SETSCANNPROBES "SETSCANNPROBES"
286 #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
287 #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
288 #define CMD_SETJOINPREFER "SETJOINPREFER"
289 
290 #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
291 #define CMD_REASSOC "REASSOC"
292 
293 #define CMD_GETWESMODE "GETWESMODE"
294 #define CMD_SETWESMODE "SETWESMODE"
295 #define CMD_GETNCHOMODE	"GETNCHOMODE"
296 #define CMD_SETNCHOMODE	"SETNCHOMODE"
297 
298 /* Customer requested to Remove OKCMODE command */
299 #define CMD_GETOKCMODE "GETOKCMODE"
300 #define CMD_SETOKCMODE "SETOKCMODE"
301 
302 #define CMD_OKC_SET_PMK         "SET_PMK"
303 #define CMD_OKC_ENABLE          "OKC_ENABLE"
304 
305 typedef struct android_wifi_reassoc_params {
306 	unsigned char bssid[18];
307 	int channel;
308 } android_wifi_reassoc_params_t;
309 
310 #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
311 
312 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
313 
314 typedef struct android_wifi_af_params {
315 	unsigned char bssid[18];
316 	int channel;
317 	int dwell_time;
318 	int len;
319 	unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
320 } android_wifi_af_params_t;
321 
322 #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
323 #endif /* WES_SUPPORT */
324 #ifdef SUPPORT_AMPDU_MPDU_CMD
325 #define CMD_AMPDU_MPDU		"AMPDU_MPDU"
326 #endif /* SUPPORT_AMPDU_MPDU_CMD */
327 
328 #define CMD_CHANGE_RL 	"CHANGE_RL"
329 #define CMD_RESTORE_RL  "RESTORE_RL"
330 
331 #define CMD_SET_RMC_ENABLE			"SETRMCENABLE"
332 #define CMD_SET_RMC_TXRATE			"SETRMCTXRATE"
333 #define CMD_SET_RMC_ACTPERIOD		"SETRMCACTIONPERIOD"
334 #define CMD_SET_RMC_IDLEPERIOD		"SETRMCIDLEPERIOD"
335 #define CMD_SET_RMC_LEADER			"SETRMCLEADER"
336 #define CMD_SET_RMC_EVENT			"SETRMCEVENT"
337 
338 #define CMD_SET_SCSCAN		"SETSINGLEANT"
339 #define CMD_GET_SCSCAN		"GETSINGLEANT"
340 #ifdef WLTDLS
341 #define CMD_TDLS_RESET "TDLS_RESET"
342 #endif /* WLTDLS */
343 
344 #ifdef CONFIG_SILENT_ROAM
345 #define CMD_SROAM_TURN_ON	"SROAMTURNON"
346 #define CMD_SROAM_SET_INFO	"SROAMSETINFO"
347 #define CMD_SROAM_GET_INFO	"SROAMGETINFO"
348 #endif /* CONFIG_SILENT_ROAM */
349 
350 #ifdef CONFIG_ROAM_RSSI_LIMIT
351 #define CMD_ROAM_RSSI_LMT	"ROAMRSSILIMIT"
352 #endif /* CONFIG_ROAM_RSSI_LIMIT */
353 #ifdef CONFIG_ROAM_MIN_DELTA
354 #define CMD_ROAM_MIN_DELTA	"ROAMMINSCOREDELTA"
355 #endif /* CONFIG_ROAM_MIN_DELTA */
356 
357 #define CMD_SET_DISCONNECT_IES  "SET_DISCONNECT_IES"
358 
359 #ifdef FCC_PWR_LIMIT_2G
360 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
361 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
362 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
363 #define CUSTOMER_HW4_ENABLE		0
364 #define CUSTOMER_HW4_DISABLE	-1
365 #endif /* FCC_PWR_LIMIT_2G */
366 #define CUSTOMER_HW4_EN_CONVERT(i)	(i += 1)
367 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
368 
369 #ifdef WLFBT
370 #define CMD_GET_FTKEY      "GET_FTKEY"
371 #endif
372 
373 #ifdef WLAIBSS
374 #define CMD_SETIBSSTXFAILEVENT		"SETIBSSTXFAILEVENT"
375 #define CMD_GET_IBSS_PEER_INFO		"GETIBSSPEERINFO"
376 #define CMD_GET_IBSS_PEER_INFO_ALL	"GETIBSSPEERINFOALL"
377 #define CMD_SETIBSSROUTETABLE		"SETIBSSROUTETABLE"
378 #define CMD_SETIBSSAMPDU			"SETIBSSAMPDU"
379 #define CMD_SETIBSSANTENNAMODE		"SETIBSSANTENNAMODE"
380 #endif /* WLAIBSS */
381 
382 #define CMD_ROAM_OFFLOAD			"SETROAMOFFLOAD"
383 #define CMD_INTERFACE_CREATE			"INTERFACE_CREATE"
384 #define CMD_INTERFACE_DELETE			"INTERFACE_DELETE"
385 #define CMD_GET_LINK_STATUS			"GETLINKSTATUS"
386 
387 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
388 #define CMD_GET_BSS_INFO            "GETBSSINFO"
389 #define CMD_GET_ASSOC_REJECT_INFO   "GETASSOCREJECTINFO"
390 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
391 #define CMD_GET_STA_INFO   "GETSTAINFO"
392 
393 /* related with CMD_GET_LINK_STATUS */
394 #define WL_ANDROID_LINK_VHT					0x01
395 #define WL_ANDROID_LINK_MIMO					0x02
396 #define WL_ANDROID_LINK_AP_VHT_SUPPORT		0x04
397 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT	0x08
398 
399 #ifdef P2PRESP_WFDIE_SRC
400 #define CMD_P2P_SET_WFDIE_RESP      "P2P_SET_WFDIE_RESP"
401 #define CMD_P2P_GET_WFDIE_RESP      "P2P_GET_WFDIE_RESP"
402 #endif /* P2PRESP_WFDIE_SRC */
403 
404 #define CMD_DFS_AP_MOVE			"DFS_AP_MOVE"
405 #define CMD_WBTEXT_ENABLE		"WBTEXT_ENABLE"
406 #define CMD_WBTEXT_PROFILE_CONFIG	"WBTEXT_PROFILE_CONFIG"
407 #define CMD_WBTEXT_WEIGHT_CONFIG	"WBTEXT_WEIGHT_CONFIG"
408 #define CMD_WBTEXT_TABLE_CONFIG		"WBTEXT_TABLE_CONFIG"
409 #define CMD_WBTEXT_DELTA_CONFIG		"WBTEXT_DELTA_CONFIG"
410 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD	"WBTEXT_BTM_TIMER_THRESHOLD"
411 #define CMD_WBTEXT_BTM_DELTA		"WBTEXT_BTM_DELTA"
412 #define CMD_WBTEXT_ESTM_ENABLE	"WBTEXT_ESTM_ENABLE"
413 
414 #ifdef WBTEXT
415 #define CMD_WBTEXT_PROFILE_CONFIG	"WBTEXT_PROFILE_CONFIG"
416 #define CMD_WBTEXT_WEIGHT_CONFIG	"WBTEXT_WEIGHT_CONFIG"
417 #define CMD_WBTEXT_TABLE_CONFIG		"WBTEXT_TABLE_CONFIG"
418 #define CMD_WBTEXT_DELTA_CONFIG		"WBTEXT_DELTA_CONFIG"
419 #define DEFAULT_WBTEXT_PROFILE_A_V2		"a -70 -75 70 10 -75 -128 0 10"
420 #define DEFAULT_WBTEXT_PROFILE_B_V2		"b -60 -75 70 10 -75 -128 0 10"
421 #define DEFAULT_WBTEXT_PROFILE_A_V3		"a -70 -75 70 10 -75 -128 0 10"
422 #define DEFAULT_WBTEXT_PROFILE_B_V3		"b -60 -75 70 10 -75 -128 0 10"
423 #define DEFAULT_WBTEXT_WEIGHT_RSSI_A	"RSSI a 65"
424 #define DEFAULT_WBTEXT_WEIGHT_RSSI_B	"RSSI b 65"
425 #define DEFAULT_WBTEXT_WEIGHT_CU_A	"CU a 35"
426 #define DEFAULT_WBTEXT_WEIGHT_CU_B	"CU b 35"
427 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A	"ESTM_DL a 70"
428 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B	"ESTM_DL b 70"
429 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_A	-70
430 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_B	-60
431 #ifdef WBTEXT_SCORE_V2
432 #define DEFAULT_WBTEXT_TABLE_RSSI_A	"RSSI a 0 55 100 55 60 90 \
433 60 70 60 70 80 20 80 90 0 90 128 0"
434 #define DEFAULT_WBTEXT_TABLE_RSSI_B	"RSSI b 0 55 100 55 60 90 \
435 60 70 60 70 80 20 80 90 0 90 128 0"
436 #define DEFAULT_WBTEXT_TABLE_CU_A	"CU a 0 30 100 30 80 20 \
437 80 100 20"
438 #define DEFAULT_WBTEXT_TABLE_CU_B	"CU b 0 10 100 10 70 20 \
439 70 100 20"
440 #else
441 #define DEFAULT_WBTEXT_TABLE_RSSI_A	"RSSI a 0 55 100 55 60 90 \
442 60 65 70 65 70 50 70 128 20"
443 #define DEFAULT_WBTEXT_TABLE_RSSI_B	"RSSI b 0 55 100 55 60 90 \
444 60 65 70 65 70 50 70 128 20"
445 #define DEFAULT_WBTEXT_TABLE_CU_A	"CU a 0 30 100 30 50 90 \
446 50 60 70 60 80 50 80 100 20"
447 #define DEFAULT_WBTEXT_TABLE_CU_B	"CU b 0 10 100 10 25 90 \
448 25 40 70 40 70 50 70 100 20"
449 #endif /* WBTEXT_SCORE_V2 */
450 #endif /* WBTEXT */
451 
452 #define BUFSZ 8
453 #define BUFSZN	BUFSZ + 1
454 
455 #define _S(x) #x
456 #define S(x) _S(x)
457 
458 #define  MAXBANDS    2  /**< Maximum #of bands */
459 #define BAND_2G_INDEX      1
460 #define BAND_5G_INDEX      0
461 
462 typedef union {
463 	wl_roam_prof_band_v1_t v1;
464 	wl_roam_prof_band_v2_t v2;
465 	wl_roam_prof_band_v3_t v3;
466 	wl_roam_prof_band_v4_t v4;
467 } wl_roamprof_band_t;
468 
469 #ifdef WLWFDS
470 #define CMD_ADD_WFDS_HASH	"ADD_WFDS_HASH"
471 #define CMD_DEL_WFDS_HASH	"DEL_WFDS_HASH"
472 #endif /* WLWFDS */
473 
474 #ifdef BT_WIFI_HANDOVER
475 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
476 #endif /* BT_WIFI_HANDOVER */
477 
478 #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
479 
480 #ifdef SUPPORT_RSSI_SUM_REPORT
481 #define CMD_SET_RSSI_LOGGING				"SET_RSSI_LOGGING"
482 #define CMD_GET_RSSI_LOGGING				"GET_RSSI_LOGGING"
483 #define CMD_GET_RSSI_PER_ANT				"GET_RSSI_PER_ANT"
484 #endif /* SUPPORT_RSSI_SUM_REPORT */
485 
486 #define CMD_GET_SNR							"GET_SNR"
487 
488 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
489 #define CMD_SET_AP_BEACONRATE				"SET_AP_BEACONRATE"
490 #define CMD_GET_AP_BASICRATE				"GET_AP_BASICRATE"
491 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
492 
493 #ifdef SUPPORT_AP_RADIO_PWRSAVE
494 #define CMD_SET_AP_RPS						"SET_AP_RPS"
495 #define CMD_GET_AP_RPS						"GET_AP_RPS"
496 #define CMD_SET_AP_RPS_PARAMS				"SET_AP_RPS_PARAMS"
497 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
498 
499 #ifdef SUPPORT_AP_SUSPEND
500 #define CMD_SET_AP_SUSPEND			"SET_AP_SUSPEND"
501 #endif /* SUPPORT_AP_SUSPEND */
502 
503 #ifdef SUPPORT_AP_BWCTRL
504 #define CMD_SET_AP_BW			"SET_AP_BW"
505 #define CMD_GET_AP_BW			"GET_AP_BW"
506 #endif /* SUPPORT_AP_BWCTRL */
507 
508 /* miracast related definition */
509 #define MIRACAST_MODE_OFF	0
510 #define MIRACAST_MODE_SOURCE	1
511 #define MIRACAST_MODE_SINK	2
512 
513 #ifdef CONNECTION_STATISTICS
514 #define CMD_GET_CONNECTION_STATS	"GET_CONNECTION_STATS"
515 
516 struct connection_stats {
517 	u32 txframe;
518 	u32 txbyte;
519 	u32 txerror;
520 	u32 rxframe;
521 	u32 rxbyte;
522 	u32 txfail;
523 	u32 txretry;
524 	u32 txretrie;
525 	u32 txrts;
526 	u32 txnocts;
527 	u32 txexptime;
528 	u32 txrate;
529 	u8	chan_idle;
530 };
531 #endif /* CONNECTION_STATISTICS */
532 
533 #ifdef SUPPORT_LQCM
534 #define CMD_SET_LQCM_ENABLE			"SET_LQCM_ENABLE"
535 #define CMD_GET_LQCM_REPORT			"GET_LQCM_REPORT"
536 #endif
537 
538 static LIST_HEAD(miracast_resume_list);
539 #ifdef WL_CFG80211
540 static u8 miracast_cur_mode;
541 #endif /* WL_CFG80211 */
542 
543 #ifdef DHD_LOG_DUMP
544 #define CMD_NEW_DEBUG_PRINT_DUMP	"DEBUG_DUMP"
545 #define SUBCMD_UNWANTED			"UNWANTED"
546 #define SUBCMD_DISCONNECTED		"DISCONNECTED"
547 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
548 #endif /* DHD_LOG_DUMP */
549 
550 #ifdef DHD_STATUS_LOGGING
551 #define CMD_DUMP_STATUS_LOG		"DUMP_STAT_LOG"
552 #define CMD_QUERY_STATUS_LOG		"QUERY_STAT_LOG"
553 #endif /* DHD_STATUS_LOGGING */
554 
555 #ifdef DHD_HANG_SEND_UP_TEST
556 #define CMD_MAKE_HANG  "MAKE_HANG"
557 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
558 #ifdef DHD_DEBUG_UART
559 extern bool dhd_debug_uart_is_running(struct net_device *dev);
560 #endif	/* DHD_DEBUG_UART */
561 
562 #ifdef RTT_GEOFENCE_INTERVAL
563 #if defined (RTT_SUPPORT) && defined(WL_NAN)
564 #define CMD_GEOFENCE_INTERVAL	"GEOFENCE_INT"
565 #endif /* RTT_SUPPORT && WL_NAN */
566 #endif /* RTT_GEOFENCE_INTERVAL */
567 
568 struct io_cfg {
569 	s8 *iovar;
570 	s32 param;
571 	u32 ioctl;
572 	void *arg;
573 	u32 len;
574 	struct list_head list;
575 };
576 
577 #if defined(BCMFW_ROAM_ENABLE)
578 #define CMD_SET_ROAMPREF	"SET_ROAMPREF"
579 
580 #define MAX_NUM_SUITES		10
581 #define WIDTH_AKM_SUITE		8
582 #define JOIN_PREF_RSSI_LEN		0x02
583 #define JOIN_PREF_RSSI_SIZE		4	/* RSSI pref header size in bytes */
584 #define JOIN_PREF_WPA_HDR_SIZE		4 /* WPA pref header size in bytes */
585 #define JOIN_PREF_WPA_TUPLE_SIZE	12	/* Tuple size in bytes */
586 #define JOIN_PREF_MAX_WPA_TUPLES	16
587 #define MAX_BUF_SIZE		(JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +	\
588 				           (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
589 #endif /* BCMFW_ROAM_ENABLE */
590 
591 #if defined(CONFIG_TIZEN)
592 /*
593  * adding these private commands corresponding to atd-server's implementation
594  * __atd_control_pm_state()
595  */
596 #define CMD_POWERSAVEMODE_SET "SETPOWERSAVEMODE"
597 #define CMD_POWERSAVEMODE_GET "GETPOWERSAVEMODE"
598 #endif /* CONFIG_TIZEN */
599 
600 #define CMD_DEBUG_VERBOSE          "DEBUG_VERBOSE"
601 #ifdef WL_NATOE
602 
603 #define CMD_NATOE		"NATOE"
604 
605 #define NATOE_MAX_PORT_NUM	65535
606 
607 /* natoe command info structure */
608 typedef struct wl_natoe_cmd_info {
609 	uint8  *command;        /* pointer to the actual command */
610 	uint16 tot_len;        /* total length of the command */
611 	uint16 bytes_written;  /* Bytes written for get response */
612 } wl_natoe_cmd_info_t;
613 
614 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
615 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
616 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
617 
618 struct wl_natoe_sub_cmd {
619 	char *name;
620 	uint8  version;              /* cmd  version */
621 	uint16 id;                   /* id for the dongle f/w switch/case */
622 	uint16 type;                 /* base type of argument */
623 	natoe_cmd_handler_t *handler; /* cmd handler  */
624 };
625 
626 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
627 static int wl_android_process_natoe_cmd(struct net_device *dev,
628 		char *command, int total_len);
629 static int wl_android_natoe_subcmd_enable(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_ips(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_config_ports(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_dbg_stats(struct net_device *dev,
636 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
637 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
638 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
639 
640 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
641 	/* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
642 	{"enable", 0x01, WL_NATOE_CMD_ENABLE,
643 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
644 	},
645 	{"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
646 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
647 	},
648 	{"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
649 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
650 	},
651 	{"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
652 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
653 	},
654 	{"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
655 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
656 	},
657 	{NULL, 0, 0, 0, NULL}
658 };
659 
660 #endif /* WL_NATOE */
661 
662 #ifdef SET_PCIE_IRQ_CPU_CORE
663 #define CMD_PCIE_IRQ_CORE	"PCIE_IRQ_CORE"
664 #endif /* SET_PCIE_IRQ_CPU_CORE */
665 
666 #ifdef WLADPS_PRIVATE_CMD
667 #define CMD_SET_ADPS	"SET_ADPS"
668 #define CMD_GET_ADPS	"GET_ADPS"
669 #ifdef WLADPS_ENERGY_GAIN
670 #define CMD_GET_GAIN_ADPS	"GET_GAIN_ADPS"
671 #define CMD_RESET_GAIN_ADPS	"RESET_GAIN_ADPS"
672 #ifndef ADPS_GAIN_2G_PM0_IDLE
673 #define ADPS_GAIN_2G_PM0_IDLE 0
674 #endif
675 #ifndef ADPS_GAIN_5G_PM0_IDLE
676 #define ADPS_GAIN_5G_PM0_IDLE 0
677 #endif
678 #ifndef ADPS_GAIN_2G_TX_PSPOLL
679 #define ADPS_GAIN_2G_TX_PSPOLL 0
680 #endif
681 #ifndef ADPS_GAIN_5G_TX_PSPOLL
682 #define ADPS_GAIN_5G_TX_PSPOLL 0
683 #endif
684 #endif	/* WLADPS_ENERGY_GAIN */
685 #endif /* WLADPS_PRIVATE_CMD */
686 
687 #ifdef DHD_PKT_LOGGING
688 #define CMD_PKTLOG_FILTER_ENABLE	"PKTLOG_FILTER_ENABLE"
689 #define CMD_PKTLOG_FILTER_DISABLE	"PKTLOG_FILTER_DISABLE"
690 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE	"PKTLOG_FILTER_PATTERN_ENABLE"
691 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE	"PKTLOG_FILTER_PATTERN_DISABLE"
692 #define CMD_PKTLOG_FILTER_ADD	"PKTLOG_FILTER_ADD"
693 #define CMD_PKTLOG_FILTER_DEL	"PKTLOG_FILTER_DEL"
694 #define CMD_PKTLOG_FILTER_INFO	"PKTLOG_FILTER_INFO"
695 #define CMD_PKTLOG_START	"PKTLOG_START"
696 #define CMD_PKTLOG_STOP		"PKTLOG_STOP"
697 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
698 #define CMD_PKTLOG_MINMIZE_ENABLE	"PKTLOG_MINMIZE_ENABLE"
699 #define CMD_PKTLOG_MINMIZE_DISABLE	"PKTLOG_MINMIZE_DISABLE"
700 #define CMD_PKTLOG_CHANGE_SIZE	"PKTLOG_CHANGE_SIZE"
701 #define CMD_PKTLOG_DEBUG_DUMP	"PKTLOG_DEBUG_DUMP"
702 #endif /* DHD_PKT_LOGGING */
703 
704 #ifdef DHD_EVENT_LOG_FILTER
705 #define CMD_EWP_FILTER		"EWP_FILTER"
706 #endif /* DHD_EVENT_LOG_FILTER */
707 
708 #ifdef WL_BCNRECV
709 #define CMD_BEACON_RECV "BEACON_RECV"
710 #endif /* WL_BCNRECV */
711 #ifdef WL_CAC_TS
712 #define CMD_CAC_TSPEC "CAC_TSPEC"
713 #endif /* WL_CAC_TS */
714 #ifdef WL_GET_CU
715 #define CMD_GET_CHAN_UTIL "GET_CU"
716 #endif /* WL_GET_CU */
717 
718 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
719 #define CMD_SET_SOFTAP_ELNA_BYPASS				"SET_SOFTAP_ELNA_BYPASS"
720 #define CMD_GET_SOFTAP_ELNA_BYPASS				"GET_SOFTAP_ELNA_BYPASS"
721 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
722 
723 #ifdef WL_NAN
724 #define CMD_GET_NAN_STATUS	"GET_NAN_STATUS"
725 #endif /* WL_NAN */
726 
727 #ifdef WL_TWT
728 #define CMD_TWT_SETUP		"TWT_SETUP"
729 #define CMD_TWT_TEARDOWN	"TWT_TEARDOWN"
730 #define CMD_TWT_INFO		"TWT_INFO_FRM"
731 #define CMD_TWT_STATUS_QUERY	"TWT_STATUS"
732 #define CMD_TWT_CAPABILITY	"TWT_CAP"
733 #endif /* WL_TWT */
734 
735 /* drv command info structure */
736 typedef struct wl_drv_cmd_info {
737 	uint8  *command;        /* pointer to the actual command */
738 	uint16 tot_len;         /* total length of the command */
739 	uint16 bytes_written;   /* Bytes written for get response */
740 } wl_drv_cmd_info_t;
741 
742 typedef struct wl_drv_sub_cmd wl_drv_sub_cmd_t;
743 typedef int (drv_cmd_handler_t)(struct net_device *dev,
744 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
745 
746 struct wl_drv_sub_cmd {
747 	char *name;
748 	uint8  version;              /* cmd  version */
749 	uint16 id;                   /* id for the dongle f/w switch/case */
750 	uint16 type;                 /* base type of argument */
751 	drv_cmd_handler_t *handler;  /* cmd handler  */
752 };
753 
754 #ifdef WL_MBO
755 
756 #define CMD_MBO		"MBO"
757 enum {
758 	WL_MBO_CMD_NON_CHAN_PREF = 1,
759 	WL_MBO_CMD_CELL_DATA_CAP = 2
760 };
761 #define WL_ANDROID_MBO_FUNC(suffix) wl_android_mbo_subcmd_ ##suffix
762 
763 static int wl_android_process_mbo_cmd(struct net_device *dev,
764 		char *command, int total_len);
765 static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
766 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
767 static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
768 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
769 
770 static const wl_drv_sub_cmd_t mbo_cmd_list[] = {
771 	{"non_pref_chan", 0x01, WL_MBO_CMD_NON_CHAN_PREF,
772 	IOVT_BUFFER, WL_ANDROID_MBO_FUNC(non_pref_chan)
773 	},
774 	{"cell_data_cap", 0x01, WL_MBO_CMD_CELL_DATA_CAP,
775 	IOVT_BUFFER, WL_ANDROID_MBO_FUNC(cell_data_cap)
776 	},
777 	{NULL, 0, 0, 0, NULL}
778 };
779 
780 #endif /* WL_MBO */
781 
782 #ifdef WL_GENL
783 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
784 static int wl_genl_init(void);
785 static int wl_genl_deinit(void);
786 
787 extern struct net init_net;
788 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
789  * possible values defined in net/netlink.h
790  */
791 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
792 	[BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
793 	[BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
794 };
795 
796 #define WL_GENL_VER 1
797 /* family definition */
798 static struct genl_family wl_genl_family = {
799 	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
800 	.hdrsize = 0,
801 	.name = "bcm-genl",        /* Netlink I/F for Android */
802 	.version = WL_GENL_VER,     /* Version Number */
803 	.maxattr = BCM_GENL_ATTR_MAX,
804 };
805 
806 /* commands: mapping between the command enumeration and the actual function */
807 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
808 struct genl_ops wl_genl_ops[] = {
809 	{
810 	.cmd = BCM_GENL_CMD_MSG,
811 	.flags = 0,
812 	.policy = wl_genl_policy,
813 	.doit = wl_genl_handle_msg,
814 	.dumpit = NULL,
815 	},
816 };
817 #else
818 struct genl_ops wl_genl_ops = {
819 	.cmd = BCM_GENL_CMD_MSG,
820 	.flags = 0,
821 	.policy = wl_genl_policy,
822 	.doit = wl_genl_handle_msg,
823 	.dumpit = NULL,
824 
825 };
826 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
827 
828 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
829 static struct genl_multicast_group wl_genl_mcast[] = {
830 	 { .name = "bcm-genl-mcast", },
831 };
832 #else
833 static struct genl_multicast_group wl_genl_mcast = {
834 	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
835 	.name = "bcm-genl-mcast",
836 };
837 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
838 #endif /* WL_GENL */
839 
840 #ifdef SUPPORT_LQCM
841 #define LQCM_ENAB_MASK			0x000000FF	/* LQCM enable flag mask */
842 #define LQCM_TX_INDEX_MASK		0x0000FF00	/* LQCM tx index mask */
843 #define LQCM_RX_INDEX_MASK		0x00FF0000	/* LQCM rx index mask */
844 
845 #define LQCM_TX_INDEX_SHIFT		8	/* LQCM tx index shift */
846 #define LQCM_RX_INDEX_SHIFT		16	/* LQCM rx index shift */
847 #endif /* SUPPORT_LQCM */
848 
849 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
850 #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS	7
851 static int priv_cmd_errors = 0;
852 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
853 
854 #ifdef WL_P2P_6G
855 #define CMD_ENABLE_6G_P2P	"ENABLE_6G_P2P"
856 #endif /* WL_P2P_6G */
857 
858 /**
859  * Extern function declarations (TODO: move them to dhd_linux.h)
860  */
861 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
862 int dhd_dev_init_ioctl(struct net_device *dev);
863 #ifdef WL_CFG80211
864 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
865 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
866 #ifdef WES_SUPPORT
867 int wl_cfg80211_set_wes_mode(struct net_device *dev, int mode);
868 int wl_cfg80211_get_wes_mode(struct net_device *dev);
869 int wl_cfg80211_set_ncho_mode(struct net_device *dev, int mode);
870 int wl_cfg80211_get_ncho_mode(struct net_device *dev);
871 #endif /* WES_SUPPORT */
872 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)873 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
874 { return 0; }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)875 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
876 { return 0; }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)877 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
878 { return 0; }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)879 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
880 { return 0; }
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)881 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
882 { return 0; }
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)883 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
884 { return 0; }
885 #endif /* WL_CFG80211 */
886 #if defined(WL_WTC) && defined(CUSTOMER_HW4_PRIVATE_CMD)
887 static int wl_android_wtc_config(struct net_device *dev, char *command, int total_len);
888 #endif /* WL_WTC && CUSTOMER_HW4_PRIVATE_CMD */
889 #ifdef WBTEXT
890 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
891 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
892 	char *command, int total_len);
893 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
894 	char *command, int total_len);
895 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
896 	char *command, int total_len);
897 static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
898 	uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size);
899 static int wl_android_wbtext_enable(struct net_device *dev, int mode);
900 #endif /* WBTEXT */
901 #ifdef WES_SUPPORT
902 /* wl_roam.c */
903 extern int get_roamscan_mode(struct net_device *dev, int *mode);
904 extern int set_roamscan_mode(struct net_device *dev, int mode);
905 extern int get_roamscan_chanspec_list(struct net_device *dev, chanspec_t *chanspecs);
906 extern int set_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
907 extern int add_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
908 
909 static char* legacy_cmdlist[] =
910 {
911 	CMD_GETROAMSCANCHLEGACY, CMD_ADDROAMSCANCHLEGACY,
912 	CMD_GETROAMSCANFQLEGACY, CMD_ADDROAMSCANFQLEGACY,
913 	CMD_GETROAMTRIGLEGACY, CMD_SETROAMTRIGLEGACY,
914 	CMD_REASSOCLEGACY,
915 	CMD_GETSCANCHANNELTIMELEGACY, CMD_SETSCANCHANNELTIMELEGACY,
916 	CMD_GETSCANUNASSOCTIMELEGACY, CMD_SETSCANUNASSOCTIMELEGACY,
917 	CMD_GETSCANPASSIVETIMELEGACY, CMD_SETSCANPASSIVETIMELEGACY,
918 	CMD_GETSCANHOMETIMELEGACY, CMD_SETSCANHOMETIMELEGACY,
919 	CMD_GETSCANHOMEAWAYTIMELEGACY, CMD_SETSCANHOMEAWAYTIMELEGACY,
920 	"\0"
921 };
922 
923 static char* ncho_cmdlist[] =
924 {
925 	CMD_ROAMTRIGGER_GET, CMD_ROAMTRIGGER_SET,
926 	CMD_ROAMDELTA_GET, CMD_ROAMDELTA_SET,
927 	CMD_ROAMSCANPERIOD_GET, CMD_ROAMSCANPERIOD_SET,
928 	CMD_FULLROAMSCANPERIOD_GET, CMD_FULLROAMSCANPERIOD_SET,
929 	CMD_COUNTRYREV_GET, CMD_COUNTRYREV_SET,
930 	CMD_GETROAMSCANCONTROL,	CMD_SETROAMSCANCONTROL,
931 	CMD_GETROAMSCANCHANNELS, CMD_SETROAMSCANCHANNELS, CMD_ADDROAMSCANCHANNELS,
932 	CMD_GETROAMSCANFREQS, CMD_SETROAMSCANFREQS, CMD_ADDROAMSCANFREQS,
933 	CMD_SENDACTIONFRAME,
934 	CMD_REASSOC,
935 	CMD_GETSCANCHANNELTIME,	CMD_SETSCANCHANNELTIME,
936 	CMD_GETSCANUNASSOCTIME,	CMD_SETSCANUNASSOCTIME,
937 	CMD_GETSCANPASSIVETIME,	CMD_SETSCANPASSIVETIME,
938 	CMD_GETSCANHOMETIME, CMD_SETSCANHOMETIME,
939 	CMD_GETSCANHOMEAWAYTIME, CMD_SETSCANHOMEAWAYTIME,
940 	CMD_GETSCANNPROBES, CMD_SETSCANNPROBES,
941 	CMD_GETDFSSCANMODE, CMD_SETDFSSCANMODE,
942 	CMD_SETJOINPREFER,
943 	CMD_GETWESMODE,	CMD_SETWESMODE,
944 	"\0"
945 };
946 #endif /* WES_SUPPORT */
947 #ifdef ROAM_CHANNEL_CACHE
948 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
949 #endif /* ROAM_CHANNEL_CACHE */
950 
951 int wl_android_priority_roam_enable(struct net_device *dev, int mode);
952 #ifdef CONFIG_SILENT_ROAM
953 int wl_android_sroam_turn_on(struct net_device *dev, int mode);
954 #endif /* CONFIG_SILENT_ROAM */
955 int wl_android_rcroam_turn_on(struct net_device *dev, int mode);
956 
957 #ifdef ENABLE_4335BT_WAR
958 extern int bcm_bt_lock(int cookie);
959 extern void bcm_bt_unlock(int cookie);
960 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24;	/* cookie is "WiFi" */
961 #endif /* ENABLE_4335BT_WAR */
962 
963 extern bool ap_fw_loaded;
964 extern char iface_name[IFNAMSIZ];
965 #ifdef DHD_PM_CONTROL_FROM_FILE
966 extern bool g_pm_control;
967 #endif	/* DHD_PM_CONTROL_FROM_FILE */
968 
969 /* private command support for restoring roam/scan parameters */
970 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
971 #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
972 
973 typedef int (*PRIV_CMD_HANDLER) (struct net_device *dev, char *command);
974 typedef int (*PRIV_CMD_HANDLER_WITH_LEN) (struct net_device *dev, char *command, int total_len);
975 
976 enum {
977 	RESTORE_TYPE_UNSPECIFIED = 0,
978 	RESTORE_TYPE_PRIV_CMD = 1,
979 	RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
980 };
981 
982 typedef struct android_restore_scan_params {
983 	char command[64];
984 	int parameter;
985 	int cmd_type;
986 	union {
987 		PRIV_CMD_HANDLER cmd_handler;
988 		PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
989 	};
990 } android_restore_scan_params_t;
991 
992 /* function prototypes of private command handler */
993 static int wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len);
994 static int wl_android_set_roam_trigger(struct net_device *dev, char* command);
995 int wl_android_set_roam_delta(struct net_device *dev, char* command);
996 int wl_android_set_roam_scan_period(struct net_device *dev, char* command);
997 int wl_android_set_full_roam_scan_period(struct net_device *dev, char* command);
998 int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
999 int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
1000 int wl_android_set_scan_home_time(struct net_device *dev, char *command);
1001 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
1002 int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
1003 static int wl_android_set_band(struct net_device *dev, char *command);
1004 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
1005 int wl_android_set_wes_mode(struct net_device *dev, char *command);
1006 int wl_android_set_okc_mode(struct net_device *dev, char *command);
1007 
1008 /* default values */
1009 #ifdef ROAM_API
1010 #define DEFAULT_ROAM_TIRGGER	-75
1011 #define DEFAULT_ROAM_DELTA	10
1012 #define DEFAULT_ROAMSCANPERIOD	10
1013 #define DEFAULT_FULLROAMSCANPERIOD_SET	120
1014 #endif /* ROAM_API */
1015 #ifdef WES_SUPPORT
1016 #define DEFAULT_ROAMSCANCONTROL	0
1017 #define DEFAULT_SCANCHANNELTIME	40
1018 #ifdef BCM4361_CHIP
1019 #define DEFAULT_SCANHOMETIME	60
1020 #else
1021 #define DEFAULT_SCANHOMETIME	45
1022 #endif /* BCM4361_CHIP */
1023 #define DEFAULT_SCANHOMEAWAYTIME	100
1024 #define DEFAULT_SCANPROBES	2
1025 #define DEFAULT_DFSSCANMODE	1
1026 #define DEFAULT_WESMODE		0
1027 #define DEFAULT_OKCMODE		1
1028 #endif /* WES_SUPPORT */
1029 #define DEFAULT_BAND		0
1030 #ifdef WBTEXT
1031 #define DEFAULT_WBTEXT_ENABLE	1
1032 #endif /* WBTEXT */
1033 
1034 /* restoring parameter list, please don't change order */
1035 static android_restore_scan_params_t restore_params[] =
1036 {
1037 /* wbtext need to be disabled while updating roam/scan parameters */
1038 #ifdef WBTEXT
1039 	{ CMD_WBTEXT_ENABLE, 0, RESTORE_TYPE_PRIV_CMD_WITH_LEN,
1040 		.cmd_handler_w_len = wl_android_wbtext},
1041 #endif /* WBTEXT */
1042 #ifdef ROAM_API
1043 	{ CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER,
1044 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_trigger},
1045 	{ CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA,
1046 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_delta},
1047 	{ CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD,
1048 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_period},
1049 	{ CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
1050 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_full_roam_scan_period},
1051 #endif /* ROAM_API */
1052 #ifdef WES_SUPPORT
1053 	{ CMD_SETROAMSCANCONTROL, DEFAULT_ROAMSCANCONTROL,
1054 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_control},
1055 	{ CMD_SETSCANCHANNELTIME, DEFAULT_SCANCHANNELTIME,
1056 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time},
1057 	{ CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME,
1058 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time},
1059 	{ CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME,
1060 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time},
1061 	{ CMD_SETSCANNPROBES, DEFAULT_SCANPROBES,
1062 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes},
1063 	{ CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE,
1064 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode},
1065 	{ CMD_SETWESMODE, DEFAULT_WESMODE,
1066 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode},
1067 #endif /* WES_SUPPORT */
1068 	{ CMD_SETBAND, DEFAULT_BAND,
1069 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band},
1070 #ifdef WBTEXT
1071 	{ CMD_WBTEXT_ENABLE, DEFAULT_WBTEXT_ENABLE,
1072 		RESTORE_TYPE_PRIV_CMD_WITH_LEN, .cmd_handler_w_len = wl_android_wbtext},
1073 #endif /* WBTEXT */
1074 	{ "\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}
1075 };
1076 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
1077 
1078 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1079 #define CMD_GET_LATENCY_CRITICAL_DATA	"GET_LATENCY_CRT_DATA"
1080 #define CMD_SET_LATENCY_CRITICAL_DATA	"SET_LATENCY_CRT_DATA"
1081 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
1082 
1083 typedef struct android_priv_cmd_log_cfg_table {
1084 	char command[64];
1085 	int  enable;
1086 } android_priv_cmd_log_cfg_table_t;
1087 
1088 static android_priv_cmd_log_cfg_table_t loging_params[] = {
1089 	{CMD_GET_SNR, FALSE},
1090 #ifdef SUPPORT_LQCM
1091 	{CMD_GET_LQCM_REPORT, FALSE},
1092 #endif
1093 #ifdef WL_GET_CU
1094 	{CMD_GET_CHAN_UTIL, FALSE},
1095 #endif
1096 	{"\0", FALSE}
1097 };
1098 
1099 /**
1100  * Local (static) functions and variables
1101  */
1102 
1103 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
1104  * time (only) in dhd_open, subsequential wifi on will be handled by
1105  * wl_android_wifi_on
1106  */
1107 int g_wifi_on = TRUE;
1108 
1109 /**
1110  * Local (static) function definitions
1111  */
1112 
wl_android_get_band_str(u16 band)1113 static char* wl_android_get_band_str(u16 band)
1114 {
1115 	switch (band) {
1116 #ifdef WL_6G_BAND
1117 		case WLC_BAND_6G:
1118 			return "6G";
1119 #endif /* WL_6G_BAND */
1120 		case WLC_BAND_5G:
1121 			return "5G";
1122 		case WLC_BAND_2G:
1123 			return "2G";
1124 		default:
1125 			ANDROID_ERROR(("Unkown band: %d \n", band));
1126 			return "Unknown band";
1127 	}
1128 }
1129 
1130 #ifdef WBTEXT
wl_android_bandstr_to_fwband(char * band,u8 * fw_band)1131 static int wl_android_bandstr_to_fwband(char *band, u8 *fw_band)
1132 {
1133 	int err = BCME_OK;
1134 
1135 	if (!strcasecmp(band, "a")) {
1136 		*fw_band = WLC_BAND_5G;
1137 	} else if (!strcasecmp(band, "b")) {
1138 		*fw_band = WLC_BAND_2G;
1139 #ifdef WL_6G_BAND
1140 	} else if (!strcasecmp(band, "6g")) {
1141 		*fw_band = WLC_BAND_6G;
1142 #endif /* WL_6G_BAND */
1143 	} else if (!strcasecmp(band, "all")) {
1144 		*fw_band = WLC_BAND_ALL;
1145 	} else {
1146 		err = BCME_BADBAND;
1147 	}
1148 
1149 	return err;
1150 }
1151 #endif /* WBTEXT */
1152 
1153 #ifdef WLWFDS
wl_android_set_wfds_hash(struct net_device * dev,char * command,bool enable)1154 static int wl_android_set_wfds_hash(
1155 	struct net_device *dev, char *command, bool enable)
1156 {
1157 	int error = 0;
1158 	wl_p2p_wfds_hash_t *wfds_hash = NULL;
1159 	char *smbuf = NULL;
1160 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1161 
1162 	smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
1163 	if (smbuf == NULL) {
1164 		ANDROID_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n",
1165 			WLC_IOCTL_MAXLEN));
1166 		return -ENOMEM;
1167 	}
1168 
1169 	if (enable) {
1170 		wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
1171 		error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
1172 			sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1173 	}
1174 	else {
1175 		wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
1176 		error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
1177 			sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1178 	}
1179 
1180 	if (error) {
1181 		ANDROID_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error));
1182 	}
1183 
1184 	if (smbuf) {
1185 		MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
1186 	}
1187 	return error;
1188 }
1189 #endif /* WLWFDS */
1190 
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)1191 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
1192 {
1193 	int link_speed;
1194 	int bytes_written;
1195 	int error;
1196 
1197 	error = wldev_get_link_speed(net, &link_speed);
1198 	if (error) {
1199 		ANDROID_ERROR(("Get linkspeed failed \n"));
1200 		return -1;
1201 	}
1202 
1203 	/* Convert Kbps to Android Mbps */
1204 	link_speed = link_speed / 1000;
1205 	bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
1206 	ANDROID_INFO(("wl_android_get_link_speed: command result is %s\n", command));
1207 	return bytes_written;
1208 }
1209 
wl_android_get_rssi(struct net_device * net,char * command,int total_len)1210 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
1211 {
1212 	wlc_ssid_t ssid = {0, {0}};
1213 	int bytes_written = 0;
1214 	int error = 0;
1215 	scb_val_t scbval;
1216 	char *delim = NULL;
1217 	struct net_device *target_ndev = net;
1218 #ifdef WL_VIRTUAL_APSTA
1219 	char *pos = NULL;
1220 	struct bcm_cfg80211 *cfg;
1221 #endif /* WL_VIRTUAL_APSTA */
1222 
1223 	delim = strchr(command, ' ');
1224 	/* For Ap mode rssi command would be
1225 	 * driver rssi <sta_mac_addr>
1226 	 * for STA/GC mode
1227 	 * driver rssi
1228 	*/
1229 	if (delim) {
1230 		/* Ap/GO mode
1231 		* driver rssi <sta_mac_addr>
1232 		*/
1233 		ANDROID_TRACE(("wl_android_get_rssi: cmd:%s\n", delim));
1234 		/* skip space from delim after finding char */
1235 		delim++;
1236 		if (!(bcm_ether_atoe((delim), &scbval.ea))) {
1237 			ANDROID_ERROR(("wl_android_get_rssi: address err\n"));
1238 			return -1;
1239 		}
1240 		scbval.val = htod32(0);
1241 		ANDROID_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet)));
1242 #ifdef WL_VIRTUAL_APSTA
1243 		/* RSDB AP may have another virtual interface
1244 		 * In this case, format of private command is as following,
1245 		 * DRIVER rssi <sta_mac_addr> <AP interface name>
1246 		 */
1247 
1248 		/* Current position is start of MAC address string */
1249 		pos = delim;
1250 		delim = strchr(pos, ' ');
1251 		if (delim) {
1252 			/* skip space from delim after finding char */
1253 			delim++;
1254 			if (strnlen(delim, IFNAMSIZ)) {
1255 				cfg = wl_get_cfg(net);
1256 				target_ndev = wl_get_ap_netdev(cfg, delim);
1257 				if (target_ndev == NULL)
1258 					target_ndev = net;
1259 			}
1260 		}
1261 #endif /* WL_VIRTUAL_APSTA */
1262 	}
1263 	else {
1264 		/* STA/GC mode */
1265 		bzero(&scbval, sizeof(scb_val_t));
1266 	}
1267 
1268 	error = wldev_get_rssi(target_ndev, &scbval);
1269 	if (error)
1270 		return -1;
1271 #if defined(RSSIOFFSET)
1272 	scbval.val = wl_update_rssi_offset(net, scbval.val);
1273 #endif
1274 
1275 	error = wldev_get_ssid(target_ndev, &ssid);
1276 	if (error)
1277 		return -1;
1278 	if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
1279 		ANDROID_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n"));
1280 	} else if (total_len <= ssid.SSID_len) {
1281 		return -ENOMEM;
1282 	} else {
1283 		memcpy(command, ssid.SSID, ssid.SSID_len);
1284 		bytes_written = ssid.SSID_len;
1285 	}
1286 	if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
1287 		return -ENOMEM;
1288 
1289 	bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
1290 		" rssi %d", scbval.val);
1291 	command[bytes_written] = '\0';
1292 
1293 	ANDROID_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written));
1294 	return bytes_written;
1295 }
1296 
wl_android_set_suspendopt(struct net_device * dev,char * command)1297 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
1298 {
1299 	int suspend_flag;
1300 	int ret_now;
1301 	int ret = 0;
1302 
1303 	suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
1304 
1305 	if (suspend_flag != 0) {
1306 		suspend_flag = 1;
1307 	}
1308 	ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1309 
1310 	if (ret_now != suspend_flag) {
1311 		if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
1312 			ANDROID_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n",
1313 				ret_now, suspend_flag));
1314 		} else {
1315 			ANDROID_ERROR(("wl_android_set_suspendopt: failed %d\n", ret));
1316 		}
1317 	}
1318 
1319 	return ret;
1320 }
1321 
wl_android_set_suspendmode(struct net_device * dev,char * command)1322 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
1323 {
1324 	int ret = 0;
1325 
1326 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
1327 	int suspend_flag;
1328 
1329 	suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
1330 	if (suspend_flag != 0)
1331 		suspend_flag = 1;
1332 
1333 	if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
1334 		ANDROID_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag));
1335 	else
1336 		ANDROID_ERROR(("wl_android_set_suspendmode: failed %d\n", ret));
1337 #endif
1338 
1339 	return ret;
1340 }
1341 
1342 #ifdef WL_CFG80211
wl_android_get_80211_mode(struct net_device * dev,char * command,int total_len)1343 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
1344 {
1345 	uint8 mode[5];
1346 	int  error = 0;
1347 	int bytes_written = 0;
1348 
1349 	error = wldev_get_mode(dev, mode, sizeof(mode));
1350 	if (error)
1351 		return -1;
1352 
1353 	ANDROID_INFO(("wl_android_get_80211_mode: mode:%s\n", mode));
1354 	bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
1355 	ANDROID_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command));
1356 	return bytes_written;
1357 
1358 }
1359 
1360 extern chanspec_t
1361 wl_chspec_driver_to_host(chanspec_t chanspec);
wl_android_get_chanspec(struct net_device * dev,char * command,int total_len)1362 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
1363 {
1364 	int error = 0;
1365 	int bytes_written = 0;
1366 	int chsp = {0};
1367 	uint16 band = 0;
1368 	uint16 bw = 0;
1369 	uint16 channel = 0;
1370 	u32 sb = 0;
1371 	chanspec_t chanspec;
1372 
1373 	/* command is
1374 	 * driver chanspec
1375 	 */
1376 	error = wldev_iovar_getint(dev, "chanspec", &chsp);
1377 	if (error)
1378 		return -1;
1379 
1380 	chanspec = wl_chspec_driver_to_host(chsp);
1381 	ANDROID_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec));
1382 
1383 	channel = chanspec & WL_CHANSPEC_CHAN_MASK;
1384 	band = chanspec & WL_CHANSPEC_BAND_MASK;
1385 	bw = chanspec & WL_CHANSPEC_BW_MASK;
1386 
1387 	ANDROID_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n",
1388 		channel, band, bw));
1389 
1390 	if (bw == WL_CHANSPEC_BW_160) {
1391 		bw = WL_CH_BANDWIDTH_160MHZ;
1392 	} else if (bw == WL_CHANSPEC_BW_80) {
1393 		bw = WL_CH_BANDWIDTH_80MHZ;
1394 	} else if (bw == WL_CHANSPEC_BW_40) {
1395 		bw = WL_CH_BANDWIDTH_40MHZ;
1396 	} else if (bw == WL_CHANSPEC_BW_20) {
1397 		bw = WL_CH_BANDWIDTH_20MHZ;
1398 	} else {
1399 		bw = WL_CH_BANDWIDTH_20MHZ;
1400 	}
1401 
1402 	if (bw == WL_CH_BANDWIDTH_40MHZ) {
1403 		if (CHSPEC_SB_UPPER(chanspec)) {
1404 			channel += CH_10MHZ_APART;
1405 		} else {
1406 			channel -= CH_10MHZ_APART;
1407 		}
1408 	}
1409 	else if (bw == WL_CH_BANDWIDTH_80MHZ) {
1410 		sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
1411 		if (sb == WL_CHANSPEC_CTL_SB_LL) {
1412 			channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
1413 		} else if (sb == WL_CHANSPEC_CTL_SB_LU) {
1414 			channel -= CH_10MHZ_APART;
1415 		} else if (sb == WL_CHANSPEC_CTL_SB_UL) {
1416 			channel += CH_10MHZ_APART;
1417 		} else {
1418 			/* WL_CHANSPEC_CTL_SB_UU */
1419 			channel += (CH_10MHZ_APART + CH_20MHZ_APART);
1420 		}
1421 	} else if (bw == WL_CH_BANDWIDTH_160MHZ) {
1422 		channel = wf_chspec_primary20_chan(chanspec);
1423 	}
1424 	bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
1425 		channel, wl_android_get_band_str(CHSPEC2WLC_BAND(chanspec)), bw);
1426 
1427 	ANDROID_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command));
1428 	return bytes_written;
1429 
1430 }
1431 #endif /* WL_CFG80211 */
1432 
1433 /* returns current datarate datarate returned from firmware are in 500kbps */
wl_android_get_datarate(struct net_device * dev,char * command,int total_len)1434 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
1435 {
1436 	int  error = 0;
1437 	int datarate = 0;
1438 	int bytes_written = 0;
1439 
1440 	error = wldev_get_datarate(dev, &datarate);
1441 	if (error)
1442 		return -1;
1443 
1444 	ANDROID_INFO(("wl_android_get_datarate: datarate:%d\n", datarate));
1445 
1446 	bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
1447 	return bytes_written;
1448 }
wl_android_get_assoclist(struct net_device * dev,char * command,int total_len)1449 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
1450 {
1451 	int  error = 0;
1452 	int bytes_written = 0;
1453 	uint i;
1454 	int len = 0;
1455 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
1456 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
1457 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1458 
1459 	ANDROID_TRACE(("wl_android_get_assoclist: ENTER\n"));
1460 
1461 	assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
1462 
1463 	error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
1464 	if (error)
1465 		return -1;
1466 
1467 	assoc_maclist->count = dtoh32(assoc_maclist->count);
1468 	bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
1469 		CMD_ASSOC_CLIENTS, assoc_maclist->count);
1470 
1471 	for (i = 0; i < assoc_maclist->count; i++) {
1472 		len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
1473 			MAC2STRDBG(assoc_maclist->ea[i].octet));
1474 		/* A return value of '(total_len - bytes_written)' or more means that the
1475 		 * output was truncated
1476 		 */
1477 		if ((len > 0) && (len < (total_len - bytes_written))) {
1478 			bytes_written += len;
1479 		} else {
1480 			ANDROID_ERROR(("wl_android_get_assoclist: Insufficient buffer %d,"
1481 				" bytes_written %d\n",
1482 				total_len, bytes_written));
1483 			bytes_written = -1;
1484 			break;
1485 		}
1486 	}
1487 	return bytes_written;
1488 }
1489 
1490 #ifdef WL_CFG80211
1491 extern chanspec_t
1492 wl_chspec_host_to_driver(chanspec_t chanspec);
wl_android_set_csa(struct net_device * dev,char * command)1493 static int wl_android_set_csa(struct net_device *dev, char *command)
1494 {
1495 	int error = 0;
1496 	char smbuf[WLC_IOCTL_SMLEN];
1497 	wl_chan_switch_t csa_arg;
1498 	u32 chnsp = 0;
1499 	int err = 0;
1500 
1501 	ANDROID_INFO(("wl_android_set_csa: command:%s\n", command));
1502 
1503 	command = (command + strlen(CMD_SET_CSA));
1504 	/* Order is mode, count channel */
1505 	if (!*++command) {
1506 		ANDROID_ERROR(("wl_android_set_csa:error missing arguments\n"));
1507 		return -1;
1508 	}
1509 	csa_arg.mode = bcm_atoi(command);
1510 
1511 	if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1512 		ANDROID_ERROR(("Invalid mode\n"));
1513 		return -1;
1514 	}
1515 
1516 	if (!*++command) {
1517 		ANDROID_ERROR(("wl_android_set_csa: error missing count\n"));
1518 		return -1;
1519 	}
1520 	command++;
1521 	csa_arg.count = bcm_atoi(command);
1522 
1523 	csa_arg.reg = 0;
1524 	csa_arg.chspec = 0;
1525 	command += 2;
1526 	if (!*command) {
1527 		ANDROID_ERROR(("wl_android_set_csa: error missing channel\n"));
1528 		return -1;
1529 	}
1530 
1531 	chnsp = wf_chspec_aton(command);
1532 	if (chnsp == 0)	{
1533 		ANDROID_ERROR(("wl_android_set_csa:chsp is not correct\n"));
1534 		return -1;
1535 	}
1536 	chnsp = wl_chspec_host_to_driver(chnsp);
1537 	csa_arg.chspec = chnsp;
1538 
1539 	if (chnsp & WL_CHANSPEC_BAND_5G) {
1540 		u32 chanspec = chnsp;
1541 		err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1542 		if (!err) {
1543 			if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1544 				ANDROID_ERROR(("Channel is radar sensitive\n"));
1545 				return -1;
1546 			}
1547 			if (chanspec == 0) {
1548 				ANDROID_ERROR(("Invalid hw channel\n"));
1549 				return -1;
1550 			}
1551 		} else  {
1552 			ANDROID_ERROR(("does not support per_chan_info\n"));
1553 			return -1;
1554 		}
1555 		ANDROID_INFO(("non radar sensitivity\n"));
1556 	}
1557 	error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
1558 		smbuf, sizeof(smbuf), NULL);
1559 	if (error) {
1560 		ANDROID_ERROR(("wl_android_set_csa:set csa failed:%d\n", error));
1561 		return -1;
1562 	}
1563 	return 0;
1564 }
1565 #endif /* WL_CFG80211 */
1566 
1567 static int
wl_android_set_bcn_li_dtim(struct net_device * dev,char * command)1568 wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1569 {
1570 	int ret = 0;
1571 	int dtim;
1572 
1573 	dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1574 
1575 	if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1576 		ANDROID_ERROR(("%s: failed, invalid dtim %d\n",
1577 			__FUNCTION__, dtim));
1578 		return BCME_ERROR;
1579 	}
1580 
1581 	if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1582 		ANDROID_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
1583 			__FUNCTION__, dtim));
1584 	} else {
1585 		ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1586 	}
1587 
1588 	return ret;
1589 }
1590 
1591 static int
wl_android_set_max_dtim(struct net_device * dev,char * command)1592 wl_android_set_max_dtim(struct net_device *dev, char *command)
1593 {
1594 	int ret = 0;
1595 	int dtim_flag;
1596 
1597 	dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1598 
1599 	if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1600 		ANDROID_TRACE(("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n",
1601 			(dtim_flag ? "Enable" : "Disable")));
1602 	} else {
1603 		ANDROID_ERROR(("wl_android_set_max_dtim: failed %d\n", ret));
1604 	}
1605 
1606 	return ret;
1607 }
1608 
1609 #ifdef DISABLE_DTIM_IN_SUSPEND
1610 static int
wl_android_set_disable_dtim_in_suspend(struct net_device * dev,char * command)1611 wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command)
1612 {
1613 	int ret = 0;
1614 	int dtim_flag;
1615 
1616 	dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
1617 
1618 	if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
1619 		ANDROID_TRACE(("wl_android_set_disable_dtim_in_suspend: "
1620 			"use Disable bcn_li_dtim in suspend %s\n",
1621 			(dtim_flag ? "Enable" : "Disable")));
1622 	} else {
1623 		ANDROID_ERROR(("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret));
1624 	}
1625 
1626 	return ret;
1627 }
1628 #endif /* DISABLE_DTIM_IN_SUSPEND */
1629 
wl_android_get_band(struct net_device * dev,char * command,int total_len)1630 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
1631 {
1632 	uint band;
1633 	int bytes_written;
1634 	int error = BCME_OK;
1635 
1636 	error = wldev_iovar_getint(dev, "if_band", &band);
1637 	if (error == BCME_UNSUPPORTED) {
1638 		error = wldev_get_band(dev, &band);
1639 		if (error) {
1640 			return error;
1641 		}
1642 	}
1643 	bytes_written = snprintf(command, total_len, "Band %d", band);
1644 	return bytes_written;
1645 }
1646 
1647 #ifdef WL_CFG80211
1648 static int
wl_android_set_band(struct net_device * dev,char * command)1649 wl_android_set_band(struct net_device *dev, char *command)
1650 {
1651 	int error = 0;
1652 	uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1653 #ifdef WL_HOST_BAND_MGMT
1654 	int ret = 0;
1655 	if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
1656 		if (ret == BCME_UNSUPPORTED) {
1657 			/* If roam_var is unsupported, fallback to the original method */
1658 			ANDROID_ERROR(("WL_HOST_BAND_MGMT defined, "
1659 				"but roam_band iovar unsupported in the firmware\n"));
1660 		} else {
1661 			error = -1;
1662 		}
1663 	}
1664 	if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
1665 		/* Apply if roam_band iovar is not supported or band setting is AUTO */
1666 		error = wldev_set_band(dev, band);
1667 	}
1668 #else
1669 	error = wl_cfg80211_set_if_band(dev, band);
1670 #endif /* WL_HOST_BAND_MGMT */
1671 #ifdef ROAM_CHANNEL_CACHE
1672 	wl_update_roamscan_cache_by_band(dev, band);
1673 #endif /* ROAM_CHANNEL_CACHE */
1674 	return error;
1675 }
1676 #endif /* WL_CFG80211 */
1677 
1678 #ifdef CUSTOMER_HW4_PRIVATE_CMD
1679 #ifdef ROAM_API
1680 #ifdef WBTEXT
wl_android_check_wbtext_support(struct net_device * dev)1681 static bool wl_android_check_wbtext_support(struct net_device *dev)
1682 {
1683 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1684 	return dhdp->wbtext_support;
1685 }
1686 #endif /* WBTEXT */
1687 
1688 static bool
wl_android_check_wbtext_policy(struct net_device * dev)1689 wl_android_check_wbtext_policy(struct net_device *dev)
1690 {
1691 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1692 	if (dhdp->wbtext_policy == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
1693 		return TRUE;
1694 	}
1695 
1696 	return FALSE;
1697 }
1698 
1699 static int
wl_android_set_roam_trigger(struct net_device * dev,char * command)1700 wl_android_set_roam_trigger(struct net_device *dev, char* command)
1701 {
1702 	int roam_trigger[2] = {0, 0};
1703 	int error;
1704 
1705 #ifdef WBTEXT
1706 	if (wl_android_check_wbtext_policy(dev)) {
1707 		ANDROID_ERROR(("blocked to set roam trigger. try with setting roam profile\n"));
1708 		return BCME_ERROR;
1709 	}
1710 #endif /* WBTEXT */
1711 
1712 	sscanf(command, "%*s %10d", &roam_trigger[0]);
1713 	if (roam_trigger[0] >= 0) {
1714 		ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1715 		return BCME_ERROR;
1716 	}
1717 
1718 	roam_trigger[1] = WLC_BAND_ALL;
1719 	error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1720 		sizeof(roam_trigger));
1721 	if (error != BCME_OK) {
1722 		ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1723 		return BCME_ERROR;
1724 	}
1725 
1726 	return BCME_OK;
1727 }
1728 
1729 static int
wl_android_get_roam_trigger(struct net_device * dev,char * command,int total_len)1730 wl_android_get_roam_trigger(struct net_device *dev, char *command, int total_len)
1731 {
1732 	int bytes_written, error;
1733 	int roam_trigger[2] = {0, 0};
1734 	uint16 band = 0;
1735 	int chsp = {0};
1736 	chanspec_t chanspec;
1737 #ifdef WBTEXT
1738 	int i;
1739 	wl_roamprof_band_t rp;
1740 	uint8 roam_prof_ver = 0, roam_prof_size = 0;
1741 #endif /* WBTEXT */
1742 
1743 	error = wldev_iovar_getint(dev, "chanspec", &chsp);
1744 	if (error != BCME_OK) {
1745 		ANDROID_ERROR(("failed to get chanspec (%d)\n", error));
1746 		return BCME_ERROR;
1747 	}
1748 
1749 	chanspec = wl_chspec_driver_to_host(chsp);
1750 	band = CHSPEC2WLC_BAND(chanspec);
1751 
1752 	if (wl_android_check_wbtext_policy(dev)) {
1753 #ifdef WBTEXT
1754 		memset_s(&rp, sizeof(rp), 0, sizeof(rp));
1755 		if ((error = wlc_wbtext_get_roam_prof(dev, &rp, band, &roam_prof_ver,
1756 			&roam_prof_size))) {
1757 			ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", error));
1758 			return -EINVAL;
1759 		}
1760 		switch (roam_prof_ver) {
1761 			case WL_ROAM_PROF_VER_1:
1762 			{
1763 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1764 					if (rp.v2.roam_prof[i].channel_usage == 0) {
1765 						roam_trigger[0] = rp.v2.roam_prof[i].roam_trigger;
1766 						break;
1767 					}
1768 				}
1769 			}
1770 			break;
1771 			case WL_ROAM_PROF_VER_2:
1772 			{
1773 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1774 					if (rp.v3.roam_prof[i].channel_usage == 0) {
1775 						roam_trigger[0] = rp.v3.roam_prof[i].roam_trigger;
1776 						break;
1777 					}
1778 				}
1779 			}
1780 			break;
1781 			case WL_ROAM_PROF_VER_3:
1782 			{
1783 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1784 					if (rp.v4.roam_prof[i].channel_usage == 0) {
1785 						roam_trigger[0] = rp.v4.roam_prof[i].roam_trigger;
1786 						break;
1787 					}
1788 				}
1789 			}
1790 			break;
1791 			default:
1792 				ANDROID_ERROR(("bad version = %d \n", roam_prof_ver));
1793 				return BCME_VERSION;
1794 		}
1795 #endif /* WBTEXT */
1796 		if (roam_trigger[0] == 0) {
1797 			ANDROID_ERROR(("roam trigger was not set properly\n"));
1798 			return BCME_ERROR;
1799 		}
1800 	} else {
1801 		roam_trigger[1] = band;
1802 		error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
1803 			sizeof(roam_trigger));
1804 		if (error != BCME_OK) {
1805 			ANDROID_ERROR(("failed to get roam trigger (%d)\n", error));
1806 			return BCME_ERROR;
1807 		}
1808 	}
1809 
1810 	bytes_written = snprintf(command, total_len, "%s %d",
1811 		CMD_ROAMTRIGGER_GET, roam_trigger[0]);
1812 
1813 	return bytes_written;
1814 }
1815 
1816 #ifdef WBTEXT
1817 s32
wl_cfg80211_wbtext_roam_trigger_config(struct net_device * ndev,int roam_trigger)1818 wl_cfg80211_wbtext_roam_trigger_config(struct net_device *ndev, int roam_trigger)
1819 {
1820 	char *commandp = NULL;
1821 	s32 ret = BCME_OK;
1822 	char *data;
1823 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1824 	uint8 bandidx = 0;
1825 
1826 	commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
1827 	if (unlikely(!commandp)) {
1828 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
1829 		ret =  -ENOMEM;
1830 		goto exit;
1831 	}
1832 
1833 	ANDROID_INFO(("roam trigger %d\n", roam_trigger));
1834 	if (roam_trigger > 0) {
1835 		ANDROID_ERROR(("Invalid roam trigger value %d\n", roam_trigger));
1836 		goto exit;
1837 	}
1838 
1839 	for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
1840 		char *band;
1841 		int tri0, tri1, low0, low1, cu0, cu1, dur0, dur1;
1842 		int tri0_dflt;
1843 		if (bandidx == BAND_5G_INDEX) {
1844 			band = "a";
1845 			tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_A;
1846 		} else {
1847 			band = "b";
1848 			tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_B;
1849 		}
1850 
1851 		/* Get ROAM Profile
1852 		 * WBTEXT_PROFILE_CONFIG band
1853 		 */
1854 		bzero(commandp, WLC_IOCTL_SMLEN);
1855 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
1856 			CMD_WBTEXT_PROFILE_CONFIG, band);
1857 		data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
1858 		wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1859 
1860 		/* Set ROAM Profile
1861 		 * WBTEXT_PROFILE_CONFIG band -70 roam_trigger 70 10 roam_trigger -128 0 10
1862 		 */
1863 		sscanf(commandp, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)"
1864 			"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
1865 			&tri0, &low0, &cu0, &dur0, &tri1, &low1, &cu1, &dur1);
1866 
1867 		if (tri0_dflt <= roam_trigger) {
1868 			tri0 = roam_trigger + 1;
1869 		} else {
1870 			tri0 = tri0_dflt;
1871 		}
1872 
1873 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
1874 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s %d %d %d %d %d %d %d %d",
1875 			CMD_WBTEXT_PROFILE_CONFIG, band,
1876 			tri0, roam_trigger, cu0, dur0, roam_trigger, low1, cu1, dur1);
1877 
1878 		ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1879 		if (ret != BCME_OK) {
1880 			ANDROID_ERROR(("Failed to set roam_prof %s error = %d\n", data, ret));
1881 			goto exit;
1882 		}
1883 	}
1884 
1885 exit:
1886 	if (commandp) {
1887 		MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
1888 	}
1889 	return ret;
1890 }
1891 #endif /* WBTEXT */
1892 
1893 static int
wl_android_set_roam_trigger_legacy(struct net_device * dev,char * command)1894 wl_android_set_roam_trigger_legacy(struct net_device *dev, char* command)
1895 {
1896 	int roam_trigger[2] = {0, 0};
1897 	int error;
1898 
1899 	sscanf(command, "%*s %10d", &roam_trigger[0]);
1900 	if (roam_trigger[0] >= 0) {
1901 		ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1902 		return BCME_ERROR;
1903 	}
1904 
1905 	if (wl_android_check_wbtext_policy(dev)) {
1906 #ifdef WBTEXT
1907 		error = wl_cfg80211_wbtext_roam_trigger_config(dev, roam_trigger[0]);
1908 		if (error != BCME_OK) {
1909 			ANDROID_ERROR(("failed to set roam prof trigger (%d)\n", error));
1910 			return BCME_ERROR;
1911 		}
1912 #endif /* WBTEXT */
1913 	} else {
1914 		if (roam_trigger[0] >= 0) {
1915 			ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1916 			return BCME_ERROR;
1917 		}
1918 
1919 		roam_trigger[1] = WLC_BAND_ALL;
1920 		error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1921 			sizeof(roam_trigger));
1922 		if (error != BCME_OK) {
1923 			ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1924 			return BCME_ERROR;
1925 		}
1926 	}
1927 
1928 	return BCME_OK;
1929 }
1930 
wl_android_set_roam_delta(struct net_device * dev,char * command)1931 int wl_android_set_roam_delta(
1932 	struct net_device *dev, char* command)
1933 {
1934 	int roam_delta[2];
1935 
1936 	sscanf(command, "%*s %10d", &roam_delta[0]);
1937 	roam_delta[1] = WLC_BAND_ALL;
1938 
1939 	return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
1940 		sizeof(roam_delta));
1941 }
1942 
wl_android_get_roam_delta(struct net_device * dev,char * command,int total_len)1943 static int wl_android_get_roam_delta(
1944 	struct net_device *dev, char *command, int total_len)
1945 {
1946 	int bytes_written;
1947 	int roam_delta[2] = {0, 0};
1948 
1949 	roam_delta[1] = WLC_BAND_2G;
1950 	if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1951 		sizeof(roam_delta))) {
1952 		roam_delta[1] = WLC_BAND_5G;
1953 #ifdef WL_6G_BAND
1954 		if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1955 			sizeof(roam_delta))) {
1956 			roam_delta[1] = WLC_BAND_6G;
1957 #endif /* WL_6G_BAND */
1958 			if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1959 				sizeof(roam_delta))) {
1960 				return -1;
1961 			}
1962 #ifdef WL_6G_BAND
1963 		}
1964 #endif /* WL_6G_BAND */
1965 	}
1966 
1967 	bytes_written = snprintf(command, total_len, "%s %d",
1968 		CMD_ROAMDELTA_GET, roam_delta[0]);
1969 
1970 	return bytes_written;
1971 }
1972 
wl_android_set_roam_scan_period(struct net_device * dev,char * command)1973 int wl_android_set_roam_scan_period(
1974 	struct net_device *dev, char* command)
1975 {
1976 	int roam_scan_period = 0;
1977 
1978 	sscanf(command, "%*s %10d", &roam_scan_period);
1979 	return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
1980 		sizeof(roam_scan_period));
1981 }
1982 
wl_android_get_roam_scan_period(struct net_device * dev,char * command,int total_len)1983 static int wl_android_get_roam_scan_period(
1984 	struct net_device *dev, char *command, int total_len)
1985 {
1986 	int bytes_written;
1987 	int roam_scan_period = 0;
1988 
1989 	if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
1990 		sizeof(roam_scan_period)))
1991 		return -1;
1992 
1993 	bytes_written = snprintf(command, total_len, "%s %d",
1994 		CMD_ROAMSCANPERIOD_GET, roam_scan_period);
1995 
1996 	return bytes_written;
1997 }
1998 
wl_android_set_full_roam_scan_period(struct net_device * dev,char * command)1999 int wl_android_set_full_roam_scan_period(
2000 	struct net_device *dev, char* command)
2001 {
2002 	int error = 0;
2003 	int full_roam_scan_period = 0;
2004 	char smbuf[WLC_IOCTL_SMLEN];
2005 
2006 	sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
2007 	WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
2008 
2009 	error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
2010 		sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
2011 	if (error) {
2012 		ANDROID_ERROR(("Failed to set full roam scan period, error = %d\n", error));
2013 	}
2014 
2015 	return error;
2016 }
2017 
wl_android_get_full_roam_scan_period(struct net_device * dev,char * command,int total_len)2018 static int wl_android_get_full_roam_scan_period(
2019 	struct net_device *dev, char *command, int total_len)
2020 {
2021 	int error;
2022 	int bytes_written;
2023 	int full_roam_scan_period = 0;
2024 
2025 	error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
2026 
2027 	if (error) {
2028 		ANDROID_ERROR(("%s: get full roam scan period failed code %d\n",
2029 			__func__, error));
2030 		return -1;
2031 	} else {
2032 		ANDROID_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
2033 	}
2034 
2035 	bytes_written = snprintf(command, total_len, "%s %d",
2036 		CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
2037 
2038 	return bytes_written;
2039 }
2040 
wl_android_set_country_rev(struct net_device * dev,char * command)2041 int wl_android_set_country_rev(
2042 	struct net_device *dev, char* command)
2043 {
2044 	int error = 0;
2045 	wl_country_t cspec = {{0}, 0, {0} };
2046 	char country_code[WLC_CNTRY_BUF_SZ];
2047 	char smbuf[WLC_IOCTL_SMLEN];
2048 	int rev = 0;
2049 
2050 	bzero(country_code, sizeof(country_code));
2051 	sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
2052 	WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
2053 
2054 	memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
2055 	memcpy(cspec.ccode, country_code, sizeof(country_code));
2056 	cspec.rev = rev;
2057 
2058 	error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
2059 		sizeof(cspec), smbuf, sizeof(smbuf), NULL);
2060 
2061 	if (error) {
2062 		ANDROID_ERROR(("wl_android_set_country_rev: set country '%s/%d' failed code %d\n",
2063 			cspec.ccode, cspec.rev, error));
2064 	} else {
2065 		dhd_bus_country_set(dev, &cspec, true);
2066 		ANDROID_INFO(("wl_android_set_country_rev: set country '%s/%d'\n",
2067 			cspec.ccode, cspec.rev));
2068 	}
2069 
2070 	return error;
2071 }
2072 
wl_android_get_country_rev(struct net_device * dev,char * command,int total_len)2073 static int wl_android_get_country_rev(
2074 	struct net_device *dev, char *command, int total_len)
2075 {
2076 	int error;
2077 	int bytes_written;
2078 	char smbuf[WLC_IOCTL_SMLEN];
2079 	wl_country_t cspec;
2080 
2081 	error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
2082 		sizeof(smbuf), NULL);
2083 
2084 	if (error) {
2085 		ANDROID_ERROR(("wl_android_get_country_rev: get country failed code %d\n",
2086 			error));
2087 		return -1;
2088 	} else {
2089 		memcpy(&cspec, smbuf, sizeof(cspec));
2090 		ANDROID_INFO(("wl_android_get_country_rev: get country '%c%c %d'\n",
2091 			cspec.ccode[0], cspec.ccode[1], cspec.rev));
2092 	}
2093 
2094 	bytes_written = snprintf(command, total_len, "%s %c%c %d",
2095 		CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
2096 
2097 	return bytes_written;
2098 }
2099 #endif /* ROAM_API */
2100 
2101 #ifdef WES_SUPPORT
wl_android_get_roam_scan_control(struct net_device * dev,char * command,int total_len)2102 int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
2103 {
2104 	int error = 0;
2105 	int bytes_written = 0;
2106 	int mode = 0;
2107 
2108 	error = get_roamscan_mode(dev, &mode);
2109 	if (error) {
2110 		ANDROID_ERROR(("wl_android_get_roam_scan_control: Failed to get Scan Control,"
2111 			" error = %d\n", error));
2112 		return -1;
2113 	}
2114 
2115 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
2116 
2117 	return bytes_written;
2118 }
2119 
wl_android_set_roam_scan_control(struct net_device * dev,char * command)2120 int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
2121 {
2122 	int error = 0;
2123 	int mode = 0;
2124 
2125 	if (sscanf(command, "%*s %d", &mode) != 1) {
2126 		ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to get Parameter\n"));
2127 		return -1;
2128 	}
2129 
2130 	error = set_roamscan_mode(dev, mode);
2131 	if (error) {
2132 		ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to set Scan Control %d,"
2133 		" error = %d\n",
2134 		 mode, error));
2135 		return -1;
2136 	}
2137 
2138 	return 0;
2139 }
2140 
2141 int
wl_android_get_roam_scan_channels(struct net_device * dev,char * command,int total_len,char * cmd)2142 wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len, char *cmd)
2143 {
2144 	int bytes_written = 0;
2145 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2146 	int nchan = 0, i = 0;
2147 	int buf_avail, len;
2148 
2149 	nchan = get_roamscan_chanspec_list(dev, chanspecs);
2150 	if (nchan < 0) {
2151 		ANDROID_ERROR(("Failed to Set roamscan channels, n_chan = %d\n", nchan));
2152 		return BCME_ERROR;
2153 	}
2154 
2155 	bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2156 
2157 	buf_avail = total_len - bytes_written;
2158 	for (i = 0; i < nchan; i++) {
2159 		/* A return value of 'buf_avail' or more means that the output was truncated */
2160 		len = snprintf(command + bytes_written, buf_avail, " %d",
2161 			CHSPEC_CHANNEL(chanspecs[i]));
2162 		if (len >= buf_avail) {
2163 			ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2164 			ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2165 			bytes_written = -1;
2166 			break;
2167 		}
2168 		/* 'buf_avail' decremented by number of bytes written */
2169 		buf_avail -= len;
2170 		bytes_written += len;
2171 	}
2172 	ANDROID_INFO(("%s\n", command));
2173 	return bytes_written;
2174 }
2175 
2176 #define CHANNEL_IDX	1
2177 int
wl_android_set_roam_scan_channels(struct net_device * dev,char * command)2178 wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
2179 {
2180 	int error = BCME_OK, i;
2181 	unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
2182 	uint16 nchan = 0, channel = 0;
2183 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2184 
2185 	nchan = p[0];
2186 	if (nchan > MAX_ROAM_CHANNEL) {
2187 		ANDROID_ERROR(("Failed to Set roamscan channnels, n_chan = %d\n", nchan));
2188 		return BCME_BADARG;
2189 	}
2190 
2191 	for (i = 0; i < nchan; i++) {
2192 		channel = p[i + CHANNEL_IDX];
2193 		/* Convert chanspec from channel */
2194 		chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2195 	}
2196 
2197 	error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2198 	if (error) {
2199 		ANDROID_ERROR(("Failed to Set Scan Channels %d, error = %d\n", p[0], error));
2200 		return error;
2201 	}
2202 
2203 	return error;
2204 }
2205 
2206 int
wl_android_add_roam_scan_channels(struct net_device * dev,char * command,uint cmdlen)2207 wl_android_add_roam_scan_channels(struct net_device *dev, char *command, uint cmdlen)
2208 {
2209 	int i, error = BCME_OK;
2210 	char *pcmd, *token;
2211 	uint16 nchan = 0, channel = 0;
2212 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2213 
2214 	pcmd = (command + cmdlen + 1);
2215 	/* Parse roam channel count */
2216 	token = bcmstrtok(&pcmd, " ", NULL);
2217 	if (!token) {
2218 		ANDROID_ERROR(("Bad argument!\n"));
2219 		return BCME_BADARG;
2220 	}
2221 	nchan = bcm_atoi(token);
2222 	if (nchan > MAX_ROAM_CHANNEL) {
2223 		ANDROID_ERROR(("Failed to Add roamscan channnels, n_chan = %d\n", nchan));
2224 		return BCME_BADARG;
2225 	}
2226 
2227 	for (i = 0; i < nchan; i++) {
2228 		/* Parse roam channel list */
2229 		token = bcmstrtok(&pcmd, " ", NULL);
2230 		if (!token) {
2231 			ANDROID_ERROR(("Bad argument!\n"));
2232 			return BCME_BADARG;
2233 		}
2234 		channel = bcm_atoi(token);
2235 		/* Convert chanspec from channel */
2236 		if (channel > 0) {
2237 			chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2238 		}
2239 	}
2240 
2241 	error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2242 	if (error) {
2243 		ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2244 	}
2245 
2246 	return error;
2247 }
2248 
2249 int
wl_android_get_roam_scan_freqs(struct net_device * dev,char * command,int total_len,char * cmd)2250 wl_android_get_roam_scan_freqs(struct net_device *dev, char *command, int total_len, char *cmd)
2251 {
2252 	int bytes_written = 0;
2253 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2254 	int nchan = 0, i = 0;
2255 	int buf_avail, len;
2256 	u32 freq = 0;
2257 	uint start_factor = 0;
2258 
2259 	nchan = get_roamscan_chanspec_list(dev, chanspecs);
2260 	if (nchan < 0) {
2261 		ANDROID_ERROR(("Failed to Get roamscan frequencies, n_chan = %d\n", nchan));
2262 		return BCME_ERROR;
2263 	}
2264 
2265 	bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2266 
2267 	buf_avail = total_len - bytes_written;
2268 	for (i = 0; i < nchan; i++) {
2269 		start_factor = WF_CHAN_FACTOR_2_4_G;
2270 		if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_5G) {
2271 			start_factor = WF_CHAN_FACTOR_5_G;
2272 		} else if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_6G) {
2273 			start_factor = WF_CHAN_FACTOR_6_G;
2274 		}
2275 		freq = wf_channel2mhz(CHSPEC_CHANNEL(chanspecs[i]), start_factor);
2276 		/* A return value of 'buf_avail' or more means that the output was truncated */
2277 		len = snprintf(command + bytes_written, buf_avail, " %d", freq);
2278 		if (len >= buf_avail) {
2279 			ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2280 			bytes_written = -1;
2281 			break;
2282 		}
2283 		/* 'buf_avail' decremented by number of bytes written */
2284 		buf_avail -= len;
2285 		bytes_written += len;
2286 	}
2287 	ANDROID_INFO(("%s\n", command));
2288 	return bytes_written;
2289 }
2290 
2291 int
wl_android_set_roam_scan_freqs(struct net_device * dev,char * command)2292 wl_android_set_roam_scan_freqs(struct net_device *dev, char *command)
2293 {
2294 	int error = BCME_OK, i;
2295 	char *pcmd, *token;
2296 	uint16 nchan = 0, freq = 0;
2297 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2298 
2299 	pcmd = (command + strlen(CMD_SETROAMSCANFREQS) + 1);
2300 	/* Parse roam channel count */
2301 	token = bcmstrtok(&pcmd, " ", NULL);
2302 	if (!token) {
2303 		ANDROID_ERROR(("Bad argument!\n"));
2304 		return BCME_BADARG;
2305 	}
2306 	nchan = bcm_atoi(token);
2307 	if (nchan > MAX_ROAM_CHANNEL) {
2308 		ANDROID_ERROR(("Failed to Set roamscan frequencies, n_chan = %d\n", nchan));
2309 		return BCME_BADARG;
2310 	}
2311 
2312 	for (i = 0; i < nchan; i++) {
2313 		/* Parse roam channel list */
2314 		token = bcmstrtok(&pcmd, " ", NULL);
2315 		if (!token) {
2316 			ANDROID_ERROR(("Bad argument!\n"));
2317 			return BCME_BADARG;
2318 		}
2319 		freq = bcm_atoi(token);
2320 		/* Convert chanspec from frequency */
2321 		chanspecs[i] = wl_freq_to_chanspec(freq);
2322 	}
2323 
2324 	error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2325 	if (error) {
2326 		ANDROID_ERROR(("Failed to set Scan Channels %d, error = %d\n", nchan, error));
2327 		return error;
2328 	}
2329 
2330 	return error;
2331 }
2332 
2333 int
wl_android_add_roam_scan_freqs(struct net_device * dev,char * command,uint cmdlen)2334 wl_android_add_roam_scan_freqs(struct net_device *dev, char *command, uint cmdlen)
2335 {
2336 	int i, error = BCME_OK;
2337 	char *pcmd, *token;
2338 	uint16 nchan = 0, freq = 0;
2339 	chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2340 
2341 	pcmd = (command + cmdlen + 1);
2342 	/* Parse roam channel count */
2343 	token = bcmstrtok(&pcmd, " ", NULL);
2344 	if (!token) {
2345 		ANDROID_ERROR(("Bad argument!\n"));
2346 		return BCME_BADARG;
2347 	}
2348 	nchan = bcm_atoi(token);
2349 	if (nchan > MAX_ROAM_CHANNEL) {
2350 		ANDROID_ERROR(("Failed to Add roamscan frequencies, n_chan = %d\n", nchan));
2351 		return BCME_BADARG;
2352 	}
2353 
2354 	for (i = 0; i < nchan; i++) {
2355 		/* Parse roam channel list */
2356 		token = bcmstrtok(&pcmd, " ", NULL);
2357 		if (!token) {
2358 			ANDROID_ERROR(("Bad argument!\n"));
2359 			return BCME_BADARG;
2360 		}
2361 		freq = bcm_atoi(token);
2362 		/* Convert chanspec from channel */
2363 		if (freq > 0) {
2364 			chanspecs[i] = wl_freq_to_chanspec(freq);
2365 		}
2366 	}
2367 
2368 	error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2369 	if (error) {
2370 		ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2371 	}
2372 
2373 	return error;
2374 }
2375 
2376 int
wl_android_get_scan_channel_time(struct net_device * dev,char * command,int total_len)2377 wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
2378 {
2379 	int error = BCME_OK;
2380 	int bytes_written = 0;
2381 	int time = 0;
2382 
2383 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2384 	if (error) {
2385 		ANDROID_ERROR(("Failed to get Scan Channel Time, error = %d\n", error));
2386 		return BCME_ERROR;
2387 	}
2388 
2389 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
2390 
2391 	return bytes_written;
2392 }
2393 
2394 int
wl_android_set_scan_channel_time(struct net_device * dev,char * command)2395 wl_android_set_scan_channel_time(struct net_device *dev, char *command)
2396 {
2397 	int error = BCME_OK;
2398 	int time = 0;
2399 
2400 	if (sscanf(command, "%*s %d", &time) != 1) {
2401 		ANDROID_ERROR(("Failed to get Parameter\n"));
2402 		return BCME_ERROR;
2403 	}
2404 
2405 	if (time == 0) {
2406 		/* Set default value when Private param is 0. */
2407 		time = DHD_SCAN_ASSOC_ACTIVE_TIME;
2408 	}
2409 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2410 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
2411 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2412 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2413 	if (error) {
2414 		ANDROID_ERROR(("Failed to set Scan Channel Time %d, error = %d\n", time, error));
2415 		return BCME_ERROR;
2416 	}
2417 
2418 	return error;
2419 }
2420 
2421 int
wl_android_get_scan_unassoc_time(struct net_device * dev,char * command,int total_len)2422 wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
2423 {
2424 	int error = BCME_OK;
2425 	int bytes_written = 0;
2426 	int time = 0;
2427 
2428 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2429 	if (error) {
2430 		ANDROID_ERROR(("Failed to get Scan Unassoc Time, error = %d\n", error));
2431 		return BCME_ERROR;
2432 	}
2433 
2434 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
2435 
2436 	return bytes_written;
2437 }
2438 
2439 int
wl_android_set_scan_unassoc_time(struct net_device * dev,char * command)2440 wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
2441 {
2442 	int error = BCME_OK;
2443 	int time = 0;
2444 
2445 	if (sscanf(command, "%*s %d", &time) != 1) {
2446 		ANDROID_ERROR(("Failed to get Parameter\n"));
2447 		return BCME_ERROR;
2448 	}
2449 	if (time == 0) {
2450 		/* Set default value when Private param is 0. */
2451 		time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
2452 	}
2453 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2454 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
2455 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2456 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2457 	if (error) {
2458 		ANDROID_ERROR(("Failed to set Scan Unassoc Time %d, error = %d\n", time, error));
2459 		return BCME_ERROR;
2460 	}
2461 
2462 	return error;
2463 }
2464 
2465 int
wl_android_get_scan_passive_time(struct net_device * dev,char * command,int total_len)2466 wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
2467 {
2468 	int error = BCME_OK;
2469 	int bytes_written = 0;
2470 	int time = 0;
2471 
2472 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2473 	if (error) {
2474 		ANDROID_ERROR(("Failed to get Scan Passive Time, error = %d\n", error));
2475 		return BCME_ERROR;
2476 	}
2477 
2478 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
2479 
2480 	return bytes_written;
2481 }
2482 
2483 int
wl_android_set_scan_passive_time(struct net_device * dev,char * command)2484 wl_android_set_scan_passive_time(struct net_device *dev, char *command)
2485 {
2486 	int error = BCME_OK;
2487 	int time = 0;
2488 
2489 	if (sscanf(command, "%*s %d", &time) != 1) {
2490 		ANDROID_ERROR(("Failed to get Parameter\n"));
2491 		return BCME_ERROR;
2492 	}
2493 	if (time == 0) {
2494 		/* Set default value when Private param is 0. */
2495 		time = DHD_SCAN_PASSIVE_TIME;
2496 	}
2497 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2498 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
2499 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2500 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2501 	if (error) {
2502 		ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n", time, error));
2503 		return BCME_ERROR;
2504 	}
2505 
2506 	return error;
2507 }
2508 
2509 int
wl_android_get_scan_home_time(struct net_device * dev,char * command,int total_len)2510 wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
2511 {
2512 	int error = BCME_OK;
2513 	int bytes_written = 0;
2514 	int time = 0;
2515 
2516 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
2517 	if (error) {
2518 		ANDROID_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
2519 		return BCME_ERROR;
2520 	}
2521 
2522 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
2523 
2524 	return bytes_written;
2525 }
2526 
wl_android_set_scan_home_time(struct net_device * dev,char * command)2527 int wl_android_set_scan_home_time(struct net_device *dev, char *command)
2528 {
2529 	int error = BCME_OK;
2530 	int time = 0;
2531 
2532 	if (sscanf(command, "%*s %d", &time) != 1) {
2533 		ANDROID_ERROR(("Failed to get Parameter\n"));
2534 		return BCME_ERROR;
2535 	}
2536 	if (time == 0) {
2537 		/* Set default value when Private param is 0. */
2538 		time = DHD_SCAN_HOME_TIME;
2539 	}
2540 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2541 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
2542 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
2543 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2544 	if (error) {
2545 		ANDROID_ERROR(("Failed to set Scan Home Time %d, error = %d\n", time, error));
2546 		return BCME_ERROR;
2547 	}
2548 
2549 	return error;
2550 }
2551 
2552 int
wl_android_get_scan_home_away_time(struct net_device * dev,char * command,int total_len)2553 wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
2554 {
2555 	int error = BCME_OK;
2556 	int bytes_written = 0;
2557 	int time = 0;
2558 
2559 	error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
2560 	if (error) {
2561 		ANDROID_ERROR(("Failed to get Scan Home Away Time, error = %d\n", error));
2562 		return BCME_ERROR;
2563 	}
2564 
2565 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
2566 
2567 	return bytes_written;
2568 }
2569 
2570 int
wl_android_set_scan_home_away_time(struct net_device * dev,char * command)2571 wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
2572 {
2573 	int error = BCME_OK;
2574 	int time = 0;
2575 
2576 	if (sscanf(command, "%*s %d", &time) != 1) {
2577 		ANDROID_ERROR(("Failed to get Parameter\n"));
2578 		return BCME_ERROR;
2579 	}
2580 	if (time == 0) {
2581 		/* Set default value when Private param is 0. */
2582 		time = DHD_SCAN_HOME_AWAY_TIME;
2583 	}
2584 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2585 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
2586 	error = wldev_iovar_setint(dev, "scan_home_away_time", time);
2587 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2588 	if (error) {
2589 		ANDROID_ERROR(("Failed to set Scan Home Away Time %d, error = %d\n",  time, error));
2590 		return BCME_ERROR;
2591 	}
2592 
2593 	return error;
2594 }
2595 
2596 int
wl_android_get_scan_nprobes(struct net_device * dev,char * command,int total_len)2597 wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
2598 {
2599 	int error = BCME_OK;
2600 	int bytes_written = 0;
2601 	int num = 0;
2602 
2603 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
2604 	if (error) {
2605 		ANDROID_ERROR(("Failed to get Scan NProbes, error = %d\n", error));
2606 		return BCME_ERROR;
2607 	}
2608 
2609 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
2610 
2611 	return bytes_written;
2612 }
2613 
2614 int
wl_android_set_scan_nprobes(struct net_device * dev,char * command)2615 wl_android_set_scan_nprobes(struct net_device *dev, char *command)
2616 {
2617 	int error = BCME_OK;
2618 	int num = 0;
2619 
2620 	if (sscanf(command, "%*s %d", &num) != 1) {
2621 		ANDROID_ERROR(("Failed to get Parameter\n"));
2622 		return BCME_ERROR;
2623 	}
2624 
2625 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
2626 	if (error) {
2627 		ANDROID_ERROR(("Failed to set Scan NProbes %d, error = %d\n", num, error));
2628 		return BCME_ERROR;
2629 	}
2630 
2631 	return error;
2632 }
2633 
2634 int
wl_android_get_scan_dfs_channel_mode(struct net_device * dev,char * command,int total_len)2635 wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
2636 {
2637 	int error = BCME_OK;
2638 	int bytes_written = 0;
2639 	int mode = 0;
2640 	int scan_passive_time = 0;
2641 
2642 	error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
2643 	if (error) {
2644 		ANDROID_ERROR(("Failed to get Passive Time, error = %d\n", error));
2645 		return BCME_ERROR;
2646 	}
2647 
2648 	if (scan_passive_time == 0) {
2649 		mode = 0;
2650 	} else {
2651 		mode = 1;
2652 	}
2653 
2654 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
2655 
2656 	return bytes_written;
2657 }
2658 
2659 int
wl_android_set_scan_dfs_channel_mode(struct net_device * dev,char * command)2660 wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
2661 {
2662 	int error = BCME_OK;
2663 	int mode = 0;
2664 	int scan_passive_time = 0;
2665 
2666 	if (sscanf(command, "%*s %d", &mode) != 1) {
2667 		ANDROID_ERROR(("Failed to get Parameter\n"));
2668 		return BCME_ERROR;
2669 	}
2670 
2671 	if (mode == 1) {
2672 		scan_passive_time = DHD_SCAN_PASSIVE_TIME;
2673 	} else if (mode == 0) {
2674 		scan_passive_time = 0;
2675 	} else {
2676 		ANDROID_ERROR(("Failed to set Scan DFS channel mode %d\n", mode));
2677 		return BCME_ERROR;
2678 	}
2679 	error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
2680 	if (error) {
2681 		ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n",
2682 			scan_passive_time, error));
2683 		return BCME_ERROR;
2684 	}
2685 
2686 	return error;
2687 }
2688 
2689 #define JOINPREFFER_BUF_SIZE 12
2690 
2691 static int
wl_android_set_join_prefer(struct net_device * dev,char * command)2692 wl_android_set_join_prefer(struct net_device *dev, char *command)
2693 {
2694 	int error = BCME_OK;
2695 	char smbuf[WLC_IOCTL_SMLEN];
2696 	uint8 buf[JOINPREFFER_BUF_SIZE];
2697 	char *pcmd;
2698 	int total_len_left;
2699 	int i;
2700 	char hex[] = "XX";
2701 #ifdef WBTEXT
2702 	int turn_on = OFF;
2703 	char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
2704 #endif /* WBTEXT */
2705 
2706 	pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
2707 	total_len_left = strlen(pcmd);
2708 
2709 	bzero(buf, sizeof(buf));
2710 
2711 	if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
2712 		ANDROID_ERROR(("wl_android_set_join_prefer: Failed to get Parameter\n"));
2713 		return BCME_ERROR;
2714 	}
2715 
2716 	/* Store the MSB first, as required by join_pref */
2717 	for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
2718 		hex[0] = *pcmd++;
2719 		hex[1] = *pcmd++;
2720 		buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
2721 	}
2722 
2723 #ifdef WBTEXT
2724 	/* Set WBTEXT mode */
2725 	turn_on = memcmp(buf, clear, sizeof(buf)) == 0 ? TRUE : FALSE;
2726 	error = wl_android_wbtext_enable(dev, turn_on);
2727 	if (error) {
2728 		ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2729 			error, (turn_on ? "Enable" : "Disable")));
2730 	}
2731 #endif /* WBTEXT */
2732 
2733 	prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
2734 	error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
2735 		smbuf, sizeof(smbuf), NULL);
2736 	if (error) {
2737 		ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
2738 	}
2739 
2740 	return error;
2741 }
2742 
wl_android_send_action_frame(struct net_device * dev,char * command,int total_len)2743 int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
2744 {
2745 	int error = -1;
2746 	android_wifi_af_params_t *params = NULL;
2747 	wl_action_frame_t *action_frame = NULL;
2748 	wl_af_params_t *af_params = NULL;
2749 	char *smbuf = NULL;
2750 	struct ether_addr tmp_bssid;
2751 	int tmp_channel = 0;
2752 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2753 
2754 	if (total_len <
2755 			(strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
2756 		ANDROID_ERROR(("wl_android_send_action_frame: Invalid parameters \n"));
2757 		goto send_action_frame_out;
2758 	}
2759 
2760 	params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
2761 
2762 	if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
2763 		ANDROID_ERROR(("wl_android_send_action_frame: Requested action frame len"
2764 			" was out of range(%d)\n",
2765 			params->len));
2766 		goto send_action_frame_out;
2767 	}
2768 
2769 	smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
2770 	if (smbuf == NULL) {
2771 		ANDROID_ERROR(("wl_android_send_action_frame: failed to allocated memory %d bytes\n",
2772 		WLC_IOCTL_MAXLEN));
2773 		goto send_action_frame_out;
2774 	}
2775 
2776 	af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
2777 	if (af_params == NULL) {
2778 		ANDROID_ERROR(("wl_android_send_action_frame: unable to allocate frame\n"));
2779 		goto send_action_frame_out;
2780 	}
2781 
2782 	bzero(&tmp_bssid, ETHER_ADDR_LEN);
2783 	if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
2784 		bzero(&tmp_bssid, ETHER_ADDR_LEN);
2785 
2786 		error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2787 		if (error) {
2788 			bzero(&tmp_bssid, ETHER_ADDR_LEN);
2789 			ANDROID_ERROR(("wl_android_send_action_frame: failed to get bssid,"
2790 				" error=%d\n", error));
2791 			goto send_action_frame_out;
2792 		}
2793 	}
2794 
2795 	if (params->channel < 0) {
2796 		struct channel_info ci;
2797 		bzero(&ci, sizeof(ci));
2798 		error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
2799 		if (error) {
2800 			ANDROID_ERROR(("wl_android_send_action_frame: failed to get channel,"
2801 				" error=%d\n", error));
2802 			goto send_action_frame_out;
2803 		}
2804 
2805 		tmp_channel = ci.hw_channel;
2806 	}
2807 	else {
2808 		tmp_channel = params->channel;
2809 	}
2810 
2811 	af_params->channel = tmp_channel;
2812 	af_params->dwell_time = params->dwell_time;
2813 	memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2814 	action_frame = &af_params->action_frame;
2815 
2816 	action_frame->packetId = 0;
2817 	memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
2818 	action_frame->len = (uint16)params->len;
2819 	memcpy(action_frame->data, params->data, action_frame->len);
2820 
2821 	error = wldev_iovar_setbuf(dev, "actframe", af_params,
2822 		sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
2823 	if (error) {
2824 		ANDROID_ERROR(("wl_android_send_action_frame: failed to set action frame,"
2825 			" error=%d\n", error));
2826 	}
2827 
2828 send_action_frame_out:
2829 	if (af_params) {
2830 		MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
2831 	}
2832 
2833 	if (smbuf) {
2834 		MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
2835 	}
2836 
2837 	if (error)
2838 		return -1;
2839 	else
2840 		return 0;
2841 }
2842 
2843 int
wl_android_reassoc(struct net_device * dev,char * command,int total_len)2844 wl_android_reassoc(struct net_device *dev, char *command, int total_len)
2845 {
2846 	int error = BCME_OK;
2847 	android_wifi_reassoc_params_t *params = NULL;
2848 	chanspec_t channel;
2849 	u32 params_size;
2850 	wl_reassoc_params_t reassoc_params;
2851 	char pcmd[WL_PRIV_CMD_LEN + 1];
2852 
2853 	sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s *", pcmd);
2854 	if (total_len < (strlen(pcmd) + 1 + sizeof(android_wifi_reassoc_params_t))) {
2855 		ANDROID_ERROR(("Invalid parameters %s\n", command));
2856 		return BCME_ERROR;
2857 	}
2858 	params = (android_wifi_reassoc_params_t *)(command + strlen(pcmd) + 1);
2859 
2860 	bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
2861 
2862 	if (bcm_ether_atoe((const char *)params->bssid,
2863 	(struct ether_addr *)&reassoc_params.bssid) == 0) {
2864 		ANDROID_ERROR(("Invalid bssid \n"));
2865 		return BCME_BADARG;
2866 	}
2867 
2868 	if (params->channel < 0) {
2869 		ANDROID_ERROR(("Invalid Channel %d\n", params->channel));
2870 		return BCME_BADARG;
2871 	}
2872 
2873 	reassoc_params.chanspec_num = 1;
2874 
2875 	channel = params->channel;
2876 	if (CHANNEL_IS_2G(channel) || CHANNEL_IS_5G(channel)) {
2877 		/* If reassoc Param is BSSID and Channel */
2878 		reassoc_params.chanspec_list[0] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2879 	} else {
2880 		/* If reassoc Param is BSSID and Frequency */
2881 		reassoc_params.chanspec_list[0] = wl_freq_to_chanspec(channel);
2882 	}
2883 	params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
2884 
2885 	error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
2886 	if (error) {
2887 		ANDROID_ERROR(("failed to reassoc, error=%d\n", error));
2888 		return error;
2889 	}
2890 	return error;
2891 }
2892 
wl_android_get_wes_mode(struct net_device * dev,char * command,int total_len)2893 int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
2894 {
2895 	int bytes_written = 0;
2896 	int mode = 0;
2897 
2898 	mode = wl_cfg80211_get_wes_mode(dev);
2899 
2900 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
2901 
2902 	return bytes_written;
2903 }
2904 
wl_android_set_wes_mode(struct net_device * dev,char * command)2905 int wl_android_set_wes_mode(struct net_device *dev, char *command)
2906 {
2907 	int error = 0;
2908 	int mode = 0;
2909 
2910 	if (sscanf(command, "%*s %d", &mode) != 1) {
2911 		ANDROID_ERROR(("wl_android_set_wes_mode: Failed to get Parameter\n"));
2912 		return -1;
2913 	}
2914 
2915 	error = wl_cfg80211_set_wes_mode(dev, mode);
2916 	if (error) {
2917 		ANDROID_ERROR(("wl_android_set_wes_mode: Failed to set WES Mode %d, error = %d\n",
2918 		mode, error));
2919 		return -1;
2920 	}
2921 
2922 	return 0;
2923 }
2924 
2925 int
wl_android_get_ncho_mode(struct net_device * dev,char * command,int total_len)2926 wl_android_get_ncho_mode(struct net_device *dev, char *command, int total_len)
2927 {
2928 	int bytes_written = 0;
2929 	int mode = 0;
2930 
2931 	mode = wl_cfg80211_get_ncho_mode(dev);
2932 
2933 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETNCHOMODE, mode);
2934 
2935 	return bytes_written;
2936 }
2937 
2938 int
wl_android_set_ncho_mode(struct net_device * dev,int mode)2939 wl_android_set_ncho_mode(struct net_device *dev, int mode)
2940 {
2941 	char cmd[WLC_IOCTL_SMLEN];
2942 	int error = BCME_OK;
2943 
2944 #ifdef WBTEXT
2945 	/* Set WBTEXT mode */
2946 	error = wl_android_wbtext_enable(dev, !mode);
2947 	if (error) {
2948 		ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2949 			error, (mode ? "Disable" : "Enable")));
2950 	}
2951 #endif /* WBTEXT */
2952 	/* Set Piority roam mode */
2953 	error = wl_android_priority_roam_enable(dev, !mode);
2954 	if (error) {
2955 		ANDROID_ERROR(("Failed to set Priority Roam(%d) = %s\n",
2956 			error, (mode ? "Disable" : "Enable")));
2957 	}
2958 #ifdef CONFIG_SILENT_ROAM
2959 	/* Set Silent roam  mode */
2960 	error = wl_android_sroam_turn_on(dev, !mode);
2961 	if (error) {
2962 		ANDROID_ERROR(("Failed to set SROAM(%d) = %s\n",
2963 			error, (mode ? "Disable" : "Enable")));
2964 	}
2965 #endif /* CONFIG_SILENT_ROAM */
2966 	/* Set RCROAM(ROAMEXT) mode */
2967 	error = wl_android_rcroam_turn_on(dev, !mode);
2968 	if (error) {
2969 		ANDROID_ERROR(("Failed to set RCROAM(%d) = %s\n",
2970 			error, (mode ? "Disable" : "Enable")));
2971 	}
2972 
2973 	if (mode == OFF) {
2974 		/* restore NCHO set parameters */
2975 		bzero(cmd, WLC_IOCTL_SMLEN);
2976 		snprintf(cmd, WLC_IOCTL_SMLEN, "%s", CMD_RESTORE_SCAN_PARAMS);
2977 		error = wl_android_default_set_scan_params(dev, cmd, WLC_IOCTL_SMLEN);
2978 		if (error) {
2979 			ANDROID_ERROR(("Failed to set RESTORE_SCAN_PARAMS(%d)\n", error));
2980 		}
2981 
2982 		wl_cfg80211_set_wes_mode(dev, OFF);
2983 		set_roamscan_mode(dev, ROAMSCAN_MODE_NORMAL);
2984 	}
2985 
2986 	error = wl_cfg80211_set_ncho_mode(dev, mode);
2987 	if (error) {
2988 		ANDROID_ERROR(("Failed to set NCHO Mode %d, error = %d\n", mode, error));
2989 	}
2990 
2991 	return error;
2992 }
2993 
2994 static int
wl_android_set_pmk(struct net_device * dev,char * command,int total_len)2995 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
2996 {
2997 	uchar pmk[33];
2998 	int error = 0;
2999 	char smbuf[WLC_IOCTL_SMLEN];
3000 	dhd_pub_t *dhdp;
3001 #ifdef OKC_DEBUG
3002 	int i = 0;
3003 #endif
3004 
3005 	if (total_len < (strlen("SET_PMK ") + 32)) {
3006 		ANDROID_ERROR(("wl_android_set_pmk: Invalid argument\n"));
3007 		return -1;
3008 	}
3009 
3010 	dhdp = wl_cfg80211_get_dhdp(dev);
3011 	if (!dhdp) {
3012 		ANDROID_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3013 		return -1;
3014 	}
3015 
3016 	bzero(pmk, sizeof(pmk));
3017 	DHD_STATLOG_CTRL(dhdp, ST(INSTALL_OKC_PMK), dhd_net2idx(dhdp->info, dev), 0);
3018 	memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
3019 	error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
3020 	if (error) {
3021 		ANDROID_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
3022 	}
3023 #ifdef OKC_DEBUG
3024 	ANDROID_ERROR(("PMK is "));
3025 	for (i = 0; i < 32; i++)
3026 		ANDROID_ERROR(("%02X ", pmk[i]));
3027 
3028 	ANDROID_ERROR(("\n"));
3029 #endif
3030 	return error;
3031 }
3032 
3033 static int
wl_android_okc_enable(struct net_device * dev,char * command)3034 wl_android_okc_enable(struct net_device *dev, char *command)
3035 {
3036 	int error = 0;
3037 	char okc_enable = 0;
3038 
3039 	okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
3040 	error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
3041 	if (error) {
3042 		ANDROID_ERROR(("Failed to %s OKC, error = %d\n",
3043 			okc_enable ? "enable" : "disable", error));
3044 	}
3045 
3046 	return error;
3047 }
3048 
3049 static int
wl_android_legacy_check_command(struct net_device * dev,char * command)3050 wl_android_legacy_check_command(struct net_device *dev, char *command)
3051 {
3052 	int cnt = 0;
3053 
3054 	while (strlen(legacy_cmdlist[cnt]) > 0) {
3055 		if (strnicmp(command, legacy_cmdlist[cnt], strlen(legacy_cmdlist[cnt])) == 0) {
3056 			char cmd[WL_PRIV_CMD_LEN + 1];
3057 			sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3058 			if (strlen(legacy_cmdlist[cnt]) == strlen(cmd)) {
3059 				return TRUE;
3060 			}
3061 		}
3062 		cnt++;
3063 	}
3064 	return FALSE;
3065 }
3066 
3067 static int
wl_android_legacy_private_command(struct net_device * net,char * command,int total_len)3068 wl_android_legacy_private_command(struct net_device *net, char *command, int total_len)
3069 {
3070 	int bytes_written = 0;
3071 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3072 
3073 	if (cfg->ncho_mode == ON) {
3074 		ANDROID_ERROR(("Enabled NCHO mode\n"));
3075 		/* In order to avoid Sequential error HANG event. */
3076 		return BCME_UNSUPPORTED;
3077 	}
3078 
3079 	/* ROAMSCAN CHANNELS Add, Get Command */
3080 	if (strnicmp(command, CMD_ADDROAMSCANCHLEGACY, strlen(CMD_ADDROAMSCANCHLEGACY)) == 0) {
3081 		bytes_written = wl_android_add_roam_scan_channels(net, command,
3082 			strlen(CMD_ADDROAMSCANCHLEGACY));
3083 	}
3084 	else if (strnicmp(command, CMD_GETROAMSCANCHLEGACY, strlen(CMD_GETROAMSCANCHLEGACY)) == 0) {
3085 		bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3086 			CMD_GETROAMSCANCHLEGACY);
3087 	}
3088 	/* ROAMSCAN FREQUENCIES Add, Get Command */
3089 	else if (strnicmp(command, CMD_ADDROAMSCANFQLEGACY, strlen(CMD_ADDROAMSCANFQLEGACY)) == 0) {
3090 		bytes_written = wl_android_add_roam_scan_freqs(net, command,
3091 			strlen(CMD_ADDROAMSCANFQLEGACY));
3092 	}
3093 	else if (strnicmp(command, CMD_GETROAMSCANFQLEGACY, strlen(CMD_GETROAMSCANFQLEGACY)) == 0) {
3094 		bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3095 			CMD_GETROAMSCANFQLEGACY);
3096 	}
3097 	else if (strnicmp(command, CMD_GETROAMTRIGLEGACY, strlen(CMD_GETROAMTRIGLEGACY)) == 0) {
3098 		bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3099 	}
3100 	else if (strnicmp(command, CMD_SETROAMTRIGLEGACY, strlen(CMD_SETROAMTRIGLEGACY)) == 0) {
3101 		bytes_written = wl_android_set_roam_trigger_legacy(net, command);
3102 	}
3103 	else if (strnicmp(command, CMD_REASSOCLEGACY, strlen(CMD_REASSOCLEGACY)) == 0) {
3104 		bytes_written = wl_android_reassoc(net, command, total_len);
3105 	}
3106 	else if (strnicmp(command, CMD_GETSCANCHANNELTIMELEGACY,
3107 		strlen(CMD_GETSCANCHANNELTIMELEGACY)) == 0) {
3108 		bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3109 	}
3110 	else if (strnicmp(command, CMD_SETSCANCHANNELTIMELEGACY,
3111 		strlen(CMD_SETSCANCHANNELTIMELEGACY)) == 0) {
3112 		bytes_written = wl_android_set_scan_channel_time(net, command);
3113 	}
3114 	else if (strnicmp(command, CMD_GETSCANUNASSOCTIMELEGACY,
3115 		strlen(CMD_GETSCANUNASSOCTIMELEGACY)) == 0) {
3116 		bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3117 	}
3118 	else if (strnicmp(command, CMD_SETSCANUNASSOCTIMELEGACY,
3119 		strlen(CMD_SETSCANUNASSOCTIMELEGACY)) == 0) {
3120 		bytes_written = wl_android_set_scan_unassoc_time(net, command);
3121 	}
3122 	else if (strnicmp(command, CMD_GETSCANPASSIVETIMELEGACY,
3123 		strlen(CMD_GETSCANPASSIVETIMELEGACY)) == 0) {
3124 		bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3125 	}
3126 	else if (strnicmp(command, CMD_SETSCANPASSIVETIMELEGACY,
3127 		strlen(CMD_SETSCANPASSIVETIMELEGACY)) == 0) {
3128 		bytes_written = wl_android_set_scan_passive_time(net, command);
3129 	}
3130 	else if (strnicmp(command, CMD_GETSCANHOMETIMELEGACY,
3131 		strlen(CMD_GETSCANHOMETIMELEGACY)) == 0) {
3132 		bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3133 	}
3134 	else if (strnicmp(command, CMD_SETSCANHOMETIMELEGACY,
3135 		strlen(CMD_SETSCANHOMETIMELEGACY)) == 0) {
3136 		bytes_written = wl_android_set_scan_home_time(net, command);
3137 	}
3138 	else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIMELEGACY,
3139 		strlen(CMD_GETSCANHOMEAWAYTIMELEGACY)) == 0) {
3140 		bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3141 	}
3142 	else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIMELEGACY,
3143 		strlen(CMD_SETSCANHOMEAWAYTIMELEGACY)) == 0) {
3144 		bytes_written = wl_android_set_scan_home_away_time(net, command);
3145 	}
3146 	else {
3147 		ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3148 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3149 	}
3150 
3151 	return bytes_written;
3152 }
3153 
3154 static int
wl_android_ncho_check_command(struct net_device * dev,char * command)3155 wl_android_ncho_check_command(struct net_device *dev, char *command)
3156 {
3157 	int cnt = 0;
3158 
3159 	while (strlen(ncho_cmdlist[cnt]) > 0) {
3160 		if (strnicmp(command, ncho_cmdlist[cnt], strlen(ncho_cmdlist[cnt])) == 0) {
3161 			char cmd[WL_PRIV_CMD_LEN + 1];
3162 			sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3163 			if (strlen(ncho_cmdlist[cnt]) == strlen(cmd)) {
3164 				return TRUE;
3165 			}
3166 		}
3167 		cnt++;
3168 	}
3169 	return FALSE;
3170 }
3171 
3172 static int
wl_android_ncho_private_command(struct net_device * net,char * command,int total_len)3173 wl_android_ncho_private_command(struct net_device *net, char *command, int total_len)
3174 {
3175 	int bytes_written = 0;
3176 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3177 
3178 	if (cfg->ncho_mode == OFF) {
3179 		ANDROID_ERROR(("Disable NCHO mode\n"));
3180 		/* In order to avoid Sequential error HANG event. */
3181 		return BCME_UNSUPPORTED;
3182 	}
3183 
3184 #ifdef ROAM_API
3185 	if (strnicmp(command, CMD_ROAMTRIGGER_SET, strlen(CMD_ROAMTRIGGER_SET)) == 0) {
3186 		bytes_written = wl_android_set_roam_trigger(net, command);
3187 	} else if (strnicmp(command, CMD_ROAMTRIGGER_GET, strlen(CMD_ROAMTRIGGER_GET)) == 0) {
3188 		bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3189 	} else if (strnicmp(command, CMD_ROAMDELTA_SET, strlen(CMD_ROAMDELTA_SET)) == 0) {
3190 		bytes_written = wl_android_set_roam_delta(net, command);
3191 	} else if (strnicmp(command, CMD_ROAMDELTA_GET, strlen(CMD_ROAMDELTA_GET)) == 0) {
3192 		bytes_written = wl_android_get_roam_delta(net, command, total_len);
3193 	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
3194 		strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
3195 		bytes_written = wl_android_set_roam_scan_period(net, command);
3196 	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
3197 		strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
3198 		bytes_written = wl_android_get_roam_scan_period(net, command, total_len);
3199 	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
3200 		strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
3201 		bytes_written = wl_android_set_full_roam_scan_period(net, command);
3202 	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
3203 		strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
3204 		bytes_written = wl_android_get_full_roam_scan_period(net, command, total_len);
3205 	} else if (strnicmp(command, CMD_COUNTRYREV_SET, strlen(CMD_COUNTRYREV_SET)) == 0) {
3206 		bytes_written = wl_android_set_country_rev(net, command);
3207 #ifdef FCC_PWR_LIMIT_2G
3208 		if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
3209 			ANDROID_ERROR(("fccpwrlimit2g deactivation is failed\n"));
3210 		} else {
3211 			ANDROID_ERROR(("fccpwrlimit2g is deactivated\n"));
3212 		}
3213 #endif /* FCC_PWR_LIMIT_2G */
3214 	} else if (strnicmp(command, CMD_COUNTRYREV_GET, strlen(CMD_COUNTRYREV_GET)) == 0) {
3215 		bytes_written = wl_android_get_country_rev(net, command, total_len);
3216 	} else
3217 #endif /* ROAM_API */
3218 	if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
3219 		bytes_written = wl_android_get_roam_scan_control(net, command, total_len);
3220 	}
3221 	else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
3222 		bytes_written = wl_android_set_roam_scan_control(net, command);
3223 	}
3224 	/* ROAMSCAN CHANNELS Add, Get, Set Command */
3225 	else if (strnicmp(command, CMD_ADDROAMSCANCHANNELS, strlen(CMD_ADDROAMSCANCHANNELS)) == 0) {
3226 		bytes_written = wl_android_add_roam_scan_channels(net, command,
3227 			strlen(CMD_ADDROAMSCANCHANNELS));
3228 	}
3229 	else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
3230 		bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3231 			CMD_GETROAMSCANCHANNELS);
3232 	}
3233 	else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
3234 		bytes_written = wl_android_set_roam_scan_channels(net, command);
3235 	}
3236 	/* ROAMSCAN FREQUENCIES Add, Get, Set Command */
3237 	else if (strnicmp(command, CMD_ADDROAMSCANFREQS, strlen(CMD_ADDROAMSCANFREQS)) == 0) {
3238 		bytes_written = wl_android_add_roam_scan_freqs(net, command,
3239 			strlen(CMD_ADDROAMSCANFREQS));
3240 	}
3241 	else if (strnicmp(command, CMD_GETROAMSCANFREQS, strlen(CMD_GETROAMSCANFREQS)) == 0) {
3242 		bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3243 			CMD_GETROAMSCANFREQS);
3244 	}
3245 	else if (strnicmp(command, CMD_SETROAMSCANFREQS, strlen(CMD_SETROAMSCANFREQS)) == 0) {
3246 		bytes_written = wl_android_set_roam_scan_freqs(net, command);
3247 	}
3248 	else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
3249 		bytes_written = wl_android_send_action_frame(net, command, total_len);
3250 	}
3251 	else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
3252 		bytes_written = wl_android_reassoc(net, command, total_len);
3253 	}
3254 	else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
3255 		bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3256 	}
3257 	else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
3258 		bytes_written = wl_android_set_scan_channel_time(net, command);
3259 	}
3260 	else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
3261 		bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3262 	}
3263 	else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
3264 		bytes_written = wl_android_set_scan_unassoc_time(net, command);
3265 	}
3266 	else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
3267 		bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3268 	}
3269 	else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
3270 		bytes_written = wl_android_set_scan_passive_time(net, command);
3271 	}
3272 	else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
3273 		bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3274 	}
3275 	else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
3276 		bytes_written = wl_android_set_scan_home_time(net, command);
3277 	}
3278 	else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
3279 		bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3280 	}
3281 	else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
3282 		bytes_written = wl_android_set_scan_home_away_time(net, command);
3283 	}
3284 	else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
3285 		bytes_written = wl_android_get_scan_nprobes(net, command, total_len);
3286 	}
3287 	else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
3288 		bytes_written = wl_android_set_scan_nprobes(net, command);
3289 	}
3290 	else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
3291 		bytes_written = wl_android_get_scan_dfs_channel_mode(net, command, total_len);
3292 	}
3293 	else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
3294 		bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
3295 	}
3296 	else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
3297 		bytes_written = wl_android_set_join_prefer(net, command);
3298 	}
3299 	else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
3300 		bytes_written = wl_android_get_wes_mode(net, command, total_len);
3301 	}
3302 	else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
3303 		bytes_written = wl_android_set_wes_mode(net, command);
3304 	}
3305 	else {
3306 		ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3307 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3308 	}
3309 
3310 	return bytes_written;
3311 }
3312 #endif /* WES_SUPPORT */
3313 
3314 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
3315 static int
wl_android_default_set_scan_params(struct net_device * dev,char * command,int total_len)3316 wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len)
3317 {
3318 	int error = 0;
3319 	uint error_cnt = 0;
3320 	int cnt = 0;
3321 	char restore_command[WLC_IOCTL_SMLEN];
3322 
3323 	while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) {
3324 		snprintf(restore_command, WLC_IOCTL_SMLEN, "%s %d",
3325 			restore_params[cnt].command, restore_params[cnt].parameter);
3326 		if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) {
3327 			error = restore_params[cnt].cmd_handler(dev, restore_command);
3328 		}  else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) {
3329 			error = restore_params[cnt].cmd_handler_w_len(dev,
3330 				restore_command, total_len);
3331 		} else {
3332 			ANDROID_ERROR(("Unknown restore command handler\n"));
3333 			error = -1;
3334 		}
3335 		if (error) {
3336 			ANDROID_ERROR(("Failed to restore scan parameters %s, error : %d\n",
3337 				restore_command, error));
3338 			error_cnt++;
3339 		}
3340 		cnt++;
3341 	}
3342 	if (error_cnt > 0) {
3343 		ANDROID_ERROR(("Got %d error(s) while restoring scan parameters\n",
3344 			error_cnt));
3345 		error = -1;
3346 	}
3347 	return error;
3348 }
3349 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT  */
3350 
3351 #ifdef WLTDLS
wl_android_tdls_reset(struct net_device * dev)3352 int wl_android_tdls_reset(struct net_device *dev)
3353 {
3354 	int ret = 0;
3355 	ret = dhd_tdls_enable(dev, false, false, NULL);
3356 	if (ret < 0) {
3357 		ANDROID_ERROR(("Disable tdls failed. %d\n", ret));
3358 		return ret;
3359 	}
3360 	ret = dhd_tdls_enable(dev, true, true, NULL);
3361 	if (ret < 0) {
3362 		ANDROID_ERROR(("enable tdls failed. %d\n", ret));
3363 		return ret;
3364 	}
3365 	return 0;
3366 }
3367 #endif /* WLTDLS */
3368 
3369 int
wl_android_rcroam_turn_on(struct net_device * dev,int rcroam_enab)3370 wl_android_rcroam_turn_on(struct net_device *dev, int rcroam_enab)
3371 {
3372 	int ret = BCME_OK;
3373 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3374 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3375 	wlc_rcroam_t *prcroam;
3376 	wlc_rcroam_info_v1_t *rcroam;
3377 	uint rcroamlen = sizeof(*rcroam) + RCROAM_HDRLEN;
3378 
3379 	ANDROID_INFO(("RCROAM mode %s\n", rcroam_enab ? "enable" : "disable"));
3380 
3381 	prcroam = (wlc_rcroam_t *)MALLOCZ(dhdp->osh, rcroamlen);
3382 	if (!prcroam) {
3383 		ANDROID_ERROR(("Fail to malloc buffer\n"));
3384 		return BCME_NOMEM;
3385 	}
3386 
3387 	/* Get RCROAM param */
3388 	ret = wldev_iovar_getbuf(dev, "rcroam", NULL, 0, prcroam, rcroamlen, NULL);
3389 	if (ret) {
3390 		ANDROID_ERROR(("Failed to get RCROAM info(%d)\n", ret));
3391 		goto done;
3392 	}
3393 
3394 	if (prcroam->ver != WLC_RC_ROAM_CUR_VER) {
3395 		ret = BCME_VERSION;
3396 		ANDROID_ERROR(("Ver(%d:%d). mismatch RCROAM info(%d)\n",
3397 			prcroam->ver, WLC_RC_ROAM_CUR_VER, ret));
3398 		goto done;
3399 	}
3400 
3401 	/* Set RCROAM param */
3402 	rcroam = (wlc_rcroam_info_v1_t *)prcroam->data;
3403 	prcroam->ver = WLC_RC_ROAM_CUR_VER;
3404 	prcroam->len = sizeof(*rcroam);
3405 	rcroam->enab = rcroam_enab;
3406 
3407 	ret = wldev_iovar_setbuf(dev, "rcroam", prcroam, rcroamlen,
3408 		ioctl_buf, sizeof(ioctl_buf), NULL);
3409 	if (ret) {
3410 		ANDROID_ERROR(("Failed to set RCROAM %s(%d)\n",
3411 			rcroam_enab ? "Enable" : "Disable", ret));
3412 		goto done;
3413 	}
3414 done:
3415 	if (prcroam) {
3416 		MFREE(dhdp->osh, prcroam, rcroamlen);
3417 	}
3418 
3419 	return ret;
3420 }
3421 
3422 #ifdef CONFIG_SILENT_ROAM
3423 int
wl_android_sroam_turn_on(struct net_device * dev,int sroam_mode)3424 wl_android_sroam_turn_on(struct net_device *dev, int sroam_mode)
3425 {
3426 	int ret = BCME_OK;
3427 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3428 
3429 	dhdp->sroam_turn_on = sroam_mode;
3430 	ANDROID_INFO(("%s Silent mode %s\n", __FUNCTION__,
3431 		sroam_mode ? "enable" : "disable"));
3432 
3433 	if (!sroam_mode) {
3434 		ret = dhd_sroam_set_mon(dhdp, FALSE);
3435 		if (ret) {
3436 			ANDROID_ERROR(("%s Failed to Set sroam %d\n",
3437 				__FUNCTION__, ret));
3438 		}
3439 	}
3440 
3441 	return ret;
3442 }
3443 
3444 int
wl_android_sroam_set_info(struct net_device * dev,char * data,char * command,int total_len)3445 wl_android_sroam_set_info(struct net_device *dev, char *data,
3446 	char *command, int total_len)
3447 {
3448 	int ret = BCME_OK;
3449 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3450 	size_t slen = strlen(data);
3451 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3452 	wlc_sroam_t *psroam;
3453 	wlc_sroam_info_t *sroam;
3454 	uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3455 
3456 	data[slen] = '\0';
3457 	psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3458 	if (!psroam) {
3459 		ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3460 		ret = BCME_NOMEM;
3461 		goto done;
3462 	}
3463 
3464 	psroam->ver = WLC_SILENT_ROAM_CUR_VER;
3465 	psroam->len = sizeof(*sroam);
3466 	sroam = (wlc_sroam_info_t *)psroam->data;
3467 
3468 	sroam->sroam_on = FALSE;
3469 	if (*data && *data != '\0') {
3470 		sroam->sroam_min_rssi = simple_strtol(data, &data, 10);
3471 		ANDROID_INFO(("1.Minimum RSSI %d\n", sroam->sroam_min_rssi));
3472 		data++;
3473 	}
3474 	if (*data && *data != '\0') {
3475 		sroam->sroam_rssi_range = simple_strtol(data, &data, 10);
3476 		ANDROID_INFO(("2.RSSI Range %d\n", sroam->sroam_rssi_range));
3477 		data++;
3478 	}
3479 	if (*data && *data != '\0') {
3480 		sroam->sroam_score_delta = simple_strtol(data, &data, 10);
3481 		ANDROID_INFO(("3.Score Delta %d\n", sroam->sroam_score_delta));
3482 		data++;
3483 	}
3484 	if (*data && *data != '\0') {
3485 		sroam->sroam_period_time = simple_strtol(data, &data, 10);
3486 		ANDROID_INFO(("4.Sroam period %d\n", sroam->sroam_period_time));
3487 		data++;
3488 	}
3489 	if (*data && *data != '\0') {
3490 		sroam->sroam_band = simple_strtol(data, &data, 10);
3491 		ANDROID_INFO(("5.Sroam Band %d\n", sroam->sroam_band));
3492 		data++;
3493 	}
3494 	if (*data && *data != '\0') {
3495 		sroam->sroam_inact_cnt = simple_strtol(data, &data, 10);
3496 		ANDROID_INFO(("6.Inactivity Count %d\n", sroam->sroam_inact_cnt));
3497 		data++;
3498 	}
3499 
3500 	if (*data != '\0') {
3501 		ret = BCME_BADARG;
3502 		goto done;
3503 	}
3504 
3505 	ret = wldev_iovar_setbuf(dev, "sroam", psroam, sroamlen, ioctl_buf,
3506 		sizeof(ioctl_buf), NULL);
3507 	if (ret) {
3508 		ANDROID_ERROR(("Failed to set silent roam info(%d)\n", ret));
3509 		goto done;
3510 	}
3511 done:
3512 	if (psroam) {
3513 		MFREE(dhdp->osh, psroam, sroamlen);
3514 	}
3515 
3516 	return ret;
3517 }
3518 
3519 int
wl_android_sroam_get_info(struct net_device * dev,char * command,int total_len)3520 wl_android_sroam_get_info(struct net_device *dev, char *command, int total_len)
3521 {
3522 	int ret = BCME_OK;
3523 	int bytes_written = 0;
3524 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3525 	wlc_sroam_t *psroam;
3526 	wlc_sroam_info_t *sroam;
3527 	uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3528 
3529 	psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3530 	if (!psroam) {
3531 		ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3532 		ret = BCME_NOMEM;
3533 		goto done;
3534 	}
3535 
3536 	ret = wldev_iovar_getbuf(dev, "sroam", NULL, 0, psroam, sroamlen, NULL);
3537 	if (ret) {
3538 		ANDROID_ERROR(("Failed to get silent roam info(%d)\n", ret));
3539 		goto done;
3540 	}
3541 
3542 	if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) {
3543 		ret = BCME_VERSION;
3544 		ANDROID_ERROR(("Ver(%d:%d). mismatch silent roam info(%d)\n",
3545 			psroam->ver, WLC_SILENT_ROAM_CUR_VER, ret));
3546 		goto done;
3547 	}
3548 
3549 	sroam = (wlc_sroam_info_t *)psroam->data;
3550 	bytes_written = snprintf(command, total_len,
3551 		"%s %d %d %d %d %d %d %d\n",
3552 		CMD_SROAM_GET_INFO, sroam->sroam_on, sroam->sroam_min_rssi, sroam->sroam_rssi_range,
3553 		sroam->sroam_score_delta, sroam->sroam_period_time, sroam->sroam_band,
3554 		sroam->sroam_inact_cnt);
3555 	ret = bytes_written;
3556 
3557 	ANDROID_INFO(("%s", command));
3558 done:
3559 	if (psroam) {
3560 		MFREE(dhdp->osh, psroam, sroamlen);
3561 	}
3562 
3563 	return ret;
3564 }
3565 #endif /* CONFIG_SILENT_ROAM */
3566 
3567 int
wl_android_priority_roam_enable(struct net_device * dev,int mode)3568 wl_android_priority_roam_enable(struct net_device *dev, int mode)
3569 {
3570 	int error = BCME_OK;
3571 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3572 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3573 	wl_prio_roam_prof_v1_t *prio_roam;
3574 	uint buf_len = sizeof(wl_prio_roam_prof_v1_t) + (uint)strlen("priority_roam") + 1;
3575 
3576 	prio_roam = (wl_prio_roam_prof_v1_t *)MALLOCZ(dhdp->osh, buf_len);
3577 	if (!prio_roam) {
3578 		ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3579 		error = BCME_NOMEM;
3580 		goto done;
3581 	}
3582 
3583 	error = wldev_iovar_getbuf(dev, "priority_roam", NULL, 0, prio_roam, buf_len, NULL);
3584 	if (error == BCME_UNSUPPORTED) {
3585 		ANDROID_ERROR(("Priority Roam Unsupport\n"));
3586 		error = BCME_OK;
3587 		goto done;
3588 	} else if (prio_roam->version != WL_PRIO_ROAM_PROF_V1) {
3589 		ANDROID_ERROR(("Priority Roam Version mismatch\n"));
3590 		goto done;
3591 	} else if (prio_roam->prio_roam_mode == mode) {
3592 		ANDROID_INFO(("Priority Roam already set(mode:%d)\n", mode));
3593 		goto done;
3594 	}
3595 
3596 	prio_roam->version = WL_PRIO_ROAM_PROF_V1;
3597 	prio_roam->length = sizeof(wl_prio_roam_prof_v1_t);
3598 	prio_roam->prio_roam_mode = mode;
3599 
3600 	error = wldev_iovar_setbuf(dev, "priority_roam", prio_roam,
3601 		sizeof(wl_prio_roam_prof_v1_t), ioctl_buf, sizeof(ioctl_buf), NULL);
3602 	if (error) {
3603 		ANDROID_ERROR(("Failed to set Priority Roam %s(%d)\n",
3604 			mode ? "Enable" : "Disable", error));
3605 		goto done;
3606 	}
3607 done:
3608 	if (prio_roam) {
3609 		MFREE(dhdp->osh, prio_roam, sizeof(wl_prio_roam_prof_v1_t));
3610 	}
3611 
3612 	return error;
3613 }
3614 
3615 #ifdef CONFIG_ROAM_RSSI_LIMIT
3616 int
wl_android_roam_rssi_limit(struct net_device * dev,char * command,int total_len)3617 wl_android_roam_rssi_limit(struct net_device *dev, char *command, int total_len)
3618 {
3619 	int ret = BCME_OK;
3620 	int argc, bytes_written = 0;
3621 	int lmt2g, lmt5g;
3622 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3623 
3624 	argc = sscanf(command, CMD_ROAM_RSSI_LMT " %d %d\n", &lmt2g, &lmt5g);
3625 
3626 	if (!argc) {
3627 		ret = dhd_roam_rssi_limit_get(dhdp, &lmt2g, &lmt5g);
3628 		if (ret) {
3629 			ANDROID_ERROR(("Failed to Get roam_rssi_limit (%d)\n", ret));
3630 			return ret;
3631 		}
3632 		bytes_written = snprintf(command, total_len, "%d, %d\n", lmt2g, lmt5g);
3633 		/* Get roam rssi limit */
3634 		return bytes_written;
3635 	} else {
3636 		/* Set roam rssi limit */
3637 		ret = dhd_roam_rssi_limit_set(dhdp, lmt2g, lmt5g);
3638 		if (ret) {
3639 			ANDROID_ERROR(("Failed to Set roam_rssi_limit (%d)\n", ret));
3640 			return ret;
3641 		}
3642 	}
3643 
3644 	return ret;
3645 }
3646 #endif /* CONFIG_ROAM_RSSI_LIMIT */
3647 
3648 #ifdef CONFIG_ROAM_MIN_DELTA
3649 int
wl_android_roam_min_delta(struct net_device * dev,char * command,int total_len)3650 wl_android_roam_min_delta(struct net_device *dev, char *command, int total_len)
3651 {
3652 	int ret = BCME_OK;
3653 	int argc, bytes_written = 0;
3654 	uint32 delta2g = 0, delta5g = 0, delta = 0;
3655 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3656 
3657 	argc = sscanf(command, CMD_ROAM_MIN_DELTA " %d\n", &delta);
3658 
3659 	if (!argc) {
3660 		/* Get Minimum ROAM score delta */
3661 		ret = dhd_roam_min_delta_get(dhdp, &delta2g, &delta5g);
3662 		if (ret) {
3663 			ANDROID_ERROR(("Failed to Get roam_min_delta (%d)\n", ret));
3664 			return ret;
3665 		}
3666 		bytes_written = snprintf(command, total_len, "%d, %d\n", delta2g, delta5g);
3667 		return bytes_written;
3668 	} else {
3669 		/* Set Minimum ROAM score delta
3670 		 * Framework set one parameter # wpa_cli driver ROAMMINSCOREDELTA <value>
3671 		 */
3672 		ret = dhd_roam_min_delta_set(dhdp, delta, delta);
3673 		if (ret) {
3674 			ANDROID_ERROR(("Failed to Set roam_min_delta (%d)\n", ret));
3675 			return ret;
3676 		}
3677 	}
3678 
3679 	return ret;
3680 }
3681 #endif /* CONFIG_ROAM_MIN_DELTA */
3682 
3683 static int
get_int_bytes(uchar * oui_str,uchar * oui,int len)3684 get_int_bytes(uchar *oui_str, uchar *oui, int len)
3685 {
3686 	int idx;
3687 	uchar val;
3688 	uchar *src, *dest;
3689 	char hexstr[3];
3690 
3691 	if ((oui_str == NULL) || (oui == NULL) || (len == 0)) {
3692 		return BCME_BADARG;
3693 	}
3694 	src = oui_str;
3695 	dest = oui;
3696 
3697 	for (idx = 0; idx < len; idx++) {
3698 		if (*src == '\0') {
3699 			*dest = '\0';
3700 			break;
3701 		}
3702 		hexstr[0] = src[0];
3703 		hexstr[1] = src[1];
3704 		hexstr[2] = '\0';
3705 
3706 		val = (uchar)bcm_strtoul(hexstr, NULL, 16);
3707 		if (val == (uchar)-1) {
3708 			return BCME_ERROR;
3709 		}
3710 		*dest++ = val;
3711 		src += 2;
3712 	}
3713 	return BCME_OK;
3714 }
3715 
3716 #define TAG_BYTE 0
3717 static int
wl_android_set_disconnect_ies(struct net_device * dev,char * command)3718 wl_android_set_disconnect_ies(struct net_device *dev, char *command)
3719 {
3720 	int cmd_prefix_len = 0;
3721 	char ie_len = 0;
3722 	int hex_ie_len = 0;
3723 	int total_len = 0;
3724 	int max_len = 0;
3725 	int cmd_len = 0;
3726 	uchar disassoc_ie[VNDR_IE_MAX_LEN] = {0};
3727 	s32 bssidx = 0;
3728 	struct bcm_cfg80211 *cfg = NULL;
3729 	s32 ret = 0;
3730 	cfg = wl_get_cfg(dev);
3731 
3732 	cmd_prefix_len = strlen("SET_DISCONNECT_IES ");
3733 	cmd_len = strlen(command);
3734 	/*
3735 	 * <CMD> + <IES in HEX format>
3736 	 * IES in hex format has to be in following format
3737 	 * First byte = Tag, Second Byte = len and rest of
3738 	 * bytes will be value. For ex: SET_DISCONNECT_IES dd0411223344
3739 	 * tag = dd, len =04. Total IEs len = len + 2
3740 	 */
3741 	ANDROID_INFO(("cmd recv = %s\n", command));
3742 	max_len = MIN(cmd_len, VNDR_IE_MAX_LEN);
3743 	/* Validate IEs len */
3744 	get_int_bytes(&command[cmd_prefix_len + 2], &ie_len, 1);
3745 	ANDROID_INFO(("ie_len = %d \n", ie_len));
3746 	if (ie_len <= 0 || ie_len > max_len) {
3747 		ret = BCME_BADLEN;
3748 		return ret;
3749 	}
3750 
3751 	/* Total len in hex is sum of double binary len, tag and len byte */
3752 	hex_ie_len = (ie_len * 2) + 4;
3753 	total_len = cmd_prefix_len + hex_ie_len;
3754 	if (command[total_len] != '\0' || (cmd_len != total_len)) {
3755 		ANDROID_ERROR(("command recv not matching with len, command = %s"
3756 			"total_len = %d, cmd_len = %d\n", command, total_len, cmd_len));
3757 		ret = BCME_BADARG;
3758 		return ret;
3759 	}
3760 
3761 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3762 		ANDROID_ERROR(("Find index failed\n"));
3763 		ret = -EINVAL;
3764 		return ret;
3765 	}
3766 
3767 	/* Tag and len bytes are also part of total len of ies in binary */
3768 	ie_len = ie_len + 2;
3769 	/* Convert IEs in binary */
3770 	get_int_bytes(&command[cmd_prefix_len], disassoc_ie, ie_len);
3771 	if (disassoc_ie[TAG_BYTE] != 0xdd) {
3772 		ANDROID_ERROR(("Wrong tag recv, tag = 0x%02x\n", disassoc_ie[TAG_BYTE]));
3773 		ret = BCME_UNSUPPORTED;
3774 		return ret;
3775 	}
3776 
3777 	ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
3778 		ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, disassoc_ie, ie_len);
3779 
3780 	return ret;
3781 }
3782 
3783 #ifdef FCC_PWR_LIMIT_2G
3784 int
wl_android_set_fcc_pwr_limit_2g(struct net_device * dev,char * command)3785 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
3786 {
3787 	int error = 0;
3788 	int enable = 0;
3789 
3790 	sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
3791 
3792 	if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
3793 		ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: Invalid data\n"));
3794 		return BCME_ERROR;
3795 	}
3796 
3797 	CUSTOMER_HW4_EN_CONVERT(enable);
3798 
3799 	ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g set (%d)\n", enable));
3800 	error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
3801 	if (error) {
3802 		ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g"
3803 			" set returned (%d)\n", error));
3804 		return BCME_ERROR;
3805 	}
3806 
3807 	return error;
3808 }
3809 
3810 int
wl_android_get_fcc_pwr_limit_2g(struct net_device * dev,char * command,int total_len)3811 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
3812 {
3813 	int error = 0;
3814 	int enable = 0;
3815 	int bytes_written = 0;
3816 
3817 	error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
3818 	if (error) {
3819 		ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get"
3820 			" error (%d)\n", error));
3821 		return BCME_ERROR;
3822 	}
3823 	ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get (%d)\n", enable));
3824 
3825 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
3826 
3827 	return bytes_written;
3828 }
3829 #endif /* FCC_PWR_LIMIT_2G */
3830 
3831 /* Additional format of sta_info
3832  * tx_pkts, tx_failures, tx_rate(kbps), rssi(main), rssi(aux), tx_pkts_retried,
3833  * tx_pkts_retry_exhausted, rx_lastpkt_rssi(main), rx_lastpkt_rssi(aux),
3834  * tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
3835  * tx_pkts_fw_retry_exhausted
3836  */
3837 #define STA_INFO_ADD_FMT	"%d %d %d %d %d %d %d %d %d %d %d %d %d %d"
3838 
3839 #ifdef BIGDATA_SOFTAP
3840 #define BIGDATA_SOFTAP_FMT	MACOUI " %d %s %d %d %d %d %d %d"
3841 #endif /* BIGDATA_SOFTAP */
3842 
3843 #define STAINFO_BAND_2G    0x0001
3844 #define STAINFO_BAND_5G    0x0002
3845 #define STAINFO_BAND_6G    0x0004
3846 #define STAINFO_BAND_60G   0x0008
3847 s32
wl_cfg80211_get_sta_info(struct net_device * dev,char * command,int total_len)3848 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
3849 {
3850 	int bytes_written = -1, ret = 0;
3851 	char *pos, *token, *cmdstr;
3852 	bool is_macaddr = FALSE;
3853 	sta_info_v4_t *sta = NULL;
3854 	struct ether_addr mac;
3855 	char *iovar_buf = NULL;
3856 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3857 	struct net_device *apdev = NULL;
3858 #ifdef BCMDONGLEHOST
3859 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3860 #endif /* BCMDONGLEHOST */
3861 
3862 #ifdef BIGDATA_SOFTAP
3863 	void *data = NULL;
3864 	wl_ap_sta_data_t *sta_data = NULL;
3865 #endif /* BIGDATA_SOFTAP */
3866 
3867 	/* Client information */
3868 	uint16 cap = 0;
3869 	uint32 rxrtry = 0, rxmulti = 0;
3870 	uint32 tx_pkts = 0, tx_failures = 0, tx_rate = 0;
3871 	uint32 tx_pkts_retried = 0, tx_pkts_retry_exhausted = 0;
3872 	uint32 tx_pkts_total = 0, tx_pkts_retries = 0;
3873 	uint32 tx_pkts_fw_total = 0, tx_pkts_fw_retries = 0;
3874 	uint32 tx_pkts_fw_retry_exhausted = 0;
3875 	int8 rssi[WL_STA_ANT_MAX] = {0};
3876 	int8 rx_lastpkt_rssi[WL_STA_ANT_MAX] = {0};
3877 	wl_if_stats_t *if_stats = NULL;
3878 	u16 bands = 0;
3879 	u32 sta_flags = 0;
3880 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
3881 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
3882 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
3883 
3884 	BCM_REFERENCE(if_stats);
3885 	/* This Command used during only SoftAP mode. */
3886 	ANDROID_INFO(("%s\n", command));
3887 
3888 	/* Check the current op_mode */
3889 	if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
3890 		ANDROID_ERROR(("unsupported op mode: %d\n", dhdp->op_mode));
3891 		return BCME_NOTAP;
3892 	}
3893 
3894 	/*
3895 	 * DRIVER GETSTAINFO [client MAC or ALL] [ifname]
3896 	 */
3897 	pos = command;
3898 
3899 	/* drop command */
3900 	token = bcmstrtok(&pos, " ", NULL);
3901 
3902 	/* Client MAC or ALL */
3903 	token = bcmstrtok(&pos, " ", NULL);
3904 	if (!token) {
3905 		ANDROID_ERROR(("GETSTAINFO subcmd not provided wl_cfg80211_get_sta_info\n"));
3906 		return -EINVAL;
3907 	}
3908 	cmdstr = token;
3909 
3910 	bzero(&mac, ETHER_ADDR_LEN);
3911 	if ((!strncmp(token, "all", 3)) || (!strncmp(token, "ALL", 3))) {
3912 		is_macaddr = FALSE;
3913 	} else if ((bcm_ether_atoe(token, &mac))) {
3914 		is_macaddr = TRUE;
3915 	} else {
3916 		ANDROID_ERROR(("Failed to get address\n"));
3917 		return -EINVAL;
3918 	}
3919 
3920 	/* get the interface name */
3921 	token = bcmstrtok(&pos, " ", NULL);
3922 	if (!token) {
3923 		/* assign requested dev for compatibility */
3924 		apdev = dev;
3925 	} else {
3926 		/* Find a net_device for SoftAP by interface name */
3927 		apdev = wl_get_ap_netdev(cfg, token);
3928 		if (!apdev) {
3929 			ANDROID_ERROR(("cannot find a net_device for SoftAP\n"));
3930 			return -EINVAL;
3931 		}
3932 	}
3933 
3934 	iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
3935 	if (!iovar_buf) {
3936 		ANDROID_ERROR(("Failed to allocated memory %d bytes\n",
3937 			WLC_IOCTL_MAXLEN));
3938 		return BCME_NOMEM;
3939 	}
3940 
3941 	if (is_macaddr) {
3942 		int cnt;
3943 
3944 		/* get the sta info */
3945 		ret = wldev_iovar_getbuf(apdev, "sta_info",
3946 			(struct ether_addr *)mac.octet, ETHER_ADDR_LEN,
3947 			iovar_buf, WLC_IOCTL_MAXLEN, NULL);
3948 		if (ret < 0) {
3949 			ANDROID_ERROR(("Get sta_info ERR %d\n", ret));
3950 
3951 #ifdef BIGDATA_SOFTAP
3952 			/* Customer wants to send basic client information
3953 			 * to the framework even if DHD cannot get the sta_info.
3954 			 */
3955 			goto get_bigdata;
3956 #endif /* BIGDATA_SOFTAP */
3957 
3958 #ifndef BIGDATA_SOFTAP
3959 			goto error;
3960 #endif /* BIGDATA_SOFTAP */
3961 		}
3962 
3963 		sta = (sta_info_v4_t *)iovar_buf;
3964 		if (dtoh16(sta->ver) != WL_STA_VER_4) {
3965 			ANDROID_ERROR(("sta_info struct version mismatch, "
3966 				"host ver : %d, fw ver : %d\n", WL_STA_VER_4,
3967 				dtoh16(sta->ver)));
3968 
3969 #ifdef BIGDATA_SOFTAP
3970 			/* Customer wants to send basic client information
3971 			 * to the framework even if DHD cannot get the sta_info.
3972 			 */
3973 			goto get_bigdata;
3974 #endif /* BIGDATA_SOFTAP */
3975 
3976 #ifndef BIGDATA_SOFTAP
3977 			goto error;
3978 #endif /* BIGDATA_SOFTAP */
3979 		}
3980 		cap = dtoh16(sta->cap);
3981 		rxrtry = dtoh32(sta->rx_pkts_retried);
3982 		rxmulti = dtoh32(sta->rx_mcast_pkts);
3983 		tx_pkts = dtoh32(sta->tx_pkts);
3984 		tx_failures = dtoh32(sta->tx_failures);
3985 		tx_rate = dtoh32(sta->tx_rate);
3986 		tx_pkts_retried = dtoh32(sta->tx_pkts_retried);
3987 		tx_pkts_retry_exhausted = dtoh32(sta->tx_pkts_retry_exhausted);
3988 		tx_pkts_total = dtoh32(sta->tx_pkts_total);
3989 		tx_pkts_retries = dtoh32(sta->tx_pkts_retries);
3990 		tx_pkts_fw_total = dtoh32(sta->tx_pkts_fw_total);
3991 		tx_pkts_fw_retries = dtoh32(sta->tx_pkts_fw_retries);
3992 		tx_pkts_fw_retry_exhausted = dtoh32(sta->tx_pkts_fw_retry_exhausted);
3993 		sta_flags = dtoh32(sta->flags);
3994 		if (sta_flags & WL_STA_IS_2G) {
3995 			bands |= STAINFO_BAND_2G;
3996 		}
3997 		if (sta_flags & WL_STA_IS_5G) {
3998 			bands |= STAINFO_BAND_5G;
3999 		}
4000 		if (sta_flags & WL_STA_IS_6G) {
4001 			bands |= STAINFO_BAND_6G;
4002 		}
4003 		for (cnt = WL_ANT_IDX_1; cnt < WL_RSSI_ANT_MAX; cnt++) {
4004 			rssi[cnt] = sta->rssi[cnt];
4005 			rx_lastpkt_rssi[cnt] = sta->rx_lastpkt_rssi[cnt];
4006 		}
4007 	} else {
4008 		int i;
4009 
4010 		/* Check if there is an associated STA or not */
4011 		assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
4012 		ret = wldev_ioctl_get(apdev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
4013 
4014 		if (ret < 0) {
4015 			ANDROID_ERROR(("Fail to get assoc list: %d\n", ret));
4016 			goto error;
4017 		}
4018 
4019 		assoc_maclist->count = dtoh32(assoc_maclist->count);
4020 		ANDROID_INFO(("Assoc count :  %d\n", assoc_maclist->count));
4021 
4022 		for (i = 0; i < assoc_maclist->count; i++) {
4023 			/* get the sta info */
4024 			ret = wldev_iovar_getbuf(apdev, "sta_info",
4025 				(struct ether_addr *)assoc_maclist->ea[i].octet, ETHER_ADDR_LEN,
4026 				iovar_buf, WLC_IOCTL_MAXLEN, NULL);
4027 
4028 			if (ret < 0) {
4029 				ANDROID_ERROR(("sta_info err : %d", ret));
4030 				continue;
4031 			}
4032 			sta = (sta_info_v4_t *)iovar_buf;
4033 			if (dtoh16(sta->ver) == WL_STA_VER_4) {
4034 				rxrtry += dtoh32(sta->rx_pkts_retried);
4035 				rxmulti += dtoh32(sta->rx_mcast_pkts);
4036 				tx_pkts += dtoh32(sta->tx_pkts);
4037 				tx_failures += dtoh32(sta->tx_failures);
4038 				tx_pkts_total += dtoh32(sta->tx_pkts_total);
4039 				tx_pkts_retries += dtoh32(sta->tx_pkts_retries);
4040 				tx_pkts_fw_total += dtoh32(sta->tx_pkts_fw_total);
4041 				tx_pkts_fw_retries += dtoh32(sta->tx_pkts_fw_retries);
4042 				tx_pkts_fw_retry_exhausted +=
4043 					dtoh32(sta->tx_pkts_fw_retry_exhausted);
4044 			}
4045 		}
4046 	}
4047 
4048 #ifdef BIGDATA_SOFTAP
4049 get_bigdata:
4050 
4051 	if (is_macaddr && wl_get_ap_stadata(cfg, &mac, &data) == BCME_OK) {
4052 		ANDROID_ERROR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
4053 		sta_data = (wl_ap_sta_data_t *)data;
4054 #ifdef STAINFO_LEGACY
4055 		bytes_written = snprintf(command, total_len,
4056 			"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4057 			"CAP=%04x " BIGDATA_SOFTAP_FMT " " STA_INFO_ADD_FMT
4058 			"\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4059 			MACOUI2STR((char*)&sta_data->mac),
4060 			sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4061 			sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4062 			sta_data->nss, sta_data->mimo, sta_data->reason_code,
4063 			tx_pkts, tx_failures, tx_rate,
4064 			(int32)rssi[WL_ANT_IDX_1], (int32)rssi[WL_ANT_IDX_2],
4065 			tx_pkts_retried, tx_pkts_retry_exhausted,
4066 			(int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4067 			(int32)rx_lastpkt_rssi[WL_ANT_IDX_2],
4068 			tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total,
4069 			tx_pkts_fw_retries, tx_pkts_fw_retry_exhausted);
4070 #else
4071 		bytes_written = snprintf(command, total_len,
4072 			"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4073 			"CAP=%04x " BIGDATA_SOFTAP_FMT " %d\n",
4074 			CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4075 			MACOUI2STR((char*)&sta_data->mac),
4076 			sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4077 			sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4078 			sta_data->nss, sta_data->mimo, sta_data->reason_code, bands);
4079 #endif /* STAINFO_LEGACY */
4080 	} else
4081 #endif /* BIGDATA_SOFTAP */
4082 	{
4083 		ANDROID_ERROR(("ALL\n"));
4084 		bytes_written = snprintf(command, total_len,
4085 			"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x "
4086 			STA_INFO_ADD_FMT "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4087 			tx_pkts, tx_failures, tx_rate, (int32)rssi[WL_ANT_IDX_1],
4088 			(int32)rssi[WL_ANT_IDX_2], tx_pkts_retried,
4089 			tx_pkts_retry_exhausted, (int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4090 			(int32)rx_lastpkt_rssi[WL_ANT_IDX_2], tx_pkts_total,
4091 			tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
4092 			tx_pkts_fw_retry_exhausted);
4093 	}
4094 	WL_ERR_KERN(("Command: %s", command));
4095 
4096 error:
4097 	if (iovar_buf) {
4098 		MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
4099 	}
4100 	if (if_stats) {
4101 		MFREE(cfg->osh, if_stats, sizeof(*if_stats));
4102 	}
4103 
4104 	return bytes_written;
4105 }
4106 
4107 #ifdef WL_WTC
4108 /*
4109  * CMD Format
4110  * Enable format for 3 band and 2 band respectively:
4111  * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G 6G>
4112  * DRIVER SETWTCMODE 0 1 -80 -70 -65 -60
4113  * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G>
4114  * DRIVER SETWTCMODE 0 1 -80 -70 -65
4115  * Disable format for 3 band and 2 band respectively:
4116  * DRIVER SETWTCMODE 1 0 0 0 0 0
4117  * DRIVER SETWTCMODE 1 0 0 0 0
4118  */
4119 #define WL_TRIBAND     3
4120 #define WL_DUALBAND    2
4121 
4122 /* For WTC disable, any value >= 1 */
4123 #define WL_WTC_ENABLE 0
4124 static int
wl_android_wtc_config(struct net_device * dev,char * command,int total_len)4125 wl_android_wtc_config(struct net_device *dev, char *command, int total_len)
4126 {
4127 	s32 bw;
4128 	char *token, *pos;
4129 	wlc_wtc_args_t *wtc_params;
4130 	wlc_wtcconfig_info_v1_t *wtc_config;
4131 	u32 i, wtc_paramslen, maxbands = WL_DUALBAND;
4132 	u8 buf[WLC_IOCTL_SMLEN] = {0};
4133 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4134 
4135 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
4136 #ifdef WL_6G_BAND
4137 	if (cfg->band_6g_supported) {
4138 		maxbands = WL_TRIBAND;
4139 	}
4140 #endif	/* WL_6G_BAND */
4141 	wtc_paramslen = sizeof(wlc_wtcconfig_info_v1_t) + WLC_WTC_ROAM_CONFIG_HDRLEN;
4142 	wtc_params = (wlc_wtc_args_t*)MALLOCZ(cfg->osh, wtc_paramslen);
4143 	if (!wtc_params) {
4144 		ANDROID_ERROR(("Error allocating wtc_params\n"));
4145 		return -ENOMEM;
4146 	}
4147 
4148 	wtc_config = (wlc_wtcconfig_info_v1_t *)wtc_params->data;
4149 	/* Get wtc config information and check version compatibility */
4150 	bw = wldev_iovar_getbuf(dev, "wnm_wbtext_wtc_config",
4151 		(char*)&wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, 0);
4152 	if (bw) {
4153 		ANDROID_ERROR(("Error querying wnm_wbtext_wtc_config: %d\n", bw));
4154 		goto exit;
4155 	}
4156 
4157 	(void)memcpy_s(wtc_params, wtc_paramslen, buf, wtc_paramslen);
4158 	if (wtc_params->ver != WLC_WTC_ROAM_VER_1) {
4159 		ANDROID_ERROR(("Wrong version:%d\n", wtc_params->ver));
4160 		bw = -EINVAL;
4161 		goto exit;
4162 	}
4163 
4164 	if (wtc_params->len != sizeof(wlc_wtcconfig_info_v1_t)) {
4165 		ANDROID_ERROR(("Bad len\n"));
4166 		bw = -EINVAL;
4167 		goto exit;
4168 	}
4169 
4170 	if (strlen(command) == strlen(CMD_WTC_CONFIG)) {
4171 		/* No additional arguments given. GET case  */
4172 		bw += scnprintf(command, (total_len - bw), "%u %u",
4173 			wtc_config->mode, wtc_config->scantype);
4174 		bw += scnprintf(command + bw, (total_len - bw), " %d",
4175 			wtc_config->rssithresh[0]);
4176 		for (i = 0; i < maxbands; i++) {
4177 			bw += scnprintf(command + bw, (total_len - bw), " %d",
4178 				wtc_config->ap_rssithresh[i]);
4179 		}
4180 		bw += scnprintf(command + bw, (total_len - bw), "\n");
4181 	} else {
4182 		/* SET */
4183 		pos = command + sizeof(CMD_WTC_CONFIG);
4184 
4185 		/* mode */
4186 		token = strsep((char**)&pos, " ");
4187 		if (!token) {
4188 			ANDROID_ERROR(("No mode present\n"));
4189 			bw = -EINVAL;
4190 			goto exit;
4191 		}
4192 		wtc_config->mode = (u8)bcm_atoi(token);
4193 
4194 		/* scantype */
4195 		token = strsep((char**)&pos, " ");
4196 		if (!token) {
4197 			ANDROID_ERROR(("No scantype present\n"));
4198 			bw = -EINVAL;
4199 			goto exit;
4200 		}
4201 		wtc_config->scantype = (u8)bcm_atoi(token);
4202 
4203 		/* rssithreshold */
4204 		token = strsep((char**)&pos, " ");
4205 		if (!token) {
4206 			ANDROID_ERROR(("Invalid arg for rssi threshold\n"));
4207 			bw = -EINVAL;
4208 			goto exit;
4209 		}
4210 		for (i = 0; i < maxbands; i++) {
4211 			wtc_config->rssithresh[i] = (s8)bcm_atoi(token);
4212 		}
4213 
4214 		/* AP rssithreshold */
4215 		for (i = 0; i < maxbands; i++) {
4216 			token = strsep((char**)&pos, " ");
4217 			if (!token) {
4218 				ANDROID_ERROR(("Invalid arg for ap threshold\n"));
4219 				bw = -EINVAL;
4220 				goto exit;
4221 			}
4222 			wtc_config->ap_rssithresh[i] = (s8)bcm_atoi(token);
4223 		}
4224 
4225 		bw = wldev_iovar_setbuf(dev, "wnm_wbtext_wtc_config",
4226 			(char*)wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, NULL);
4227 		if (bw) {
4228 			ANDROID_ERROR(("wtc config set failed. ret:%d\n", bw));
4229 		}
4230 	}
4231 
4232 exit:
4233 	if (wtc_params) {
4234 		MFREE(cfg->osh, wtc_params, wtc_paramslen);
4235 	}
4236 	return bw;
4237 }
4238 #endif /* WL_WTC */
4239 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4240 
4241 #ifdef WBTEXT
wl_android_wbtext(struct net_device * dev,char * command,int total_len)4242 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
4243 {
4244 	int error = BCME_OK, argc = 0;
4245 	int data, bytes_written;
4246 	int roam_trigger[2];
4247 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4248 
4249 	argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
4250 	if (!argc) {
4251 		error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
4252 		if (error) {
4253 			ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4254 				error));
4255 			return error;
4256 		}
4257 		bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
4258 				(data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
4259 				"ENABLED" : "DISABLED");
4260 		return bytes_written;
4261 	} else {
4262 		if (data) {
4263 			data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
4264 		}
4265 
4266 		if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
4267 			ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4268 				error));
4269 			return error;
4270 		}
4271 
4272 		if (data) {
4273 			/* reset roam_prof when wbtext is on */
4274 			if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
4275 				return error;
4276 			}
4277 		} else {
4278 			/* reset legacy roam trigger when wbtext is off */
4279 			roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
4280 			roam_trigger[1] = WLC_BAND_ALL;
4281 			if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
4282 					sizeof(roam_trigger))) != BCME_OK) {
4283 				ANDROID_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n",
4284 					error));
4285 				return error;
4286 			}
4287 		}
4288 		dhdp->wbtext_policy = data;
4289 	}
4290 	return error;
4291 }
4292 
4293 static int
wl_android_wbtext_enable(struct net_device * dev,int mode)4294 wl_android_wbtext_enable(struct net_device *dev, int mode)
4295 {
4296 	int error = BCME_OK;
4297 	char commandp[WLC_IOCTL_SMLEN];
4298 
4299 	if (wl_android_check_wbtext_support(dev)) {
4300 		bzero(commandp, sizeof(commandp));
4301 		snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE %d", mode);
4302 		error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN);
4303 		if (error) {
4304 			ANDROID_ERROR(("Failed to set WBTEXT = %d\n", error));
4305 			return error;
4306 		}
4307 	}
4308 
4309 	return error;
4310 }
4311 
wl_cfg80211_wbtext_btm_timer_threshold(struct net_device * dev,char * command,int total_len)4312 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
4313 	char *command, int total_len)
4314 {
4315 	int error = BCME_OK, argc = 0;
4316 	int data, bytes_written;
4317 
4318 	argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
4319 	if (!argc) {
4320 		error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
4321 		if (error) {
4322 			ANDROID_ERROR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
4323 			return error;
4324 		}
4325 		bytes_written = snprintf(command, total_len, "%d\n", data);
4326 		return bytes_written;
4327 	} else {
4328 		if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
4329 				data)) != BCME_OK) {
4330 			ANDROID_ERROR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
4331 			return error;
4332 		}
4333 	}
4334 	return error;
4335 }
4336 
wl_cfg80211_wbtext_btm_delta(struct net_device * dev,char * command,int total_len)4337 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
4338 	char *command, int total_len)
4339 {
4340 	int error = BCME_OK, argc = 0;
4341 	int data = 0, bytes_written;
4342 
4343 	argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
4344 	if (!argc) {
4345 		error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
4346 		if (error) {
4347 			ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4348 			return error;
4349 		}
4350 		bytes_written = snprintf(command, total_len, "%d\n", data);
4351 		return bytes_written;
4352 	} else {
4353 		if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
4354 				data)) != BCME_OK) {
4355 			ANDROID_ERROR(("Failed to set wnm_btmdelta (%d)\n", error));
4356 			return error;
4357 		}
4358 	}
4359 	return error;
4360 }
4361 
wl_cfg80211_wbtext_estm_enable(struct net_device * dev,char * command,int total_len)4362 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
4363 	char *command, int total_len)
4364 {
4365 	int error = BCME_OK;
4366 	int data = 0, bytes_written = 0;
4367 	int wnmmask = 0;
4368 	char *pcmd = command;
4369 
4370 	bcmstrtok(&pcmd, " ", NULL);
4371 
4372 	error = wldev_iovar_getint(dev, "wnm", &wnmmask);
4373 	if (error) {
4374 		ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4375 		return error;
4376 	}
4377 	ANDROID_INFO(("wnmmask %x\n", wnmmask));
4378 	if (*pcmd == WL_IOCTL_ACTION_GET) {
4379 		bytes_written = snprintf(command, total_len, "wbtext_estm_enable %d\n",
4380 			(wnmmask & WL_WNM_ESTM) ? 1:0);
4381 		return bytes_written;
4382 	} else {
4383 		data = bcm_atoi(pcmd);
4384 		if (data == 0) {
4385 			wnmmask &= ~WL_WNM_ESTM;
4386 		} else {
4387 			wnmmask |= WL_WNM_ESTM;
4388 		}
4389 		ANDROID_INFO(("wnmmask %x\n", wnmmask));
4390 		if ((error = wldev_iovar_setint(dev, "wnm", wnmmask)) != BCME_OK) {
4391 			ANDROID_ERROR(("Failed to set wnm mask (%d)\n", error));
4392 			return error;
4393 		}
4394 	}
4395 	return error;
4396 }
4397 #endif /* WBTEXT */
4398 
4399 #ifdef PNO_SUPPORT
4400 #define PNO_PARAM_SIZE 50
4401 #define VALUE_SIZE 50
4402 #define LIMIT_STR_FMT  ("%50s %50s")
4403 static int
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)4404 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
4405 {
4406 	int err = BCME_OK;
4407 	uint i, tokens, len_remain;
4408 	char *pos, *pos2, *token, *token2, *delim;
4409 	char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
4410 	struct dhd_pno_batch_params batch_params;
4411 
4412 	ANDROID_INFO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len));
4413 	len_remain = total_len;
4414 	if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
4415 		pos = command + strlen(CMD_WLS_BATCHING) + 1;
4416 		len_remain -= strlen(CMD_WLS_BATCHING) + 1;
4417 	} else {
4418 		ANDROID_ERROR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len));
4419 		err = BCME_ERROR;
4420 		goto exit;
4421 	}
4422 	bzero(&batch_params, sizeof(struct dhd_pno_batch_params));
4423 	if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
4424 		if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
4425 			pos += strlen(PNO_BATCHING_SET) + 1;
4426 		} else {
4427 			ANDROID_ERROR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n",
4428 				PNO_BATCHING_SET, total_len));
4429 			err = BCME_ERROR;
4430 			goto exit;
4431 		}
4432 		while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
4433 			bzero(param, sizeof(param));
4434 			bzero(value, sizeof(value));
4435 			if (token == NULL || !*token)
4436 				break;
4437 			if (*token == '\0')
4438 				continue;
4439 			delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
4440 			if (delim != NULL)
4441 				*delim = ' ';
4442 
4443 			tokens = sscanf(token, LIMIT_STR_FMT, param, value);
4444 			if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
4445 				batch_params.scan_fr = simple_strtol(value, NULL, 0);
4446 				ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
4447 			} else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
4448 				batch_params.bestn = simple_strtol(value, NULL, 0);
4449 				ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
4450 			} else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
4451 				batch_params.mscan = simple_strtol(value, NULL, 0);
4452 				ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
4453 			} else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
4454 				i = 0;
4455 				pos2 = value;
4456 				tokens = sscanf(value, "<%s>", value);
4457 				if (tokens != 1) {
4458 					err = BCME_ERROR;
4459 					ANDROID_ERROR(("wls_parse_batching_cmd: invalid format"
4460 					" for channel"
4461 					" <> params\n"));
4462 					goto exit;
4463 				}
4464 				while ((token2 = strsep(&pos2,
4465 						PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
4466 					if (token2 == NULL || !*token2)
4467 						break;
4468 					if (*token2 == '\0')
4469 						continue;
4470 					if (*token2 == 'A' || *token2 == 'B') {
4471 						batch_params.band = (*token2 == 'A')?
4472 							WLC_BAND_5G : WLC_BAND_2G;
4473 						ANDROID_INFO(("band : %s\n",
4474 							(*token2 == 'A')? "A" : "B"));
4475 					} else {
4476 						if ((batch_params.nchan >= WL_NUMCHANNELS) ||
4477 							(i >= WL_NUMCHANNELS)) {
4478 							ANDROID_ERROR(("Too many nchan %d\n",
4479 								batch_params.nchan));
4480 							err = BCME_BUFTOOSHORT;
4481 							goto exit;
4482 						}
4483 						batch_params.chan_list[i++] =
4484 							simple_strtol(token2, NULL, 0);
4485 						batch_params.nchan++;
4486 						ANDROID_INFO(("channel :%d\n",
4487 							batch_params.chan_list[i-1]));
4488 					}
4489 				 }
4490 			} else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
4491 				batch_params.rtt = simple_strtol(value, NULL, 0);
4492 				ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
4493 			} else {
4494 				ANDROID_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param));
4495 				err = BCME_ERROR;
4496 				goto exit;
4497 			}
4498 		}
4499 		err = dhd_dev_pno_set_for_batch(dev, &batch_params);
4500 		if (err < 0) {
4501 			ANDROID_ERROR(("failed to configure batch scan\n"));
4502 		} else {
4503 			bzero(command, total_len);
4504 			err = snprintf(command, total_len, "%d", err);
4505 		}
4506 	} else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
4507 		err = dhd_dev_pno_get_for_batch(dev, command, total_len);
4508 		if (err < 0) {
4509 			ANDROID_ERROR(("failed to getting batching results\n"));
4510 		} else {
4511 			err = strlen(command);
4512 		}
4513 	} else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
4514 		err = dhd_dev_pno_stop_for_batch(dev);
4515 		if (err < 0) {
4516 			ANDROID_ERROR(("failed to stop batching scan\n"));
4517 		} else {
4518 			bzero(command, total_len);
4519 			err = snprintf(command, total_len, "OK");
4520 		}
4521 	} else {
4522 		ANDROID_ERROR(("wls_parse_batching_cmd : unknown command\n"));
4523 		err = BCME_ERROR;
4524 		goto exit;
4525 	}
4526 exit:
4527 	return err;
4528 }
4529 
4530 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)4531 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
4532 {
4533 	wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
4534 	int res = -1;
4535 	int nssid = 0;
4536 	cmd_tlv_t *cmd_tlv_temp;
4537 	char *str_ptr;
4538 	int tlv_size_left;
4539 	int pno_time = 0;
4540 	int pno_repeat = 0;
4541 	int pno_freq_expo_max = 0;
4542 
4543 #ifdef PNO_SET_DEBUG
4544 	int i;
4545 	char pno_in_example[] = {
4546 		'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
4547 		'S', '1', '2', '0',
4548 		'S',
4549 		0x05,
4550 		'd', 'l', 'i', 'n', 'k',
4551 		'S',
4552 		0x04,
4553 		'G', 'O', 'O', 'G',
4554 		'T',
4555 		'0', 'B',
4556 		'R',
4557 		'2',
4558 		'M',
4559 		'2',
4560 		0x00
4561 		};
4562 #endif /* PNO_SET_DEBUG */
4563 	ANDROID_INFO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len));
4564 
4565 	if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
4566 		ANDROID_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len));
4567 		goto exit_proc;
4568 	}
4569 #ifdef PNO_SET_DEBUG
4570 	memcpy(command, pno_in_example, sizeof(pno_in_example));
4571 	total_len = sizeof(pno_in_example);
4572 #endif
4573 	str_ptr = command + strlen(CMD_PNOSETUP_SET);
4574 	tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
4575 
4576 	cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
4577 	bzero(ssids_local, sizeof(ssids_local));
4578 
4579 	if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
4580 		(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
4581 		(cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
4582 
4583 		str_ptr += sizeof(cmd_tlv_t);
4584 		tlv_size_left -= sizeof(cmd_tlv_t);
4585 
4586 		if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
4587 			MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
4588 			ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
4589 			goto exit_proc;
4590 		} else {
4591 			if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
4592 				ANDROID_ERROR(("wl_android_set_pno_setup: scan duration corrupted"
4593 					" field size %d\n",
4594 					tlv_size_left));
4595 				goto exit_proc;
4596 			}
4597 			str_ptr++;
4598 			pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
4599 			ANDROID_INFO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time));
4600 
4601 			if (str_ptr[0] != 0) {
4602 				if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
4603 					ANDROID_ERROR(("wl_android_set_pno_setup: pno repeat:"
4604 						" corrupted field\n"));
4605 					goto exit_proc;
4606 				}
4607 				str_ptr++;
4608 				pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
4609 				ANDROID_INFO(("wl_android_set_pno_setup: got pno_repeat=%d\n",
4610 					pno_repeat));
4611 				if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
4612 					ANDROID_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX"
4613 						" corrupted field size\n"));
4614 					goto exit_proc;
4615 				}
4616 				str_ptr++;
4617 				pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
4618 				ANDROID_INFO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n",
4619 					pno_freq_expo_max));
4620 			}
4621 		}
4622 	} else {
4623 		ANDROID_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n"));
4624 		goto exit_proc;
4625 	}
4626 
4627 	res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
4628 		pno_freq_expo_max, NULL, 0);
4629 exit_proc:
4630 	return res;
4631 }
4632 #endif /* !WL_SCHED_SCAN */
4633 #endif /* PNO_SUPPORT  */
4634 
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)4635 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
4636 {
4637 	int ret;
4638 	struct ether_addr p2pdev_addr;
4639 
4640 #define MAC_ADDR_STR_LEN 18
4641 	if (total_len < MAC_ADDR_STR_LEN) {
4642 		ANDROID_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n",
4643 			total_len));
4644 		return -1;
4645 	}
4646 
4647 	ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
4648 	if (ret) {
4649 		ANDROID_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n"));
4650 		return -1;
4651 	}
4652 	return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
4653 }
4654 
4655 int
wl_android_set_ap_mac_list(struct net_device * dev,int macmode,struct maclist * maclist)4656 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
4657 {
4658 	int i, j, match;
4659 	int ret	= 0;
4660 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
4661 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
4662 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
4663 
4664 	/* set filtering mode */
4665 	if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
4666 		ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret));
4667 		return ret;
4668 	}
4669 	if (macmode != MACLIST_MODE_DISABLED) {
4670 		/* set the MAC filter list */
4671 		if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
4672 			sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
4673 			ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret));
4674 			return ret;
4675 		}
4676 		/* get the current list of associated STAs */
4677 		assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
4678 		if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
4679 			sizeof(mac_buf))) != 0) {
4680 			ANDROID_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n",
4681 				ret));
4682 			return ret;
4683 		}
4684 		/* do we have any STA associated?  */
4685 		if (assoc_maclist->count) {
4686 			/* iterate each associated STA */
4687 			for (i = 0; i < assoc_maclist->count; i++) {
4688 				match = 0;
4689 				/* compare with each entry */
4690 				for (j = 0; j < maclist->count; j++) {
4691 					ANDROID_INFO(("wl_android_set_ap_mac_list: associated="MACDBG
4692 					"list = "MACDBG "\n",
4693 					MAC2STRDBG(assoc_maclist->ea[i].octet),
4694 					MAC2STRDBG(maclist->ea[j].octet)));
4695 					if (memcmp(assoc_maclist->ea[i].octet,
4696 						maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
4697 						match = 1;
4698 						break;
4699 					}
4700 				}
4701 				/* do conditional deauth */
4702 				/*   "if not in the allow list" or "if in the deny list" */
4703 				if ((macmode == MACLIST_MODE_ALLOW && !match) ||
4704 					(macmode == MACLIST_MODE_DENY && match)) {
4705 					scb_val_t scbval;
4706 
4707 					scbval.val = htod32(1);
4708 					memcpy(&scbval.ea, &assoc_maclist->ea[i],
4709 						ETHER_ADDR_LEN);
4710 					if ((ret = wldev_ioctl_set(dev,
4711 						WLC_SCB_DEAUTHENTICATE_FOR_REASON,
4712 						&scbval, sizeof(scb_val_t))) != 0)
4713 						ANDROID_ERROR(("wl_android_set_ap_mac_list:"
4714 							" WLC_SCB_DEAUTHENTICATE"
4715 							" error=%d\n",
4716 							ret));
4717 				}
4718 			}
4719 		}
4720 	}
4721 	return ret;
4722 }
4723 
4724 /*
4725  * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
4726  *
4727  */
4728 static int
wl_android_set_mac_address_filter(struct net_device * dev,char * str)4729 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
4730 {
4731 	int i;
4732 	int ret = 0;
4733 	int macnum = 0;
4734 	int macmode = MACLIST_MODE_DISABLED;
4735 	struct maclist *list;
4736 	char eabuf[ETHER_ADDR_STR_LEN];
4737 	const char *token;
4738 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4739 
4740 	/* string should look like below (macmode/macnum/maclist) */
4741 	/*   1 2 00:11:22:33:44:55 00:11:22:33:44:ff  */
4742 
4743 	/* get the MAC filter mode */
4744 	token = strsep((char**)&str, " ");
4745 	if (!token) {
4746 		return -1;
4747 	}
4748 	macmode = bcm_atoi(token);
4749 
4750 	if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
4751 		ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode));
4752 		return -1;
4753 	}
4754 
4755 	token = strsep((char**)&str, " ");
4756 	if (!token) {
4757 		return -1;
4758 	}
4759 	macnum = bcm_atoi(token);
4760 	if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
4761 		ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC"
4762 			" address entries %d\n",
4763 			macnum));
4764 		return -1;
4765 	}
4766 	/* allocate memory for the MAC list */
4767 	list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
4768 		sizeof(struct ether_addr) * macnum);
4769 	if (!list) {
4770 		ANDROID_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n"));
4771 		return -1;
4772 	}
4773 	/* prepare the MAC list */
4774 	list->count = htod32(macnum);
4775 	bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
4776 	for (i = 0; i < list->count; i++) {
4777 		token = strsep((char**)&str, " ");
4778 		if (token == NULL) {
4779 			ANDROID_ERROR(("wl_android_set_mac_address_filter : No mac address present\n"));
4780 			ret = -EINVAL;
4781 			goto exit;
4782 		}
4783 		strlcpy(eabuf, token, sizeof(eabuf));
4784 		if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
4785 			ANDROID_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d,"
4786 				" addr=%s\n",
4787 				i, eabuf));
4788 			list->count = i;
4789 			break;
4790 		}
4791 		ANDROID_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s",
4792 			i, list->count, eabuf));
4793 	}
4794 	if (i == 0)
4795 		goto exit;
4796 
4797 	/* set the list */
4798 	if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
4799 		ANDROID_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n",
4800 			ret));
4801 
4802 exit:
4803 	MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
4804 
4805 	return ret;
4806 }
4807 
wl_android_get_factory_mac_addr(struct net_device * ndev,char * command,int total_len)4808 static int wl_android_get_factory_mac_addr(struct net_device *ndev, char *command, int total_len)
4809 {
4810 	int ret;
4811 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
4812 
4813 	if (total_len < ETHER_ADDR_STR_LEN) {
4814 		ANDROID_ERROR(("wl_android_get_factory_mac_addr buflen %d"
4815 			"is less than factory mac addr\n", total_len));
4816 		return BCME_ERROR;
4817 	}
4818 	ret = snprintf(command, total_len, MACDBG,
4819 		MAC2STRDBG(bcmcfg_to_prmry_ndev(cfg)->perm_addr));
4820 	return ret;
4821 }
4822 
4823 #if defined(WLAN_ACCEL_BOOT)
wl_android_wifi_accel_on(struct net_device * dev,bool force_reg_on)4824 int wl_android_wifi_accel_on(struct net_device *dev, bool force_reg_on)
4825 {
4826 	int ret = 0;
4827 
4828 	ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4829 	if (!dev) {
4830 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4831 		return -EINVAL;
4832 	}
4833 
4834 	if (force_reg_on) {
4835 		/* First resume the bus if it is in suspended state */
4836 		ret = dhd_net_bus_resume(dev, 0);
4837 		if (ret) {
4838 			ANDROID_ERROR(("%s: dhd_net_bus_resume failed\n", __FUNCTION__));
4839 		}
4840 		/* Toggle wl_reg_on */
4841 		ret = wl_android_wifi_off(dev, TRUE);
4842 		if (ret) {
4843 			ANDROID_ERROR(("%s: wl_android_wifi_off failed\n", __FUNCTION__));
4844 		}
4845 		ret = wl_android_wifi_on(dev);
4846 		if (ret) {
4847 			ANDROID_ERROR(("%s: wl_android_wifi_on failed\n", __FUNCTION__));
4848 		}
4849 	} else {
4850 		ret = dhd_net_bus_resume(dev, 0);
4851 	}
4852 
4853 	return ret;
4854 }
4855 
wl_android_wifi_accel_off(struct net_device * dev,bool force_reg_on)4856 int wl_android_wifi_accel_off(struct net_device *dev, bool force_reg_on)
4857 {
4858 	int ret = 0;
4859 
4860 	ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4861 	if (!dev) {
4862 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4863 		return -EINVAL;
4864 	}
4865 
4866 	if (force_reg_on) {
4867 		ANDROID_ERROR(("%s: do nothing as wl_reg_on will be toggled in UP\n",
4868 			__FUNCTION__));
4869 	} else {
4870 		ret = dhd_net_bus_suspend(dev);
4871 	}
4872 
4873 	return ret;
4874 }
4875 #endif /* WLAN_ACCEL_BOOT */
4876 
4877 #ifdef WBRC
4878 extern int wbrc_wl2bt_reset(void);
4879 #endif /* WBRC */
4880 
4881 /**
4882  * Global function definitions (declared in wl_android.h)
4883  */
4884 
wl_android_wifi_on(struct net_device * dev)4885 int wl_android_wifi_on(struct net_device *dev)
4886 {
4887 	int ret = 0;
4888 	int retry = POWERUP_MAX_RETRY;
4889 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4890 
4891 	BCM_REFERENCE(dhdp);
4892 	if (!dev) {
4893 		ANDROID_ERROR(("wl_android_wifi_on: dev is null\n"));
4894 		return -EINVAL;
4895 	}
4896 
4897 	dhd_net_if_lock(dev);
4898 	WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on);
4899 	if (!g_wifi_on) {
4900 		do {
4901 			dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
4902 #ifdef BCMSDIO
4903 			ret = dhd_net_bus_resume(dev, 0);
4904 			if (ret)
4905 				goto retry_power;
4906 #endif /* BCMSDIO */
4907 			ret = dhd_net_bus_devreset(dev, FALSE);
4908 #ifdef WBRC
4909 			if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ONCE) {
4910 				ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4911 					__FUNCTION__, dhdp->dhd_induce_bh_error));
4912 				/* Forcefully set error */
4913 				ret = BCME_ERROR;
4914 				/* Clear the induced bh error */
4915 				dhdp->dhd_induce_bh_error = DHD_INDUCE_ERROR_CLEAR;
4916 			}
4917 			if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ALWAYS) {
4918 				ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4919 					__FUNCTION__, dhdp->dhd_induce_bh_error));
4920 				/* Forcefully set error */
4921 				ret = BCME_ERROR;
4922 			}
4923 #endif /* WBRC */
4924 			if (ret)
4925 				goto retry_power;
4926 #if defined(BCMSDIO) || defined(BCMDBUS)
4927 #ifdef BCMSDIO
4928 			dhd_net_bus_resume(dev, 1);
4929 #endif /* BCMSDIO */
4930 			ret = dhd_dev_init_ioctl(dev);
4931 			if (ret < 0) {
4932 				goto retry_bus;
4933 			}
4934 #endif /* BCMSDIO || BCMDBUS */
4935 			if (ret == 0) {
4936 				break;
4937 			}
4938 #if defined(BCMSDIO) || defined(BCMDBUS)
4939 retry_bus:
4940 #ifdef BCMSDIO
4941 			dhd_net_bus_suspend(dev);
4942 #endif /* BCMSDIO */
4943 #endif /* BCMSDIO || BCMDBUS */
4944 retry_power:
4945 			ANDROID_ERROR(("failed to power up wifi chip, retry again (%d left) **\n\n",
4946 				retry));
4947 			dhd_net_bus_devreset(dev, TRUE);
4948 			dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4949 #ifdef WBRC
4950 			/* Inform BT reset which will internally wait till BT reset is done */
4951 			if (wbrc_wl2bt_reset()) {
4952 				ANDROID_ERROR(("Failed to reset BT, nothing to be done!!!!\n"));
4953 			}
4954 #endif /* WBRC */
4955 		} while (retry-- > 0);
4956 		if (ret != 0) {
4957 			ANDROID_ERROR(("failed to power up wifi chip, max retry reached **\n\n"));
4958 #ifdef BCM_DETECT_TURN_ON_FAILURE
4959 			BUG_ON(1);
4960 #endif /* BCM_DETECT_TURN_ON_FAILURE */
4961 			goto exit;
4962 		}
4963 		g_wifi_on = TRUE;
4964 	}
4965 
4966 exit:
4967 	if (ret)
4968 		WL_MSG(dev->name, "Failed %d\n", ret);
4969 	else
4970 		WL_MSG(dev->name, "Success\n");
4971 	dhd_net_if_unlock(dev);
4972 	return ret;
4973 }
4974 
wl_android_wifi_off(struct net_device * dev,bool on_failure)4975 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
4976 {
4977 	int ret = 0;
4978 
4979 	if (!dev) {
4980 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4981 		return -EINVAL;
4982 	}
4983 
4984 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
4985 	ret = dhd_debug_uart_is_running(dev);
4986 	if (ret) {
4987 		ANDROID_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
4988 		return -EBUSY;
4989 	}
4990 #endif	/* BCMPCIE && DHD_DEBUG_UART */
4991 	dhd_net_if_lock(dev);
4992 	WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure);
4993 	if (g_wifi_on || on_failure) {
4994 #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
4995 		ret = dhd_net_bus_devreset(dev, TRUE);
4996 #ifdef BCMSDIO
4997 		dhd_net_bus_suspend(dev);
4998 #endif /* BCMSDIO */
4999 #endif /* BCMSDIO || BCMPCIE || BCMDBUS */
5000 		dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
5001 		g_wifi_on = FALSE;
5002 	}
5003 	WL_MSG(dev->name, "out\n");
5004 	dhd_net_if_unlock(dev);
5005 
5006 	return ret;
5007 }
5008 
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)5009 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
5010 {
5011 	if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
5012 		return -1;
5013 	return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
5014 }
5015 
5016 #ifdef CONNECTION_STATISTICS
5017 static int
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)5018 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
5019 {
5020 	int err;
5021 	wl_chanim_stats_t *list;
5022 	/* Parameter _and_ returned buffer of chanim_stats. */
5023 	wl_chanim_stats_t param;
5024 	u8 result[WLC_IOCTL_SMLEN];
5025 	chanim_stats_t *stats;
5026 
5027 	bzero(&param, sizeof(param));
5028 
5029 	param.buflen = htod32(sizeof(wl_chanim_stats_t));
5030 	param.count = htod32(WL_CHANIM_COUNT_ONE);
5031 
5032 	if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
5033 		(char*)result, sizeof(result), 0)) < 0) {
5034 		ANDROID_ERROR(("Failed to get chanim results %d \n", err));
5035 		return err;
5036 	}
5037 
5038 	list = (wl_chanim_stats_t*)result;
5039 
5040 	list->buflen = dtoh32(list->buflen);
5041 	list->version = dtoh32(list->version);
5042 	list->count = dtoh32(list->count);
5043 
5044 	if (list->buflen == 0) {
5045 		list->version = 0;
5046 		list->count = 0;
5047 	} else if (list->version != WL_CHANIM_STATS_VERSION) {
5048 		ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
5049 			"but driver supports only version %d.\n",
5050 				list->version, WL_CHANIM_STATS_VERSION));
5051 		list->buflen = 0;
5052 		list->count = 0;
5053 	}
5054 
5055 	stats = list->stats;
5056 	stats->glitchcnt = dtoh32(stats->glitchcnt);
5057 	stats->badplcp = dtoh32(stats->badplcp);
5058 	stats->chanspec = dtoh16(stats->chanspec);
5059 	stats->timestamp = dtoh32(stats->timestamp);
5060 	stats->chan_idle = dtoh32(stats->chan_idle);
5061 
5062 	ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
5063 		stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
5064 		stats->timestamp));
5065 
5066 	*chan_idle = stats->chan_idle;
5067 
5068 	return (err);
5069 }
5070 
5071 static int
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)5072 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
5073 {
5074 	static char iovar_buf[WLC_IOCTL_MAXLEN];
5075 	const wl_cnt_wlc_t* wlc_cnt = NULL;
5076 #ifndef DISABLE_IF_COUNTERS
5077 	wl_if_stats_t* if_stats = NULL;
5078 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5079 #ifdef BCMDONGLEHOST
5080 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
5081 #endif /* BCMDONGLEHOST */
5082 #endif /* DISABLE_IF_COUNTERS */
5083 
5084 	int link_speed = 0;
5085 	struct connection_stats *output;
5086 	unsigned int bufsize = 0;
5087 	int bytes_written = -1;
5088 	int ret = 0;
5089 
5090 	ANDROID_INFO(("wl_android_get_connection_stats: enter Get Connection Stats\n"));
5091 
5092 	if (total_len <= 0) {
5093 		ANDROID_ERROR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len));
5094 		goto error;
5095 	}
5096 
5097 	bufsize = total_len;
5098 	if (bufsize < sizeof(struct connection_stats)) {
5099 		ANDROID_ERROR(("wl_android_get_connection_stats: not enough buffer size, provided=%u,"
5100 			" requires=%zu\n",
5101 			bufsize,
5102 			sizeof(struct connection_stats)));
5103 		goto error;
5104 	}
5105 
5106 	output = (struct connection_stats *)command;
5107 
5108 #ifndef DISABLE_IF_COUNTERS
5109 	if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
5110 	if (if_stats == NULL) {
5111 		ANDROID_ERROR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
5112 		goto error;
5113 	}
5114 	bzero(if_stats, sizeof(*if_stats));
5115 
5116 #ifdef BCMDONGLEHOST
5117 	if (FW_SUPPORTED(dhdp, ifst)) {
5118 		ret = wl_cfg80211_ifstats_counters(dev, if_stats);
5119 	} else
5120 #endif /* BCMDONGLEHOST */
5121 	{
5122 		ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5123 			(char *)if_stats, sizeof(*if_stats), NULL);
5124 	}
5125 
5126 	ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5127 		(char *)if_stats, sizeof(*if_stats), NULL);
5128 	if (ret) {
5129 		ANDROID_ERROR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n",
5130 			ret));
5131 
5132 		/* In case if_stats IOVAR is not supported, get information from counters. */
5133 #endif /* DISABLE_IF_COUNTERS */
5134 		ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
5135 			iovar_buf, WLC_IOCTL_MAXLEN, NULL);
5136 		if (unlikely(ret)) {
5137 			ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
5138 			goto error;
5139 		}
5140 		ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
5141 		if (ret != BCME_OK) {
5142 			ANDROID_ERROR(("wl_android_get_connection_stats:"
5143 			" wl_cntbuf_to_xtlv_format ERR %d\n",
5144 			ret));
5145 			goto error;
5146 		}
5147 
5148 		if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
5149 			ANDROID_ERROR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
5150 			goto error;
5151 		}
5152 
5153 		output->txframe   = dtoh32(wlc_cnt->txframe);
5154 		output->txbyte    = dtoh32(wlc_cnt->txbyte);
5155 		output->txerror   = dtoh32(wlc_cnt->txerror);
5156 		output->rxframe   = dtoh32(wlc_cnt->rxframe);
5157 		output->rxbyte    = dtoh32(wlc_cnt->rxbyte);
5158 		output->txfail    = dtoh32(wlc_cnt->txfail);
5159 		output->txretry   = dtoh32(wlc_cnt->txretry);
5160 		output->txretrie  = dtoh32(wlc_cnt->txretrie);
5161 		output->txrts     = dtoh32(wlc_cnt->txrts);
5162 		output->txnocts   = dtoh32(wlc_cnt->txnocts);
5163 		output->txexptime = dtoh32(wlc_cnt->txexptime);
5164 #ifndef DISABLE_IF_COUNTERS
5165 	} else {
5166 		/* Populate from if_stats. */
5167 		if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
5168 			ANDROID_ERROR(("wl_android_get_connection_stats: incorrect version of"
5169 				" wl_if_stats_t,"
5170 				" expected=%u got=%u\n",
5171 				WL_IF_STATS_T_VERSION, if_stats->version));
5172 			goto error;
5173 		}
5174 
5175 		output->txframe   = (uint32)dtoh64(if_stats->txframe);
5176 		output->txbyte    = (uint32)dtoh64(if_stats->txbyte);
5177 		output->txerror   = (uint32)dtoh64(if_stats->txerror);
5178 		output->rxframe   = (uint32)dtoh64(if_stats->rxframe);
5179 		output->rxbyte    = (uint32)dtoh64(if_stats->rxbyte);
5180 		output->txfail    = (uint32)dtoh64(if_stats->txfail);
5181 		output->txretry   = (uint32)dtoh64(if_stats->txretry);
5182 		output->txretrie  = (uint32)dtoh64(if_stats->txretrie);
5183 		if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
5184 			output->txexptime = (uint32)dtoh64(if_stats->txexptime);
5185 			output->txrts     = (uint32)dtoh64(if_stats->txrts);
5186 			output->txnocts   = (uint32)dtoh64(if_stats->txnocts);
5187 		} else {
5188 			output->txexptime = 0;
5189 			output->txrts     = 0;
5190 			output->txnocts   = 0;
5191 		}
5192 	}
5193 #endif /* DISABLE_IF_COUNTERS */
5194 
5195 	/* link_speed is in kbps */
5196 	ret = wldev_get_link_speed(dev, &link_speed);
5197 	if (ret || link_speed < 0) {
5198 		ANDROID_ERROR(("wl_android_get_connection_stats: wldev_get_link_speed()"
5199 			" failed, ret=%d, speed=%d\n",
5200 			ret, link_speed));
5201 		goto error;
5202 	}
5203 
5204 	output->txrate    = link_speed;
5205 
5206 	/* Channel idle ratio. */
5207 	if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
5208 		output->chan_idle = 0;
5209 	};
5210 
5211 	bytes_written = sizeof(struct connection_stats);
5212 
5213 error:
5214 #ifndef DISABLE_IF_COUNTERS
5215 	if (if_stats) {
5216 		MFREE(cfg->osh, if_stats, sizeof(*if_stats));
5217 	}
5218 #endif /* DISABLE_IF_COUNTERS */
5219 
5220 	return bytes_written;
5221 }
5222 #endif /* CONNECTION_STATISTICS */
5223 
5224 #ifdef WL_NATOE
5225 static int
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)5226 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
5227 {
5228 	int ret = BCME_ERROR;
5229 	char *pcmd = command;
5230 	char *str = NULL;
5231 	wl_natoe_cmd_info_t cmd_info;
5232 	const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
5233 
5234 	/* skip to cmd name after "natoe" */
5235 	str = bcmstrtok(&pcmd, " ", NULL);
5236 
5237 	/* If natoe subcmd name is not provided, return error */
5238 	if (*pcmd == '\0') {
5239 		ANDROID_ERROR(("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
5240 		ret = -EINVAL;
5241 		return ret;
5242 	}
5243 
5244 	/* get the natoe command name to str */
5245 	str = bcmstrtok(&pcmd, " ", NULL);
5246 
5247 	while (natoe_cmd->name != NULL) {
5248 		if (strcmp(natoe_cmd->name, str) == 0)  {
5249 			/* dispacth cmd to appropriate handler */
5250 			if (natoe_cmd->handler) {
5251 				cmd_info.command = command;
5252 				cmd_info.tot_len = total_len;
5253 				ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
5254 			}
5255 			return ret;
5256 		}
5257 		natoe_cmd++;
5258 	}
5259 	return ret;
5260 }
5261 
5262 static int
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)5263 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
5264 {
5265 	int res = BCME_OK;
5266 	wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
5267 	uint8 *command = cmd_info->command;
5268 	uint16 total_len = cmd_info->tot_len;
5269 	uint16 bytes_written = 0;
5270 
5271 	UNUSED_PARAMETER(len);
5272 
5273 	switch (type) {
5274 
5275 	case WL_NATOE_XTLV_ENABLE:
5276 	{
5277 		bytes_written = snprintf(command, total_len, "natoe: %s\n",
5278 				*data?"enabled":"disabled");
5279 		cmd_info->bytes_written = bytes_written;
5280 		break;
5281 	}
5282 
5283 	case WL_NATOE_XTLV_CONFIG_IPS:
5284 	{
5285 		wl_natoe_config_ips_t *config_ips;
5286 		uint8 buf[16];
5287 
5288 		config_ips = (wl_natoe_config_ips_t *)data;
5289 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
5290 		bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
5291 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
5292 		bytes_written += snprintf(command + bytes_written, total_len,
5293 				"sta netmask: %s\n", buf);
5294 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
5295 		bytes_written += snprintf(command + bytes_written, total_len,
5296 				"sta router ip: %s\n", buf);
5297 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
5298 		bytes_written += snprintf(command + bytes_written, total_len,
5299 				"sta dns ip: %s\n", buf);
5300 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
5301 		bytes_written += snprintf(command + bytes_written, total_len,
5302 				"ap ip: %s\n", buf);
5303 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
5304 		bytes_written += snprintf(command + bytes_written, total_len,
5305 				"ap netmask: %s\n", buf);
5306 		cmd_info->bytes_written = bytes_written;
5307 		break;
5308 	}
5309 
5310 	case WL_NATOE_XTLV_CONFIG_PORTS:
5311 	{
5312 		wl_natoe_ports_config_t *ports_config;
5313 
5314 		ports_config = (wl_natoe_ports_config_t *)data;
5315 		bytes_written = snprintf(command, total_len, "starting port num: %d\n",
5316 				dtoh16(ports_config->start_port_num));
5317 		bytes_written += snprintf(command + bytes_written, total_len,
5318 				"number of ports: %d\n", dtoh16(ports_config->no_of_ports));
5319 		cmd_info->bytes_written = bytes_written;
5320 		break;
5321 	}
5322 
5323 	case WL_NATOE_XTLV_DBG_STATS:
5324 	{
5325 		char *stats_dump = (char *)data;
5326 
5327 		bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
5328 		cmd_info->bytes_written = bytes_written;
5329 		break;
5330 	}
5331 
5332 	case WL_NATOE_XTLV_TBL_CNT:
5333 	{
5334 		bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
5335 				dtoh32(*(uint32 *)data));
5336 		cmd_info->bytes_written = bytes_written;
5337 		break;
5338 	}
5339 
5340 	default:
5341 		/* ignore */
5342 		break;
5343 	}
5344 
5345 	return res;
5346 }
5347 
5348 /*
5349  *   --- common for all natoe get commands ----
5350  */
5351 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)5352 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
5353 		uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
5354 {
5355 	/* for gets we only need to pass ioc header */
5356 	wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
5357 	int res;
5358 
5359 	/*  send getbuf natoe iovar */
5360 	res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
5361 			buflen, NULL);
5362 
5363 	/*  check the response buff  */
5364 	if ((res == BCME_OK)) {
5365 		/* scans ioctl tlvbuf f& invokes the cbfn for processing  */
5366 		res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
5367 				BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
5368 
5369 		if (res == BCME_OK) {
5370 			res = cmd_info->bytes_written;
5371 		}
5372 	}
5373 	else
5374 	{
5375 		ANDROID_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res));
5376 		res = BCME_ERROR;
5377 	}
5378 
5379 	return res;
5380 }
5381 
5382 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)5383 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5384 		char *command, wl_natoe_cmd_info_t *cmd_info)
5385 {
5386 	int ret = BCME_OK;
5387 	wl_natoe_ioc_t *natoe_ioc;
5388 	char *pcmd = command;
5389 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5390 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5391 	bcm_xtlv_t *pxtlv = NULL;
5392 	char *ioctl_buf = NULL;
5393 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5394 
5395 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5396 	if (!ioctl_buf) {
5397 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5398 		return -ENOMEM;
5399 	}
5400 
5401 	/* alloc mem for ioctl headr + tlv data */
5402 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5403 	if (!natoe_ioc) {
5404 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5405 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5406 		return -ENOMEM;
5407 	}
5408 
5409 	/* make up natoe cmd ioctl header */
5410 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5411 	natoe_ioc->id = htod16(cmd->id);
5412 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5413 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5414 
5415 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5416 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5417 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5418 				WLC_IOCTL_MEDLEN, cmd_info);
5419 		if (ret != BCME_OK) {
5420 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
5421 			ret = -EINVAL;
5422 		}
5423 	} else {	/* set */
5424 		uint8 val = bcm_atoi(pcmd);
5425 
5426 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5427 		/* save buflen at start */
5428 		uint16 buflen_at_start = buflen;
5429 
5430 		/* we'll adjust final ioc size at the end */
5431 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5432 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5433 
5434 		if (ret != BCME_OK) {
5435 			ret = -EINVAL;
5436 			goto exit;
5437 		}
5438 
5439 		/* adjust iocsz to the end of last data record */
5440 		natoe_ioc->len = (buflen_at_start - buflen);
5441 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5442 
5443 		ret = wldev_iovar_setbuf(dev, "natoe",
5444 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5445 		if (ret != BCME_OK) {
5446 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5447 			ret = -EINVAL;
5448 		}
5449 	}
5450 
5451 exit:
5452 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5453 	MFREE(cfg->osh, natoe_ioc, iocsz);
5454 
5455 	return ret;
5456 }
5457 
5458 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)5459 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
5460 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5461 {
5462 	int ret = BCME_OK;
5463 	wl_natoe_config_ips_t config_ips;
5464 	wl_natoe_ioc_t *natoe_ioc;
5465 	char *pcmd = command;
5466 	char *str;
5467 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5468 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5469 	bcm_xtlv_t *pxtlv = NULL;
5470 	char *ioctl_buf = NULL;
5471 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5472 
5473 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5474 	if (!ioctl_buf) {
5475 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5476 		return -ENOMEM;
5477 	}
5478 
5479 	/* alloc mem for ioctl headr + tlv data */
5480 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5481 	if (!natoe_ioc) {
5482 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5483 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5484 		return -ENOMEM;
5485 	}
5486 
5487 	/* make up natoe cmd ioctl header */
5488 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5489 	natoe_ioc->id = htod16(cmd->id);
5490 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5491 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5492 
5493 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5494 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5495 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5496 				WLC_IOCTL_MEDLEN, cmd_info);
5497 		if (ret != BCME_OK) {
5498 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
5499 			ret = -EINVAL;
5500 		}
5501 	} else {	/* set */
5502 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5503 		/* save buflen at start */
5504 		uint16 buflen_at_start = buflen;
5505 
5506 		bzero(&config_ips, sizeof(config_ips));
5507 
5508 		str = bcmstrtok(&pcmd, " ", NULL);
5509 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
5510 			ANDROID_ERROR(("Invalid STA IP addr %s\n", str));
5511 			ret = -EINVAL;
5512 			goto exit;
5513 		}
5514 
5515 		str = bcmstrtok(&pcmd, " ", NULL);
5516 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
5517 			ANDROID_ERROR(("Invalid STA netmask %s\n", str));
5518 			ret = -EINVAL;
5519 			goto exit;
5520 		}
5521 
5522 		str = bcmstrtok(&pcmd, " ", NULL);
5523 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
5524 			ANDROID_ERROR(("Invalid STA router IP addr %s\n", str));
5525 			ret = -EINVAL;
5526 			goto exit;
5527 		}
5528 
5529 		str = bcmstrtok(&pcmd, " ", NULL);
5530 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
5531 			ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str));
5532 			ret = -EINVAL;
5533 			goto exit;
5534 		}
5535 
5536 		str = bcmstrtok(&pcmd, " ", NULL);
5537 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
5538 			ANDROID_ERROR(("Invalid AP IP addr %s\n", str));
5539 			ret = -EINVAL;
5540 			goto exit;
5541 		}
5542 
5543 		str = bcmstrtok(&pcmd, " ", NULL);
5544 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
5545 			ANDROID_ERROR(("Invalid AP netmask %s\n", str));
5546 			ret = -EINVAL;
5547 			goto exit;
5548 		}
5549 
5550 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5551 				&buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
5552 				&config_ips, BCM_XTLV_OPTION_ALIGN32);
5553 
5554 		if (ret != BCME_OK) {
5555 			ret = -EINVAL;
5556 			goto exit;
5557 		}
5558 
5559 		/* adjust iocsz to the end of last data record */
5560 		natoe_ioc->len = (buflen_at_start - buflen);
5561 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5562 
5563 		ret = wldev_iovar_setbuf(dev, "natoe",
5564 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5565 		if (ret != BCME_OK) {
5566 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5567 			ret = -EINVAL;
5568 		}
5569 	}
5570 
5571 exit:
5572 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5573 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5574 
5575 	return ret;
5576 }
5577 
5578 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)5579 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
5580 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5581 {
5582 	int ret = BCME_OK;
5583 	wl_natoe_ports_config_t ports_config;
5584 	wl_natoe_ioc_t *natoe_ioc;
5585 	char *pcmd = command;
5586 	char *str;
5587 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5588 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5589 	bcm_xtlv_t *pxtlv = NULL;
5590 	char *ioctl_buf = NULL;
5591 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5592 
5593 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5594 	if (!ioctl_buf) {
5595 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5596 		return -ENOMEM;
5597 	}
5598 
5599 	/* alloc mem for ioctl headr + tlv data */
5600 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5601 	if (!natoe_ioc) {
5602 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5603 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5604 		return -ENOMEM;
5605 	}
5606 
5607 	/* make up natoe cmd ioctl header */
5608 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5609 	natoe_ioc->id = htod16(cmd->id);
5610 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5611 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5612 
5613 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5614 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5615 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5616 				WLC_IOCTL_MEDLEN, cmd_info);
5617 		if (ret != BCME_OK) {
5618 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
5619 			ret = -EINVAL;
5620 		}
5621 	} else {	/* set */
5622 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5623 		/* save buflen at start */
5624 		uint16 buflen_at_start = buflen;
5625 
5626 		bzero(&ports_config, sizeof(ports_config));
5627 
5628 		str = bcmstrtok(&pcmd, " ", NULL);
5629 		if (!str) {
5630 			ANDROID_ERROR(("Invalid port string %s\n", str));
5631 			ret = -EINVAL;
5632 			goto exit;
5633 		}
5634 		ports_config.start_port_num = htod16(bcm_atoi(str));
5635 
5636 		str = bcmstrtok(&pcmd, " ", NULL);
5637 		if (!str) {
5638 			ANDROID_ERROR(("Invalid port string %s\n", str));
5639 			ret = -EINVAL;
5640 			goto exit;
5641 		}
5642 		ports_config.no_of_ports = htod16(bcm_atoi(str));
5643 
5644 		if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
5645 				NATOE_MAX_PORT_NUM) {
5646 			ANDROID_ERROR(("Invalid port configuration\n"));
5647 			ret = -EINVAL;
5648 			goto exit;
5649 		}
5650 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5651 				&buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
5652 				&ports_config, BCM_XTLV_OPTION_ALIGN32);
5653 
5654 		if (ret != BCME_OK) {
5655 			ret = -EINVAL;
5656 			goto exit;
5657 		}
5658 
5659 		/* adjust iocsz to the end of last data record */
5660 		natoe_ioc->len = (buflen_at_start - buflen);
5661 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5662 
5663 		ret = wldev_iovar_setbuf(dev, "natoe",
5664 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5665 		if (ret != BCME_OK) {
5666 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5667 			ret = -EINVAL;
5668 		}
5669 	}
5670 
5671 exit:
5672 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5673 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5674 
5675 	return ret;
5676 }
5677 
5678 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)5679 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5680 		char *command, wl_natoe_cmd_info_t *cmd_info)
5681 {
5682 	int ret = BCME_OK;
5683 	wl_natoe_ioc_t *natoe_ioc;
5684 	char *pcmd = command;
5685 	uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5686 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
5687 	uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
5688 	bcm_xtlv_t *pxtlv = NULL;
5689 	char *ioctl_buf = NULL;
5690 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5691 
5692 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5693 	if (!ioctl_buf) {
5694 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5695 		return -ENOMEM;
5696 	}
5697 
5698 	/* alloc mem for ioctl headr + tlv data */
5699 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5700 	if (!natoe_ioc) {
5701 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5702 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5703 		return -ENOMEM;
5704 	}
5705 
5706 	/* make up natoe cmd ioctl header */
5707 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5708 	natoe_ioc->id = htod16(cmd->id);
5709 	natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
5710 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5711 
5712 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5713 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5714 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5715 				WLC_IOCTL_MAXLEN, cmd_info);
5716 		if (ret != BCME_OK) {
5717 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
5718 			ret = -EINVAL;
5719 		}
5720 	} else {	/* set */
5721 		uint8 val = bcm_atoi(pcmd);
5722 
5723 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5724 		/* save buflen at start */
5725 		uint16 buflen_at_start = buflen;
5726 
5727 		/* we'll adjust final ioc size at the end */
5728 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5729 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5730 
5731 		if (ret != BCME_OK) {
5732 			ret = -EINVAL;
5733 			goto exit;
5734 		}
5735 
5736 		/* adjust iocsz to the end of last data record */
5737 		natoe_ioc->len = (buflen_at_start - buflen);
5738 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5739 
5740 		ret = wldev_iovar_setbuf(dev, "natoe",
5741 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
5742 		if (ret != BCME_OK) {
5743 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5744 			ret = -EINVAL;
5745 		}
5746 	}
5747 
5748 exit:
5749 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5750 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
5751 
5752 	return ret;
5753 }
5754 
5755 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)5756 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5757 		char *command, wl_natoe_cmd_info_t *cmd_info)
5758 {
5759 	int ret = BCME_OK;
5760 	wl_natoe_ioc_t *natoe_ioc;
5761 	char *pcmd = command;
5762 	uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5763 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5764 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5765 	bcm_xtlv_t *pxtlv = NULL;
5766 	char *ioctl_buf = NULL;
5767 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5768 
5769 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5770 	if (!ioctl_buf) {
5771 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5772 		return -ENOMEM;
5773 	}
5774 
5775 	/* alloc mem for ioctl headr + tlv data */
5776 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5777 	if (!natoe_ioc) {
5778 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5779 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5780 		return -ENOMEM;
5781 	}
5782 
5783 	/* make up natoe cmd ioctl header */
5784 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5785 	natoe_ioc->id = htod16(cmd->id);
5786 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5787 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5788 
5789 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5790 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5791 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5792 				WLC_IOCTL_MEDLEN, cmd_info);
5793 		if (ret != BCME_OK) {
5794 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
5795 			ret = -EINVAL;
5796 		}
5797 	} else {	/* set */
5798 		uint32 val = bcm_atoi(pcmd);
5799 
5800 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5801 		/* save buflen at start */
5802 		uint16 buflen_at_start = buflen;
5803 
5804 		/* we'll adjust final ioc size at the end */
5805 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
5806 			sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
5807 
5808 		if (ret != BCME_OK) {
5809 			ret = -EINVAL;
5810 			goto exit;
5811 		}
5812 
5813 		/* adjust iocsz to the end of last data record */
5814 		natoe_ioc->len = (buflen_at_start - buflen);
5815 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5816 
5817 		ret = wldev_iovar_setbuf(dev, "natoe",
5818 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5819 		if (ret != BCME_OK) {
5820 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5821 			ret = -EINVAL;
5822 		}
5823 	}
5824 
5825 exit:
5826 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5827 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5828 
5829 	return ret;
5830 }
5831 
5832 #endif /* WL_NATOE */
5833 
5834 #ifdef WL_MBO
5835 static int
wl_android_process_mbo_cmd(struct net_device * dev,char * command,int total_len)5836 wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len)
5837 {
5838 	int ret = BCME_ERROR;
5839 	char *pcmd = command;
5840 	char *str = NULL;
5841 	wl_drv_cmd_info_t cmd_info;
5842 	const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
5843 
5844 	/* skip to cmd name after "mbo" */
5845 	str = bcmstrtok(&pcmd, " ", NULL);
5846 
5847 	/* If mbo subcmd name is not provided, return error */
5848 	if (*pcmd == '\0') {
5849 		ANDROID_ERROR(("mbo subcmd not provided %s\n", __FUNCTION__));
5850 		ret = -EINVAL;
5851 		return ret;
5852 	}
5853 
5854 	/* get the mbo command name to str */
5855 	str = bcmstrtok(&pcmd, " ", NULL);
5856 
5857 	while (mbo_cmd->name != NULL) {
5858 		if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
5859 			/* dispatch cmd to appropriate handler */
5860 			if (mbo_cmd->handler) {
5861 				cmd_info.command = command;
5862 				cmd_info.tot_len = total_len;
5863 				ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
5864 			}
5865 			return ret;
5866 		}
5867 		mbo_cmd++;
5868 	}
5869 	return ret;
5870 }
5871 
5872 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)5873 wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf,
5874 	uint16 iov_buf_len, uint8 *iov_resp, uint16 iov_resp_len, uint8 sub_elem_type)
5875 {
5876 	int ret = BCME_OK;
5877 	uint8 *pxtlv = NULL;
5878 	uint16 iovlen = 0;
5879 	uint16 buflen = 0, buflen_start = 0;
5880 
5881 	memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
5882 	iov_buf->version = WL_MBO_IOV_VERSION;
5883 	iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
5884 	buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
5885 	pxtlv = (uint8 *)&iov_buf->data[0];
5886 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
5887 		sizeof(sub_elem_type), &sub_elem_type, BCM_XTLV_OPTION_ALIGN32);
5888 	if (ret != BCME_OK) {
5889 		return ret;
5890 	}
5891 	iov_buf->len = buflen_start - buflen;
5892 	iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5893 	ret = wldev_iovar_setbuf(dev, "mbo",
5894 			iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5895 	if (ret != BCME_OK) {
5896 		ANDROID_ERROR(("Fail to sent wnm notif %d\n", ret));
5897 	}
5898 	return ret;
5899 }
5900 
5901 static int
wl_android_mbo_resp_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5902 wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5903 {
5904 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
5905 	uint8 *command = cmd_info->command;
5906 	uint16 total_len = cmd_info->tot_len;
5907 	uint16 bytes_written = 0;
5908 
5909 	UNUSED_PARAMETER(len);
5910 	/* TODO: validate data value */
5911 	if (data == NULL) {
5912 		ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
5913 		return -EINVAL;
5914 	}
5915 	switch (type) {
5916 		case WL_MBO_XTLV_CELL_DATA_CAP:
5917 		{
5918 			bytes_written = snprintf(command, total_len, "cell_data_cap: %u\n", *data);
5919 			cmd_info->bytes_written = bytes_written;
5920 		}
5921 		break;
5922 		default:
5923 			ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
5924 	}
5925 	return BCME_OK;
5926 }
5927 
5928 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)5929 wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd_t *cmd,
5930 		char *command, wl_drv_cmd_info_t *cmd_info)
5931 {
5932 	int ret = BCME_OK;
5933 	uint8 *pxtlv = NULL;
5934 	uint16 buflen = 0, buflen_start = 0;
5935 	uint16 iovlen = 0;
5936 	char *pcmd = command;
5937 	bcm_iov_buf_t *iov_buf = NULL;
5938 	bcm_iov_buf_t *p_resp = NULL;
5939 	uint8 *iov_resp = NULL;
5940 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5941 	uint16 version;
5942 
5943 	/* first get the configured value */
5944 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5945 	if (iov_buf == NULL) {
5946 		ret = -ENOMEM;
5947 		ANDROID_ERROR(("iov buf memory alloc exited\n"));
5948 		goto exit;
5949 	}
5950 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5951 	if (iov_resp == NULL) {
5952 		ret = -ENOMEM;
5953 		ANDROID_ERROR(("iov resp memory alloc exited\n"));
5954 		goto exit;
5955 	}
5956 
5957 	/* fill header */
5958 	iov_buf->version = WL_MBO_IOV_VERSION;
5959 	iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
5960 
5961 	ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
5962 		WLC_IOCTL_MAXLEN,
5963 		NULL);
5964 	if (ret != BCME_OK) {
5965 		goto exit;
5966 	}
5967 	p_resp = (bcm_iov_buf_t *)iov_resp;
5968 
5969 	/* get */
5970 	if (*pcmd == WL_IOCTL_ACTION_GET) {
5971 		/* Check for version */
5972 		version = dtoh16(*(uint16 *)iov_resp);
5973 		if (version != WL_MBO_IOV_VERSION) {
5974 			ret = -EINVAL;
5975 		}
5976 		if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
5977 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
5978 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
5979 				wl_android_mbo_resp_parse_cbfn);
5980 			if (ret == BCME_OK) {
5981 				ret = cmd_info->bytes_written;
5982 			}
5983 		} else {
5984 			ret = -EINVAL;
5985 			ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
5986 			goto exit;
5987 		}
5988 	} else {
5989 		uint8 cell_cap = bcm_atoi(pcmd);
5990 		const uint8* old_cell_cap = NULL;
5991 		uint16 len = 0;
5992 
5993 		old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len,
5994 			WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32);
5995 		if (old_cell_cap && *old_cell_cap == cell_cap) {
5996 			ANDROID_ERROR(("No change is cellular data capability\n"));
5997 			/* No change in value */
5998 			goto exit;
5999 		}
6000 
6001 		buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
6002 
6003 		if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
6004 			cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
6005 			ANDROID_ERROR(("wrong value %u\n", cell_cap));
6006 			ret = -EINVAL;
6007 			goto exit;
6008 		}
6009 		pxtlv = (uint8 *)&iov_buf->data[0];
6010 		ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
6011 			sizeof(cell_cap), &cell_cap, BCM_XTLV_OPTION_ALIGN32);
6012 		if (ret != BCME_OK) {
6013 			goto exit;
6014 		}
6015 		iov_buf->len = buflen_start - buflen;
6016 		iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6017 		ret = wldev_iovar_setbuf(dev, "mbo",
6018 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6019 		if (ret != BCME_OK) {
6020 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6021 			ret = -EINVAL;
6022 			goto exit;
6023 		}
6024 		/* Skip for CUSTOMER_HW4 - WNM notification
6025 		 * for cellular data capability is handled by host
6026 		 */
6027 #if !defined(CUSTOMER_HW4)
6028 		/* send a WNM notification request to associated AP */
6029 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6030 			ANDROID_INFO(("Sending WNM Notif\n"));
6031 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6032 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP);
6033 			if (ret != BCME_OK) {
6034 				ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6035 				ret = -EINVAL;
6036 			}
6037 		}
6038 #endif /* CUSTOMER_HW4 */
6039 	}
6040 exit:
6041 	if (iov_buf) {
6042 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6043 	}
6044 	if (iov_resp) {
6045 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6046 	}
6047 	return ret;
6048 }
6049 
6050 static int
wl_android_mbo_non_pref_chan_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)6051 wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
6052 {
6053 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
6054 	uint8 *command = cmd_info->command + cmd_info->bytes_written;
6055 	uint16 total_len = cmd_info->tot_len;
6056 	uint16 bytes_written = 0;
6057 
6058 	ANDROID_INFO(("Total bytes written at begining %u\n", cmd_info->bytes_written));
6059 	UNUSED_PARAMETER(len);
6060 	if (data == NULL) {
6061 		ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
6062 		return -EINVAL;
6063 	}
6064 	switch (type) {
6065 		case WL_MBO_XTLV_OPCLASS:
6066 		{
6067 			bytes_written = snprintf(command, total_len, "%u:", *data);
6068 			ANDROID_ERROR(("wr %u %u\n", bytes_written, *data));
6069 			command += bytes_written;
6070 			cmd_info->bytes_written += bytes_written;
6071 		}
6072 		break;
6073 		case WL_MBO_XTLV_CHAN:
6074 		{
6075 			bytes_written = snprintf(command, total_len, "%u:", *data);
6076 			ANDROID_ERROR(("wr %u\n", bytes_written));
6077 			command += bytes_written;
6078 			cmd_info->bytes_written += bytes_written;
6079 		}
6080 		break;
6081 		case WL_MBO_XTLV_PREFERENCE:
6082 		{
6083 			bytes_written = snprintf(command, total_len, "%u:", *data);
6084 			ANDROID_ERROR(("wr %u\n", bytes_written));
6085 			command += bytes_written;
6086 			cmd_info->bytes_written += bytes_written;
6087 		}
6088 		break;
6089 		case WL_MBO_XTLV_REASON_CODE:
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 		default:
6098 			ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
6099 	}
6100 	ANDROID_INFO(("Total bytes written %u\n", cmd_info->bytes_written));
6101 	return BCME_OK;
6102 }
6103 
6104 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)6105 wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
6106 		const wl_drv_sub_cmd_t *cmd, char *command,
6107 		wl_drv_cmd_info_t *cmd_info)
6108 {
6109 	int ret = BCME_OK;
6110 	uint8 *pxtlv = NULL;
6111 	uint16 buflen = 0, buflen_start = 0;
6112 	uint16 iovlen = 0;
6113 	char *pcmd = command;
6114 	bcm_iov_buf_t *iov_buf = NULL;
6115 	bcm_iov_buf_t *p_resp = NULL;
6116 	uint8 *iov_resp = NULL;
6117 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6118 	uint16 version;
6119 
6120 	ANDROID_ERROR(("%s:%d\n", __FUNCTION__, __LINE__));
6121 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
6122 	if (iov_buf == NULL) {
6123 		ret = -ENOMEM;
6124 		ANDROID_ERROR(("iov buf memory alloc exited\n"));
6125 		goto exit;
6126 	}
6127 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6128 	if (iov_resp == NULL) {
6129 		ret = -ENOMEM;
6130 		ANDROID_ERROR(("iov resp memory alloc exited\n"));
6131 		goto exit;
6132 	}
6133 	/* get */
6134 	if (*pcmd == WL_IOCTL_ACTION_GET) {
6135 		/* fill header */
6136 		iov_buf->version = WL_MBO_IOV_VERSION;
6137 		iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
6138 
6139 		ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
6140 				WLC_IOCTL_MAXLEN, NULL);
6141 		if (ret != BCME_OK) {
6142 			goto exit;
6143 		}
6144 		p_resp = (bcm_iov_buf_t *)iov_resp;
6145 		/* Check for version */
6146 		version = dtoh16(*(uint16 *)iov_resp);
6147 		if (version != WL_MBO_IOV_VERSION) {
6148 			ANDROID_ERROR(("Version mismatch. returned ver %u expected %u\n",
6149 				version, WL_MBO_IOV_VERSION));
6150 			ret = -EINVAL;
6151 		}
6152 		if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
6153 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
6154 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
6155 				wl_android_mbo_non_pref_chan_parse_cbfn);
6156 			if (ret == BCME_OK) {
6157 				ret = cmd_info->bytes_written;
6158 			}
6159 		} else {
6160 			ret = -EINVAL;
6161 			ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
6162 			goto exit;
6163 		}
6164 	} else {
6165 		char *str = pcmd;
6166 		uint opcl = 0, ch = 0, pref = 0, rc = 0;
6167 
6168 		str = bcmstrtok(&pcmd, " ", NULL);
6169 		if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) {
6170 			/* delete all configurations */
6171 			iov_buf->version = WL_MBO_IOV_VERSION;
6172 			iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
6173 			iov_buf->len = 0;
6174 			iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6175 			ret = wldev_iovar_setbuf(dev, "mbo",
6176 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6177 			if (ret != BCME_OK) {
6178 				ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6179 				ret = -EINVAL;
6180 				goto exit;
6181 			}
6182 		} else {
6183 			ANDROID_ERROR(("Unknown command %s\n", str));
6184 			goto exit;
6185 		}
6186 		/* parse non pref channel list */
6187 		if (strnicmp(str, "set", 3) == 0) {
6188 			uint8 cnt = 0;
6189 			str = bcmstrtok(&pcmd, " ", NULL);
6190 			while (str != NULL) {
6191 				ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
6192 				ANDROID_ERROR(("buflen %u op %u, ch %u, pref %u rc %u\n",
6193 					buflen, opcl, ch, pref, rc));
6194 				if (ret != 4) {
6195 					ANDROID_ERROR(("Not all parameter presents\n"));
6196 					ret = -EINVAL;
6197 				}
6198 				/* TODO: add a validation check here */
6199 				memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
6200 				buflen = buflen_start = WLC_IOCTL_MEDLEN;
6201 				pxtlv = (uint8 *)&iov_buf->data[0];
6202 				/* opclass */
6203 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
6204 					sizeof(uint8), (uint8 *)&opcl, BCM_XTLV_OPTION_ALIGN32);
6205 				if (ret != BCME_OK) {
6206 					goto exit;
6207 				}
6208 				/* channel */
6209 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
6210 					sizeof(uint8), (uint8 *)&ch, BCM_XTLV_OPTION_ALIGN32);
6211 				if (ret != BCME_OK) {
6212 					goto exit;
6213 				}
6214 				/* preference */
6215 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
6216 					sizeof(uint8), (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
6217 				if (ret != BCME_OK) {
6218 					goto exit;
6219 				}
6220 				/* reason */
6221 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
6222 					sizeof(uint8), (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
6223 				if (ret != BCME_OK) {
6224 					goto exit;
6225 				}
6226 				ANDROID_ERROR(("len %u\n", (buflen_start - buflen)));
6227 				/* Now set the new non pref channels */
6228 				iov_buf->version = WL_MBO_IOV_VERSION;
6229 				iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
6230 				iov_buf->len = buflen_start - buflen;
6231 				iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6232 				ret = wldev_iovar_setbuf(dev, "mbo",
6233 					iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL);
6234 				if (ret != BCME_OK) {
6235 					ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6236 					ret = -EINVAL;
6237 					goto exit;
6238 				}
6239 				cnt++;
6240 				if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
6241 					break;
6242 				}
6243 				ANDROID_ERROR(("%d cnt %u\n", __LINE__, cnt));
6244 				str = bcmstrtok(&pcmd, " ", NULL);
6245 			}
6246 		}
6247 		/* send a WNM notification request to associated AP */
6248 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6249 			ANDROID_INFO(("Sending WNM Notif\n"));
6250 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6251 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT);
6252 			if (ret != BCME_OK) {
6253 				ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6254 				ret = -EINVAL;
6255 			}
6256 		}
6257 	}
6258 exit:
6259 	if (iov_buf) {
6260 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6261 	}
6262 	if (iov_resp) {
6263 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6264 	}
6265 	return ret;
6266 }
6267 #endif /* WL_MBO */
6268 
6269 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6270 #ifdef SUPPORT_AMPDU_MPDU_CMD
6271 /* CMD_AMPDU_MPDU */
6272 static int
wl_android_set_ampdu_mpdu(struct net_device * dev,const char * string_num)6273 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
6274 {
6275 	int err = 0;
6276 	int ampdu_mpdu;
6277 
6278 	ampdu_mpdu = bcm_atoi(string_num);
6279 
6280 	if (ampdu_mpdu > 32) {
6281 		ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n"));
6282 		return -1;
6283 	}
6284 
6285 	ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu));
6286 	err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
6287 	if (err < 0) {
6288 		ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err));
6289 		return -1;
6290 	}
6291 
6292 	return 0;
6293 }
6294 #endif /* SUPPORT_AMPDU_MPDU_CMD */
6295 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
6296 
6297 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6298 extern int wl_cfg80211_send_msg_to_ril(void);
6299 extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
6300 extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
6301 extern int g_mhs_chan_for_cpcoex;
6302 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6303 
6304 #if defined (WL_SUPPORT_AUTO_CHANNEL)
6305 static s32
wl_android_set_auto_channel_scan_state(struct net_device * ndev)6306 wl_android_set_auto_channel_scan_state(struct net_device *ndev)
6307 {
6308 	u32 val = 0;
6309 	s32 ret = BCME_ERROR;
6310 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6311 	/* Set interface up, explicitly. */
6312 	val = 1;
6313 
6314 	ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
6315 	if (ret < 0) {
6316 		ANDROID_ERROR(("set interface up failed, error = %d\n", ret));
6317 		goto done;
6318 	}
6319 
6320 	/* Stop all scan explicitly, till auto channel selection complete. */
6321 	wl_set_drv_status(cfg, SCANNING, ndev);
6322 	if (cfg->escan_info.ndev == NULL) {
6323 		ret = BCME_OK;
6324 		goto done;
6325 	}
6326 
6327 	wl_cfgscan_cancel_scan(cfg);
6328 
6329 done:
6330 	return ret;
6331 }
6332 
6333 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)6334 wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *list,
6335 	s32 buflen, const char* cmd_str, int sta_channel, chanspec_band_t sta_acs_band)
6336 {
6337 	u32 freq = 0;
6338 	chanspec_t chanspec = 0;
6339 	s32 ret = BCME_OK;
6340 	int i = 0;
6341 	char *pcmd, *token;
6342 	int len = buflen;
6343 
6344 	pcmd = bcmstrstr(cmd_str, FREQ_STR);
6345 	pcmd += strlen(FREQ_STR);
6346 
6347 	len -= sizeof(list->count);
6348 
6349 	while ((token = strsep(&pcmd, ",")) != NULL) {
6350 		if (*token == '\0')
6351 			continue;
6352 
6353 		if (len < sizeof(list->element[i]))
6354 			break;
6355 
6356 		freq = bcm_atoi(token);
6357 		/* Convert chanspec from frequency */
6358 		if ((freq > 0) &&
6359 			((chanspec = wl_freq_to_chanspec(freq)) != INVCHANSPEC)) {
6360 			ANDROID_INFO(("Adding chanspec in list : 0x%x at the index %d\n", chanspec, i));
6361 			list->element[i] = chanspec;
6362 			len -= sizeof(list->element[i]);
6363 			i++;
6364 #ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN
6365 			/* Android includes 2g channels even for 5g band configuration. For
6366 			 * customers using only single channel 5G AP, set the channel and
6367 			 * return without doing ACS
6368 			 */
6369 			if (CHSPEC_BAND(chanspec) == WL_CHANSPEC_BAND_5G) {
6370 				ANDROID_INFO(("Pick default channnel from 5g\n"));
6371 				if (!sta_channel) {
6372 					list->element[0] = chanspec;
6373 					list->count = 1;
6374 					return ret;
6375 				}
6376 				break;
6377 			}
6378 #endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */
6379 		}
6380 	}
6381 
6382 	list->count = i;
6383 	/* valid chanspec present in the list */
6384 	if (list->count && sta_channel) {
6385 		/* STA associated case. Can't do ACS.
6386 		* Frequency list is order of lower to higher band.
6387 		* check with the highest band entry.
6388 		*/
6389 		chanspec = list->element[i-1];
6390 		if (CHSPEC_BAND(chanspec) == sta_acs_band) {
6391 			/* softap request is for same band. Use SCC
6392 			 * Convert sta channel to freq
6393 			 */
6394 			freq = wl_channel_to_frequency(sta_channel, sta_acs_band);
6395 			list->element[0] =
6396 				wl_freq_to_chanspec(freq);
6397 			ANDROID_INFO(("Softap on same band as STA."
6398 				"Use SCC. chanspec:0x%x\n", chanspec));
6399 		} else {
6400 			list->element[0] = chanspec;
6401 			ANDROID_INFO(("RSDB case chanspec:0x%x\n", chanspec));
6402 		}
6403 		list->count = 1;
6404 		return ret;
6405 	}
6406 	return ret;
6407 }
6408 
6409 s32
wl_android_get_band_chanspecs(struct net_device * ndev,void * buf,s32 buflen,chanspec_band_t band,bool acs_req)6410 wl_android_get_band_chanspecs(struct net_device *ndev, void *buf, s32 buflen,
6411 	chanspec_band_t band, bool acs_req)
6412 {
6413 	u32 channel = 0;
6414 	s32 ret = BCME_ERROR;
6415 	s32 i = 0;
6416 	s32 j = 0;
6417 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6418 	wl_uint32_list_t *list = NULL;
6419 	chanspec_t chanspec = 0;
6420 
6421 	if (band != 0xff) {
6422 		chanspec |= (band | WL_CHANSPEC_BW_20 |
6423 			WL_CHANSPEC_CTL_SB_NONE);
6424 		chanspec = wl_chspec_host_to_driver(chanspec);
6425 	}
6426 
6427 	ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
6428 		sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
6429 	if (ret < 0) {
6430 		ANDROID_ERROR(("get 'chanspecs' failed, error = %d\n", ret));
6431 		goto done;
6432 	}
6433 
6434 	list = (wl_uint32_list_t *)buf;
6435 	/* Skip DFS and inavlid P2P channel. */
6436 	for (i = 0, j = 0; i < dtoh32(list->count); i++) {
6437 		if (!CHSPEC_IS20(list->element[i])) {
6438 			continue;
6439 		}
6440 		chanspec = (chanspec_t) dtoh32(list->element[i]);
6441 		channel = chanspec | WL_CHANSPEC_BW_20;
6442 		channel = wl_chspec_host_to_driver(channel);
6443 
6444 		ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
6445 		if (ret < 0) {
6446 			ANDROID_ERROR(("get 'per_chan_info' failed, error = %d\n", ret));
6447 			goto done;
6448 		}
6449 
6450 		if (CHSPEC_IS5G(chanspec) && (CHANNEL_IS_RADAR(channel) ||
6451 #ifndef ALLOW_5G_ACS
6452 			((acs_req == true) && (CHSPEC_CHANNEL(chanspec) != APCS_DEFAULT_5G_CH)) ||
6453 #endif /* !ALLOW_5G_ACS */
6454 			(0))) {
6455 			continue;
6456 		} else if (!(CHSPEC_IS2G(chanspec) || CHSPEC_IS5G(chanspec)) &&
6457 			!(CHSPEC_IS_6G_PSC(chanspec))) {
6458 			continue;
6459 		}
6460 		else {
6461 			list->element[j] = list->element[i];
6462 			ANDROID_INFO(("Adding chanspec in list : %x\n", list->element[j]));
6463 		}
6464 
6465 		j++;
6466 	}
6467 
6468 	list->count = j;
6469 
6470 done:
6471 	return ret;
6472 }
6473 
6474 static s32
wl_android_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)6475 wl_android_get_best_channel(struct net_device *ndev, void *buf, int buflen,
6476 	int *channel)
6477 {
6478 	s32 ret = BCME_ERROR;
6479 	int chosen = 0;
6480 	int retry = 0;
6481 
6482 	/* Start auto channel selection scan. */
6483 	ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0);
6484 	if (ret < 0) {
6485 		ANDROID_ERROR(("can't start auto channel scan, error = %d\n", ret));
6486 		*channel = 0;
6487 		goto done;
6488 	}
6489 
6490 	/* Wait for auto channel selection, worst case possible delay is 5250ms. */
6491 	retry = CHAN_SEL_RETRY_COUNT;
6492 
6493 	while (retry--) {
6494 		OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
6495 		chosen = 0;
6496 		ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6497 		if ((ret == 0) && (dtoh32(chosen) != 0)) {
6498 			*channel = (u16)(chosen & 0x00FF);
6499 			ANDROID_INFO(("selected channel = %d\n", *channel));
6500 			break;
6501 		}
6502 		ANDROID_INFO(("attempt = %d, ret = %d, chosen = %d\n",
6503 			(CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
6504 	}
6505 
6506 	if (retry <= 0)	{
6507 		ANDROID_ERROR(("failure, auto channel selection timed out\n"));
6508 		*channel = 0;
6509 		ret = BCME_ERROR;
6510 	}
6511 
6512 done:
6513 	return ret;
6514 }
6515 
6516 static s32
wl_android_restore_auto_channel_scan_state(struct net_device * ndev)6517 wl_android_restore_auto_channel_scan_state(struct net_device *ndev)
6518 {
6519 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6520 	/* Clear scan stop driver status. */
6521 	wl_clr_drv_status(cfg, SCANNING, ndev);
6522 
6523 	return BCME_OK;
6524 }
6525 
6526 s32
wl_android_get_best_channels(struct net_device * dev,char * cmd,int total_len)6527 wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len)
6528 {
6529 	int channel = 0;
6530 	s32 ret = BCME_ERROR;
6531 	u8 *buf = NULL;
6532 	char *pos = cmd;
6533 	struct bcm_cfg80211 *cfg = NULL;
6534 	struct net_device *ndev = NULL;
6535 
6536 	bzero(cmd, total_len);
6537 	cfg = wl_get_cfg(dev);
6538 
6539 	buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
6540 	if (buf == NULL) {
6541 		ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6542 		return -ENOMEM;
6543 	}
6544 
6545 	/*
6546 	 * Always use primary interface, irrespective of interface on which
6547 	 * command came.
6548 	 */
6549 	ndev = bcmcfg_to_prmry_ndev(cfg);
6550 
6551 	/*
6552 	 * Make sure that FW and driver are in right state to do auto channel
6553 	 * selection scan.
6554 	 */
6555 	ret = wl_android_set_auto_channel_scan_state(ndev);
6556 	if (ret < 0) {
6557 		ANDROID_ERROR(("can't set auto channel scan state, error = %d\n", ret));
6558 		goto done;
6559 	}
6560 
6561 	/* Best channel selection in 2.4GHz band. */
6562 	ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6563 		WL_CHANSPEC_BAND_2G, false);
6564 	if (ret < 0) {
6565 		ANDROID_ERROR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
6566 		goto done;
6567 	}
6568 
6569 	ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6570 		&channel);
6571 	if (ret < 0) {
6572 		ANDROID_ERROR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
6573 		goto done;
6574 	}
6575 
6576 	if (CHANNEL_IS_2G(channel)) {
6577 		channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
6578 	} else {
6579 		ANDROID_ERROR(("invalid 2.4GHz channel, channel = %d\n", channel));
6580 		channel = 0;
6581 	}
6582 
6583 	pos += snprintf(pos, total_len, "%04d ", channel);
6584 
6585 	/* Best channel selection in 5GHz band. */
6586 	ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6587 		WL_CHANSPEC_BAND_5G, false);
6588 	if (ret < 0) {
6589 		ANDROID_ERROR(("can't get chanspecs in 5GHz, error = %d\n", ret));
6590 		goto done;
6591 	}
6592 
6593 	ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6594 		&channel);
6595 	if (ret < 0) {
6596 		ANDROID_ERROR(("can't select best channel scan in 5GHz, error = %d\n", ret));
6597 		goto done;
6598 	}
6599 
6600 	if (CHANNEL_IS_5G(channel)) {
6601 		channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
6602 	} else {
6603 		ANDROID_ERROR(("invalid 5GHz channel, channel = %d\n", channel));
6604 		channel = 0;
6605 	}
6606 
6607 	pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6608 
6609 	/* Set overall best channel same as 5GHz best channel. */
6610 	pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6611 
6612 done:
6613 	if (NULL != buf) {
6614 		MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
6615 	}
6616 
6617 	/* Restore FW and driver back to normal state. */
6618 	ret = wl_android_restore_auto_channel_scan_state(ndev);
6619 	if (ret < 0) {
6620 		ANDROID_ERROR(("can't restore auto channel scan state, error = %d\n", ret));
6621 	}
6622 
6623 	return (pos - cmd);
6624 }
6625 
6626 int
wl_android_set_spect(struct net_device * dev,int spect)6627 wl_android_set_spect(struct net_device *dev, int spect)
6628 {
6629 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6630 	int wlc_down = 1;
6631 	int wlc_up = 1;
6632 	int err = BCME_OK;
6633 
6634 	if (!wl_get_drv_status_all(cfg, CONNECTED)) {
6635 		err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
6636 		if (err) {
6637 			ANDROID_ERROR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
6638 			return err;
6639 		}
6640 
6641 		err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
6642 		if (err) {
6643 			ANDROID_ERROR(("%s: error setting spect: code: %d\n", __func__, err));
6644 			return err;
6645 		}
6646 
6647 		err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
6648 		if (err) {
6649 			ANDROID_ERROR(("%s: WLC_UP failed: code: %d\n", __func__, err));
6650 			return err;
6651 		}
6652 	}
6653 	return err;
6654 }
6655 
6656 static int
wl_android_get_sta_channel(struct bcm_cfg80211 * cfg)6657 wl_android_get_sta_channel(struct bcm_cfg80211 *cfg)
6658 {
6659 	chanspec_t *sta_chanspec = NULL;
6660 	u32 channel = 0;
6661 
6662 	if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
6663 		if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
6664 			bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) {
6665 			channel = wf_chspec_ctlchan(*sta_chanspec);
6666 		}
6667 	}
6668 	return channel;
6669 }
6670 
6671 static int
wl_cfg80211_get_acs_band(int band)6672 wl_cfg80211_get_acs_band(int band)
6673 {
6674 	chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6675 	switch (band) {
6676 		case WLC_BAND_AUTO:
6677 			ANDROID_INFO(("ACS full channel scan \n"));
6678 			/* Restricting band to 2G in case of hw_mode any */
6679 			acs_band = WL_CHANSPEC_BAND_2G;
6680 			break;
6681 #ifdef WL_6G_BAND
6682 		case WLC_BAND_6G:
6683 			ANDROID_INFO(("ACS 6G band scan \n"));
6684 			acs_band = WL_CHANSPEC_BAND_6G;
6685 			break;
6686 #endif /* WL_6G_BAND */
6687 		case WLC_BAND_5G:
6688 			ANDROID_INFO(("ACS 5G band scan \n"));
6689 			acs_band = WL_CHANSPEC_BAND_5G;
6690 			break;
6691 		case WLC_BAND_2G:
6692 			/*
6693 			 * If channel argument is not provided/ argument 20 is provided,
6694 			 * Restrict channel to 2GHz, 20MHz BW, No SB
6695 			 */
6696 			ANDROID_INFO(("ACS 2G band scan \n"));
6697 			acs_band = WL_CHANSPEC_BAND_2G;
6698 			break;
6699 		default:
6700 			ANDROID_ERROR(("ACS: No band chosen\n"));
6701 			break;
6702 	}
6703 	ANDROID_INFO(("%s: ACS: band = %d, acs_band = 0x%x\n", __FUNCTION__, band, acs_band));
6704 	return acs_band;
6705 }
6706 
6707 /* SoftAP feature */
6708 static int
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)6709 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
6710 	char* command, int total_len)
6711 {
6712 	int channel = 0, sta_channel = 0;
6713 	int chosen = 0;
6714 	int retry = 0;
6715 	int ret = 0;
6716 	int spect = 0;
6717 	u8 *reqbuf = NULL;
6718 	uint32 band = WLC_BAND_INVALID, sta_band = WLC_BAND_INVALID;
6719 	chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6720 	uint32 buf_size;
6721 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6722 	bool acs_freq_list_present = false;
6723 	char *pcmd;
6724 
6725 	if (cmd_str) {
6726 		ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
6727 		pcmd = bcmstrstr(cmd_str, FREQ_STR);
6728 		if (pcmd) {
6729 			acs_freq_list_present = true;
6730 			ANDROID_INFO(("ACS has freq list\n"));
6731 		} else if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
6732 			band = WLC_BAND_AUTO;
6733 #ifdef WL_6G_BAND
6734 		} else if (strnicmp(cmd_str, APCS_BAND_6G, strlen(APCS_BAND_6G)) == 0) {
6735 			band = WLC_BAND_6G;
6736 #endif /* WL_6G_BAND */
6737 		} else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
6738 			band = WLC_BAND_5G;
6739 		} else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
6740 			band = WLC_BAND_2G;
6741 		} else {
6742 			/*
6743 			 * For backward compatibility: Some platforms used to issue argument 20 or 0
6744 			 * to enforce the 2G channel selection
6745 			 */
6746 			channel = bcm_atoi(cmd_str);
6747 			if ((channel == APCS_BAND_2G_LEGACY1) ||
6748 				(channel == APCS_BAND_2G_LEGACY2)) {
6749 				band = WLC_BAND_2G;
6750 			} else {
6751 				ANDROID_ERROR(("Invalid argument\n"));
6752 				return -EINVAL;
6753 			}
6754 		}
6755 	} else {
6756 		/* If no argument is provided, default to 2G */
6757 		ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
6758 		band = WLC_BAND_2G;
6759 	}
6760 	ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
6761 
6762 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6763 	wl_cfg80211_register_dev_ril_bridge_event_notifier();
6764 	if (band == WLC_BAND_2G) {
6765 		wl_cfg80211_send_msg_to_ril();
6766 
6767 		if (g_mhs_chan_for_cpcoex) {
6768 			channel = g_mhs_chan_for_cpcoex;
6769 			g_mhs_chan_for_cpcoex = 0;
6770 			goto done2;
6771 		}
6772 	}
6773 	wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
6774 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6775 
6776 	/* If STA is connected, return is STA channel, else ACS can be issued,
6777 	 * set spect to 0 and proceed with ACS
6778 	 */
6779 	sta_channel = wl_android_get_sta_channel(cfg);
6780 	sta_band = WL_GET_BAND(sta_channel);
6781 	if (sta_channel && (band != WLC_BAND_INVALID)) {
6782 		switch (sta_band) {
6783 			case (WLC_BAND_5G):
6784 #ifdef WL_6G_BAND
6785 			case (WLC_BAND_6G):
6786 #endif /* WL_6G_BAND */
6787 			{
6788 				if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
6789 					channel = APCS_DEFAULT_2G_CH;
6790 				} else if (band == WLC_BAND_5G) {
6791 					channel = sta_channel;
6792 				}
6793 				break;
6794 			}
6795 			case (WLC_BAND_2G): {
6796 				if (band == WLC_BAND_5G) {
6797 					channel = APCS_DEFAULT_5G_CH;
6798 				} else if (band == WLC_BAND_2G) {
6799 					channel = sta_channel;
6800 				}
6801 #ifdef WL_6G_BAND
6802 				else if (band == WLC_BAND_6G) {
6803 					channel = APCS_DEFAULT_6G_CH;
6804 				}
6805 #endif /* WL_6G_BAND */
6806 				break;
6807 			}
6808 			default:
6809 				/* Intentional fall through to use same sta channel for softap */
6810 				channel = sta_channel;
6811 				break;
6812 		}
6813 		WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel);
6814 		goto done2;
6815 	}
6816 
6817 	/* If AP is started on wlan0 iface,
6818 	 * do not issue any iovar to fw and choose default ACS channel for softap
6819 	 */
6820 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6821 		if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
6822 			ANDROID_INFO(("Softap started on primary iface\n"));
6823 			goto done;
6824 		}
6825 	}
6826 
6827 	channel = wl_ext_autochannel(dev, ACS_DRV_BIT, band);
6828 	if (channel) {
6829 		acs_band = CHSPEC_BAND(channel);
6830 		goto done2;
6831 	} else
6832 		goto done;
6833 
6834 	ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
6835 	if (ret) {
6836 		ANDROID_ERROR(("ACS: error getting the spect, ret=%d\n", ret));
6837 		goto done;
6838 	}
6839 
6840 	if (spect > 0) {
6841 		ret = wl_android_set_spect(dev, 0);
6842 		if (ret < 0) {
6843 			ANDROID_ERROR(("ACS: error while setting spect, ret=%d\n", ret));
6844 			goto done;
6845 		}
6846 	}
6847 
6848 	reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
6849 	if (reqbuf == NULL) {
6850 		ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6851 		return -ENOMEM;
6852 	}
6853 
6854 	if (acs_freq_list_present) {
6855 		wl_uint32_list_t *list = NULL;
6856 		bzero(reqbuf, sizeof(*reqbuf));
6857 		list = (wl_uint32_list_t *)reqbuf;
6858 
6859 		ret = wl_android_get_freq_list_chanspecs(dev, list, CHANSPEC_BUF_SIZE,
6860 			cmd_str, sta_channel, wl_cfg80211_get_acs_band(sta_band));
6861 		if (ret < 0) {
6862 			ANDROID_ERROR(("ACS chanspec set failed!\n"));
6863 			goto done;
6864 		}
6865 
6866 		/* skip ACS for single channel case */
6867 		if (list->count == 1) {
6868 			cfg->acs_chspec = (chanspec_t)list->element[0];
6869 			channel = wf_chspec_ctlchan((chanspec_t)list->element[0]);
6870 			acs_band = CHSPEC_BAND((chanspec_t)list->element[0]);
6871 			goto done2;
6872 		}
6873 	} else {
6874 		acs_band = wl_cfg80211_get_acs_band(band);
6875 		if (acs_band == WLC_ACS_BAND_INVALID) {
6876 			ANDROID_ERROR(("ACS: No band chosen\n"));
6877 			goto done2;
6878 		}
6879 
6880 		if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE,
6881 			acs_band, true)) < 0) {
6882 			ANDROID_ERROR(("ACS chanspec retrieval failed! \n"));
6883 			goto done;
6884 		}
6885 	}
6886 
6887 	buf_size = CHANSPEC_BUF_SIZE;
6888 	ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
6889 		buf_size);
6890 	if (ret < 0) {
6891 		ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
6892 		channel = 0;
6893 		goto done;
6894 	}
6895 
6896 	/* Wait for auto channel selection, max 3000 ms */
6897 	if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) {
6898 		OSL_SLEEP(500);
6899 	} else {
6900 		/*
6901 		 * Full channel scan at the minimum takes 1.2secs
6902 		 * even with parallel scan. max wait time: 3500ms
6903 		 */
6904 		OSL_SLEEP(1000);
6905 	}
6906 
6907 	retry = APCS_MAX_RETRY;
6908 	while (retry--) {
6909 		ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
6910 			sizeof(chosen));
6911 		if (ret < 0) {
6912 			chosen = 0;
6913 		} else {
6914 			chosen = dtoh32(chosen);
6915 		}
6916 
6917 		if (chosen) {
6918 			/* Update chanspec which can be used during softAP bringup with right BW */
6919 			cfg->acs_chspec = chosen;
6920 			channel = wf_chspec_ctlchan(chosen);
6921 			acs_band = CHSPEC_BAND(chosen);
6922 			break;
6923 		}
6924 		ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x, acs_band = 0x%x\n",
6925 			(APCS_MAX_RETRY - retry), ret, chosen, acs_band));
6926 		OSL_SLEEP(250);
6927 	}
6928 
6929 done:
6930 	if ((retry == 0) || (ret < 0)) {
6931 		/* On failure, fallback to a default channel */
6932 		if (band == WLC_BAND_5G) {
6933 			channel = APCS_DEFAULT_5G_CH;
6934 #ifdef WL_6G_BAND
6935 		} else if (band == WLC_BAND_6G) {
6936 			channel = APCS_DEFAULT_6G_CH;
6937 #endif /* WL_6G_BAND */
6938 		} else {
6939 			channel = APCS_DEFAULT_2G_CH;
6940 		}
6941 		ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel));
6942 	}
6943 done2:
6944 	if (spect > 0) {
6945 		if ((ret = wl_android_set_spect(dev, spect) < 0)) {
6946 			ANDROID_ERROR(("ACS: error while setting spect\n"));
6947 		}
6948 	}
6949 
6950 	if (reqbuf) {
6951 		MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
6952 	}
6953 
6954 	if (channel) {
6955 		ret = snprintf(command, total_len, "%d", channel);
6956 		ANDROID_INFO(("command result is %s \n", command));
6957 	}
6958 
6959 	return ret;
6960 }
6961 #endif /* WL_SUPPORT_AUTO_CHANNEL */
6962 
6963 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6964 static int
wl_android_set_roam_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)6965 wl_android_set_roam_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
6966 {
6967 	s32 err = BCME_OK;
6968 	u32 roam_vsie_enable = 0;
6969 	u32 cmd_str_len = (u32)strlen(CMD_ROAM_VSIE_ENAB_SET);
6970 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6971 
6972 	/* <CMD><SPACE><VAL> */
6973 	if (!cmd || (cmd_len < (cmd_str_len + 1))) {
6974 		ANDROID_ERROR(("wrong arg\n"));
6975 		err = -EINVAL;
6976 		goto exit;
6977 	}
6978 
6979 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6980 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
6981 		err = -ENODEV;
6982 		goto exit;
6983 	}
6984 
6985 	roam_vsie_enable = cmd[(cmd_str_len + 1)] - '0';
6986 	if (roam_vsie_enable > 1) {
6987 		roam_vsie_enable = 1;
6988 	}
6989 
6990 	WL_DBG_MEM(("set roam vsie %d\n", roam_vsie_enable));
6991 	err = wldev_iovar_setint(dev, "roam_vsie", roam_vsie_enable);
6992 	if (unlikely(err)) {
6993 		ANDROID_ERROR(("set roam vsie enable failed. ret:%d\n", err));
6994 	}
6995 
6996 exit:
6997 	return err;
6998 }
6999 
7000 static int
wl_android_get_roam_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7001 wl_android_get_roam_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7002 {
7003 	s32 err = BCME_OK;
7004 	u32 roam_vsie_enable = 0;
7005 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7006 	int bytes_written;
7007 
7008 	/* <CMD> */
7009 	if (!cmd) {
7010 		ANDROID_ERROR(("wrong arg\n"));
7011 		return -1;
7012 	}
7013 
7014 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7015 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7016 		return -1;
7017 	}
7018 
7019 	err = wldev_iovar_getint(dev, "roam_vsie", &roam_vsie_enable);
7020 	if (unlikely(err)) {
7021 		ANDROID_ERROR(("get roam vsie enable failed. ret:%d\n", err));
7022 		return -1;
7023 	}
7024 	ANDROID_INFO(("get roam vsie %d\n", roam_vsie_enable));
7025 
7026 	bytes_written = snprintf(cmd, cmd_len, "%s %d",
7027 		CMD_ROAM_VSIE_ENAB_GET, roam_vsie_enable);
7028 
7029 	return bytes_written;
7030 }
7031 
7032 static int
wl_android_set_bcn_rpt_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)7033 wl_android_set_bcn_rpt_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
7034 {
7035 	s32 err;
7036 	u32 bcn_vsie_enable = 0;
7037 	u32 cmd_str_len = (u32)strlen(CMD_BR_VSIE_ENAB_SET);
7038 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7039 
7040 	/* <CMD><SPACE><VAL> */
7041 	if (!cmd || (cmd_len < (cmd_str_len + 1))) {
7042 		ANDROID_ERROR(("invalid arg\n"));
7043 		err = -EINVAL;
7044 		goto exit;
7045 	}
7046 
7047 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7048 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7049 		err = -ENODEV;
7050 		goto exit;
7051 	}
7052 
7053 	bcn_vsie_enable = cmd[cmd_str_len + 1] - '0';
7054 	if (bcn_vsie_enable > 1) {
7055 		bcn_vsie_enable = 1;
7056 	}
7057 
7058 	WL_DBG_MEM(("set bcn report vsie %d\n", bcn_vsie_enable));
7059 	err = wldev_iovar_setint(dev, "bcnrpt_vsie_en", bcn_vsie_enable);
7060 	if (unlikely(err)) {
7061 		ANDROID_ERROR(("set bcn vsie failed. ret:%d\n", err));
7062 	}
7063 
7064 exit:
7065 	return err;
7066 }
7067 
7068 static int
wl_android_get_bcn_rpt_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7069 wl_android_get_bcn_rpt_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7070 {
7071 	s32 err = BCME_OK;
7072 	u32 bcn_vsie_enable = 0;
7073 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7074 	int bytes_written;
7075 
7076 	/* <CMD> */
7077 	if (!cmd) {
7078 		ANDROID_ERROR(("wrong arg\n"));
7079 		return -1;
7080 	}
7081 
7082 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7083 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7084 		return -1;
7085 	}
7086 
7087 	err = wldev_iovar_getint(dev, "bcnrpt_vsie_en", &bcn_vsie_enable);
7088 	if (unlikely(err)) {
7089 		ANDROID_ERROR(("get bcn vsie failed. ret:%d\n", err));
7090 		return -1;
7091 	}
7092 	ANDROID_INFO(("get bcn report vsie %d\n", bcn_vsie_enable));
7093 
7094 	bytes_written = snprintf(cmd, cmd_len, "%s %d",
7095 		CMD_BR_VSIE_ENAB_GET, bcn_vsie_enable);
7096 
7097 	return bytes_written;
7098 }
7099 
7100 #ifdef SUPPORT_HIDDEN_AP
7101 static int
wl_android_set_max_num_sta(struct net_device * dev,const char * string_num)7102 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
7103 {
7104 	int err = BCME_ERROR;
7105 	int max_assoc;
7106 
7107 	max_assoc = bcm_atoi(string_num);
7108 	ANDROID_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc));
7109 
7110 	err = wldev_iovar_setint(dev, "maxassoc", max_assoc);
7111 	if (err < 0) {
7112 		ANDROID_ERROR(("failed to set maxassoc, error:%d\n", err));
7113 	}
7114 
7115 	return err;
7116 }
7117 
7118 static int
wl_android_set_ssid(struct net_device * dev,const char * hapd_ssid)7119 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
7120 {
7121 	wlc_ssid_t ssid;
7122 	s32 ret;
7123 
7124 	ssid.SSID_len = strlen(hapd_ssid);
7125 	if (ssid.SSID_len == 0) {
7126 		ANDROID_ERROR(("wl_android_set_ssids : No SSID\n"));
7127 		return -1;
7128 	}
7129 	if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
7130 		ssid.SSID_len = DOT11_MAX_SSID_LEN;
7131 		ANDROID_ERROR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid)));
7132 	}
7133 	bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
7134 	ANDROID_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID));
7135 	ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
7136 	if (ret < 0) {
7137 		ANDROID_ERROR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret));
7138 	}
7139 	return 1;
7140 
7141 }
7142 
7143 static int
wl_android_set_hide_ssid(struct net_device * dev,const char * string_num)7144 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
7145 {
7146 	int hide_ssid;
7147 	int enable = 0;
7148 	int err = BCME_ERROR;
7149 
7150 	hide_ssid = bcm_atoi(string_num);
7151 	ANDROID_INFO(("wl_android_set_hide_ssid: HAPD_HIDE_SSID = %d\n", hide_ssid));
7152 	if (hide_ssid) {
7153 		enable = 1;
7154 	}
7155 
7156 	err = wldev_iovar_setint(dev, "closednet", enable);
7157 	if (err < 0) {
7158 		ANDROID_ERROR(("failed to set closednet, error:%d\n", err));
7159 	}
7160 
7161 	return err;
7162 }
7163 #endif /* SUPPORT_HIDDEN_AP */
7164 
7165 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
7166 static int
wl_android_sta_diassoc(struct net_device * dev,const char * straddr)7167 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
7168 {
7169 	scb_val_t scbval;
7170 	int error  = 0;
7171 
7172 	ANDROID_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr));
7173 
7174 	/* Unspecified reason */
7175 	scbval.val = htod32(1);
7176 
7177 	if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
7178 		ANDROID_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n"));
7179 		return -1;
7180 	}
7181 
7182 	ANDROID_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n",
7183 		MAC2STRDBG(scbval.ea.octet), scbval.val));
7184 
7185 	error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
7186 		sizeof(scb_val_t));
7187 	if (error) {
7188 		ANDROID_ERROR(("Fail to DEAUTH station, error = %d\n", error));
7189 	}
7190 
7191 	return 1;
7192 }
7193 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
7194 
7195 #ifdef SUPPORT_SET_LPC
7196 static int
wl_android_set_lpc(struct net_device * dev,const char * string_num)7197 wl_android_set_lpc(struct net_device *dev, const char* string_num)
7198 {
7199 	int lpc_enabled, ret;
7200 	s32 val = 1;
7201 
7202 	lpc_enabled = bcm_atoi(string_num);
7203 	ANDROID_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled));
7204 
7205 	ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
7206 	if (ret < 0)
7207 		ANDROID_ERROR(("WLC_DOWN error %d\n", ret));
7208 
7209 	wldev_iovar_setint(dev, "lpc", lpc_enabled);
7210 
7211 	ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
7212 	if (ret < 0)
7213 		ANDROID_ERROR(("WLC_UP error %d\n", ret));
7214 
7215 	return 1;
7216 }
7217 #endif /* SUPPORT_SET_LPC */
7218 
7219 static int
wl_android_ch_res_rl(struct net_device * dev,bool change)7220 wl_android_ch_res_rl(struct net_device *dev, bool change)
7221 {
7222 	int error = 0;
7223 	s32 srl = 7;
7224 	s32 lrl = 4;
7225 	ANDROID_ERROR(("wl_android_ch_res_rl: enter\n"));
7226 	if (change) {
7227 		srl = 4;
7228 		lrl = 2;
7229 	}
7230 
7231 	BCM_REFERENCE(lrl);
7232 
7233 	error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
7234 	if (error) {
7235 		ANDROID_ERROR(("Failed to set SRL, error = %d\n", error));
7236 	}
7237 #ifndef CUSTOM_LONG_RETRY_LIMIT
7238 	error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
7239 	if (error) {
7240 		ANDROID_ERROR(("Failed to set LRL, error = %d\n", error));
7241 	}
7242 #endif /* CUSTOM_LONG_RETRY_LIMIT */
7243 	return error;
7244 }
7245 
7246 #ifdef SUPPORT_LTECX
7247 #define DEFAULT_WLANRX_PROT	1
7248 #define DEFAULT_LTERX_PROT	0
7249 #define DEFAULT_LTETX_ADV	1200
7250 
7251 static int
wl_android_set_ltecx(struct net_device * dev,const char * string_num)7252 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
7253 {
7254 	uint16 chan_bitmap;
7255 	int ret;
7256 
7257 	chan_bitmap = bcm_strtoul(string_num, NULL, 16);
7258 
7259 	ANDROID_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap));
7260 
7261 	if (chan_bitmap) {
7262 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7263 		if (ret < 0) {
7264 			ANDROID_ERROR(("mws_coex_bitmap error %d\n", ret));
7265 		}
7266 
7267 		ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
7268 		if (ret < 0) {
7269 			ANDROID_ERROR(("mws_wlanrx_prot error %d\n", ret));
7270 		}
7271 
7272 		ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
7273 		if (ret < 0) {
7274 			ANDROID_ERROR(("mws_lterx_prot error %d\n", ret));
7275 		}
7276 
7277 		ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
7278 		if (ret < 0) {
7279 			ANDROID_ERROR(("mws_ltetx_adv error %d\n", ret));
7280 		}
7281 	} else {
7282 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7283 		if (ret < 0) {
7284 			if (ret == BCME_UNSUPPORTED) {
7285 				ANDROID_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
7286 			} else {
7287 				ANDROID_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
7288 			}
7289 		}
7290 	}
7291 	return 1;
7292 }
7293 #endif /* SUPPORT_LTECX */
7294 
7295 #ifdef WL_RELMCAST
7296 static int
wl_android_rmc_enable(struct net_device * net,int rmc_enable)7297 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
7298 {
7299 	int err;
7300 
7301 	err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
7302 	if (err != BCME_OK) {
7303 		ANDROID_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err));
7304 	}
7305 	return err;
7306 }
7307 
7308 static int
wl_android_rmc_set_leader(struct net_device * dev,const char * straddr)7309 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
7310 {
7311 	int error  = BCME_OK;
7312 	char smbuf[WLC_IOCTL_SMLEN];
7313 	wl_rmc_entry_t rmc_entry;
7314 	ANDROID_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr));
7315 
7316 	bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7317 	if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
7318 		if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
7319 			ANDROID_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n"));
7320 			bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7321 		} else {
7322 			ANDROID_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n"));
7323 			return BCME_ERROR;
7324 		}
7325 	}
7326 
7327 	error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
7328 		smbuf, sizeof(smbuf), NULL);
7329 
7330 	if (error != BCME_OK) {
7331 		ANDROID_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n",
7332 			error));
7333 	}
7334 
7335 	return error;
7336 }
7337 
wl_android_set_rmc_event(struct net_device * dev,char * command)7338 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
7339 {
7340 	int err = 0;
7341 	int pid = 0;
7342 
7343 	if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
7344 		ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
7345 		return -1;
7346 	}
7347 
7348 	/* set pid, and if the event was happened, let's send a notification through netlink */
7349 	wl_cfg80211_set_rmc_pid(dev, pid);
7350 
7351 	ANDROID_INFO(("RMC pid=%d\n", pid));
7352 
7353 	return err;
7354 }
7355 #endif /* WL_RELMCAST */
7356 
wl_android_get_singlecore_scan(struct net_device * dev,char * command,int total_len)7357 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
7358 {
7359 	int error = 0;
7360 	int bytes_written = 0;
7361 	int mode = 0;
7362 
7363 	error = wldev_iovar_getint(dev, "scan_ps", &mode);
7364 	if (error) {
7365 		ANDROID_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode,"
7366 			" error = %d\n",
7367 			error));
7368 		return -1;
7369 	}
7370 
7371 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
7372 
7373 	return bytes_written;
7374 }
7375 
wl_android_set_singlecore_scan(struct net_device * dev,char * command)7376 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
7377 {
7378 	int error = 0;
7379 	int mode = 0;
7380 
7381 	if (sscanf(command, "%*s %d", &mode) != 1) {
7382 		ANDROID_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n"));
7383 		return -1;
7384 	}
7385 
7386 	error = wldev_iovar_setint(dev, "scan_ps", mode);
7387 	if (error) {
7388 		ANDROID_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n",
7389 		mode, error));
7390 		return -1;
7391 	}
7392 
7393 	return error;
7394 }
7395 #ifdef TEST_TX_POWER_CONTROL
7396 static int
wl_android_set_tx_power(struct net_device * dev,const char * string_num)7397 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
7398 {
7399 	int err = 0;
7400 	s32 dbm;
7401 	enum nl80211_tx_power_setting type;
7402 
7403 	dbm = bcm_atoi(string_num);
7404 
7405 	if (dbm < -1) {
7406 		ANDROID_ERROR(("wl_android_set_tx_power: dbm is negative...\n"));
7407 		return -EINVAL;
7408 	}
7409 
7410 	if (dbm == -1)
7411 		type = NL80211_TX_POWER_AUTOMATIC;
7412 	else
7413 		type = NL80211_TX_POWER_FIXED;
7414 
7415 	err = wl_set_tx_power(dev, type, dbm);
7416 	if (unlikely(err)) {
7417 		ANDROID_ERROR(("wl_android_set_tx_power: error (%d)\n", err));
7418 		return err;
7419 	}
7420 
7421 	return 1;
7422 }
7423 
7424 static int
wl_android_get_tx_power(struct net_device * dev,char * command,int total_len)7425 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
7426 {
7427 	int err;
7428 	int bytes_written;
7429 	s32 dbm = 0;
7430 
7431 	err = wl_get_tx_power(dev, &dbm);
7432 	if (unlikely(err)) {
7433 		ANDROID_ERROR(("wl_android_get_tx_power: error (%d)\n", err));
7434 		return err;
7435 	}
7436 
7437 	bytes_written = snprintf(command, total_len, "%s %d",
7438 		CMD_TEST_GET_TX_POWER, dbm);
7439 
7440 	ANDROID_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm));
7441 
7442 	return bytes_written;
7443 }
7444 #endif /* TEST_TX_POWER_CONTROL */
7445 
7446 static int
wl_android_set_sarlimit_txctrl(struct net_device * dev,const char * string_num)7447 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
7448 {
7449 	int err = BCME_ERROR;
7450 	int setval = 0;
7451 	s32 mode = bcm_atoi(string_num);
7452 	s32 mode_bit = 0;
7453 	int enab = 0;
7454 
7455 	/* As Samsung specific and their requirement,
7456 	 * the mode set as the following form.
7457 	 * -1 : HEAD SAR disabled
7458 	 *  0 : HEAD SAR enabled
7459 	 *  1 : GRIP SAR disabled
7460 	 *  2 : GRIP SAR enabled
7461 	 *  3 : NR mmWave SAR disabled
7462 	 *  4 : NR mmWave SAR enabled
7463 	 *  5 : NR Sub6 SAR disabled
7464 	 *  6 : NR Sub6 SAR enabled
7465 	 *  7 : SAR BACKOFF disabled all
7466 	 * The 'SAR BACKOFF disabled all' index should be the end of the mode.
7467 	 */
7468 	if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) {
7469 		ANDROID_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num)));
7470 		err = BCME_RANGE;
7471 		goto error;
7472 	}
7473 
7474 	mode_bit = mode + 1;
7475 	enab = mode_bit % 2;
7476 	mode_bit = mode_bit / 2;
7477 
7478 	err = wldev_iovar_getint(dev, "sar_enable", &setval);
7479 	if (unlikely(err)) {
7480 		ANDROID_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err));
7481 		goto error;
7482 	}
7483 
7484 	if (mode == SAR_BACKOFF_DISABLE_ALL) {
7485 		ANDROID_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__));
7486 		setval = 0;
7487 	} else {
7488 		ANDROID_ERROR(("%s: SAR limit control mode %d enab %d\n",
7489 			__FUNCTION__, mode_bit, enab));
7490 		if (enab) {
7491 			setval |= (1 << mode_bit);
7492 		} else {
7493 			setval &= ~(1 << mode_bit);
7494 		}
7495 	}
7496 
7497 	err = wldev_iovar_setint(dev, "sar_enable", setval);
7498 	if (unlikely(err)) {
7499 		ANDROID_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
7500 		goto error;
7501 	}
7502 	err = BCME_OK;
7503 error:
7504 	return err;
7505 }
7506 
7507 #ifdef SUPPORT_SET_TID
7508 static int
wl_android_set_tid(struct net_device * dev,char * command)7509 wl_android_set_tid(struct net_device *dev, char* command)
7510 {
7511 	int err = BCME_ERROR;
7512 	char *pos = command;
7513 	char *token = NULL;
7514 	uint8 mode = 0;
7515 	uint32 uid = 0;
7516 	uint8 prio = 0;
7517 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7518 
7519 	if (!dhdp) {
7520 		ANDROID_ERROR(("dhd is NULL\n"));
7521 		return err;
7522 	}
7523 
7524 	ANDROID_INFO(("%s: command[%s]\n", __FUNCTION__, command));
7525 
7526 	/* drop command */
7527 	token = bcmstrtok(&pos, " ", NULL);
7528 
7529 	token = bcmstrtok(&pos, " ", NULL);
7530 	if (!token) {
7531 		ANDROID_ERROR(("Invalid arguments\n"));
7532 		return err;
7533 	}
7534 
7535 	mode = bcm_atoi(token);
7536 
7537 	if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
7538 		ANDROID_ERROR(("Invalid arguments, mode %d\n", mode));
7539 			return err;
7540 	}
7541 
7542 	if (mode) {
7543 		token = bcmstrtok(&pos, " ", NULL);
7544 		if (!token) {
7545 			ANDROID_ERROR(("Invalid arguments for target uid\n"));
7546 			return err;
7547 		}
7548 
7549 		uid = bcm_atoi(token);
7550 
7551 		token = bcmstrtok(&pos, " ", NULL);
7552 		if (!token) {
7553 			ANDROID_ERROR(("Invalid arguments for target tid\n"));
7554 			return err;
7555 		}
7556 
7557 		prio = bcm_atoi(token);
7558 		if (prio >= 0 && prio <= MAXPRIO) {
7559 			dhdp->tid_mode = mode;
7560 			dhdp->target_uid = uid;
7561 			dhdp->target_tid = prio;
7562 		} else {
7563 			ANDROID_ERROR(("Invalid arguments, prio %d\n", prio));
7564 			return err;
7565 		}
7566 	} else {
7567 		dhdp->tid_mode = SET_TID_OFF;
7568 		dhdp->target_uid = 0;
7569 		dhdp->target_tid = 0;
7570 	}
7571 
7572 	ANDROID_INFO(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
7573 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
7574 
7575 	err = BCME_OK;
7576 	return err;
7577 }
7578 
7579 static int
wl_android_get_tid(struct net_device * dev,char * command,int total_len)7580 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
7581 {
7582 	int bytes_written = BCME_ERROR;
7583 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7584 
7585 	if (!dhdp) {
7586 		ANDROID_ERROR(("dhd is NULL\n"));
7587 		return bytes_written;
7588 	}
7589 
7590 	bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
7591 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
7592 
7593 	ANDROID_INFO(("%s: command results %s\n", __FUNCTION__, command));
7594 
7595 	return bytes_written;
7596 }
7597 #endif /* SUPPORT_SET_TID */
7598 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7599 
wl_android_set_roam_mode(struct net_device * dev,char * command)7600 int wl_android_set_roam_mode(struct net_device *dev, char *command)
7601 {
7602 	int error = 0;
7603 	int mode = 0;
7604 
7605 	if (sscanf(command, "%*s %d", &mode) != 1) {
7606 		ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7607 		return -1;
7608 	}
7609 
7610 	error = wldev_iovar_setint(dev, "roam_off", mode);
7611 	if (error) {
7612 		ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
7613 		__FUNCTION__, mode, error));
7614 		return -1;
7615 	}
7616 	else
7617 		ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
7618 		__FUNCTION__, mode, error));
7619 	return 0;
7620 }
7621 
7622 #ifdef WL_CFG80211
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)7623 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
7624 {
7625 	char ie_buf[VNDR_IE_MAX_LEN];
7626 	char *ioctl_buf = NULL;
7627 	char hex[] = "XX";
7628 	char *pcmd = NULL;
7629 	int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
7630 	vndr_ie_setbuf_t *vndr_ie = NULL;
7631 	s32 iecount;
7632 	uint32 pktflag;
7633 	s32 err = BCME_OK, bssidx;
7634 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7635 
7636 	/* Check the VSIE (Vendor Specific IE) which was added.
7637 	 *  If exist then send IOVAR to delete it
7638 	 */
7639 	if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
7640 		return -EINVAL;
7641 	}
7642 
7643 	if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
7644 		ANDROID_ERROR(("error. total_len:%d\n", total_len));
7645 		return -EINVAL;
7646 	}
7647 
7648 	pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
7649 	for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
7650 		if (*pcmd == '\0') {
7651 			ANDROID_ERROR(("error while parsing OUI.\n"));
7652 			return -EINVAL;
7653 		}
7654 		hex[0] = *pcmd++;
7655 		hex[1] = *pcmd++;
7656 		ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
7657 	}
7658 	pcmd++;
7659 	while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
7660 		hex[0] = *pcmd++;
7661 		hex[1] = *pcmd++;
7662 		ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
7663 		datalen++;
7664 	}
7665 
7666 	if (datalen <= 0) {
7667 		ANDROID_ERROR(("error. vndr ie len:%d\n", datalen));
7668 		return -EINVAL;
7669 	}
7670 
7671 	tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
7672 	vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
7673 	if (!vndr_ie) {
7674 		ANDROID_ERROR(("IE memory alloc failed\n"));
7675 		return -ENOMEM;
7676 	}
7677 	/* Copy the vndr_ie SET command ("add"/"del") to the buffer */
7678 	strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
7679 
7680 	/* Set the IE count - the buffer contains only 1 IE */
7681 	iecount = htod32(1);
7682 	memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
7683 
7684 	/* Set packet flag to indicate that BEACON's will contain this IE */
7685 	pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
7686 	memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
7687 		sizeof(u32));
7688 	/* Set the IE ID */
7689 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
7690 
7691 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
7692 		DOT11_OUI_LEN);
7693 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
7694 		&ie_buf[DOT11_OUI_LEN], datalen);
7695 
7696 	ielen = DOT11_OUI_LEN + datalen;
7697 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
7698 
7699 	ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
7700 	if (!ioctl_buf) {
7701 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
7702 		if (vndr_ie) {
7703 			MFREE(cfg->osh, vndr_ie, tot_len);
7704 		}
7705 		return -ENOMEM;
7706 	}
7707 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);	/* init the buffer */
7708 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7709 		ANDROID_ERROR(("Find index failed\n"));
7710 		err = BCME_ERROR;
7711 		goto end;
7712 	}
7713 	err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
7714 			WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
7715 end:
7716 	if (err != BCME_OK) {
7717 		err = -EINVAL;
7718 		if (vndr_ie) {
7719 			MFREE(cfg->osh, vndr_ie, tot_len);
7720 		}
7721 	}
7722 	else {
7723 		/* do NOT free 'vndr_ie' for the next process */
7724 		wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
7725 	}
7726 
7727 	if (ioctl_buf) {
7728 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
7729 	}
7730 
7731 	return err;
7732 }
7733 #endif /* WL_CFG80211 */
7734 
7735 #if defined(BCMFW_ROAM_ENABLE)
7736 static int
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)7737 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
7738 {
7739 	int error = 0;
7740 	char smbuf[WLC_IOCTL_SMLEN];
7741 	uint8 buf[MAX_BUF_SIZE];
7742 	uint8 *pref = buf;
7743 	char *pcmd;
7744 	int num_ucipher_suites = 0;
7745 	int num_akm_suites = 0;
7746 	wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
7747 	wpa_suite_t akm_suites[MAX_NUM_SUITES];
7748 	int num_tuples = 0;
7749 	int total_bytes = 0;
7750 	int total_len_left;
7751 	int i, j;
7752 	char hex[] = "XX";
7753 
7754 	pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
7755 	total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
7756 
7757 	num_akm_suites = simple_strtoul(pcmd, NULL, 16);
7758 	if (num_akm_suites > MAX_NUM_SUITES) {
7759 		ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites));
7760 		return -1;
7761 	}
7762 
7763 	/* Increment for number of AKM suites field + space */
7764 	pcmd += 3;
7765 	total_len_left -= 3;
7766 
7767 	/* check to make sure pcmd does not overrun */
7768 	if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
7769 		return -1;
7770 
7771 	bzero(buf, sizeof(buf));
7772 	bzero(akm_suites, sizeof(akm_suites));
7773 	bzero(ucipher_suites, sizeof(ucipher_suites));
7774 
7775 	/* Save the AKM suites passed in the command */
7776 	for (i = 0; i < num_akm_suites; i++) {
7777 		/* Store the MSB first, as required by join_pref */
7778 		for (j = 0; j < 4; j++) {
7779 			hex[0] = *pcmd++;
7780 			hex[1] = *pcmd++;
7781 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7782 		}
7783 		memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
7784 	}
7785 
7786 	total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
7787 	num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
7788 	/* Increment for number of cipher suites field + space */
7789 	pcmd += 3;
7790 	total_len_left -= 3;
7791 
7792 	if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
7793 		return -1;
7794 
7795 	/* Save the cipher suites passed in the command */
7796 	for (i = 0; i < num_ucipher_suites; i++) {
7797 		/* Store the MSB first, as required by join_pref */
7798 		for (j = 0; j < 4; j++) {
7799 			hex[0] = *pcmd++;
7800 			hex[1] = *pcmd++;
7801 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7802 		}
7803 		memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
7804 	}
7805 
7806 	/* Join preference for RSSI
7807 	 * Type	  : 1 byte (0x01)
7808 	 * Length : 1 byte (0x02)
7809 	 * Value  : 2 bytes	(reserved)
7810 	 */
7811 	*pref++ = WL_JOIN_PREF_RSSI;
7812 	*pref++ = JOIN_PREF_RSSI_LEN;
7813 	*pref++ = 0;
7814 	*pref++ = 0;
7815 
7816 	/* Join preference for WPA
7817 	 * Type	  : 1 byte (0x02)
7818 	 * Length : 1 byte (not used)
7819 	 * Value  : (variable length)
7820 	 *		reserved: 1 byte
7821 	 *      count	: 1 byte (no of tuples)
7822 	 *		Tuple1	: 12 bytes
7823 	 *			akm[4]
7824 	 *			ucipher[4]
7825 	 *			mcipher[4]
7826 	 *		Tuple2	: 12 bytes
7827 	 *		Tuplen	: 12 bytes
7828 	 */
7829 	num_tuples = num_akm_suites * num_ucipher_suites;
7830 	if (num_tuples != 0) {
7831 		if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
7832 			*pref++ = WL_JOIN_PREF_WPA;
7833 			*pref++ = 0;
7834 			*pref++ = 0;
7835 			*pref++ = (uint8)num_tuples;
7836 			total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
7837 				(JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
7838 		} else {
7839 			ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
7840 			return -1;
7841 		}
7842 	} else {
7843 		/* No WPA config, configure only RSSI preference */
7844 		total_bytes = JOIN_PREF_RSSI_SIZE;
7845 	}
7846 
7847 	/* akm-ucipher-mcipher tuples in the format required for join_pref */
7848 	for (i = 0; i < num_ucipher_suites; i++) {
7849 		for (j = 0; j < num_akm_suites; j++) {
7850 			memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
7851 			pref += WPA_SUITE_LEN;
7852 			memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
7853 			pref += WPA_SUITE_LEN;
7854 			/* Set to 0 to match any available multicast cipher */
7855 			bzero(pref, WPA_SUITE_LEN);
7856 			pref += WPA_SUITE_LEN;
7857 		}
7858 	}
7859 
7860 	prhex("join pref", (uint8 *)buf, total_bytes);
7861 	error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
7862 	if (error) {
7863 		ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
7864 	}
7865 	return error;
7866 }
7867 #endif /* defined(BCMFW_ROAM_ENABLE */
7868 
7869 #ifdef WL_CFG80211
7870 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)7871 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
7872 {
7873 	struct io_cfg *resume_cfg;
7874 	s32 ret;
7875 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7876 
7877 	resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
7878 	if (!resume_cfg)
7879 		return -ENOMEM;
7880 
7881 	if (config->iovar) {
7882 		ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
7883 		if (ret) {
7884 			ANDROID_ERROR(("%s: Failed to get current %s value\n",
7885 				__FUNCTION__, config->iovar));
7886 			goto error;
7887 		}
7888 
7889 		ret = wldev_iovar_setint(dev, config->iovar, config->param);
7890 		if (ret) {
7891 			ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7892 				config->iovar, config->param));
7893 			goto error;
7894 		}
7895 
7896 		resume_cfg->iovar = config->iovar;
7897 	} else {
7898 		resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
7899 		if (!resume_cfg->arg) {
7900 			ret = -ENOMEM;
7901 			goto error;
7902 		}
7903 		ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
7904 		if (ret) {
7905 			ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
7906 				config->ioctl));
7907 			goto error;
7908 		}
7909 		ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
7910 		if (ret) {
7911 			ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7912 				config->iovar, config->param));
7913 			goto error;
7914 		}
7915 		if (config->ioctl + 1 == WLC_SET_PM)
7916 			wl_cfg80211_update_power_mode(dev);
7917 		resume_cfg->ioctl = config->ioctl;
7918 		resume_cfg->len = config->len;
7919 	}
7920 
7921 	/* assuming only one active user and no list protection */
7922 	list_add(&resume_cfg->list, head);
7923 
7924 	return 0;
7925 error:
7926 	MFREE(cfg->osh, resume_cfg->arg, config->len);
7927 	MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
7928 	return ret;
7929 }
7930 
7931 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)7932 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
7933 {
7934 	struct io_cfg *config;
7935 	struct list_head *cur, *q;
7936 	s32 ret = 0;
7937 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7938 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7939 	list_for_each_safe(cur, q, head) {
7940 		config = list_entry(cur, struct io_cfg, list);
7941 		GCC_DIAGNOSTIC_POP();
7942 		if (config->iovar) {
7943 			if (!ret)
7944 				ret = wldev_iovar_setint(dev, config->iovar,
7945 					config->param);
7946 		} else {
7947 			if (!ret)
7948 				ret = wldev_ioctl_set(dev, config->ioctl + 1,
7949 					config->arg, config->len);
7950 			if (config->ioctl + 1 == WLC_SET_PM)
7951 				wl_cfg80211_update_power_mode(dev);
7952 			MFREE(cfg->osh, config->arg, config->len);
7953 		}
7954 		list_del(cur);
7955 		MFREE(cfg->osh, config, sizeof(struct io_cfg));
7956 	}
7957 }
7958 
7959 static int
wl_android_set_miracast(struct net_device * dev,char * command)7960 wl_android_set_miracast(struct net_device *dev, char *command)
7961 {
7962 	int mode, val = 0;
7963 	int ret = 0;
7964 	struct io_cfg config;
7965 
7966 	if (sscanf(command, "%*s %d", &mode) != 1) {
7967 		ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7968 		return -1;
7969 	}
7970 
7971 	ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
7972 
7973 	if (miracast_cur_mode == mode) {
7974 		return 0;
7975 	}
7976 
7977 	wl_android_iolist_resume(dev, &miracast_resume_list);
7978 	miracast_cur_mode = MIRACAST_MODE_OFF;
7979 
7980 	bzero((void *)&config, sizeof(config));
7981 	switch (mode) {
7982 	case MIRACAST_MODE_SOURCE:
7983 #ifdef MIRACAST_MCHAN_ALGO
7984 		/* setting mchan_algo to platform specific value */
7985 		config.iovar = "mchan_algo";
7986 
7987 		/* check for station's beacon interval(BI)
7988 		 * If BI is over 100ms, don't use mchan_algo
7989 		 */
7990 		ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
7991 		if (!ret && val > 100) {
7992 			config.param = 0;
7993 			ANDROID_ERROR(("%s: Connected station's beacon interval: "
7994 				"%d and set mchan_algo to %d \n",
7995 				__FUNCTION__, val, config.param));
7996 		} else {
7997 			config.param = MIRACAST_MCHAN_ALGO;
7998 		}
7999 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8000 		if (ret) {
8001 			goto resume;
8002 		}
8003 #endif /* MIRACAST_MCHAN_ALGO */
8004 
8005 #ifdef MIRACAST_MCHAN_BW
8006 		/* setting mchan_bw to platform specific value */
8007 		config.iovar = "mchan_bw";
8008 		config.param = MIRACAST_MCHAN_BW;
8009 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8010 		if (ret) {
8011 			goto resume;
8012 		}
8013 #endif /* MIRACAST_MCHAN_BW */
8014 
8015 #ifdef MIRACAST_AMPDU_SIZE
8016 		/* setting apmdu to platform specific value */
8017 		config.iovar = "ampdu_mpdu";
8018 		config.param = MIRACAST_AMPDU_SIZE;
8019 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8020 		if (ret) {
8021 			goto resume;
8022 		}
8023 #endif /* MIRACAST_AMPDU_SIZE */
8024 		/* FALLTROUGH */
8025 		/* Source mode shares most configurations with sink mode.
8026 		 * Fall through here to avoid code duplication
8027 		 */
8028 	case MIRACAST_MODE_SINK:
8029 		/* disable internal roaming */
8030 		config.iovar = "roam_off";
8031 		config.param = 1;
8032 		config.arg = NULL;
8033 		config.len = 0;
8034 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8035 		if (ret) {
8036 			goto resume;
8037 		}
8038 
8039 #ifdef CUSTOMER_HW10
8040 		/* [CSP#812738] Change scan engine parameters to reduce scan time
8041 		 * and guarantee more times to mirroring.
8042 		 */
8043 		val = 10;
8044 		config.iovar = NULL;
8045 		config.ioctl = WLC_GET_SCAN_CHANNEL_TIME;
8046 		config.arg = &val;
8047 		config.len = sizeof(int);
8048 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8049 		if (ret)
8050 			goto resume;
8051 
8052 		val = 180;
8053 		config.iovar = NULL;
8054 		config.ioctl = WLC_GET_SCAN_HOME_TIME;
8055 		config.arg = &val;
8056 		config.len = sizeof(int);
8057 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8058 		if (ret)
8059 			goto resume;
8060 
8061 #if defined(BCM4339_CHIP)
8062 		config.iovar = "phy_watchdog";
8063 		config.param = 0;
8064 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8065 		ANDROID_INFO(("%s: do iovar cmd=%s (ret=%d)\n",
8066 			__FUNCTION__, config.iovar, ret));
8067 #endif
8068 #endif /* CUSTOMER_HW10 */
8069 
8070 #ifndef CUSTOMER_HW10
8071 
8072 		/* tunr off pm */
8073 		ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
8074 		if (ret) {
8075 			goto resume;
8076 		}
8077 
8078 		if (val != PM_OFF) {
8079 			val = PM_OFF;
8080 			config.iovar = NULL;
8081 			config.ioctl = WLC_GET_PM;
8082 			config.arg = &val;
8083 			config.len = sizeof(int);
8084 			ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8085 			if (ret) {
8086 				goto resume;
8087 			}
8088 		}
8089 #endif /* CUSTOMER_HW10 */
8090 		break;
8091 	case MIRACAST_MODE_OFF:
8092 	default:
8093 		break;
8094 	}
8095 	miracast_cur_mode = mode;
8096 
8097 	return 0;
8098 
8099 resume:
8100 	ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
8101 	wl_android_iolist_resume(dev, &miracast_resume_list);
8102 	return ret;
8103 }
8104 #endif /* WL_CFG80211 */
8105 
8106 #ifdef WL_RELMCAST
8107 #define NETLINK_OXYGEN     30
8108 #define AIBSS_BEACON_TIMEOUT	10
8109 
8110 static struct sock *nl_sk = NULL;
8111 
wl_netlink_recv(struct sk_buff * skb)8112 static void wl_netlink_recv(struct sk_buff *skb)
8113 {
8114 	ANDROID_ERROR(("netlink_recv called\n"));
8115 }
8116 
wl_netlink_init(void)8117 static int wl_netlink_init(void)
8118 {
8119 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8120 	struct netlink_kernel_cfg cfg = {
8121 		.input	= wl_netlink_recv,
8122 	};
8123 #endif
8124 
8125 	if (nl_sk != NULL) {
8126 		ANDROID_ERROR(("nl_sk already exist\n"));
8127 		return BCME_ERROR;
8128 	}
8129 
8130 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
8131 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
8132 		0, wl_netlink_recv, NULL, THIS_MODULE);
8133 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
8134 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
8135 #else
8136 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
8137 #endif
8138 
8139 	if (nl_sk == NULL) {
8140 		ANDROID_ERROR(("nl_sk is not ready\n"));
8141 		return BCME_ERROR;
8142 	}
8143 
8144 	return BCME_OK;
8145 }
8146 
wl_netlink_deinit(void)8147 static void wl_netlink_deinit(void)
8148 {
8149 	if (nl_sk) {
8150 		netlink_kernel_release(nl_sk);
8151 		nl_sk = NULL;
8152 	}
8153 }
8154 
8155 s32
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)8156 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
8157 {
8158 	struct sk_buff *skb = NULL;
8159 	struct nlmsghdr *nlh = NULL;
8160 	int ret = -1;
8161 
8162 	if (nl_sk == NULL) {
8163 		ANDROID_ERROR(("nl_sk was not initialized\n"));
8164 		goto nlmsg_failure;
8165 	}
8166 
8167 	skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
8168 	if (skb == NULL) {
8169 		ANDROID_ERROR(("failed to allocate memory\n"));
8170 		goto nlmsg_failure;
8171 	}
8172 
8173 	nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
8174 	if (nlh == NULL) {
8175 		ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
8176 			skb_tailroom(skb), nlmsg_total_size(size)));
8177 		dev_kfree_skb(skb);
8178 		goto nlmsg_failure;
8179 	}
8180 
8181 	memcpy(nlmsg_data(nlh), data, size);
8182 	nlh->nlmsg_seq = seq;
8183 	nlh->nlmsg_type = type;
8184 
8185 	/* netlink_unicast() takes ownership of the skb and frees it itself. */
8186 	ret = netlink_unicast(nl_sk, skb, pid, 0);
8187 	ANDROID_INFO(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
8188 
8189 nlmsg_failure:
8190 	return ret;
8191 }
8192 #endif /* WL_RELMCAST */
8193 
8194 #ifdef WLAIBSS
wl_android_set_ibss_txfail_event(struct net_device * dev,char * command,int total_len)8195 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
8196 {
8197 	int err = 0;
8198 	int retry = 0;
8199 	int pid = 0;
8200 	aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
8201 	char smbuf[WLC_IOCTL_SMLEN];
8202 
8203 	if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
8204 		ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
8205 		return -1;
8206 	}
8207 
8208 	/* set pid, and if the event was happened, let's send a notification through netlink */
8209 	wl_cfg80211_set_txfail_pid(dev, pid);
8210 
8211 #ifdef WL_RELMCAST
8212 	/* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
8213 	wl_cfg80211_set_rmc_pid(dev, pid);
8214 #endif /* WL_RELMCAST */
8215 
8216 	/* If retry value is 0, it disables the functionality for TX Fail. */
8217 	if (retry > 0) {
8218 		txfail_config.max_tx_retry = retry;
8219 		txfail_config.bcn_timeout = 0;	/* 0 : disable tx fail from beacon */
8220 	}
8221 	txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
8222 	txfail_config.len = sizeof(txfail_config);
8223 
8224 	err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
8225 		sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
8226 	ANDROID_INFO(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
8227 
8228 	return ((err == 0)?total_len:err);
8229 }
8230 
wl_android_get_ibss_peer_info(struct net_device * dev,char * command,int total_len,bool bAll)8231 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
8232 	int total_len, bool bAll)
8233 {
8234 	int error;
8235 	int bytes_written = 0;
8236 	void *buf = NULL;
8237 	bss_peer_list_info_t peer_list_info;
8238 	bss_peer_info_t *peer_info;
8239 	int i;
8240 	bool found = false;
8241 	struct ether_addr mac_ea;
8242 	char *str = command;
8243 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8244 
8245 	ANDROID_INFO(("get ibss peer info(%s)\n", bAll?"true":"false"));
8246 
8247 	if (!bAll) {
8248 		if (bcmstrtok(&str, " ", NULL) == NULL) {
8249 			ANDROID_ERROR(("invalid command\n"));
8250 			return -1;
8251 		}
8252 
8253 		if (!str || !bcm_ether_atoe(str, &mac_ea)) {
8254 			ANDROID_ERROR(("invalid MAC address\n"));
8255 			return -1;
8256 		}
8257 	}
8258 
8259 	if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) {
8260 		ANDROID_ERROR(("kmalloc failed\n"));
8261 		return -1;
8262 	}
8263 
8264 	error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
8265 	if (unlikely(error)) {
8266 		ANDROID_ERROR(("could not get ibss peer info (%d)\n", error));
8267 		MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8268 		return -1;
8269 	}
8270 
8271 	memcpy(&peer_list_info, buf, sizeof(peer_list_info));
8272 	peer_list_info.version = htod16(peer_list_info.version);
8273 	peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
8274 	peer_list_info.count = htod32(peer_list_info.count);
8275 
8276 	ANDROID_INFO(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
8277 		peer_list_info.bss_peer_info_len, peer_list_info.count));
8278 
8279 	if (peer_list_info.count > 0) {
8280 		if (bAll)
8281 			bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
8282 				peer_list_info.count);
8283 
8284 		peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
8285 
8286 		for (i = 0; i < peer_list_info.count; i++) {
8287 
8288 			ANDROID_INFO(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
8289 				peer_info->tx_rate, peer_info->rx_rate));
8290 
8291 			if (!bAll &&
8292 				memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
8293 				found = true;
8294 			}
8295 
8296 			if (bAll || found) {
8297 				bytes_written += snprintf(&command[bytes_written],
8298 					total_len - bytes_written,
8299 					MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
8300 					peer_info->tx_rate/1000, peer_info->rssi);
8301 				if (bytes_written >= total_len) {
8302 					ANDROID_ERROR(("wl_android_get_ibss_peer_info: Insufficient"
8303 						" memory, %d bytes\n",
8304 						total_len));
8305 					bytes_written = -1;
8306 					break;
8307 				}
8308 			}
8309 
8310 			if (found)
8311 				break;
8312 
8313 			peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
8314 		}
8315 	}
8316 	else {
8317 		ANDROID_ERROR(("could not get ibss peer info : no item\n"));
8318 	}
8319 	ANDROID_INFO(("command(%u):%s\n", total_len, command));
8320 	ANDROID_INFO(("bytes_written:%d\n", bytes_written));
8321 
8322 	MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8323 	return bytes_written;
8324 }
8325 
wl_android_set_ibss_routetable(struct net_device * dev,char * command)8326 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
8327 {
8328 
8329 	char *pcmd = command;
8330 	char *str = NULL;
8331 	ibss_route_tbl_t *route_tbl = NULL;
8332 	char *ioctl_buf = NULL;
8333 	s32 err = BCME_OK;
8334 	uint32 route_tbl_len;
8335 	uint32 entries;
8336 	char *endptr;
8337 	uint32 i = 0;
8338 	struct ipv4_addr  dipaddr;
8339 	struct ether_addr ea;
8340 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8341 
8342 	route_tbl_len = sizeof(ibss_route_tbl_t) +
8343 		(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
8344 	route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
8345 	if (!route_tbl) {
8346 		ANDROID_ERROR(("Route TBL alloc failed\n"));
8347 		return -ENOMEM;
8348 	}
8349 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
8350 	if (!ioctl_buf) {
8351 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
8352 		if (route_tbl) {
8353 			MFREE(cfg->osh, route_tbl, route_tbl_len);
8354 		}
8355 		return -ENOMEM;
8356 	}
8357 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);
8358 
8359 	/* drop command */
8360 	str = bcmstrtok(&pcmd, " ", NULL);
8361 
8362 	/* get count */
8363 	str = bcmstrtok(&pcmd, " ",  NULL);
8364 	if (!str) {
8365 		ANDROID_ERROR(("Invalid number parameter %s\n", str));
8366 		err = -EINVAL;
8367 		goto exit;
8368 	}
8369 	entries = bcm_strtoul(str, &endptr, 0);
8370 	if (*endptr != '\0') {
8371 		ANDROID_ERROR(("Invalid number parameter %s\n", str));
8372 		err = -EINVAL;
8373 		goto exit;
8374 	}
8375 	if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
8376 		ANDROID_ERROR(("Invalid entries number %u\n", entries));
8377 		err = -EINVAL;
8378 		goto exit;
8379 	}
8380 
8381 	ANDROID_INFO(("Routing table count:%u\n", entries));
8382 	route_tbl->num_entry = entries;
8383 
8384 	for (i = 0; i < entries; i++) {
8385 		str = bcmstrtok(&pcmd, " ", NULL);
8386 		if (!str || !bcm_atoipv4(str, &dipaddr)) {
8387 			ANDROID_ERROR(("Invalid ip string %s\n", str));
8388 			err = -EINVAL;
8389 			goto exit;
8390 		}
8391 
8392 		str = bcmstrtok(&pcmd, " ", NULL);
8393 		if (!str || !bcm_ether_atoe(str, &ea)) {
8394 			ANDROID_ERROR(("Invalid ethernet string %s\n", str));
8395 			err = -EINVAL;
8396 			goto exit;
8397 		}
8398 		bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
8399 		bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
8400 	}
8401 
8402 	route_tbl_len = sizeof(ibss_route_tbl_t) +
8403 		((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
8404 	err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
8405 		route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
8406 	if (err != BCME_OK) {
8407 		ANDROID_ERROR(("Fail to set iovar %d\n", err));
8408 		err = -EINVAL;
8409 	}
8410 
8411 exit:
8412 	if (route_tbl) {
8413 		MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
8414 			(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
8415 	}
8416 	if (ioctl_buf) {
8417 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
8418 	}
8419 	return err;
8420 
8421 }
8422 
8423 int
wl_android_set_ibss_ampdu(struct net_device * dev,char * command,int total_len)8424 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
8425 {
8426 	char *pcmd = command;
8427 	char *str = NULL, *endptr = NULL;
8428 	struct ampdu_aggr aggr;
8429 	char smbuf[WLC_IOCTL_SMLEN];
8430 	int idx;
8431 	int err = 0;
8432 	int wme_AC2PRIO[AC_COUNT][2] = {
8433 		{PRIO_8021D_VO, PRIO_8021D_NC},		/* AC_VO - 3 */
8434 		{PRIO_8021D_CL, PRIO_8021D_VI},		/* AC_VI - 2 */
8435 		{PRIO_8021D_BK, PRIO_8021D_NONE},	/* AC_BK - 1 */
8436 		{PRIO_8021D_BE, PRIO_8021D_EE}};	/* AC_BE - 0 */
8437 
8438 	ANDROID_INFO(("set ibss ampdu:%s\n", command));
8439 
8440 	bzero(&aggr, sizeof(aggr));
8441 	/* Cofigure all priorities */
8442 	aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
8443 
8444 	/* acquire parameters */
8445 	/* drop command */
8446 	str = bcmstrtok(&pcmd, " ", NULL);
8447 
8448 	for (idx = 0; idx < AC_COUNT; idx++) {
8449 		bool on;
8450 		str = bcmstrtok(&pcmd, " ", NULL);
8451 		if (!str) {
8452 			ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8453 			return -EINVAL;
8454 		}
8455 		on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
8456 		if (*endptr != '\0') {
8457 			ANDROID_ERROR(("Invalid number format %s\n", str));
8458 			return -EINVAL;
8459 		}
8460 		if (on) {
8461 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
8462 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
8463 		}
8464 	}
8465 
8466 	err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
8467 	sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
8468 
8469 	return ((err == 0) ? total_len : err);
8470 }
8471 
wl_android_set_ibss_antenna(struct net_device * dev,char * command,int total_len)8472 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
8473 {
8474 	char *pcmd = command;
8475 	char *str = NULL;
8476 	int txchain, rxchain;
8477 	int err = 0;
8478 
8479 	ANDROID_INFO(("set ibss antenna:%s\n", command));
8480 
8481 	/* acquire parameters */
8482 	/* drop command */
8483 	str = bcmstrtok(&pcmd, " ", NULL);
8484 
8485 	/* TX chain */
8486 	str = bcmstrtok(&pcmd, " ", NULL);
8487 	if (!str) {
8488 		ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8489 		return -EINVAL;
8490 	}
8491 	txchain = bcm_atoi(str);
8492 
8493 	/* RX chain */
8494 	str = bcmstrtok(&pcmd, " ", NULL);
8495 	if (!str) {
8496 		ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8497 		return -EINVAL;
8498 	}
8499 	rxchain = bcm_atoi(str);
8500 
8501 	err = wldev_iovar_setint(dev, "txchain", txchain);
8502 	if (err != 0)
8503 		return err;
8504 	err = wldev_iovar_setint(dev, "rxchain", rxchain);
8505 	return ((err == 0)?total_len:err);
8506 }
8507 #endif /* WLAIBSS */
8508 
wl_keep_alive_set(struct net_device * dev,char * extra)8509 int wl_keep_alive_set(struct net_device *dev, char* extra)
8510 {
8511 	wl_mkeep_alive_pkt_t	mkeep_alive_pkt;
8512 	int ret;
8513 	uint period_msec = 0;
8514 	char *buf;
8515 	dhd_pub_t *dhd = dhd_get_pub(dev);
8516 
8517 	if (extra == NULL) {
8518 		 ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
8519 		 return -1;
8520 	}
8521 	if (sscanf(extra, "%d", &period_msec) != 1) {
8522 		 ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
8523 		 return -EINVAL;
8524 	}
8525 	ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
8526 
8527 	bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
8528 
8529 	mkeep_alive_pkt.period_msec = period_msec;
8530 	mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
8531 	mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
8532 
8533 	/* Setup keep alive zero for null packet generation */
8534 	mkeep_alive_pkt.keep_alive_id = 0;
8535 	mkeep_alive_pkt.len_bytes = 0;
8536 
8537 	buf = (char *)MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
8538 	if (!buf) {
8539 		ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
8540 		return BCME_NOMEM;
8541 	}
8542 	ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
8543 			WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8544 	if (ret < 0)
8545 		ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
8546 	else
8547 		ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
8548 	MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
8549 	return ret;
8550 }
8551 
8552 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)8553 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
8554 {
8555 	int error = 0;
8556 	int bytes_written = 0;
8557 	int only_resp_wfdsrc = 0;
8558 
8559 	error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
8560 	if (error) {
8561 		ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
8562 			__FUNCTION__, error));
8563 		return -1;
8564 	}
8565 
8566 	bytes_written = snprintf(command, total_len, "%s %d",
8567 		CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
8568 
8569 	return bytes_written;
8570 }
8571 
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)8572 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
8573 {
8574 	int error = 0;
8575 
8576 	error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
8577 	if (error) {
8578 		ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
8579 			__FUNCTION__, only_resp_wfdsrc, error));
8580 		return -1;
8581 	}
8582 
8583 	return 0;
8584 }
8585 #endif /* P2PRESP_WFDIE_SRC */
8586 
8587 #ifdef BT_WIFI_HANDOVER
8588 static int
wl_tbow_teardown(struct net_device * dev)8589 wl_tbow_teardown(struct net_device *dev)
8590 {
8591 	int err = BCME_OK;
8592 	char buf[WLC_IOCTL_SMLEN];
8593 	tbow_setup_netinfo_t netinfo;
8594 	bzero(&netinfo, sizeof(netinfo));
8595 	netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
8596 
8597 	err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
8598 			sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
8599 	if (err < 0) {
8600 		ANDROID_ERROR(("tbow_doho iovar error %d\n", err));
8601 		return err;
8602 	}
8603 	return err;
8604 }
8605 #endif /* BT_WIFI_HANOVER */
8606 
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)8607 static int wl_android_get_link_status(struct net_device *dev, char *command,
8608 	int total_len)
8609 {
8610 	int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
8611 	uint32 rspec;
8612 	uint encode, txexp;
8613 	wl_bss_info_t *bi;
8614 	int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
8615 	char buf[WLC_IOCTL_SMLEN];
8616 
8617 	if (datalen > WLC_IOCTL_SMLEN) {
8618 		ANDROID_ERROR(("data too big\n"));
8619 		return -1;
8620 	}
8621 
8622 	bzero(buf, datalen);
8623 	/* get BSS information */
8624 	*(u32 *) buf = htod32(datalen);
8625 	error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
8626 	if (unlikely(error)) {
8627 		ANDROID_ERROR(("Could not get bss info %d\n", error));
8628 		return -1;
8629 	}
8630 
8631 	bi = (wl_bss_info_t*) (buf + sizeof(uint32));
8632 
8633 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
8634 		if (bi->BSSID.octet[i] > 0) {
8635 			break;
8636 		}
8637 	}
8638 
8639 	if (i == ETHER_ADDR_LEN) {
8640 		ANDROID_INFO(("No BSSID\n"));
8641 		return -1;
8642 	}
8643 
8644 	/* check VHT capability at beacon */
8645 	if (bi->vht_cap) {
8646 		if (CHSPEC_IS5G(bi->chanspec)) {
8647 			result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
8648 		}
8649 	}
8650 
8651 	/* get a rspec (radio spectrum) rate */
8652 	error = wldev_iovar_getint(dev, "nrate", &rspec);
8653 	if (unlikely(error) || rspec == 0) {
8654 		ANDROID_ERROR(("get link status error (%d)\n", error));
8655 		return -1;
8656 	}
8657 
8658 	/* referred wl_nrate_print() for the calculation */
8659 	encode = (rspec & WL_RSPEC_ENCODING_MASK);
8660 	txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
8661 
8662 	switch (encode) {
8663 	case WL_RSPEC_ENCODE_HT:
8664 		/* check Rx MCS Map for HT */
8665 		for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
8666 			int8 bitmap = 0xFF;
8667 			if (i == MAX_STREAMS_SUPPORTED-1) {
8668 				bitmap = 0x7F;
8669 			}
8670 			if (bi->basic_mcs[i] & bitmap) {
8671 				nss++;
8672 			}
8673 		}
8674 		break;
8675 	case WL_RSPEC_ENCODE_VHT:
8676 		/* check Rx MCS Map for VHT */
8677 		for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
8678 			mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
8679 			if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
8680 				nss++;
8681 			}
8682 		}
8683 		break;
8684 	}
8685 
8686 	/* check MIMO capability with nss in beacon */
8687 	if (nss > 1) {
8688 		result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
8689 	}
8690 
8691 	/* Legacy rates WL_RSPEC_ENCODE_RATE are single stream, and
8692 	 * HT rates for mcs 0-7 are single stream.
8693 	 * In case of VHT NSS comes from rspec.
8694 	 */
8695 	single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
8696 		((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
8697 		((encode == WL_RSPEC_ENCODE_VHT) &&
8698 		((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
8699 
8700 	if (txexp == 0) {
8701 		if ((rspec & WL_RSPEC_STBC) && single_stream) {
8702 			stf = OLD_NRATE_STF_STBC;
8703 		} else {
8704 			stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
8705 		}
8706 	} else if (txexp == 1 && single_stream) {
8707 		stf = OLD_NRATE_STF_CDD;
8708 	}
8709 
8710 	/* check 11ac (VHT) */
8711 	if (encode == WL_RSPEC_ENCODE_VHT) {
8712 		if (CHSPEC_IS5G(bi->chanspec)) {
8713 			result |= WL_ANDROID_LINK_VHT;
8714 		}
8715 	}
8716 
8717 	/* check MIMO */
8718 	if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
8719 		switch (stf) {
8720 		case OLD_NRATE_STF_SISO:
8721 			break;
8722 		case OLD_NRATE_STF_CDD:
8723 		case OLD_NRATE_STF_STBC:
8724 			result |= WL_ANDROID_LINK_MIMO;
8725 			break;
8726 		case OLD_NRATE_STF_SDM:
8727 			if (!single_stream) {
8728 				result |= WL_ANDROID_LINK_MIMO;
8729 			}
8730 			break;
8731 		}
8732 	}
8733 
8734 	ANDROID_INFO(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
8735 		__FUNCTION__, result, stf, single_stream, nss));
8736 
8737 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
8738 
8739 	return bytes_written;
8740 }
8741 
8742 #ifdef P2P_LISTEN_OFFLOADING
8743 
8744 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 * cfg)8745 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
8746 {
8747 	s32 bssidx;
8748 	int ret = 0;
8749 	int p2plo_pause = 0;
8750 	dhd_pub_t *dhd = NULL;
8751 	if (!cfg || !cfg->p2p) {
8752 		ANDROID_ERROR(("Wl %p or cfg->p2p %p is null\n",
8753 			cfg, cfg ? cfg->p2p : 0));
8754 		return 0;
8755 	}
8756 
8757 	dhd =  (dhd_pub_t *)(cfg->pub);
8758 	if (!dhd->up) {
8759 		ANDROID_ERROR(("bus is already down\n"));
8760 		return ret;
8761 	}
8762 
8763 	bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8764 	ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
8765 			"p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
8766 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
8767 	if (ret < 0) {
8768 		ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8769 	}
8770 
8771 	return  ret;
8772 }
8773 s32
wl_cfg80211_p2plo_listen_start(struct net_device * dev,u8 * buf,int len)8774 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
8775 {
8776 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8777 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8778 	wl_p2plo_listen_t p2plo_listen;
8779 	int ret = -EAGAIN;
8780 	int channel = 0;
8781 	int period = 0;
8782 	int interval = 0;
8783 	int count = 0;
8784 	if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
8785 		ANDROID_ERROR(("Sending Action Frames. Try it again.\n"));
8786 		goto exit;
8787 	}
8788 
8789 	if (wl_get_drv_status_all(cfg, SCANNING)) {
8790 		ANDROID_ERROR(("Scanning already\n"));
8791 		goto exit;
8792 	}
8793 
8794 	if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
8795 		ANDROID_ERROR(("Scanning being aborted\n"));
8796 		goto exit;
8797 	}
8798 
8799 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8800 		ANDROID_ERROR(("p2p listen offloading already running\n"));
8801 		goto exit;
8802 	}
8803 
8804 	/* Just in case if it is not enabled */
8805 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
8806 		ANDROID_ERROR(("cfgp2p_enable discovery failed"));
8807 		goto exit;
8808 	}
8809 
8810 	bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
8811 
8812 	if (len) {
8813 		sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
8814 		if ((channel == 0) || (period == 0) ||
8815 				(interval == 0) || (count == 0)) {
8816 			ANDROID_ERROR(("Wrong argument %d/%d/%d/%d \n",
8817 				channel, period, interval, count));
8818 			ret = -EAGAIN;
8819 			goto exit;
8820 		}
8821 		p2plo_listen.period = period;
8822 		p2plo_listen.interval = interval;
8823 		p2plo_listen.count = count;
8824 
8825 		ANDROID_ERROR(("channel:%d period:%d, interval:%d count:%d\n",
8826 			channel, period, interval, count));
8827 	} else {
8828 		ANDROID_ERROR(("Argument len is wrong.\n"));
8829 		ret = -EAGAIN;
8830 		goto exit;
8831 	}
8832 
8833 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
8834 			sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8835 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8836 		ANDROID_ERROR(("p2po_listen_channel Failed :%d\n", ret));
8837 		goto exit;
8838 	}
8839 
8840 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
8841 			sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8842 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8843 		ANDROID_ERROR(("p2po_listen Failed :%d\n", ret));
8844 		goto exit;
8845 	}
8846 
8847 	wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
8848 exit :
8849 	return ret;
8850 }
8851 s32
wl_cfg80211_p2plo_listen_stop(struct net_device * dev)8852 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
8853 {
8854 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8855 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8856 	int ret = -EAGAIN;
8857 
8858 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
8859 			0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8860 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8861 		ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8862 		goto exit;
8863 	}
8864 
8865 exit:
8866 	return ret;
8867 }
8868 
8869 s32
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)8870 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
8871 {
8872 	int ret = 0;
8873 
8874 	ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len));
8875 
8876 	if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
8877 		ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
8878 	} else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
8879 		ret = wl_cfg80211_p2plo_listen_stop(dev);
8880 	} else {
8881 		ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf));
8882 		ret = -EINVAL;
8883 	}
8884 	return ret;
8885 }
8886 void
wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 * cfg)8887 wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
8888 {
8889 	struct wireless_dev *wdev;
8890 	if (!cfg) {
8891 		return;
8892 	}
8893 
8894 	wdev = bcmcfg_to_p2p_wdev(cfg);
8895 
8896 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8897 		ANDROID_INFO(("P2P_FIND: Discovery offload is already in progress."
8898 					"it aborted\n"));
8899 		wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
8900 		if (wdev != NULL) {
8901 #if defined(WL_CFG80211_P2P_DEV_IF)
8902 			cfg80211_remain_on_channel_expired(wdev,
8903 					cfg->last_roc_id,
8904 					&cfg->remain_on_chan, GFP_KERNEL);
8905 #else
8906 			cfg80211_remain_on_channel_expired(wdev,
8907 					cfg->last_roc_id,
8908 					&cfg->remain_on_chan,
8909 					cfg->remain_on_chan_type, GFP_KERNEL);
8910 #endif /* WL_CFG80211_P2P_DEV_IF */
8911 		}
8912 		wl_cfg80211_p2plo_deinit(cfg);
8913 	}
8914 }
8915 #endif /* P2P_LISTEN_OFFLOADING */
8916 
8917 #ifdef WL_MURX
8918 int
wl_android_murx_bfe_cap(struct net_device * dev,int val)8919 wl_android_murx_bfe_cap(struct net_device *dev, int val)
8920 {
8921 	int err = BCME_OK;
8922 	int iface_count = wl_cfg80211_iface_count(dev);
8923 	struct ether_addr bssid;
8924 	wl_reassoc_params_t params;
8925 
8926 	if (iface_count > 1) {
8927 		ANDROID_ERROR(("murx_bfe_cap change is not allowed when "
8928 				"there are multiple interfaces\n"));
8929 		return -EINVAL;
8930 	}
8931 	/* Now there is only single interface */
8932 	err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
8933 	if (unlikely(err)) {
8934 		ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d,"
8935 				"error %d\n", val, err));
8936 		return err;
8937 	}
8938 
8939 	/* If successful intiate a reassoc */
8940 	bzero(&bssid, ETHER_ADDR_LEN);
8941 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
8942 		ANDROID_ERROR(("Failed to get bssid, error=%d\n", err));
8943 		return err;
8944 	}
8945 
8946 	bzero(&params, sizeof(wl_reassoc_params_t));
8947 	memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
8948 
8949 	if ((err = wldev_ioctl_set(dev, WLC_REASSOC, &params,
8950 		sizeof(wl_reassoc_params_t))) < 0) {
8951 		ANDROID_ERROR(("reassoc failed err:%d \n", err));
8952 	} else {
8953 		ANDROID_INFO(("reassoc issued successfully\n"));
8954 	}
8955 
8956 	return err;
8957 }
8958 #endif /* WL_MURX */
8959 
8960 #ifdef SUPPORT_RSSI_SUM_REPORT
8961 int
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)8962 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
8963 {
8964 	wl_rssi_ant_mimo_t rssi_ant_mimo;
8965 	char *ifname = NULL;
8966 	char *peer_mac = NULL;
8967 	char *mimo_cmd = "mimo";
8968 	char *pos, *token;
8969 	int err = BCME_OK;
8970 	int bytes_written = 0;
8971 	bool mimo_rssi = FALSE;
8972 
8973 	bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
8974 	/*
8975 	 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
8976 	 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
8977 	 */
8978 	pos = command;
8979 
8980 	/* drop command */
8981 	token = bcmstrtok(&pos, " ", NULL);
8982 
8983 	/* get the interface name */
8984 	token = bcmstrtok(&pos, " ", NULL);
8985 	if (!token) {
8986 		ANDROID_ERROR(("Invalid arguments\n"));
8987 		return -EINVAL;
8988 	}
8989 	ifname = token;
8990 
8991 	/* Optional: Check the MIMO RSSI mode or peer MAC address */
8992 	token = bcmstrtok(&pos, " ", NULL);
8993 	if (token) {
8994 		/* Check the MIMO RSSI mode */
8995 		if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
8996 			mimo_rssi = TRUE;
8997 		} else {
8998 			peer_mac = token;
8999 		}
9000 	}
9001 
9002 	/* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
9003 	token = bcmstrtok(&pos, " ", NULL);
9004 	if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9005 		mimo_rssi = TRUE;
9006 	}
9007 
9008 	err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
9009 	if (unlikely(err)) {
9010 		ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err));
9011 		return err;
9012 	}
9013 
9014 	/* Parse the results */
9015 	ANDROID_INFO(("ifname %s, version %d, count %d, mimo rssi %d\n",
9016 		ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
9017 	if (mimo_rssi) {
9018 		ANDROID_INFO(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
9019 		bytes_written = snprintf(command, total_len, "%s MIMO %d",
9020 			CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
9021 	} else {
9022 		int cnt;
9023 		bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
9024 		for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
9025 			ANDROID_INFO(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
9026 			bytes_written = snprintf(command, total_len, "%d ",
9027 				rssi_ant_mimo.rssi_ant[cnt]);
9028 		}
9029 	}
9030 
9031 	return bytes_written;
9032 }
9033 
9034 int
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)9035 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
9036 {
9037 	rssilog_set_param_t set_param;
9038 	char *pos, *token;
9039 	int err = BCME_OK;
9040 
9041 	bzero(&set_param, sizeof(rssilog_set_param_t));
9042 	/*
9043 	 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
9044 	 */
9045 	pos = command;
9046 
9047 	/* drop command */
9048 	token = bcmstrtok(&pos, " ", NULL);
9049 
9050 	/* enable/disable */
9051 	token = bcmstrtok(&pos, " ", NULL);
9052 	if (!token) {
9053 		ANDROID_ERROR(("Invalid arguments\n"));
9054 		return -EINVAL;
9055 	}
9056 	set_param.enable = bcm_atoi(token);
9057 
9058 	/* RSSI Threshold */
9059 	token = bcmstrtok(&pos, " ", NULL);
9060 	if (!token) {
9061 		ANDROID_ERROR(("Invalid arguments\n"));
9062 		return -EINVAL;
9063 	}
9064 	set_param.rssi_threshold = bcm_atoi(token);
9065 
9066 	/* Time Threshold */
9067 	token = bcmstrtok(&pos, " ", NULL);
9068 	if (!token) {
9069 		ANDROID_ERROR(("Invalid arguments\n"));
9070 		return -EINVAL;
9071 	}
9072 	set_param.time_threshold = bcm_atoi(token);
9073 
9074 	ANDROID_INFO(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
9075 		set_param.rssi_threshold, set_param.time_threshold));
9076 
9077 	err = wl_set_rssi_logging(dev, (void *)&set_param);
9078 	if (unlikely(err)) {
9079 		ANDROID_ERROR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
9080 			" Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
9081 			set_param.time_threshold));
9082 	}
9083 
9084 	return err;
9085 }
9086 
9087 int
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)9088 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
9089 {
9090 	rssilog_get_param_t get_param;
9091 	int err = BCME_OK;
9092 	int bytes_written = 0;
9093 
9094 	err = wl_get_rssi_logging(dev, (void *)&get_param);
9095 	if (unlikely(err)) {
9096 		ANDROID_ERROR(("Failed to get RSSI logging info\n"));
9097 		return BCME_ERROR;
9098 	}
9099 
9100 	ANDROID_INFO(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
9101 		get_param.report_count, get_param.enable, get_param.rssi_threshold,
9102 		get_param.time_threshold));
9103 
9104 	/* Parse the parameter */
9105 	if (!get_param.enable) {
9106 		ANDROID_INFO(("RSSI LOGGING: Feature is disables\n"));
9107 		bytes_written = snprintf(command, total_len,
9108 			"%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
9109 	} else if (get_param.enable &
9110 		(RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
9111 		if (!get_param.report_count) {
9112 			ANDROID_INFO(("[PASS] RSSI difference across antennas is within"
9113 				" threshold limits\n"));
9114 			bytes_written = snprintf(command, total_len, "%s PASS\n",
9115 				CMD_GET_RSSI_LOGGING);
9116 		} else {
9117 			ANDROID_INFO(("[FAIL] RSSI difference across antennas found "
9118 				"to be greater than %3d dB\n", get_param.rssi_threshold));
9119 			ANDROID_INFO(("[FAIL] RSSI difference check have failed for "
9120 				"%d out of %d times\n", get_param.report_count,
9121 				get_param.time_threshold));
9122 			ANDROID_INFO(("[FAIL] RSSI difference is being monitored once "
9123 				"per second, for a %d secs window\n", get_param.time_threshold));
9124 			bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
9125 				"%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
9126 				get_param.rssi_threshold, get_param.report_count,
9127 				get_param.time_threshold);
9128 		}
9129 	} else {
9130 		ANDROID_INFO(("[BUSY] Reprot is not ready\n"));
9131 		bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
9132 			CMD_GET_RSSI_LOGGING);
9133 	}
9134 
9135 	return bytes_written;
9136 }
9137 #endif /* SUPPORT_RSSI_SUM_REPORT */
9138 
9139 #ifdef SET_PCIE_IRQ_CPU_CORE
9140 void
wl_android_set_irq_cpucore(struct net_device * net,int affinity_cmd)9141 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
9142 {
9143 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9144 	if (!dhdp) {
9145 		ANDROID_ERROR(("dhd is NULL\n"));
9146 		return;
9147 	}
9148 
9149 	dhd_set_irq_cpucore(dhdp, affinity_cmd);
9150 }
9151 #endif /* SET_PCIE_IRQ_CPU_CORE */
9152 
9153 #ifdef SUPPORT_LQCM
9154 static int
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)9155 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
9156 {
9157 	int err = 0;
9158 
9159 	err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
9160 	if (err != BCME_OK) {
9161 		ANDROID_ERROR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
9162 		return -EIO;
9163 	}
9164 	return err;
9165 }
9166 
9167 static int
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)9168 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
9169 {
9170 	int bytes_written, err = 0;
9171 	uint32 lqcm_report = 0;
9172 	uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
9173 
9174 	err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
9175 	if (err != BCME_OK) {
9176 		ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err));
9177 		return -EIO;
9178 	}
9179 	lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
9180 	tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
9181 	rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
9182 
9183 	ANDROID_INFO(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
9184 
9185 	bytes_written = snprintf(command, total_len, "%s %d",
9186 			CMD_GET_LQCM_REPORT, lqcm_report);
9187 
9188 	return bytes_written;
9189 }
9190 #endif /* SUPPORT_LQCM */
9191 
9192 int
wl_android_get_snr(struct net_device * dev,char * command,int total_len)9193 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
9194 {
9195 	int bytes_written, error = 0;
9196 	s32 snr = 0;
9197 
9198 	error = wldev_iovar_getint(dev, "snr", &snr);
9199 	if (error) {
9200 		ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n",
9201 			__FUNCTION__, snr, error));
9202 		return -EIO;
9203 	}
9204 
9205 	bytes_written = snprintf(command, total_len, "snr %d", snr);
9206 	ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
9207 	return bytes_written;
9208 }
9209 
9210 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
9211 int
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)9212 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
9213 {
9214 	int rate = 0;
9215 	char *pos, *token;
9216 	char *ifname = NULL;
9217 	int err = BCME_OK;
9218 
9219 	/*
9220 	 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
9221 	 */
9222 	pos = command;
9223 
9224 	/* drop command */
9225 	token = bcmstrtok(&pos, " ", NULL);
9226 
9227 	/* Rate */
9228 	token = bcmstrtok(&pos, " ", NULL);
9229 	if (!token)
9230 		return -EINVAL;
9231 	rate = bcm_atoi(token);
9232 
9233 	/* get the interface name */
9234 	token = bcmstrtok(&pos, " ", NULL);
9235 	if (!token)
9236 		return -EINVAL;
9237 	ifname = token;
9238 
9239 	ANDROID_INFO(("rate %d, ifacename %s\n", rate, ifname));
9240 
9241 	err = wl_set_ap_beacon_rate(dev, rate, ifname);
9242 	if (unlikely(err)) {
9243 		ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
9244 	}
9245 
9246 	return err;
9247 }
9248 
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)9249 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
9250 {
9251 	char *pos, *token;
9252 	char *ifname = NULL;
9253 	int bytes_written = 0;
9254 	/*
9255 	 * DRIVER GET_AP_BASICRATE <ifname>
9256 	 */
9257 	pos = command;
9258 
9259 	/* drop command */
9260 	token = bcmstrtok(&pos, " ", NULL);
9261 
9262 	/* get the interface name */
9263 	token = bcmstrtok(&pos, " ", NULL);
9264 	if (!token)
9265 		return -EINVAL;
9266 	ifname = token;
9267 
9268 	ANDROID_INFO(("ifacename %s\n", ifname));
9269 
9270 	bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
9271 	if (bytes_written < 1) {
9272 		ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written));
9273 		return -EPROTO;
9274 	}
9275 
9276 	return bytes_written;
9277 }
9278 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
9279 
9280 #ifdef SUPPORT_AP_RADIO_PWRSAVE
9281 int
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)9282 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
9283 {
9284 	char *pos, *token;
9285 	char *ifname = NULL;
9286 	int bytes_written = 0;
9287 	char name[IFNAMSIZ];
9288 	/*
9289 	 * DRIVER GET_AP_RPS <ifname>
9290 	 */
9291 	pos = command;
9292 
9293 	/* drop command */
9294 	token = bcmstrtok(&pos, " ", NULL);
9295 
9296 	/* get the interface name */
9297 	token = bcmstrtok(&pos, " ", NULL);
9298 	if (!token)
9299 		return -EINVAL;
9300 	ifname = token;
9301 
9302 	strlcpy(name, ifname, sizeof(name));
9303 	ANDROID_INFO(("ifacename %s\n", name));
9304 
9305 	bytes_written = wl_get_ap_rps(dev, command, name, total_len);
9306 	if (bytes_written < 1) {
9307 		ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written));
9308 		return -EPROTO;
9309 	}
9310 
9311 	return bytes_written;
9312 
9313 }
9314 
9315 int
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)9316 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
9317 {
9318 	int enable = 0;
9319 	char *pos, *token;
9320 	char *ifname = NULL;
9321 	int err = BCME_OK;
9322 	char name[IFNAMSIZ];
9323 
9324 	/*
9325 	 * DRIVER SET_AP_RPS <0/1> <ifname>
9326 	 */
9327 	pos = command;
9328 
9329 	/* drop command */
9330 	token = bcmstrtok(&pos, " ", NULL);
9331 
9332 	/* Enable */
9333 	token = bcmstrtok(&pos, " ", NULL);
9334 	if (!token)
9335 		return -EINVAL;
9336 	enable = bcm_atoi(token);
9337 
9338 	/* get the interface name */
9339 	token = bcmstrtok(&pos, " ", NULL);
9340 	if (!token)
9341 		return -EINVAL;
9342 	ifname = token;
9343 
9344 	strlcpy(name, ifname, sizeof(name));
9345 	ANDROID_INFO(("enable %d, ifacename %s\n", enable, name));
9346 
9347 	err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
9348 	if (unlikely(err)) {
9349 		ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err));
9350 	}
9351 
9352 	return err;
9353 }
9354 
9355 int
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)9356 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
9357 {
9358 	ap_rps_info_t rps;
9359 	char *pos, *token;
9360 	char *ifname = NULL;
9361 	int err = BCME_OK;
9362 	char name[IFNAMSIZ];
9363 
9364 	bzero(&rps, sizeof(rps));
9365 	/*
9366 	 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
9367 	 */
9368 	pos = command;
9369 
9370 	/* drop command */
9371 	token = bcmstrtok(&pos, " ", NULL);
9372 
9373 	/* pps */
9374 	token = bcmstrtok(&pos, " ", NULL);
9375 	if (!token)
9376 		return -EINVAL;
9377 	rps.pps = bcm_atoi(token);
9378 
9379 	/* level */
9380 	token = bcmstrtok(&pos, " ", NULL);
9381 	if (!token)
9382 		return -EINVAL;
9383 	rps.level = bcm_atoi(token);
9384 
9385 	/* quiettime */
9386 	token = bcmstrtok(&pos, " ", NULL);
9387 	if (!token)
9388 		return -EINVAL;
9389 	rps.quiet_time = bcm_atoi(token);
9390 
9391 	/* sta assoc check */
9392 	token = bcmstrtok(&pos, " ", NULL);
9393 	if (!token)
9394 		return -EINVAL;
9395 	rps.sta_assoc_check = bcm_atoi(token);
9396 
9397 	/* get the interface name */
9398 	token = bcmstrtok(&pos, " ", NULL);
9399 	if (!token)
9400 		return -EINVAL;
9401 	ifname = token;
9402 	strlcpy(name, ifname, sizeof(name));
9403 
9404 	ANDROID_INFO(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
9405 		"ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
9406 		rps.sta_assoc_check, name));
9407 
9408 	err = wl_update_ap_rps_params(dev, &rps, name);
9409 	if (unlikely(err)) {
9410 		ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, "
9411 			"sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
9412 			rps.sta_assoc_check, err));
9413 	}
9414 
9415 	return err;
9416 }
9417 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
9418 
9419 #if defined(DHD_HANG_SEND_UP_TEST)
9420 void
wl_android_make_hang_with_reason(struct net_device * dev,const char * string_num)9421 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
9422 {
9423 	dhd_make_hang_with_reason(dev, string_num);
9424 }
9425 #endif /* DHD_HANG_SEND_UP_TEST */
9426 
9427 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
9428 static void
wl_android_check_priv_cmd_errors(struct net_device * dev)9429 wl_android_check_priv_cmd_errors(struct net_device *dev)
9430 {
9431 	dhd_pub_t *dhdp;
9432 	int memdump_mode;
9433 
9434 	if (!dev) {
9435 		ANDROID_ERROR(("dev is NULL\n"));
9436 		return;
9437 	}
9438 
9439 	dhdp = wl_cfg80211_get_dhdp(dev);
9440 	if (!dhdp) {
9441 		ANDROID_ERROR(("dhdp is NULL\n"));
9442 		return;
9443 	}
9444 
9445 #ifdef DHD_FW_COREDUMP
9446 	memdump_mode = dhdp->memdump_enabled;
9447 #else
9448 	/* Default enable if DHD doesn't support SOCRAM dump */
9449 	memdump_mode = 1;
9450 #endif /* DHD_FW_COREDUMP */
9451 
9452 	if (report_hang_privcmd_err) {
9453 		priv_cmd_errors++;
9454 	} else {
9455 		priv_cmd_errors = 0;
9456 	}
9457 
9458 	/* Trigger HANG event only if memdump mode is enabled
9459 	 * due to customer's request
9460 	 */
9461 	if (memdump_mode == DUMP_MEMFILE_BUGON &&
9462 		(priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
9463 		ANDROID_ERROR(("Send HANG event due to sequential private cmd errors\n"));
9464 		priv_cmd_errors = 0;
9465 #ifdef DHD_FW_COREDUMP
9466 		/* Take a SOCRAM dump */
9467 		dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
9468 		dhd_common_socram_dump(dhdp);
9469 #endif /* DHD_FW_COREDUMP */
9470 		/* Send the HANG event to upper layer */
9471 		dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
9472 		dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
9473 	}
9474 }
9475 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
9476 
9477 #ifdef DHD_PKT_LOGGING
9478 static int
wl_android_pktlog_filter_enable(struct net_device * dev,char * command,int total_len)9479 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
9480 {
9481 	int bytes_written = 0;
9482 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9483 	dhd_pktlog_filter_t *filter;
9484 	int err = BCME_OK;
9485 
9486 	if (!dhdp || !dhdp->pktlog) {
9487 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9488 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9489 		return -EINVAL;
9490 	}
9491 
9492 	filter = dhdp->pktlog->pktlog_filter;
9493 
9494 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
9495 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
9496 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
9497 
9498 	if (err == BCME_OK) {
9499 		bytes_written = snprintf(command, total_len, "OK");
9500 		ANDROID_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
9501 	} else {
9502 		ANDROID_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
9503 		return BCME_ERROR;
9504 	}
9505 
9506 	return bytes_written;
9507 }
9508 
9509 static int
wl_android_pktlog_filter_disable(struct net_device * dev,char * command,int total_len)9510 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
9511 {
9512 	int bytes_written = 0;
9513 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9514 	dhd_pktlog_filter_t *filter;
9515 	int err = BCME_OK;
9516 
9517 	if (!dhdp || !dhdp->pktlog) {
9518 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9519 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9520 		return -EINVAL;
9521 	}
9522 
9523 	filter = dhdp->pktlog->pktlog_filter;
9524 
9525 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
9526 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
9527 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
9528 
9529 	if (err == BCME_OK) {
9530 		bytes_written = snprintf(command, total_len, "OK");
9531 		ANDROID_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
9532 	} else {
9533 		ANDROID_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
9534 		return BCME_ERROR;
9535 	}
9536 
9537 	return bytes_written;
9538 }
9539 
9540 static int
wl_android_pktlog_filter_pattern_enable(struct net_device * dev,char * command,int total_len)9541 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
9542 {
9543 	int bytes_written = 0;
9544 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9545 	dhd_pktlog_filter_t *filter;
9546 	int err = BCME_OK;
9547 
9548 	if (!dhdp || !dhdp->pktlog) {
9549 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9550 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9551 		return -EINVAL;
9552 	}
9553 
9554 	filter = dhdp->pktlog->pktlog_filter;
9555 
9556 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
9557 		return BCME_ERROR;
9558 	}
9559 
9560 	err = dhd_pktlog_filter_pattern_enable(filter,
9561 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
9562 
9563 	if (err == BCME_OK) {
9564 		bytes_written = snprintf(command, total_len, "OK");
9565 		ANDROID_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
9566 	} else {
9567 		ANDROID_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
9568 		return BCME_ERROR;
9569 	}
9570 
9571 	return bytes_written;
9572 }
9573 
9574 static int
wl_android_pktlog_filter_pattern_disable(struct net_device * dev,char * command,int total_len)9575 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
9576 {
9577 	int bytes_written = 0;
9578 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9579 	dhd_pktlog_filter_t *filter;
9580 	int err = BCME_OK;
9581 
9582 	if (!dhdp || !dhdp->pktlog) {
9583 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9584 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9585 		return -EINVAL;
9586 	}
9587 
9588 	filter = dhdp->pktlog->pktlog_filter;
9589 
9590 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
9591 		return BCME_ERROR;
9592 	}
9593 
9594 	err = dhd_pktlog_filter_pattern_enable(filter,
9595 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
9596 
9597 	if (err == BCME_OK) {
9598 		bytes_written = snprintf(command, total_len, "OK");
9599 		ANDROID_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
9600 	} else {
9601 		ANDROID_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
9602 		return BCME_ERROR;
9603 	}
9604 
9605 	return bytes_written;
9606 }
9607 
9608 static int
wl_android_pktlog_filter_add(struct net_device * dev,char * command,int total_len)9609 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
9610 {
9611 	int bytes_written = 0;
9612 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9613 	dhd_pktlog_filter_t *filter;
9614 	int err = BCME_OK;
9615 
9616 	if (!dhdp || !dhdp->pktlog) {
9617 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9618 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9619 		return -EINVAL;
9620 	}
9621 
9622 	filter = dhdp->pktlog->pktlog_filter;
9623 
9624 	if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
9625 		return BCME_ERROR;
9626 	}
9627 
9628 	err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
9629 
9630 	if (err == BCME_OK) {
9631 		bytes_written = snprintf(command, total_len, "OK");
9632 		ANDROID_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
9633 	} else {
9634 		ANDROID_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
9635 		return BCME_ERROR;
9636 	}
9637 
9638 	return bytes_written;
9639 }
9640 
9641 static int
wl_android_pktlog_filter_del(struct net_device * dev,char * command,int total_len)9642 wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_len)
9643 {
9644 	int bytes_written = 0;
9645 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9646 	dhd_pktlog_filter_t *filter;
9647 	int err = BCME_OK;
9648 
9649 	if (!dhdp || !dhdp->pktlog) {
9650 		ANDROID_ERROR(("%s(): dhdp=%p pktlog=%p\n",
9651 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9652 		return -EINVAL;
9653 	}
9654 
9655 	filter = dhdp->pktlog->pktlog_filter;
9656 
9657 	if (strlen(CMD_PKTLOG_FILTER_DEL) + 1 > total_len) {
9658 		DHD_PKT_LOG(("%s(): wrong cmd length %d found\n",
9659 			__FUNCTION__, (int)strlen(CMD_PKTLOG_FILTER_DEL)));
9660 		return BCME_ERROR;
9661 	}
9662 
9663 	err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1);
9664 	if (err == BCME_OK) {
9665 		bytes_written = snprintf(command, total_len, "OK");
9666 		ANDROID_ERROR(("%s: pktlog filter del success\n", __FUNCTION__));
9667 	} else {
9668 		ANDROID_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__));
9669 		return BCME_ERROR;
9670 	}
9671 
9672 	return bytes_written;
9673 }
9674 
9675 static int
wl_android_pktlog_filter_info(struct net_device * dev,char * command,int total_len)9676 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
9677 {
9678 	int bytes_written = 0;
9679 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9680 	dhd_pktlog_filter_t *filter;
9681 	int err = BCME_OK;
9682 
9683 	if (!dhdp || !dhdp->pktlog) {
9684 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9685 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9686 		return -EINVAL;
9687 	}
9688 
9689 	filter = dhdp->pktlog->pktlog_filter;
9690 
9691 	err = dhd_pktlog_filter_info(filter);
9692 
9693 	if (err == BCME_OK) {
9694 		bytes_written = snprintf(command, total_len, "OK");
9695 		ANDROID_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
9696 	} else {
9697 		ANDROID_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
9698 		return BCME_ERROR;
9699 	}
9700 
9701 	return bytes_written;
9702 }
9703 
9704 static int
wl_android_pktlog_start(struct net_device * dev,char * command,int total_len)9705 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
9706 {
9707 	int bytes_written = 0;
9708 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9709 
9710 	if (!dhdp || !dhdp->pktlog) {
9711 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9712 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9713 		return -EINVAL;
9714 	}
9715 
9716 	if (!dhdp->pktlog->pktlog_ring) {
9717 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9718 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9719 		return -EINVAL;
9720 	}
9721 
9722 	atomic_set(&dhdp->pktlog->pktlog_ring->start, TRUE);
9723 
9724 	bytes_written = snprintf(command, total_len, "OK");
9725 
9726 	ANDROID_ERROR(("%s: pktlog start success\n", __FUNCTION__));
9727 
9728 	return bytes_written;
9729 }
9730 
9731 static int
wl_android_pktlog_stop(struct net_device * dev,char * command,int total_len)9732 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
9733 {
9734 	int bytes_written = 0;
9735 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9736 
9737 	if (!dhdp || !dhdp->pktlog) {
9738 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9739 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9740 		return -EINVAL;
9741 	}
9742 
9743 	if (!dhdp->pktlog->pktlog_ring) {
9744 		DHD_PKT_LOG(("%s(): _pktlog_ring=%p\n",
9745 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9746 		return -EINVAL;
9747 	}
9748 
9749 	atomic_set(&dhdp->pktlog->pktlog_ring->start, FALSE);
9750 
9751 	bytes_written = snprintf(command, total_len, "OK");
9752 
9753 	ANDROID_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
9754 
9755 	return bytes_written;
9756 }
9757 
9758 static int
wl_android_pktlog_filter_exist(struct net_device * dev,char * command,int total_len)9759 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
9760 {
9761 	int bytes_written = 0;
9762 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9763 	dhd_pktlog_filter_t *filter;
9764 	uint32 id;
9765 	bool exist = FALSE;
9766 
9767 	if (!dhdp || !dhdp->pktlog) {
9768 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9769 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9770 		return -EINVAL;
9771 	}
9772 
9773 	filter = dhdp->pktlog->pktlog_filter;
9774 
9775 	if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
9776 		return BCME_ERROR;
9777 	}
9778 
9779 	exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
9780 			&id);
9781 
9782 	if (exist) {
9783 		bytes_written = snprintf(command, total_len, "TRUE");
9784 		ANDROID_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
9785 	} else {
9786 		bytes_written = snprintf(command, total_len, "FALSE");
9787 		ANDROID_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
9788 	}
9789 
9790 	return bytes_written;
9791 }
9792 
9793 static int
wl_android_pktlog_minmize_enable(struct net_device * dev,char * command,int total_len)9794 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
9795 {
9796 	int bytes_written = 0;
9797 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9798 
9799 	if (!dhdp || !dhdp->pktlog) {
9800 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9801 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9802 		return -EINVAL;
9803 	}
9804 
9805 	if (!dhdp->pktlog->pktlog_ring) {
9806 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9807 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9808 		return -EINVAL;
9809 	}
9810 
9811 	dhdp->pktlog->pktlog_ring->pktlog_minmize = TRUE;
9812 
9813 	bytes_written = snprintf(command, total_len, "OK");
9814 
9815 	ANDROID_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
9816 
9817 	return bytes_written;
9818 }
9819 
9820 static int
wl_android_pktlog_minmize_disable(struct net_device * dev,char * command,int total_len)9821 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
9822 {
9823 	int bytes_written = 0;
9824 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9825 
9826 	if (!dhdp || !dhdp->pktlog) {
9827 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9828 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9829 		return -EINVAL;
9830 	}
9831 
9832 	if (!dhdp->pktlog->pktlog_ring) {
9833 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9834 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9835 		return -EINVAL;
9836 	}
9837 
9838 	dhdp->pktlog->pktlog_ring->pktlog_minmize = FALSE;
9839 
9840 	bytes_written = snprintf(command, total_len, "OK");
9841 
9842 	ANDROID_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
9843 
9844 	return bytes_written;
9845 }
9846 
9847 static int
wl_android_pktlog_change_size(struct net_device * dev,char * command,int total_len)9848 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
9849 {
9850 	int bytes_written = 0;
9851 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9852 	int err = BCME_OK;
9853 	int size;
9854 
9855 	if (!dhdp || !dhdp->pktlog) {
9856 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9857 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9858 		return -EINVAL;
9859 	}
9860 
9861 	if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
9862 		return BCME_ERROR;
9863 	}
9864 
9865 	size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
9866 
9867 	dhdp->pktlog->pktlog_ring =
9868 		dhd_pktlog_ring_change_size(dhdp->pktlog->pktlog_ring, size);
9869 	if (!dhdp->pktlog->pktlog_ring) {
9870 		err = BCME_ERROR;
9871 	}
9872 
9873 	if (err == BCME_OK) {
9874 		bytes_written = snprintf(command, total_len, "OK");
9875 		ANDROID_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
9876 	} else {
9877 		ANDROID_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
9878 		return BCME_ERROR;
9879 	}
9880 
9881 	return bytes_written;
9882 }
9883 
9884 static int
wl_android_pktlog_dbg_dump(struct net_device * dev,char * command,int total_len)9885 wl_android_pktlog_dbg_dump(struct net_device *dev, char *command, int total_len)
9886 {
9887 	int bytes_written = 0;
9888 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9889 	int err = BCME_OK;
9890 
9891 	if (!dhdp || !dhdp->pktlog) {
9892 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9893 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9894 		return -EINVAL;
9895 	}
9896 
9897 	if (strlen(CMD_PKTLOG_DEBUG_DUMP) + 1 > total_len) {
9898 		return BCME_ERROR;
9899 	}
9900 
9901 	err = dhd_pktlog_debug_dump(dhdp);
9902 	if (err == BCME_OK) {
9903 		bytes_written = snprintf(command, total_len, "OK");
9904 		ANDROID_INFO(("%s: pktlog dbg dump success\n", __FUNCTION__));
9905 	} else {
9906 		ANDROID_ERROR(("%s: pktlog dbg dump fail\n", __FUNCTION__));
9907 		return BCME_ERROR;
9908 	}
9909 
9910 	return bytes_written;
9911 }
9912 #endif /* DHD_PKT_LOGGING */
9913 
9914 #if defined(CONFIG_TIZEN)
wl_android_set_powersave_mode(struct net_device * dev,char * command,int total_len)9915 static int wl_android_set_powersave_mode(
9916 	struct net_device *dev, char* command, int total_len)
9917 {
9918 	int pm;
9919 
9920 	int err = BCME_OK;
9921 #ifdef DHD_PM_OVERRIDE
9922 	extern bool g_pm_override;
9923 #endif /* DHD_PM_OVERRIDE */
9924 	sscanf(command, "%*s %10d", &pm);
9925 	if (pm < PM_OFF || pm > PM_FAST) {
9926 		ANDROID_ERROR(("check pm=%d\n", pm));
9927 		return BCME_ERROR;
9928 	}
9929 
9930 #ifdef DHD_PM_OVERRIDE
9931 	if (pm > PM_OFF) {
9932 		g_pm_override = FALSE;
9933 	}
9934 #endif /* DHD_PM_OVERRIDE */
9935 
9936 	err =  wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
9937 
9938 #ifdef DHD_PM_OVERRIDE
9939 	if (pm == PM_OFF) {
9940 		g_pm_override = TRUE;
9941 	}
9942 
9943 	ANDROID_ERROR(("%s: PM:%d, pm_override=%d\n", __FUNCTION__, pm, g_pm_override));
9944 #endif /* DHD_PM_OVERRIDE */
9945 	return err;
9946 }
9947 
wl_android_get_powersave_mode(struct net_device * dev,char * command,int total_len)9948 static int wl_android_get_powersave_mode(
9949 	struct net_device *dev, char *command, int total_len)
9950 {
9951 	int err, bytes_written;
9952 	int pm;
9953 
9954 	err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
9955 	if (err != BCME_OK) {
9956 		ANDROID_ERROR(("failed to get pm (%d)", err));
9957 		return err;
9958 	}
9959 
9960 	bytes_written = snprintf(command, total_len, "%s %d",
9961 		CMD_POWERSAVEMODE_GET, pm);
9962 
9963 	return bytes_written;
9964 }
9965 #endif /* CONFIG_TIZEN */
9966 
9967 #ifdef DHD_EVENT_LOG_FILTER
9968 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
9969 
9970 #ifdef DHD_EWPR_VER2
9971 uint32 dhd_event_log_filter_serialize_bit(dhd_pub_t *dhdp, char *buf, uint32 tot_len,
9972 	int index1, int index2, int index3);
9973 #endif
9974 
9975 static int
wl_android_ewp_filter(struct net_device * dev,char * command,uint32 tot_len)9976 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
9977 {
9978 	uint32 bytes_written = 0;
9979 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9980 #ifdef DHD_EWPR_VER2
9981 	int index1 = 0, index2 = 0, index3 = 0;
9982 	unsigned char *index_str = (unsigned char *)(command +
9983 		strlen(CMD_EWP_FILTER) + 1);
9984 #else
9985 	int type = 0;
9986 #endif
9987 
9988 	if (!dhdp || !command) {
9989 		ANDROID_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
9990 		return -EINVAL;
9991 	}
9992 
9993 	if (!FW_SUPPORTED(dhdp, ecounters)) {
9994 		ANDROID_ERROR(("does not support ecounters!\n"));
9995 		return BCME_UNSUPPORTED;
9996 	}
9997 
9998 #ifdef DHD_EWPR_VER2
9999 	if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) {
10000 		sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3);
10001 		ANDROID_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__,
10002 			index1, index2, index3));
10003 	}
10004 	bytes_written += dhd_event_log_filter_serialize_bit(dhdp,
10005 		&command[bytes_written], tot_len - bytes_written, index1, index2, index3);
10006 #else
10007 	/* NEED TO GET TYPE if EXIST */
10008 	type = 0;
10009 
10010 	bytes_written += dhd_event_log_filter_serialize(dhdp,
10011 		&command[bytes_written], tot_len - bytes_written, type);
10012 #endif
10013 
10014 	return (int)bytes_written;
10015 }
10016 #endif /* DHD_EVENT_LOG_FILTER */
10017 
10018 #ifdef SUPPORT_AP_SUSPEND
10019 int
wl_android_set_ap_suspend(struct net_device * dev,char * command,int total_len)10020 wl_android_set_ap_suspend(struct net_device *dev, char *command, int total_len)
10021 {
10022 	int suspend = 0;
10023 	char *pos, *token;
10024 	char *ifname = NULL;
10025 	int err = BCME_OK;
10026 	char name[IFNAMSIZ];
10027 
10028 	/*
10029 	 * DRIVER SET_AP_SUSPEND <0/1> <ifname>
10030 	 */
10031 	pos = command;
10032 
10033 	/* drop command */
10034 	token = bcmstrtok(&pos, " ", NULL);
10035 
10036 	/* Enable */
10037 	token = bcmstrtok(&pos, " ", NULL);
10038 	if (!token) {
10039 		return -EINVAL;
10040 	}
10041 	suspend = bcm_atoi(token);
10042 
10043 	/* get the interface name */
10044 	token = bcmstrtok(&pos, " ", NULL);
10045 	if (!token) {
10046 		return -EINVAL;
10047 	}
10048 	ifname = token;
10049 
10050 	strlcpy(name, ifname, sizeof(name));
10051 	ANDROID_INFO(("suspend %d, ifacename %s\n", suspend, name));
10052 
10053 	err = wl_set_ap_suspend(dev, suspend? TRUE: FALSE, name);
10054 	if (unlikely(err)) {
10055 		ANDROID_ERROR(("Failed to set suspend, suspend %d, error = %d\n", suspend, err));
10056 	}
10057 
10058 	return err;
10059 }
10060 #endif /* SUPPORT_AP_SUSPEND */
10061 
10062 #ifdef SUPPORT_AP_BWCTRL
10063 int
wl_android_set_ap_bw(struct net_device * dev,char * command,int total_len)10064 wl_android_set_ap_bw(struct net_device *dev, char *command, int total_len)
10065 {
10066 	int bw = DOT11_OPER_MODE_20MHZ;
10067 	char *pos, *token;
10068 	char *ifname = NULL;
10069 	int err = BCME_OK;
10070 	char name[IFNAMSIZ];
10071 
10072 	/*
10073 	 * DRIVER SET_AP_BW <0/1/2> <ifname>
10074 	 * 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10075 	 * This is from operating mode field
10076 	 * in 8.4.1.50 of 802.11ac-2013
10077 	 */
10078 	pos = command;
10079 
10080 	/* drop command */
10081 	token = bcmstrtok(&pos, " ", NULL);
10082 
10083 	/* BW */
10084 	token = bcmstrtok(&pos, " ", NULL);
10085 	if (!token) {
10086 		return -EINVAL;
10087 	}
10088 	bw = bcm_atoi(token);
10089 
10090 	/* get the interface name */
10091 	token = bcmstrtok(&pos, " ", NULL);
10092 	if (!token) {
10093 		return -EINVAL;
10094 	}
10095 	ifname = token;
10096 
10097 	strlcpy(name, ifname, sizeof(name));
10098 	ANDROID_INFO(("bw %d, ifacename %s\n", bw, name));
10099 
10100 	err = wl_set_ap_bw(dev, bw, name);
10101 	if (unlikely(err)) {
10102 		ANDROID_ERROR(("Failed to set bw, bw %d, error = %d\n", bw, err));
10103 	}
10104 
10105 	return err;
10106 }
10107 
10108 int
wl_android_get_ap_bw(struct net_device * dev,char * command,int total_len)10109 wl_android_get_ap_bw(struct net_device *dev, char *command, int total_len)
10110 {
10111 	char *pos, *token;
10112 	char *ifname = NULL;
10113 	int bytes_written = 0;
10114 	char name[IFNAMSIZ];
10115 
10116 	/*
10117 	 * DRIVER GET_AP_BW <ifname>
10118 	 * returns 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10119 	 * This is from operating mode field
10120 	 * in 8.4.1.50 of 802.11ac-2013
10121 	 */
10122 	pos = command;
10123 
10124 	/* drop command */
10125 	token = bcmstrtok(&pos, " ", NULL);
10126 
10127 	/* get the interface name */
10128 	token = bcmstrtok(&pos, " ", NULL);
10129 	if (!token) {
10130 		return -EINVAL;
10131 	}
10132 	ifname = token;
10133 
10134 	strlcpy(name, ifname, sizeof(name));
10135 	ANDROID_INFO(("ifacename %s\n", name));
10136 
10137 	bytes_written = wl_get_ap_bw(dev, command, name, total_len);
10138 	if (bytes_written < 1) {
10139 		ANDROID_ERROR(("Failed to get bw, error = %d\n", bytes_written));
10140 		return -EPROTO;
10141 	}
10142 
10143 	return bytes_written;
10144 
10145 }
10146 #endif /* SUPPORT_AP_BWCTRL */
10147 
10148 static int
wl_android_priv_cmd_log_enable_check(char * cmd)10149 wl_android_priv_cmd_log_enable_check(char* cmd)
10150 {
10151 	int cnt = 0;
10152 
10153 	while (strlen(loging_params[cnt].command) > 0) {
10154 		if (!strnicmp(cmd, loging_params[cnt].command,
10155 			strlen(loging_params[cnt].command))) {
10156 			return loging_params[cnt].enable;
10157 		}
10158 
10159 		cnt++;
10160 	}
10161 
10162 	return FALSE;
10163 }
10164 
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr)10165 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
10166 {
10167 #define PRIVATE_COMMAND_MAX_LEN	8192
10168 #define PRIVATE_COMMAND_DEF_LEN	4096
10169 	int ret = 0;
10170 	char *command = NULL;
10171 	int bytes_written = 0;
10172 	android_wifi_priv_cmd priv_cmd;
10173 	int buf_size = 0;
10174 	dhd_pub_t *dhd = dhd_get_pub(net);
10175 
10176 	net_os_wake_lock(net);
10177 
10178 	if (!capable(CAP_NET_ADMIN)) {
10179 		ret = -EPERM;
10180 		goto exit;
10181 	}
10182 
10183 	if (!ifr->ifr_data) {
10184 		ret = -EINVAL;
10185 		goto exit;
10186 	}
10187 
10188 #ifdef CONFIG_COMPAT
10189 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
10190 	if (in_compat_syscall())
10191 #else
10192 	if (is_compat_task())
10193 #endif
10194 	{
10195 		compat_android_wifi_priv_cmd compat_priv_cmd;
10196 		if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
10197 			sizeof(compat_android_wifi_priv_cmd))) {
10198 			ret = -EFAULT;
10199 			goto exit;
10200 
10201 		}
10202 		priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
10203 		priv_cmd.used_len = compat_priv_cmd.used_len;
10204 		priv_cmd.total_len = compat_priv_cmd.total_len;
10205 	} else
10206 #endif /* CONFIG_COMPAT */
10207 	{
10208 		if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
10209 			ret = -EFAULT;
10210 			goto exit;
10211 		}
10212 	}
10213 	if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
10214 		ANDROID_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
10215 			priv_cmd.total_len));
10216 		ret = -EINVAL;
10217 		goto exit;
10218 	}
10219 
10220 	buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
10221 	command = (char *)MALLOC(dhd->osh, (buf_size + 1));
10222 	if (!command) {
10223 		ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
10224 		ret = -ENOMEM;
10225 		goto exit;
10226 	}
10227 	if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
10228 		ret = -EFAULT;
10229 		goto exit;
10230 	}
10231 	command[priv_cmd.total_len] = '\0';
10232 
10233 	if (wl_android_priv_cmd_log_enable_check(command)) {
10234 		ANDROID_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__,
10235 			command, ifr->ifr_name));
10236 	}
10237 	else {
10238 		ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
10239 
10240 	}
10241 
10242 	bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
10243 	if (bytes_written >= 0) {
10244 		if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
10245 			command[0] = '\0';
10246 		}
10247 		if (bytes_written >= priv_cmd.total_len) {
10248 			ANDROID_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
10249 				__FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
10250 
10251 			ret = BCME_BUFTOOSHORT;
10252 			goto exit;
10253 		}
10254 		bytes_written++;
10255 		priv_cmd.used_len = bytes_written;
10256 		if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
10257 			ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
10258 			ret = -EFAULT;
10259 		}
10260 	}
10261 	else {
10262 		/* Propagate the error */
10263 		ret = bytes_written;
10264 	}
10265 
10266 exit:
10267 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
10268 	if (ret) {
10269 		/* Avoid incrementing priv_cmd_errors in case of unsupported feature */
10270 		if (ret != BCME_UNSUPPORTED) {
10271 			wl_android_check_priv_cmd_errors(net);
10272 		}
10273 	} else {
10274 		priv_cmd_errors = 0;
10275 	}
10276 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
10277 	net_os_wake_unlock(net);
10278 	MFREE(dhd->osh, command, (buf_size + 1));
10279 	return ret;
10280 }
10281 
10282 #ifdef WLADPS_PRIVATE_CMD
10283 static int
wl_android_set_adps_mode(struct net_device * dev,const char * string_num)10284 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
10285 {
10286 	int err = 0, adps_mode;
10287 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10288 #ifdef DHD_PM_CONTROL_FROM_FILE
10289 	if (g_pm_control) {
10290 		return -EPERM;
10291 	}
10292 #endif	/* DHD_PM_CONTROL_FROM_FILE */
10293 
10294 	adps_mode = bcm_atoi(string_num);
10295 	ANDROID_ERROR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
10296 
10297 	if (!(adps_mode == 0 || adps_mode == 1)) {
10298 		ANDROID_ERROR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode));
10299 		return -EINVAL;
10300 	}
10301 
10302 	err = dhd_enable_adps(dhdp, adps_mode);
10303 	if (err != BCME_OK) {
10304 		ANDROID_ERROR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
10305 		return -EIO;
10306 	}
10307 	return err;
10308 }
10309 static int
wl_android_get_adps_mode(struct net_device * dev,char * command,int total_len)10310 wl_android_get_adps_mode(
10311 	struct net_device *dev, char *command, int total_len)
10312 {
10313 	int bytes_written, err = 0;
10314 	uint len;
10315 	char buf[WLC_IOCTL_SMLEN];
10316 
10317 	bcm_iov_buf_t iov_buf;
10318 	bcm_iov_buf_t *ptr = NULL;
10319 	wl_adps_params_v1_t *data = NULL;
10320 
10321 	uint8 *pdata = NULL;
10322 	uint8 band, mode = 0;
10323 
10324 	bzero(&iov_buf, sizeof(iov_buf));
10325 
10326 	len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
10327 
10328 	iov_buf.version = WL_ADPS_IOV_VER;
10329 	iov_buf.len = sizeof(band);
10330 	iov_buf.id = WL_ADPS_IOV_MODE;
10331 
10332 	pdata = (uint8 *)&iov_buf.data;
10333 
10334 	for (band = 1; band <= MAX_BANDS; band++) {
10335 		pdata[0] = band;
10336 		err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
10337 			buf, WLC_IOCTL_SMLEN, NULL);
10338 		if (err != BCME_OK) {
10339 			ANDROID_ERROR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n",
10340 					band, err));
10341 			return -EIO;
10342 		}
10343 		ptr = (bcm_iov_buf_t *) buf;
10344 		data = (wl_adps_params_v1_t *) ptr->data;
10345 		mode = data->mode;
10346 		if (mode != OFF) {
10347 			break;
10348 		}
10349 	}
10350 
10351 	bytes_written = snprintf(command, total_len, "%s %d",
10352 		CMD_GET_ADPS, mode);
10353 	return bytes_written;
10354 }
10355 
10356 #ifdef WLADPS_ENERGY_GAIN
10357 static int
wl_android_get_gain_adps(struct net_device * dev,char * command,int total_len)10358 wl_android_get_gain_adps(
10359 	struct net_device *dev, char *command, int total_len)
10360 {
10361 	int bytes_written;
10362 
10363 	int ret = 0;
10364 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10365 
10366 	ret = dhd_event_log_filter_adps_energy_gain(dhdp);
10367 	if (ret < 0) {
10368 		return ret;
10369 	}
10370 
10371 	ANDROID_INFO(("%s ADPS Energy Gain: %d uAh\n", __FUNCTION__, ret));
10372 
10373 	bytes_written = snprintf(command, total_len, "%s %d uAm",
10374 		CMD_GET_GAIN_ADPS, ret);
10375 
10376 	return bytes_written;
10377 }
10378 
10379 static int
wl_android_reset_gain_adps(struct net_device * dev,char * command)10380 wl_android_reset_gain_adps(
10381 	struct net_device *dev, char *command)
10382 {
10383 	int ret = BCME_OK;
10384 
10385 	bcm_iov_buf_t iov_buf;
10386 	char buf[WLC_IOCTL_SMLEN] = {0, };
10387 
10388 	iov_buf.version = WL_ADPS_IOV_VER;
10389 	iov_buf.id = WL_ADPS_IOV_RESET_GAIN;
10390 	iov_buf.len = 0;
10391 
10392 	if ((ret = wldev_iovar_setbuf(dev, "adps", &iov_buf, sizeof(iov_buf),
10393 		buf, sizeof(buf), NULL)) < 0) {
10394 		ANDROID_ERROR(("%s fail to reset adps gain (%d)\n", __FUNCTION__, ret));
10395 	}
10396 
10397 	return ret;
10398 }
10399 #endif	/* WLADPS_ENERGY_GAIN */
10400 #endif /* WLADPS_PRIVATE_CMD */
10401 
10402 #ifdef WL_BCNRECV
10403 #define BCNRECV_ATTR_HDR_LEN 30
10404 int
wl_android_bcnrecv_event(struct net_device * ndev,uint attr_type,uint status,uint reason,uint8 * data,uint data_len)10405 wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
10406 		uint status, uint reason, uint8 *data, uint data_len)
10407 {
10408 	s32 err = BCME_OK;
10409 	struct sk_buff *skb;
10410 	gfp_t kflags;
10411 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10412 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10413 	uint len;
10414 
10415 	len = BCNRECV_ATTR_HDR_LEN + data_len;
10416 
10417 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10418 	skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
10419 		BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
10420 	if (!skb) {
10421 		ANDROID_ERROR(("skb alloc failed"));
10422 		return -ENOMEM;
10423 	}
10424 	if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
10425 		/* send bcn info to upper layer */
10426 		nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
10427 	} else if (attr_type == BCNRECV_ATTR_STATUS) {
10428 		nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
10429 		if (reason) {
10430 			nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
10431 		}
10432 	} else {
10433 		ANDROID_ERROR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
10434 		kfree_skb(skb);
10435 		return -EINVAL;
10436 	}
10437 	cfg80211_vendor_event(skb, kflags);
10438 	return err;
10439 }
10440 
10441 static int
_wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool user_trigger)10442 _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
10443 {
10444 	s32 err = BCME_OK;
10445 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10446 
10447 	/* check any scan is in progress before beacon recv scan trigger IOVAR */
10448 	if (wl_get_drv_status_all(cfg, SCANNING)) {
10449 		err = BCME_UNSUPPORTED;
10450 		ANDROID_ERROR(("Scan in progress, Aborting beacon recv start, "
10451 			"error:%d\n", err));
10452 		goto exit;
10453 	}
10454 
10455 	if (wl_get_p2p_status(cfg, SCANNING)) {
10456 		err = BCME_UNSUPPORTED;
10457 		ANDROID_ERROR(("P2P Scan in progress, Aborting beacon recv start, "
10458 			"error:%d\n", err));
10459 		goto exit;
10460 	}
10461 
10462 	if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
10463 		err = BCME_UNSUPPORTED;
10464 		ANDROID_ERROR(("P2P remain on channel, Aborting beacon recv start, "
10465 			"error:%d\n", err));
10466 		goto exit;
10467 	}
10468 
10469 	/* check STA is in connected state, Beacon recv required connected state
10470 	 * else exit from beacon recv scan
10471 	 */
10472 	if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
10473 		err = BCME_UNSUPPORTED;
10474 		ANDROID_ERROR(("STA is in not associated state error:%d\n", err));
10475 		goto exit;
10476 	}
10477 
10478 #ifdef WL_NAN
10479 	/* Check NAN is enabled, if enabled exit else continue */
10480 	if (wl_cfgnan_is_enabled(cfg)) {
10481 		err = BCME_UNSUPPORTED;
10482 		ANDROID_ERROR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
10483 		goto exit;
10484 	}
10485 #endif /* WL_NAN */
10486 
10487 	/* Triggering an sendup_bcn iovar */
10488 	err = wldev_iovar_setint(pdev, "sendup_bcn", 1);
10489 	if (unlikely(err)) {
10490 		ANDROID_ERROR(("sendup_bcn failed to set, error:%d\n", err));
10491 	} else {
10492 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
10493 		ANDROID_INFO(("bcnrecv started. user_trigger:%d ifindex:%d\n",
10494 			user_trigger, ndev->ifindex));
10495 		if (user_trigger) {
10496 			if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS,
10497 					WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
10498 				ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10499 			}
10500 		}
10501 	}
10502 exit:
10503 	/*
10504 	 * BCNRECV start request can be rejected from dongle
10505 	 * in various conditions.
10506 	 * Error code need to be overridden to BCME_UNSUPPORTED
10507 	 * to avoid hang event from continous private
10508 	 * command error
10509 	 */
10510 	if (err) {
10511 		err = BCME_UNSUPPORTED;
10512 	}
10513 	return err;
10514 }
10515 
10516 int
_wl_android_bcnrecv_stop(struct bcm_cfg80211 * cfg,struct net_device * ndev,uint reason)10517 _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
10518 {
10519 	s32 err = BCME_OK;
10520 	u32 status;
10521 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10522 
10523 	/* Stop bcnrx except for fw abort event case */
10524 	if (reason != WL_BCNRECV_ROAMABORT) {
10525 		err = wldev_iovar_setint(pdev, "sendup_bcn", 0);
10526 		if (unlikely(err)) {
10527 			ANDROID_ERROR(("sendup_bcn failed to set error:%d\n", err));
10528 			goto exit;
10529 		}
10530 	}
10531 
10532 	/* Send notification for all cases */
10533 	if (reason == WL_BCNRECV_SUSPEND) {
10534 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
10535 		status = WL_BCNRECV_SUSPENDED;
10536 	} else {
10537 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
10538 		ANDROID_INFO(("bcnrecv stopped. reason:%d ifindex:%d\n",
10539 			reason, ndev->ifindex));
10540 		if (reason == WL_BCNRECV_USER_TRIGGER) {
10541 			status = WL_BCNRECV_STOPPED;
10542 		} else {
10543 			status = WL_BCNRECV_ABORTED;
10544 		}
10545 	}
10546 	if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, status,
10547 			reason, NULL, 0)) != BCME_OK) {
10548 		ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10549 	}
10550 exit:
10551 	return err;
10552 }
10553 
10554 static int
wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev)10555 wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
10556 {
10557 	s32 err = BCME_OK;
10558 
10559 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10560 	mutex_lock(&cfg->scan_sync);
10561 	mutex_lock(&cfg->bcn_sync);
10562 	err = _wl_android_bcnrecv_start(cfg, ndev, true);
10563 	mutex_unlock(&cfg->bcn_sync);
10564 	mutex_unlock(&cfg->scan_sync);
10565 	return err;
10566 }
10567 
10568 int
wl_android_bcnrecv_stop(struct net_device * ndev,uint reason)10569 wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
10570 {
10571 	s32 err = BCME_OK;
10572 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10573 
10574 	mutex_lock(&cfg->bcn_sync);
10575 	if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
10576 	   (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
10577 		err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
10578 	}
10579 	mutex_unlock(&cfg->bcn_sync);
10580 	return err;
10581 }
10582 
10583 int
wl_android_bcnrecv_suspend(struct net_device * ndev)10584 wl_android_bcnrecv_suspend(struct net_device *ndev)
10585 {
10586 	s32 ret = BCME_OK;
10587 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10588 
10589 	mutex_lock(&cfg->bcn_sync);
10590 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
10591 		ANDROID_INFO(("bcnrecv suspend\n"));
10592 		ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
10593 	}
10594 	mutex_unlock(&cfg->bcn_sync);
10595 	return ret;
10596 }
10597 
10598 int
wl_android_bcnrecv_resume(struct net_device * ndev)10599 wl_android_bcnrecv_resume(struct net_device *ndev)
10600 {
10601 	s32 ret = BCME_OK;
10602 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10603 
10604 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10605 	mutex_lock(&cfg->scan_sync);
10606 	mutex_lock(&cfg->bcn_sync);
10607 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
10608 		ANDROID_INFO(("bcnrecv resume\n"));
10609 		ret = _wl_android_bcnrecv_start(cfg, ndev, false);
10610 	}
10611 	mutex_unlock(&cfg->bcn_sync);
10612 	mutex_unlock(&cfg->scan_sync);
10613 	return ret;
10614 }
10615 
10616 /* Beacon recv functionality code implementation */
10617 int
wl_android_bcnrecv_config(struct net_device * ndev,char * cmd_argv,int total_len)10618 wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
10619 {
10620 	struct bcm_cfg80211 *cfg = NULL;
10621 	uint err = BCME_OK;
10622 
10623 	if (!ndev) {
10624 		ANDROID_ERROR(("ndev is NULL\n"));
10625 		return -EINVAL;
10626 	}
10627 
10628 	cfg = wl_get_cfg(ndev);
10629 	if (!cfg) {
10630 		ANDROID_ERROR(("cfg is NULL\n"));
10631 		return -EINVAL;
10632 	}
10633 
10634 	/* sync commands from user space */
10635 	mutex_lock(&cfg->usr_sync);
10636 	if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
10637 		ANDROID_INFO(("BCNRECV start\n"));
10638 		err = wl_android_bcnrecv_start(cfg, ndev);
10639 		if (err != BCME_OK) {
10640 			ANDROID_ERROR(("Failed to process the start command, error:%d\n", err));
10641 			goto exit;
10642 		}
10643 	} else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
10644 		ANDROID_INFO(("BCNRECV stop\n"));
10645 		err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
10646 		if (err != BCME_OK) {
10647 			ANDROID_ERROR(("Failed to stop the bcn recv, error:%d\n", err));
10648 			goto exit;
10649 		}
10650 	} else {
10651 		err = BCME_ERROR;
10652 	}
10653 exit:
10654 	mutex_unlock(&cfg->usr_sync);
10655 	return err;
10656 }
10657 #endif /* WL_BCNRECV */
10658 
10659 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
10660 static int
wl_android_set_latency_crt_data(struct net_device * dev,int mode)10661 wl_android_set_latency_crt_data(struct net_device *dev, int mode)
10662 {
10663 	int ret;
10664 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10665 	dhd_pub_t *dhdp = NULL;
10666 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10667 	if (mode >= LATENCY_CRT_DATA_MODE_LAST) {
10668 		return BCME_BADARG;
10669 	}
10670 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10671 	dhdp = wl_cfg80211_get_dhdp(dev);
10672 	if (mode != LATENCY_CRT_DATA_MODE_OFF) {
10673 		ANDROID_ERROR(("Not permitted GRO by framework\n"));
10674 		dhdp->permitted_gro = FALSE;
10675 	} else {
10676 		ANDROID_ERROR(("Permitted GRO by framework\n"));
10677 		dhdp->permitted_gro = TRUE;
10678 	}
10679 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10680 	ret = wldev_iovar_setint(dev, "latency_critical_data", mode);
10681 	if (ret != BCME_OK) {
10682 		ANDROID_ERROR(("failed to set latency_critical_data mode %d, error = %d\n",
10683 			mode, ret));
10684 		return ret;
10685 	}
10686 
10687 	return ret;
10688 }
10689 
10690 static int
wl_android_get_latency_crt_data(struct net_device * dev,char * command,int total_len)10691 wl_android_get_latency_crt_data(struct net_device *dev, char *command, int total_len)
10692 {
10693 	int ret;
10694 	int mode = LATENCY_CRT_DATA_MODE_OFF;
10695 	int bytes_written;
10696 
10697 	ret = wldev_iovar_getint(dev, "latency_critical_data", &mode);
10698 	if (ret != BCME_OK) {
10699 		ANDROID_ERROR(("failed to get latency_critical_data error = %d\n", ret));
10700 		return ret;
10701 	}
10702 
10703 	bytes_written = snprintf(command, total_len, "%s %d",
10704 		CMD_GET_LATENCY_CRITICAL_DATA, mode);
10705 
10706 	return bytes_written;
10707 }
10708 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
10709 
10710 #ifdef WL_CAC_TS
10711 /* CAC TSPEC functionality code implementation */
10712 static void
wl_android_update_tsinfo(uint8 access_category,tspec_arg_t * tspec_arg)10713 wl_android_update_tsinfo(uint8 access_category, tspec_arg_t *tspec_arg)
10714 {
10715 	uint8 tspec_id;
10716 	/* Using direction as bidirectional by default */
10717 	uint8 direction = TSPEC_BI_DIRECTION;
10718 	/* Using U-APSD as the default power save mode */
10719 	uint8 user_psb = TSPEC_UAPSD_PSB;
10720 	uint8 ADDTS_AC2PRIO[4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI, PRIO_8021D_VO};
10721 
10722 	/* Map tspec_id from access category */
10723 	tspec_id = ADDTS_AC2PRIO[access_category];
10724 
10725 	/* Update the tsinfo */
10726 	tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
10727 		(tspec_id << TSPEC_TSINFO_TID_SHIFT));
10728 	tspec_arg->tsinfo.octets[1] = (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) |
10729 		user_psb);
10730 	tspec_arg->tsinfo.octets[2] = 0x00;
10731 }
10732 
10733 static s32
wl_android_handle_cac_action(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * argv)10734 wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev, char * argv)
10735 {
10736 	tspec_arg_t tspec_arg;
10737 	s32 err = BCME_ERROR;
10738 	u8 ts_cmd[12] = "cac_addts";
10739 	uint8 access_category;
10740 	s32 bssidx;
10741 
10742 	/* Following handling is done only for the primary interface */
10743 	memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
10744 	if (strncmp(argv, "addts", strlen("addts")) == 0) {
10745 		tspec_arg.version = TSPEC_ARG_VERSION;
10746 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10747 		/* Read the params passed */
10748 		sscanf(argv, "%*s %hhu %hu %hu", &access_category,
10749 			&tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
10750 		if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
10751 			((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
10752 			(tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
10753 			(tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
10754 			ANDROID_ERROR(("Invalid params access_category %hhu nom_msdu_size %hu"
10755 				" surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size,
10756 				tspec_arg.surplus_bw));
10757 			return BCME_USAGE_ERROR;
10758 		}
10759 
10760 		/* Update tsinfo */
10761 		wl_android_update_tsinfo(access_category, &tspec_arg);
10762 		/* Update other tspec parameters */
10763 		tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
10764 		tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
10765 		tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
10766 	} else if (strncmp(argv, "delts", strlen("delts")) == 0) {
10767 		snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
10768 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10769 		tspec_arg.version = TSPEC_ARG_VERSION;
10770 		/* Read the params passed */
10771 		sscanf(argv, "%*s %hhu", &access_category);
10772 
10773 		if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
10774 			ANDROID_INFO(("Invalide param, access_category %hhu\n", access_category));
10775 			return BCME_USAGE_ERROR;
10776 		}
10777 		/* Update tsinfo */
10778 		wl_android_update_tsinfo(access_category, &tspec_arg);
10779 	}
10780 
10781 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
10782 		ANDROID_ERROR(("Find index failed\n"));
10783 		err = BCME_ERROR;
10784 		return err;
10785 	}
10786 	err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
10787 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
10788 	if (unlikely(err)) {
10789 		ANDROID_ERROR(("%s error (%d)\n", ts_cmd, err));
10790 	}
10791 
10792 	return err;
10793 }
10794 
10795 static s32
wl_android_cac_ts_config(struct net_device * ndev,char * cmd_argv,int total_len)10796 wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len)
10797 {
10798 	struct bcm_cfg80211 *cfg = NULL;
10799 	s32 err = BCME_OK;
10800 
10801 	if (!ndev) {
10802 		ANDROID_ERROR(("ndev is NULL\n"));
10803 		return -EINVAL;
10804 	}
10805 
10806 	cfg = wl_get_cfg(ndev);
10807 	if (!cfg) {
10808 		ANDROID_ERROR(("cfg is NULL\n"));
10809 		return -EINVAL;
10810 	}
10811 
10812 	/* Request supported only for primary interface */
10813 	if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
10814 		ANDROID_ERROR(("Request on non-primary interface\n"));
10815 		return -1;
10816 	}
10817 
10818 	/* sync commands from user space */
10819 	mutex_lock(&cfg->usr_sync);
10820 	err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
10821 	mutex_unlock(&cfg->usr_sync);
10822 
10823 	return err;
10824 }
10825 #endif /* WL_CAC_TS */
10826 
10827 #ifdef WL_GET_CU
10828 /* Implementation to get channel usage from framework */
10829 static s32
wl_android_get_channel_util(struct net_device * ndev,char * command,int total_len)10830 wl_android_get_channel_util(struct net_device *ndev, char *command, int total_len)
10831 {
10832 	s32 bytes_written, err = 0;
10833 	wl_bssload_t bssload;
10834 	u8 smbuf[WLC_IOCTL_SMLEN];
10835 	u8 chan_use_percentage = 0;
10836 
10837 	if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL,
10838 		0, smbuf, WLC_IOCTL_SMLEN, NULL))) {
10839 		ANDROID_ERROR(("Getting bssload report failed with err=%d \n", err));
10840 		return err;
10841 	}
10842 
10843 	(void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
10844 	/* Convert channel usage to percentage value */
10845 	chan_use_percentage = (bssload.chan_util * 100) / 255;
10846 
10847 	bytes_written = snprintf(command, total_len, "CU %hhu",
10848 		chan_use_percentage);
10849 	ANDROID_INFO(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage));
10850 
10851 	return bytes_written;
10852 }
10853 #endif /* WL_GET_CU */
10854 
10855 #ifdef RTT_GEOFENCE_INTERVAL
10856 #if defined (RTT_SUPPORT) && defined(WL_NAN)
10857 static void
wl_android_set_rtt_geofence_interval(struct net_device * ndev,char * command)10858 wl_android_set_rtt_geofence_interval(struct net_device *ndev, char *command)
10859 {
10860 	int rtt_interval = 0;
10861 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
10862 	char *rtt_intp = command + strlen(CMD_GEOFENCE_INTERVAL) + 1;
10863 
10864 	rtt_interval = bcm_atoi(rtt_intp);
10865 	dhd_rtt_set_geofence_rtt_interval(dhdp, rtt_interval);
10866 }
10867 #endif /* RTT_SUPPORT && WL_NAN */
10868 #endif /* RTT_GEOFENCE_INTERVAL */
10869 
10870 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
10871 int
wl_android_set_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10872 wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10873 {
10874 	char *ifname = NULL;
10875 	char *pos, *token;
10876 	int err = BCME_OK;
10877 	int enable = FALSE;
10878 
10879 	/*
10880 	 * STA/AP/GO I/F: DRIVER SET_SOFTAP_ELNA_BYPASS <ifname> <enable/disable>
10881 	 * the enable/disable format follows Samsung specific rules as following
10882 	 * Enable : 0
10883 	 * Disable :-1
10884 	 */
10885 	pos = command;
10886 
10887 	/* drop command */
10888 	token = bcmstrtok(&pos, " ", NULL);
10889 
10890 	/* get the interface name */
10891 	token = bcmstrtok(&pos, " ", NULL);
10892 	if (!token) {
10893 		ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10894 		return -EINVAL;
10895 	}
10896 	ifname = token;
10897 
10898 	/* get enable/disable flag */
10899 	token = bcmstrtok(&pos, " ", NULL);
10900 	if (!token) {
10901 		ANDROID_ERROR(("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__));
10902 		return -EINVAL;
10903 	}
10904 	enable = bcm_atoi(token);
10905 
10906 	CUSTOMER_HW4_EN_CONVERT(enable);
10907 	err = wl_set_softap_elna_bypass(dev, ifname, enable);
10908 	if (unlikely(err)) {
10909 		ANDROID_ERROR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n",
10910 			__FUNCTION__, err));
10911 		return err;
10912 	}
10913 
10914 	return err;
10915 }
10916 
10917 int
wl_android_get_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10918 wl_android_get_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10919 {
10920 	char *ifname = NULL;
10921 	char *pos, *token;
10922 	int err = BCME_OK;
10923 	int bytes_written = 0;
10924 	int softap_elnabypass = 0;
10925 
10926 	/*
10927 	 * STA/AP/GO I/F: DRIVER GET_SOFTAP_ELNA_BYPASS <ifname>
10928 	 */
10929 	pos = command;
10930 
10931 	/* drop command */
10932 	token = bcmstrtok(&pos, " ", NULL);
10933 
10934 	/* get the interface name */
10935 	token = bcmstrtok(&pos, " ", NULL);
10936 	if (!token) {
10937 		ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10938 		return -EINVAL;
10939 	}
10940 	ifname = token;
10941 
10942 	err = wl_get_softap_elna_bypass(dev, ifname, &softap_elnabypass);
10943 	if (unlikely(err)) {
10944 		ANDROID_ERROR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n",
10945 			__FUNCTION__, err));
10946 		return err;
10947 	} else {
10948 		softap_elnabypass--; //Convert format to Customer HW4
10949 		ANDROID_INFO(("%s: eLNA Bypass feature enable status is %d\n",
10950 			__FUNCTION__, softap_elnabypass));
10951 		bytes_written = snprintf(command, total_len, "%s %d",
10952 			CMD_GET_SOFTAP_ELNA_BYPASS, softap_elnabypass);
10953 	}
10954 
10955 	return bytes_written;
10956 }
10957 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
10958 
10959 #ifdef WL_NAN
10960 int
wl_android_get_nan_status(struct net_device * dev,char * command,int total_len)10961 wl_android_get_nan_status(struct net_device *dev, char *command, int total_len)
10962 {
10963 	int bytes_written = 0;
10964 	int error = BCME_OK;
10965 	wl_nan_conf_status_t nstatus;
10966 
10967 	error = wl_cfgnan_get_status(dev, &nstatus);
10968 	if (error) {
10969 		ANDROID_ERROR(("Failed to get nan status (%d)\n", error));
10970 		return error;
10971 	}
10972 
10973 	bytes_written = snprintf(command, total_len,
10974 			"EN:%d Role:%d EM:%d CID:"MACF" NMI:"MACF" SC(2G):%d SC(5G):%d "
10975 			"MR:"NMRSTR" AMR:"NMRSTR" IMR:"NMRSTR
10976 			"HC:%d AMBTT:%04x TSF[%04x:%04x]\n",
10977 			nstatus.enabled,
10978 			nstatus.role,
10979 			nstatus.election_mode,
10980 			ETHERP_TO_MACF(&(nstatus.cid)),
10981 			ETHERP_TO_MACF(&(nstatus.nmi)),
10982 			nstatus.social_chans[0],
10983 			nstatus.social_chans[1],
10984 			NMR2STR(nstatus.mr),
10985 			NMR2STR(nstatus.amr),
10986 			NMR2STR(nstatus.imr),
10987 			nstatus.hop_count,
10988 			nstatus.ambtt,
10989 			nstatus.cluster_tsf_h,
10990 			nstatus.cluster_tsf_l);
10991 	return bytes_written;
10992 }
10993 #endif /* WL_NAN */
10994 
10995 #ifdef SUPPORT_NAN_RANGING_TEST_BW
10996 enum {
10997 	NAN_RANGING_5G_BW20 = 1,
10998 	NAN_RANGING_5G_BW40,
10999 	NAN_RANGING_5G_BW80
11000 };
11001 
11002 int
wl_nan_ranging_bw(struct net_device * net,int bw,char * command)11003 wl_nan_ranging_bw(struct net_device *net, int bw, char *command)
11004 {
11005 	int bytes_written, err = BCME_OK;
11006 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
11007 	s32 val = 1;
11008 	struct {
11009 		u32 band;
11010 		u32 bw_cap;
11011 	} param = {0, 0};
11012 
11013 	if (bw < NAN_RANGING_5G_BW20 || bw > NAN_RANGING_5G_BW80) {
11014 		ANDROID_ERROR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__));
11015 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11016 		return bytes_written;
11017 	}
11018 
11019 	switch (bw) {
11020 		case NAN_RANGING_5G_BW20:
11021 			ANDROID_ERROR(("NAN_RANGING 5G/BW20\n"));
11022 			param.band = WLC_BAND_5G;
11023 			param.bw_cap = 0x1;
11024 			break;
11025 		case NAN_RANGING_5G_BW40:
11026 			ANDROID_ERROR(("NAN_RANGING 5G/BW40\n"));
11027 			param.band = WLC_BAND_5G;
11028 			param.bw_cap = 0x3;
11029 			break;
11030 		case NAN_RANGING_5G_BW80:
11031 			ANDROID_ERROR(("NAN_RANGING 5G/BW80\n"));
11032 			param.band = WLC_BAND_5G;
11033 			param.bw_cap = 0x7;
11034 			break;
11035 	}
11036 
11037 	err = wldev_ioctl_set(net, WLC_DOWN, &val, sizeof(s32));
11038 	if (err) {
11039 		ANDROID_ERROR(("WLC_DOWN error %d\n", err));
11040 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11041 	} else {
11042 		err = wldev_iovar_setbuf(net, "bw_cap", &param, sizeof(param),
11043 			ioctl_buf, sizeof(ioctl_buf), NULL);
11044 
11045 		if (err) {
11046 			ANDROID_ERROR(("BW set failed\n"));
11047 			bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11048 		} else {
11049 			ANDROID_ERROR(("BW set done\n"));
11050 			bytes_written = scnprintf(command, sizeof("OK"), "OK");
11051 		}
11052 
11053 		err = wldev_ioctl_set(net, WLC_UP, &val, sizeof(s32));
11054 		if (err < 0) {
11055 			ANDROID_ERROR(("WLC_UP error %d\n", err));
11056 			bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11057 		}
11058 	}
11059 	return bytes_written;
11060 }
11061 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
11062 
11063 static int
wl_android_set_softap_ax_mode(struct net_device * dev,const char * cmd_str)11064 wl_android_set_softap_ax_mode(struct net_device *dev, const char* cmd_str)
11065 {
11066 	int enable = 0;
11067 	int err = 0;
11068 	s32 bssidx = 0;
11069 	struct bcm_cfg80211 *cfg = NULL;
11070 
11071 	if (!dev) {
11072 		err = -EINVAL;
11073 		goto exit;
11074 	}
11075 
11076 	cfg = wl_get_cfg(dev);
11077 	if (!cfg) {
11078 		err = -EINVAL;
11079 		goto exit;
11080 	}
11081 
11082 	if (cmd_str) {
11083 		enable = bcm_atoi(cmd_str);
11084 	} else {
11085 		ANDROID_ERROR(("failed due to wrong received parameter\n"));
11086 		err = -EINVAL;
11087 		goto exit;
11088 	}
11089 
11090 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11091 		ANDROID_ERROR(("find softap index from wdev failed\n"));
11092 		err = -EINVAL;
11093 		goto exit;
11094 	}
11095 
11096 	ANDROID_INFO(("HAPD_SET_AX_MODE = %d\n", enable));
11097 	err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, (bool)enable);
11098 	if (err) {
11099 		ANDROID_ERROR(("failed to set softap ax mode(%d)\n", enable));
11100 
11101 	}
11102 exit :
11103 	return err;
11104 }
11105 
11106 #ifdef WL_P2P_6G
11107 #define WL_HE_FEATURES_P2P_6G	0x0200u
11108 static int
wl_android_enable_p2p_6g(struct net_device * dev,int enable)11109 wl_android_enable_p2p_6g(struct net_device *dev, int enable)
11110 {
11111 	s32 err = 0;
11112 	s32 bssidx = 0;
11113 	struct bcm_cfg80211 *cfg = NULL;
11114 
11115 	if (!dev) {
11116 		err = -EINVAL;
11117 		return err;
11118 	}
11119 
11120 	cfg = wl_get_cfg(dev);
11121 	if (!cfg) {
11122 		err = -EINVAL;
11123 		return err;
11124 	}
11125 
11126 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11127 		ANDROID_ERROR(("find softap index from wdev failed\n"));
11128 		err = -EINVAL;
11129 		return err;
11130 	}
11131 
11132 	/* Enable/disable for P2P 6G, both P2P and P2P_6G needs to be handled together */
11133 	err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, (WL_HE_FEATURES_HE_P2P |
11134 		WL_HE_FEATURES_P2P_6G), (bool)enable);
11135 	if (err == BCME_OK) {
11136 		/* Set P2P 6G support flag */
11137 		if (enable) {
11138 			cfg->p2p_6g_enabled = TRUE;
11139 		} else {
11140 			cfg->p2p_6g_enabled = FALSE;
11141 		}
11142 	}
11143 
11144 	return err;
11145 }
11146 #endif /* WL_P2P_6G */
11147 
11148 #ifdef WL_TWT
11149 
11150 static int
wl_android_twt_setup(struct net_device * ndev,char * command,int total_len)11151 wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
11152 {
11153 	wl_twt_config_t val;
11154 	s32 bw;
11155 	char *token, *pos;
11156 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11157 	u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
11158 	u64 twt;
11159 	uint8 *rem = mybuf;
11160 	uint16 rem_len = sizeof(mybuf);
11161 	int32 val32;
11162 
11163 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11164 
11165 	if (strlen(command) == strlen(CMD_TWT_SETUP)) {
11166 		ANDROID_ERROR(("Error, twt_setup cmd  missing params\n"));
11167 		bw = -EINVAL;
11168 		goto exit;
11169 	}
11170 
11171 	bzero(&val, sizeof(val));
11172 	val.version = WL_TWT_SETUP_VER;
11173 	val.length = sizeof(val.version) + sizeof(val.length);
11174 
11175 	/* Default values, Overide Below */
11176 	val.desc.wake_time_h = 0xFFFFFFFF;
11177 	val.desc.wake_time_l = 0xFFFFFFFF;
11178 	val.desc.wake_int_min = 0xFFFFFFFF;
11179 	val.desc.wake_int_max = 0xFFFFFFFF;
11180 	val.desc.wake_dur_min = 0xFFFFFFFF;
11181 	val.desc.wake_dur_max = 0xFFFFFFFF;
11182 	val.desc.avg_pkt_num  = 0xFFFFFFFF;
11183 
11184 	pos = command + sizeof(CMD_TWT_SETUP);
11185 
11186 	/* negotiation_type */
11187 	token = strsep((char**)&pos, " ");
11188 	if (!token) {
11189 		ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11190 		bw = -EINVAL;
11191 		goto exit;
11192 	}
11193 	val.desc.negotiation_type  = htod32((u32)bcm_atoi(token));
11194 
11195 	/* Wake Duration */
11196 	token = strsep((char**)&pos, " ");
11197 	if (!token) {
11198 		ANDROID_ERROR(("Mandatory param wake Duration not present\n"));
11199 		bw = -EINVAL;
11200 		goto exit;
11201 	}
11202 	val.desc.wake_dur = htod32((u32)bcm_atoi(token));
11203 
11204 	/* Wake interval */
11205 	token = strsep((char**)&pos, " ");
11206 	if (!token) {
11207 		ANDROID_ERROR(("Mandaory param Wake Interval not present\n"));
11208 		bw = -EINVAL;
11209 		goto exit;
11210 	}
11211 	val.desc.wake_int = htod32((u32)bcm_atoi(token));
11212 
11213 	/* Wake Time parameter */
11214 	token = strsep((char**)&pos, " ");
11215 	if (!token) {
11216 		ANDROID_ERROR(("No Wake Time parameter provided, using default\n"));
11217 	} else {
11218 		twt = (u64)bcm_atoi(token);
11219 		val32 = htod32((u32)(twt >> 32));
11220 		if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11221 			val.desc.wake_time_h = htod32((u32)(twt >> 32));
11222 			val.desc.wake_time_l = htod32((u32)twt);
11223 		}
11224 	}
11225 
11226 	/* Minimum allowed Wake interval */
11227 	token = strsep((char**)&pos, " ");
11228 	if (!token) {
11229 		ANDROID_ERROR(("No Minimum allowed Wake interval provided, using default\n"));
11230 	} else {
11231 		val32 = htod32((u32)bcm_atoi(token));
11232 		if (val32 != -1) {
11233 			val.desc.wake_int_min = htod32((u32)bcm_atoi(token));
11234 		}
11235 	}
11236 
11237 	/* Max Allowed Wake interval */
11238 	token = strsep((char**)&pos, " ");
11239 	if (!token) {
11240 		ANDROID_ERROR(("Maximum allowed Wake interval not provided, using default\n"));
11241 	} else {
11242 		val32 = htod32((u32)bcm_atoi(token));
11243 		if (val32 != -1) {
11244 			val.desc.wake_int_max = htod32((u32)bcm_atoi(token));
11245 		}
11246 	}
11247 
11248 	/* Minimum allowed Wake duration */
11249 	token = strsep((char**)&pos, " ");
11250 	if (!token) {
11251 		ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
11252 	} else {
11253 		val32 = htod32((u32)bcm_atoi(token));
11254 		if (val32 != -1) {
11255 			val.desc.wake_dur_min = htod32((u32)bcm_atoi(token));
11256 		}
11257 	}
11258 
11259 	/* Maximum allowed Wake duration */
11260 	token = strsep((char**)&pos, " ");
11261 	if (!token) {
11262 		ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
11263 	} else {
11264 		val32 = htod32((u32)bcm_atoi(token));
11265 		if (val32 != -1) {
11266 			val.desc.wake_dur_max = htod32((u32)bcm_atoi(token));
11267 		}
11268 	}
11269 
11270 	/* Average number of packets */
11271 	token = strsep((char**)&pos, " ");
11272 	if (!token) {
11273 		ANDROID_ERROR(("Average number of packets not provided, using default\n"));
11274 	} else {
11275 		val32 = htod32((u32)bcm_atoi(token));
11276 		if (val32 != -1) {
11277 			val.desc.avg_pkt_num  = htod32((u32)bcm_atoi(token));
11278 		}
11279 	}
11280 
11281 	/* a peer_address */
11282 	token = strsep((char**)&pos, " ");
11283 	if (!token) {
11284 		ANDROID_ERROR(("Average number of packets not provided, using default\n"));
11285 	} else {
11286 		/* get peer mac */
11287 		if (!bcm_ether_atoe(token, &val.peer)) {
11288 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11289 			bw = BCME_ERROR;
11290 			goto exit;
11291 		}
11292 	}
11293 
11294 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
11295 			sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11296 	if (bw != BCME_OK) {
11297 		goto exit;
11298 	}
11299 
11300 	bw = wldev_iovar_setbuf(ndev, "twt",
11301 		mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
11302 	if (bw < 0) {
11303 		ANDROID_ERROR(("twt config set failed. ret:%d\n", bw));
11304 	}
11305 exit:
11306 	return bw;
11307 }
11308 
11309 static int
wl_android_twt_display_cap(wl_twt_cap_t * result,char * command,int total_len)11310 wl_android_twt_display_cap(wl_twt_cap_t *result, char *command, int total_len)
11311 {
11312 	int rem_len = 0, bytes_written = 0;
11313 
11314 	rem_len = total_len;
11315 	bytes_written = scnprintf(command, rem_len, "Device TWT Capabilities:\n");
11316 	command += bytes_written;
11317 	rem_len -= bytes_written;
11318 
11319 	bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11320 			!!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11321 	command += bytes_written;
11322 	rem_len -= bytes_written;
11323 
11324 	bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11325 			!!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11326 	command += bytes_written;
11327 	rem_len -= bytes_written;
11328 
11329 	bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11330 			!!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11331 	command += bytes_written;
11332 	rem_len -= bytes_written;
11333 
11334 	bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11335 			!!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11336 	command += bytes_written;
11337 	rem_len -= bytes_written;
11338 
11339 	bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11340 			!!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11341 	command += bytes_written;
11342 	rem_len -= bytes_written;
11343 
11344 	/* Peer capabilities */
11345 	bytes_written = scnprintf(command, rem_len, "\nPeer TWT Capabilities:\n");
11346 	command += bytes_written;
11347 	rem_len -= bytes_written;
11348 
11349 	bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11350 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11351 	command += bytes_written;
11352 	rem_len -= bytes_written;
11353 
11354 	bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11355 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11356 	command += bytes_written;
11357 	rem_len -= bytes_written;
11358 
11359 	bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11360 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11361 	command += bytes_written;
11362 	rem_len -= bytes_written;
11363 
11364 	bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11365 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11366 	command += bytes_written;
11367 	rem_len -= bytes_written;
11368 
11369 	bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11370 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11371 	command += bytes_written;
11372 	rem_len -= bytes_written;
11373 
11374 	bytes_written = scnprintf(command, rem_len, "\t------------"
11375 		"---------------------------------------------------\n\n");
11376 	command += bytes_written;
11377 	rem_len -= bytes_written;
11378 	ANDROID_INFO(("Device TWT Capabilities:\n"));
11379 	ANDROID_INFO(("Requester Support %d, \t",
11380 		!!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11381 	ANDROID_INFO(("Responder Support %d, \t",
11382 		!!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11383 	ANDROID_INFO(("Broadcast TWT Support %d, \t",
11384 		!!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11385 	ANDROID_INFO(("Flexible TWT Support %d, \t",
11386 		!!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11387 	ANDROID_INFO(("TWT Required by peer %d, \n",
11388 		!!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11389 	/* Peer capabilities */
11390 	ANDROID_INFO(("\nPeer TWT Capabilities:\n"));
11391 	ANDROID_INFO(("Requester Support %d, \t",
11392 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11393 	ANDROID_INFO(("Responder Support %d, \t",
11394 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11395 	ANDROID_INFO(("Broadcast TWT Support %d, \t",
11396 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11397 	ANDROID_INFO(("Flexible TWT Support %d, \t",
11398 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11399 	ANDROID_INFO(("TWT Required by peer %d, \n",
11400 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11401 	ANDROID_INFO(("\t-----------------------------------------------------------------\n\n"));
11402 
11403 	if ((total_len - rem_len) > 0) {
11404 		return (total_len - rem_len);
11405 	} else {
11406 		return BCME_ERROR;
11407 	}
11408 }
11409 
11410 static int
wl_android_twt_cap(struct net_device * dev,char * command,int total_len)11411 wl_android_twt_cap(struct net_device *dev, char *command, int total_len)
11412 {
11413 	int ret = BCME_OK;
11414 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11415 	uint8 *pxtlv = NULL;
11416 	uint8 *iovresp = NULL;
11417 	wl_twt_cap_cmd_t cmd_cap;
11418 	wl_twt_cap_t result;
11419 
11420 	uint16 buflen = 0, bufstart = 0;
11421 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11422 
11423 	bzero(&cmd_cap, sizeof(cmd_cap));
11424 
11425 	cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
11426 	cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
11427 
11428 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11429 	if (iovresp == NULL) {
11430 		ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11431 		goto exit;
11432 	}
11433 
11434 	buflen = bufstart = WLC_IOCTL_SMLEN;
11435 	pxtlv = (uint8 *)iovbuf;
11436 
11437 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
11438 			sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
11439 	if (ret != BCME_OK) {
11440 		ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11441 		goto exit;
11442 	}
11443 
11444 	if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11445 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11446 		ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11447 		goto exit;
11448 	}
11449 	if (ret) {
11450 		ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11451 	}
11452 
11453 	(void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11454 
11455 	if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
11456 		ANDROID_ERROR(("capability ver %d, \n", dtoh16(result.version)));
11457 		ret = wl_android_twt_display_cap(&result, command, total_len);
11458 		return ret;
11459 	} else {
11460 		ret = BCME_UNSUPPORTED;
11461 		ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11462 		goto exit;
11463 	}
11464 
11465 exit:
11466 	if (iovresp) {
11467 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11468 	}
11469 
11470 	return ret;
11471 }
11472 
11473 static int
wl_android_twt_status_display_v1(wl_twt_status_v1_t * status,char * command,int total_len)11474 wl_android_twt_status_display_v1(wl_twt_status_v1_t *status, char *command, int total_len)
11475 {
11476 	uint i;
11477 	wl_twt_sdesc_t *desc = NULL;
11478 	int rem_len = 0, bytes_written = 0;
11479 
11480 	rem_len = total_len;
11481 
11482 	ANDROID_ERROR(("\nNumber of Individual TWTs: %d\n", status->num_fid));
11483 	bytes_written = scnprintf(command, rem_len,
11484 			"\nNumber of Individual TWTs: %d\n", status->num_fid);
11485 	command += bytes_written;
11486 	rem_len -= bytes_written;
11487 	bytes_written = scnprintf(command, rem_len,
11488 			"Number of Broadcast TWTs: %d\n", status->num_bid);
11489 	command += bytes_written;
11490 	rem_len -= bytes_written;
11491 	bytes_written = scnprintf(command, rem_len,
11492 			"TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11493 			!!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11494 			!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11495 			!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE));
11496 	command += bytes_written;
11497 	rem_len -= bytes_written;
11498 	ANDROID_INFO(("Number of Broadcast TWTs: %d\n", status->num_bid));
11499 	ANDROID_INFO(("TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11500 		!!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11501 		!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11502 		!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE)));
11503 	ANDROID_INFO(("\t---------------- Individual TWT list-------------------\n"));
11504 	bytes_written = scnprintf(command, rem_len,
11505 			"\t---------------- Individual TWT list-------------------\n");
11506 	command += bytes_written;
11507 	rem_len -= bytes_written;
11508 
11509 	for (i = 0; i < WL_TWT_MAX_ITWT; i ++) {
11510 		if ((status->itwt_status[i].state == WL_TWT_ACTIVE) ||
11511 			(status->itwt_status[i].state == WL_TWT_SUSPEND)) {
11512 			desc = &status->itwt_status[i].desc;
11513 			bytes_written = scnprintf(command, rem_len, "\tFlow ID %d \tState %d\t",
11514 					desc->flow_id,
11515 					status->itwt_status[i].state);
11516 			command += bytes_written;
11517 			rem_len -= bytes_written;
11518 
11519 			bytes_written = scnprintf(command, rem_len,
11520 					"peer: "MACF"\n",
11521 					ETHER_TO_MACF(status->itwt_status[i].peer));
11522 			command += bytes_written;
11523 			rem_len -= bytes_written;
11524 
11525 			bytes_written = scnprintf(command, rem_len,
11526 					"Unannounced %d\tTriggered %d\tProtection %d\t"
11527 					"Info Frame Disabled %d\n",
11528 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11529 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11530 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11531 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11532 			command += bytes_written;
11533 			rem_len -= bytes_written;
11534 
11535 			bytes_written = scnprintf(command, rem_len,
11536 					"target wake time: 0x%08x%08x\t",
11537 					desc->wake_time_h, desc->wake_time_l);
11538 			command += bytes_written;
11539 			rem_len -= bytes_written;
11540 
11541 			bytes_written = scnprintf(command, rem_len,
11542 					"wake duration: %u\t", desc->wake_dur);
11543 			command += bytes_written;
11544 			rem_len -= bytes_written;
11545 
11546 			bytes_written = scnprintf(command, rem_len,
11547 					"wake interval: %u\t", desc->wake_int);
11548 			command += bytes_written;
11549 			rem_len -= bytes_written;
11550 
11551 			bytes_written = scnprintf(command, rem_len,
11552 					"TWT channel: %u\n", desc->channel);
11553 			command += bytes_written;
11554 			rem_len -= bytes_written;
11555 			ANDROID_INFO(("\tFlow ID %d \tState %d\t",
11556 				desc->flow_id,
11557 				status->itwt_status[i].state));
11558 			ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->itwt_status[i].peer)));
11559 			ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11560 				"Info Frame Disabled %d\n",
11561 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11562 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11563 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11564 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11565 			ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11566 				desc->wake_time_h, desc->wake_time_l));
11567 			ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11568 			ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11569 			ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11570 		}
11571 	}
11572 
11573 	ANDROID_INFO(("\t---------------- Broadcast TWT list-------------------\n"));
11574 	bytes_written = scnprintf(command, rem_len,
11575 			"\t---------------- Broadcast TWT list-------------------\n");
11576 	command += bytes_written;
11577 	rem_len -= bytes_written;
11578 	for (i = 0; i < WL_TWT_MAX_BTWT; i ++) {
11579 		if ((status->btwt_status[i].state == WL_TWT_ACTIVE) ||
11580 			(status->btwt_status[i].state == WL_TWT_SUSPEND)) {
11581 			desc = &status->btwt_status[i].desc;
11582 			bytes_written = scnprintf(command, rem_len,
11583 					"Broadcast ID %d \tState %d\t",
11584 					desc->bid, status->btwt_status[i].state);
11585 			command += bytes_written;
11586 			rem_len -= bytes_written;
11587 
11588 			bytes_written = scnprintf(command, rem_len,
11589 					"peer: "MACF"\n",
11590 					ETHER_TO_MACF(status->btwt_status[i].peer));
11591 			command += bytes_written;
11592 			rem_len -= bytes_written;
11593 
11594 			bytes_written = scnprintf(command, rem_len,
11595 					"Unannounced %d\tTriggered %d\tProtection %d\t"
11596 					"Info Frame Disabled %d\t",
11597 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11598 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11599 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11600 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11601 			command += bytes_written;
11602 			rem_len -= bytes_written;
11603 
11604 			bytes_written = scnprintf(command, rem_len,
11605 					"Frame Recommendation %d\tBTWT Persistence %d\n",
11606 					desc->frame_recomm, desc->btwt_persistence);
11607 			command += bytes_written;
11608 			rem_len -= bytes_written;
11609 
11610 			bytes_written = scnprintf(command, rem_len,
11611 					"target wake time: 0x%08x%08x\t",
11612 					desc->wake_time_h, desc->wake_time_l);
11613 			command += bytes_written;
11614 			rem_len -= bytes_written;
11615 			bytes_written = scnprintf(command, rem_len,
11616 					"wake duration: %u\t", desc->wake_dur);
11617 			command += bytes_written;
11618 			rem_len -= bytes_written;
11619 
11620 			bytes_written = scnprintf(command, rem_len,
11621 					"wake interval: %u\t", desc->wake_int);
11622 			command += bytes_written;
11623 			rem_len -= bytes_written;
11624 
11625 			bytes_written = scnprintf(command, rem_len,
11626 					"TWT channel: %u\n", desc->channel);
11627 			command += bytes_written;
11628 			rem_len -= bytes_written;
11629 			ANDROID_INFO(("Broadcast ID %d \tState %d\t",
11630 				desc->bid, status->btwt_status[i].state));
11631 			ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->btwt_status[i].peer)));
11632 			ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11633 				"Info Frame Disabled %d\t",
11634 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11635 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11636 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11637 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11638 			ANDROID_INFO(("Frame Recommendation %d\tBTWT Persistence %d\n",
11639 				desc->frame_recomm, desc->btwt_persistence));
11640 			ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11641 				desc->wake_time_h, desc->wake_time_l));
11642 			ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11643 			ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11644 			ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11645 		}
11646 	}
11647 
11648 	if ((total_len - rem_len) > 0) {
11649 		return (total_len - rem_len);
11650 	} else {
11651 		return BCME_ERROR;
11652 	}
11653 }
11654 
11655 static int
wl_android_twt_status_query(struct net_device * dev,char * command,int total_len)11656 wl_android_twt_status_query(struct net_device *dev, char *command, int total_len)
11657 {
11658 	int ret = BCME_OK;
11659 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11660 	uint8 *pxtlv = NULL;
11661 	uint8 *iovresp = NULL;
11662 	wl_twt_status_cmd_v1_t status_cmd;
11663 	wl_twt_status_v1_t result;
11664 
11665 	uint16 buflen = 0, bufstart = 0;
11666 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11667 
11668 	bzero(&status_cmd, sizeof(status_cmd));
11669 
11670 	status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1;
11671 	status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer);
11672 
11673 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11674 	if (iovresp == NULL) {
11675 		ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11676 		goto exit;
11677 	}
11678 
11679 	buflen = bufstart = WLC_IOCTL_SMLEN;
11680 	pxtlv = (uint8 *)iovbuf;
11681 
11682 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS,
11683 			sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32);
11684 	if (ret != BCME_OK) {
11685 		ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11686 		goto exit;
11687 	}
11688 
11689 	if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11690 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11691 		ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11692 		goto exit;
11693 	}
11694 	if (ret) {
11695 		ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11696 	}
11697 
11698 	(void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11699 
11700 	if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) {
11701 		ANDROID_ERROR(("status query ver %d, \n", dtoh16(result.version)));
11702 		ret = wl_android_twt_status_display_v1(&result, command, total_len);
11703 		return ret;
11704 	} else {
11705 		ret = BCME_UNSUPPORTED;
11706 		ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11707 		goto exit;
11708 	}
11709 
11710 exit:
11711 	if (iovresp) {
11712 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11713 	}
11714 
11715 	return ret;
11716 }
11717 
11718 static int
wl_android_twt_info(struct net_device * ndev,char * command,int total_len)11719 wl_android_twt_info(struct net_device *ndev, char *command, int total_len)
11720 {
11721 	wl_twt_info_t val;
11722 	s32 bw;
11723 	char *token, *pos;
11724 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11725 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11726 	u64 twt;
11727 	uint8 *rem = mybuf;
11728 	uint16 rem_len = sizeof(mybuf);
11729 	int32 val32;
11730 
11731 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11732 
11733 	if (strlen(command) == strlen(CMD_TWT_INFO)) {
11734 		ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11735 		bw = -EINVAL;
11736 		goto exit;
11737 	}
11738 
11739 	bzero(&val, sizeof(val));
11740 	val.version = WL_TWT_INFO_VER;
11741 	val.length = sizeof(val.version) + sizeof(val.length);
11742 
11743 	/* Default values, Overide Below */
11744 	val.infodesc.flow_id = 0xFF;
11745 	val.desc.next_twt_h = 0xFFFFFFFF;
11746 	val.desc.next_twt_l = 0xFFFFFFFF;
11747 
11748 	pos = command + sizeof(CMD_TWT_TEARDOWN);
11749 
11750 	/* (all TWT) */
11751 	token = strsep((char**)&pos, " ");
11752 	if (!token) {
11753 		ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11754 		bw = -EINVAL;
11755 		goto exit;
11756 	}
11757 	if (htod32((u32)bcm_atoi(token)) == 1) {
11758 		val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
11759 	}
11760 
11761 	/* Flow ID */
11762 	token = strsep((char**)&pos, " ");
11763 	if (!token) {
11764 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11765 	} else {
11766 		val32 = htod32((u32)bcm_atoi(token));
11767 		if (val32 != -1) {
11768 			val.infodesc.flow_id = htod32((u32)bcm_atoi(token));
11769 		}
11770 	}
11771 
11772 	/* resume offset */
11773 	token = strsep((char**)&pos, " ");
11774 	if (!token) {
11775 		ANDROID_ERROR(("resume offset not provided, using default\n"));
11776 	} else {
11777 		twt = (u64)bcm_atoi(token);
11778 		val32 = htod32((u32)(twt >> 32));
11779 		if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11780 			val.infodesc.next_twt_h = htod32((u32)(twt >> 32));
11781 			val.infodesc.next_twt_l = htod32((u32)twt);
11782 			val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
11783 		}
11784 	}
11785 
11786 	/* peer_address */
11787 	token = strsep((char**)&pos, " ");
11788 	if (!token) {
11789 		ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11790 	} else {
11791 		/* get peer mac */
11792 		if (!bcm_ether_atoe(token, &val.peer)) {
11793 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11794 			bw = BCME_ERROR;
11795 			goto exit;
11796 		}
11797 	}
11798 
11799 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
11800 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11801 	if (bw != BCME_OK) {
11802 		goto exit;
11803 	}
11804 
11805 	bw = wldev_iovar_setbuf(ndev, "twt",
11806 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11807 	if (bw < 0) {
11808 		ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11809 	}
11810 exit:
11811 	return bw;
11812 
11813 }
11814 
11815 static int
wl_android_twt_teardown(struct net_device * ndev,char * command,int total_len)11816 wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len)
11817 {
11818 	wl_twt_teardown_t val;
11819 	s32 bw;
11820 	char *token, *pos;
11821 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11822 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11823 	uint8 *rem = mybuf;
11824 	uint16 rem_len = sizeof(mybuf);
11825 	int32 val32;
11826 
11827 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11828 
11829 	if (strlen(command) == strlen(CMD_TWT_TEARDOWN)) {
11830 		ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11831 		bw = -EINVAL;
11832 		goto exit;
11833 	}
11834 
11835 	bzero(&val, sizeof(val));
11836 	val.version = WL_TWT_TEARDOWN_VER;
11837 	val.length = sizeof(val.version) + sizeof(val.length);
11838 
11839 	/* Default values, Overide Below */
11840 	val.teardesc.flow_id = 0xFF;
11841 	val.teardesc.bid = 0xFF;
11842 
11843 	pos = command + sizeof(CMD_TWT_TEARDOWN);
11844 
11845 	/* negotiation_type */
11846 	token = strsep((char**)&pos, " ");
11847 	if (!token) {
11848 		ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11849 		bw = -EINVAL;
11850 		goto exit;
11851 	}
11852 	val.teardesc.negotiation_type  = htod32((u32)bcm_atoi(token));
11853 
11854 	/* (all TWT) */
11855 	token = strsep((char**)&pos, " ");
11856 	if (!token) {
11857 		ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11858 		bw = -EINVAL;
11859 		goto exit;
11860 	}
11861 	val.teardesc.alltwt = htod32((u32)bcm_atoi(token));
11862 
11863 	/* Flow ID */
11864 	token = strsep((char**)&pos, " ");
11865 	if (!token) {
11866 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11867 	} else {
11868 		val32 = htod32((u32)bcm_atoi(token));
11869 		if (val32 != -1) {
11870 			val.teardesc.flow_id = htod32((u32)bcm_atoi(token));
11871 		}
11872 	}
11873 
11874 	/* Broadcas ID */
11875 	token = strsep((char**)&pos, " ");
11876 	if (!token) {
11877 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11878 	} else {
11879 		val32 = htod32((u32)bcm_atoi(token));
11880 		if (val32 != -1) {
11881 			val.teardesc.bid = htod32((u32)bcm_atoi(token));
11882 		}
11883 	}
11884 
11885 	/* peer_address */
11886 	token = strsep((char**)&pos, " ");
11887 	if (!token) {
11888 		ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11889 	} else {
11890 		/* get peer mac */
11891 		if (!bcm_ether_atoe(token, &val.peer)) {
11892 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11893 			bw = BCME_ERROR;
11894 			goto exit;
11895 		}
11896 	}
11897 
11898 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
11899 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11900 	if (bw != BCME_OK) {
11901 		goto exit;
11902 	}
11903 
11904 	bw = wldev_iovar_setbuf(ndev, "twt",
11905 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11906 	if (bw < 0) {
11907 		ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11908 	}
11909 exit:
11910 	return bw;
11911 }
11912 #endif /* WL_TWT */
11913 
11914 int
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)11915 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
11916 {
11917 	int bytes_written = 0;
11918 	android_wifi_priv_cmd priv_cmd;
11919 
11920 	bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
11921 	priv_cmd.total_len = cmd_len;
11922 
11923 	if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
11924 		ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
11925 #ifdef SUPPORT_DEEP_SLEEP
11926 		trigger_deep_sleep = 1;
11927 #else
11928 #ifdef  BT_OVER_SDIO
11929 		bytes_written = dhd_net_bus_get(net);
11930 #else
11931 		bytes_written = wl_android_wifi_on(net);
11932 #endif /* BT_OVER_SDIO */
11933 #endif /* SUPPORT_DEEP_SLEEP */
11934 	}
11935 	else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
11936 		bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
11937 	}
11938 
11939 	if (!g_wifi_on) {
11940 		ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
11941 			__FUNCTION__, command));
11942 		return 0;
11943 	}
11944 
11945 	if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
11946 #ifdef SUPPORT_DEEP_SLEEP
11947 		trigger_deep_sleep = 1;
11948 #else
11949 #ifdef  BT_OVER_SDIO
11950 		bytes_written = dhd_net_bus_put(net);
11951 #else
11952 		bytes_written = wl_android_wifi_off(net, FALSE);
11953 #endif /* BT_OVER_SDIO */
11954 #endif /* SUPPORT_DEEP_SLEEP */
11955 	}
11956 #ifdef WL_CFG80211
11957 	else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
11958 		wl_cfg80211_set_passive_scan(net, command);
11959 	}
11960 	else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
11961 		wl_cfg80211_set_passive_scan(net, command);
11962 	}
11963 #endif /* WL_CFG80211 */
11964 	else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
11965 		bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
11966 	}
11967 	else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
11968 		bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
11969 	}
11970 #ifdef PKT_FILTER_SUPPORT
11971 	else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
11972 		bytes_written = net_os_enable_packet_filter(net, 1);
11973 	}
11974 	else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
11975 		bytes_written = net_os_enable_packet_filter(net, 0);
11976 	}
11977 	else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
11978 		int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
11979 		bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
11980 	}
11981 	else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
11982 		int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
11983 		bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
11984 	}
11985 #endif /* PKT_FILTER_SUPPORT */
11986 	else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
11987 		/* TBD: BTCOEXSCAN-START */
11988 	}
11989 	else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
11990 		/* TBD: BTCOEXSCAN-STOP */
11991 	}
11992 	else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
11993 #ifdef WL_CFG80211
11994 		void *dhdp = wl_cfg80211_get_dhdp(net);
11995 		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
11996 #else
11997 #ifdef PKT_FILTER_SUPPORT
11998 		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
11999 
12000 		if (mode == 1)
12001 			net_os_enable_packet_filter(net, 0); /* DHCP starts */
12002 		else
12003 			net_os_enable_packet_filter(net, 1); /* DHCP ends */
12004 #endif /* PKT_FILTER_SUPPORT */
12005 #endif /* WL_CFG80211 */
12006 	}
12007 	else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
12008 		bytes_written = wl_android_set_suspendopt(net, command);
12009 	}
12010 	else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
12011 		bytes_written = wl_android_set_suspendmode(net, command);
12012 	}
12013 	else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
12014 		bytes_written = wl_android_set_bcn_li_dtim(net, command);
12015 	}
12016 	else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
12017 		bytes_written = wl_android_set_max_dtim(net, command);
12018 	}
12019 #ifdef DISABLE_DTIM_IN_SUSPEND
12020 	else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
12021 		bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
12022 	}
12023 #endif /* DISABLE_DTIM_IN_SUSPEND */
12024 #ifdef WL_CFG80211
12025 	else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
12026 		bytes_written = wl_android_set_band(net, command);
12027 	}
12028 #endif /* WL_CFG80211 */
12029 	else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
12030 		bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
12031 	}
12032 #ifdef WL_CFG80211
12033 	else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
12034 		bytes_written = wl_android_set_csa(net, command);
12035 	} else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
12036 		bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
12037 	} else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
12038 		bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
12039 	}
12040 #endif /* WL_CFG80211 */
12041 #ifndef CUSTOMER_SET_COUNTRY
12042 	/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
12043 	else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
12044 		/*
12045 		 * Usage examples:
12046 		 * DRIVER COUNTRY US
12047 		 * DRIVER COUNTRY US/7
12048 		 * Wrong revinfo should be filtered:
12049 		 * DRIVER COUNTRY US/-1
12050 		 */
12051 		char *country_code = command + strlen(CMD_COUNTRY) + 1;
12052 		char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
12053 		int revinfo = -1;
12054 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12055 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12056 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12057 		if ((rev_info_delim) &&
12058 			(strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
12059 			strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
12060 			(rev_info_delim + 1)) {
12061 			revinfo  = bcm_atoi(rev_info_delim + 1);
12062 		} else {
12063 			revinfo = 0;
12064 		}
12065 
12066 		if (revinfo < 0) {
12067 			ANDROID_ERROR(("%s:failed due to wrong revinfo %d\n", __FUNCTION__, revinfo));
12068 			return BCME_BADARG;
12069 		}
12070 
12071 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12072 		if (dhdp->is_blob) {
12073 			revinfo = 0;
12074 		}
12075 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12076 
12077 #ifdef WL_CFG80211
12078 		bytes_written = wl_cfg80211_set_country_code(net, country_code,
12079 				true, true, revinfo);
12080 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12081 #ifdef FCC_PWR_LIMIT_2G
12082 		if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
12083 			ANDROID_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
12084 		} else {
12085 			ANDROID_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
12086 		}
12087 #endif /* FCC_PWR_LIMIT_2G */
12088 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12089 #else
12090 		bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
12091 #endif /* WL_CFG80211 */
12092 	}
12093 #endif /* CUSTOMER_SET_COUNTRY */
12094 	else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
12095 		bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
12096 	} else if (strnicmp(command, CMD_ASSOC_CLIENTS,	strlen(CMD_ASSOC_CLIENTS)) == 0) {
12097 		bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
12098 	}
12099 
12100 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12101 	else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_SET, strlen(CMD_ROAM_VSIE_ENAB_SET)) == 0) {
12102 		bytes_written = wl_android_set_roam_vsie_enab(net, command, priv_cmd.total_len);
12103 	} else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_GET, strlen(CMD_ROAM_VSIE_ENAB_GET)) == 0) {
12104 		bytes_written = wl_android_get_roam_vsie_enab(net, command, priv_cmd.total_len);
12105 	} else if (strnicmp(command, CMD_BR_VSIE_ENAB_SET, strlen(CMD_BR_VSIE_ENAB_SET)) == 0) {
12106 		bytes_written = wl_android_set_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12107 	} else if (strnicmp(command, CMD_BR_VSIE_ENAB_GET, strlen(CMD_BR_VSIE_ENAB_GET)) == 0) {
12108 		bytes_written = wl_android_get_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12109 	}
12110 #ifdef WES_SUPPORT
12111 	else if (strnicmp(command, CMD_GETNCHOMODE, strlen(CMD_GETNCHOMODE)) == 0) {
12112 		bytes_written = wl_android_get_ncho_mode(net, command, priv_cmd.total_len);
12113 	}
12114 	else if (strnicmp(command, CMD_SETNCHOMODE, strlen(CMD_SETNCHOMODE)) == 0) {
12115 		int mode;
12116 		sscanf(command, "%*s %d", &mode);
12117 		bytes_written = wl_android_set_ncho_mode(net, mode);
12118 	}
12119 	else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
12120 		bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
12121 	}
12122 	else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
12123 		bytes_written = wl_android_okc_enable(net, command);
12124 	}
12125 	else if (wl_android_legacy_check_command(net, command)) {
12126 		bytes_written = wl_android_legacy_private_command(net, command, priv_cmd.total_len);
12127 	}
12128 	else if (wl_android_ncho_check_command(net, command)) {
12129 		bytes_written = wl_android_ncho_private_command(net, command, priv_cmd.total_len);
12130 	}
12131 #endif /* WES_SUPPORT */
12132 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
12133 	else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
12134 		bytes_written = wl_android_default_set_scan_params(net, command,
12135 			priv_cmd.total_len);
12136 	}
12137 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
12138 #ifdef WLTDLS
12139 	else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
12140 		bytes_written = wl_android_tdls_reset(net);
12141 	}
12142 #endif /* WLTDLS */
12143 #ifdef CONFIG_SILENT_ROAM
12144 	else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) {
12145 		int mode = *(command + strlen(CMD_SROAM_TURN_ON) + 1) - '0';
12146 		bytes_written = wl_android_sroam_turn_on(net, mode);
12147 	}
12148 	else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) {
12149 		char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1);
12150 		bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len);
12151 	}
12152 	else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) {
12153 		bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len);
12154 	}
12155 #endif /* CONFIG_SILENT_ROAM */
12156 #ifdef CONFIG_ROAM_RSSI_LIMIT
12157 	else if (strnicmp(command, CMD_ROAM_RSSI_LMT, strlen(CMD_ROAM_RSSI_LMT)) == 0) {
12158 		bytes_written = wl_android_roam_rssi_limit(net, command, priv_cmd.total_len);
12159 	}
12160 #endif /* CONFIG_ROAM_RSSI_LIMIT */
12161 #ifdef CONFIG_ROAM_MIN_DELTA
12162 	else if (strnicmp(command, CMD_ROAM_MIN_DELTA, strlen(CMD_ROAM_MIN_DELTA)) == 0) {
12163 		bytes_written = wl_android_roam_min_delta(net, command, priv_cmd.total_len);
12164 	}
12165 #endif /* CONFIG_ROAM_MIN_DELTA */
12166 	else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) {
12167 		bytes_written = wl_android_set_disconnect_ies(net, command);
12168 	}
12169 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12170 
12171 #ifdef PNO_SUPPORT
12172 	else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
12173 		bytes_written = dhd_dev_pno_stop_for_ssid(net);
12174 	}
12175 #ifndef WL_SCHED_SCAN
12176 	else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
12177 		bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
12178 	}
12179 #endif /* !WL_SCHED_SCAN */
12180 	else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
12181 		int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
12182 		bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
12183 	}
12184 	else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
12185 		bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
12186 	}
12187 #endif /* PNO_SUPPORT */
12188 	else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
12189 		bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
12190 	}
12191 	else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
12192 		int skip = strlen(CMD_P2P_SET_NOA) + 1;
12193 		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
12194 			priv_cmd.total_len - skip);
12195 	}
12196 #ifdef WL_SDO
12197 	else if (strnicmp(command, CMD_P2P_SD_OFFLOAD, strlen(CMD_P2P_SD_OFFLOAD)) == 0) {
12198 		u8 *buf = command;
12199 		u8 *cmd_id = NULL;
12200 		int len;
12201 
12202 		cmd_id = strsep((char **)&buf, " ");
12203 		if (!cmd_id) {
12204 			/* Propagate the error */
12205 			bytes_written = -EINVAL;
12206 		} else {
12207 			/* if buf == NULL, means no arg */
12208 			if (buf == NULL) {
12209 				len = 0;
12210 			} else {
12211 				len = strlen(buf);
12212 			}
12213 			bytes_written = wl_cfg80211_sd_offload(net, cmd_id, buf, len);
12214 		}
12215 	}
12216 #endif /* WL_SDO */
12217 #ifdef P2P_LISTEN_OFFLOADING
12218 	else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
12219 		u8 *sub_command = strchr(command, ' ');
12220 		bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
12221 				sub_command ? strlen(sub_command) : 0);
12222 	}
12223 #endif /* P2P_LISTEN_OFFLOADING */
12224 #if !defined WL_ENABLE_P2P_IF
12225 	else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
12226 		bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
12227 	}
12228 #endif /* WL_ENABLE_P2P_IF */
12229 	else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
12230 		int skip = strlen(CMD_P2P_SET_PS) + 1;
12231 		bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
12232 			priv_cmd.total_len - skip);
12233 	}
12234 	else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
12235 		int skip = strlen(CMD_P2P_ECSA) + 1;
12236 		bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
12237 			priv_cmd.total_len - skip);
12238 	}
12239 	/* This command is not for normal VSDB operation but for only specific P2P operation.
12240 	 * Ex) P2P OTA backup operation
12241 	 */
12242 	else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
12243 		int skip = strlen(CMD_P2P_INC_BW) + 1;
12244 		bytes_written = wl_cfg80211_increase_p2p_bw(net,
12245 				command + skip, priv_cmd.total_len - skip);
12246 	}
12247 #ifdef WL_CFG80211
12248 	else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
12249 		strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
12250 		int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
12251 		bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
12252 			priv_cmd.total_len - skip, *(command + skip - 2) - '0');
12253 	}
12254 #ifdef WLFBT
12255 	else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
12256 		bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
12257 	}
12258 #endif /* WLFBT */
12259 #endif /* WL_CFG80211 */
12260 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12261 	else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
12262 		strlen(CMD_GET_BEST_CHANNELS)) == 0) {
12263 		bytes_written = wl_android_get_best_channels(net, command,
12264 			priv_cmd.total_len);
12265 	}
12266 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12267 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12268 	else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
12269 		strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
12270 		int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
12271 		bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
12272 			priv_cmd.total_len);
12273 	}
12274 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12275 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12276 #ifdef SUPPORT_AMPDU_MPDU_CMD
12277 	/* CMD_AMPDU_MPDU */
12278 	else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
12279 		int skip = strlen(CMD_AMPDU_MPDU) + 1;
12280 		bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
12281 	}
12282 #endif /* SUPPORT_AMPDU_MPDU_CMD */
12283 #if defined (SUPPORT_HIDDEN_AP)
12284 	else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
12285 		strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
12286 		int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
12287 		wl_android_set_max_num_sta(net, (const char*)command+skip);
12288 	}
12289 	else if (strnicmp(command, CMD_SET_HAPD_SSID,
12290 		strlen(CMD_SET_HAPD_SSID)) == 0) {
12291 		int skip = strlen(CMD_SET_HAPD_SSID) + 3;
12292 		wl_android_set_ssid(net, (const char*)command+skip);
12293 	}
12294 	else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
12295 		strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
12296 		int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
12297 		wl_android_set_hide_ssid(net, (const char*)command+skip);
12298 	}
12299 #endif /* SUPPORT_HIDDEN_AP */
12300 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
12301 	else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
12302 		strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
12303 		int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
12304 		wl_android_sta_diassoc(net, (const char*)command+skip);
12305 	}
12306 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
12307 #ifdef SUPPORT_SET_LPC
12308 	else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
12309 		strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
12310 		int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
12311 		wl_android_set_lpc(net, (const char*)command+skip);
12312 	}
12313 #endif /* SUPPORT_SET_LPC */
12314 #ifdef SUPPORT_TRIGGER_HANG_EVENT
12315 	else if (strnicmp(command, CMD_TEST_FORCE_HANG,
12316 		strlen(CMD_TEST_FORCE_HANG)) == 0) {
12317 		int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
12318 		net_os_send_hang_message_reason(net, (const char*)command+skip);
12319 	}
12320 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
12321 	else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
12322 		bytes_written = wl_android_ch_res_rl(net, true);
12323 	else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
12324 		bytes_written = wl_android_ch_res_rl(net, false);
12325 #ifdef SUPPORT_LTECX
12326 	else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
12327 		int skip = strlen(CMD_LTECX_SET) + 1;
12328 		bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
12329 	}
12330 #endif /* SUPPORT_LTECX */
12331 #ifdef WL_RELMCAST
12332 	else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
12333 		int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
12334 		bytes_written = wl_android_rmc_enable(net, rmc_enable);
12335 	}
12336 	else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
12337 		int rmc_txrate;
12338 		sscanf(command, "%*s %10d", &rmc_txrate);
12339 		bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
12340 	}
12341 	else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
12342 		int actperiod;
12343 		sscanf(command, "%*s %10d", &actperiod);
12344 		bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
12345 	}
12346 	else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
12347 		int acktimeout;
12348 		sscanf(command, "%*s %10d", &acktimeout);
12349 		acktimeout *= 1000;
12350 		bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
12351 	}
12352 	else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
12353 		int skip = strlen(CMD_SET_RMC_LEADER) + 1;
12354 		bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
12355 	}
12356 	else if (strnicmp(command, CMD_SET_RMC_EVENT,
12357 		strlen(CMD_SET_RMC_EVENT)) == 0) {
12358 		bytes_written = wl_android_set_rmc_event(net, command);
12359 	}
12360 #endif /* WL_RELMCAST */
12361 	else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
12362 		bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
12363 	}
12364 	else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
12365 		bytes_written = wl_android_set_singlecore_scan(net, command);
12366 	}
12367 #ifdef TEST_TX_POWER_CONTROL
12368 	else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
12369 		strlen(CMD_TEST_SET_TX_POWER)) == 0) {
12370 		int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
12371 		wl_android_set_tx_power(net, (const char*)command+skip);
12372 	}
12373 	else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
12374 		strlen(CMD_TEST_GET_TX_POWER)) == 0) {
12375 		wl_android_get_tx_power(net, command, priv_cmd.total_len);
12376 	}
12377 #endif /* TEST_TX_POWER_CONTROL */
12378 	else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
12379 		strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
12380 		int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
12381 		bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
12382 	}
12383 #ifdef SUPPORT_SET_TID
12384 	else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
12385 		bytes_written = wl_android_set_tid(net, command);
12386 	}
12387 	else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
12388 		bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
12389 	}
12390 #endif /* SUPPORT_SET_TID */
12391 #ifdef WL_WTC
12392 	else if (strnicmp(command, CMD_WTC_CONFIG, strlen(CMD_WTC_CONFIG)) == 0) {
12393 		bytes_written = wl_android_wtc_config(net, command, priv_cmd.total_len);
12394 	}
12395 #endif /* WL_WTC */
12396 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12397 	else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
12398 		int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
12399 		wl_android_set_mac_address_filter(net, command+skip);
12400 	}
12401 	else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
12402 		bytes_written = wl_android_set_roam_mode(net, command);
12403 #if defined(BCMFW_ROAM_ENABLE)
12404 	else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
12405 		bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
12406 	}
12407 #endif /* BCMFW_ROAM_ENABLE */
12408 #ifdef WL_CFG80211
12409 	else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
12410 		bytes_written = wl_android_set_miracast(net, command);
12411 	else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
12412 		bytes_written = wl_android_set_ibss_beacon_ouidata(net,
12413 		command, priv_cmd.total_len);
12414 #endif /* WL_CFG80211 */
12415 #ifdef WLAIBSS
12416 	else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
12417 		strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
12418 		bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
12419 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
12420 		strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
12421 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12422 			TRUE);
12423 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
12424 		strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
12425 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12426 			FALSE);
12427 	else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
12428 		strlen(CMD_SETIBSSROUTETABLE)) == 0)
12429 		bytes_written = wl_android_set_ibss_routetable(net, command);
12430 	else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
12431 		bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
12432 	else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
12433 		bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
12434 #endif /* WLAIBSS */
12435 	else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
12436 		int skip = strlen(CMD_KEEP_ALIVE) + 1;
12437 		bytes_written = wl_keep_alive_set(net, command + skip);
12438 	}
12439 #ifdef WL_CFG80211
12440 	else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
12441 		int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
12442 		bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
12443 	}
12444 	else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
12445 		char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
12446 		ANDROID_INFO(("Creating %s interface\n", name));
12447 		if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
12448 				name, NULL) == NULL) {
12449 			bytes_written = -ENODEV;
12450 		} else {
12451 			/* Return success */
12452 			bytes_written = 0;
12453 		}
12454 	}
12455 	else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
12456 		char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
12457 		ANDROID_INFO(("Deleteing %s interface\n", name));
12458 		bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
12459 	}
12460 #endif /* WL_CFG80211 */
12461 	else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
12462 		bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
12463 	}
12464 #ifdef P2PRESP_WFDIE_SRC
12465 	else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
12466 		strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
12467 		int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
12468 		bytes_written = wl_android_set_wfdie_resp(net, mode);
12469 	} else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
12470 		strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
12471 		bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
12472 	}
12473 #endif /* P2PRESP_WFDIE_SRC */
12474 #ifdef WL_CFG80211
12475 	else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
12476 		char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
12477 		bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
12478 	}
12479 #endif /* WL_CFG80211 */
12480 #ifdef WBTEXT
12481 	else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
12482 		bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
12483 	}
12484 	else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
12485 			strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
12486 		char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
12487 		bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
12488 	}
12489 	else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
12490 			strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
12491 		char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
12492 		bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
12493 				command, priv_cmd.total_len);
12494 	}
12495 	else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
12496 			strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
12497 		char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
12498 		bytes_written = wl_cfg80211_wbtext_table_config(net, data,
12499 				command, priv_cmd.total_len);
12500 	}
12501 	else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
12502 			strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
12503 		char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
12504 		bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
12505 				command, priv_cmd.total_len);
12506 	}
12507 	else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
12508 			strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
12509 		bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
12510 			priv_cmd.total_len);
12511 	}
12512 	else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
12513 			strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
12514 		bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
12515 			priv_cmd.total_len);
12516 	}
12517 	else if (strnicmp(command, CMD_WBTEXT_ESTM_ENABLE,
12518 			strlen(CMD_WBTEXT_ESTM_ENABLE)) == 0) {
12519 		bytes_written = wl_cfg80211_wbtext_estm_enable(net, command,
12520 			priv_cmd.total_len);
12521 	}
12522 #endif /* WBTEXT */
12523 #ifdef WLWFDS
12524 	else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
12525 		bytes_written = wl_android_set_wfds_hash(net, command, 1);
12526 	}
12527 	else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
12528 		bytes_written = wl_android_set_wfds_hash(net, command, 0);
12529 	}
12530 #endif /* WLWFDS */
12531 #ifdef BT_WIFI_HANDOVER
12532 	else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
12533 	    bytes_written = wl_tbow_teardown(net);
12534 	}
12535 #endif /* BT_WIFI_HANDOVER */
12536 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12537 #ifdef FCC_PWR_LIMIT_2G
12538 	else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
12539 		strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
12540 		bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
12541 	}
12542 	else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
12543 		strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
12544 		bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
12545 	}
12546 #endif /* FCC_PWR_LIMIT_2G */
12547 	else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
12548 		bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
12549 	}
12550 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12551 	else if (strnicmp(command, CMD_MURX_BFE_CAP,
12552 			strlen(CMD_MURX_BFE_CAP)) == 0) {
12553 #ifdef WL_MURX
12554 		uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
12555 		bytes_written = wl_android_murx_bfe_cap(net, val);
12556 #else
12557 		return BCME_UNSUPPORTED;
12558 #endif /* WL_MURX */
12559 	}
12560 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
12561 	else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
12562 		bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
12563 	}
12564 	else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
12565 		bytes_written = wl_android_set_ap_beaconrate(net, command);
12566 	}
12567 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
12568 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12569 	else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
12570 		bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
12571 	}
12572 	else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
12573 		bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
12574 	}
12575 	else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
12576 		bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
12577 	}
12578 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12579 #ifdef SUPPORT_AP_SUSPEND
12580 	else if (strnicmp(command, CMD_SET_AP_SUSPEND, strlen(CMD_SET_AP_SUSPEND)) == 0) {
12581 		bytes_written = wl_android_set_ap_suspend(net, command, priv_cmd.total_len);
12582 	}
12583 #endif /* SUPPORT_AP_SUSPEND */
12584 #ifdef SUPPORT_AP_BWCTRL
12585 	else if (strnicmp(command, CMD_SET_AP_BW, strlen(CMD_SET_AP_BW)) == 0) {
12586 		bytes_written = wl_android_set_ap_bw(net, command, priv_cmd.total_len);
12587 	}
12588 	else if (strnicmp(command, CMD_GET_AP_BW, strlen(CMD_GET_AP_BW)) == 0) {
12589 		bytes_written = wl_android_get_ap_bw(net, command, priv_cmd.total_len);
12590 	}
12591 #endif /* SUPPORT_AP_BWCTRL */
12592 #ifdef SUPPORT_RSSI_SUM_REPORT
12593 	else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
12594 		bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
12595 	}
12596 	else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
12597 		bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
12598 	}
12599 	else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
12600 		bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
12601 	}
12602 #endif /* SUPPORT_RSSI_SUM_REPORT */
12603 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
12604 	else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
12605 		bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
12606 	}
12607 	else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
12608 			== 0) {
12609 		bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
12610 				priv_cmd.total_len);
12611 	}
12612 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
12613 #if defined(SUPPORT_RANDOM_MAC_SCAN)
12614 	else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
12615 		bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
12616 	} else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
12617 		bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
12618 	}
12619 #endif /* SUPPORT_RANDOM_MAC_SCAN */
12620 #ifdef WL_NATOE
12621 	else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
12622 		bytes_written = wl_android_process_natoe_cmd(net, command,
12623 				priv_cmd.total_len);
12624 	}
12625 #endif /* WL_NATOE */
12626 #ifdef CONNECTION_STATISTICS
12627 	else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
12628 		strlen(CMD_GET_CONNECTION_STATS)) == 0) {
12629 		bytes_written = wl_android_get_connection_stats(net, command,
12630 			priv_cmd.total_len);
12631 	}
12632 #endif
12633 #ifdef DHD_LOG_DUMP
12634 	else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
12635 		strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
12636 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12637 		/* check whether it has more command */
12638 		if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
12639 			/* compare unwanted/disconnected command */
12640 			if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12641 				SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
12642 				dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
12643 			} else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12644 				SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
12645 				dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
12646 			} else {
12647 				dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12648 			}
12649 		} else {
12650 			dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12651 		}
12652 	}
12653 #endif /* DHD_LOG_DUMP */
12654 #ifdef DHD_STATUS_LOGGING
12655 	else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) {
12656 		dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
12657 	}
12658 	else if (strnicmp(command, CMD_QUERY_STATUS_LOG, strlen(CMD_QUERY_STATUS_LOG)) == 0) {
12659 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12660 		bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
12661 	}
12662 #endif /* DHD_STATUS_LOGGING */
12663 #if defined(CONFIG_TIZEN)
12664 	else if (strnicmp(command, CMD_POWERSAVEMODE_SET,
12665 			strlen(CMD_POWERSAVEMODE_SET)) == 0) {
12666 		bytes_written = wl_android_set_powersave_mode(net, command,
12667 			priv_cmd.total_len);
12668 	}
12669 	else if (strnicmp(command, CMD_POWERSAVEMODE_GET,
12670 			strlen(CMD_POWERSAVEMODE_GET)) == 0) {
12671 		bytes_written = wl_android_get_powersave_mode(net, command,
12672 			priv_cmd.total_len);
12673 	}
12674 #endif /* CONFIG_TIZEN */
12675 #ifdef SET_PCIE_IRQ_CPU_CORE
12676 	else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
12677 		int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
12678 		wl_android_set_irq_cpucore(net, affinity_cmd);
12679 	}
12680 #endif /* SET_PCIE_IRQ_CPU_CORE */
12681 #if defined(DHD_HANG_SEND_UP_TEST)
12682 	else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
12683 		int skip = strlen(CMD_MAKE_HANG) + 1;
12684 		wl_android_make_hang_with_reason(net, (const char*)command+skip);
12685 	}
12686 #endif /* DHD_HANG_SEND_UP_TEST */
12687 #ifdef SUPPORT_LQCM
12688 	else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
12689 		int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
12690 		bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
12691 	}
12692 	else if (strnicmp(command, CMD_GET_LQCM_REPORT,
12693 			strlen(CMD_GET_LQCM_REPORT)) == 0) {
12694 		bytes_written = wl_android_get_lqcm_report(net, command,
12695 			priv_cmd.total_len);
12696 	}
12697 #endif
12698 	else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
12699 		bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
12700 	}
12701 #ifdef WLADPS_PRIVATE_CMD
12702 	else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
12703 		int skip = strlen(CMD_SET_ADPS) + 1;
12704 		bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
12705 	}
12706 	else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
12707 		bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
12708 	}
12709 #ifdef WLADPS_ENERGY_GAIN
12710 	else if (strnicmp(command, CMD_GET_GAIN_ADPS, strlen(CMD_GET_GAIN_ADPS)) == 0) {
12711 		bytes_written = wl_android_get_gain_adps(net, command, priv_cmd.total_len);
12712 	}
12713 	else if (strnicmp(command, CMD_RESET_GAIN_ADPS, strlen(CMD_RESET_GAIN_ADPS)) == 0) {
12714 		bytes_written = wl_android_reset_gain_adps(net, command);
12715 	}
12716 #endif	/* WLADPS_ENERGY_GAIN */
12717 #endif /* WLADPS_PRIVATE_CMD */
12718 #ifdef DHD_PKT_LOGGING
12719 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
12720 		strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
12721 		bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
12722 	}
12723 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
12724 		strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
12725 		bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
12726 	}
12727 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
12728 		strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
12729 		bytes_written =
12730 			wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
12731 	}
12732 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
12733 		strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
12734 		bytes_written =
12735 			wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
12736 	}
12737 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
12738 		bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
12739 	}
12740 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DEL, strlen(CMD_PKTLOG_FILTER_DEL)) == 0) {
12741 		bytes_written = wl_android_pktlog_filter_del(net, command, priv_cmd.total_len);
12742 	}
12743 	else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
12744 		bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
12745 	}
12746 	else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
12747 		bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
12748 	}
12749 	else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
12750 		bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
12751 	}
12752 	else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
12753 		bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
12754 	}
12755 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
12756 		strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
12757 		bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
12758 	}
12759 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
12760 		strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
12761 		bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
12762 	}
12763 	else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
12764 		strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
12765 		bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
12766 	}
12767 	else if (strnicmp(command, CMD_PKTLOG_DEBUG_DUMP, strlen(CMD_PKTLOG_DEBUG_DUMP)) == 0) {
12768 		bytes_written = wl_android_pktlog_dbg_dump(net, command, priv_cmd.total_len);
12769 	}
12770 #endif /* DHD_PKT_LOGGING */
12771 #ifdef WL_CFG80211
12772 	else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
12773 		int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
12774 		bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
12775 	}
12776 #endif /* WL_CFG80211 */
12777 #ifdef DHD_EVENT_LOG_FILTER
12778 	else if (strnicmp(command, CMD_EWP_FILTER,
12779 		strlen(CMD_EWP_FILTER)) == 0) {
12780 		bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
12781 	}
12782 #endif /* DHD_EVENT_LOG_FILTER */
12783 #ifdef WL_BCNRECV
12784 	else if (strnicmp(command, CMD_BEACON_RECV,
12785 		strlen(CMD_BEACON_RECV)) == 0) {
12786 		char *data = (command + strlen(CMD_BEACON_RECV) + 1);
12787 		bytes_written = wl_android_bcnrecv_config(net,
12788 				data, priv_cmd.total_len);
12789 	}
12790 #endif /* WL_BCNRECV */
12791 #ifdef WL_MBO
12792 	else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
12793 		bytes_written = wl_android_process_mbo_cmd(net, command,
12794 			priv_cmd.total_len);
12795 	}
12796 #endif /* WL_MBO */
12797 #ifdef WL_CAC_TS
12798 	else if (strnicmp(command, CMD_CAC_TSPEC,
12799 		strlen(CMD_CAC_TSPEC)) == 0) {
12800 		char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
12801 		bytes_written = wl_android_cac_ts_config(net,
12802 				data, priv_cmd.total_len);
12803 	}
12804 #endif /* WL_CAC_TS */
12805 #ifdef WL_GET_CU
12806 	else if (strnicmp(command, CMD_GET_CHAN_UTIL,
12807 		strlen(CMD_GET_CHAN_UTIL)) == 0) {
12808 		bytes_written = wl_android_get_channel_util(net,
12809 			command, priv_cmd.total_len);
12810 	}
12811 #endif /* WL_GET_CU */
12812 #ifdef RTT_GEOFENCE_INTERVAL
12813 #if defined (RTT_SUPPORT) && defined(WL_NAN)
12814 	else if (strnicmp(command, CMD_GEOFENCE_INTERVAL,
12815 			strlen(CMD_GEOFENCE_INTERVAL)) == 0) {
12816 		(void)wl_android_set_rtt_geofence_interval(net, command);
12817 	}
12818 #endif /* RTT_SUPPORT && WL_NAN */
12819 #endif /* RTT_GEOFENCE_INTERVAL */
12820 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
12821 	else if (strnicmp(command, CMD_SET_SOFTAP_ELNA_BYPASS,
12822 			strlen(CMD_SET_SOFTAP_ELNA_BYPASS)) == 0) {
12823 		bytes_written =
12824 			wl_android_set_softap_elna_bypass(net, command, priv_cmd.total_len);
12825 	}
12826 	else if (strnicmp(command, CMD_GET_SOFTAP_ELNA_BYPASS,
12827 			strlen(CMD_GET_SOFTAP_ELNA_BYPASS)) == 0) {
12828 		bytes_written =
12829 			wl_android_get_softap_elna_bypass(net, command, priv_cmd.total_len);
12830 	}
12831 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
12832 #ifdef WL_NAN
12833 	else if (strnicmp(command, CMD_GET_NAN_STATUS,
12834 			strlen(CMD_GET_NAN_STATUS)) == 0) {
12835 		bytes_written =
12836 			wl_android_get_nan_status(net, command, priv_cmd.total_len);
12837 	}
12838 #endif /* WL_NAN */
12839 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
12840 	else if (strnicmp(command, CMD_NAN_RANGING_SET_BW, strlen(CMD_NAN_RANGING_SET_BW)) == 0) {
12841 		int bw_cmd = *(command + strlen(CMD_NAN_RANGING_SET_BW) + 1) - '0';
12842 		bytes_written = wl_nan_ranging_bw(net, bw_cmd, command);
12843 	}
12844 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
12845 	else if (strnicmp(command, CMD_GET_FACTORY_MAC, strlen(CMD_GET_FACTORY_MAC)) == 0) {
12846 		bytes_written = wl_android_get_factory_mac_addr(net, command, priv_cmd.total_len);
12847 	}
12848 	else if (strnicmp(command, CMD_HAPD_SET_AX_MODE, strlen(CMD_HAPD_SET_AX_MODE)) == 0) {
12849 		int skip = strlen(CMD_HAPD_SET_AX_MODE) + 1;
12850 		bytes_written = wl_android_set_softap_ax_mode(net, command + skip);
12851 	}
12852 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
12853 	else if (strnicmp(command, CMD_SET_LATENCY_CRITICAL_DATA,
12854 		strlen(CMD_SET_LATENCY_CRITICAL_DATA)) == 0) {
12855 		int enable = *(command + strlen(CMD_SET_LATENCY_CRITICAL_DATA) + 1) - '0';
12856 		bytes_written = wl_android_set_latency_crt_data(net, enable);
12857 	}
12858 	else if  (strnicmp(command, CMD_GET_LATENCY_CRITICAL_DATA,
12859 		strlen(CMD_GET_LATENCY_CRITICAL_DATA)) == 0) {
12860 		bytes_written = wl_android_get_latency_crt_data(net, command, priv_cmd.total_len);
12861 	}
12862 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
12863 #ifdef WL_TWT
12864 	else if (strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) {
12865 		bytes_written = wl_android_twt_setup(net, command, priv_cmd.total_len);
12866 	}
12867 	else if (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) {
12868 		bytes_written = wl_android_twt_teardown(net, command, priv_cmd.total_len);
12869 	}
12870 	else if (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0) {
12871 		bytes_written = wl_android_twt_info(net, command, priv_cmd.total_len);
12872 	}
12873 	else if (strnicmp(command, CMD_TWT_STATUS_QUERY, strlen(CMD_TWT_STATUS_QUERY)) == 0) {
12874 		bytes_written = wl_android_twt_status_query(net, command, priv_cmd.total_len);
12875 	}
12876 	else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) {
12877 		bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len);
12878 	}
12879 #endif /* WL_TWT */
12880 #ifdef WL_P2P_6G
12881 	else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) {
12882 		int enable = *(command + strlen(CMD_ENABLE_6G_P2P) + 1) - '0';
12883 		bytes_written = wl_android_enable_p2p_6g(net, enable);
12884 	}
12885 #endif /* WL_P2P_6G */
12886 	else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len, &bytes_written) == 0) {
12887 	}
12888 	else {
12889 		ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
12890 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
12891 	}
12892 
12893 	return bytes_written;
12894 }
12895 
12896 /*
12897 * ENABLE_INSMOD_NO_FW_LOAD	X O O O
12898 * ENABLE_INSMOD_NO_POWER_OFF	X X O O
12899 * NO_POWER_OFF_AFTER_OPEN	X X X O
12900 * after insmod					H L H H
12901 * wlan0 down					H L L H
12902 * fw trap trigger wlan0 down		H L L L
12903 */
12904 
wl_android_init(void)12905 int wl_android_init(void)
12906 {
12907 	int ret = 0;
12908 
12909 #ifdef ENABLE_INSMOD_NO_POWER_OFF
12910 	dhd_download_fw_on_driverload = TRUE;
12911 #elif defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE)
12912 	dhd_download_fw_on_driverload = FALSE;
12913 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
12914 	if (!iface_name[0]) {
12915 		bzero(iface_name, IFNAMSIZ);
12916 		bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
12917 	}
12918 
12919 #ifdef CUSTOMER_HW4_DEBUG
12920 	/* No Kernel Panic from ASSERT() on customer platform. */
12921 	g_assert_type = 1;
12922 #endif /* CUSTOMER_HW4_DEBUG */
12923 
12924 #ifdef WL_GENL
12925 	wl_genl_init();
12926 #endif
12927 #ifdef WL_RELMCAST
12928 	wl_netlink_init();
12929 #endif /* WL_RELMCAST */
12930 
12931 	return ret;
12932 }
12933 
wl_android_exit(void)12934 int wl_android_exit(void)
12935 {
12936 	int ret = 0;
12937 	struct io_cfg *cur, *q;
12938 
12939 #ifdef WL_GENL
12940 	wl_genl_deinit();
12941 #endif /* WL_GENL */
12942 #ifdef WL_RELMCAST
12943 	wl_netlink_deinit();
12944 #endif /* WL_RELMCAST */
12945 
12946 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
12947 	list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
12948 		GCC_DIAGNOSTIC_POP();
12949 		list_del(&cur->list);
12950 		kfree(cur);
12951 	}
12952 
12953 	return ret;
12954 }
12955 
wl_android_post_init(void)12956 void wl_android_post_init(void)
12957 {
12958 
12959 #ifdef ENABLE_4335BT_WAR
12960 	bcm_bt_unlock(lock_cookie_wifi);
12961 	ANDROID_ERROR(("%s: btlock released\n", __FUNCTION__));
12962 #endif /* ENABLE_4335BT_WAR */
12963 
12964 	if (!dhd_download_fw_on_driverload) {
12965 		g_wifi_on = FALSE;
12966 	}
12967 }
12968 
12969 #ifdef WL_GENL
12970 /* Generic Netlink Initializaiton */
wl_genl_init(void)12971 static int wl_genl_init(void)
12972 {
12973 	int ret;
12974 
12975 	ANDROID_INFO(("GEN Netlink Init\n\n"));
12976 
12977 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
12978 	/* register new family */
12979 	ret = genl_register_family(&wl_genl_family);
12980 	if (ret != 0)
12981 		goto failure;
12982 
12983 	/* register functions (commands) of the new family */
12984 	ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
12985 	if (ret != 0) {
12986 		ANDROID_ERROR(("register ops failed: %i\n", ret));
12987 		genl_unregister_family(&wl_genl_family);
12988 		goto failure;
12989 	}
12990 
12991 	ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
12992 #else
12993 	ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
12994 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
12995 	if (ret != 0) {
12996 		ANDROID_ERROR(("register mc_group failed: %i\n", ret));
12997 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
12998 		genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
12999 #endif
13000 		genl_unregister_family(&wl_genl_family);
13001 		goto failure;
13002 	}
13003 
13004 	return 0;
13005 
13006 failure:
13007 	ANDROID_ERROR(("Registering Netlink failed!!\n"));
13008 	return -1;
13009 }
13010 
13011 /* Generic netlink deinit */
wl_genl_deinit(void)13012 static int wl_genl_deinit(void)
13013 {
13014 
13015 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13016 	if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
13017 		ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13018 #endif
13019 	if (genl_unregister_family(&wl_genl_family) < 0)
13020 		ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13021 
13022 	return 0;
13023 }
13024 
wl_event_to_bcm_event(u16 event_type)13025 s32 wl_event_to_bcm_event(u16 event_type)
13026 {
13027 	/* When you add any new event, please mention the
13028 	 * version of BCM supplicant supporting it
13029 	 */
13030 	u16 event = -1;
13031 
13032 	switch (event_type) {
13033 		case WLC_E_SERVICE_FOUND:
13034 			event = BCM_E_SVC_FOUND;
13035 			break;
13036 		case WLC_E_P2PO_ADD_DEVICE:
13037 			event = BCM_E_DEV_FOUND;
13038 			break;
13039 		case WLC_E_P2PO_DEL_DEVICE:
13040 			event = BCM_E_DEV_LOST;
13041 			break;
13042 	/* Above events are supported from BCM Supp ver 47 Onwards */
13043 #ifdef BT_WIFI_HANDOVER
13044 		case WLC_E_BT_WIFI_HANDOVER_REQ:
13045 			event = BCM_E_DEV_BT_WIFI_HO_REQ;
13046 			break;
13047 #endif /* BT_WIFI_HANDOVER */
13048 
13049 		default:
13050 			ANDROID_ERROR(("Event not supported\n"));
13051 	}
13052 
13053 	return event;
13054 }
13055 
13056 s32
wl_genl_send_msg(struct net_device * ndev,u32 event_type,const u8 * buf,u16 len,u8 * subhdr,u16 subhdr_len)13057 wl_genl_send_msg(
13058 	struct net_device *ndev,
13059 	u32 event_type,
13060 	const u8 *buf,
13061 	u16 len,
13062 	u8 *subhdr,
13063 	u16 subhdr_len)
13064 {
13065 	int ret = 0;
13066 	struct sk_buff *skb;
13067 	void *msg;
13068 	u32 attr_type = 0;
13069 	bcm_event_hdr_t *hdr = NULL;
13070 	int mcast = 1; /* By default sent as mutlicast type */
13071 	int pid = 0;
13072 	u8 *ptr = NULL, *p = NULL;
13073 	u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
13074 	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13075 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13076 
13077 	ANDROID_INFO(("Enter \n"));
13078 
13079 	/* Decide between STRING event and Data event */
13080 	if (event_type == 0)
13081 		attr_type = BCM_GENL_ATTR_STRING;
13082 	else
13083 		attr_type = BCM_GENL_ATTR_MSG;
13084 
13085 	skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
13086 	if (skb == NULL) {
13087 		ret = -ENOMEM;
13088 		goto out;
13089 	}
13090 
13091 	msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
13092 	if (msg == NULL) {
13093 		ret = -ENOMEM;
13094 		goto out;
13095 	}
13096 
13097 	if (attr_type == BCM_GENL_ATTR_STRING) {
13098 		/* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
13099 		 * make sure it is null terminated
13100 		 */
13101 		if (subhdr || subhdr_len) {
13102 			ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n"));
13103 			ret =  -EINVAL;
13104 			goto out;
13105 		}
13106 
13107 		ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
13108 		if (ret != 0) {
13109 			ANDROID_ERROR(("nla_put_string failed\n"));
13110 			goto out;
13111 		}
13112 	} else {
13113 		/* ATTR_MSG */
13114 
13115 		/* Create a single buffer for all */
13116 		p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
13117 		if (!ptr) {
13118 			ret = -ENOMEM;
13119 			ANDROID_ERROR(("ENOMEM!!\n"));
13120 			goto out;
13121 		}
13122 
13123 		/* Include the bcm event header */
13124 		hdr = (bcm_event_hdr_t *)ptr;
13125 		hdr->event_type = wl_event_to_bcm_event(event_type);
13126 		hdr->len = len + subhdr_len;
13127 		ptr += sizeof(bcm_event_hdr_t);
13128 
13129 		/* Copy subhdr (if any) */
13130 		if (subhdr && subhdr_len) {
13131 			memcpy(ptr, subhdr, subhdr_len);
13132 			ptr += subhdr_len;
13133 		}
13134 
13135 		/* Copy the data */
13136 		if (buf && len) {
13137 			memcpy(ptr, buf, len);
13138 		}
13139 
13140 		ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
13141 		if (ret != 0) {
13142 			ANDROID_ERROR(("nla_put_string failed\n"));
13143 			goto out;
13144 		}
13145 	}
13146 
13147 	if (mcast) {
13148 		int err = 0;
13149 		/* finalize the message */
13150 		genlmsg_end(skb, msg);
13151 		/* NETLINK_CB(skb).dst_group = 1; */
13152 
13153 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
13154 		if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
13155 #else
13156 		if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
13157 #endif
13158 			ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
13159 				attr_type, err));
13160 		else
13161 			ANDROID_INFO(("Multicast msg sent successfully. attr_type:%d len:%d \n",
13162 				attr_type, tot_len));
13163 	} else {
13164 		NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
13165 
13166 		/* finalize the message */
13167 		genlmsg_end(skb, msg);
13168 
13169 		/* send the message back */
13170 		if (genlmsg_unicast(&init_net, skb, pid) < 0)
13171 			ANDROID_ERROR(("genlmsg_unicast failed\n"));
13172 	}
13173 
13174 out:
13175 	if (p) {
13176 		MFREE(cfg->osh, p, tot_len);
13177 	}
13178 	if (ret)
13179 		nlmsg_free(skb);
13180 
13181 	return ret;
13182 }
13183 
13184 static s32
wl_genl_handle_msg(struct sk_buff * skb,struct genl_info * info)13185 wl_genl_handle_msg(
13186 	struct sk_buff *skb,
13187 	struct genl_info *info)
13188 {
13189 	struct nlattr *na;
13190 	u8 *data = NULL;
13191 
13192 	ANDROID_INFO(("Enter \n"));
13193 
13194 	if (info == NULL) {
13195 		return -EINVAL;
13196 	}
13197 
13198 	na = info->attrs[BCM_GENL_ATTR_MSG];
13199 	if (!na) {
13200 		ANDROID_ERROR(("nlattribute NULL\n"));
13201 		return -EINVAL;
13202 	}
13203 
13204 	data = (char *)nla_data(na);
13205 	if (!data) {
13206 		ANDROID_ERROR(("Invalid data\n"));
13207 		return -EINVAL;
13208 	} else {
13209 		/* Handle the data */
13210 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || \
13211 	defined(WL_COMPAT_WIRELESS)
13212 		ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13213 			info->snd_pid));
13214 #else
13215 		ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13216 			info->snd_portid));
13217 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
13218 	}
13219 
13220 	return 0;
13221 }
13222 #endif /* WL_GENL */
13223 
wl_fatal_error(void * wl,int rc)13224 int wl_fatal_error(void * wl, int rc)
13225 {
13226 	return FALSE;
13227 }
13228 
13229 void
wl_android_set_wifi_on_flag(bool enable)13230 wl_android_set_wifi_on_flag(bool enable)
13231 {
13232 	ANDROID_ERROR(("%s: %d\n", __FUNCTION__, enable));
13233 	g_wifi_on = enable;
13234 }
13235 
13236 #ifdef WL_STATIC_IF
13237 #include <dhd_linux_priv.h>
13238 struct net_device *
wl_cfg80211_register_static_if(struct bcm_cfg80211 * cfg,u16 iftype,char * ifname,int static_ifidx)13239 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname,
13240 	int static_ifidx)
13241 {
13242 #if defined(CUSTOM_MULTI_MAC) || defined(WL_EXT_IAPSTA)
13243 	dhd_pub_t *dhd = cfg->pub;
13244 #endif
13245 	struct net_device *ndev;
13246 	struct wireless_dev *wdev = NULL;
13247 	int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
13248 	u8 mac_addr[ETH_ALEN];
13249 	struct net_device *primary_ndev;
13250 #ifdef DHD_USE_RANDMAC
13251 	struct ether_addr ea_addr;
13252 #endif /* DHD_USE_RANDMAC */
13253 #ifdef CUSTOM_MULTI_MAC
13254 	char hw_ether[62];
13255 #endif
13256 
13257 	ANDROID_INFO(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
13258 
13259 	if (!cfg) {
13260 		ANDROID_ERROR(("cfg null\n"));
13261 		return NULL;
13262 	}
13263 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13264 
13265 	ifidx += static_ifidx;
13266 #ifdef DHD_USE_RANDMAC
13267 	wl_cfg80211_generate_mac_addr(&ea_addr);
13268 	(void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN);
13269 #else
13270 #if defined(CUSTOM_MULTI_MAC)
13271 	if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) {
13272 		(void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN);
13273 	} else
13274 #endif
13275 	{
13276 		/* Use primary mac with locally admin bit set */
13277 		(void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
13278 		mac_addr[0] |= 0x02;
13279 #ifdef WL_EXT_IAPSTA
13280 		wl_ext_iapsta_get_vif_macaddr(dhd, static_ifidx+1, mac_addr);
13281 #endif
13282 	}
13283 #endif /* DHD_USE_RANDMAC */
13284 
13285 	ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
13286 		WL_BSSIDX_MAX, NULL);
13287 	if (unlikely(!ndev)) {
13288 		ANDROID_ERROR(("Failed to allocate static_if\n"));
13289 		goto fail;
13290 	}
13291 	wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
13292 	if (unlikely(!wdev)) {
13293 		ANDROID_ERROR(("Failed to allocate wdev for static_if\n"));
13294 		goto fail;
13295 	}
13296 
13297 	wdev->wiphy = cfg->wdev->wiphy;
13298 	wdev->iftype = iftype;
13299 
13300 	ndev->ieee80211_ptr = wdev;
13301 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
13302 	wdev->netdev = ndev;
13303 
13304 	if (wl_cfg80211_register_if(cfg, ifidx,
13305 		ndev, TRUE) != BCME_OK) {
13306 		ANDROID_ERROR(("ndev registration failed!\n"));
13307 		goto fail;
13308 	}
13309 
13310 	cfg->static_ndev[static_ifidx] = ndev;
13311 	cfg->static_ndev_state[static_ifidx] = NDEV_STATE_OS_IF_CREATED;
13312 	wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
13313 		ifname, NDEV_STATE_OS_IF_CREATED);
13314 	ANDROID_INFO(("Static I/F (%s) Registered\n", ndev->name));
13315 	return ndev;
13316 
13317 fail:
13318 	wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
13319 	return NULL;
13320 }
13321 
13322 void
wl_cfg80211_unregister_static_if(struct bcm_cfg80211 * cfg)13323 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
13324 {
13325 	int i;
13326 
13327 	ANDROID_INFO(("[STATIC_IF] Enter\n"));
13328 	if (!cfg) {
13329 		ANDROID_ERROR(("invalid input\n"));
13330 		return;
13331 	}
13332 
13333 	/* wdev free will happen from notifier context */
13334 	/* free_netdev(cfg->static_ndev);
13335 	*/
13336 	for (i=0; i<DHD_MAX_STATIC_IFS; i++) {
13337 		if (cfg->static_ndev[i])
13338 			unregister_netdev(cfg->static_ndev[i]);
13339 	}
13340 }
13341 
13342 s32
wl_cfg80211_static_if_open(struct net_device * net)13343 wl_cfg80211_static_if_open(struct net_device *net)
13344 {
13345 	struct wireless_dev *wdev = NULL;
13346 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13347 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13348 	u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
13349 	u16 wl_iftype, wl_mode;
13350 #ifdef CUSTOM_MULTI_MAC
13351 	dhd_pub_t *dhd = dhd_get_pub(net);
13352 	char hw_ether[62];
13353 #endif
13354 	int static_ifidx;
13355 
13356 	ANDROID_INFO(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
13357 	static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
13358 	ASSERT(static_ifidx >= 0);
13359 
13360 	if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) <  0) {
13361 		return BCME_ERROR;
13362 	}
13363 	if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) {
13364 #ifdef CUSTOM_MULTI_MAC
13365 		if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1))
13366 			dev_addr_set(net, hw_ether);
13367 #endif
13368 		wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr);
13369 		if (!wdev) {
13370 			ANDROID_ERROR(("[STATIC_IF] wdev is NULL, can't proceed\n"));
13371 			return BCME_ERROR;
13372 		}
13373 	} else {
13374 		ANDROID_INFO(("Fw IF for static netdev already created\n"));
13375 	}
13376 
13377 	return BCME_OK;
13378 }
13379 
13380 s32
wl_cfg80211_static_if_close(struct net_device * net)13381 wl_cfg80211_static_if_close(struct net_device *net)
13382 {
13383 	int ret = BCME_OK;
13384 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13385 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13386 	int static_ifidx;
13387 
13388 	static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
13389 
13390 	if (cfg->static_ndev_state[static_ifidx] == NDEV_STATE_FW_IF_CREATED) {
13391 		if (mutex_is_locked(&cfg->if_sync) == TRUE) {
13392 			ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13393 		} else {
13394 			ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13395 		}
13396 
13397 		if (unlikely(ret)) {
13398 			ANDROID_ERROR(("Del iface failed for static_if %d\n", ret));
13399 		}
13400 	}
13401 
13402 	return ret;
13403 }
13404 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)13405 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
13406 	wl_if_event_info *event, u8 *addr, s32 iface_type, int static_ifidx)
13407 {
13408 	struct net_device *new_ndev = NULL;
13409 	struct wireless_dev *wdev = NULL;
13410 
13411 	ANDROID_INFO(("Updating static iface after Fw IF create \n"));
13412 	new_ndev = cfg->static_ndev[static_ifidx];
13413 
13414 	if (new_ndev) {
13415 		wdev = new_ndev->ieee80211_ptr;
13416 		ASSERT(wdev);
13417 		wdev->iftype = iface_type;
13418 		dev_addr_set(new_ndev, addr);
13419 	}
13420 
13421 	cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED;
13422 	wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
13423 		event->name, NDEV_STATE_FW_IF_CREATED);
13424 	return new_ndev;
13425 }
13426 s32
wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 * cfg,struct net_device * ndev)13427 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13428 {
13429 	int static_ifidx;
13430 	int ifidx = WL_STATIC_IFIDX;
13431 
13432 	static_ifidx = wl_cfg80211_static_ifidx(cfg, ndev);
13433 	ifidx += static_ifidx;
13434 	cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_DELETED;
13435 	wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL,
13436 		WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
13437 	wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
13438 	wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
13439 	return BCME_OK;
13440 }
13441 #endif /* WL_STATIC_IF */
13442 
13443 #ifdef WBTEXT
13444 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)13445 wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
13446 	uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size)
13447 {
13448 	int err = BCME_OK;
13449 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13450 	u8 *ioctl_buf = NULL;
13451 
13452 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13453 	if (unlikely(!ioctl_buf)) {
13454 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13455 		err =  -ENOMEM;
13456 		goto exit;
13457 	}
13458 	rp->v1.band = band;
13459 	rp->v1.len = 0;
13460 	/* Getting roam profile from fw */
13461 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13462 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13463 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13464 		goto exit;
13465 	}
13466 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13467 	/* roam_prof version get */
13468 	if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13469 		ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13470 		err = BCME_VERSION;
13471 		goto exit;
13472 	}
13473 	switch (rp->v1.ver) {
13474 		case WL_ROAM_PROF_VER_0:
13475 		{
13476 			*roam_prof_size = sizeof(wl_roam_prof_v1_t);
13477 			*roam_prof_ver = WL_ROAM_PROF_VER_0;
13478 		}
13479 		break;
13480 		case WL_ROAM_PROF_VER_1:
13481 		{
13482 			*roam_prof_size = sizeof(wl_roam_prof_v2_t);
13483 			*roam_prof_ver = WL_ROAM_PROF_VER_1;
13484 		}
13485 		break;
13486 		case WL_ROAM_PROF_VER_2:
13487 		{
13488 			*roam_prof_size = sizeof(wl_roam_prof_v3_t);
13489 			*roam_prof_ver = WL_ROAM_PROF_VER_2;
13490 		}
13491 		break;
13492 		case WL_ROAM_PROF_VER_3:
13493 		{
13494 			*roam_prof_size = sizeof(wl_roam_prof_v4_t);
13495 			*roam_prof_ver = WL_ROAM_PROF_VER_3;
13496 		}
13497 		break;
13498 		default:
13499 			ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13500 			err = BCME_VERSION;
13501 			goto exit;
13502 	}
13503 	ANDROID_INFO(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size));
13504 	if ((rp->v1.len % *roam_prof_size) != 0) {
13505 		ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13506 		err = BCME_BADLEN;
13507 	}
13508 exit:
13509 	if (ioctl_buf) {
13510 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13511 	}
13512 	return err;
13513 }
13514 
13515 s32
wl_cfg80211_wbtext_set_default(struct net_device * ndev)13516 wl_cfg80211_wbtext_set_default(struct net_device *ndev)
13517 {
13518 	char *commandp = NULL;
13519 	s32 ret = BCME_OK;
13520 	char *data;
13521 	u8 *ioctl_buf = NULL;
13522 	wl_roamprof_band_t rp;
13523 	uint8 bandidx = 0;
13524 	int wnmmask = 0;
13525 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13526 
13527 	ANDROID_INFO(("set wbtext to default\n"));
13528 
13529 	commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13530 	if (unlikely(!commandp)) {
13531 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13532 		ret =  -ENOMEM;
13533 		goto exit;
13534 	}
13535 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13536 	if (unlikely(!ioctl_buf)) {
13537 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13538 		ret =  -ENOMEM;
13539 		goto exit;
13540 	}
13541 
13542 	rp.v1.band = WLC_BAND_2G;
13543 	rp.v1.len = 0;
13544 	/* Getting roam profile from fw */
13545 	if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp),
13546 		ioctl_buf, WLC_IOCTL_SMLEN, NULL))) {
13547 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", ret));
13548 		goto exit;
13549 	}
13550 	memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp));
13551 	for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
13552 		switch (rp.v1.ver) {
13553 			case WL_ROAM_PROF_VER_1:
13554 			{
13555 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13556 				if (bandidx == BAND_5G_INDEX) {
13557 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13558 						CMD_WBTEXT_PROFILE_CONFIG,
13559 						DEFAULT_WBTEXT_PROFILE_A_V2);
13560 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13561 				} else {
13562 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13563 						CMD_WBTEXT_PROFILE_CONFIG,
13564 						DEFAULT_WBTEXT_PROFILE_B_V2);
13565 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13566 				}
13567 			}
13568 			break;
13569 			case WL_ROAM_PROF_VER_2:
13570 			case WL_ROAM_PROF_VER_3:
13571 			{
13572 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13573 				if (bandidx == BAND_5G_INDEX) {
13574 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13575 						CMD_WBTEXT_PROFILE_CONFIG,
13576 						DEFAULT_WBTEXT_PROFILE_A_V3);
13577 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13578 				} else {
13579 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13580 						CMD_WBTEXT_PROFILE_CONFIG,
13581 						DEFAULT_WBTEXT_PROFILE_B_V3);
13582 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13583 				}
13584 			}
13585 			break;
13586 			default:
13587 				ANDROID_ERROR(("No Support for roam prof ver = %d \n", rp.v1.ver));
13588 				ret = -EINVAL;
13589 				goto exit;
13590 		}
13591 		/* set roam profile */
13592 		ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13593 		if (ret != BCME_OK) {
13594 			ANDROID_ERROR(("%s: Failed to set roam_prof %s error = %d\n",
13595 				__FUNCTION__, data, ret));
13596 			goto exit;
13597 		}
13598 	}
13599 
13600 	/* wbtext code for backward compatibility. Newer firmwares set default value
13601 	* from fw init
13602 	*/
13603 	/* set RSSI weight */
13604 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13605 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13606 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
13607 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13608 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13609 	if (ret != BCME_OK) {
13610 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13611 			__FUNCTION__, data, ret));
13612 		goto exit;
13613 	}
13614 
13615 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13616 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13617 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
13618 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13619 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13620 	if (ret != BCME_OK) {
13621 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13622 			__FUNCTION__, data, ret));
13623 		goto exit;
13624 	}
13625 
13626 	/* set CU weight */
13627 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13628 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13629 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
13630 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13631 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13632 	if (ret != BCME_OK) {
13633 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13634 			__FUNCTION__, data, ret));
13635 		goto exit;
13636 	}
13637 
13638 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13639 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13640 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
13641 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13642 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13643 	if (ret != BCME_OK) {
13644 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13645 			__FUNCTION__, data, ret));
13646 		goto exit;
13647 	}
13648 
13649 	ret = wldev_iovar_getint(ndev, "wnm", &wnmmask);
13650 	if (ret != BCME_OK) {
13651 		ANDROID_ERROR(("%s: Failed to get wnmmask error = %d\n", __func__, ret));
13652 		goto exit;
13653 	}
13654 	/* set ESTM DL weight. */
13655 	if (wnmmask & WL_WNM_ESTM) {
13656 		ANDROID_ERROR(("Setting ESTM wt\n"));
13657 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13658 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13659 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A);
13660 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13661 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13662 		if (ret != BCME_OK) {
13663 			ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13664 				__FUNCTION__, data, ret));
13665 			goto exit;
13666 		}
13667 
13668 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13669 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13670 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B);
13671 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13672 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13673 		if (ret != BCME_OK) {
13674 			ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13675 				__FUNCTION__, data, ret));
13676 			goto exit;
13677 		}
13678 	}
13679 
13680 	/* set RSSI table */
13681 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13682 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13683 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
13684 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13685 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13686 	if (ret != BCME_OK) {
13687 		ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13688 			__FUNCTION__, data, ret));
13689 		goto exit;
13690 	}
13691 
13692 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13693 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13694 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
13695 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13696 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13697 	if (ret != BCME_OK) {
13698 		ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13699 			__FUNCTION__, data, ret));
13700 		goto exit;
13701 	}
13702 
13703 	/* set CU table */
13704 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13705 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13706 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
13707 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13708 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13709 	if (ret != BCME_OK) {
13710 		ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13711 			__FUNCTION__, data, ret));
13712 		goto exit;
13713 	}
13714 
13715 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13716 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13717 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
13718 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13719 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13720 	if (ret != BCME_OK) {
13721 		ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13722 			__FUNCTION__, data, ret));
13723 		goto exit;
13724 	}
13725 
13726 exit:
13727 	if (commandp) {
13728 		MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
13729 	}
13730 	if (ioctl_buf) {
13731 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_SMLEN);
13732 	}
13733 	return ret;
13734 }
13735 
13736 s32
wl_cfg80211_wbtext_config(struct net_device * ndev,char * data,char * command,int total_len)13737 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
13738 {
13739 	uint i = 0;
13740 	long int rssi_lower, roam_trigger;
13741 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13742 	wl_roamprof_band_t *rp = NULL;
13743 	int err = -EINVAL, bytes_written = 0;
13744 	size_t len = strlen(data);
13745 	int rp_len = 0;
13746 	u8 *ioctl_buf = NULL;
13747 	uint8 roam_prof_size = 0, roam_prof_ver = 0, fs_per = 0, prof_cnt = 0;
13748 
13749 	data[len] = '\0';
13750 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13751 	if (unlikely(!ioctl_buf)) {
13752 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13753 		err =  -ENOMEM;
13754 		goto exit;
13755 	}
13756 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
13757 	if (unlikely(!rp)) {
13758 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13759 		err =  -ENOMEM;
13760 		goto exit;
13761 	}
13762 	if (*data && (!strncmp(data, "b", 1))) {
13763 		rp->v1.band = WLC_BAND_2G;
13764 	} else if (*data && (!strncmp(data, "a", 1))) {
13765 		rp->v1.band = WLC_BAND_5G;
13766 	} else {
13767 		err = snprintf(command, total_len, "Missing band\n");
13768 		goto exit;
13769 	}
13770 	data++;
13771 	rp->v1.len = 0;
13772 	/* Getting roam profile from fw */
13773 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13774 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13775 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13776 		goto exit;
13777 	}
13778 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13779 	/* roam_prof version get */
13780 	if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13781 		ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13782 		err = -EINVAL;
13783 		goto exit;
13784 	}
13785 	switch (rp->v1.ver) {
13786 		case WL_ROAM_PROF_VER_0:
13787 		{
13788 			roam_prof_size = sizeof(wl_roam_prof_v1_t);
13789 			roam_prof_ver = WL_ROAM_PROF_VER_0;
13790 		}
13791 		break;
13792 		case WL_ROAM_PROF_VER_1:
13793 		{
13794 			roam_prof_size = sizeof(wl_roam_prof_v2_t);
13795 			roam_prof_ver = WL_ROAM_PROF_VER_1;
13796 		}
13797 		break;
13798 		case WL_ROAM_PROF_VER_2:
13799 		{
13800 			roam_prof_size = sizeof(wl_roam_prof_v3_t);
13801 			roam_prof_ver = WL_ROAM_PROF_VER_2;
13802 		}
13803 		break;
13804 		case WL_ROAM_PROF_VER_3:
13805 		{
13806 			roam_prof_size = sizeof(wl_roam_prof_v4_t);
13807 			roam_prof_ver = WL_ROAM_PROF_VER_3;
13808 		}
13809 		break;
13810 		default:
13811 			ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13812 			goto exit;
13813 	}
13814 	ANDROID_INFO(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size));
13815 	if ((rp->v1.len % roam_prof_size) != 0) {
13816 		ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13817 		err = -EINVAL;
13818 		goto exit;
13819 	}
13820 	for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13821 		/* printing contents of roam profile data from fw and exits
13822 		 * if code hits any of one of the below condtion. If remaining
13823 		 * length of buffer is less than roam profile size or
13824 		 * if there is no valid entry.
13825 		 */
13826 		if (((i * roam_prof_size) > rp->v1.len)) {
13827 			break;
13828 		}
13829 		if (roam_prof_ver == WL_ROAM_PROF_VER_0) {
13830 			fs_per = rp->v1.roam_prof[i].fullscan_period;
13831 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13832 			fs_per = rp->v2.roam_prof[i].fullscan_period;
13833 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13834 			fs_per = rp->v3.roam_prof[i].fullscan_period;
13835 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13836 			fs_per = rp->v4.roam_prof[i].fullscan_period;
13837 		}
13838 		if (fs_per == 0) {
13839 			break;
13840 		}
13841 		prof_cnt++;
13842 	}
13843 
13844 	if (!*data) {
13845 		for (i = 0; (i < prof_cnt) && (i < WL_MAX_ROAM_PROF_BRACKETS); i++) {
13846 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13847 				bytes_written += scnprintf(command+bytes_written,
13848 					total_len - bytes_written,
13849 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13850 					rp->v2.roam_prof[i].roam_trigger,
13851 					rp->v2.roam_prof[i].rssi_lower,
13852 					rp->v2.roam_prof[i].channel_usage,
13853 					rp->v2.roam_prof[i].cu_avg_calc_dur);
13854 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13855 				bytes_written += scnprintf(command+bytes_written,
13856 					total_len - bytes_written,
13857 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13858 					rp->v3.roam_prof[i].roam_trigger,
13859 					rp->v3.roam_prof[i].rssi_lower,
13860 					rp->v3.roam_prof[i].channel_usage,
13861 					rp->v3.roam_prof[i].cu_avg_calc_dur);
13862 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13863 				bytes_written += snprintf(command+bytes_written,
13864 					total_len - bytes_written,
13865 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13866 					rp->v4.roam_prof[i].roam_trigger,
13867 					rp->v4.roam_prof[i].rssi_lower,
13868 					rp->v4.roam_prof[i].channel_usage,
13869 					rp->v4.roam_prof[i].cu_avg_calc_dur);
13870 			}
13871 		}
13872 		bytes_written += scnprintf(command+bytes_written, total_len - bytes_written, "\n");
13873 		err = bytes_written;
13874 		goto exit;
13875 	} else {
13876 		/* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
13877 		if (prof_cnt != 2) {
13878 			ANDROID_ERROR(("FW must have 2 rows to fill roam_prof\n"));
13879 			err = -EINVAL;
13880 			goto exit;
13881 		}
13882 		/* setting roam profile to fw */
13883 		data++;
13884 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13885 			roam_trigger = simple_strtol(data, &data, 10);
13886 			if (roam_trigger >= 0) {
13887 				ANDROID_ERROR(("roam trigger[%d] value must be negative\n", i));
13888 				err = -EINVAL;
13889 				goto exit;
13890 			}
13891 			data++;
13892 			rssi_lower = simple_strtol(data, &data, 10);
13893 			if (rssi_lower >= 0) {
13894 				ANDROID_ERROR(("rssi lower[%d] value must be negative\n", i));
13895 				err = -EINVAL;
13896 				goto exit;
13897 			}
13898 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13899 				rp->v2.roam_prof[i].roam_trigger = roam_trigger;
13900 				rp->v2.roam_prof[i].rssi_lower = rssi_lower;
13901 				data++;
13902 				rp->v2.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13903 				data++;
13904 				rp->v2.roam_prof[i].cu_avg_calc_dur =
13905 					simple_strtol(data, &data, 10);
13906 			}
13907 			if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13908 				rp->v3.roam_prof[i].roam_trigger = roam_trigger;
13909 				rp->v3.roam_prof[i].rssi_lower = rssi_lower;
13910 				data++;
13911 				rp->v3.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13912 				data++;
13913 				rp->v3.roam_prof[i].cu_avg_calc_dur =
13914 					simple_strtol(data, &data, 10);
13915 			}
13916 			if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13917 				rp->v4.roam_prof[i].roam_trigger = roam_trigger;
13918 				rp->v4.roam_prof[i].rssi_lower = rssi_lower;
13919 				data++;
13920 				rp->v4.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13921 				data++;
13922 				rp->v4.roam_prof[i].cu_avg_calc_dur =
13923 					simple_strtol(data, &data, 10);
13924 			}
13925 
13926 			rp_len += roam_prof_size;
13927 
13928 			if (*data == '\0') {
13929 				break;
13930 			}
13931 			data++;
13932 		}
13933 		if (i != 1) {
13934 			ANDROID_ERROR(("Only two roam_prof rows supported.\n"));
13935 			err = -EINVAL;
13936 			goto exit;
13937 		}
13938 		rp->v1.len = rp_len;
13939 		if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
13940 				sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
13941 				&cfg->ioctl_buf_sync)) < 0) {
13942 			ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
13943 		}
13944 	}
13945 exit:
13946 	if (rp) {
13947 		MFREE(cfg->osh, rp, sizeof(*rp));
13948 	}
13949 	if (ioctl_buf) {
13950 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13951 	}
13952 	return err;
13953 }
13954 
wl_cfg80211_wbtext_weight_config(struct net_device * ndev,char * data,char * command,int total_len)13955 int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
13956 		char *command, int total_len)
13957 {
13958 	int bytes_written = 0, err = -EINVAL, argc = 0;
13959 	char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
13960 	char *endptr = NULL;
13961 	wnm_bss_select_weight_cfg_t *bwcfg;
13962 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
13963 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13964 
13965 	bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
13966 	if (unlikely(!bwcfg)) {
13967 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13968 		err = -ENOMEM;
13969 		goto exit;
13970 	}
13971 	bwcfg->version =  WNM_BSSLOAD_MONITOR_VERSION;
13972 	bwcfg->type = 0;
13973 	bwcfg->weight = 0;
13974 
13975 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
13976 
13977 	if (!strcasecmp(rssi, "rssi"))
13978 		bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
13979 	else if (!strcasecmp(rssi, "cu"))
13980 		bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
13981 	else if (!strcasecmp(rssi, "estm_dl"))
13982 		bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL;
13983 	else {
13984 		/* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu/estm_dl> <band> <weight> */
13985 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
13986 		goto exit;
13987 	}
13988 
13989 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &bwcfg->band)) {
13990 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
13991 		goto exit;
13992 	}
13993 
13994 	if (argc == 2) {
13995 		/* If there is no data after band, getting wnm_bss_select_weight from fw */
13996 		if (bwcfg->band == WLC_BAND_ALL) {
13997 			ANDROID_ERROR(("band option \"all\" is for set only, not get\n"));
13998 			goto exit;
13999 		}
14000 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
14001 				sizeof(*bwcfg),
14002 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14003 			ANDROID_ERROR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
14004 			goto exit;
14005 		}
14006 		memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
14007 		bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
14008 			(bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" :
14009 			(bwcfg->type == WNM_BSS_SELECT_TYPE_CU) ? "CU": "ESTM_DL",
14010 			wl_android_get_band_str(bwcfg->band), bwcfg->weight);
14011 		err = bytes_written;
14012 		goto exit;
14013 	} else {
14014 		/* if weight is non integer returns command usage error */
14015 		bwcfg->weight = simple_strtol(weight, &endptr, 0);
14016 		if (*endptr != '\0') {
14017 			ANDROID_ERROR(("%s: Command usage error", __func__));
14018 			goto exit;
14019 		}
14020 		/* setting weight for iovar wnm_bss_select_weight to fw */
14021 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
14022 				sizeof(*bwcfg),
14023 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14024 			ANDROID_ERROR(("setting wnm_bss_select_weight failed with err=%d\n", err));
14025 		}
14026 	}
14027 exit:
14028 	if (bwcfg) {
14029 		MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
14030 	}
14031 	return err;
14032 }
14033 
14034 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
14035 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
14036 
wl_cfg80211_wbtext_table_config(struct net_device * ndev,char * data,char * command,int total_len)14037 int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
14038 	char *command, int total_len)
14039 {
14040 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14041 	int bytes_written = 0, err = -EINVAL;
14042 	char rssi[BUFSZN], band[BUFSZN];
14043 	int btcfg_len = 0, i = 0, parsed_len = 0;
14044 	wnm_bss_select_factor_cfg_t *btcfg;
14045 	size_t slen = strlen(data);
14046 	char *start_addr = NULL;
14047 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
14048 
14049 	data[slen] = '\0';
14050 	btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
14051 		(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14052 	if (unlikely(!btcfg)) {
14053 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14054 		err = -ENOMEM;
14055 		goto exit;
14056 	}
14057 
14058 	btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
14059 	btcfg->band = WLC_BAND_AUTO;
14060 	btcfg->type = 0;
14061 	btcfg->count = 0;
14062 
14063 	sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
14064 
14065 	if (!strcasecmp(rssi, "rssi")) {
14066 		btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
14067 	}
14068 	else if (!strcasecmp(rssi, "cu")) {
14069 		btcfg->type = WNM_BSS_SELECT_TYPE_CU;
14070 	}
14071 	else {
14072 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
14073 		goto exit;
14074 	}
14075 
14076 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &btcfg->band)) {
14077 		ANDROID_ERROR(("%s: Command usage, Wrong band\n", __func__));
14078 		goto exit;
14079 	}
14080 
14081 	if ((slen - 1) == (strlen(rssi) + strlen(band))) {
14082 		/* Getting factor table using iovar 'wnm_bss_select_table' from fw */
14083 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
14084 				sizeof(*btcfg),
14085 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14086 			ANDROID_ERROR(("Getting wnm_bss_select_table failed with err=%d \n", err));
14087 			goto exit;
14088 		}
14089 		memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
14090 		memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
14091 
14092 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14093 					"No of entries in table: %d\n", btcfg->count);
14094 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14095 				"%s factor table\n",
14096 				(btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
14097 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14098 					"low\thigh\tfactor\n");
14099 		for (i = 0; i <= btcfg->count-1; i++) {
14100 			bytes_written += snprintf(command + bytes_written,
14101 				total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
14102 				btcfg->params[i].high, btcfg->params[i].factor);
14103 		}
14104 		err = bytes_written;
14105 		goto exit;
14106 	} else {
14107 		uint16 len = (sizeof(wnm_bss_select_factor_params_t) * WL_FACTOR_TABLE_MAX_LIMIT);
14108 		memset_s(btcfg->params, len, 0, len);
14109 		data += (strlen(rssi) + strlen(band) + 2);
14110 		start_addr = data;
14111 		slen = slen - (strlen(rssi) + strlen(band) + 2);
14112 		for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
14113 			if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
14114 				btcfg->params[i].low = simple_strtol(data, &data, 10);
14115 				data++;
14116 				btcfg->params[i].high = simple_strtol(data, &data, 10);
14117 				data++;
14118 				btcfg->params[i].factor = simple_strtol(data, &data, 10);
14119 				btcfg->count++;
14120 				if (*data == '\0') {
14121 					break;
14122 				}
14123 				data++;
14124 				parsed_len = data - start_addr;
14125 			} else {
14126 				ANDROID_ERROR(("%s:Command usage:less no of args\n", __func__));
14127 				goto exit;
14128 			}
14129 		}
14130 		btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
14131 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
14132 				cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
14133 			ANDROID_ERROR(("seting wnm_bss_select_table failed with err %d\n", err));
14134 			goto exit;
14135 		}
14136 	}
14137 exit:
14138 	if (btcfg) {
14139 		MFREE(cfg->osh, btcfg,
14140 			(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14141 	}
14142 	return err;
14143 }
14144 
14145 s32
wl_cfg80211_wbtext_delta_config(struct net_device * ndev,char * data,char * command,int total_len)14146 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
14147 {
14148 	uint i = 0;
14149 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14150 	int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
14151 	char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
14152 	wl_roamprof_band_t *rp = NULL;
14153 	uint8 band_val = 0, roam_prof_size = 0, roam_prof_ver = 0;
14154 
14155 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
14156 	if (unlikely(!rp)) {
14157 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14158 		err = -ENOMEM;
14159 		goto exit;
14160 	}
14161 
14162 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
14163 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &band_val)) {
14164 		ANDROID_ERROR(("%s: Missing band\n", __func__));
14165 		goto exit;
14166 	}
14167 	if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver,
14168 		&roam_prof_size))) {
14169 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
14170 		err = -EINVAL;
14171 		goto exit;
14172 	}
14173 	if (argc == 2) {
14174 		/* if delta is non integer returns command usage error */
14175 		val = simple_strtol(delta, &endptr, 0);
14176 		if (*endptr != '\0') {
14177 			ANDROID_ERROR(("%s: Command usage error", __func__));
14178 			goto exit;
14179 		}
14180 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
14181 		/*
14182 		 * Checking contents of roam profile data from fw and exits
14183 		 * if code hits below condtion. If remaining length of buffer is
14184 		 * less than roam profile size or if there is no valid entry.
14185 		 */
14186 			if (len >= rp->v1.len) {
14187 				break;
14188 			}
14189 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14190 				if (rp->v2.roam_prof[i].fullscan_period == 0) {
14191 					break;
14192 				}
14193 				if (rp->v2.roam_prof[i].channel_usage != 0) {
14194 					rp->v2.roam_prof[i].roam_delta = val;
14195 				}
14196 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14197 				if (rp->v3.roam_prof[i].fullscan_period == 0) {
14198 					break;
14199 				}
14200 				if (rp->v3.roam_prof[i].channel_usage != 0) {
14201 					rp->v3.roam_prof[i].roam_delta = val;
14202 				}
14203 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14204 				if (rp->v4.roam_prof[i].fullscan_period == 0) {
14205 					break;
14206 				}
14207 				if (rp->v4.roam_prof[i].channel_usage != 0) {
14208 					rp->v4.roam_prof[i].roam_delta = val;
14209 				}
14210 			}
14211 			len += roam_prof_size;
14212 		}
14213 	}
14214 	else {
14215 		if (rp->v2.roam_prof[0].channel_usage != 0) {
14216 			bytes_written = snprintf(command, total_len,
14217 				"%s Delta %d\n", wl_android_get_band_str(rp->v1.band),
14218 				rp->v2.roam_prof[0].roam_delta);
14219 		}
14220 		err = bytes_written;
14221 		goto exit;
14222 	}
14223 	rp->v1.len = len;
14224 	if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
14225 			sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
14226 			&cfg->ioctl_buf_sync)) < 0) {
14227 		ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
14228 	}
14229 exit :
14230 	if (rp) {
14231 		MFREE(cfg->osh, rp, sizeof(*rp));
14232 	}
14233 	return err;
14234 }
14235 #endif /* WBTEXT */
14236