• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 			printk(KERN_ERR DHD_LOG_PREFIXS "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 			printk(KERN_INFO DHD_LOG_PREFIXS "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 			printk(KERN_INFO DHD_LOG_PREFIXS "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 #endif /* BCMSDIO */
4905 #ifdef BCMPCIE
4906 			ret = dhd_net_bus_devreset(dev, FALSE);
4907 #endif /* BCMPCIE */
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 == 0) {
4925 				break;
4926 			}
4927 			ANDROID_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
4928 				retry));
4929 #ifdef BCMPCIE
4930 			dhd_net_bus_devreset(dev, TRUE);
4931 #endif /* BCMPCIE */
4932 			dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4933 #ifdef WBRC
4934 			/* Inform BT reset which will internally wait till BT reset is done */
4935 			if (wbrc_wl2bt_reset()) {
4936 				ANDROID_ERROR(("Failed to reset BT, nothing to be done!!!!\n"));
4937 			}
4938 #endif /* WBRC */
4939 		} while (retry-- > 0);
4940 		if (ret != 0) {
4941 			ANDROID_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
4942 #ifdef BCM_DETECT_TURN_ON_FAILURE
4943 			BUG_ON(1);
4944 #endif /* BCM_DETECT_TURN_ON_FAILURE */
4945 			goto exit;
4946 		}
4947 #if defined(BCMSDIO) || defined(BCMDBUS)
4948 		ret = dhd_net_bus_devreset(dev, FALSE);
4949 		if (ret)
4950 			goto err;
4951 #ifdef BCMSDIO
4952 		dhd_net_bus_resume(dev, 1);
4953 #endif /* BCMSDIO */
4954 #endif /* BCMSDIO || BCMDBUS */
4955 #if defined(BCMSDIO) || defined(BCMDBUS)
4956 		if (!ret) {
4957 			if (dhd_dev_init_ioctl(dev) < 0) {
4958 				ret = -EFAULT;
4959 				goto err;
4960 			}
4961 		}
4962 #endif /* BCMSDIO || BCMDBUS */
4963 		g_wifi_on = TRUE;
4964 	}
4965 
4966 exit:
4967 	WL_MSG(dev->name, "Success\n");
4968 	dhd_net_if_unlock(dev);
4969 	return ret;
4970 
4971 #if defined(BCMSDIO) || defined(BCMDBUS)
4972 err:
4973 	dhd_net_bus_devreset(dev, TRUE);
4974 #ifdef BCMSDIO
4975 	dhd_net_bus_suspend(dev);
4976 #endif /* BCMSDIO */
4977 	dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4978 	WL_MSG(dev->name, "Failed\n");
4979 	dhd_net_if_unlock(dev);
4980 	return ret;
4981 #endif /* BCMSDIO || BCMDBUS */
4982 }
4983 
wl_android_wifi_off(struct net_device * dev,bool on_failure)4984 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
4985 {
4986 	int ret = 0;
4987 
4988 	if (!dev) {
4989 		ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4990 		return -EINVAL;
4991 	}
4992 
4993 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
4994 	ret = dhd_debug_uart_is_running(dev);
4995 	if (ret) {
4996 		ANDROID_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
4997 		return -EBUSY;
4998 	}
4999 #endif	/* BCMPCIE && DHD_DEBUG_UART */
5000 	dhd_net_if_lock(dev);
5001 	WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure);
5002 	if (g_wifi_on || on_failure) {
5003 #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
5004 		ret = dhd_net_bus_devreset(dev, TRUE);
5005 #ifdef BCMSDIO
5006 		dhd_net_bus_suspend(dev);
5007 #endif /* BCMSDIO */
5008 #endif /* BCMSDIO || BCMPCIE || BCMDBUS */
5009 		dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
5010 		g_wifi_on = FALSE;
5011 	}
5012 	WL_MSG(dev->name, "out\n");
5013 	dhd_net_if_unlock(dev);
5014 
5015 	return ret;
5016 }
5017 
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)5018 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
5019 {
5020 	if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
5021 		return -1;
5022 	return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
5023 }
5024 
5025 #ifdef CONNECTION_STATISTICS
5026 static int
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)5027 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
5028 {
5029 	int err;
5030 	wl_chanim_stats_t *list;
5031 	/* Parameter _and_ returned buffer of chanim_stats. */
5032 	wl_chanim_stats_t param;
5033 	u8 result[WLC_IOCTL_SMLEN];
5034 	chanim_stats_t *stats;
5035 
5036 	bzero(&param, sizeof(param));
5037 
5038 	param.buflen = htod32(sizeof(wl_chanim_stats_t));
5039 	param.count = htod32(WL_CHANIM_COUNT_ONE);
5040 
5041 	if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
5042 		(char*)result, sizeof(result), 0)) < 0) {
5043 		ANDROID_ERROR(("Failed to get chanim results %d \n", err));
5044 		return err;
5045 	}
5046 
5047 	list = (wl_chanim_stats_t*)result;
5048 
5049 	list->buflen = dtoh32(list->buflen);
5050 	list->version = dtoh32(list->version);
5051 	list->count = dtoh32(list->count);
5052 
5053 	if (list->buflen == 0) {
5054 		list->version = 0;
5055 		list->count = 0;
5056 	} else if (list->version != WL_CHANIM_STATS_VERSION) {
5057 		ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
5058 			"but driver supports only version %d.\n",
5059 				list->version, WL_CHANIM_STATS_VERSION));
5060 		list->buflen = 0;
5061 		list->count = 0;
5062 	}
5063 
5064 	stats = list->stats;
5065 	stats->glitchcnt = dtoh32(stats->glitchcnt);
5066 	stats->badplcp = dtoh32(stats->badplcp);
5067 	stats->chanspec = dtoh16(stats->chanspec);
5068 	stats->timestamp = dtoh32(stats->timestamp);
5069 	stats->chan_idle = dtoh32(stats->chan_idle);
5070 
5071 	ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
5072 		stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
5073 		stats->timestamp));
5074 
5075 	*chan_idle = stats->chan_idle;
5076 
5077 	return (err);
5078 }
5079 
5080 static int
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)5081 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
5082 {
5083 	static char iovar_buf[WLC_IOCTL_MAXLEN];
5084 	const wl_cnt_wlc_t* wlc_cnt = NULL;
5085 #ifndef DISABLE_IF_COUNTERS
5086 	wl_if_stats_t* if_stats = NULL;
5087 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5088 #ifdef BCMDONGLEHOST
5089 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
5090 #endif /* BCMDONGLEHOST */
5091 #endif /* DISABLE_IF_COUNTERS */
5092 
5093 	int link_speed = 0;
5094 	struct connection_stats *output;
5095 	unsigned int bufsize = 0;
5096 	int bytes_written = -1;
5097 	int ret = 0;
5098 
5099 	ANDROID_INFO(("wl_android_get_connection_stats: enter Get Connection Stats\n"));
5100 
5101 	if (total_len <= 0) {
5102 		ANDROID_ERROR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len));
5103 		goto error;
5104 	}
5105 
5106 	bufsize = total_len;
5107 	if (bufsize < sizeof(struct connection_stats)) {
5108 		ANDROID_ERROR(("wl_android_get_connection_stats: not enough buffer size, provided=%u,"
5109 			" requires=%zu\n",
5110 			bufsize,
5111 			sizeof(struct connection_stats)));
5112 		goto error;
5113 	}
5114 
5115 	output = (struct connection_stats *)command;
5116 
5117 #ifndef DISABLE_IF_COUNTERS
5118 	if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
5119 	if (if_stats == NULL) {
5120 		ANDROID_ERROR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
5121 		goto error;
5122 	}
5123 	bzero(if_stats, sizeof(*if_stats));
5124 
5125 #ifdef BCMDONGLEHOST
5126 	if (FW_SUPPORTED(dhdp, ifst)) {
5127 		ret = wl_cfg80211_ifstats_counters(dev, if_stats);
5128 	} else
5129 #endif /* BCMDONGLEHOST */
5130 	{
5131 		ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5132 			(char *)if_stats, sizeof(*if_stats), NULL);
5133 	}
5134 
5135 	ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5136 		(char *)if_stats, sizeof(*if_stats), NULL);
5137 	if (ret) {
5138 		ANDROID_ERROR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n",
5139 			ret));
5140 
5141 		/* In case if_stats IOVAR is not supported, get information from counters. */
5142 #endif /* DISABLE_IF_COUNTERS */
5143 		ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
5144 			iovar_buf, WLC_IOCTL_MAXLEN, NULL);
5145 		if (unlikely(ret)) {
5146 			ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
5147 			goto error;
5148 		}
5149 		ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
5150 		if (ret != BCME_OK) {
5151 			ANDROID_ERROR(("wl_android_get_connection_stats:"
5152 			" wl_cntbuf_to_xtlv_format ERR %d\n",
5153 			ret));
5154 			goto error;
5155 		}
5156 
5157 		if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
5158 			ANDROID_ERROR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
5159 			goto error;
5160 		}
5161 
5162 		output->txframe   = dtoh32(wlc_cnt->txframe);
5163 		output->txbyte    = dtoh32(wlc_cnt->txbyte);
5164 		output->txerror   = dtoh32(wlc_cnt->txerror);
5165 		output->rxframe   = dtoh32(wlc_cnt->rxframe);
5166 		output->rxbyte    = dtoh32(wlc_cnt->rxbyte);
5167 		output->txfail    = dtoh32(wlc_cnt->txfail);
5168 		output->txretry   = dtoh32(wlc_cnt->txretry);
5169 		output->txretrie  = dtoh32(wlc_cnt->txretrie);
5170 		output->txrts     = dtoh32(wlc_cnt->txrts);
5171 		output->txnocts   = dtoh32(wlc_cnt->txnocts);
5172 		output->txexptime = dtoh32(wlc_cnt->txexptime);
5173 #ifndef DISABLE_IF_COUNTERS
5174 	} else {
5175 		/* Populate from if_stats. */
5176 		if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
5177 			ANDROID_ERROR(("wl_android_get_connection_stats: incorrect version of"
5178 				" wl_if_stats_t,"
5179 				" expected=%u got=%u\n",
5180 				WL_IF_STATS_T_VERSION, if_stats->version));
5181 			goto error;
5182 		}
5183 
5184 		output->txframe   = (uint32)dtoh64(if_stats->txframe);
5185 		output->txbyte    = (uint32)dtoh64(if_stats->txbyte);
5186 		output->txerror   = (uint32)dtoh64(if_stats->txerror);
5187 		output->rxframe   = (uint32)dtoh64(if_stats->rxframe);
5188 		output->rxbyte    = (uint32)dtoh64(if_stats->rxbyte);
5189 		output->txfail    = (uint32)dtoh64(if_stats->txfail);
5190 		output->txretry   = (uint32)dtoh64(if_stats->txretry);
5191 		output->txretrie  = (uint32)dtoh64(if_stats->txretrie);
5192 		if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
5193 			output->txexptime = (uint32)dtoh64(if_stats->txexptime);
5194 			output->txrts     = (uint32)dtoh64(if_stats->txrts);
5195 			output->txnocts   = (uint32)dtoh64(if_stats->txnocts);
5196 		} else {
5197 			output->txexptime = 0;
5198 			output->txrts     = 0;
5199 			output->txnocts   = 0;
5200 		}
5201 	}
5202 #endif /* DISABLE_IF_COUNTERS */
5203 
5204 	/* link_speed is in kbps */
5205 	ret = wldev_get_link_speed(dev, &link_speed);
5206 	if (ret || link_speed < 0) {
5207 		ANDROID_ERROR(("wl_android_get_connection_stats: wldev_get_link_speed()"
5208 			" failed, ret=%d, speed=%d\n",
5209 			ret, link_speed));
5210 		goto error;
5211 	}
5212 
5213 	output->txrate    = link_speed;
5214 
5215 	/* Channel idle ratio. */
5216 	if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
5217 		output->chan_idle = 0;
5218 	};
5219 
5220 	bytes_written = sizeof(struct connection_stats);
5221 
5222 error:
5223 #ifndef DISABLE_IF_COUNTERS
5224 	if (if_stats) {
5225 		MFREE(cfg->osh, if_stats, sizeof(*if_stats));
5226 	}
5227 #endif /* DISABLE_IF_COUNTERS */
5228 
5229 	return bytes_written;
5230 }
5231 #endif /* CONNECTION_STATISTICS */
5232 
5233 #ifdef WL_NATOE
5234 static int
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)5235 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
5236 {
5237 	int ret = BCME_ERROR;
5238 	char *pcmd = command;
5239 	char *str = NULL;
5240 	wl_natoe_cmd_info_t cmd_info;
5241 	const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
5242 
5243 	/* skip to cmd name after "natoe" */
5244 	str = bcmstrtok(&pcmd, " ", NULL);
5245 
5246 	/* If natoe subcmd name is not provided, return error */
5247 	if (*pcmd == '\0') {
5248 		ANDROID_ERROR(("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
5249 		ret = -EINVAL;
5250 		return ret;
5251 	}
5252 
5253 	/* get the natoe command name to str */
5254 	str = bcmstrtok(&pcmd, " ", NULL);
5255 
5256 	while (natoe_cmd->name != NULL) {
5257 		if (strcmp(natoe_cmd->name, str) == 0)  {
5258 			/* dispacth cmd to appropriate handler */
5259 			if (natoe_cmd->handler) {
5260 				cmd_info.command = command;
5261 				cmd_info.tot_len = total_len;
5262 				ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
5263 			}
5264 			return ret;
5265 		}
5266 		natoe_cmd++;
5267 	}
5268 	return ret;
5269 }
5270 
5271 static int
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)5272 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
5273 {
5274 	int res = BCME_OK;
5275 	wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
5276 	uint8 *command = cmd_info->command;
5277 	uint16 total_len = cmd_info->tot_len;
5278 	uint16 bytes_written = 0;
5279 
5280 	UNUSED_PARAMETER(len);
5281 
5282 	switch (type) {
5283 
5284 	case WL_NATOE_XTLV_ENABLE:
5285 	{
5286 		bytes_written = snprintf(command, total_len, "natoe: %s\n",
5287 				*data?"enabled":"disabled");
5288 		cmd_info->bytes_written = bytes_written;
5289 		break;
5290 	}
5291 
5292 	case WL_NATOE_XTLV_CONFIG_IPS:
5293 	{
5294 		wl_natoe_config_ips_t *config_ips;
5295 		uint8 buf[16];
5296 
5297 		config_ips = (wl_natoe_config_ips_t *)data;
5298 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
5299 		bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
5300 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
5301 		bytes_written += snprintf(command + bytes_written, total_len,
5302 				"sta netmask: %s\n", buf);
5303 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
5304 		bytes_written += snprintf(command + bytes_written, total_len,
5305 				"sta router ip: %s\n", buf);
5306 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
5307 		bytes_written += snprintf(command + bytes_written, total_len,
5308 				"sta dns ip: %s\n", buf);
5309 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
5310 		bytes_written += snprintf(command + bytes_written, total_len,
5311 				"ap ip: %s\n", buf);
5312 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
5313 		bytes_written += snprintf(command + bytes_written, total_len,
5314 				"ap netmask: %s\n", buf);
5315 		cmd_info->bytes_written = bytes_written;
5316 		break;
5317 	}
5318 
5319 	case WL_NATOE_XTLV_CONFIG_PORTS:
5320 	{
5321 		wl_natoe_ports_config_t *ports_config;
5322 
5323 		ports_config = (wl_natoe_ports_config_t *)data;
5324 		bytes_written = snprintf(command, total_len, "starting port num: %d\n",
5325 				dtoh16(ports_config->start_port_num));
5326 		bytes_written += snprintf(command + bytes_written, total_len,
5327 				"number of ports: %d\n", dtoh16(ports_config->no_of_ports));
5328 		cmd_info->bytes_written = bytes_written;
5329 		break;
5330 	}
5331 
5332 	case WL_NATOE_XTLV_DBG_STATS:
5333 	{
5334 		char *stats_dump = (char *)data;
5335 
5336 		bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
5337 		cmd_info->bytes_written = bytes_written;
5338 		break;
5339 	}
5340 
5341 	case WL_NATOE_XTLV_TBL_CNT:
5342 	{
5343 		bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
5344 				dtoh32(*(uint32 *)data));
5345 		cmd_info->bytes_written = bytes_written;
5346 		break;
5347 	}
5348 
5349 	default:
5350 		/* ignore */
5351 		break;
5352 	}
5353 
5354 	return res;
5355 }
5356 
5357 /*
5358  *   --- common for all natoe get commands ----
5359  */
5360 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)5361 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
5362 		uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
5363 {
5364 	/* for gets we only need to pass ioc header */
5365 	wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
5366 	int res;
5367 
5368 	/*  send getbuf natoe iovar */
5369 	res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
5370 			buflen, NULL);
5371 
5372 	/*  check the response buff  */
5373 	if ((res == BCME_OK)) {
5374 		/* scans ioctl tlvbuf f& invokes the cbfn for processing  */
5375 		res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
5376 				BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
5377 
5378 		if (res == BCME_OK) {
5379 			res = cmd_info->bytes_written;
5380 		}
5381 	}
5382 	else
5383 	{
5384 		ANDROID_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res));
5385 		res = BCME_ERROR;
5386 	}
5387 
5388 	return res;
5389 }
5390 
5391 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)5392 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5393 		char *command, wl_natoe_cmd_info_t *cmd_info)
5394 {
5395 	int ret = BCME_OK;
5396 	wl_natoe_ioc_t *natoe_ioc;
5397 	char *pcmd = command;
5398 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5399 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5400 	bcm_xtlv_t *pxtlv = NULL;
5401 	char *ioctl_buf = NULL;
5402 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5403 
5404 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5405 	if (!ioctl_buf) {
5406 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5407 		return -ENOMEM;
5408 	}
5409 
5410 	/* alloc mem for ioctl headr + tlv data */
5411 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5412 	if (!natoe_ioc) {
5413 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5414 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5415 		return -ENOMEM;
5416 	}
5417 
5418 	/* make up natoe cmd ioctl header */
5419 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5420 	natoe_ioc->id = htod16(cmd->id);
5421 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5422 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5423 
5424 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5425 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5426 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5427 				WLC_IOCTL_MEDLEN, cmd_info);
5428 		if (ret != BCME_OK) {
5429 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
5430 			ret = -EINVAL;
5431 		}
5432 	} else {	/* set */
5433 		uint8 val = bcm_atoi(pcmd);
5434 
5435 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5436 		/* save buflen at start */
5437 		uint16 buflen_at_start = buflen;
5438 
5439 		/* we'll adjust final ioc size at the end */
5440 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5441 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5442 
5443 		if (ret != BCME_OK) {
5444 			ret = -EINVAL;
5445 			goto exit;
5446 		}
5447 
5448 		/* adjust iocsz to the end of last data record */
5449 		natoe_ioc->len = (buflen_at_start - buflen);
5450 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5451 
5452 		ret = wldev_iovar_setbuf(dev, "natoe",
5453 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5454 		if (ret != BCME_OK) {
5455 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5456 			ret = -EINVAL;
5457 		}
5458 	}
5459 
5460 exit:
5461 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5462 	MFREE(cfg->osh, natoe_ioc, iocsz);
5463 
5464 	return ret;
5465 }
5466 
5467 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)5468 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
5469 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5470 {
5471 	int ret = BCME_OK;
5472 	wl_natoe_config_ips_t config_ips;
5473 	wl_natoe_ioc_t *natoe_ioc;
5474 	char *pcmd = command;
5475 	char *str;
5476 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5477 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5478 	bcm_xtlv_t *pxtlv = NULL;
5479 	char *ioctl_buf = NULL;
5480 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5481 
5482 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5483 	if (!ioctl_buf) {
5484 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5485 		return -ENOMEM;
5486 	}
5487 
5488 	/* alloc mem for ioctl headr + tlv data */
5489 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5490 	if (!natoe_ioc) {
5491 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5492 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5493 		return -ENOMEM;
5494 	}
5495 
5496 	/* make up natoe cmd ioctl header */
5497 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5498 	natoe_ioc->id = htod16(cmd->id);
5499 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5500 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5501 
5502 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5503 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5504 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5505 				WLC_IOCTL_MEDLEN, cmd_info);
5506 		if (ret != BCME_OK) {
5507 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
5508 			ret = -EINVAL;
5509 		}
5510 	} else {	/* set */
5511 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5512 		/* save buflen at start */
5513 		uint16 buflen_at_start = buflen;
5514 
5515 		bzero(&config_ips, sizeof(config_ips));
5516 
5517 		str = bcmstrtok(&pcmd, " ", NULL);
5518 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
5519 			ANDROID_ERROR(("Invalid STA IP addr %s\n", str));
5520 			ret = -EINVAL;
5521 			goto exit;
5522 		}
5523 
5524 		str = bcmstrtok(&pcmd, " ", NULL);
5525 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
5526 			ANDROID_ERROR(("Invalid STA netmask %s\n", str));
5527 			ret = -EINVAL;
5528 			goto exit;
5529 		}
5530 
5531 		str = bcmstrtok(&pcmd, " ", NULL);
5532 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
5533 			ANDROID_ERROR(("Invalid STA router IP addr %s\n", str));
5534 			ret = -EINVAL;
5535 			goto exit;
5536 		}
5537 
5538 		str = bcmstrtok(&pcmd, " ", NULL);
5539 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
5540 			ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str));
5541 			ret = -EINVAL;
5542 			goto exit;
5543 		}
5544 
5545 		str = bcmstrtok(&pcmd, " ", NULL);
5546 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
5547 			ANDROID_ERROR(("Invalid AP IP addr %s\n", str));
5548 			ret = -EINVAL;
5549 			goto exit;
5550 		}
5551 
5552 		str = bcmstrtok(&pcmd, " ", NULL);
5553 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
5554 			ANDROID_ERROR(("Invalid AP netmask %s\n", str));
5555 			ret = -EINVAL;
5556 			goto exit;
5557 		}
5558 
5559 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5560 				&buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
5561 				&config_ips, BCM_XTLV_OPTION_ALIGN32);
5562 
5563 		if (ret != BCME_OK) {
5564 			ret = -EINVAL;
5565 			goto exit;
5566 		}
5567 
5568 		/* adjust iocsz to the end of last data record */
5569 		natoe_ioc->len = (buflen_at_start - buflen);
5570 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5571 
5572 		ret = wldev_iovar_setbuf(dev, "natoe",
5573 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5574 		if (ret != BCME_OK) {
5575 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5576 			ret = -EINVAL;
5577 		}
5578 	}
5579 
5580 exit:
5581 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5582 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5583 
5584 	return ret;
5585 }
5586 
5587 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)5588 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
5589 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5590 {
5591 	int ret = BCME_OK;
5592 	wl_natoe_ports_config_t ports_config;
5593 	wl_natoe_ioc_t *natoe_ioc;
5594 	char *pcmd = command;
5595 	char *str;
5596 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5597 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5598 	bcm_xtlv_t *pxtlv = NULL;
5599 	char *ioctl_buf = NULL;
5600 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5601 
5602 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5603 	if (!ioctl_buf) {
5604 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5605 		return -ENOMEM;
5606 	}
5607 
5608 	/* alloc mem for ioctl headr + tlv data */
5609 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5610 	if (!natoe_ioc) {
5611 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5612 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5613 		return -ENOMEM;
5614 	}
5615 
5616 	/* make up natoe cmd ioctl header */
5617 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5618 	natoe_ioc->id = htod16(cmd->id);
5619 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5620 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5621 
5622 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5623 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5624 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5625 				WLC_IOCTL_MEDLEN, cmd_info);
5626 		if (ret != BCME_OK) {
5627 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
5628 			ret = -EINVAL;
5629 		}
5630 	} else {	/* set */
5631 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5632 		/* save buflen at start */
5633 		uint16 buflen_at_start = buflen;
5634 
5635 		bzero(&ports_config, sizeof(ports_config));
5636 
5637 		str = bcmstrtok(&pcmd, " ", NULL);
5638 		if (!str) {
5639 			ANDROID_ERROR(("Invalid port string %s\n", str));
5640 			ret = -EINVAL;
5641 			goto exit;
5642 		}
5643 		ports_config.start_port_num = htod16(bcm_atoi(str));
5644 
5645 		str = bcmstrtok(&pcmd, " ", NULL);
5646 		if (!str) {
5647 			ANDROID_ERROR(("Invalid port string %s\n", str));
5648 			ret = -EINVAL;
5649 			goto exit;
5650 		}
5651 		ports_config.no_of_ports = htod16(bcm_atoi(str));
5652 
5653 		if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
5654 				NATOE_MAX_PORT_NUM) {
5655 			ANDROID_ERROR(("Invalid port configuration\n"));
5656 			ret = -EINVAL;
5657 			goto exit;
5658 		}
5659 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5660 				&buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
5661 				&ports_config, BCM_XTLV_OPTION_ALIGN32);
5662 
5663 		if (ret != BCME_OK) {
5664 			ret = -EINVAL;
5665 			goto exit;
5666 		}
5667 
5668 		/* adjust iocsz to the end of last data record */
5669 		natoe_ioc->len = (buflen_at_start - buflen);
5670 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5671 
5672 		ret = wldev_iovar_setbuf(dev, "natoe",
5673 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5674 		if (ret != BCME_OK) {
5675 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5676 			ret = -EINVAL;
5677 		}
5678 	}
5679 
5680 exit:
5681 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5682 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5683 
5684 	return ret;
5685 }
5686 
5687 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)5688 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5689 		char *command, wl_natoe_cmd_info_t *cmd_info)
5690 {
5691 	int ret = BCME_OK;
5692 	wl_natoe_ioc_t *natoe_ioc;
5693 	char *pcmd = command;
5694 	uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5695 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
5696 	uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
5697 	bcm_xtlv_t *pxtlv = NULL;
5698 	char *ioctl_buf = NULL;
5699 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5700 
5701 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5702 	if (!ioctl_buf) {
5703 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5704 		return -ENOMEM;
5705 	}
5706 
5707 	/* alloc mem for ioctl headr + tlv data */
5708 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5709 	if (!natoe_ioc) {
5710 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5711 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5712 		return -ENOMEM;
5713 	}
5714 
5715 	/* make up natoe cmd ioctl header */
5716 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5717 	natoe_ioc->id = htod16(cmd->id);
5718 	natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
5719 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5720 
5721 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5722 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5723 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5724 				WLC_IOCTL_MAXLEN, cmd_info);
5725 		if (ret != BCME_OK) {
5726 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
5727 			ret = -EINVAL;
5728 		}
5729 	} else {	/* set */
5730 		uint8 val = bcm_atoi(pcmd);
5731 
5732 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5733 		/* save buflen at start */
5734 		uint16 buflen_at_start = buflen;
5735 
5736 		/* we'll adjust final ioc size at the end */
5737 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5738 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5739 
5740 		if (ret != BCME_OK) {
5741 			ret = -EINVAL;
5742 			goto exit;
5743 		}
5744 
5745 		/* adjust iocsz to the end of last data record */
5746 		natoe_ioc->len = (buflen_at_start - buflen);
5747 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5748 
5749 		ret = wldev_iovar_setbuf(dev, "natoe",
5750 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
5751 		if (ret != BCME_OK) {
5752 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5753 			ret = -EINVAL;
5754 		}
5755 	}
5756 
5757 exit:
5758 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5759 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
5760 
5761 	return ret;
5762 }
5763 
5764 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)5765 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5766 		char *command, wl_natoe_cmd_info_t *cmd_info)
5767 {
5768 	int ret = BCME_OK;
5769 	wl_natoe_ioc_t *natoe_ioc;
5770 	char *pcmd = command;
5771 	uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5772 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5773 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
5774 	bcm_xtlv_t *pxtlv = NULL;
5775 	char *ioctl_buf = NULL;
5776 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5777 
5778 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5779 	if (!ioctl_buf) {
5780 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
5781 		return -ENOMEM;
5782 	}
5783 
5784 	/* alloc mem for ioctl headr + tlv data */
5785 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5786 	if (!natoe_ioc) {
5787 		ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5788 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5789 		return -ENOMEM;
5790 	}
5791 
5792 	/* make up natoe cmd ioctl header */
5793 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5794 	natoe_ioc->id = htod16(cmd->id);
5795 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5796 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5797 
5798 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5799 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5800 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5801 				WLC_IOCTL_MEDLEN, cmd_info);
5802 		if (ret != BCME_OK) {
5803 			ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
5804 			ret = -EINVAL;
5805 		}
5806 	} else {	/* set */
5807 		uint32 val = bcm_atoi(pcmd);
5808 
5809 		/* buflen is max tlv data we can write, it will be decremented as we pack */
5810 		/* save buflen at start */
5811 		uint16 buflen_at_start = buflen;
5812 
5813 		/* we'll adjust final ioc size at the end */
5814 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
5815 			sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
5816 
5817 		if (ret != BCME_OK) {
5818 			ret = -EINVAL;
5819 			goto exit;
5820 		}
5821 
5822 		/* adjust iocsz to the end of last data record */
5823 		natoe_ioc->len = (buflen_at_start - buflen);
5824 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5825 
5826 		ret = wldev_iovar_setbuf(dev, "natoe",
5827 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5828 		if (ret != BCME_OK) {
5829 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5830 			ret = -EINVAL;
5831 		}
5832 	}
5833 
5834 exit:
5835 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5836 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5837 
5838 	return ret;
5839 }
5840 
5841 #endif /* WL_NATOE */
5842 
5843 #ifdef WL_MBO
5844 static int
wl_android_process_mbo_cmd(struct net_device * dev,char * command,int total_len)5845 wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len)
5846 {
5847 	int ret = BCME_ERROR;
5848 	char *pcmd = command;
5849 	char *str = NULL;
5850 	wl_drv_cmd_info_t cmd_info;
5851 	const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
5852 
5853 	/* skip to cmd name after "mbo" */
5854 	str = bcmstrtok(&pcmd, " ", NULL);
5855 
5856 	/* If mbo subcmd name is not provided, return error */
5857 	if (*pcmd == '\0') {
5858 		ANDROID_ERROR(("mbo subcmd not provided %s\n", __FUNCTION__));
5859 		ret = -EINVAL;
5860 		return ret;
5861 	}
5862 
5863 	/* get the mbo command name to str */
5864 	str = bcmstrtok(&pcmd, " ", NULL);
5865 
5866 	while (mbo_cmd->name != NULL) {
5867 		if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
5868 			/* dispatch cmd to appropriate handler */
5869 			if (mbo_cmd->handler) {
5870 				cmd_info.command = command;
5871 				cmd_info.tot_len = total_len;
5872 				ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
5873 			}
5874 			return ret;
5875 		}
5876 		mbo_cmd++;
5877 	}
5878 	return ret;
5879 }
5880 
5881 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)5882 wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf,
5883 	uint16 iov_buf_len, uint8 *iov_resp, uint16 iov_resp_len, uint8 sub_elem_type)
5884 {
5885 	int ret = BCME_OK;
5886 	uint8 *pxtlv = NULL;
5887 	uint16 iovlen = 0;
5888 	uint16 buflen = 0, buflen_start = 0;
5889 
5890 	memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
5891 	iov_buf->version = WL_MBO_IOV_VERSION;
5892 	iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
5893 	buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
5894 	pxtlv = (uint8 *)&iov_buf->data[0];
5895 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
5896 		sizeof(sub_elem_type), &sub_elem_type, BCM_XTLV_OPTION_ALIGN32);
5897 	if (ret != BCME_OK) {
5898 		return ret;
5899 	}
5900 	iov_buf->len = buflen_start - buflen;
5901 	iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5902 	ret = wldev_iovar_setbuf(dev, "mbo",
5903 			iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5904 	if (ret != BCME_OK) {
5905 		ANDROID_ERROR(("Fail to sent wnm notif %d\n", ret));
5906 	}
5907 	return ret;
5908 }
5909 
5910 static int
wl_android_mbo_resp_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5911 wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5912 {
5913 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
5914 	uint8 *command = cmd_info->command;
5915 	uint16 total_len = cmd_info->tot_len;
5916 	uint16 bytes_written = 0;
5917 
5918 	UNUSED_PARAMETER(len);
5919 	/* TODO: validate data value */
5920 	if (data == NULL) {
5921 		ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
5922 		return -EINVAL;
5923 	}
5924 	switch (type) {
5925 		case WL_MBO_XTLV_CELL_DATA_CAP:
5926 		{
5927 			bytes_written = snprintf(command, total_len, "cell_data_cap: %u\n", *data);
5928 			cmd_info->bytes_written = bytes_written;
5929 		}
5930 		break;
5931 		default:
5932 			ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
5933 	}
5934 	return BCME_OK;
5935 }
5936 
5937 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)5938 wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd_t *cmd,
5939 		char *command, wl_drv_cmd_info_t *cmd_info)
5940 {
5941 	int ret = BCME_OK;
5942 	uint8 *pxtlv = NULL;
5943 	uint16 buflen = 0, buflen_start = 0;
5944 	uint16 iovlen = 0;
5945 	char *pcmd = command;
5946 	bcm_iov_buf_t *iov_buf = NULL;
5947 	bcm_iov_buf_t *p_resp = NULL;
5948 	uint8 *iov_resp = NULL;
5949 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5950 	uint16 version;
5951 
5952 	/* first get the configured value */
5953 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5954 	if (iov_buf == NULL) {
5955 		ret = -ENOMEM;
5956 		ANDROID_ERROR(("iov buf memory alloc exited\n"));
5957 		goto exit;
5958 	}
5959 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5960 	if (iov_resp == NULL) {
5961 		ret = -ENOMEM;
5962 		ANDROID_ERROR(("iov resp memory alloc exited\n"));
5963 		goto exit;
5964 	}
5965 
5966 	/* fill header */
5967 	iov_buf->version = WL_MBO_IOV_VERSION;
5968 	iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
5969 
5970 	ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
5971 		WLC_IOCTL_MAXLEN,
5972 		NULL);
5973 	if (ret != BCME_OK) {
5974 		goto exit;
5975 	}
5976 	p_resp = (bcm_iov_buf_t *)iov_resp;
5977 
5978 	/* get */
5979 	if (*pcmd == WL_IOCTL_ACTION_GET) {
5980 		/* Check for version */
5981 		version = dtoh16(*(uint16 *)iov_resp);
5982 		if (version != WL_MBO_IOV_VERSION) {
5983 			ret = -EINVAL;
5984 		}
5985 		if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
5986 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
5987 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
5988 				wl_android_mbo_resp_parse_cbfn);
5989 			if (ret == BCME_OK) {
5990 				ret = cmd_info->bytes_written;
5991 			}
5992 		} else {
5993 			ret = -EINVAL;
5994 			ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
5995 			goto exit;
5996 		}
5997 	} else {
5998 		uint8 cell_cap = bcm_atoi(pcmd);
5999 		const uint8* old_cell_cap = NULL;
6000 		uint16 len = 0;
6001 
6002 		old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len,
6003 			WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32);
6004 		if (old_cell_cap && *old_cell_cap == cell_cap) {
6005 			ANDROID_ERROR(("No change is cellular data capability\n"));
6006 			/* No change in value */
6007 			goto exit;
6008 		}
6009 
6010 		buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
6011 
6012 		if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
6013 			cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
6014 			ANDROID_ERROR(("wrong value %u\n", cell_cap));
6015 			ret = -EINVAL;
6016 			goto exit;
6017 		}
6018 		pxtlv = (uint8 *)&iov_buf->data[0];
6019 		ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
6020 			sizeof(cell_cap), &cell_cap, BCM_XTLV_OPTION_ALIGN32);
6021 		if (ret != BCME_OK) {
6022 			goto exit;
6023 		}
6024 		iov_buf->len = buflen_start - buflen;
6025 		iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6026 		ret = wldev_iovar_setbuf(dev, "mbo",
6027 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6028 		if (ret != BCME_OK) {
6029 			ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6030 			ret = -EINVAL;
6031 			goto exit;
6032 		}
6033 		/* Skip for CUSTOMER_HW4 - WNM notification
6034 		 * for cellular data capability is handled by host
6035 		 */
6036 #if !defined(CUSTOMER_HW4)
6037 		/* send a WNM notification request to associated AP */
6038 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6039 			ANDROID_INFO(("Sending WNM Notif\n"));
6040 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6041 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP);
6042 			if (ret != BCME_OK) {
6043 				ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6044 				ret = -EINVAL;
6045 			}
6046 		}
6047 #endif /* CUSTOMER_HW4 */
6048 	}
6049 exit:
6050 	if (iov_buf) {
6051 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6052 	}
6053 	if (iov_resp) {
6054 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6055 	}
6056 	return ret;
6057 }
6058 
6059 static int
wl_android_mbo_non_pref_chan_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)6060 wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
6061 {
6062 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
6063 	uint8 *command = cmd_info->command + cmd_info->bytes_written;
6064 	uint16 total_len = cmd_info->tot_len;
6065 	uint16 bytes_written = 0;
6066 
6067 	ANDROID_INFO(("Total bytes written at begining %u\n", cmd_info->bytes_written));
6068 	UNUSED_PARAMETER(len);
6069 	if (data == NULL) {
6070 		ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
6071 		return -EINVAL;
6072 	}
6073 	switch (type) {
6074 		case WL_MBO_XTLV_OPCLASS:
6075 		{
6076 			bytes_written = snprintf(command, total_len, "%u:", *data);
6077 			ANDROID_ERROR(("wr %u %u\n", bytes_written, *data));
6078 			command += bytes_written;
6079 			cmd_info->bytes_written += bytes_written;
6080 		}
6081 		break;
6082 		case WL_MBO_XTLV_CHAN:
6083 		{
6084 			bytes_written = snprintf(command, total_len, "%u:", *data);
6085 			ANDROID_ERROR(("wr %u\n", bytes_written));
6086 			command += bytes_written;
6087 			cmd_info->bytes_written += bytes_written;
6088 		}
6089 		break;
6090 		case WL_MBO_XTLV_PREFERENCE:
6091 		{
6092 			bytes_written = snprintf(command, total_len, "%u:", *data);
6093 			ANDROID_ERROR(("wr %u\n", bytes_written));
6094 			command += bytes_written;
6095 			cmd_info->bytes_written += bytes_written;
6096 		}
6097 		break;
6098 		case WL_MBO_XTLV_REASON_CODE:
6099 		{
6100 			bytes_written = snprintf(command, total_len, "%u ", *data);
6101 			ANDROID_ERROR(("wr %u\n", bytes_written));
6102 			command += bytes_written;
6103 			cmd_info->bytes_written += bytes_written;
6104 		}
6105 		break;
6106 		default:
6107 			ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
6108 	}
6109 	ANDROID_INFO(("Total bytes written %u\n", cmd_info->bytes_written));
6110 	return BCME_OK;
6111 }
6112 
6113 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)6114 wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
6115 		const wl_drv_sub_cmd_t *cmd, char *command,
6116 		wl_drv_cmd_info_t *cmd_info)
6117 {
6118 	int ret = BCME_OK;
6119 	uint8 *pxtlv = NULL;
6120 	uint16 buflen = 0, buflen_start = 0;
6121 	uint16 iovlen = 0;
6122 	char *pcmd = command;
6123 	bcm_iov_buf_t *iov_buf = NULL;
6124 	bcm_iov_buf_t *p_resp = NULL;
6125 	uint8 *iov_resp = NULL;
6126 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6127 	uint16 version;
6128 
6129 	ANDROID_ERROR(("%s:%d\n", __FUNCTION__, __LINE__));
6130 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
6131 	if (iov_buf == NULL) {
6132 		ret = -ENOMEM;
6133 		ANDROID_ERROR(("iov buf memory alloc exited\n"));
6134 		goto exit;
6135 	}
6136 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6137 	if (iov_resp == NULL) {
6138 		ret = -ENOMEM;
6139 		ANDROID_ERROR(("iov resp memory alloc exited\n"));
6140 		goto exit;
6141 	}
6142 	/* get */
6143 	if (*pcmd == WL_IOCTL_ACTION_GET) {
6144 		/* fill header */
6145 		iov_buf->version = WL_MBO_IOV_VERSION;
6146 		iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
6147 
6148 		ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
6149 				WLC_IOCTL_MAXLEN, NULL);
6150 		if (ret != BCME_OK) {
6151 			goto exit;
6152 		}
6153 		p_resp = (bcm_iov_buf_t *)iov_resp;
6154 		/* Check for version */
6155 		version = dtoh16(*(uint16 *)iov_resp);
6156 		if (version != WL_MBO_IOV_VERSION) {
6157 			ANDROID_ERROR(("Version mismatch. returned ver %u expected %u\n",
6158 				version, WL_MBO_IOV_VERSION));
6159 			ret = -EINVAL;
6160 		}
6161 		if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
6162 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
6163 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
6164 				wl_android_mbo_non_pref_chan_parse_cbfn);
6165 			if (ret == BCME_OK) {
6166 				ret = cmd_info->bytes_written;
6167 			}
6168 		} else {
6169 			ret = -EINVAL;
6170 			ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
6171 			goto exit;
6172 		}
6173 	} else {
6174 		char *str = pcmd;
6175 		uint opcl = 0, ch = 0, pref = 0, rc = 0;
6176 
6177 		str = bcmstrtok(&pcmd, " ", NULL);
6178 		if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) {
6179 			/* delete all configurations */
6180 			iov_buf->version = WL_MBO_IOV_VERSION;
6181 			iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
6182 			iov_buf->len = 0;
6183 			iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6184 			ret = wldev_iovar_setbuf(dev, "mbo",
6185 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6186 			if (ret != BCME_OK) {
6187 				ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6188 				ret = -EINVAL;
6189 				goto exit;
6190 			}
6191 		} else {
6192 			ANDROID_ERROR(("Unknown command %s\n", str));
6193 			goto exit;
6194 		}
6195 		/* parse non pref channel list */
6196 		if (strnicmp(str, "set", 3) == 0) {
6197 			uint8 cnt = 0;
6198 			str = bcmstrtok(&pcmd, " ", NULL);
6199 			while (str != NULL) {
6200 				ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
6201 				ANDROID_ERROR(("buflen %u op %u, ch %u, pref %u rc %u\n",
6202 					buflen, opcl, ch, pref, rc));
6203 				if (ret != 4) {
6204 					ANDROID_ERROR(("Not all parameter presents\n"));
6205 					ret = -EINVAL;
6206 				}
6207 				/* TODO: add a validation check here */
6208 				memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
6209 				buflen = buflen_start = WLC_IOCTL_MEDLEN;
6210 				pxtlv = (uint8 *)&iov_buf->data[0];
6211 				/* opclass */
6212 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
6213 					sizeof(uint8), (uint8 *)&opcl, BCM_XTLV_OPTION_ALIGN32);
6214 				if (ret != BCME_OK) {
6215 					goto exit;
6216 				}
6217 				/* channel */
6218 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
6219 					sizeof(uint8), (uint8 *)&ch, BCM_XTLV_OPTION_ALIGN32);
6220 				if (ret != BCME_OK) {
6221 					goto exit;
6222 				}
6223 				/* preference */
6224 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
6225 					sizeof(uint8), (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
6226 				if (ret != BCME_OK) {
6227 					goto exit;
6228 				}
6229 				/* reason */
6230 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
6231 					sizeof(uint8), (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
6232 				if (ret != BCME_OK) {
6233 					goto exit;
6234 				}
6235 				ANDROID_ERROR(("len %u\n", (buflen_start - buflen)));
6236 				/* Now set the new non pref channels */
6237 				iov_buf->version = WL_MBO_IOV_VERSION;
6238 				iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
6239 				iov_buf->len = buflen_start - buflen;
6240 				iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6241 				ret = wldev_iovar_setbuf(dev, "mbo",
6242 					iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL);
6243 				if (ret != BCME_OK) {
6244 					ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6245 					ret = -EINVAL;
6246 					goto exit;
6247 				}
6248 				cnt++;
6249 				if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
6250 					break;
6251 				}
6252 				ANDROID_ERROR(("%d cnt %u\n", __LINE__, cnt));
6253 				str = bcmstrtok(&pcmd, " ", NULL);
6254 			}
6255 		}
6256 		/* send a WNM notification request to associated AP */
6257 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6258 			ANDROID_INFO(("Sending WNM Notif\n"));
6259 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6260 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT);
6261 			if (ret != BCME_OK) {
6262 				ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6263 				ret = -EINVAL;
6264 			}
6265 		}
6266 	}
6267 exit:
6268 	if (iov_buf) {
6269 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6270 	}
6271 	if (iov_resp) {
6272 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6273 	}
6274 	return ret;
6275 }
6276 #endif /* WL_MBO */
6277 
6278 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6279 #ifdef SUPPORT_AMPDU_MPDU_CMD
6280 /* CMD_AMPDU_MPDU */
6281 static int
wl_android_set_ampdu_mpdu(struct net_device * dev,const char * string_num)6282 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
6283 {
6284 	int err = 0;
6285 	int ampdu_mpdu;
6286 
6287 	ampdu_mpdu = bcm_atoi(string_num);
6288 
6289 	if (ampdu_mpdu > 32) {
6290 		ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n"));
6291 		return -1;
6292 	}
6293 
6294 	ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu));
6295 	err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
6296 	if (err < 0) {
6297 		ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err));
6298 		return -1;
6299 	}
6300 
6301 	return 0;
6302 }
6303 #endif /* SUPPORT_AMPDU_MPDU_CMD */
6304 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
6305 
6306 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6307 extern int wl_cfg80211_send_msg_to_ril(void);
6308 extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
6309 extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
6310 extern int g_mhs_chan_for_cpcoex;
6311 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6312 
6313 #if defined (WL_SUPPORT_AUTO_CHANNEL)
6314 static s32
wl_android_set_auto_channel_scan_state(struct net_device * ndev)6315 wl_android_set_auto_channel_scan_state(struct net_device *ndev)
6316 {
6317 	u32 val = 0;
6318 	s32 ret = BCME_ERROR;
6319 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6320 	/* Set interface up, explicitly. */
6321 	val = 1;
6322 
6323 	ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
6324 	if (ret < 0) {
6325 		ANDROID_ERROR(("set interface up failed, error = %d\n", ret));
6326 		goto done;
6327 	}
6328 
6329 	/* Stop all scan explicitly, till auto channel selection complete. */
6330 	wl_set_drv_status(cfg, SCANNING, ndev);
6331 	if (cfg->escan_info.ndev == NULL) {
6332 		ret = BCME_OK;
6333 		goto done;
6334 	}
6335 
6336 	wl_cfgscan_cancel_scan(cfg);
6337 
6338 done:
6339 	return ret;
6340 }
6341 
6342 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)6343 wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *list,
6344 	s32 buflen, const char* cmd_str, int sta_channel, chanspec_band_t sta_acs_band)
6345 {
6346 	u32 freq = 0;
6347 	chanspec_t chanspec = 0;
6348 	s32 ret = BCME_OK;
6349 	int i = 0;
6350 	char *pcmd, *token;
6351 	int len = buflen;
6352 
6353 	pcmd = bcmstrstr(cmd_str, FREQ_STR);
6354 	pcmd += strlen(FREQ_STR);
6355 
6356 	len -= sizeof(list->count);
6357 
6358 	while ((token = strsep(&pcmd, ",")) != NULL) {
6359 		if (*token == '\0')
6360 			continue;
6361 
6362 		if (len < sizeof(list->element[i]))
6363 			break;
6364 
6365 		freq = bcm_atoi(token);
6366 		/* Convert chanspec from frequency */
6367 		if ((freq > 0) &&
6368 			((chanspec = wl_freq_to_chanspec(freq)) != INVCHANSPEC)) {
6369 			ANDROID_INFO(("Adding chanspec in list : 0x%x at the index %d\n", chanspec, i));
6370 			list->element[i] = chanspec;
6371 			len -= sizeof(list->element[i]);
6372 			i++;
6373 #ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN
6374 			/* Android includes 2g channels even for 5g band configuration. For
6375 			 * customers using only single channel 5G AP, set the channel and
6376 			 * return without doing ACS
6377 			 */
6378 			if (CHSPEC_BAND(chanspec) == WL_CHANSPEC_BAND_5G) {
6379 				ANDROID_INFO(("Pick default channnel from 5g\n"));
6380 				if (!sta_channel) {
6381 					list->element[0] = chanspec;
6382 					list->count = 1;
6383 					return ret;
6384 				}
6385 				break;
6386 			}
6387 #endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */
6388 		}
6389 	}
6390 
6391 	list->count = i;
6392 	/* valid chanspec present in the list */
6393 	if (list->count && sta_channel) {
6394 		/* STA associated case. Can't do ACS.
6395 		* Frequency list is order of lower to higher band.
6396 		* check with the highest band entry.
6397 		*/
6398 		chanspec = list->element[i-1];
6399 		if (CHSPEC_BAND(chanspec) == sta_acs_band) {
6400 			/* softap request is for same band. Use SCC
6401 			 * Convert sta channel to freq
6402 			 */
6403 			freq = wl_channel_to_frequency(sta_channel, sta_acs_band);
6404 			list->element[0] =
6405 				wl_freq_to_chanspec(freq);
6406 			ANDROID_INFO(("Softap on same band as STA."
6407 				"Use SCC. chanspec:0x%x\n", chanspec));
6408 		} else {
6409 			list->element[0] = chanspec;
6410 			ANDROID_INFO(("RSDB case chanspec:0x%x\n", chanspec));
6411 		}
6412 		list->count = 1;
6413 		return ret;
6414 	}
6415 	return ret;
6416 }
6417 
6418 s32
wl_android_get_band_chanspecs(struct net_device * ndev,void * buf,s32 buflen,chanspec_band_t band,bool acs_req)6419 wl_android_get_band_chanspecs(struct net_device *ndev, void *buf, s32 buflen,
6420 	chanspec_band_t band, bool acs_req)
6421 {
6422 	u32 channel = 0;
6423 	s32 ret = BCME_ERROR;
6424 	s32 i = 0;
6425 	s32 j = 0;
6426 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6427 	wl_uint32_list_t *list = NULL;
6428 	chanspec_t chanspec = 0;
6429 
6430 	if (band != 0xff) {
6431 		chanspec |= (band | WL_CHANSPEC_BW_20 |
6432 			WL_CHANSPEC_CTL_SB_NONE);
6433 		chanspec = wl_chspec_host_to_driver(chanspec);
6434 	}
6435 
6436 	ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
6437 		sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
6438 	if (ret < 0) {
6439 		ANDROID_ERROR(("get 'chanspecs' failed, error = %d\n", ret));
6440 		goto done;
6441 	}
6442 
6443 	list = (wl_uint32_list_t *)buf;
6444 	/* Skip DFS and inavlid P2P channel. */
6445 	for (i = 0, j = 0; i < dtoh32(list->count); i++) {
6446 		if (!CHSPEC_IS20(list->element[i])) {
6447 			continue;
6448 		}
6449 		chanspec = (chanspec_t) dtoh32(list->element[i]);
6450 		channel = chanspec | WL_CHANSPEC_BW_20;
6451 		channel = wl_chspec_host_to_driver(channel);
6452 
6453 		ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
6454 		if (ret < 0) {
6455 			ANDROID_ERROR(("get 'per_chan_info' failed, error = %d\n", ret));
6456 			goto done;
6457 		}
6458 
6459 		if (CHSPEC_IS5G(chanspec) && (CHANNEL_IS_RADAR(channel) ||
6460 #ifndef ALLOW_5G_ACS
6461 			((acs_req == true) && (CHSPEC_CHANNEL(chanspec) != APCS_DEFAULT_5G_CH)) ||
6462 #endif /* !ALLOW_5G_ACS */
6463 			(0))) {
6464 			continue;
6465 		} else if (!(CHSPEC_IS2G(chanspec) || CHSPEC_IS5G(chanspec)) &&
6466 			!(CHSPEC_IS_6G_PSC(chanspec))) {
6467 			continue;
6468 		}
6469 		else {
6470 			list->element[j] = list->element[i];
6471 			ANDROID_INFO(("Adding chanspec in list : %x\n", list->element[j]));
6472 		}
6473 
6474 		j++;
6475 	}
6476 
6477 	list->count = j;
6478 
6479 done:
6480 	return ret;
6481 }
6482 
6483 static s32
wl_android_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)6484 wl_android_get_best_channel(struct net_device *ndev, void *buf, int buflen,
6485 	int *channel)
6486 {
6487 	s32 ret = BCME_ERROR;
6488 	int chosen = 0;
6489 	int retry = 0;
6490 
6491 	/* Start auto channel selection scan. */
6492 	ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0);
6493 	if (ret < 0) {
6494 		ANDROID_ERROR(("can't start auto channel scan, error = %d\n", ret));
6495 		*channel = 0;
6496 		goto done;
6497 	}
6498 
6499 	/* Wait for auto channel selection, worst case possible delay is 5250ms. */
6500 	retry = CHAN_SEL_RETRY_COUNT;
6501 
6502 	while (retry--) {
6503 		OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
6504 		chosen = 0;
6505 		ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6506 		if ((ret == 0) && (dtoh32(chosen) != 0)) {
6507 			*channel = (u16)(chosen & 0x00FF);
6508 			ANDROID_INFO(("selected channel = %d\n", *channel));
6509 			break;
6510 		}
6511 		ANDROID_INFO(("attempt = %d, ret = %d, chosen = %d\n",
6512 			(CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
6513 	}
6514 
6515 	if (retry <= 0)	{
6516 		ANDROID_ERROR(("failure, auto channel selection timed out\n"));
6517 		*channel = 0;
6518 		ret = BCME_ERROR;
6519 	}
6520 
6521 done:
6522 	return ret;
6523 }
6524 
6525 static s32
wl_android_restore_auto_channel_scan_state(struct net_device * ndev)6526 wl_android_restore_auto_channel_scan_state(struct net_device *ndev)
6527 {
6528 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6529 	/* Clear scan stop driver status. */
6530 	wl_clr_drv_status(cfg, SCANNING, ndev);
6531 
6532 	return BCME_OK;
6533 }
6534 
6535 s32
wl_android_get_best_channels(struct net_device * dev,char * cmd,int total_len)6536 wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len)
6537 {
6538 	int channel = 0;
6539 	s32 ret = BCME_ERROR;
6540 	u8 *buf = NULL;
6541 	char *pos = cmd;
6542 	struct bcm_cfg80211 *cfg = NULL;
6543 	struct net_device *ndev = NULL;
6544 
6545 	bzero(cmd, total_len);
6546 	cfg = wl_get_cfg(dev);
6547 
6548 	buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
6549 	if (buf == NULL) {
6550 		ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6551 		return -ENOMEM;
6552 	}
6553 
6554 	/*
6555 	 * Always use primary interface, irrespective of interface on which
6556 	 * command came.
6557 	 */
6558 	ndev = bcmcfg_to_prmry_ndev(cfg);
6559 
6560 	/*
6561 	 * Make sure that FW and driver are in right state to do auto channel
6562 	 * selection scan.
6563 	 */
6564 	ret = wl_android_set_auto_channel_scan_state(ndev);
6565 	if (ret < 0) {
6566 		ANDROID_ERROR(("can't set auto channel scan state, error = %d\n", ret));
6567 		goto done;
6568 	}
6569 
6570 	/* Best channel selection in 2.4GHz band. */
6571 	ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6572 		WL_CHANSPEC_BAND_2G, false);
6573 	if (ret < 0) {
6574 		ANDROID_ERROR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
6575 		goto done;
6576 	}
6577 
6578 	ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6579 		&channel);
6580 	if (ret < 0) {
6581 		ANDROID_ERROR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
6582 		goto done;
6583 	}
6584 
6585 	if (CHANNEL_IS_2G(channel)) {
6586 		channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
6587 	} else {
6588 		ANDROID_ERROR(("invalid 2.4GHz channel, channel = %d\n", channel));
6589 		channel = 0;
6590 	}
6591 
6592 	pos += snprintf(pos, total_len, "%04d ", channel);
6593 
6594 	/* Best channel selection in 5GHz band. */
6595 	ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6596 		WL_CHANSPEC_BAND_5G, false);
6597 	if (ret < 0) {
6598 		ANDROID_ERROR(("can't get chanspecs in 5GHz, error = %d\n", ret));
6599 		goto done;
6600 	}
6601 
6602 	ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6603 		&channel);
6604 	if (ret < 0) {
6605 		ANDROID_ERROR(("can't select best channel scan in 5GHz, error = %d\n", ret));
6606 		goto done;
6607 	}
6608 
6609 	if (CHANNEL_IS_5G(channel)) {
6610 		channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
6611 	} else {
6612 		ANDROID_ERROR(("invalid 5GHz channel, channel = %d\n", channel));
6613 		channel = 0;
6614 	}
6615 
6616 	pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6617 
6618 	/* Set overall best channel same as 5GHz best channel. */
6619 	pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6620 
6621 done:
6622 	if (NULL != buf) {
6623 		MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
6624 	}
6625 
6626 	/* Restore FW and driver back to normal state. */
6627 	ret = wl_android_restore_auto_channel_scan_state(ndev);
6628 	if (ret < 0) {
6629 		ANDROID_ERROR(("can't restore auto channel scan state, error = %d\n", ret));
6630 	}
6631 
6632 	return (pos - cmd);
6633 }
6634 
6635 int
wl_android_set_spect(struct net_device * dev,int spect)6636 wl_android_set_spect(struct net_device *dev, int spect)
6637 {
6638 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6639 	int wlc_down = 1;
6640 	int wlc_up = 1;
6641 	int err = BCME_OK;
6642 
6643 	if (!wl_get_drv_status_all(cfg, CONNECTED)) {
6644 		err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
6645 		if (err) {
6646 			ANDROID_ERROR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
6647 			return err;
6648 		}
6649 
6650 		err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
6651 		if (err) {
6652 			ANDROID_ERROR(("%s: error setting spect: code: %d\n", __func__, err));
6653 			return err;
6654 		}
6655 
6656 		err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
6657 		if (err) {
6658 			ANDROID_ERROR(("%s: WLC_UP failed: code: %d\n", __func__, err));
6659 			return err;
6660 		}
6661 	}
6662 	return err;
6663 }
6664 
6665 static int
wl_android_get_sta_channel(struct bcm_cfg80211 * cfg)6666 wl_android_get_sta_channel(struct bcm_cfg80211 *cfg)
6667 {
6668 	chanspec_t *sta_chanspec = NULL;
6669 	u32 channel = 0;
6670 
6671 	if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
6672 		if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
6673 			bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) {
6674 			channel = wf_chspec_ctlchan(*sta_chanspec);
6675 		}
6676 	}
6677 	return channel;
6678 }
6679 
6680 static int
wl_cfg80211_get_acs_band(int band)6681 wl_cfg80211_get_acs_band(int band)
6682 {
6683 	chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6684 	switch (band) {
6685 		case WLC_BAND_AUTO:
6686 			ANDROID_INFO(("ACS full channel scan \n"));
6687 			/* Restricting band to 2G in case of hw_mode any */
6688 			acs_band = WL_CHANSPEC_BAND_2G;
6689 			break;
6690 #ifdef WL_6G_BAND
6691 		case WLC_BAND_6G:
6692 			ANDROID_INFO(("ACS 6G band scan \n"));
6693 			acs_band = WL_CHANSPEC_BAND_6G;
6694 			break;
6695 #endif /* WL_6G_BAND */
6696 		case WLC_BAND_5G:
6697 			ANDROID_INFO(("ACS 5G band scan \n"));
6698 			acs_band = WL_CHANSPEC_BAND_5G;
6699 			break;
6700 		case WLC_BAND_2G:
6701 			/*
6702 			 * If channel argument is not provided/ argument 20 is provided,
6703 			 * Restrict channel to 2GHz, 20MHz BW, No SB
6704 			 */
6705 			ANDROID_INFO(("ACS 2G band scan \n"));
6706 			acs_band = WL_CHANSPEC_BAND_2G;
6707 			break;
6708 		default:
6709 			ANDROID_ERROR(("ACS: No band chosen\n"));
6710 			break;
6711 	}
6712 	ANDROID_INFO(("%s: ACS: band = %d, acs_band = 0x%x\n", __FUNCTION__, band, acs_band));
6713 	return acs_band;
6714 }
6715 
6716 /* SoftAP feature */
6717 static int
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)6718 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
6719 	char* command, int total_len)
6720 {
6721 	int channel = 0, sta_channel = 0;
6722 	int chosen = 0;
6723 	int retry = 0;
6724 	int ret = 0;
6725 	int spect = 0;
6726 	u8 *reqbuf = NULL;
6727 	uint32 band = WLC_BAND_INVALID, sta_band = WLC_BAND_INVALID;
6728 	chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6729 	uint32 buf_size;
6730 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6731 	bool acs_freq_list_present = false;
6732 	char *pcmd;
6733 	int freq = 0;
6734 
6735 	if (cmd_str) {
6736 		ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
6737 		pcmd = bcmstrstr(cmd_str, FREQ_STR);
6738 		if (pcmd) {
6739 			acs_freq_list_present = true;
6740 			ANDROID_INFO(("ACS has freq list\n"));
6741 		} else if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
6742 			band = WLC_BAND_AUTO;
6743 #ifdef WL_6G_BAND
6744 		} else if (strnicmp(cmd_str, APCS_BAND_6G, strlen(APCS_BAND_6G)) == 0) {
6745 			band = WLC_BAND_6G;
6746 #endif /* WL_6G_BAND */
6747 		} else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
6748 			band = WLC_BAND_5G;
6749 		} else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
6750 			band = WLC_BAND_2G;
6751 		} else {
6752 			/*
6753 			 * For backward compatibility: Some platforms used to issue argument 20 or 0
6754 			 * to enforce the 2G channel selection
6755 			 */
6756 			channel = bcm_atoi(cmd_str);
6757 			if ((channel == APCS_BAND_2G_LEGACY1) ||
6758 				(channel == APCS_BAND_2G_LEGACY2)) {
6759 				band = WLC_BAND_2G;
6760 			} else {
6761 				ANDROID_ERROR(("Invalid argument\n"));
6762 				return -EINVAL;
6763 			}
6764 		}
6765 	} else {
6766 		/* If no argument is provided, default to 2G */
6767 		ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
6768 		band = WLC_BAND_2G;
6769 	}
6770 	ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
6771 
6772 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6773 	wl_cfg80211_register_dev_ril_bridge_event_notifier();
6774 	if (band == WLC_BAND_2G) {
6775 		wl_cfg80211_send_msg_to_ril();
6776 
6777 		if (g_mhs_chan_for_cpcoex) {
6778 			channel = g_mhs_chan_for_cpcoex;
6779 			g_mhs_chan_for_cpcoex = 0;
6780 			goto done2;
6781 		}
6782 	}
6783 	wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
6784 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6785 
6786 	/* If STA is connected, return is STA channel, else ACS can be issued,
6787 	 * set spect to 0 and proceed with ACS
6788 	 */
6789 	sta_channel = wl_android_get_sta_channel(cfg);
6790 	sta_band = WL_GET_BAND(sta_channel);
6791 	if (sta_channel && (band != WLC_BAND_INVALID)) {
6792 		switch (sta_band) {
6793 			case (WLC_BAND_5G):
6794 #ifdef WL_6G_BAND
6795 			case (WLC_BAND_6G):
6796 #endif /* WL_6G_BAND */
6797 			{
6798 				if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
6799 					channel = APCS_DEFAULT_2G_CH;
6800 				}
6801 				break;
6802 			}
6803 			case (WLC_BAND_2G): {
6804 				if (band == WLC_BAND_5G) {
6805 					channel = APCS_DEFAULT_5G_CH;
6806 				}
6807 #ifdef WL_6G_BAND
6808 				else if (band == WLC_BAND_6G) {
6809 					channel = APCS_DEFAULT_6G_CH;
6810 				}
6811 #endif /* WL_6G_BAND */
6812 				break;
6813 			}
6814 			default:
6815 				/* Intentional fall through to use same sta channel for softap */
6816 				channel = sta_channel;
6817 				break;
6818 		}
6819 		WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel);
6820 		goto done2;
6821 	}
6822 
6823 	/* If AP is started on wlan0 iface,
6824 	 * do not issue any iovar to fw and choose default ACS channel for softap
6825 	 */
6826 	if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6827 		if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
6828 			ANDROID_INFO(("Softap started on primary iface\n"));
6829 			goto done;
6830 		}
6831 	}
6832 
6833 	channel = wl_ext_autochannel(dev, ACS_DRV_BIT, band);
6834 	if (channel) {
6835 		acs_band = CHSPEC_BAND(channel);
6836 		goto done2;
6837 	} else
6838 		goto done;
6839 
6840 	ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
6841 	if (ret) {
6842 		ANDROID_ERROR(("ACS: error getting the spect, ret=%d\n", ret));
6843 		goto done;
6844 	}
6845 
6846 	if (spect > 0) {
6847 		ret = wl_android_set_spect(dev, 0);
6848 		if (ret < 0) {
6849 			ANDROID_ERROR(("ACS: error while setting spect, ret=%d\n", ret));
6850 			goto done;
6851 		}
6852 	}
6853 
6854 	reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
6855 	if (reqbuf == NULL) {
6856 		ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6857 		return -ENOMEM;
6858 	}
6859 
6860 	if (acs_freq_list_present) {
6861 		wl_uint32_list_t *list = NULL;
6862 		bzero(reqbuf, sizeof(*reqbuf));
6863 		list = (wl_uint32_list_t *)reqbuf;
6864 
6865 		ret = wl_android_get_freq_list_chanspecs(dev, list, CHANSPEC_BUF_SIZE,
6866 			cmd_str, sta_channel, wl_cfg80211_get_acs_band(sta_band));
6867 		if (ret < 0) {
6868 			ANDROID_ERROR(("ACS chanspec set failed!\n"));
6869 			goto done;
6870 		}
6871 
6872 		/* skip ACS for single channel case */
6873 		if (list->count == 1) {
6874 			cfg->acs_chspec = (chanspec_t)list->element[0];
6875 			channel = wf_chspec_ctlchan((chanspec_t)list->element[0]);
6876 			acs_band = CHSPEC_BAND((chanspec_t)list->element[0]);
6877 			goto done2;
6878 		}
6879 	} else {
6880 		acs_band = wl_cfg80211_get_acs_band(band);
6881 		if (acs_band == WLC_ACS_BAND_INVALID) {
6882 			ANDROID_ERROR(("ACS: No band chosen\n"));
6883 			goto done2;
6884 		}
6885 
6886 		if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE,
6887 			acs_band, true)) < 0) {
6888 			ANDROID_ERROR(("ACS chanspec retrieval failed! \n"));
6889 			goto done;
6890 		}
6891 	}
6892 
6893 	buf_size = CHANSPEC_BUF_SIZE;
6894 	ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
6895 		buf_size);
6896 	if (ret < 0) {
6897 		ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
6898 		channel = 0;
6899 		goto done;
6900 	}
6901 
6902 	/* Wait for auto channel selection, max 3000 ms */
6903 	if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) {
6904 		OSL_SLEEP(500);
6905 	} else {
6906 		/*
6907 		 * Full channel scan at the minimum takes 1.2secs
6908 		 * even with parallel scan. max wait time: 3500ms
6909 		 */
6910 		OSL_SLEEP(1000);
6911 	}
6912 
6913 	retry = APCS_MAX_RETRY;
6914 	while (retry--) {
6915 		ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
6916 			sizeof(chosen));
6917 		if (ret < 0) {
6918 			chosen = 0;
6919 		} else {
6920 			chosen = dtoh32(chosen);
6921 		}
6922 
6923 		if (chosen) {
6924 			/* Update chanspec which can be used during softAP bringup with right BW */
6925 			cfg->acs_chspec = chosen;
6926 			channel = wf_chspec_ctlchan(chosen);
6927 			acs_band = CHSPEC_BAND(chosen);
6928 			break;
6929 		}
6930 		ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x, acs_band = 0x%x\n",
6931 			(APCS_MAX_RETRY - retry), ret, chosen, acs_band));
6932 		OSL_SLEEP(250);
6933 	}
6934 
6935 done:
6936 	if ((retry == 0) || (ret < 0)) {
6937 		/* On failure, fallback to a default channel */
6938 		if (band == WLC_BAND_5G) {
6939 			channel = APCS_DEFAULT_5G_CH;
6940 #ifdef WL_6G_BAND
6941 		} else if (band == WLC_BAND_6G) {
6942 			channel = APCS_DEFAULT_6G_CH;
6943 #endif /* WL_6G_BAND */
6944 		} else {
6945 			channel = APCS_DEFAULT_2G_CH;
6946 		}
6947 		ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel));
6948 	}
6949 done2:
6950 	if (spect > 0) {
6951 		if ((ret = wl_android_set_spect(dev, spect) < 0)) {
6952 			ANDROID_ERROR(("ACS: error while setting spect\n"));
6953 		}
6954 	}
6955 
6956 	if (reqbuf) {
6957 		MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
6958 	}
6959 
6960 	ANDROID_INFO(("ACS: Channel = %d, acs_band = 0x%x\n", channel, acs_band));
6961 	if (channel && (acs_band != WLC_ACS_BAND_INVALID)) {
6962 		freq = wl_channel_to_frequency(channel, acs_band);
6963 		if (!freq) {
6964 			ANDROID_ERROR(("ACS: Invalid freq\n"));
6965 			return BCME_ERROR;
6966 		}
6967 		ret = snprintf(command, total_len, "%d freq=%d", channel, freq);
6968 		ANDROID_INFO(("command result is %s \n", command));
6969 	}
6970 
6971 	return ret;
6972 }
6973 #endif /* WL_SUPPORT_AUTO_CHANNEL */
6974 
6975 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6976 static int
wl_android_set_roam_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)6977 wl_android_set_roam_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
6978 {
6979 	s32 err = BCME_OK;
6980 	u32 roam_vsie_enable = 0;
6981 	u32 cmd_str_len = (u32)strlen(CMD_ROAM_VSIE_ENAB_SET);
6982 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6983 
6984 	/* <CMD><SPACE><VAL> */
6985 	if (!cmd || (cmd_len < (cmd_str_len + 1))) {
6986 		ANDROID_ERROR(("wrong arg\n"));
6987 		err = -EINVAL;
6988 		goto exit;
6989 	}
6990 
6991 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6992 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
6993 		err = -ENODEV;
6994 		goto exit;
6995 	}
6996 
6997 	roam_vsie_enable = cmd[(cmd_str_len + 1)] - '0';
6998 	if (roam_vsie_enable > 1) {
6999 		roam_vsie_enable = 1;
7000 	}
7001 
7002 	WL_DBG_MEM(("set roam vsie %d\n", roam_vsie_enable));
7003 	err = wldev_iovar_setint(dev, "roam_vsie", roam_vsie_enable);
7004 	if (unlikely(err)) {
7005 		ANDROID_ERROR(("set roam vsie enable failed. ret:%d\n", err));
7006 	}
7007 
7008 exit:
7009 	return err;
7010 }
7011 
7012 static int
wl_android_get_roam_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7013 wl_android_get_roam_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7014 {
7015 	s32 err = BCME_OK;
7016 	u32 roam_vsie_enable = 0;
7017 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7018 	int bytes_written;
7019 
7020 	/* <CMD> */
7021 	if (!cmd) {
7022 		ANDROID_ERROR(("wrong arg\n"));
7023 		return -1;
7024 	}
7025 
7026 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7027 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7028 		return -1;
7029 	}
7030 
7031 	err = wldev_iovar_getint(dev, "roam_vsie", &roam_vsie_enable);
7032 	if (unlikely(err)) {
7033 		ANDROID_ERROR(("get roam vsie enable failed. ret:%d\n", err));
7034 		return -1;
7035 	}
7036 	ANDROID_INFO(("get roam vsie %d\n", roam_vsie_enable));
7037 
7038 	bytes_written = snprintf(cmd, cmd_len, "%s %d",
7039 		CMD_ROAM_VSIE_ENAB_GET, roam_vsie_enable);
7040 
7041 	return bytes_written;
7042 }
7043 
7044 static int
wl_android_set_bcn_rpt_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)7045 wl_android_set_bcn_rpt_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
7046 {
7047 	s32 err;
7048 	u32 bcn_vsie_enable = 0;
7049 	u32 cmd_str_len = (u32)strlen(CMD_BR_VSIE_ENAB_SET);
7050 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7051 
7052 	/* <CMD><SPACE><VAL> */
7053 	if (!cmd || (cmd_len < (cmd_str_len + 1))) {
7054 		ANDROID_ERROR(("invalid arg\n"));
7055 		err = -EINVAL;
7056 		goto exit;
7057 	}
7058 
7059 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7060 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7061 		err = -ENODEV;
7062 		goto exit;
7063 	}
7064 
7065 	bcn_vsie_enable = cmd[cmd_str_len + 1] - '0';
7066 	if (bcn_vsie_enable > 1) {
7067 		bcn_vsie_enable = 1;
7068 	}
7069 
7070 	WL_DBG_MEM(("set bcn report vsie %d\n", bcn_vsie_enable));
7071 	err = wldev_iovar_setint(dev, "bcnrpt_vsie_en", bcn_vsie_enable);
7072 	if (unlikely(err)) {
7073 		ANDROID_ERROR(("set bcn vsie failed. ret:%d\n", err));
7074 	}
7075 
7076 exit:
7077 	return err;
7078 }
7079 
7080 static int
wl_android_get_bcn_rpt_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7081 wl_android_get_bcn_rpt_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7082 {
7083 	s32 err = BCME_OK;
7084 	u32 bcn_vsie_enable = 0;
7085 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7086 	int bytes_written;
7087 
7088 	/* <CMD> */
7089 	if (!cmd) {
7090 		ANDROID_ERROR(("wrong arg\n"));
7091 		return -1;
7092 	}
7093 
7094 	if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7095 		ANDROID_ERROR(("config not supported on non primary i/f\n"));
7096 		return -1;
7097 	}
7098 
7099 	err = wldev_iovar_getint(dev, "bcnrpt_vsie_en", &bcn_vsie_enable);
7100 	if (unlikely(err)) {
7101 		ANDROID_ERROR(("get bcn vsie failed. ret:%d\n", err));
7102 		return -1;
7103 	}
7104 	ANDROID_INFO(("get bcn report vsie %d\n", bcn_vsie_enable));
7105 
7106 	bytes_written = snprintf(cmd, cmd_len, "%s %d",
7107 		CMD_BR_VSIE_ENAB_GET, bcn_vsie_enable);
7108 
7109 	return bytes_written;
7110 }
7111 
7112 #ifdef SUPPORT_HIDDEN_AP
7113 static int
wl_android_set_max_num_sta(struct net_device * dev,const char * string_num)7114 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
7115 {
7116 	int err = BCME_ERROR;
7117 	int max_assoc;
7118 
7119 	max_assoc = bcm_atoi(string_num);
7120 	ANDROID_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc));
7121 
7122 	err = wldev_iovar_setint(dev, "maxassoc", max_assoc);
7123 	if (err < 0) {
7124 		ANDROID_ERROR(("failed to set maxassoc, error:%d\n", err));
7125 	}
7126 
7127 	return err;
7128 }
7129 
7130 static int
wl_android_set_ssid(struct net_device * dev,const char * hapd_ssid)7131 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
7132 {
7133 	wlc_ssid_t ssid;
7134 	s32 ret;
7135 
7136 	ssid.SSID_len = strlen(hapd_ssid);
7137 	if (ssid.SSID_len == 0) {
7138 		ANDROID_ERROR(("wl_android_set_ssids : No SSID\n"));
7139 		return -1;
7140 	}
7141 	if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
7142 		ssid.SSID_len = DOT11_MAX_SSID_LEN;
7143 		ANDROID_ERROR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid)));
7144 	}
7145 	bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
7146 	ANDROID_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID));
7147 	ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
7148 	if (ret < 0) {
7149 		ANDROID_ERROR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret));
7150 	}
7151 	return 1;
7152 
7153 }
7154 
7155 static int
wl_android_set_hide_ssid(struct net_device * dev,const char * string_num)7156 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
7157 {
7158 	int hide_ssid;
7159 	int enable = 0;
7160 	int err = BCME_ERROR;
7161 
7162 	hide_ssid = bcm_atoi(string_num);
7163 	ANDROID_INFO(("wl_android_set_hide_ssid: HAPD_HIDE_SSID = %d\n", hide_ssid));
7164 	if (hide_ssid) {
7165 		enable = 1;
7166 	}
7167 
7168 	err = wldev_iovar_setint(dev, "closednet", enable);
7169 	if (err < 0) {
7170 		ANDROID_ERROR(("failed to set closednet, error:%d\n", err));
7171 	}
7172 
7173 	return err;
7174 }
7175 #endif /* SUPPORT_HIDDEN_AP */
7176 
7177 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
7178 static int
wl_android_sta_diassoc(struct net_device * dev,const char * straddr)7179 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
7180 {
7181 	scb_val_t scbval;
7182 	int error  = 0;
7183 
7184 	ANDROID_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr));
7185 
7186 	/* Unspecified reason */
7187 	scbval.val = htod32(1);
7188 
7189 	if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
7190 		ANDROID_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n"));
7191 		return -1;
7192 	}
7193 
7194 	ANDROID_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n",
7195 		MAC2STRDBG(scbval.ea.octet), scbval.val));
7196 
7197 	error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
7198 		sizeof(scb_val_t));
7199 	if (error) {
7200 		ANDROID_ERROR(("Fail to DEAUTH station, error = %d\n", error));
7201 	}
7202 
7203 	return 1;
7204 }
7205 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
7206 
7207 #ifdef SUPPORT_SET_LPC
7208 static int
wl_android_set_lpc(struct net_device * dev,const char * string_num)7209 wl_android_set_lpc(struct net_device *dev, const char* string_num)
7210 {
7211 	int lpc_enabled, ret;
7212 	s32 val = 1;
7213 
7214 	lpc_enabled = bcm_atoi(string_num);
7215 	ANDROID_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled));
7216 
7217 	ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
7218 	if (ret < 0)
7219 		ANDROID_ERROR(("WLC_DOWN error %d\n", ret));
7220 
7221 	wldev_iovar_setint(dev, "lpc", lpc_enabled);
7222 
7223 	ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
7224 	if (ret < 0)
7225 		ANDROID_ERROR(("WLC_UP error %d\n", ret));
7226 
7227 	return 1;
7228 }
7229 #endif /* SUPPORT_SET_LPC */
7230 
7231 static int
wl_android_ch_res_rl(struct net_device * dev,bool change)7232 wl_android_ch_res_rl(struct net_device *dev, bool change)
7233 {
7234 	int error = 0;
7235 	s32 srl = 7;
7236 	s32 lrl = 4;
7237 	ANDROID_ERROR(("wl_android_ch_res_rl: enter\n"));
7238 	if (change) {
7239 		srl = 4;
7240 		lrl = 2;
7241 	}
7242 
7243 	BCM_REFERENCE(lrl);
7244 
7245 	error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
7246 	if (error) {
7247 		ANDROID_ERROR(("Failed to set SRL, error = %d\n", error));
7248 	}
7249 #ifndef CUSTOM_LONG_RETRY_LIMIT
7250 	error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
7251 	if (error) {
7252 		ANDROID_ERROR(("Failed to set LRL, error = %d\n", error));
7253 	}
7254 #endif /* CUSTOM_LONG_RETRY_LIMIT */
7255 	return error;
7256 }
7257 
7258 #ifdef SUPPORT_LTECX
7259 #define DEFAULT_WLANRX_PROT	1
7260 #define DEFAULT_LTERX_PROT	0
7261 #define DEFAULT_LTETX_ADV	1200
7262 
7263 static int
wl_android_set_ltecx(struct net_device * dev,const char * string_num)7264 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
7265 {
7266 	uint16 chan_bitmap;
7267 	int ret;
7268 
7269 	chan_bitmap = bcm_strtoul(string_num, NULL, 16);
7270 
7271 	ANDROID_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap));
7272 
7273 	if (chan_bitmap) {
7274 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7275 		if (ret < 0) {
7276 			ANDROID_ERROR(("mws_coex_bitmap error %d\n", ret));
7277 		}
7278 
7279 		ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
7280 		if (ret < 0) {
7281 			ANDROID_ERROR(("mws_wlanrx_prot error %d\n", ret));
7282 		}
7283 
7284 		ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
7285 		if (ret < 0) {
7286 			ANDROID_ERROR(("mws_lterx_prot error %d\n", ret));
7287 		}
7288 
7289 		ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
7290 		if (ret < 0) {
7291 			ANDROID_ERROR(("mws_ltetx_adv error %d\n", ret));
7292 		}
7293 	} else {
7294 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7295 		if (ret < 0) {
7296 			if (ret == BCME_UNSUPPORTED) {
7297 				ANDROID_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
7298 			} else {
7299 				ANDROID_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
7300 			}
7301 		}
7302 	}
7303 	return 1;
7304 }
7305 #endif /* SUPPORT_LTECX */
7306 
7307 #ifdef WL_RELMCAST
7308 static int
wl_android_rmc_enable(struct net_device * net,int rmc_enable)7309 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
7310 {
7311 	int err;
7312 
7313 	err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
7314 	if (err != BCME_OK) {
7315 		ANDROID_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err));
7316 	}
7317 	return err;
7318 }
7319 
7320 static int
wl_android_rmc_set_leader(struct net_device * dev,const char * straddr)7321 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
7322 {
7323 	int error  = BCME_OK;
7324 	char smbuf[WLC_IOCTL_SMLEN];
7325 	wl_rmc_entry_t rmc_entry;
7326 	ANDROID_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr));
7327 
7328 	bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7329 	if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
7330 		if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
7331 			ANDROID_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n"));
7332 			bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7333 		} else {
7334 			ANDROID_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n"));
7335 			return BCME_ERROR;
7336 		}
7337 	}
7338 
7339 	error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
7340 		smbuf, sizeof(smbuf), NULL);
7341 
7342 	if (error != BCME_OK) {
7343 		ANDROID_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n",
7344 			error));
7345 	}
7346 
7347 	return error;
7348 }
7349 
wl_android_set_rmc_event(struct net_device * dev,char * command)7350 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
7351 {
7352 	int err = 0;
7353 	int pid = 0;
7354 
7355 	if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
7356 		ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
7357 		return -1;
7358 	}
7359 
7360 	/* set pid, and if the event was happened, let's send a notification through netlink */
7361 	wl_cfg80211_set_rmc_pid(dev, pid);
7362 
7363 	ANDROID_INFO(("RMC pid=%d\n", pid));
7364 
7365 	return err;
7366 }
7367 #endif /* WL_RELMCAST */
7368 
wl_android_get_singlecore_scan(struct net_device * dev,char * command,int total_len)7369 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
7370 {
7371 	int error = 0;
7372 	int bytes_written = 0;
7373 	int mode = 0;
7374 
7375 	error = wldev_iovar_getint(dev, "scan_ps", &mode);
7376 	if (error) {
7377 		ANDROID_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode,"
7378 			" error = %d\n",
7379 			error));
7380 		return -1;
7381 	}
7382 
7383 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
7384 
7385 	return bytes_written;
7386 }
7387 
wl_android_set_singlecore_scan(struct net_device * dev,char * command)7388 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
7389 {
7390 	int error = 0;
7391 	int mode = 0;
7392 
7393 	if (sscanf(command, "%*s %d", &mode) != 1) {
7394 		ANDROID_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n"));
7395 		return -1;
7396 	}
7397 
7398 	error = wldev_iovar_setint(dev, "scan_ps", mode);
7399 	if (error) {
7400 		ANDROID_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n",
7401 		mode, error));
7402 		return -1;
7403 	}
7404 
7405 	return error;
7406 }
7407 #ifdef TEST_TX_POWER_CONTROL
7408 static int
wl_android_set_tx_power(struct net_device * dev,const char * string_num)7409 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
7410 {
7411 	int err = 0;
7412 	s32 dbm;
7413 	enum nl80211_tx_power_setting type;
7414 
7415 	dbm = bcm_atoi(string_num);
7416 
7417 	if (dbm < -1) {
7418 		ANDROID_ERROR(("wl_android_set_tx_power: dbm is negative...\n"));
7419 		return -EINVAL;
7420 	}
7421 
7422 	if (dbm == -1)
7423 		type = NL80211_TX_POWER_AUTOMATIC;
7424 	else
7425 		type = NL80211_TX_POWER_FIXED;
7426 
7427 	err = wl_set_tx_power(dev, type, dbm);
7428 	if (unlikely(err)) {
7429 		ANDROID_ERROR(("wl_android_set_tx_power: error (%d)\n", err));
7430 		return err;
7431 	}
7432 
7433 	return 1;
7434 }
7435 
7436 static int
wl_android_get_tx_power(struct net_device * dev,char * command,int total_len)7437 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
7438 {
7439 	int err;
7440 	int bytes_written;
7441 	s32 dbm = 0;
7442 
7443 	err = wl_get_tx_power(dev, &dbm);
7444 	if (unlikely(err)) {
7445 		ANDROID_ERROR(("wl_android_get_tx_power: error (%d)\n", err));
7446 		return err;
7447 	}
7448 
7449 	bytes_written = snprintf(command, total_len, "%s %d",
7450 		CMD_TEST_GET_TX_POWER, dbm);
7451 
7452 	ANDROID_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm));
7453 
7454 	return bytes_written;
7455 }
7456 #endif /* TEST_TX_POWER_CONTROL */
7457 
7458 static int
wl_android_set_sarlimit_txctrl(struct net_device * dev,const char * string_num)7459 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
7460 {
7461 	int err = BCME_ERROR;
7462 	int setval = 0;
7463 	s32 mode = bcm_atoi(string_num);
7464 	s32 mode_bit = 0;
7465 	int enab = 0;
7466 
7467 	/* As Samsung specific and their requirement,
7468 	 * the mode set as the following form.
7469 	 * -1 : HEAD SAR disabled
7470 	 *  0 : HEAD SAR enabled
7471 	 *  1 : GRIP SAR disabled
7472 	 *  2 : GRIP SAR enabled
7473 	 *  3 : NR mmWave SAR disabled
7474 	 *  4 : NR mmWave SAR enabled
7475 	 *  5 : NR Sub6 SAR disabled
7476 	 *  6 : NR Sub6 SAR enabled
7477 	 *  7 : SAR BACKOFF disabled all
7478 	 * The 'SAR BACKOFF disabled all' index should be the end of the mode.
7479 	 */
7480 	if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) {
7481 		ANDROID_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num)));
7482 		err = BCME_RANGE;
7483 		goto error;
7484 	}
7485 
7486 	mode_bit = mode + 1;
7487 	enab = mode_bit % 2;
7488 	mode_bit = mode_bit / 2;
7489 
7490 	err = wldev_iovar_getint(dev, "sar_enable", &setval);
7491 	if (unlikely(err)) {
7492 		ANDROID_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err));
7493 		goto error;
7494 	}
7495 
7496 	if (mode == SAR_BACKOFF_DISABLE_ALL) {
7497 		ANDROID_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__));
7498 		setval = 0;
7499 	} else {
7500 		ANDROID_ERROR(("%s: SAR limit control mode %d enab %d\n",
7501 			__FUNCTION__, mode_bit, enab));
7502 		if (enab) {
7503 			setval |= (1 << mode_bit);
7504 		} else {
7505 			setval &= ~(1 << mode_bit);
7506 		}
7507 	}
7508 
7509 	err = wldev_iovar_setint(dev, "sar_enable", setval);
7510 	if (unlikely(err)) {
7511 		ANDROID_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
7512 		goto error;
7513 	}
7514 	err = BCME_OK;
7515 error:
7516 	return err;
7517 }
7518 
7519 #ifdef SUPPORT_SET_TID
7520 static int
wl_android_set_tid(struct net_device * dev,char * command)7521 wl_android_set_tid(struct net_device *dev, char* command)
7522 {
7523 	int err = BCME_ERROR;
7524 	char *pos = command;
7525 	char *token = NULL;
7526 	uint8 mode = 0;
7527 	uint32 uid = 0;
7528 	uint8 prio = 0;
7529 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7530 
7531 	if (!dhdp) {
7532 		ANDROID_ERROR(("dhd is NULL\n"));
7533 		return err;
7534 	}
7535 
7536 	ANDROID_INFO(("%s: command[%s]\n", __FUNCTION__, command));
7537 
7538 	/* drop command */
7539 	token = bcmstrtok(&pos, " ", NULL);
7540 
7541 	token = bcmstrtok(&pos, " ", NULL);
7542 	if (!token) {
7543 		ANDROID_ERROR(("Invalid arguments\n"));
7544 		return err;
7545 	}
7546 
7547 	mode = bcm_atoi(token);
7548 
7549 	if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
7550 		ANDROID_ERROR(("Invalid arguments, mode %d\n", mode));
7551 			return err;
7552 	}
7553 
7554 	if (mode) {
7555 		token = bcmstrtok(&pos, " ", NULL);
7556 		if (!token) {
7557 			ANDROID_ERROR(("Invalid arguments for target uid\n"));
7558 			return err;
7559 		}
7560 
7561 		uid = bcm_atoi(token);
7562 
7563 		token = bcmstrtok(&pos, " ", NULL);
7564 		if (!token) {
7565 			ANDROID_ERROR(("Invalid arguments for target tid\n"));
7566 			return err;
7567 		}
7568 
7569 		prio = bcm_atoi(token);
7570 		if (prio >= 0 && prio <= MAXPRIO) {
7571 			dhdp->tid_mode = mode;
7572 			dhdp->target_uid = uid;
7573 			dhdp->target_tid = prio;
7574 		} else {
7575 			ANDROID_ERROR(("Invalid arguments, prio %d\n", prio));
7576 			return err;
7577 		}
7578 	} else {
7579 		dhdp->tid_mode = SET_TID_OFF;
7580 		dhdp->target_uid = 0;
7581 		dhdp->target_tid = 0;
7582 	}
7583 
7584 	ANDROID_INFO(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
7585 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
7586 
7587 	err = BCME_OK;
7588 	return err;
7589 }
7590 
7591 static int
wl_android_get_tid(struct net_device * dev,char * command,int total_len)7592 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
7593 {
7594 	int bytes_written = BCME_ERROR;
7595 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7596 
7597 	if (!dhdp) {
7598 		ANDROID_ERROR(("dhd is NULL\n"));
7599 		return bytes_written;
7600 	}
7601 
7602 	bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
7603 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
7604 
7605 	ANDROID_INFO(("%s: command results %s\n", __FUNCTION__, command));
7606 
7607 	return bytes_written;
7608 }
7609 #endif /* SUPPORT_SET_TID */
7610 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7611 
wl_android_set_roam_mode(struct net_device * dev,char * command)7612 int wl_android_set_roam_mode(struct net_device *dev, char *command)
7613 {
7614 	int error = 0;
7615 	int mode = 0;
7616 
7617 	if (sscanf(command, "%*s %d", &mode) != 1) {
7618 		ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7619 		return -1;
7620 	}
7621 
7622 	error = wldev_iovar_setint(dev, "roam_off", mode);
7623 	if (error) {
7624 		ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
7625 		__FUNCTION__, mode, error));
7626 		return -1;
7627 	}
7628 	else
7629 		ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
7630 		__FUNCTION__, mode, error));
7631 	return 0;
7632 }
7633 
7634 #ifdef WL_CFG80211
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)7635 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
7636 {
7637 	char ie_buf[VNDR_IE_MAX_LEN];
7638 	char *ioctl_buf = NULL;
7639 	char hex[] = "XX";
7640 	char *pcmd = NULL;
7641 	int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
7642 	vndr_ie_setbuf_t *vndr_ie = NULL;
7643 	s32 iecount;
7644 	uint32 pktflag;
7645 	s32 err = BCME_OK, bssidx;
7646 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7647 
7648 	/* Check the VSIE (Vendor Specific IE) which was added.
7649 	 *  If exist then send IOVAR to delete it
7650 	 */
7651 	if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
7652 		return -EINVAL;
7653 	}
7654 
7655 	if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
7656 		ANDROID_ERROR(("error. total_len:%d\n", total_len));
7657 		return -EINVAL;
7658 	}
7659 
7660 	pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
7661 	for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
7662 		if (*pcmd == '\0') {
7663 			ANDROID_ERROR(("error while parsing OUI.\n"));
7664 			return -EINVAL;
7665 		}
7666 		hex[0] = *pcmd++;
7667 		hex[1] = *pcmd++;
7668 		ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
7669 	}
7670 	pcmd++;
7671 	while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
7672 		hex[0] = *pcmd++;
7673 		hex[1] = *pcmd++;
7674 		ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
7675 		datalen++;
7676 	}
7677 
7678 	if (datalen <= 0) {
7679 		ANDROID_ERROR(("error. vndr ie len:%d\n", datalen));
7680 		return -EINVAL;
7681 	}
7682 
7683 	tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
7684 	vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
7685 	if (!vndr_ie) {
7686 		ANDROID_ERROR(("IE memory alloc failed\n"));
7687 		return -ENOMEM;
7688 	}
7689 	/* Copy the vndr_ie SET command ("add"/"del") to the buffer */
7690 	strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
7691 
7692 	/* Set the IE count - the buffer contains only 1 IE */
7693 	iecount = htod32(1);
7694 	memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
7695 
7696 	/* Set packet flag to indicate that BEACON's will contain this IE */
7697 	pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
7698 	memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
7699 		sizeof(u32));
7700 	/* Set the IE ID */
7701 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
7702 
7703 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
7704 		DOT11_OUI_LEN);
7705 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
7706 		&ie_buf[DOT11_OUI_LEN], datalen);
7707 
7708 	ielen = DOT11_OUI_LEN + datalen;
7709 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
7710 
7711 	ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
7712 	if (!ioctl_buf) {
7713 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
7714 		if (vndr_ie) {
7715 			MFREE(cfg->osh, vndr_ie, tot_len);
7716 		}
7717 		return -ENOMEM;
7718 	}
7719 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);	/* init the buffer */
7720 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7721 		ANDROID_ERROR(("Find index failed\n"));
7722 		err = BCME_ERROR;
7723 		goto end;
7724 	}
7725 	err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
7726 			WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
7727 end:
7728 	if (err != BCME_OK) {
7729 		err = -EINVAL;
7730 		if (vndr_ie) {
7731 			MFREE(cfg->osh, vndr_ie, tot_len);
7732 		}
7733 	}
7734 	else {
7735 		/* do NOT free 'vndr_ie' for the next process */
7736 		wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
7737 	}
7738 
7739 	if (ioctl_buf) {
7740 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
7741 	}
7742 
7743 	return err;
7744 }
7745 #endif /* WL_CFG80211 */
7746 
7747 #if defined(BCMFW_ROAM_ENABLE)
7748 static int
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)7749 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
7750 {
7751 	int error = 0;
7752 	char smbuf[WLC_IOCTL_SMLEN];
7753 	uint8 buf[MAX_BUF_SIZE];
7754 	uint8 *pref = buf;
7755 	char *pcmd;
7756 	int num_ucipher_suites = 0;
7757 	int num_akm_suites = 0;
7758 	wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
7759 	wpa_suite_t akm_suites[MAX_NUM_SUITES];
7760 	int num_tuples = 0;
7761 	int total_bytes = 0;
7762 	int total_len_left;
7763 	int i, j;
7764 	char hex[] = "XX";
7765 
7766 	pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
7767 	total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
7768 
7769 	num_akm_suites = simple_strtoul(pcmd, NULL, 16);
7770 	if (num_akm_suites > MAX_NUM_SUITES) {
7771 		ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites));
7772 		return -1;
7773 	}
7774 
7775 	/* Increment for number of AKM suites field + space */
7776 	pcmd += 3;
7777 	total_len_left -= 3;
7778 
7779 	/* check to make sure pcmd does not overrun */
7780 	if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
7781 		return -1;
7782 
7783 	bzero(buf, sizeof(buf));
7784 	bzero(akm_suites, sizeof(akm_suites));
7785 	bzero(ucipher_suites, sizeof(ucipher_suites));
7786 
7787 	/* Save the AKM suites passed in the command */
7788 	for (i = 0; i < num_akm_suites; i++) {
7789 		/* Store the MSB first, as required by join_pref */
7790 		for (j = 0; j < 4; j++) {
7791 			hex[0] = *pcmd++;
7792 			hex[1] = *pcmd++;
7793 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7794 		}
7795 		memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
7796 	}
7797 
7798 	total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
7799 	num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
7800 	/* Increment for number of cipher suites field + space */
7801 	pcmd += 3;
7802 	total_len_left -= 3;
7803 
7804 	if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
7805 		return -1;
7806 
7807 	/* Save the cipher suites passed in the command */
7808 	for (i = 0; i < num_ucipher_suites; i++) {
7809 		/* Store the MSB first, as required by join_pref */
7810 		for (j = 0; j < 4; j++) {
7811 			hex[0] = *pcmd++;
7812 			hex[1] = *pcmd++;
7813 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7814 		}
7815 		memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
7816 	}
7817 
7818 	/* Join preference for RSSI
7819 	 * Type	  : 1 byte (0x01)
7820 	 * Length : 1 byte (0x02)
7821 	 * Value  : 2 bytes	(reserved)
7822 	 */
7823 	*pref++ = WL_JOIN_PREF_RSSI;
7824 	*pref++ = JOIN_PREF_RSSI_LEN;
7825 	*pref++ = 0;
7826 	*pref++ = 0;
7827 
7828 	/* Join preference for WPA
7829 	 * Type	  : 1 byte (0x02)
7830 	 * Length : 1 byte (not used)
7831 	 * Value  : (variable length)
7832 	 *		reserved: 1 byte
7833 	 *      count	: 1 byte (no of tuples)
7834 	 *		Tuple1	: 12 bytes
7835 	 *			akm[4]
7836 	 *			ucipher[4]
7837 	 *			mcipher[4]
7838 	 *		Tuple2	: 12 bytes
7839 	 *		Tuplen	: 12 bytes
7840 	 */
7841 	num_tuples = num_akm_suites * num_ucipher_suites;
7842 	if (num_tuples != 0) {
7843 		if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
7844 			*pref++ = WL_JOIN_PREF_WPA;
7845 			*pref++ = 0;
7846 			*pref++ = 0;
7847 			*pref++ = (uint8)num_tuples;
7848 			total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
7849 				(JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
7850 		} else {
7851 			ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
7852 			return -1;
7853 		}
7854 	} else {
7855 		/* No WPA config, configure only RSSI preference */
7856 		total_bytes = JOIN_PREF_RSSI_SIZE;
7857 	}
7858 
7859 	/* akm-ucipher-mcipher tuples in the format required for join_pref */
7860 	for (i = 0; i < num_ucipher_suites; i++) {
7861 		for (j = 0; j < num_akm_suites; j++) {
7862 			memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
7863 			pref += WPA_SUITE_LEN;
7864 			memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
7865 			pref += WPA_SUITE_LEN;
7866 			/* Set to 0 to match any available multicast cipher */
7867 			bzero(pref, WPA_SUITE_LEN);
7868 			pref += WPA_SUITE_LEN;
7869 		}
7870 	}
7871 
7872 	prhex("join pref", (uint8 *)buf, total_bytes);
7873 	error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
7874 	if (error) {
7875 		ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
7876 	}
7877 	return error;
7878 }
7879 #endif /* defined(BCMFW_ROAM_ENABLE */
7880 
7881 #ifdef WL_CFG80211
7882 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)7883 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
7884 {
7885 	struct io_cfg *resume_cfg;
7886 	s32 ret;
7887 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7888 
7889 	resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
7890 	if (!resume_cfg)
7891 		return -ENOMEM;
7892 
7893 	if (config->iovar) {
7894 		ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
7895 		if (ret) {
7896 			ANDROID_ERROR(("%s: Failed to get current %s value\n",
7897 				__FUNCTION__, config->iovar));
7898 			goto error;
7899 		}
7900 
7901 		ret = wldev_iovar_setint(dev, config->iovar, config->param);
7902 		if (ret) {
7903 			ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7904 				config->iovar, config->param));
7905 			goto error;
7906 		}
7907 
7908 		resume_cfg->iovar = config->iovar;
7909 	} else {
7910 		resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
7911 		if (!resume_cfg->arg) {
7912 			ret = -ENOMEM;
7913 			goto error;
7914 		}
7915 		ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
7916 		if (ret) {
7917 			ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
7918 				config->ioctl));
7919 			goto error;
7920 		}
7921 		ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
7922 		if (ret) {
7923 			ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7924 				config->iovar, config->param));
7925 			goto error;
7926 		}
7927 		if (config->ioctl + 1 == WLC_SET_PM)
7928 			wl_cfg80211_update_power_mode(dev);
7929 		resume_cfg->ioctl = config->ioctl;
7930 		resume_cfg->len = config->len;
7931 	}
7932 
7933 	/* assuming only one active user and no list protection */
7934 	list_add(&resume_cfg->list, head);
7935 
7936 	return 0;
7937 error:
7938 	MFREE(cfg->osh, resume_cfg->arg, config->len);
7939 	MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
7940 	return ret;
7941 }
7942 
7943 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)7944 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
7945 {
7946 	struct io_cfg *config;
7947 	struct list_head *cur, *q;
7948 	s32 ret = 0;
7949 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7950 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7951 	list_for_each_safe(cur, q, head) {
7952 		config = list_entry(cur, struct io_cfg, list);
7953 		GCC_DIAGNOSTIC_POP();
7954 		if (config->iovar) {
7955 			if (!ret)
7956 				ret = wldev_iovar_setint(dev, config->iovar,
7957 					config->param);
7958 		} else {
7959 			if (!ret)
7960 				ret = wldev_ioctl_set(dev, config->ioctl + 1,
7961 					config->arg, config->len);
7962 			if (config->ioctl + 1 == WLC_SET_PM)
7963 				wl_cfg80211_update_power_mode(dev);
7964 			MFREE(cfg->osh, config->arg, config->len);
7965 		}
7966 		list_del(cur);
7967 		MFREE(cfg->osh, config, sizeof(struct io_cfg));
7968 	}
7969 }
7970 
7971 static int
wl_android_set_miracast(struct net_device * dev,char * command)7972 wl_android_set_miracast(struct net_device *dev, char *command)
7973 {
7974 	int mode, val = 0;
7975 	int ret = 0;
7976 	struct io_cfg config;
7977 
7978 	if (sscanf(command, "%*s %d", &mode) != 1) {
7979 		ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7980 		return -1;
7981 	}
7982 
7983 	ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
7984 
7985 	if (miracast_cur_mode == mode) {
7986 		return 0;
7987 	}
7988 
7989 	wl_android_iolist_resume(dev, &miracast_resume_list);
7990 	miracast_cur_mode = MIRACAST_MODE_OFF;
7991 
7992 	bzero((void *)&config, sizeof(config));
7993 	switch (mode) {
7994 	case MIRACAST_MODE_SOURCE:
7995 #ifdef MIRACAST_MCHAN_ALGO
7996 		/* setting mchan_algo to platform specific value */
7997 		config.iovar = "mchan_algo";
7998 
7999 		/* check for station's beacon interval(BI)
8000 		 * If BI is over 100ms, don't use mchan_algo
8001 		 */
8002 		ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
8003 		if (!ret && val > 100) {
8004 			config.param = 0;
8005 			ANDROID_ERROR(("%s: Connected station's beacon interval: "
8006 				"%d and set mchan_algo to %d \n",
8007 				__FUNCTION__, val, config.param));
8008 		} else {
8009 			config.param = MIRACAST_MCHAN_ALGO;
8010 		}
8011 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8012 		if (ret) {
8013 			goto resume;
8014 		}
8015 #endif /* MIRACAST_MCHAN_ALGO */
8016 
8017 #ifdef MIRACAST_MCHAN_BW
8018 		/* setting mchan_bw to platform specific value */
8019 		config.iovar = "mchan_bw";
8020 		config.param = MIRACAST_MCHAN_BW;
8021 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8022 		if (ret) {
8023 			goto resume;
8024 		}
8025 #endif /* MIRACAST_MCHAN_BW */
8026 
8027 #ifdef MIRACAST_AMPDU_SIZE
8028 		/* setting apmdu to platform specific value */
8029 		config.iovar = "ampdu_mpdu";
8030 		config.param = MIRACAST_AMPDU_SIZE;
8031 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8032 		if (ret) {
8033 			goto resume;
8034 		}
8035 #endif /* MIRACAST_AMPDU_SIZE */
8036 		/* FALLTROUGH */
8037 		/* Source mode shares most configurations with sink mode.
8038 		 * Fall through here to avoid code duplication
8039 		 */
8040 	case MIRACAST_MODE_SINK:
8041 		/* disable internal roaming */
8042 		config.iovar = "roam_off";
8043 		config.param = 1;
8044 		config.arg = NULL;
8045 		config.len = 0;
8046 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8047 		if (ret) {
8048 			goto resume;
8049 		}
8050 
8051 #ifdef CUSTOMER_HW10
8052 		/* [CSP#812738] Change scan engine parameters to reduce scan time
8053 		 * and guarantee more times to mirroring.
8054 		 */
8055 		val = 10;
8056 		config.iovar = NULL;
8057 		config.ioctl = WLC_GET_SCAN_CHANNEL_TIME;
8058 		config.arg = &val;
8059 		config.len = sizeof(int);
8060 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8061 		if (ret)
8062 			goto resume;
8063 
8064 		val = 180;
8065 		config.iovar = NULL;
8066 		config.ioctl = WLC_GET_SCAN_HOME_TIME;
8067 		config.arg = &val;
8068 		config.len = sizeof(int);
8069 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8070 		if (ret)
8071 			goto resume;
8072 
8073 #if defined(BCM4339_CHIP)
8074 		config.iovar = "phy_watchdog";
8075 		config.param = 0;
8076 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8077 		ANDROID_INFO(("%s: do iovar cmd=%s (ret=%d)\n",
8078 			__FUNCTION__, config.iovar, ret));
8079 #endif
8080 #endif /* CUSTOMER_HW10 */
8081 
8082 #ifndef CUSTOMER_HW10
8083 
8084 		/* tunr off pm */
8085 		ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
8086 		if (ret) {
8087 			goto resume;
8088 		}
8089 
8090 		if (val != PM_OFF) {
8091 			val = PM_OFF;
8092 			config.iovar = NULL;
8093 			config.ioctl = WLC_GET_PM;
8094 			config.arg = &val;
8095 			config.len = sizeof(int);
8096 			ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8097 			if (ret) {
8098 				goto resume;
8099 			}
8100 		}
8101 #endif /* CUSTOMER_HW10 */
8102 		break;
8103 	case MIRACAST_MODE_OFF:
8104 	default:
8105 		break;
8106 	}
8107 	miracast_cur_mode = mode;
8108 
8109 	return 0;
8110 
8111 resume:
8112 	ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
8113 	wl_android_iolist_resume(dev, &miracast_resume_list);
8114 	return ret;
8115 }
8116 #endif /* WL_CFG80211 */
8117 
8118 #ifdef WL_RELMCAST
8119 #define NETLINK_OXYGEN     30
8120 #define AIBSS_BEACON_TIMEOUT	10
8121 
8122 static struct sock *nl_sk = NULL;
8123 
wl_netlink_recv(struct sk_buff * skb)8124 static void wl_netlink_recv(struct sk_buff *skb)
8125 {
8126 	ANDROID_ERROR(("netlink_recv called\n"));
8127 }
8128 
wl_netlink_init(void)8129 static int wl_netlink_init(void)
8130 {
8131 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8132 	struct netlink_kernel_cfg cfg = {
8133 		.input	= wl_netlink_recv,
8134 	};
8135 #endif
8136 
8137 	if (nl_sk != NULL) {
8138 		ANDROID_ERROR(("nl_sk already exist\n"));
8139 		return BCME_ERROR;
8140 	}
8141 
8142 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
8143 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
8144 		0, wl_netlink_recv, NULL, THIS_MODULE);
8145 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
8146 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
8147 #else
8148 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
8149 #endif
8150 
8151 	if (nl_sk == NULL) {
8152 		ANDROID_ERROR(("nl_sk is not ready\n"));
8153 		return BCME_ERROR;
8154 	}
8155 
8156 	return BCME_OK;
8157 }
8158 
wl_netlink_deinit(void)8159 static void wl_netlink_deinit(void)
8160 {
8161 	if (nl_sk) {
8162 		netlink_kernel_release(nl_sk);
8163 		nl_sk = NULL;
8164 	}
8165 }
8166 
8167 s32
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)8168 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
8169 {
8170 	struct sk_buff *skb = NULL;
8171 	struct nlmsghdr *nlh = NULL;
8172 	int ret = -1;
8173 
8174 	if (nl_sk == NULL) {
8175 		ANDROID_ERROR(("nl_sk was not initialized\n"));
8176 		goto nlmsg_failure;
8177 	}
8178 
8179 	skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
8180 	if (skb == NULL) {
8181 		ANDROID_ERROR(("failed to allocate memory\n"));
8182 		goto nlmsg_failure;
8183 	}
8184 
8185 	nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
8186 	if (nlh == NULL) {
8187 		ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
8188 			skb_tailroom(skb), nlmsg_total_size(size)));
8189 		dev_kfree_skb(skb);
8190 		goto nlmsg_failure;
8191 	}
8192 
8193 	memcpy(nlmsg_data(nlh), data, size);
8194 	nlh->nlmsg_seq = seq;
8195 	nlh->nlmsg_type = type;
8196 
8197 	/* netlink_unicast() takes ownership of the skb and frees it itself. */
8198 	ret = netlink_unicast(nl_sk, skb, pid, 0);
8199 	ANDROID_INFO(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
8200 
8201 nlmsg_failure:
8202 	return ret;
8203 }
8204 #endif /* WL_RELMCAST */
8205 
8206 #ifdef WLAIBSS
wl_android_set_ibss_txfail_event(struct net_device * dev,char * command,int total_len)8207 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
8208 {
8209 	int err = 0;
8210 	int retry = 0;
8211 	int pid = 0;
8212 	aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
8213 	char smbuf[WLC_IOCTL_SMLEN];
8214 
8215 	if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
8216 		ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
8217 		return -1;
8218 	}
8219 
8220 	/* set pid, and if the event was happened, let's send a notification through netlink */
8221 	wl_cfg80211_set_txfail_pid(dev, pid);
8222 
8223 #ifdef WL_RELMCAST
8224 	/* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
8225 	wl_cfg80211_set_rmc_pid(dev, pid);
8226 #endif /* WL_RELMCAST */
8227 
8228 	/* If retry value is 0, it disables the functionality for TX Fail. */
8229 	if (retry > 0) {
8230 		txfail_config.max_tx_retry = retry;
8231 		txfail_config.bcn_timeout = 0;	/* 0 : disable tx fail from beacon */
8232 	}
8233 	txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
8234 	txfail_config.len = sizeof(txfail_config);
8235 
8236 	err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
8237 		sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
8238 	ANDROID_INFO(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
8239 
8240 	return ((err == 0)?total_len:err);
8241 }
8242 
wl_android_get_ibss_peer_info(struct net_device * dev,char * command,int total_len,bool bAll)8243 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
8244 	int total_len, bool bAll)
8245 {
8246 	int error;
8247 	int bytes_written = 0;
8248 	void *buf = NULL;
8249 	bss_peer_list_info_t peer_list_info;
8250 	bss_peer_info_t *peer_info;
8251 	int i;
8252 	bool found = false;
8253 	struct ether_addr mac_ea;
8254 	char *str = command;
8255 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8256 
8257 	ANDROID_INFO(("get ibss peer info(%s)\n", bAll?"true":"false"));
8258 
8259 	if (!bAll) {
8260 		if (bcmstrtok(&str, " ", NULL) == NULL) {
8261 			ANDROID_ERROR(("invalid command\n"));
8262 			return -1;
8263 		}
8264 
8265 		if (!str || !bcm_ether_atoe(str, &mac_ea)) {
8266 			ANDROID_ERROR(("invalid MAC address\n"));
8267 			return -1;
8268 		}
8269 	}
8270 
8271 	if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) {
8272 		ANDROID_ERROR(("kmalloc failed\n"));
8273 		return -1;
8274 	}
8275 
8276 	error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
8277 	if (unlikely(error)) {
8278 		ANDROID_ERROR(("could not get ibss peer info (%d)\n", error));
8279 		MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8280 		return -1;
8281 	}
8282 
8283 	memcpy(&peer_list_info, buf, sizeof(peer_list_info));
8284 	peer_list_info.version = htod16(peer_list_info.version);
8285 	peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
8286 	peer_list_info.count = htod32(peer_list_info.count);
8287 
8288 	ANDROID_INFO(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
8289 		peer_list_info.bss_peer_info_len, peer_list_info.count));
8290 
8291 	if (peer_list_info.count > 0) {
8292 		if (bAll)
8293 			bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
8294 				peer_list_info.count);
8295 
8296 		peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
8297 
8298 		for (i = 0; i < peer_list_info.count; i++) {
8299 
8300 			ANDROID_INFO(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
8301 				peer_info->tx_rate, peer_info->rx_rate));
8302 
8303 			if (!bAll &&
8304 				memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
8305 				found = true;
8306 			}
8307 
8308 			if (bAll || found) {
8309 				bytes_written += snprintf(&command[bytes_written],
8310 					total_len - bytes_written,
8311 					MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
8312 					peer_info->tx_rate/1000, peer_info->rssi);
8313 				if (bytes_written >= total_len) {
8314 					ANDROID_ERROR(("wl_android_get_ibss_peer_info: Insufficient"
8315 						" memory, %d bytes\n",
8316 						total_len));
8317 					bytes_written = -1;
8318 					break;
8319 				}
8320 			}
8321 
8322 			if (found)
8323 				break;
8324 
8325 			peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
8326 		}
8327 	}
8328 	else {
8329 		ANDROID_ERROR(("could not get ibss peer info : no item\n"));
8330 	}
8331 	ANDROID_INFO(("command(%u):%s\n", total_len, command));
8332 	ANDROID_INFO(("bytes_written:%d\n", bytes_written));
8333 
8334 	MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8335 	return bytes_written;
8336 }
8337 
wl_android_set_ibss_routetable(struct net_device * dev,char * command)8338 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
8339 {
8340 
8341 	char *pcmd = command;
8342 	char *str = NULL;
8343 	ibss_route_tbl_t *route_tbl = NULL;
8344 	char *ioctl_buf = NULL;
8345 	s32 err = BCME_OK;
8346 	uint32 route_tbl_len;
8347 	uint32 entries;
8348 	char *endptr;
8349 	uint32 i = 0;
8350 	struct ipv4_addr  dipaddr;
8351 	struct ether_addr ea;
8352 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8353 
8354 	route_tbl_len = sizeof(ibss_route_tbl_t) +
8355 		(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
8356 	route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
8357 	if (!route_tbl) {
8358 		ANDROID_ERROR(("Route TBL alloc failed\n"));
8359 		return -ENOMEM;
8360 	}
8361 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
8362 	if (!ioctl_buf) {
8363 		ANDROID_ERROR(("ioctl memory alloc failed\n"));
8364 		if (route_tbl) {
8365 			MFREE(cfg->osh, route_tbl, route_tbl_len);
8366 		}
8367 		return -ENOMEM;
8368 	}
8369 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);
8370 
8371 	/* drop command */
8372 	str = bcmstrtok(&pcmd, " ", NULL);
8373 
8374 	/* get count */
8375 	str = bcmstrtok(&pcmd, " ",  NULL);
8376 	if (!str) {
8377 		ANDROID_ERROR(("Invalid number parameter %s\n", str));
8378 		err = -EINVAL;
8379 		goto exit;
8380 	}
8381 	entries = bcm_strtoul(str, &endptr, 0);
8382 	if (*endptr != '\0') {
8383 		ANDROID_ERROR(("Invalid number parameter %s\n", str));
8384 		err = -EINVAL;
8385 		goto exit;
8386 	}
8387 	if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
8388 		ANDROID_ERROR(("Invalid entries number %u\n", entries));
8389 		err = -EINVAL;
8390 		goto exit;
8391 	}
8392 
8393 	ANDROID_INFO(("Routing table count:%u\n", entries));
8394 	route_tbl->num_entry = entries;
8395 
8396 	for (i = 0; i < entries; i++) {
8397 		str = bcmstrtok(&pcmd, " ", NULL);
8398 		if (!str || !bcm_atoipv4(str, &dipaddr)) {
8399 			ANDROID_ERROR(("Invalid ip string %s\n", str));
8400 			err = -EINVAL;
8401 			goto exit;
8402 		}
8403 
8404 		str = bcmstrtok(&pcmd, " ", NULL);
8405 		if (!str || !bcm_ether_atoe(str, &ea)) {
8406 			ANDROID_ERROR(("Invalid ethernet string %s\n", str));
8407 			err = -EINVAL;
8408 			goto exit;
8409 		}
8410 		bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
8411 		bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
8412 	}
8413 
8414 	route_tbl_len = sizeof(ibss_route_tbl_t) +
8415 		((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
8416 	err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
8417 		route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
8418 	if (err != BCME_OK) {
8419 		ANDROID_ERROR(("Fail to set iovar %d\n", err));
8420 		err = -EINVAL;
8421 	}
8422 
8423 exit:
8424 	if (route_tbl) {
8425 		MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
8426 			(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
8427 	}
8428 	if (ioctl_buf) {
8429 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
8430 	}
8431 	return err;
8432 
8433 }
8434 
8435 int
wl_android_set_ibss_ampdu(struct net_device * dev,char * command,int total_len)8436 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
8437 {
8438 	char *pcmd = command;
8439 	char *str = NULL, *endptr = NULL;
8440 	struct ampdu_aggr aggr;
8441 	char smbuf[WLC_IOCTL_SMLEN];
8442 	int idx;
8443 	int err = 0;
8444 	int wme_AC2PRIO[AC_COUNT][2] = {
8445 		{PRIO_8021D_VO, PRIO_8021D_NC},		/* AC_VO - 3 */
8446 		{PRIO_8021D_CL, PRIO_8021D_VI},		/* AC_VI - 2 */
8447 		{PRIO_8021D_BK, PRIO_8021D_NONE},	/* AC_BK - 1 */
8448 		{PRIO_8021D_BE, PRIO_8021D_EE}};	/* AC_BE - 0 */
8449 
8450 	ANDROID_INFO(("set ibss ampdu:%s\n", command));
8451 
8452 	bzero(&aggr, sizeof(aggr));
8453 	/* Cofigure all priorities */
8454 	aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
8455 
8456 	/* acquire parameters */
8457 	/* drop command */
8458 	str = bcmstrtok(&pcmd, " ", NULL);
8459 
8460 	for (idx = 0; idx < AC_COUNT; idx++) {
8461 		bool on;
8462 		str = bcmstrtok(&pcmd, " ", NULL);
8463 		if (!str) {
8464 			ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8465 			return -EINVAL;
8466 		}
8467 		on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
8468 		if (*endptr != '\0') {
8469 			ANDROID_ERROR(("Invalid number format %s\n", str));
8470 			return -EINVAL;
8471 		}
8472 		if (on) {
8473 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
8474 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
8475 		}
8476 	}
8477 
8478 	err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
8479 	sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
8480 
8481 	return ((err == 0) ? total_len : err);
8482 }
8483 
wl_android_set_ibss_antenna(struct net_device * dev,char * command,int total_len)8484 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
8485 {
8486 	char *pcmd = command;
8487 	char *str = NULL;
8488 	int txchain, rxchain;
8489 	int err = 0;
8490 
8491 	ANDROID_INFO(("set ibss antenna:%s\n", command));
8492 
8493 	/* acquire parameters */
8494 	/* drop command */
8495 	str = bcmstrtok(&pcmd, " ", NULL);
8496 
8497 	/* TX chain */
8498 	str = bcmstrtok(&pcmd, " ", NULL);
8499 	if (!str) {
8500 		ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8501 		return -EINVAL;
8502 	}
8503 	txchain = bcm_atoi(str);
8504 
8505 	/* RX chain */
8506 	str = bcmstrtok(&pcmd, " ", NULL);
8507 	if (!str) {
8508 		ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8509 		return -EINVAL;
8510 	}
8511 	rxchain = bcm_atoi(str);
8512 
8513 	err = wldev_iovar_setint(dev, "txchain", txchain);
8514 	if (err != 0)
8515 		return err;
8516 	err = wldev_iovar_setint(dev, "rxchain", rxchain);
8517 	return ((err == 0)?total_len:err);
8518 }
8519 #endif /* WLAIBSS */
8520 
wl_keep_alive_set(struct net_device * dev,char * extra)8521 int wl_keep_alive_set(struct net_device *dev, char* extra)
8522 {
8523 	wl_mkeep_alive_pkt_t	mkeep_alive_pkt;
8524 	int ret;
8525 	uint period_msec = 0;
8526 	char *buf;
8527 	dhd_pub_t *dhd = dhd_get_pub(dev);
8528 
8529 	if (extra == NULL) {
8530 		 ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
8531 		 return -1;
8532 	}
8533 	if (sscanf(extra, "%d", &period_msec) != 1) {
8534 		 ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
8535 		 return -EINVAL;
8536 	}
8537 	ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
8538 
8539 	bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
8540 
8541 	mkeep_alive_pkt.period_msec = period_msec;
8542 	mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
8543 	mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
8544 
8545 	/* Setup keep alive zero for null packet generation */
8546 	mkeep_alive_pkt.keep_alive_id = 0;
8547 	mkeep_alive_pkt.len_bytes = 0;
8548 
8549 	buf = (char *)MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
8550 	if (!buf) {
8551 		ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
8552 		return BCME_NOMEM;
8553 	}
8554 	ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
8555 			WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8556 	if (ret < 0)
8557 		ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
8558 	else
8559 		ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
8560 	MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
8561 	return ret;
8562 }
8563 
8564 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)8565 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
8566 {
8567 	int error = 0;
8568 	int bytes_written = 0;
8569 	int only_resp_wfdsrc = 0;
8570 
8571 	error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
8572 	if (error) {
8573 		ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
8574 			__FUNCTION__, error));
8575 		return -1;
8576 	}
8577 
8578 	bytes_written = snprintf(command, total_len, "%s %d",
8579 		CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
8580 
8581 	return bytes_written;
8582 }
8583 
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)8584 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
8585 {
8586 	int error = 0;
8587 
8588 	error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
8589 	if (error) {
8590 		ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
8591 			__FUNCTION__, only_resp_wfdsrc, error));
8592 		return -1;
8593 	}
8594 
8595 	return 0;
8596 }
8597 #endif /* P2PRESP_WFDIE_SRC */
8598 
8599 #ifdef BT_WIFI_HANDOVER
8600 static int
wl_tbow_teardown(struct net_device * dev)8601 wl_tbow_teardown(struct net_device *dev)
8602 {
8603 	int err = BCME_OK;
8604 	char buf[WLC_IOCTL_SMLEN];
8605 	tbow_setup_netinfo_t netinfo;
8606 	bzero(&netinfo, sizeof(netinfo));
8607 	netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
8608 
8609 	err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
8610 			sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
8611 	if (err < 0) {
8612 		ANDROID_ERROR(("tbow_doho iovar error %d\n", err));
8613 		return err;
8614 	}
8615 	return err;
8616 }
8617 #endif /* BT_WIFI_HANOVER */
8618 
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)8619 static int wl_android_get_link_status(struct net_device *dev, char *command,
8620 	int total_len)
8621 {
8622 	int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
8623 	uint32 rspec;
8624 	uint encode, txexp;
8625 	wl_bss_info_t *bi;
8626 	int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
8627 	char buf[WLC_IOCTL_SMLEN];
8628 
8629 	if (datalen > WLC_IOCTL_SMLEN) {
8630 		ANDROID_ERROR(("data too big\n"));
8631 		return -1;
8632 	}
8633 
8634 	bzero(buf, datalen);
8635 	/* get BSS information */
8636 	*(u32 *) buf = htod32(datalen);
8637 	error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
8638 	if (unlikely(error)) {
8639 		ANDROID_ERROR(("Could not get bss info %d\n", error));
8640 		return -1;
8641 	}
8642 
8643 	bi = (wl_bss_info_t*) (buf + sizeof(uint32));
8644 
8645 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
8646 		if (bi->BSSID.octet[i] > 0) {
8647 			break;
8648 		}
8649 	}
8650 
8651 	if (i == ETHER_ADDR_LEN) {
8652 		ANDROID_INFO(("No BSSID\n"));
8653 		return -1;
8654 	}
8655 
8656 	/* check VHT capability at beacon */
8657 	if (bi->vht_cap) {
8658 		if (CHSPEC_IS5G(bi->chanspec)) {
8659 			result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
8660 		}
8661 	}
8662 
8663 	/* get a rspec (radio spectrum) rate */
8664 	error = wldev_iovar_getint(dev, "nrate", &rspec);
8665 	if (unlikely(error) || rspec == 0) {
8666 		ANDROID_ERROR(("get link status error (%d)\n", error));
8667 		return -1;
8668 	}
8669 
8670 	/* referred wl_nrate_print() for the calculation */
8671 	encode = (rspec & WL_RSPEC_ENCODING_MASK);
8672 	txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
8673 
8674 	switch (encode) {
8675 	case WL_RSPEC_ENCODE_HT:
8676 		/* check Rx MCS Map for HT */
8677 		for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
8678 			int8 bitmap = 0xFF;
8679 			if (i == MAX_STREAMS_SUPPORTED-1) {
8680 				bitmap = 0x7F;
8681 			}
8682 			if (bi->basic_mcs[i] & bitmap) {
8683 				nss++;
8684 			}
8685 		}
8686 		break;
8687 	case WL_RSPEC_ENCODE_VHT:
8688 		/* check Rx MCS Map for VHT */
8689 		for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
8690 			mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
8691 			if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
8692 				nss++;
8693 			}
8694 		}
8695 		break;
8696 	}
8697 
8698 	/* check MIMO capability with nss in beacon */
8699 	if (nss > 1) {
8700 		result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
8701 	}
8702 
8703 	/* Legacy rates WL_RSPEC_ENCODE_RATE are single stream, and
8704 	 * HT rates for mcs 0-7 are single stream.
8705 	 * In case of VHT NSS comes from rspec.
8706 	 */
8707 	single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
8708 		((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
8709 		((encode == WL_RSPEC_ENCODE_VHT) &&
8710 		((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
8711 
8712 	if (txexp == 0) {
8713 		if ((rspec & WL_RSPEC_STBC) && single_stream) {
8714 			stf = OLD_NRATE_STF_STBC;
8715 		} else {
8716 			stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
8717 		}
8718 	} else if (txexp == 1 && single_stream) {
8719 		stf = OLD_NRATE_STF_CDD;
8720 	}
8721 
8722 	/* check 11ac (VHT) */
8723 	if (encode == WL_RSPEC_ENCODE_VHT) {
8724 		if (CHSPEC_IS5G(bi->chanspec)) {
8725 			result |= WL_ANDROID_LINK_VHT;
8726 		}
8727 	}
8728 
8729 	/* check MIMO */
8730 	if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
8731 		switch (stf) {
8732 		case OLD_NRATE_STF_SISO:
8733 			break;
8734 		case OLD_NRATE_STF_CDD:
8735 		case OLD_NRATE_STF_STBC:
8736 			result |= WL_ANDROID_LINK_MIMO;
8737 			break;
8738 		case OLD_NRATE_STF_SDM:
8739 			if (!single_stream) {
8740 				result |= WL_ANDROID_LINK_MIMO;
8741 			}
8742 			break;
8743 		}
8744 	}
8745 
8746 	ANDROID_INFO(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
8747 		__FUNCTION__, result, stf, single_stream, nss));
8748 
8749 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
8750 
8751 	return bytes_written;
8752 }
8753 
8754 #ifdef P2P_LISTEN_OFFLOADING
8755 
8756 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 * cfg)8757 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
8758 {
8759 	s32 bssidx;
8760 	int ret = 0;
8761 	int p2plo_pause = 0;
8762 	dhd_pub_t *dhd = NULL;
8763 	if (!cfg || !cfg->p2p) {
8764 		ANDROID_ERROR(("Wl %p or cfg->p2p %p is null\n",
8765 			cfg, cfg ? cfg->p2p : 0));
8766 		return 0;
8767 	}
8768 
8769 	dhd =  (dhd_pub_t *)(cfg->pub);
8770 	if (!dhd->up) {
8771 		ANDROID_ERROR(("bus is already down\n"));
8772 		return ret;
8773 	}
8774 
8775 	bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8776 	ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
8777 			"p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
8778 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
8779 	if (ret < 0) {
8780 		ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8781 	}
8782 
8783 	return  ret;
8784 }
8785 s32
wl_cfg80211_p2plo_listen_start(struct net_device * dev,u8 * buf,int len)8786 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
8787 {
8788 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8789 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8790 	wl_p2plo_listen_t p2plo_listen;
8791 	int ret = -EAGAIN;
8792 	int channel = 0;
8793 	int period = 0;
8794 	int interval = 0;
8795 	int count = 0;
8796 	if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
8797 		ANDROID_ERROR(("Sending Action Frames. Try it again.\n"));
8798 		goto exit;
8799 	}
8800 
8801 	if (wl_get_drv_status_all(cfg, SCANNING)) {
8802 		ANDROID_ERROR(("Scanning already\n"));
8803 		goto exit;
8804 	}
8805 
8806 	if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
8807 		ANDROID_ERROR(("Scanning being aborted\n"));
8808 		goto exit;
8809 	}
8810 
8811 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8812 		ANDROID_ERROR(("p2p listen offloading already running\n"));
8813 		goto exit;
8814 	}
8815 
8816 	/* Just in case if it is not enabled */
8817 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
8818 		ANDROID_ERROR(("cfgp2p_enable discovery failed"));
8819 		goto exit;
8820 	}
8821 
8822 	bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
8823 
8824 	if (len) {
8825 		sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
8826 		if ((channel == 0) || (period == 0) ||
8827 				(interval == 0) || (count == 0)) {
8828 			ANDROID_ERROR(("Wrong argument %d/%d/%d/%d \n",
8829 				channel, period, interval, count));
8830 			ret = -EAGAIN;
8831 			goto exit;
8832 		}
8833 		p2plo_listen.period = period;
8834 		p2plo_listen.interval = interval;
8835 		p2plo_listen.count = count;
8836 
8837 		ANDROID_ERROR(("channel:%d period:%d, interval:%d count:%d\n",
8838 			channel, period, interval, count));
8839 	} else {
8840 		ANDROID_ERROR(("Argument len is wrong.\n"));
8841 		ret = -EAGAIN;
8842 		goto exit;
8843 	}
8844 
8845 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
8846 			sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8847 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8848 		ANDROID_ERROR(("p2po_listen_channel Failed :%d\n", ret));
8849 		goto exit;
8850 	}
8851 
8852 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
8853 			sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8854 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8855 		ANDROID_ERROR(("p2po_listen Failed :%d\n", ret));
8856 		goto exit;
8857 	}
8858 
8859 	wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
8860 exit :
8861 	return ret;
8862 }
8863 s32
wl_cfg80211_p2plo_listen_stop(struct net_device * dev)8864 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
8865 {
8866 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8867 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8868 	int ret = -EAGAIN;
8869 
8870 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
8871 			0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8872 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
8873 		ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8874 		goto exit;
8875 	}
8876 
8877 exit:
8878 	return ret;
8879 }
8880 
8881 s32
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)8882 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
8883 {
8884 	int ret = 0;
8885 
8886 	ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len));
8887 
8888 	if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
8889 		ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
8890 	} else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
8891 		ret = wl_cfg80211_p2plo_listen_stop(dev);
8892 	} else {
8893 		ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf));
8894 		ret = -EINVAL;
8895 	}
8896 	return ret;
8897 }
8898 void
wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 * cfg)8899 wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
8900 {
8901 	struct wireless_dev *wdev;
8902 	if (!cfg) {
8903 		return;
8904 	}
8905 
8906 	wdev = bcmcfg_to_p2p_wdev(cfg);
8907 
8908 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8909 		ANDROID_INFO(("P2P_FIND: Discovery offload is already in progress."
8910 					"it aborted\n"));
8911 		wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
8912 		if (wdev != NULL) {
8913 #if defined(WL_CFG80211_P2P_DEV_IF)
8914 			cfg80211_remain_on_channel_expired(wdev,
8915 					cfg->last_roc_id,
8916 					&cfg->remain_on_chan, GFP_KERNEL);
8917 #else
8918 			cfg80211_remain_on_channel_expired(wdev,
8919 					cfg->last_roc_id,
8920 					&cfg->remain_on_chan,
8921 					cfg->remain_on_chan_type, GFP_KERNEL);
8922 #endif /* WL_CFG80211_P2P_DEV_IF */
8923 		}
8924 		wl_cfg80211_p2plo_deinit(cfg);
8925 	}
8926 }
8927 #endif /* P2P_LISTEN_OFFLOADING */
8928 
8929 #ifdef WL_MURX
8930 int
wl_android_murx_bfe_cap(struct net_device * dev,int val)8931 wl_android_murx_bfe_cap(struct net_device *dev, int val)
8932 {
8933 	int err = BCME_OK;
8934 	int iface_count = wl_cfg80211_iface_count(dev);
8935 	struct ether_addr bssid;
8936 	wl_reassoc_params_t params;
8937 
8938 	if (iface_count > 1) {
8939 		ANDROID_ERROR(("murx_bfe_cap change is not allowed when "
8940 				"there are multiple interfaces\n"));
8941 		return -EINVAL;
8942 	}
8943 	/* Now there is only single interface */
8944 	err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
8945 	if (unlikely(err)) {
8946 		ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d,"
8947 				"error %d\n", val, err));
8948 		return err;
8949 	}
8950 
8951 	/* If successful intiate a reassoc */
8952 	bzero(&bssid, ETHER_ADDR_LEN);
8953 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
8954 		ANDROID_ERROR(("Failed to get bssid, error=%d\n", err));
8955 		return err;
8956 	}
8957 
8958 	bzero(&params, sizeof(wl_reassoc_params_t));
8959 	memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
8960 
8961 	if ((err = wldev_ioctl_set(dev, WLC_REASSOC, &params,
8962 		sizeof(wl_reassoc_params_t))) < 0) {
8963 		ANDROID_ERROR(("reassoc failed err:%d \n", err));
8964 	} else {
8965 		ANDROID_INFO(("reassoc issued successfully\n"));
8966 	}
8967 
8968 	return err;
8969 }
8970 #endif /* WL_MURX */
8971 
8972 #ifdef SUPPORT_RSSI_SUM_REPORT
8973 int
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)8974 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
8975 {
8976 	wl_rssi_ant_mimo_t rssi_ant_mimo;
8977 	char *ifname = NULL;
8978 	char *peer_mac = NULL;
8979 	char *mimo_cmd = "mimo";
8980 	char *pos, *token;
8981 	int err = BCME_OK;
8982 	int bytes_written = 0;
8983 	bool mimo_rssi = FALSE;
8984 
8985 	bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
8986 	/*
8987 	 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
8988 	 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
8989 	 */
8990 	pos = command;
8991 
8992 	/* drop command */
8993 	token = bcmstrtok(&pos, " ", NULL);
8994 
8995 	/* get the interface name */
8996 	token = bcmstrtok(&pos, " ", NULL);
8997 	if (!token) {
8998 		ANDROID_ERROR(("Invalid arguments\n"));
8999 		return -EINVAL;
9000 	}
9001 	ifname = token;
9002 
9003 	/* Optional: Check the MIMO RSSI mode or peer MAC address */
9004 	token = bcmstrtok(&pos, " ", NULL);
9005 	if (token) {
9006 		/* Check the MIMO RSSI mode */
9007 		if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9008 			mimo_rssi = TRUE;
9009 		} else {
9010 			peer_mac = token;
9011 		}
9012 	}
9013 
9014 	/* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
9015 	token = bcmstrtok(&pos, " ", NULL);
9016 	if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9017 		mimo_rssi = TRUE;
9018 	}
9019 
9020 	err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
9021 	if (unlikely(err)) {
9022 		ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err));
9023 		return err;
9024 	}
9025 
9026 	/* Parse the results */
9027 	ANDROID_INFO(("ifname %s, version %d, count %d, mimo rssi %d\n",
9028 		ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
9029 	if (mimo_rssi) {
9030 		ANDROID_INFO(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
9031 		bytes_written = snprintf(command, total_len, "%s MIMO %d",
9032 			CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
9033 	} else {
9034 		int cnt;
9035 		bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
9036 		for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
9037 			ANDROID_INFO(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
9038 			bytes_written = snprintf(command, total_len, "%d ",
9039 				rssi_ant_mimo.rssi_ant[cnt]);
9040 		}
9041 	}
9042 
9043 	return bytes_written;
9044 }
9045 
9046 int
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)9047 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
9048 {
9049 	rssilog_set_param_t set_param;
9050 	char *pos, *token;
9051 	int err = BCME_OK;
9052 
9053 	bzero(&set_param, sizeof(rssilog_set_param_t));
9054 	/*
9055 	 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
9056 	 */
9057 	pos = command;
9058 
9059 	/* drop command */
9060 	token = bcmstrtok(&pos, " ", NULL);
9061 
9062 	/* enable/disable */
9063 	token = bcmstrtok(&pos, " ", NULL);
9064 	if (!token) {
9065 		ANDROID_ERROR(("Invalid arguments\n"));
9066 		return -EINVAL;
9067 	}
9068 	set_param.enable = bcm_atoi(token);
9069 
9070 	/* RSSI Threshold */
9071 	token = bcmstrtok(&pos, " ", NULL);
9072 	if (!token) {
9073 		ANDROID_ERROR(("Invalid arguments\n"));
9074 		return -EINVAL;
9075 	}
9076 	set_param.rssi_threshold = bcm_atoi(token);
9077 
9078 	/* Time Threshold */
9079 	token = bcmstrtok(&pos, " ", NULL);
9080 	if (!token) {
9081 		ANDROID_ERROR(("Invalid arguments\n"));
9082 		return -EINVAL;
9083 	}
9084 	set_param.time_threshold = bcm_atoi(token);
9085 
9086 	ANDROID_INFO(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
9087 		set_param.rssi_threshold, set_param.time_threshold));
9088 
9089 	err = wl_set_rssi_logging(dev, (void *)&set_param);
9090 	if (unlikely(err)) {
9091 		ANDROID_ERROR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
9092 			" Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
9093 			set_param.time_threshold));
9094 	}
9095 
9096 	return err;
9097 }
9098 
9099 int
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)9100 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
9101 {
9102 	rssilog_get_param_t get_param;
9103 	int err = BCME_OK;
9104 	int bytes_written = 0;
9105 
9106 	err = wl_get_rssi_logging(dev, (void *)&get_param);
9107 	if (unlikely(err)) {
9108 		ANDROID_ERROR(("Failed to get RSSI logging info\n"));
9109 		return BCME_ERROR;
9110 	}
9111 
9112 	ANDROID_INFO(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
9113 		get_param.report_count, get_param.enable, get_param.rssi_threshold,
9114 		get_param.time_threshold));
9115 
9116 	/* Parse the parameter */
9117 	if (!get_param.enable) {
9118 		ANDROID_INFO(("RSSI LOGGING: Feature is disables\n"));
9119 		bytes_written = snprintf(command, total_len,
9120 			"%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
9121 	} else if (get_param.enable &
9122 		(RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
9123 		if (!get_param.report_count) {
9124 			ANDROID_INFO(("[PASS] RSSI difference across antennas is within"
9125 				" threshold limits\n"));
9126 			bytes_written = snprintf(command, total_len, "%s PASS\n",
9127 				CMD_GET_RSSI_LOGGING);
9128 		} else {
9129 			ANDROID_INFO(("[FAIL] RSSI difference across antennas found "
9130 				"to be greater than %3d dB\n", get_param.rssi_threshold));
9131 			ANDROID_INFO(("[FAIL] RSSI difference check have failed for "
9132 				"%d out of %d times\n", get_param.report_count,
9133 				get_param.time_threshold));
9134 			ANDROID_INFO(("[FAIL] RSSI difference is being monitored once "
9135 				"per second, for a %d secs window\n", get_param.time_threshold));
9136 			bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
9137 				"%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
9138 				get_param.rssi_threshold, get_param.report_count,
9139 				get_param.time_threshold);
9140 		}
9141 	} else {
9142 		ANDROID_INFO(("[BUSY] Reprot is not ready\n"));
9143 		bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
9144 			CMD_GET_RSSI_LOGGING);
9145 	}
9146 
9147 	return bytes_written;
9148 }
9149 #endif /* SUPPORT_RSSI_SUM_REPORT */
9150 
9151 #ifdef SET_PCIE_IRQ_CPU_CORE
9152 void
wl_android_set_irq_cpucore(struct net_device * net,int affinity_cmd)9153 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
9154 {
9155 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9156 	if (!dhdp) {
9157 		ANDROID_ERROR(("dhd is NULL\n"));
9158 		return;
9159 	}
9160 
9161 	dhd_set_irq_cpucore(dhdp, affinity_cmd);
9162 }
9163 #endif /* SET_PCIE_IRQ_CPU_CORE */
9164 
9165 #ifdef SUPPORT_LQCM
9166 static int
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)9167 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
9168 {
9169 	int err = 0;
9170 
9171 	err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
9172 	if (err != BCME_OK) {
9173 		ANDROID_ERROR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
9174 		return -EIO;
9175 	}
9176 	return err;
9177 }
9178 
9179 static int
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)9180 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
9181 {
9182 	int bytes_written, err = 0;
9183 	uint32 lqcm_report = 0;
9184 	uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
9185 
9186 	err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
9187 	if (err != BCME_OK) {
9188 		ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err));
9189 		return -EIO;
9190 	}
9191 	lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
9192 	tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
9193 	rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
9194 
9195 	ANDROID_INFO(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
9196 
9197 	bytes_written = snprintf(command, total_len, "%s %d",
9198 			CMD_GET_LQCM_REPORT, lqcm_report);
9199 
9200 	return bytes_written;
9201 }
9202 #endif /* SUPPORT_LQCM */
9203 
9204 int
wl_android_get_snr(struct net_device * dev,char * command,int total_len)9205 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
9206 {
9207 	int bytes_written, error = 0;
9208 	s32 snr = 0;
9209 
9210 	error = wldev_iovar_getint(dev, "snr", &snr);
9211 	if (error) {
9212 		ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n",
9213 			__FUNCTION__, snr, error));
9214 		return -EIO;
9215 	}
9216 
9217 	bytes_written = snprintf(command, total_len, "snr %d", snr);
9218 	ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
9219 	return bytes_written;
9220 }
9221 
9222 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
9223 int
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)9224 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
9225 {
9226 	int rate = 0;
9227 	char *pos, *token;
9228 	char *ifname = NULL;
9229 	int err = BCME_OK;
9230 
9231 	/*
9232 	 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
9233 	 */
9234 	pos = command;
9235 
9236 	/* drop command */
9237 	token = bcmstrtok(&pos, " ", NULL);
9238 
9239 	/* Rate */
9240 	token = bcmstrtok(&pos, " ", NULL);
9241 	if (!token)
9242 		return -EINVAL;
9243 	rate = bcm_atoi(token);
9244 
9245 	/* get the interface name */
9246 	token = bcmstrtok(&pos, " ", NULL);
9247 	if (!token)
9248 		return -EINVAL;
9249 	ifname = token;
9250 
9251 	ANDROID_INFO(("rate %d, ifacename %s\n", rate, ifname));
9252 
9253 	err = wl_set_ap_beacon_rate(dev, rate, ifname);
9254 	if (unlikely(err)) {
9255 		ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
9256 	}
9257 
9258 	return err;
9259 }
9260 
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)9261 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
9262 {
9263 	char *pos, *token;
9264 	char *ifname = NULL;
9265 	int bytes_written = 0;
9266 	/*
9267 	 * DRIVER GET_AP_BASICRATE <ifname>
9268 	 */
9269 	pos = command;
9270 
9271 	/* drop command */
9272 	token = bcmstrtok(&pos, " ", NULL);
9273 
9274 	/* get the interface name */
9275 	token = bcmstrtok(&pos, " ", NULL);
9276 	if (!token)
9277 		return -EINVAL;
9278 	ifname = token;
9279 
9280 	ANDROID_INFO(("ifacename %s\n", ifname));
9281 
9282 	bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
9283 	if (bytes_written < 1) {
9284 		ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written));
9285 		return -EPROTO;
9286 	}
9287 
9288 	return bytes_written;
9289 }
9290 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
9291 
9292 #ifdef SUPPORT_AP_RADIO_PWRSAVE
9293 int
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)9294 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
9295 {
9296 	char *pos, *token;
9297 	char *ifname = NULL;
9298 	int bytes_written = 0;
9299 	char name[IFNAMSIZ];
9300 	/*
9301 	 * DRIVER GET_AP_RPS <ifname>
9302 	 */
9303 	pos = command;
9304 
9305 	/* drop command */
9306 	token = bcmstrtok(&pos, " ", NULL);
9307 
9308 	/* get the interface name */
9309 	token = bcmstrtok(&pos, " ", NULL);
9310 	if (!token)
9311 		return -EINVAL;
9312 	ifname = token;
9313 
9314 	strlcpy(name, ifname, sizeof(name));
9315 	ANDROID_INFO(("ifacename %s\n", name));
9316 
9317 	bytes_written = wl_get_ap_rps(dev, command, name, total_len);
9318 	if (bytes_written < 1) {
9319 		ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written));
9320 		return -EPROTO;
9321 	}
9322 
9323 	return bytes_written;
9324 
9325 }
9326 
9327 int
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)9328 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
9329 {
9330 	int enable = 0;
9331 	char *pos, *token;
9332 	char *ifname = NULL;
9333 	int err = BCME_OK;
9334 	char name[IFNAMSIZ];
9335 
9336 	/*
9337 	 * DRIVER SET_AP_RPS <0/1> <ifname>
9338 	 */
9339 	pos = command;
9340 
9341 	/* drop command */
9342 	token = bcmstrtok(&pos, " ", NULL);
9343 
9344 	/* Enable */
9345 	token = bcmstrtok(&pos, " ", NULL);
9346 	if (!token)
9347 		return -EINVAL;
9348 	enable = bcm_atoi(token);
9349 
9350 	/* get the interface name */
9351 	token = bcmstrtok(&pos, " ", NULL);
9352 	if (!token)
9353 		return -EINVAL;
9354 	ifname = token;
9355 
9356 	strlcpy(name, ifname, sizeof(name));
9357 	ANDROID_INFO(("enable %d, ifacename %s\n", enable, name));
9358 
9359 	err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
9360 	if (unlikely(err)) {
9361 		ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err));
9362 	}
9363 
9364 	return err;
9365 }
9366 
9367 int
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)9368 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
9369 {
9370 	ap_rps_info_t rps;
9371 	char *pos, *token;
9372 	char *ifname = NULL;
9373 	int err = BCME_OK;
9374 	char name[IFNAMSIZ];
9375 
9376 	bzero(&rps, sizeof(rps));
9377 	/*
9378 	 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
9379 	 */
9380 	pos = command;
9381 
9382 	/* drop command */
9383 	token = bcmstrtok(&pos, " ", NULL);
9384 
9385 	/* pps */
9386 	token = bcmstrtok(&pos, " ", NULL);
9387 	if (!token)
9388 		return -EINVAL;
9389 	rps.pps = bcm_atoi(token);
9390 
9391 	/* level */
9392 	token = bcmstrtok(&pos, " ", NULL);
9393 	if (!token)
9394 		return -EINVAL;
9395 	rps.level = bcm_atoi(token);
9396 
9397 	/* quiettime */
9398 	token = bcmstrtok(&pos, " ", NULL);
9399 	if (!token)
9400 		return -EINVAL;
9401 	rps.quiet_time = bcm_atoi(token);
9402 
9403 	/* sta assoc check */
9404 	token = bcmstrtok(&pos, " ", NULL);
9405 	if (!token)
9406 		return -EINVAL;
9407 	rps.sta_assoc_check = bcm_atoi(token);
9408 
9409 	/* get the interface name */
9410 	token = bcmstrtok(&pos, " ", NULL);
9411 	if (!token)
9412 		return -EINVAL;
9413 	ifname = token;
9414 	strlcpy(name, ifname, sizeof(name));
9415 
9416 	ANDROID_INFO(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
9417 		"ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
9418 		rps.sta_assoc_check, name));
9419 
9420 	err = wl_update_ap_rps_params(dev, &rps, name);
9421 	if (unlikely(err)) {
9422 		ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, "
9423 			"sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
9424 			rps.sta_assoc_check, err));
9425 	}
9426 
9427 	return err;
9428 }
9429 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
9430 
9431 #if defined(DHD_HANG_SEND_UP_TEST)
9432 void
wl_android_make_hang_with_reason(struct net_device * dev,const char * string_num)9433 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
9434 {
9435 	dhd_make_hang_with_reason(dev, string_num);
9436 }
9437 #endif /* DHD_HANG_SEND_UP_TEST */
9438 
9439 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
9440 static void
wl_android_check_priv_cmd_errors(struct net_device * dev)9441 wl_android_check_priv_cmd_errors(struct net_device *dev)
9442 {
9443 	dhd_pub_t *dhdp;
9444 	int memdump_mode;
9445 
9446 	if (!dev) {
9447 		ANDROID_ERROR(("dev is NULL\n"));
9448 		return;
9449 	}
9450 
9451 	dhdp = wl_cfg80211_get_dhdp(dev);
9452 	if (!dhdp) {
9453 		ANDROID_ERROR(("dhdp is NULL\n"));
9454 		return;
9455 	}
9456 
9457 #ifdef DHD_FW_COREDUMP
9458 	memdump_mode = dhdp->memdump_enabled;
9459 #else
9460 	/* Default enable if DHD doesn't support SOCRAM dump */
9461 	memdump_mode = 1;
9462 #endif /* DHD_FW_COREDUMP */
9463 
9464 	if (report_hang_privcmd_err) {
9465 		priv_cmd_errors++;
9466 	} else {
9467 		priv_cmd_errors = 0;
9468 	}
9469 
9470 	/* Trigger HANG event only if memdump mode is enabled
9471 	 * due to customer's request
9472 	 */
9473 	if (memdump_mode == DUMP_MEMFILE_BUGON &&
9474 		(priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
9475 		ANDROID_ERROR(("Send HANG event due to sequential private cmd errors\n"));
9476 		priv_cmd_errors = 0;
9477 #ifdef DHD_FW_COREDUMP
9478 		/* Take a SOCRAM dump */
9479 		dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
9480 		dhd_common_socram_dump(dhdp);
9481 #endif /* DHD_FW_COREDUMP */
9482 		/* Send the HANG event to upper layer */
9483 		dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
9484 		dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
9485 	}
9486 }
9487 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
9488 
9489 #ifdef DHD_PKT_LOGGING
9490 static int
wl_android_pktlog_filter_enable(struct net_device * dev,char * command,int total_len)9491 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
9492 {
9493 	int bytes_written = 0;
9494 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9495 	dhd_pktlog_filter_t *filter;
9496 	int err = BCME_OK;
9497 
9498 	if (!dhdp || !dhdp->pktlog) {
9499 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9500 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9501 		return -EINVAL;
9502 	}
9503 
9504 	filter = dhdp->pktlog->pktlog_filter;
9505 
9506 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
9507 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
9508 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
9509 
9510 	if (err == BCME_OK) {
9511 		bytes_written = snprintf(command, total_len, "OK");
9512 		ANDROID_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
9513 	} else {
9514 		ANDROID_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
9515 		return BCME_ERROR;
9516 	}
9517 
9518 	return bytes_written;
9519 }
9520 
9521 static int
wl_android_pktlog_filter_disable(struct net_device * dev,char * command,int total_len)9522 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
9523 {
9524 	int bytes_written = 0;
9525 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9526 	dhd_pktlog_filter_t *filter;
9527 	int err = BCME_OK;
9528 
9529 	if (!dhdp || !dhdp->pktlog) {
9530 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9531 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9532 		return -EINVAL;
9533 	}
9534 
9535 	filter = dhdp->pktlog->pktlog_filter;
9536 
9537 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
9538 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
9539 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
9540 
9541 	if (err == BCME_OK) {
9542 		bytes_written = snprintf(command, total_len, "OK");
9543 		ANDROID_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
9544 	} else {
9545 		ANDROID_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
9546 		return BCME_ERROR;
9547 	}
9548 
9549 	return bytes_written;
9550 }
9551 
9552 static int
wl_android_pktlog_filter_pattern_enable(struct net_device * dev,char * command,int total_len)9553 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
9554 {
9555 	int bytes_written = 0;
9556 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9557 	dhd_pktlog_filter_t *filter;
9558 	int err = BCME_OK;
9559 
9560 	if (!dhdp || !dhdp->pktlog) {
9561 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9562 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9563 		return -EINVAL;
9564 	}
9565 
9566 	filter = dhdp->pktlog->pktlog_filter;
9567 
9568 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
9569 		return BCME_ERROR;
9570 	}
9571 
9572 	err = dhd_pktlog_filter_pattern_enable(filter,
9573 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
9574 
9575 	if (err == BCME_OK) {
9576 		bytes_written = snprintf(command, total_len, "OK");
9577 		ANDROID_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
9578 	} else {
9579 		ANDROID_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
9580 		return BCME_ERROR;
9581 	}
9582 
9583 	return bytes_written;
9584 }
9585 
9586 static int
wl_android_pktlog_filter_pattern_disable(struct net_device * dev,char * command,int total_len)9587 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
9588 {
9589 	int bytes_written = 0;
9590 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9591 	dhd_pktlog_filter_t *filter;
9592 	int err = BCME_OK;
9593 
9594 	if (!dhdp || !dhdp->pktlog) {
9595 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9596 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9597 		return -EINVAL;
9598 	}
9599 
9600 	filter = dhdp->pktlog->pktlog_filter;
9601 
9602 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
9603 		return BCME_ERROR;
9604 	}
9605 
9606 	err = dhd_pktlog_filter_pattern_enable(filter,
9607 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
9608 
9609 	if (err == BCME_OK) {
9610 		bytes_written = snprintf(command, total_len, "OK");
9611 		ANDROID_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
9612 	} else {
9613 		ANDROID_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
9614 		return BCME_ERROR;
9615 	}
9616 
9617 	return bytes_written;
9618 }
9619 
9620 static int
wl_android_pktlog_filter_add(struct net_device * dev,char * command,int total_len)9621 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
9622 {
9623 	int bytes_written = 0;
9624 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9625 	dhd_pktlog_filter_t *filter;
9626 	int err = BCME_OK;
9627 
9628 	if (!dhdp || !dhdp->pktlog) {
9629 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9630 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9631 		return -EINVAL;
9632 	}
9633 
9634 	filter = dhdp->pktlog->pktlog_filter;
9635 
9636 	if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
9637 		return BCME_ERROR;
9638 	}
9639 
9640 	err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
9641 
9642 	if (err == BCME_OK) {
9643 		bytes_written = snprintf(command, total_len, "OK");
9644 		ANDROID_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
9645 	} else {
9646 		ANDROID_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
9647 		return BCME_ERROR;
9648 	}
9649 
9650 	return bytes_written;
9651 }
9652 
9653 static int
wl_android_pktlog_filter_del(struct net_device * dev,char * command,int total_len)9654 wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_len)
9655 {
9656 	int bytes_written = 0;
9657 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9658 	dhd_pktlog_filter_t *filter;
9659 	int err = BCME_OK;
9660 
9661 	if (!dhdp || !dhdp->pktlog) {
9662 		ANDROID_ERROR(("%s(): dhdp=%p pktlog=%p\n",
9663 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9664 		return -EINVAL;
9665 	}
9666 
9667 	filter = dhdp->pktlog->pktlog_filter;
9668 
9669 	if (strlen(CMD_PKTLOG_FILTER_DEL) + 1 > total_len) {
9670 		DHD_PKT_LOG(("%s(): wrong cmd length %d found\n",
9671 			__FUNCTION__, (int)strlen(CMD_PKTLOG_FILTER_DEL)));
9672 		return BCME_ERROR;
9673 	}
9674 
9675 	err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1);
9676 	if (err == BCME_OK) {
9677 		bytes_written = snprintf(command, total_len, "OK");
9678 		ANDROID_ERROR(("%s: pktlog filter del success\n", __FUNCTION__));
9679 	} else {
9680 		ANDROID_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__));
9681 		return BCME_ERROR;
9682 	}
9683 
9684 	return bytes_written;
9685 }
9686 
9687 static int
wl_android_pktlog_filter_info(struct net_device * dev,char * command,int total_len)9688 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
9689 {
9690 	int bytes_written = 0;
9691 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9692 	dhd_pktlog_filter_t *filter;
9693 	int err = BCME_OK;
9694 
9695 	if (!dhdp || !dhdp->pktlog) {
9696 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9697 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9698 		return -EINVAL;
9699 	}
9700 
9701 	filter = dhdp->pktlog->pktlog_filter;
9702 
9703 	err = dhd_pktlog_filter_info(filter);
9704 
9705 	if (err == BCME_OK) {
9706 		bytes_written = snprintf(command, total_len, "OK");
9707 		ANDROID_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
9708 	} else {
9709 		ANDROID_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
9710 		return BCME_ERROR;
9711 	}
9712 
9713 	return bytes_written;
9714 }
9715 
9716 static int
wl_android_pktlog_start(struct net_device * dev,char * command,int total_len)9717 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
9718 {
9719 	int bytes_written = 0;
9720 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9721 
9722 	if (!dhdp || !dhdp->pktlog) {
9723 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9724 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9725 		return -EINVAL;
9726 	}
9727 
9728 	if (!dhdp->pktlog->pktlog_ring) {
9729 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9730 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9731 		return -EINVAL;
9732 	}
9733 
9734 	atomic_set(&dhdp->pktlog->pktlog_ring->start, TRUE);
9735 
9736 	bytes_written = snprintf(command, total_len, "OK");
9737 
9738 	ANDROID_ERROR(("%s: pktlog start success\n", __FUNCTION__));
9739 
9740 	return bytes_written;
9741 }
9742 
9743 static int
wl_android_pktlog_stop(struct net_device * dev,char * command,int total_len)9744 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
9745 {
9746 	int bytes_written = 0;
9747 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9748 
9749 	if (!dhdp || !dhdp->pktlog) {
9750 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9751 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9752 		return -EINVAL;
9753 	}
9754 
9755 	if (!dhdp->pktlog->pktlog_ring) {
9756 		DHD_PKT_LOG(("%s(): _pktlog_ring=%p\n",
9757 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9758 		return -EINVAL;
9759 	}
9760 
9761 	atomic_set(&dhdp->pktlog->pktlog_ring->start, FALSE);
9762 
9763 	bytes_written = snprintf(command, total_len, "OK");
9764 
9765 	ANDROID_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
9766 
9767 	return bytes_written;
9768 }
9769 
9770 static int
wl_android_pktlog_filter_exist(struct net_device * dev,char * command,int total_len)9771 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
9772 {
9773 	int bytes_written = 0;
9774 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9775 	dhd_pktlog_filter_t *filter;
9776 	uint32 id;
9777 	bool exist = FALSE;
9778 
9779 	if (!dhdp || !dhdp->pktlog) {
9780 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9781 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9782 		return -EINVAL;
9783 	}
9784 
9785 	filter = dhdp->pktlog->pktlog_filter;
9786 
9787 	if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
9788 		return BCME_ERROR;
9789 	}
9790 
9791 	exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
9792 			&id);
9793 
9794 	if (exist) {
9795 		bytes_written = snprintf(command, total_len, "TRUE");
9796 		ANDROID_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
9797 	} else {
9798 		bytes_written = snprintf(command, total_len, "FALSE");
9799 		ANDROID_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
9800 	}
9801 
9802 	return bytes_written;
9803 }
9804 
9805 static int
wl_android_pktlog_minmize_enable(struct net_device * dev,char * command,int total_len)9806 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
9807 {
9808 	int bytes_written = 0;
9809 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9810 
9811 	if (!dhdp || !dhdp->pktlog) {
9812 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9813 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9814 		return -EINVAL;
9815 	}
9816 
9817 	if (!dhdp->pktlog->pktlog_ring) {
9818 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9819 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9820 		return -EINVAL;
9821 	}
9822 
9823 	dhdp->pktlog->pktlog_ring->pktlog_minmize = TRUE;
9824 
9825 	bytes_written = snprintf(command, total_len, "OK");
9826 
9827 	ANDROID_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
9828 
9829 	return bytes_written;
9830 }
9831 
9832 static int
wl_android_pktlog_minmize_disable(struct net_device * dev,char * command,int total_len)9833 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
9834 {
9835 	int bytes_written = 0;
9836 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9837 
9838 	if (!dhdp || !dhdp->pktlog) {
9839 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9840 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9841 		return -EINVAL;
9842 	}
9843 
9844 	if (!dhdp->pktlog->pktlog_ring) {
9845 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9846 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
9847 		return -EINVAL;
9848 	}
9849 
9850 	dhdp->pktlog->pktlog_ring->pktlog_minmize = FALSE;
9851 
9852 	bytes_written = snprintf(command, total_len, "OK");
9853 
9854 	ANDROID_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
9855 
9856 	return bytes_written;
9857 }
9858 
9859 static int
wl_android_pktlog_change_size(struct net_device * dev,char * command,int total_len)9860 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
9861 {
9862 	int bytes_written = 0;
9863 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9864 	int err = BCME_OK;
9865 	int size;
9866 
9867 	if (!dhdp || !dhdp->pktlog) {
9868 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9869 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9870 		return -EINVAL;
9871 	}
9872 
9873 	if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
9874 		return BCME_ERROR;
9875 	}
9876 
9877 	size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
9878 
9879 	dhdp->pktlog->pktlog_ring =
9880 		dhd_pktlog_ring_change_size(dhdp->pktlog->pktlog_ring, size);
9881 	if (!dhdp->pktlog->pktlog_ring) {
9882 		err = BCME_ERROR;
9883 	}
9884 
9885 	if (err == BCME_OK) {
9886 		bytes_written = snprintf(command, total_len, "OK");
9887 		ANDROID_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
9888 	} else {
9889 		ANDROID_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
9890 		return BCME_ERROR;
9891 	}
9892 
9893 	return bytes_written;
9894 }
9895 
9896 static int
wl_android_pktlog_dbg_dump(struct net_device * dev,char * command,int total_len)9897 wl_android_pktlog_dbg_dump(struct net_device *dev, char *command, int total_len)
9898 {
9899 	int bytes_written = 0;
9900 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9901 	int err = BCME_OK;
9902 
9903 	if (!dhdp || !dhdp->pktlog) {
9904 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9905 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9906 		return -EINVAL;
9907 	}
9908 
9909 	if (strlen(CMD_PKTLOG_DEBUG_DUMP) + 1 > total_len) {
9910 		return BCME_ERROR;
9911 	}
9912 
9913 	err = dhd_pktlog_debug_dump(dhdp);
9914 	if (err == BCME_OK) {
9915 		bytes_written = snprintf(command, total_len, "OK");
9916 		ANDROID_INFO(("%s: pktlog dbg dump success\n", __FUNCTION__));
9917 	} else {
9918 		ANDROID_ERROR(("%s: pktlog dbg dump fail\n", __FUNCTION__));
9919 		return BCME_ERROR;
9920 	}
9921 
9922 	return bytes_written;
9923 }
9924 #endif /* DHD_PKT_LOGGING */
9925 
9926 #if defined(CONFIG_TIZEN)
wl_android_set_powersave_mode(struct net_device * dev,char * command,int total_len)9927 static int wl_android_set_powersave_mode(
9928 	struct net_device *dev, char* command, int total_len)
9929 {
9930 	int pm;
9931 
9932 	int err = BCME_OK;
9933 #ifdef DHD_PM_OVERRIDE
9934 	extern bool g_pm_override;
9935 #endif /* DHD_PM_OVERRIDE */
9936 	sscanf(command, "%*s %10d", &pm);
9937 	if (pm < PM_OFF || pm > PM_FAST) {
9938 		ANDROID_ERROR(("check pm=%d\n", pm));
9939 		return BCME_ERROR;
9940 	}
9941 
9942 #ifdef DHD_PM_OVERRIDE
9943 	if (pm > PM_OFF) {
9944 		g_pm_override = FALSE;
9945 	}
9946 #endif /* DHD_PM_OVERRIDE */
9947 
9948 	err =  wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
9949 
9950 #ifdef DHD_PM_OVERRIDE
9951 	if (pm == PM_OFF) {
9952 		g_pm_override = TRUE;
9953 	}
9954 
9955 	ANDROID_ERROR(("%s: PM:%d, pm_override=%d\n", __FUNCTION__, pm, g_pm_override));
9956 #endif /* DHD_PM_OVERRIDE */
9957 	return err;
9958 }
9959 
wl_android_get_powersave_mode(struct net_device * dev,char * command,int total_len)9960 static int wl_android_get_powersave_mode(
9961 	struct net_device *dev, char *command, int total_len)
9962 {
9963 	int err, bytes_written;
9964 	int pm;
9965 
9966 	err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
9967 	if (err != BCME_OK) {
9968 		ANDROID_ERROR(("failed to get pm (%d)", err));
9969 		return err;
9970 	}
9971 
9972 	bytes_written = snprintf(command, total_len, "%s %d",
9973 		CMD_POWERSAVEMODE_GET, pm);
9974 
9975 	return bytes_written;
9976 }
9977 #endif /* CONFIG_TIZEN */
9978 
9979 #ifdef DHD_EVENT_LOG_FILTER
9980 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
9981 
9982 #ifdef DHD_EWPR_VER2
9983 uint32 dhd_event_log_filter_serialize_bit(dhd_pub_t *dhdp, char *buf, uint32 tot_len,
9984 	int index1, int index2, int index3);
9985 #endif
9986 
9987 static int
wl_android_ewp_filter(struct net_device * dev,char * command,uint32 tot_len)9988 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
9989 {
9990 	uint32 bytes_written = 0;
9991 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9992 #ifdef DHD_EWPR_VER2
9993 	int index1 = 0, index2 = 0, index3 = 0;
9994 	unsigned char *index_str = (unsigned char *)(command +
9995 		strlen(CMD_EWP_FILTER) + 1);
9996 #else
9997 	int type = 0;
9998 #endif
9999 
10000 	if (!dhdp || !command) {
10001 		ANDROID_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
10002 		return -EINVAL;
10003 	}
10004 
10005 	if (!FW_SUPPORTED(dhdp, ecounters)) {
10006 		ANDROID_ERROR(("does not support ecounters!\n"));
10007 		return BCME_UNSUPPORTED;
10008 	}
10009 
10010 #ifdef DHD_EWPR_VER2
10011 	if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) {
10012 		sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3);
10013 		ANDROID_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__,
10014 			index1, index2, index3));
10015 	}
10016 	bytes_written += dhd_event_log_filter_serialize_bit(dhdp,
10017 		&command[bytes_written], tot_len - bytes_written, index1, index2, index3);
10018 #else
10019 	/* NEED TO GET TYPE if EXIST */
10020 	type = 0;
10021 
10022 	bytes_written += dhd_event_log_filter_serialize(dhdp,
10023 		&command[bytes_written], tot_len - bytes_written, type);
10024 #endif
10025 
10026 	return (int)bytes_written;
10027 }
10028 #endif /* DHD_EVENT_LOG_FILTER */
10029 
10030 #ifdef SUPPORT_AP_SUSPEND
10031 int
wl_android_set_ap_suspend(struct net_device * dev,char * command,int total_len)10032 wl_android_set_ap_suspend(struct net_device *dev, char *command, int total_len)
10033 {
10034 	int suspend = 0;
10035 	char *pos, *token;
10036 	char *ifname = NULL;
10037 	int err = BCME_OK;
10038 	char name[IFNAMSIZ];
10039 
10040 	/*
10041 	 * DRIVER SET_AP_SUSPEND <0/1> <ifname>
10042 	 */
10043 	pos = command;
10044 
10045 	/* drop command */
10046 	token = bcmstrtok(&pos, " ", NULL);
10047 
10048 	/* Enable */
10049 	token = bcmstrtok(&pos, " ", NULL);
10050 	if (!token) {
10051 		return -EINVAL;
10052 	}
10053 	suspend = bcm_atoi(token);
10054 
10055 	/* get the interface name */
10056 	token = bcmstrtok(&pos, " ", NULL);
10057 	if (!token) {
10058 		return -EINVAL;
10059 	}
10060 	ifname = token;
10061 
10062 	strlcpy(name, ifname, sizeof(name));
10063 	ANDROID_INFO(("suspend %d, ifacename %s\n", suspend, name));
10064 
10065 	err = wl_set_ap_suspend(dev, suspend? TRUE: FALSE, name);
10066 	if (unlikely(err)) {
10067 		ANDROID_ERROR(("Failed to set suspend, suspend %d, error = %d\n", suspend, err));
10068 	}
10069 
10070 	return err;
10071 }
10072 #endif /* SUPPORT_AP_SUSPEND */
10073 
10074 #ifdef SUPPORT_AP_BWCTRL
10075 int
wl_android_set_ap_bw(struct net_device * dev,char * command,int total_len)10076 wl_android_set_ap_bw(struct net_device *dev, char *command, int total_len)
10077 {
10078 	int bw = DOT11_OPER_MODE_20MHZ;
10079 	char *pos, *token;
10080 	char *ifname = NULL;
10081 	int err = BCME_OK;
10082 	char name[IFNAMSIZ];
10083 
10084 	/*
10085 	 * DRIVER SET_AP_BW <0/1/2> <ifname>
10086 	 * 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10087 	 * This is from operating mode field
10088 	 * in 8.4.1.50 of 802.11ac-2013
10089 	 */
10090 	pos = command;
10091 
10092 	/* drop command */
10093 	token = bcmstrtok(&pos, " ", NULL);
10094 
10095 	/* BW */
10096 	token = bcmstrtok(&pos, " ", NULL);
10097 	if (!token) {
10098 		return -EINVAL;
10099 	}
10100 	bw = bcm_atoi(token);
10101 
10102 	/* get the interface name */
10103 	token = bcmstrtok(&pos, " ", NULL);
10104 	if (!token) {
10105 		return -EINVAL;
10106 	}
10107 	ifname = token;
10108 
10109 	strlcpy(name, ifname, sizeof(name));
10110 	ANDROID_INFO(("bw %d, ifacename %s\n", bw, name));
10111 
10112 	err = wl_set_ap_bw(dev, bw, name);
10113 	if (unlikely(err)) {
10114 		ANDROID_ERROR(("Failed to set bw, bw %d, error = %d\n", bw, err));
10115 	}
10116 
10117 	return err;
10118 }
10119 
10120 int
wl_android_get_ap_bw(struct net_device * dev,char * command,int total_len)10121 wl_android_get_ap_bw(struct net_device *dev, char *command, int total_len)
10122 {
10123 	char *pos, *token;
10124 	char *ifname = NULL;
10125 	int bytes_written = 0;
10126 	char name[IFNAMSIZ];
10127 
10128 	/*
10129 	 * DRIVER GET_AP_BW <ifname>
10130 	 * returns 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10131 	 * This is from operating mode field
10132 	 * in 8.4.1.50 of 802.11ac-2013
10133 	 */
10134 	pos = command;
10135 
10136 	/* drop command */
10137 	token = bcmstrtok(&pos, " ", NULL);
10138 
10139 	/* get the interface name */
10140 	token = bcmstrtok(&pos, " ", NULL);
10141 	if (!token) {
10142 		return -EINVAL;
10143 	}
10144 	ifname = token;
10145 
10146 	strlcpy(name, ifname, sizeof(name));
10147 	ANDROID_INFO(("ifacename %s\n", name));
10148 
10149 	bytes_written = wl_get_ap_bw(dev, command, name, total_len);
10150 	if (bytes_written < 1) {
10151 		ANDROID_ERROR(("Failed to get bw, error = %d\n", bytes_written));
10152 		return -EPROTO;
10153 	}
10154 
10155 	return bytes_written;
10156 
10157 }
10158 #endif /* SUPPORT_AP_BWCTRL */
10159 
10160 static int
wl_android_priv_cmd_log_enable_check(char * cmd)10161 wl_android_priv_cmd_log_enable_check(char* cmd)
10162 {
10163 	int cnt = 0;
10164 
10165 	while (strlen(loging_params[cnt].command) > 0) {
10166 		if (!strnicmp(cmd, loging_params[cnt].command,
10167 			strlen(loging_params[cnt].command))) {
10168 			return loging_params[cnt].enable;
10169 		}
10170 
10171 		cnt++;
10172 	}
10173 
10174 	return FALSE;
10175 }
10176 
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr)10177 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
10178 {
10179 #define PRIVATE_COMMAND_MAX_LEN	8192
10180 #define PRIVATE_COMMAND_DEF_LEN	4096
10181 	int ret = 0;
10182 	char *command = NULL;
10183 	int bytes_written = 0;
10184 	android_wifi_priv_cmd priv_cmd;
10185 	int buf_size = 0;
10186 	dhd_pub_t *dhd = dhd_get_pub(net);
10187 
10188 	net_os_wake_lock(net);
10189 
10190 	if (!capable(CAP_NET_ADMIN)) {
10191 		ret = -EPERM;
10192 		goto exit;
10193 	}
10194 
10195 	if (!ifr->ifr_data) {
10196 		ret = -EINVAL;
10197 		goto exit;
10198 	}
10199 
10200 #ifdef CONFIG_COMPAT
10201 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
10202 	if (in_compat_syscall())
10203 #else
10204 	if (is_compat_task())
10205 #endif
10206 	{
10207 		compat_android_wifi_priv_cmd compat_priv_cmd;
10208 		if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
10209 			sizeof(compat_android_wifi_priv_cmd))) {
10210 			ret = -EFAULT;
10211 			goto exit;
10212 
10213 		}
10214 		priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
10215 		priv_cmd.used_len = compat_priv_cmd.used_len;
10216 		priv_cmd.total_len = compat_priv_cmd.total_len;
10217 	} else
10218 #endif /* CONFIG_COMPAT */
10219 	{
10220 		if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
10221 			ret = -EFAULT;
10222 			goto exit;
10223 		}
10224 	}
10225 	if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
10226 		ANDROID_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
10227 			priv_cmd.total_len));
10228 		ret = -EINVAL;
10229 		goto exit;
10230 	}
10231 
10232 	buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
10233 	command = (char *)MALLOC(dhd->osh, (buf_size + 1));
10234 	if (!command) {
10235 		ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
10236 		ret = -ENOMEM;
10237 		goto exit;
10238 	}
10239 	if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
10240 		ret = -EFAULT;
10241 		goto exit;
10242 	}
10243 	command[priv_cmd.total_len] = '\0';
10244 
10245 	if (wl_android_priv_cmd_log_enable_check(command)) {
10246 		ANDROID_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__,
10247 			command, ifr->ifr_name));
10248 	}
10249 	else {
10250 		ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
10251 
10252 	}
10253 
10254 	bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
10255 	if (bytes_written >= 0) {
10256 		if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
10257 			command[0] = '\0';
10258 		}
10259 		if (bytes_written >= priv_cmd.total_len) {
10260 			ANDROID_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
10261 				__FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
10262 
10263 			ret = BCME_BUFTOOSHORT;
10264 			goto exit;
10265 		}
10266 		bytes_written++;
10267 		priv_cmd.used_len = bytes_written;
10268 		if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
10269 			ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
10270 			ret = -EFAULT;
10271 		}
10272 	}
10273 	else {
10274 		/* Propagate the error */
10275 		ret = bytes_written;
10276 	}
10277 
10278 exit:
10279 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
10280 	if (ret) {
10281 		/* Avoid incrementing priv_cmd_errors in case of unsupported feature */
10282 		if (ret != BCME_UNSUPPORTED) {
10283 			wl_android_check_priv_cmd_errors(net);
10284 		}
10285 	} else {
10286 		priv_cmd_errors = 0;
10287 	}
10288 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
10289 	net_os_wake_unlock(net);
10290 	MFREE(dhd->osh, command, (buf_size + 1));
10291 	return ret;
10292 }
10293 
10294 #ifdef WLADPS_PRIVATE_CMD
10295 static int
wl_android_set_adps_mode(struct net_device * dev,const char * string_num)10296 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
10297 {
10298 	int err = 0, adps_mode;
10299 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10300 #ifdef DHD_PM_CONTROL_FROM_FILE
10301 	if (g_pm_control) {
10302 		return -EPERM;
10303 	}
10304 #endif	/* DHD_PM_CONTROL_FROM_FILE */
10305 
10306 	adps_mode = bcm_atoi(string_num);
10307 	ANDROID_ERROR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
10308 
10309 	if (!(adps_mode == 0 || adps_mode == 1)) {
10310 		ANDROID_ERROR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode));
10311 		return -EINVAL;
10312 	}
10313 
10314 	err = dhd_enable_adps(dhdp, adps_mode);
10315 	if (err != BCME_OK) {
10316 		ANDROID_ERROR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
10317 		return -EIO;
10318 	}
10319 	return err;
10320 }
10321 static int
wl_android_get_adps_mode(struct net_device * dev,char * command,int total_len)10322 wl_android_get_adps_mode(
10323 	struct net_device *dev, char *command, int total_len)
10324 {
10325 	int bytes_written, err = 0;
10326 	uint len;
10327 	char buf[WLC_IOCTL_SMLEN];
10328 
10329 	bcm_iov_buf_t iov_buf;
10330 	bcm_iov_buf_t *ptr = NULL;
10331 	wl_adps_params_v1_t *data = NULL;
10332 
10333 	uint8 *pdata = NULL;
10334 	uint8 band, mode = 0;
10335 
10336 	bzero(&iov_buf, sizeof(iov_buf));
10337 
10338 	len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
10339 
10340 	iov_buf.version = WL_ADPS_IOV_VER;
10341 	iov_buf.len = sizeof(band);
10342 	iov_buf.id = WL_ADPS_IOV_MODE;
10343 
10344 	pdata = (uint8 *)&iov_buf.data;
10345 
10346 	for (band = 1; band <= MAX_BANDS; band++) {
10347 		pdata[0] = band;
10348 		err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
10349 			buf, WLC_IOCTL_SMLEN, NULL);
10350 		if (err != BCME_OK) {
10351 			ANDROID_ERROR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n",
10352 					band, err));
10353 			return -EIO;
10354 		}
10355 		ptr = (bcm_iov_buf_t *) buf;
10356 		data = (wl_adps_params_v1_t *) ptr->data;
10357 		mode = data->mode;
10358 		if (mode != OFF) {
10359 			break;
10360 		}
10361 	}
10362 
10363 	bytes_written = snprintf(command, total_len, "%s %d",
10364 		CMD_GET_ADPS, mode);
10365 	return bytes_written;
10366 }
10367 
10368 #ifdef WLADPS_ENERGY_GAIN
10369 static int
wl_android_get_gain_adps(struct net_device * dev,char * command,int total_len)10370 wl_android_get_gain_adps(
10371 	struct net_device *dev, char *command, int total_len)
10372 {
10373 	int bytes_written;
10374 
10375 	int ret = 0;
10376 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10377 
10378 	ret = dhd_event_log_filter_adps_energy_gain(dhdp);
10379 	if (ret < 0) {
10380 		return ret;
10381 	}
10382 
10383 	ANDROID_INFO(("%s ADPS Energy Gain: %d uAh\n", __FUNCTION__, ret));
10384 
10385 	bytes_written = snprintf(command, total_len, "%s %d uAm",
10386 		CMD_GET_GAIN_ADPS, ret);
10387 
10388 	return bytes_written;
10389 }
10390 
10391 static int
wl_android_reset_gain_adps(struct net_device * dev,char * command)10392 wl_android_reset_gain_adps(
10393 	struct net_device *dev, char *command)
10394 {
10395 	int ret = BCME_OK;
10396 
10397 	bcm_iov_buf_t iov_buf;
10398 	char buf[WLC_IOCTL_SMLEN] = {0, };
10399 
10400 	iov_buf.version = WL_ADPS_IOV_VER;
10401 	iov_buf.id = WL_ADPS_IOV_RESET_GAIN;
10402 	iov_buf.len = 0;
10403 
10404 	if ((ret = wldev_iovar_setbuf(dev, "adps", &iov_buf, sizeof(iov_buf),
10405 		buf, sizeof(buf), NULL)) < 0) {
10406 		ANDROID_ERROR(("%s fail to reset adps gain (%d)\n", __FUNCTION__, ret));
10407 	}
10408 
10409 	return ret;
10410 }
10411 #endif	/* WLADPS_ENERGY_GAIN */
10412 #endif /* WLADPS_PRIVATE_CMD */
10413 
10414 #ifdef WL_BCNRECV
10415 #define BCNRECV_ATTR_HDR_LEN 30
10416 int
wl_android_bcnrecv_event(struct net_device * ndev,uint attr_type,uint status,uint reason,uint8 * data,uint data_len)10417 wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
10418 		uint status, uint reason, uint8 *data, uint data_len)
10419 {
10420 	s32 err = BCME_OK;
10421 	struct sk_buff *skb;
10422 	gfp_t kflags;
10423 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10424 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10425 	uint len;
10426 
10427 	len = BCNRECV_ATTR_HDR_LEN + data_len;
10428 
10429 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10430 	skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
10431 		BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
10432 	if (!skb) {
10433 		ANDROID_ERROR(("skb alloc failed"));
10434 		return -ENOMEM;
10435 	}
10436 	if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
10437 		/* send bcn info to upper layer */
10438 		nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
10439 	} else if (attr_type == BCNRECV_ATTR_STATUS) {
10440 		nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
10441 		if (reason) {
10442 			nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
10443 		}
10444 	} else {
10445 		ANDROID_ERROR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
10446 		kfree_skb(skb);
10447 		return -EINVAL;
10448 	}
10449 	cfg80211_vendor_event(skb, kflags);
10450 	return err;
10451 }
10452 
10453 static int
_wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool user_trigger)10454 _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
10455 {
10456 	s32 err = BCME_OK;
10457 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10458 
10459 	/* check any scan is in progress before beacon recv scan trigger IOVAR */
10460 	if (wl_get_drv_status_all(cfg, SCANNING)) {
10461 		err = BCME_UNSUPPORTED;
10462 		ANDROID_ERROR(("Scan in progress, Aborting beacon recv start, "
10463 			"error:%d\n", err));
10464 		goto exit;
10465 	}
10466 
10467 	if (wl_get_p2p_status(cfg, SCANNING)) {
10468 		err = BCME_UNSUPPORTED;
10469 		ANDROID_ERROR(("P2P Scan in progress, Aborting beacon recv start, "
10470 			"error:%d\n", err));
10471 		goto exit;
10472 	}
10473 
10474 	if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
10475 		err = BCME_UNSUPPORTED;
10476 		ANDROID_ERROR(("P2P remain on channel, Aborting beacon recv start, "
10477 			"error:%d\n", err));
10478 		goto exit;
10479 	}
10480 
10481 	/* check STA is in connected state, Beacon recv required connected state
10482 	 * else exit from beacon recv scan
10483 	 */
10484 	if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
10485 		err = BCME_UNSUPPORTED;
10486 		ANDROID_ERROR(("STA is in not associated state error:%d\n", err));
10487 		goto exit;
10488 	}
10489 
10490 #ifdef WL_NAN
10491 	/* Check NAN is enabled, if enabled exit else continue */
10492 	if (wl_cfgnan_is_enabled(cfg)) {
10493 		err = BCME_UNSUPPORTED;
10494 		ANDROID_ERROR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
10495 		goto exit;
10496 	}
10497 #endif /* WL_NAN */
10498 
10499 	/* Triggering an sendup_bcn iovar */
10500 	err = wldev_iovar_setint(pdev, "sendup_bcn", 1);
10501 	if (unlikely(err)) {
10502 		ANDROID_ERROR(("sendup_bcn failed to set, error:%d\n", err));
10503 	} else {
10504 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
10505 		ANDROID_INFO(("bcnrecv started. user_trigger:%d ifindex:%d\n",
10506 			user_trigger, ndev->ifindex));
10507 		if (user_trigger) {
10508 			if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS,
10509 					WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
10510 				ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10511 			}
10512 		}
10513 	}
10514 exit:
10515 	/*
10516 	 * BCNRECV start request can be rejected from dongle
10517 	 * in various conditions.
10518 	 * Error code need to be overridden to BCME_UNSUPPORTED
10519 	 * to avoid hang event from continous private
10520 	 * command error
10521 	 */
10522 	if (err) {
10523 		err = BCME_UNSUPPORTED;
10524 	}
10525 	return err;
10526 }
10527 
10528 int
_wl_android_bcnrecv_stop(struct bcm_cfg80211 * cfg,struct net_device * ndev,uint reason)10529 _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
10530 {
10531 	s32 err = BCME_OK;
10532 	u32 status;
10533 	struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10534 
10535 	/* Stop bcnrx except for fw abort event case */
10536 	if (reason != WL_BCNRECV_ROAMABORT) {
10537 		err = wldev_iovar_setint(pdev, "sendup_bcn", 0);
10538 		if (unlikely(err)) {
10539 			ANDROID_ERROR(("sendup_bcn failed to set error:%d\n", err));
10540 			goto exit;
10541 		}
10542 	}
10543 
10544 	/* Send notification for all cases */
10545 	if (reason == WL_BCNRECV_SUSPEND) {
10546 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
10547 		status = WL_BCNRECV_SUSPENDED;
10548 	} else {
10549 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
10550 		ANDROID_INFO(("bcnrecv stopped. reason:%d ifindex:%d\n",
10551 			reason, ndev->ifindex));
10552 		if (reason == WL_BCNRECV_USER_TRIGGER) {
10553 			status = WL_BCNRECV_STOPPED;
10554 		} else {
10555 			status = WL_BCNRECV_ABORTED;
10556 		}
10557 	}
10558 	if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, status,
10559 			reason, NULL, 0)) != BCME_OK) {
10560 		ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10561 	}
10562 exit:
10563 	return err;
10564 }
10565 
10566 static int
wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev)10567 wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
10568 {
10569 	s32 err = BCME_OK;
10570 
10571 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10572 	mutex_lock(&cfg->scan_sync);
10573 	mutex_lock(&cfg->bcn_sync);
10574 	err = _wl_android_bcnrecv_start(cfg, ndev, true);
10575 	mutex_unlock(&cfg->bcn_sync);
10576 	mutex_unlock(&cfg->scan_sync);
10577 	return err;
10578 }
10579 
10580 int
wl_android_bcnrecv_stop(struct net_device * ndev,uint reason)10581 wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
10582 {
10583 	s32 err = BCME_OK;
10584 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10585 
10586 	mutex_lock(&cfg->bcn_sync);
10587 	if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
10588 	   (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
10589 		err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
10590 	}
10591 	mutex_unlock(&cfg->bcn_sync);
10592 	return err;
10593 }
10594 
10595 int
wl_android_bcnrecv_suspend(struct net_device * ndev)10596 wl_android_bcnrecv_suspend(struct net_device *ndev)
10597 {
10598 	s32 ret = BCME_OK;
10599 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10600 
10601 	mutex_lock(&cfg->bcn_sync);
10602 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
10603 		ANDROID_INFO(("bcnrecv suspend\n"));
10604 		ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
10605 	}
10606 	mutex_unlock(&cfg->bcn_sync);
10607 	return ret;
10608 }
10609 
10610 int
wl_android_bcnrecv_resume(struct net_device * ndev)10611 wl_android_bcnrecv_resume(struct net_device *ndev)
10612 {
10613 	s32 ret = BCME_OK;
10614 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10615 
10616 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10617 	mutex_lock(&cfg->scan_sync);
10618 	mutex_lock(&cfg->bcn_sync);
10619 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
10620 		ANDROID_INFO(("bcnrecv resume\n"));
10621 		ret = _wl_android_bcnrecv_start(cfg, ndev, false);
10622 	}
10623 	mutex_unlock(&cfg->bcn_sync);
10624 	mutex_unlock(&cfg->scan_sync);
10625 	return ret;
10626 }
10627 
10628 /* Beacon recv functionality code implementation */
10629 int
wl_android_bcnrecv_config(struct net_device * ndev,char * cmd_argv,int total_len)10630 wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
10631 {
10632 	struct bcm_cfg80211 *cfg = NULL;
10633 	uint err = BCME_OK;
10634 
10635 	if (!ndev) {
10636 		ANDROID_ERROR(("ndev is NULL\n"));
10637 		return -EINVAL;
10638 	}
10639 
10640 	cfg = wl_get_cfg(ndev);
10641 	if (!cfg) {
10642 		ANDROID_ERROR(("cfg is NULL\n"));
10643 		return -EINVAL;
10644 	}
10645 
10646 	/* sync commands from user space */
10647 	mutex_lock(&cfg->usr_sync);
10648 	if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
10649 		ANDROID_INFO(("BCNRECV start\n"));
10650 		err = wl_android_bcnrecv_start(cfg, ndev);
10651 		if (err != BCME_OK) {
10652 			ANDROID_ERROR(("Failed to process the start command, error:%d\n", err));
10653 			goto exit;
10654 		}
10655 	} else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
10656 		ANDROID_INFO(("BCNRECV stop\n"));
10657 		err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
10658 		if (err != BCME_OK) {
10659 			ANDROID_ERROR(("Failed to stop the bcn recv, error:%d\n", err));
10660 			goto exit;
10661 		}
10662 	} else {
10663 		err = BCME_ERROR;
10664 	}
10665 exit:
10666 	mutex_unlock(&cfg->usr_sync);
10667 	return err;
10668 }
10669 #endif /* WL_BCNRECV */
10670 
10671 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
10672 static int
wl_android_set_latency_crt_data(struct net_device * dev,int mode)10673 wl_android_set_latency_crt_data(struct net_device *dev, int mode)
10674 {
10675 	int ret;
10676 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10677 	dhd_pub_t *dhdp = NULL;
10678 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10679 	if (mode >= LATENCY_CRT_DATA_MODE_LAST) {
10680 		return BCME_BADARG;
10681 	}
10682 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10683 	dhdp = wl_cfg80211_get_dhdp(dev);
10684 	if (mode != LATENCY_CRT_DATA_MODE_OFF) {
10685 		ANDROID_ERROR(("Not permitted GRO by framework\n"));
10686 		dhdp->permitted_gro = FALSE;
10687 	} else {
10688 		ANDROID_ERROR(("Permitted GRO by framework\n"));
10689 		dhdp->permitted_gro = TRUE;
10690 	}
10691 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10692 	ret = wldev_iovar_setint(dev, "latency_critical_data", mode);
10693 	if (ret != BCME_OK) {
10694 		ANDROID_ERROR(("failed to set latency_critical_data mode %d, error = %d\n",
10695 			mode, ret));
10696 		return ret;
10697 	}
10698 
10699 	return ret;
10700 }
10701 
10702 static int
wl_android_get_latency_crt_data(struct net_device * dev,char * command,int total_len)10703 wl_android_get_latency_crt_data(struct net_device *dev, char *command, int total_len)
10704 {
10705 	int ret;
10706 	int mode = LATENCY_CRT_DATA_MODE_OFF;
10707 	int bytes_written;
10708 
10709 	ret = wldev_iovar_getint(dev, "latency_critical_data", &mode);
10710 	if (ret != BCME_OK) {
10711 		ANDROID_ERROR(("failed to get latency_critical_data error = %d\n", ret));
10712 		return ret;
10713 	}
10714 
10715 	bytes_written = snprintf(command, total_len, "%s %d",
10716 		CMD_GET_LATENCY_CRITICAL_DATA, mode);
10717 
10718 	return bytes_written;
10719 }
10720 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
10721 
10722 #ifdef WL_CAC_TS
10723 /* CAC TSPEC functionality code implementation */
10724 static void
wl_android_update_tsinfo(uint8 access_category,tspec_arg_t * tspec_arg)10725 wl_android_update_tsinfo(uint8 access_category, tspec_arg_t *tspec_arg)
10726 {
10727 	uint8 tspec_id;
10728 	/* Using direction as bidirectional by default */
10729 	uint8 direction = TSPEC_BI_DIRECTION;
10730 	/* Using U-APSD as the default power save mode */
10731 	uint8 user_psb = TSPEC_UAPSD_PSB;
10732 	uint8 ADDTS_AC2PRIO[4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI, PRIO_8021D_VO};
10733 
10734 	/* Map tspec_id from access category */
10735 	tspec_id = ADDTS_AC2PRIO[access_category];
10736 
10737 	/* Update the tsinfo */
10738 	tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
10739 		(tspec_id << TSPEC_TSINFO_TID_SHIFT));
10740 	tspec_arg->tsinfo.octets[1] = (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) |
10741 		user_psb);
10742 	tspec_arg->tsinfo.octets[2] = 0x00;
10743 }
10744 
10745 static s32
wl_android_handle_cac_action(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * argv)10746 wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev, char * argv)
10747 {
10748 	tspec_arg_t tspec_arg;
10749 	s32 err = BCME_ERROR;
10750 	u8 ts_cmd[12] = "cac_addts";
10751 	uint8 access_category;
10752 	s32 bssidx;
10753 
10754 	/* Following handling is done only for the primary interface */
10755 	memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
10756 	if (strncmp(argv, "addts", strlen("addts")) == 0) {
10757 		tspec_arg.version = TSPEC_ARG_VERSION;
10758 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10759 		/* Read the params passed */
10760 		sscanf(argv, "%*s %hhu %hu %hu", &access_category,
10761 			&tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
10762 		if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
10763 			((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
10764 			(tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
10765 			(tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
10766 			ANDROID_ERROR(("Invalid params access_category %hhu nom_msdu_size %hu"
10767 				" surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size,
10768 				tspec_arg.surplus_bw));
10769 			return BCME_USAGE_ERROR;
10770 		}
10771 
10772 		/* Update tsinfo */
10773 		wl_android_update_tsinfo(access_category, &tspec_arg);
10774 		/* Update other tspec parameters */
10775 		tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
10776 		tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
10777 		tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
10778 	} else if (strncmp(argv, "delts", strlen("delts")) == 0) {
10779 		snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
10780 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10781 		tspec_arg.version = TSPEC_ARG_VERSION;
10782 		/* Read the params passed */
10783 		sscanf(argv, "%*s %hhu", &access_category);
10784 
10785 		if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
10786 			ANDROID_INFO(("Invalide param, access_category %hhu\n", access_category));
10787 			return BCME_USAGE_ERROR;
10788 		}
10789 		/* Update tsinfo */
10790 		wl_android_update_tsinfo(access_category, &tspec_arg);
10791 	}
10792 
10793 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
10794 		ANDROID_ERROR(("Find index failed\n"));
10795 		err = BCME_ERROR;
10796 		return err;
10797 	}
10798 	err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
10799 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
10800 	if (unlikely(err)) {
10801 		ANDROID_ERROR(("%s error (%d)\n", ts_cmd, err));
10802 	}
10803 
10804 	return err;
10805 }
10806 
10807 static s32
wl_android_cac_ts_config(struct net_device * ndev,char * cmd_argv,int total_len)10808 wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len)
10809 {
10810 	struct bcm_cfg80211 *cfg = NULL;
10811 	s32 err = BCME_OK;
10812 
10813 	if (!ndev) {
10814 		ANDROID_ERROR(("ndev is NULL\n"));
10815 		return -EINVAL;
10816 	}
10817 
10818 	cfg = wl_get_cfg(ndev);
10819 	if (!cfg) {
10820 		ANDROID_ERROR(("cfg is NULL\n"));
10821 		return -EINVAL;
10822 	}
10823 
10824 	/* Request supported only for primary interface */
10825 	if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
10826 		ANDROID_ERROR(("Request on non-primary interface\n"));
10827 		return -1;
10828 	}
10829 
10830 	/* sync commands from user space */
10831 	mutex_lock(&cfg->usr_sync);
10832 	err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
10833 	mutex_unlock(&cfg->usr_sync);
10834 
10835 	return err;
10836 }
10837 #endif /* WL_CAC_TS */
10838 
10839 #ifdef WL_GET_CU
10840 /* Implementation to get channel usage from framework */
10841 static s32
wl_android_get_channel_util(struct net_device * ndev,char * command,int total_len)10842 wl_android_get_channel_util(struct net_device *ndev, char *command, int total_len)
10843 {
10844 	s32 bytes_written, err = 0;
10845 	wl_bssload_t bssload;
10846 	u8 smbuf[WLC_IOCTL_SMLEN];
10847 	u8 chan_use_percentage = 0;
10848 
10849 	if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL,
10850 		0, smbuf, WLC_IOCTL_SMLEN, NULL))) {
10851 		ANDROID_ERROR(("Getting bssload report failed with err=%d \n", err));
10852 		return err;
10853 	}
10854 
10855 	(void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
10856 	/* Convert channel usage to percentage value */
10857 	chan_use_percentage = (bssload.chan_util * 100) / 255;
10858 
10859 	bytes_written = snprintf(command, total_len, "CU %hhu",
10860 		chan_use_percentage);
10861 	ANDROID_INFO(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage));
10862 
10863 	return bytes_written;
10864 }
10865 #endif /* WL_GET_CU */
10866 
10867 #ifdef RTT_GEOFENCE_INTERVAL
10868 #if defined (RTT_SUPPORT) && defined(WL_NAN)
10869 static void
wl_android_set_rtt_geofence_interval(struct net_device * ndev,char * command)10870 wl_android_set_rtt_geofence_interval(struct net_device *ndev, char *command)
10871 {
10872 	int rtt_interval = 0;
10873 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
10874 	char *rtt_intp = command + strlen(CMD_GEOFENCE_INTERVAL) + 1;
10875 
10876 	rtt_interval = bcm_atoi(rtt_intp);
10877 	dhd_rtt_set_geofence_rtt_interval(dhdp, rtt_interval);
10878 }
10879 #endif /* RTT_SUPPORT && WL_NAN */
10880 #endif /* RTT_GEOFENCE_INTERVAL */
10881 
10882 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
10883 int
wl_android_set_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10884 wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10885 {
10886 	char *ifname = NULL;
10887 	char *pos, *token;
10888 	int err = BCME_OK;
10889 	int enable = FALSE;
10890 
10891 	/*
10892 	 * STA/AP/GO I/F: DRIVER SET_SOFTAP_ELNA_BYPASS <ifname> <enable/disable>
10893 	 * the enable/disable format follows Samsung specific rules as following
10894 	 * Enable : 0
10895 	 * Disable :-1
10896 	 */
10897 	pos = command;
10898 
10899 	/* drop command */
10900 	token = bcmstrtok(&pos, " ", NULL);
10901 
10902 	/* get the interface name */
10903 	token = bcmstrtok(&pos, " ", NULL);
10904 	if (!token) {
10905 		ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10906 		return -EINVAL;
10907 	}
10908 	ifname = token;
10909 
10910 	/* get enable/disable flag */
10911 	token = bcmstrtok(&pos, " ", NULL);
10912 	if (!token) {
10913 		ANDROID_ERROR(("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__));
10914 		return -EINVAL;
10915 	}
10916 	enable = bcm_atoi(token);
10917 
10918 	CUSTOMER_HW4_EN_CONVERT(enable);
10919 	err = wl_set_softap_elna_bypass(dev, ifname, enable);
10920 	if (unlikely(err)) {
10921 		ANDROID_ERROR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n",
10922 			__FUNCTION__, err));
10923 		return err;
10924 	}
10925 
10926 	return err;
10927 }
10928 
10929 int
wl_android_get_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10930 wl_android_get_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10931 {
10932 	char *ifname = NULL;
10933 	char *pos, *token;
10934 	int err = BCME_OK;
10935 	int bytes_written = 0;
10936 	int softap_elnabypass = 0;
10937 
10938 	/*
10939 	 * STA/AP/GO I/F: DRIVER GET_SOFTAP_ELNA_BYPASS <ifname>
10940 	 */
10941 	pos = command;
10942 
10943 	/* drop command */
10944 	token = bcmstrtok(&pos, " ", NULL);
10945 
10946 	/* get the interface name */
10947 	token = bcmstrtok(&pos, " ", NULL);
10948 	if (!token) {
10949 		ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10950 		return -EINVAL;
10951 	}
10952 	ifname = token;
10953 
10954 	err = wl_get_softap_elna_bypass(dev, ifname, &softap_elnabypass);
10955 	if (unlikely(err)) {
10956 		ANDROID_ERROR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n",
10957 			__FUNCTION__, err));
10958 		return err;
10959 	} else {
10960 		softap_elnabypass--; //Convert format to Customer HW4
10961 		ANDROID_INFO(("%s: eLNA Bypass feature enable status is %d\n",
10962 			__FUNCTION__, softap_elnabypass));
10963 		bytes_written = snprintf(command, total_len, "%s %d",
10964 			CMD_GET_SOFTAP_ELNA_BYPASS, softap_elnabypass);
10965 	}
10966 
10967 	return bytes_written;
10968 }
10969 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
10970 
10971 #ifdef WL_NAN
10972 int
wl_android_get_nan_status(struct net_device * dev,char * command,int total_len)10973 wl_android_get_nan_status(struct net_device *dev, char *command, int total_len)
10974 {
10975 	int bytes_written = 0;
10976 	int error = BCME_OK;
10977 	wl_nan_conf_status_t nstatus;
10978 
10979 	error = wl_cfgnan_get_status(dev, &nstatus);
10980 	if (error) {
10981 		ANDROID_ERROR(("Failed to get nan status (%d)\n", error));
10982 		return error;
10983 	}
10984 
10985 	bytes_written = snprintf(command, total_len,
10986 			"EN:%d Role:%d EM:%d CID:"MACF" NMI:"MACF" SC(2G):%d SC(5G):%d "
10987 			"MR:"NMRSTR" AMR:"NMRSTR" IMR:"NMRSTR
10988 			"HC:%d AMBTT:%04x TSF[%04x:%04x]\n",
10989 			nstatus.enabled,
10990 			nstatus.role,
10991 			nstatus.election_mode,
10992 			ETHERP_TO_MACF(&(nstatus.cid)),
10993 			ETHERP_TO_MACF(&(nstatus.nmi)),
10994 			nstatus.social_chans[0],
10995 			nstatus.social_chans[1],
10996 			NMR2STR(nstatus.mr),
10997 			NMR2STR(nstatus.amr),
10998 			NMR2STR(nstatus.imr),
10999 			nstatus.hop_count,
11000 			nstatus.ambtt,
11001 			nstatus.cluster_tsf_h,
11002 			nstatus.cluster_tsf_l);
11003 	return bytes_written;
11004 }
11005 #endif /* WL_NAN */
11006 
11007 #ifdef SUPPORT_NAN_RANGING_TEST_BW
11008 enum {
11009 	NAN_RANGING_5G_BW20 = 1,
11010 	NAN_RANGING_5G_BW40,
11011 	NAN_RANGING_5G_BW80
11012 };
11013 
11014 int
wl_nan_ranging_bw(struct net_device * net,int bw,char * command)11015 wl_nan_ranging_bw(struct net_device *net, int bw, char *command)
11016 {
11017 	int bytes_written, err = BCME_OK;
11018 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
11019 	s32 val = 1;
11020 	struct {
11021 		u32 band;
11022 		u32 bw_cap;
11023 	} param = {0, 0};
11024 
11025 	if (bw < NAN_RANGING_5G_BW20 || bw > NAN_RANGING_5G_BW80) {
11026 		ANDROID_ERROR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__));
11027 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11028 		return bytes_written;
11029 	}
11030 
11031 	switch (bw) {
11032 		case NAN_RANGING_5G_BW20:
11033 			ANDROID_ERROR(("NAN_RANGING 5G/BW20\n"));
11034 			param.band = WLC_BAND_5G;
11035 			param.bw_cap = 0x1;
11036 			break;
11037 		case NAN_RANGING_5G_BW40:
11038 			ANDROID_ERROR(("NAN_RANGING 5G/BW40\n"));
11039 			param.band = WLC_BAND_5G;
11040 			param.bw_cap = 0x3;
11041 			break;
11042 		case NAN_RANGING_5G_BW80:
11043 			ANDROID_ERROR(("NAN_RANGING 5G/BW80\n"));
11044 			param.band = WLC_BAND_5G;
11045 			param.bw_cap = 0x7;
11046 			break;
11047 	}
11048 
11049 	err = wldev_ioctl_set(net, WLC_DOWN, &val, sizeof(s32));
11050 	if (err) {
11051 		ANDROID_ERROR(("WLC_DOWN error %d\n", err));
11052 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11053 	} else {
11054 		err = wldev_iovar_setbuf(net, "bw_cap", &param, sizeof(param),
11055 			ioctl_buf, sizeof(ioctl_buf), NULL);
11056 
11057 		if (err) {
11058 			ANDROID_ERROR(("BW set failed\n"));
11059 			bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11060 		} else {
11061 			ANDROID_ERROR(("BW set done\n"));
11062 			bytes_written = scnprintf(command, sizeof("OK"), "OK");
11063 		}
11064 
11065 		err = wldev_ioctl_set(net, WLC_UP, &val, sizeof(s32));
11066 		if (err < 0) {
11067 			ANDROID_ERROR(("WLC_UP error %d\n", err));
11068 			bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11069 		}
11070 	}
11071 	return bytes_written;
11072 }
11073 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
11074 
11075 static int
wl_android_set_softap_ax_mode(struct net_device * dev,const char * cmd_str)11076 wl_android_set_softap_ax_mode(struct net_device *dev, const char* cmd_str)
11077 {
11078 	int enable = 0;
11079 	int err = 0;
11080 	s32 bssidx = 0;
11081 	struct bcm_cfg80211 *cfg = NULL;
11082 
11083 	if (!dev) {
11084 		err = -EINVAL;
11085 		goto exit;
11086 	}
11087 
11088 	cfg = wl_get_cfg(dev);
11089 	if (!cfg) {
11090 		err = -EINVAL;
11091 		goto exit;
11092 	}
11093 
11094 	if (cmd_str) {
11095 		enable = bcm_atoi(cmd_str);
11096 	} else {
11097 		ANDROID_ERROR(("failed due to wrong received parameter\n"));
11098 		err = -EINVAL;
11099 		goto exit;
11100 	}
11101 
11102 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11103 		ANDROID_ERROR(("find softap index from wdev failed\n"));
11104 		err = -EINVAL;
11105 		goto exit;
11106 	}
11107 
11108 	ANDROID_INFO(("HAPD_SET_AX_MODE = %d\n", enable));
11109 	err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, (bool)enable);
11110 	if (err) {
11111 		ANDROID_ERROR(("failed to set softap ax mode(%d)\n", enable));
11112 
11113 	}
11114 exit :
11115 	return err;
11116 }
11117 
11118 #ifdef WL_P2P_6G
11119 #define WL_HE_FEATURES_P2P_6G	0x0200u
11120 static int
wl_android_enable_p2p_6g(struct net_device * dev,int enable)11121 wl_android_enable_p2p_6g(struct net_device *dev, int enable)
11122 {
11123 	s32 err = 0;
11124 	s32 bssidx = 0;
11125 	struct bcm_cfg80211 *cfg = NULL;
11126 
11127 	if (!dev) {
11128 		err = -EINVAL;
11129 		return err;
11130 	}
11131 
11132 	cfg = wl_get_cfg(dev);
11133 	if (!cfg) {
11134 		err = -EINVAL;
11135 		return err;
11136 	}
11137 
11138 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11139 		ANDROID_ERROR(("find softap index from wdev failed\n"));
11140 		err = -EINVAL;
11141 		return err;
11142 	}
11143 
11144 	/* Enable/disable for P2P 6G, both P2P and P2P_6G needs to be handled together */
11145 	err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, (WL_HE_FEATURES_HE_P2P |
11146 		WL_HE_FEATURES_P2P_6G), (bool)enable);
11147 	if (err == BCME_OK) {
11148 		/* Set P2P 6G support flag */
11149 		if (enable) {
11150 			cfg->p2p_6g_enabled = TRUE;
11151 		} else {
11152 			cfg->p2p_6g_enabled = FALSE;
11153 		}
11154 	}
11155 
11156 	return err;
11157 }
11158 #endif /* WL_P2P_6G */
11159 
11160 #ifdef WL_TWT
11161 
11162 static int
wl_android_twt_setup(struct net_device * ndev,char * command,int total_len)11163 wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
11164 {
11165 	wl_twt_config_t val;
11166 	s32 bw;
11167 	char *token, *pos;
11168 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11169 	u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
11170 	u64 twt;
11171 	uint8 *rem = mybuf;
11172 	uint16 rem_len = sizeof(mybuf);
11173 	int32 val32;
11174 
11175 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11176 
11177 	if (strlen(command) == strlen(CMD_TWT_SETUP)) {
11178 		ANDROID_ERROR(("Error, twt_setup cmd  missing params\n"));
11179 		bw = -EINVAL;
11180 		goto exit;
11181 	}
11182 
11183 	bzero(&val, sizeof(val));
11184 	val.version = WL_TWT_SETUP_VER;
11185 	val.length = sizeof(val.version) + sizeof(val.length);
11186 
11187 	/* Default values, Overide Below */
11188 	val.desc.wake_time_h = 0xFFFFFFFF;
11189 	val.desc.wake_time_l = 0xFFFFFFFF;
11190 	val.desc.wake_int_min = 0xFFFFFFFF;
11191 	val.desc.wake_int_max = 0xFFFFFFFF;
11192 	val.desc.wake_dur_min = 0xFFFFFFFF;
11193 	val.desc.wake_dur_max = 0xFFFFFFFF;
11194 	val.desc.avg_pkt_num  = 0xFFFFFFFF;
11195 
11196 	pos = command + sizeof(CMD_TWT_SETUP);
11197 
11198 	/* negotiation_type */
11199 	token = strsep((char**)&pos, " ");
11200 	if (!token) {
11201 		ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11202 		bw = -EINVAL;
11203 		goto exit;
11204 	}
11205 	val.desc.negotiation_type  = htod32((u32)bcm_atoi(token));
11206 
11207 	/* Wake Duration */
11208 	token = strsep((char**)&pos, " ");
11209 	if (!token) {
11210 		ANDROID_ERROR(("Mandatory param wake Duration not present\n"));
11211 		bw = -EINVAL;
11212 		goto exit;
11213 	}
11214 	val.desc.wake_dur = htod32((u32)bcm_atoi(token));
11215 
11216 	/* Wake interval */
11217 	token = strsep((char**)&pos, " ");
11218 	if (!token) {
11219 		ANDROID_ERROR(("Mandaory param Wake Interval not present\n"));
11220 		bw = -EINVAL;
11221 		goto exit;
11222 	}
11223 	val.desc.wake_int = htod32((u32)bcm_atoi(token));
11224 
11225 	/* Wake Time parameter */
11226 	token = strsep((char**)&pos, " ");
11227 	if (!token) {
11228 		ANDROID_ERROR(("No Wake Time parameter provided, using default\n"));
11229 	} else {
11230 		twt = (u64)bcm_atoi(token);
11231 		val32 = htod32((u32)(twt >> 32));
11232 		if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11233 			val.desc.wake_time_h = htod32((u32)(twt >> 32));
11234 			val.desc.wake_time_l = htod32((u32)twt);
11235 		}
11236 	}
11237 
11238 	/* Minimum allowed Wake interval */
11239 	token = strsep((char**)&pos, " ");
11240 	if (!token) {
11241 		ANDROID_ERROR(("No Minimum allowed Wake interval provided, using default\n"));
11242 	} else {
11243 		val32 = htod32((u32)bcm_atoi(token));
11244 		if (val32 != -1) {
11245 			val.desc.wake_int_min = htod32((u32)bcm_atoi(token));
11246 		}
11247 	}
11248 
11249 	/* Max Allowed Wake interval */
11250 	token = strsep((char**)&pos, " ");
11251 	if (!token) {
11252 		ANDROID_ERROR(("Maximum allowed Wake interval not provided, using default\n"));
11253 	} else {
11254 		val32 = htod32((u32)bcm_atoi(token));
11255 		if (val32 != -1) {
11256 			val.desc.wake_int_max = htod32((u32)bcm_atoi(token));
11257 		}
11258 	}
11259 
11260 	/* Minimum allowed Wake duration */
11261 	token = strsep((char**)&pos, " ");
11262 	if (!token) {
11263 		ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
11264 	} else {
11265 		val32 = htod32((u32)bcm_atoi(token));
11266 		if (val32 != -1) {
11267 			val.desc.wake_dur_min = htod32((u32)bcm_atoi(token));
11268 		}
11269 	}
11270 
11271 	/* Maximum allowed Wake duration */
11272 	token = strsep((char**)&pos, " ");
11273 	if (!token) {
11274 		ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
11275 	} else {
11276 		val32 = htod32((u32)bcm_atoi(token));
11277 		if (val32 != -1) {
11278 			val.desc.wake_dur_max = htod32((u32)bcm_atoi(token));
11279 		}
11280 	}
11281 
11282 	/* Average number of packets */
11283 	token = strsep((char**)&pos, " ");
11284 	if (!token) {
11285 		ANDROID_ERROR(("Average number of packets not provided, using default\n"));
11286 	} else {
11287 		val32 = htod32((u32)bcm_atoi(token));
11288 		if (val32 != -1) {
11289 			val.desc.avg_pkt_num  = htod32((u32)bcm_atoi(token));
11290 		}
11291 	}
11292 
11293 	/* a peer_address */
11294 	token = strsep((char**)&pos, " ");
11295 	if (!token) {
11296 		ANDROID_ERROR(("Average number of packets not provided, using default\n"));
11297 	} else {
11298 		/* get peer mac */
11299 		if (!bcm_ether_atoe(token, &val.peer)) {
11300 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11301 			bw = BCME_ERROR;
11302 			goto exit;
11303 		}
11304 	}
11305 
11306 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
11307 			sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11308 	if (bw != BCME_OK) {
11309 		goto exit;
11310 	}
11311 
11312 	bw = wldev_iovar_setbuf(ndev, "twt",
11313 		mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
11314 	if (bw < 0) {
11315 		ANDROID_ERROR(("twt config set failed. ret:%d\n", bw));
11316 	}
11317 exit:
11318 	return bw;
11319 }
11320 
11321 static int
wl_android_twt_display_cap(wl_twt_cap_t * result,char * command,int total_len)11322 wl_android_twt_display_cap(wl_twt_cap_t *result, char *command, int total_len)
11323 {
11324 	int rem_len = 0, bytes_written = 0;
11325 
11326 	rem_len = total_len;
11327 	bytes_written = scnprintf(command, rem_len, "Device TWT Capabilities:\n");
11328 	command += bytes_written;
11329 	rem_len -= bytes_written;
11330 
11331 	bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11332 			!!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11333 	command += bytes_written;
11334 	rem_len -= bytes_written;
11335 
11336 	bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11337 			!!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11338 	command += bytes_written;
11339 	rem_len -= bytes_written;
11340 
11341 	bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11342 			!!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11343 	command += bytes_written;
11344 	rem_len -= bytes_written;
11345 
11346 	bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11347 			!!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11348 	command += bytes_written;
11349 	rem_len -= bytes_written;
11350 
11351 	bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11352 			!!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11353 	command += bytes_written;
11354 	rem_len -= bytes_written;
11355 
11356 	/* Peer capabilities */
11357 	bytes_written = scnprintf(command, rem_len, "\nPeer TWT Capabilities:\n");
11358 	command += bytes_written;
11359 	rem_len -= bytes_written;
11360 
11361 	bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11362 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11363 	command += bytes_written;
11364 	rem_len -= bytes_written;
11365 
11366 	bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11367 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11368 	command += bytes_written;
11369 	rem_len -= bytes_written;
11370 
11371 	bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11372 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11373 	command += bytes_written;
11374 	rem_len -= bytes_written;
11375 
11376 	bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11377 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11378 	command += bytes_written;
11379 	rem_len -= bytes_written;
11380 
11381 	bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11382 			!!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11383 	command += bytes_written;
11384 	rem_len -= bytes_written;
11385 
11386 	bytes_written = scnprintf(command, rem_len, "\t------------"
11387 		"---------------------------------------------------\n\n");
11388 	command += bytes_written;
11389 	rem_len -= bytes_written;
11390 	ANDROID_INFO(("Device TWT Capabilities:\n"));
11391 	ANDROID_INFO(("Requester Support %d, \t",
11392 		!!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11393 	ANDROID_INFO(("Responder Support %d, \t",
11394 		!!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11395 	ANDROID_INFO(("Broadcast TWT Support %d, \t",
11396 		!!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11397 	ANDROID_INFO(("Flexible TWT Support %d, \t",
11398 		!!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11399 	ANDROID_INFO(("TWT Required by peer %d, \n",
11400 		!!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11401 	/* Peer capabilities */
11402 	ANDROID_INFO(("\nPeer TWT Capabilities:\n"));
11403 	ANDROID_INFO(("Requester Support %d, \t",
11404 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11405 	ANDROID_INFO(("Responder Support %d, \t",
11406 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11407 	ANDROID_INFO(("Broadcast TWT Support %d, \t",
11408 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11409 	ANDROID_INFO(("Flexible TWT Support %d, \t",
11410 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11411 	ANDROID_INFO(("TWT Required by peer %d, \n",
11412 		!!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11413 	ANDROID_INFO(("\t-----------------------------------------------------------------\n\n"));
11414 
11415 	if ((total_len - rem_len) > 0) {
11416 		return (total_len - rem_len);
11417 	} else {
11418 		return BCME_ERROR;
11419 	}
11420 }
11421 
11422 static int
wl_android_twt_cap(struct net_device * dev,char * command,int total_len)11423 wl_android_twt_cap(struct net_device *dev, char *command, int total_len)
11424 {
11425 	int ret = BCME_OK;
11426 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11427 	uint8 *pxtlv = NULL;
11428 	uint8 *iovresp = NULL;
11429 	wl_twt_cap_cmd_t cmd_cap;
11430 	wl_twt_cap_t result;
11431 
11432 	uint16 buflen = 0, bufstart = 0;
11433 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11434 
11435 	bzero(&cmd_cap, sizeof(cmd_cap));
11436 
11437 	cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
11438 	cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
11439 
11440 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11441 	if (iovresp == NULL) {
11442 		ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11443 		goto exit;
11444 	}
11445 
11446 	buflen = bufstart = WLC_IOCTL_SMLEN;
11447 	pxtlv = (uint8 *)iovbuf;
11448 
11449 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
11450 			sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
11451 	if (ret != BCME_OK) {
11452 		ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11453 		goto exit;
11454 	}
11455 
11456 	if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11457 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11458 		ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11459 		goto exit;
11460 	}
11461 	if (ret) {
11462 		ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11463 	}
11464 
11465 	(void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11466 
11467 	if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
11468 		ANDROID_ERROR(("capability ver %d, \n", dtoh16(result.version)));
11469 		ret = wl_android_twt_display_cap(&result, command, total_len);
11470 		return ret;
11471 	} else {
11472 		ret = BCME_UNSUPPORTED;
11473 		ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11474 		goto exit;
11475 	}
11476 
11477 exit:
11478 	if (iovresp) {
11479 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11480 	}
11481 
11482 	return ret;
11483 }
11484 
11485 static int
wl_android_twt_status_display_v1(wl_twt_status_v1_t * status,char * command,int total_len)11486 wl_android_twt_status_display_v1(wl_twt_status_v1_t *status, char *command, int total_len)
11487 {
11488 	uint i;
11489 	wl_twt_sdesc_t *desc = NULL;
11490 	int rem_len = 0, bytes_written = 0;
11491 
11492 	rem_len = total_len;
11493 
11494 	ANDROID_ERROR(("\nNumber of Individual TWTs: %d\n", status->num_fid));
11495 	bytes_written = scnprintf(command, rem_len,
11496 			"\nNumber of Individual TWTs: %d\n", status->num_fid);
11497 	command += bytes_written;
11498 	rem_len -= bytes_written;
11499 	bytes_written = scnprintf(command, rem_len,
11500 			"Number of Broadcast TWTs: %d\n", status->num_bid);
11501 	command += bytes_written;
11502 	rem_len -= bytes_written;
11503 	bytes_written = scnprintf(command, rem_len,
11504 			"TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11505 			!!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11506 			!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11507 			!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE));
11508 	command += bytes_written;
11509 	rem_len -= bytes_written;
11510 	ANDROID_INFO(("Number of Broadcast TWTs: %d\n", status->num_bid));
11511 	ANDROID_INFO(("TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11512 		!!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11513 		!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11514 		!!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE)));
11515 	ANDROID_INFO(("\t---------------- Individual TWT list-------------------\n"));
11516 	bytes_written = scnprintf(command, rem_len,
11517 			"\t---------------- Individual TWT list-------------------\n");
11518 	command += bytes_written;
11519 	rem_len -= bytes_written;
11520 
11521 	for (i = 0; i < WL_TWT_MAX_ITWT; i ++) {
11522 		if ((status->itwt_status[i].state == WL_TWT_ACTIVE) ||
11523 			(status->itwt_status[i].state == WL_TWT_SUSPEND)) {
11524 			desc = &status->itwt_status[i].desc;
11525 			bytes_written = scnprintf(command, rem_len, "\tFlow ID %d \tState %d\t",
11526 					desc->flow_id,
11527 					status->itwt_status[i].state);
11528 			command += bytes_written;
11529 			rem_len -= bytes_written;
11530 
11531 			bytes_written = scnprintf(command, rem_len,
11532 					"peer: "MACF"\n",
11533 					ETHER_TO_MACF(status->itwt_status[i].peer));
11534 			command += bytes_written;
11535 			rem_len -= bytes_written;
11536 
11537 			bytes_written = scnprintf(command, rem_len,
11538 					"Unannounced %d\tTriggered %d\tProtection %d\t"
11539 					"Info Frame Disabled %d\n",
11540 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11541 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11542 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11543 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11544 			command += bytes_written;
11545 			rem_len -= bytes_written;
11546 
11547 			bytes_written = scnprintf(command, rem_len,
11548 					"target wake time: 0x%08x%08x\t",
11549 					desc->wake_time_h, desc->wake_time_l);
11550 			command += bytes_written;
11551 			rem_len -= bytes_written;
11552 
11553 			bytes_written = scnprintf(command, rem_len,
11554 					"wake duration: %u\t", desc->wake_dur);
11555 			command += bytes_written;
11556 			rem_len -= bytes_written;
11557 
11558 			bytes_written = scnprintf(command, rem_len,
11559 					"wake interval: %u\t", desc->wake_int);
11560 			command += bytes_written;
11561 			rem_len -= bytes_written;
11562 
11563 			bytes_written = scnprintf(command, rem_len,
11564 					"TWT channel: %u\n", desc->channel);
11565 			command += bytes_written;
11566 			rem_len -= bytes_written;
11567 			ANDROID_INFO(("\tFlow ID %d \tState %d\t",
11568 				desc->flow_id,
11569 				status->itwt_status[i].state));
11570 			ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->itwt_status[i].peer)));
11571 			ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11572 				"Info Frame Disabled %d\n",
11573 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11574 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11575 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11576 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11577 			ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11578 				desc->wake_time_h, desc->wake_time_l));
11579 			ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11580 			ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11581 			ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11582 		}
11583 	}
11584 
11585 	ANDROID_INFO(("\t---------------- Broadcast TWT list-------------------\n"));
11586 	bytes_written = scnprintf(command, rem_len,
11587 			"\t---------------- Broadcast TWT list-------------------\n");
11588 	command += bytes_written;
11589 	rem_len -= bytes_written;
11590 	for (i = 0; i < WL_TWT_MAX_BTWT; i ++) {
11591 		if ((status->btwt_status[i].state == WL_TWT_ACTIVE) ||
11592 			(status->btwt_status[i].state == WL_TWT_SUSPEND)) {
11593 			desc = &status->btwt_status[i].desc;
11594 			bytes_written = scnprintf(command, rem_len,
11595 					"Broadcast ID %d \tState %d\t",
11596 					desc->bid, status->btwt_status[i].state);
11597 			command += bytes_written;
11598 			rem_len -= bytes_written;
11599 
11600 			bytes_written = scnprintf(command, rem_len,
11601 					"peer: "MACF"\n",
11602 					ETHER_TO_MACF(status->btwt_status[i].peer));
11603 			command += bytes_written;
11604 			rem_len -= bytes_written;
11605 
11606 			bytes_written = scnprintf(command, rem_len,
11607 					"Unannounced %d\tTriggered %d\tProtection %d\t"
11608 					"Info Frame Disabled %d\t",
11609 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11610 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11611 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11612 					!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11613 			command += bytes_written;
11614 			rem_len -= bytes_written;
11615 
11616 			bytes_written = scnprintf(command, rem_len,
11617 					"Frame Recommendation %d\tBTWT Persistence %d\n",
11618 					desc->frame_recomm, desc->btwt_persistence);
11619 			command += bytes_written;
11620 			rem_len -= bytes_written;
11621 
11622 			bytes_written = scnprintf(command, rem_len,
11623 					"target wake time: 0x%08x%08x\t",
11624 					desc->wake_time_h, desc->wake_time_l);
11625 			command += bytes_written;
11626 			rem_len -= bytes_written;
11627 			bytes_written = scnprintf(command, rem_len,
11628 					"wake duration: %u\t", desc->wake_dur);
11629 			command += bytes_written;
11630 			rem_len -= bytes_written;
11631 
11632 			bytes_written = scnprintf(command, rem_len,
11633 					"wake interval: %u\t", desc->wake_int);
11634 			command += bytes_written;
11635 			rem_len -= bytes_written;
11636 
11637 			bytes_written = scnprintf(command, rem_len,
11638 					"TWT channel: %u\n", desc->channel);
11639 			command += bytes_written;
11640 			rem_len -= bytes_written;
11641 			ANDROID_INFO(("Broadcast ID %d \tState %d\t",
11642 				desc->bid, status->btwt_status[i].state));
11643 			ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->btwt_status[i].peer)));
11644 			ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11645 				"Info Frame Disabled %d\t",
11646 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11647 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11648 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11649 				!!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11650 			ANDROID_INFO(("Frame Recommendation %d\tBTWT Persistence %d\n",
11651 				desc->frame_recomm, desc->btwt_persistence));
11652 			ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11653 				desc->wake_time_h, desc->wake_time_l));
11654 			ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11655 			ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11656 			ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11657 		}
11658 	}
11659 
11660 	if ((total_len - rem_len) > 0) {
11661 		return (total_len - rem_len);
11662 	} else {
11663 		return BCME_ERROR;
11664 	}
11665 }
11666 
11667 static int
wl_android_twt_status_query(struct net_device * dev,char * command,int total_len)11668 wl_android_twt_status_query(struct net_device *dev, char *command, int total_len)
11669 {
11670 	int ret = BCME_OK;
11671 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11672 	uint8 *pxtlv = NULL;
11673 	uint8 *iovresp = NULL;
11674 	wl_twt_status_cmd_v1_t status_cmd;
11675 	wl_twt_status_v1_t result;
11676 
11677 	uint16 buflen = 0, bufstart = 0;
11678 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11679 
11680 	bzero(&status_cmd, sizeof(status_cmd));
11681 
11682 	status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1;
11683 	status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer);
11684 
11685 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11686 	if (iovresp == NULL) {
11687 		ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11688 		goto exit;
11689 	}
11690 
11691 	buflen = bufstart = WLC_IOCTL_SMLEN;
11692 	pxtlv = (uint8 *)iovbuf;
11693 
11694 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS,
11695 			sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32);
11696 	if (ret != BCME_OK) {
11697 		ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11698 		goto exit;
11699 	}
11700 
11701 	if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11702 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11703 		ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11704 		goto exit;
11705 	}
11706 	if (ret) {
11707 		ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11708 	}
11709 
11710 	(void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11711 
11712 	if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) {
11713 		ANDROID_ERROR(("status query ver %d, \n", dtoh16(result.version)));
11714 		ret = wl_android_twt_status_display_v1(&result, command, total_len);
11715 		return ret;
11716 	} else {
11717 		ret = BCME_UNSUPPORTED;
11718 		ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11719 		goto exit;
11720 	}
11721 
11722 exit:
11723 	if (iovresp) {
11724 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11725 	}
11726 
11727 	return ret;
11728 }
11729 
11730 static int
wl_android_twt_info(struct net_device * ndev,char * command,int total_len)11731 wl_android_twt_info(struct net_device *ndev, char *command, int total_len)
11732 {
11733 	wl_twt_info_t val;
11734 	s32 bw;
11735 	char *token, *pos;
11736 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11737 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11738 	u64 twt;
11739 	uint8 *rem = mybuf;
11740 	uint16 rem_len = sizeof(mybuf);
11741 	int32 val32;
11742 
11743 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11744 
11745 	if (strlen(command) == strlen(CMD_TWT_INFO)) {
11746 		ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11747 		bw = -EINVAL;
11748 		goto exit;
11749 	}
11750 
11751 	bzero(&val, sizeof(val));
11752 	val.version = WL_TWT_INFO_VER;
11753 	val.length = sizeof(val.version) + sizeof(val.length);
11754 
11755 	/* Default values, Overide Below */
11756 	val.infodesc.flow_id = 0xFF;
11757 	val.desc.next_twt_h = 0xFFFFFFFF;
11758 	val.desc.next_twt_l = 0xFFFFFFFF;
11759 
11760 	pos = command + sizeof(CMD_TWT_TEARDOWN);
11761 
11762 	/* (all TWT) */
11763 	token = strsep((char**)&pos, " ");
11764 	if (!token) {
11765 		ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11766 		bw = -EINVAL;
11767 		goto exit;
11768 	}
11769 	if (htod32((u32)bcm_atoi(token)) == 1) {
11770 		val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
11771 	}
11772 
11773 	/* Flow ID */
11774 	token = strsep((char**)&pos, " ");
11775 	if (!token) {
11776 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11777 	} else {
11778 		val32 = htod32((u32)bcm_atoi(token));
11779 		if (val32 != -1) {
11780 			val.infodesc.flow_id = htod32((u32)bcm_atoi(token));
11781 		}
11782 	}
11783 
11784 	/* resume offset */
11785 	token = strsep((char**)&pos, " ");
11786 	if (!token) {
11787 		ANDROID_ERROR(("resume offset not provided, using default\n"));
11788 	} else {
11789 		twt = (u64)bcm_atoi(token);
11790 		val32 = htod32((u32)(twt >> 32));
11791 		if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11792 			val.infodesc.next_twt_h = htod32((u32)(twt >> 32));
11793 			val.infodesc.next_twt_l = htod32((u32)twt);
11794 			val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
11795 		}
11796 	}
11797 
11798 	/* peer_address */
11799 	token = strsep((char**)&pos, " ");
11800 	if (!token) {
11801 		ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11802 	} else {
11803 		/* get peer mac */
11804 		if (!bcm_ether_atoe(token, &val.peer)) {
11805 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11806 			bw = BCME_ERROR;
11807 			goto exit;
11808 		}
11809 	}
11810 
11811 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
11812 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11813 	if (bw != BCME_OK) {
11814 		goto exit;
11815 	}
11816 
11817 	bw = wldev_iovar_setbuf(ndev, "twt",
11818 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11819 	if (bw < 0) {
11820 		ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11821 	}
11822 exit:
11823 	return bw;
11824 
11825 }
11826 
11827 static int
wl_android_twt_teardown(struct net_device * ndev,char * command,int total_len)11828 wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len)
11829 {
11830 	wl_twt_teardown_t val;
11831 	s32 bw;
11832 	char *token, *pos;
11833 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11834 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11835 	uint8 *rem = mybuf;
11836 	uint16 rem_len = sizeof(mybuf);
11837 	int32 val32;
11838 
11839 	WL_DBG_MEM(("Enter. cmd:%s\n", command));
11840 
11841 	if (strlen(command) == strlen(CMD_TWT_TEARDOWN)) {
11842 		ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11843 		bw = -EINVAL;
11844 		goto exit;
11845 	}
11846 
11847 	bzero(&val, sizeof(val));
11848 	val.version = WL_TWT_TEARDOWN_VER;
11849 	val.length = sizeof(val.version) + sizeof(val.length);
11850 
11851 	/* Default values, Overide Below */
11852 	val.teardesc.flow_id = 0xFF;
11853 	val.teardesc.bid = 0xFF;
11854 
11855 	pos = command + sizeof(CMD_TWT_TEARDOWN);
11856 
11857 	/* negotiation_type */
11858 	token = strsep((char**)&pos, " ");
11859 	if (!token) {
11860 		ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11861 		bw = -EINVAL;
11862 		goto exit;
11863 	}
11864 	val.teardesc.negotiation_type  = htod32((u32)bcm_atoi(token));
11865 
11866 	/* (all TWT) */
11867 	token = strsep((char**)&pos, " ");
11868 	if (!token) {
11869 		ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11870 		bw = -EINVAL;
11871 		goto exit;
11872 	}
11873 	val.teardesc.alltwt = htod32((u32)bcm_atoi(token));
11874 
11875 	/* Flow ID */
11876 	token = strsep((char**)&pos, " ");
11877 	if (!token) {
11878 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11879 	} else {
11880 		val32 = htod32((u32)bcm_atoi(token));
11881 		if (val32 != -1) {
11882 			val.teardesc.flow_id = htod32((u32)bcm_atoi(token));
11883 		}
11884 	}
11885 
11886 	/* Broadcas ID */
11887 	token = strsep((char**)&pos, " ");
11888 	if (!token) {
11889 		ANDROID_ERROR(("flow ID  not provided, using default\n"));
11890 	} else {
11891 		val32 = htod32((u32)bcm_atoi(token));
11892 		if (val32 != -1) {
11893 			val.teardesc.bid = htod32((u32)bcm_atoi(token));
11894 		}
11895 	}
11896 
11897 	/* peer_address */
11898 	token = strsep((char**)&pos, " ");
11899 	if (!token) {
11900 		ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11901 	} else {
11902 		/* get peer mac */
11903 		if (!bcm_ether_atoe(token, &val.peer)) {
11904 			ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11905 			bw = BCME_ERROR;
11906 			goto exit;
11907 		}
11908 	}
11909 
11910 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
11911 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11912 	if (bw != BCME_OK) {
11913 		goto exit;
11914 	}
11915 
11916 	bw = wldev_iovar_setbuf(ndev, "twt",
11917 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11918 	if (bw < 0) {
11919 		ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11920 	}
11921 exit:
11922 	return bw;
11923 }
11924 #endif /* WL_TWT */
11925 
11926 int
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)11927 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
11928 {
11929 	int bytes_written = 0;
11930 	android_wifi_priv_cmd priv_cmd;
11931 
11932 	bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
11933 	priv_cmd.total_len = cmd_len;
11934 
11935 	if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
11936 		ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
11937 #ifdef SUPPORT_DEEP_SLEEP
11938 		trigger_deep_sleep = 1;
11939 #else
11940 #ifdef  BT_OVER_SDIO
11941 		bytes_written = dhd_net_bus_get(net);
11942 #else
11943 		bytes_written = wl_android_wifi_on(net);
11944 #endif /* BT_OVER_SDIO */
11945 #endif /* SUPPORT_DEEP_SLEEP */
11946 	}
11947 	else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
11948 		bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
11949 	}
11950 
11951 	if (!g_wifi_on) {
11952 		ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
11953 			__FUNCTION__, command));
11954 		return 0;
11955 	}
11956 
11957 	if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
11958 #ifdef SUPPORT_DEEP_SLEEP
11959 		trigger_deep_sleep = 1;
11960 #else
11961 #ifdef  BT_OVER_SDIO
11962 		bytes_written = dhd_net_bus_put(net);
11963 #else
11964 		bytes_written = wl_android_wifi_off(net, FALSE);
11965 #endif /* BT_OVER_SDIO */
11966 #endif /* SUPPORT_DEEP_SLEEP */
11967 	}
11968 #ifdef WL_CFG80211
11969 	else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
11970 		wl_cfg80211_set_passive_scan(net, command);
11971 	}
11972 	else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
11973 		wl_cfg80211_set_passive_scan(net, command);
11974 	}
11975 #endif /* WL_CFG80211 */
11976 	else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
11977 		bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
11978 	}
11979 	else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
11980 		bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
11981 	}
11982 #ifdef PKT_FILTER_SUPPORT
11983 	else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
11984 		bytes_written = net_os_enable_packet_filter(net, 1);
11985 	}
11986 	else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
11987 		bytes_written = net_os_enable_packet_filter(net, 0);
11988 	}
11989 	else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
11990 		int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
11991 		bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
11992 	}
11993 	else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
11994 		int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
11995 		bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
11996 	}
11997 #endif /* PKT_FILTER_SUPPORT */
11998 	else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
11999 		/* TBD: BTCOEXSCAN-START */
12000 	}
12001 	else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
12002 		/* TBD: BTCOEXSCAN-STOP */
12003 	}
12004 	else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
12005 #ifdef WL_CFG80211
12006 		void *dhdp = wl_cfg80211_get_dhdp(net);
12007 		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
12008 #else
12009 #ifdef PKT_FILTER_SUPPORT
12010 		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
12011 
12012 		if (mode == 1)
12013 			net_os_enable_packet_filter(net, 0); /* DHCP starts */
12014 		else
12015 			net_os_enable_packet_filter(net, 1); /* DHCP ends */
12016 #endif /* PKT_FILTER_SUPPORT */
12017 #endif /* WL_CFG80211 */
12018 	}
12019 	else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
12020 		bytes_written = wl_android_set_suspendopt(net, command);
12021 	}
12022 	else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
12023 		bytes_written = wl_android_set_suspendmode(net, command);
12024 	}
12025 	else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
12026 		bytes_written = wl_android_set_bcn_li_dtim(net, command);
12027 	}
12028 	else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
12029 		bytes_written = wl_android_set_max_dtim(net, command);
12030 	}
12031 #ifdef DISABLE_DTIM_IN_SUSPEND
12032 	else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
12033 		bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
12034 	}
12035 #endif /* DISABLE_DTIM_IN_SUSPEND */
12036 #ifdef WL_CFG80211
12037 	else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
12038 		bytes_written = wl_android_set_band(net, command);
12039 	}
12040 #endif /* WL_CFG80211 */
12041 	else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
12042 		bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
12043 	}
12044 #ifdef WL_CFG80211
12045 	else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
12046 		bytes_written = wl_android_set_csa(net, command);
12047 	} else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
12048 		bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
12049 	} else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
12050 		bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
12051 	}
12052 #endif /* WL_CFG80211 */
12053 #ifndef CUSTOMER_SET_COUNTRY
12054 	/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
12055 	else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
12056 		/*
12057 		 * Usage examples:
12058 		 * DRIVER COUNTRY US
12059 		 * DRIVER COUNTRY US/7
12060 		 * Wrong revinfo should be filtered:
12061 		 * DRIVER COUNTRY US/-1
12062 		 */
12063 		char *country_code = command + strlen(CMD_COUNTRY) + 1;
12064 		char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
12065 		int revinfo = -1;
12066 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12067 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12068 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12069 		if ((rev_info_delim) &&
12070 			(strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
12071 			strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
12072 			(rev_info_delim + 1)) {
12073 			revinfo  = bcm_atoi(rev_info_delim + 1);
12074 		} else {
12075 			revinfo = 0;
12076 		}
12077 
12078 		if (revinfo < 0) {
12079 			ANDROID_ERROR(("%s:failed due to wrong revinfo %d\n", __FUNCTION__, revinfo));
12080 			return BCME_BADARG;
12081 		}
12082 
12083 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12084 		if (dhdp->is_blob) {
12085 			revinfo = 0;
12086 		}
12087 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12088 
12089 #ifdef WL_CFG80211
12090 		bytes_written = wl_cfg80211_set_country_code(net, country_code,
12091 				true, true, revinfo);
12092 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12093 #ifdef FCC_PWR_LIMIT_2G
12094 		if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
12095 			ANDROID_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
12096 		} else {
12097 			ANDROID_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
12098 		}
12099 #endif /* FCC_PWR_LIMIT_2G */
12100 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12101 #else
12102 		bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
12103 #endif /* WL_CFG80211 */
12104 	}
12105 #endif /* CUSTOMER_SET_COUNTRY */
12106 	else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
12107 		bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
12108 	} else if (strnicmp(command, CMD_ASSOC_CLIENTS,	strlen(CMD_ASSOC_CLIENTS)) == 0) {
12109 		bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
12110 	}
12111 
12112 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12113 	else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_SET, strlen(CMD_ROAM_VSIE_ENAB_SET)) == 0) {
12114 		bytes_written = wl_android_set_roam_vsie_enab(net, command, priv_cmd.total_len);
12115 	} else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_GET, strlen(CMD_ROAM_VSIE_ENAB_GET)) == 0) {
12116 		bytes_written = wl_android_get_roam_vsie_enab(net, command, priv_cmd.total_len);
12117 	} else if (strnicmp(command, CMD_BR_VSIE_ENAB_SET, strlen(CMD_BR_VSIE_ENAB_SET)) == 0) {
12118 		bytes_written = wl_android_set_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12119 	} else if (strnicmp(command, CMD_BR_VSIE_ENAB_GET, strlen(CMD_BR_VSIE_ENAB_GET)) == 0) {
12120 		bytes_written = wl_android_get_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12121 	}
12122 #ifdef WES_SUPPORT
12123 	else if (strnicmp(command, CMD_GETNCHOMODE, strlen(CMD_GETNCHOMODE)) == 0) {
12124 		bytes_written = wl_android_get_ncho_mode(net, command, priv_cmd.total_len);
12125 	}
12126 	else if (strnicmp(command, CMD_SETNCHOMODE, strlen(CMD_SETNCHOMODE)) == 0) {
12127 		int mode;
12128 		sscanf(command, "%*s %d", &mode);
12129 		bytes_written = wl_android_set_ncho_mode(net, mode);
12130 	}
12131 	else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
12132 		bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
12133 	}
12134 	else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
12135 		bytes_written = wl_android_okc_enable(net, command);
12136 	}
12137 	else if (wl_android_legacy_check_command(net, command)) {
12138 		bytes_written = wl_android_legacy_private_command(net, command, priv_cmd.total_len);
12139 	}
12140 	else if (wl_android_ncho_check_command(net, command)) {
12141 		bytes_written = wl_android_ncho_private_command(net, command, priv_cmd.total_len);
12142 	}
12143 #endif /* WES_SUPPORT */
12144 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
12145 	else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
12146 		bytes_written = wl_android_default_set_scan_params(net, command,
12147 			priv_cmd.total_len);
12148 	}
12149 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
12150 #ifdef WLTDLS
12151 	else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
12152 		bytes_written = wl_android_tdls_reset(net);
12153 	}
12154 #endif /* WLTDLS */
12155 #ifdef CONFIG_SILENT_ROAM
12156 	else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) {
12157 		int mode = *(command + strlen(CMD_SROAM_TURN_ON) + 1) - '0';
12158 		bytes_written = wl_android_sroam_turn_on(net, mode);
12159 	}
12160 	else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) {
12161 		char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1);
12162 		bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len);
12163 	}
12164 	else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) {
12165 		bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len);
12166 	}
12167 #endif /* CONFIG_SILENT_ROAM */
12168 #ifdef CONFIG_ROAM_RSSI_LIMIT
12169 	else if (strnicmp(command, CMD_ROAM_RSSI_LMT, strlen(CMD_ROAM_RSSI_LMT)) == 0) {
12170 		bytes_written = wl_android_roam_rssi_limit(net, command, priv_cmd.total_len);
12171 	}
12172 #endif /* CONFIG_ROAM_RSSI_LIMIT */
12173 #ifdef CONFIG_ROAM_MIN_DELTA
12174 	else if (strnicmp(command, CMD_ROAM_MIN_DELTA, strlen(CMD_ROAM_MIN_DELTA)) == 0) {
12175 		bytes_written = wl_android_roam_min_delta(net, command, priv_cmd.total_len);
12176 	}
12177 #endif /* CONFIG_ROAM_MIN_DELTA */
12178 	else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) {
12179 		bytes_written = wl_android_set_disconnect_ies(net, command);
12180 	}
12181 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12182 
12183 #ifdef PNO_SUPPORT
12184 	else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
12185 		bytes_written = dhd_dev_pno_stop_for_ssid(net);
12186 	}
12187 #ifndef WL_SCHED_SCAN
12188 	else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
12189 		bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
12190 	}
12191 #endif /* !WL_SCHED_SCAN */
12192 	else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
12193 		int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
12194 		bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
12195 	}
12196 	else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
12197 		bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
12198 	}
12199 #endif /* PNO_SUPPORT */
12200 	else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
12201 		bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
12202 	}
12203 	else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
12204 		int skip = strlen(CMD_P2P_SET_NOA) + 1;
12205 		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
12206 			priv_cmd.total_len - skip);
12207 	}
12208 #ifdef WL_SDO
12209 	else if (strnicmp(command, CMD_P2P_SD_OFFLOAD, strlen(CMD_P2P_SD_OFFLOAD)) == 0) {
12210 		u8 *buf = command;
12211 		u8 *cmd_id = NULL;
12212 		int len;
12213 
12214 		cmd_id = strsep((char **)&buf, " ");
12215 		if (!cmd_id) {
12216 			/* Propagate the error */
12217 			bytes_written = -EINVAL;
12218 		} else {
12219 			/* if buf == NULL, means no arg */
12220 			if (buf == NULL) {
12221 				len = 0;
12222 			} else {
12223 				len = strlen(buf);
12224 			}
12225 			bytes_written = wl_cfg80211_sd_offload(net, cmd_id, buf, len);
12226 		}
12227 	}
12228 #endif /* WL_SDO */
12229 #ifdef P2P_LISTEN_OFFLOADING
12230 	else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
12231 		u8 *sub_command = strchr(command, ' ');
12232 		bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
12233 				sub_command ? strlen(sub_command) : 0);
12234 	}
12235 #endif /* P2P_LISTEN_OFFLOADING */
12236 #if !defined WL_ENABLE_P2P_IF
12237 	else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
12238 		bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
12239 	}
12240 #endif /* WL_ENABLE_P2P_IF */
12241 	else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
12242 		int skip = strlen(CMD_P2P_SET_PS) + 1;
12243 		bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
12244 			priv_cmd.total_len - skip);
12245 	}
12246 	else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
12247 		int skip = strlen(CMD_P2P_ECSA) + 1;
12248 		bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
12249 			priv_cmd.total_len - skip);
12250 	}
12251 	/* This command is not for normal VSDB operation but for only specific P2P operation.
12252 	 * Ex) P2P OTA backup operation
12253 	 */
12254 	else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
12255 		int skip = strlen(CMD_P2P_INC_BW) + 1;
12256 		bytes_written = wl_cfg80211_increase_p2p_bw(net,
12257 				command + skip, priv_cmd.total_len - skip);
12258 	}
12259 #ifdef WL_CFG80211
12260 	else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
12261 		strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
12262 		int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
12263 		bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
12264 			priv_cmd.total_len - skip, *(command + skip - 2) - '0');
12265 	}
12266 #ifdef WLFBT
12267 	else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
12268 		bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
12269 	}
12270 #endif /* WLFBT */
12271 #endif /* WL_CFG80211 */
12272 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12273 	else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
12274 		strlen(CMD_GET_BEST_CHANNELS)) == 0) {
12275 		bytes_written = wl_android_get_best_channels(net, command,
12276 			priv_cmd.total_len);
12277 	}
12278 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12279 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12280 	else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
12281 		strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
12282 		int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
12283 		bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
12284 			priv_cmd.total_len);
12285 	}
12286 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12287 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12288 #ifdef SUPPORT_AMPDU_MPDU_CMD
12289 	/* CMD_AMPDU_MPDU */
12290 	else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
12291 		int skip = strlen(CMD_AMPDU_MPDU) + 1;
12292 		bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
12293 	}
12294 #endif /* SUPPORT_AMPDU_MPDU_CMD */
12295 #if defined (SUPPORT_HIDDEN_AP)
12296 	else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
12297 		strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
12298 		int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
12299 		wl_android_set_max_num_sta(net, (const char*)command+skip);
12300 	}
12301 	else if (strnicmp(command, CMD_SET_HAPD_SSID,
12302 		strlen(CMD_SET_HAPD_SSID)) == 0) {
12303 		int skip = strlen(CMD_SET_HAPD_SSID) + 3;
12304 		wl_android_set_ssid(net, (const char*)command+skip);
12305 	}
12306 	else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
12307 		strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
12308 		int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
12309 		wl_android_set_hide_ssid(net, (const char*)command+skip);
12310 	}
12311 #endif /* SUPPORT_HIDDEN_AP */
12312 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
12313 	else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
12314 		strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
12315 		int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
12316 		wl_android_sta_diassoc(net, (const char*)command+skip);
12317 	}
12318 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
12319 #ifdef SUPPORT_SET_LPC
12320 	else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
12321 		strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
12322 		int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
12323 		wl_android_set_lpc(net, (const char*)command+skip);
12324 	}
12325 #endif /* SUPPORT_SET_LPC */
12326 #ifdef SUPPORT_TRIGGER_HANG_EVENT
12327 	else if (strnicmp(command, CMD_TEST_FORCE_HANG,
12328 		strlen(CMD_TEST_FORCE_HANG)) == 0) {
12329 		int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
12330 		net_os_send_hang_message_reason(net, (const char*)command+skip);
12331 	}
12332 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
12333 	else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
12334 		bytes_written = wl_android_ch_res_rl(net, true);
12335 	else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
12336 		bytes_written = wl_android_ch_res_rl(net, false);
12337 #ifdef SUPPORT_LTECX
12338 	else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
12339 		int skip = strlen(CMD_LTECX_SET) + 1;
12340 		bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
12341 	}
12342 #endif /* SUPPORT_LTECX */
12343 #ifdef WL_RELMCAST
12344 	else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
12345 		int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
12346 		bytes_written = wl_android_rmc_enable(net, rmc_enable);
12347 	}
12348 	else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
12349 		int rmc_txrate;
12350 		sscanf(command, "%*s %10d", &rmc_txrate);
12351 		bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
12352 	}
12353 	else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
12354 		int actperiod;
12355 		sscanf(command, "%*s %10d", &actperiod);
12356 		bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
12357 	}
12358 	else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
12359 		int acktimeout;
12360 		sscanf(command, "%*s %10d", &acktimeout);
12361 		acktimeout *= 1000;
12362 		bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
12363 	}
12364 	else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
12365 		int skip = strlen(CMD_SET_RMC_LEADER) + 1;
12366 		bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
12367 	}
12368 	else if (strnicmp(command, CMD_SET_RMC_EVENT,
12369 		strlen(CMD_SET_RMC_EVENT)) == 0) {
12370 		bytes_written = wl_android_set_rmc_event(net, command);
12371 	}
12372 #endif /* WL_RELMCAST */
12373 	else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
12374 		bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
12375 	}
12376 	else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
12377 		bytes_written = wl_android_set_singlecore_scan(net, command);
12378 	}
12379 #ifdef TEST_TX_POWER_CONTROL
12380 	else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
12381 		strlen(CMD_TEST_SET_TX_POWER)) == 0) {
12382 		int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
12383 		wl_android_set_tx_power(net, (const char*)command+skip);
12384 	}
12385 	else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
12386 		strlen(CMD_TEST_GET_TX_POWER)) == 0) {
12387 		wl_android_get_tx_power(net, command, priv_cmd.total_len);
12388 	}
12389 #endif /* TEST_TX_POWER_CONTROL */
12390 	else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
12391 		strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
12392 		int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
12393 		bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
12394 	}
12395 #ifdef SUPPORT_SET_TID
12396 	else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
12397 		bytes_written = wl_android_set_tid(net, command);
12398 	}
12399 	else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
12400 		bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
12401 	}
12402 #endif /* SUPPORT_SET_TID */
12403 #ifdef WL_WTC
12404 	else if (strnicmp(command, CMD_WTC_CONFIG, strlen(CMD_WTC_CONFIG)) == 0) {
12405 		bytes_written = wl_android_wtc_config(net, command, priv_cmd.total_len);
12406 	}
12407 #endif /* WL_WTC */
12408 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12409 	else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
12410 		int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
12411 		wl_android_set_mac_address_filter(net, command+skip);
12412 	}
12413 	else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
12414 		bytes_written = wl_android_set_roam_mode(net, command);
12415 #if defined(BCMFW_ROAM_ENABLE)
12416 	else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
12417 		bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
12418 	}
12419 #endif /* BCMFW_ROAM_ENABLE */
12420 #ifdef WL_CFG80211
12421 	else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
12422 		bytes_written = wl_android_set_miracast(net, command);
12423 	else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
12424 		bytes_written = wl_android_set_ibss_beacon_ouidata(net,
12425 		command, priv_cmd.total_len);
12426 #endif /* WL_CFG80211 */
12427 #ifdef WLAIBSS
12428 	else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
12429 		strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
12430 		bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
12431 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
12432 		strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
12433 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12434 			TRUE);
12435 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
12436 		strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
12437 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12438 			FALSE);
12439 	else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
12440 		strlen(CMD_SETIBSSROUTETABLE)) == 0)
12441 		bytes_written = wl_android_set_ibss_routetable(net, command);
12442 	else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
12443 		bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
12444 	else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
12445 		bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
12446 #endif /* WLAIBSS */
12447 	else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
12448 		int skip = strlen(CMD_KEEP_ALIVE) + 1;
12449 		bytes_written = wl_keep_alive_set(net, command + skip);
12450 	}
12451 #ifdef WL_CFG80211
12452 	else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
12453 		int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
12454 		bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
12455 	}
12456 	else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
12457 		char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
12458 		ANDROID_INFO(("Creating %s interface\n", name));
12459 		if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
12460 				name, NULL) == NULL) {
12461 			bytes_written = -ENODEV;
12462 		} else {
12463 			/* Return success */
12464 			bytes_written = 0;
12465 		}
12466 	}
12467 	else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
12468 		char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
12469 		ANDROID_INFO(("Deleteing %s interface\n", name));
12470 		bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
12471 	}
12472 #endif /* WL_CFG80211 */
12473 	else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
12474 		bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
12475 	}
12476 #ifdef P2PRESP_WFDIE_SRC
12477 	else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
12478 		strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
12479 		int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
12480 		bytes_written = wl_android_set_wfdie_resp(net, mode);
12481 	} else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
12482 		strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
12483 		bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
12484 	}
12485 #endif /* P2PRESP_WFDIE_SRC */
12486 #ifdef WL_CFG80211
12487 	else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
12488 		char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
12489 		bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
12490 	}
12491 #endif /* WL_CFG80211 */
12492 #ifdef WBTEXT
12493 	else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
12494 		bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
12495 	}
12496 	else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
12497 			strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
12498 		char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
12499 		bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
12500 	}
12501 	else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
12502 			strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
12503 		char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
12504 		bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
12505 				command, priv_cmd.total_len);
12506 	}
12507 	else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
12508 			strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
12509 		char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
12510 		bytes_written = wl_cfg80211_wbtext_table_config(net, data,
12511 				command, priv_cmd.total_len);
12512 	}
12513 	else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
12514 			strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
12515 		char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
12516 		bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
12517 				command, priv_cmd.total_len);
12518 	}
12519 	else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
12520 			strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
12521 		bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
12522 			priv_cmd.total_len);
12523 	}
12524 	else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
12525 			strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
12526 		bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
12527 			priv_cmd.total_len);
12528 	}
12529 	else if (strnicmp(command, CMD_WBTEXT_ESTM_ENABLE,
12530 			strlen(CMD_WBTEXT_ESTM_ENABLE)) == 0) {
12531 		bytes_written = wl_cfg80211_wbtext_estm_enable(net, command,
12532 			priv_cmd.total_len);
12533 	}
12534 #endif /* WBTEXT */
12535 #ifdef WLWFDS
12536 	else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
12537 		bytes_written = wl_android_set_wfds_hash(net, command, 1);
12538 	}
12539 	else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
12540 		bytes_written = wl_android_set_wfds_hash(net, command, 0);
12541 	}
12542 #endif /* WLWFDS */
12543 #ifdef BT_WIFI_HANDOVER
12544 	else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
12545 	    bytes_written = wl_tbow_teardown(net);
12546 	}
12547 #endif /* BT_WIFI_HANDOVER */
12548 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12549 #ifdef FCC_PWR_LIMIT_2G
12550 	else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
12551 		strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
12552 		bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
12553 	}
12554 	else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
12555 		strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
12556 		bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
12557 	}
12558 #endif /* FCC_PWR_LIMIT_2G */
12559 	else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
12560 		bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
12561 	}
12562 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12563 	else if (strnicmp(command, CMD_MURX_BFE_CAP,
12564 			strlen(CMD_MURX_BFE_CAP)) == 0) {
12565 #ifdef WL_MURX
12566 		uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
12567 		bytes_written = wl_android_murx_bfe_cap(net, val);
12568 #else
12569 		return BCME_UNSUPPORTED;
12570 #endif /* WL_MURX */
12571 	}
12572 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
12573 	else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
12574 		bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
12575 	}
12576 	else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
12577 		bytes_written = wl_android_set_ap_beaconrate(net, command);
12578 	}
12579 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
12580 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12581 	else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
12582 		bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
12583 	}
12584 	else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
12585 		bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
12586 	}
12587 	else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
12588 		bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
12589 	}
12590 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12591 #ifdef SUPPORT_AP_SUSPEND
12592 	else if (strnicmp(command, CMD_SET_AP_SUSPEND, strlen(CMD_SET_AP_SUSPEND)) == 0) {
12593 		bytes_written = wl_android_set_ap_suspend(net, command, priv_cmd.total_len);
12594 	}
12595 #endif /* SUPPORT_AP_SUSPEND */
12596 #ifdef SUPPORT_AP_BWCTRL
12597 	else if (strnicmp(command, CMD_SET_AP_BW, strlen(CMD_SET_AP_BW)) == 0) {
12598 		bytes_written = wl_android_set_ap_bw(net, command, priv_cmd.total_len);
12599 	}
12600 	else if (strnicmp(command, CMD_GET_AP_BW, strlen(CMD_GET_AP_BW)) == 0) {
12601 		bytes_written = wl_android_get_ap_bw(net, command, priv_cmd.total_len);
12602 	}
12603 #endif /* SUPPORT_AP_BWCTRL */
12604 #ifdef SUPPORT_RSSI_SUM_REPORT
12605 	else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
12606 		bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
12607 	}
12608 	else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
12609 		bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
12610 	}
12611 	else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
12612 		bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
12613 	}
12614 #endif /* SUPPORT_RSSI_SUM_REPORT */
12615 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
12616 	else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
12617 		bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
12618 	}
12619 	else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
12620 			== 0) {
12621 		bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
12622 				priv_cmd.total_len);
12623 	}
12624 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
12625 #if defined(SUPPORT_RANDOM_MAC_SCAN)
12626 	else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
12627 		bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
12628 	} else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
12629 		bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
12630 	}
12631 #endif /* SUPPORT_RANDOM_MAC_SCAN */
12632 #ifdef WL_NATOE
12633 	else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
12634 		bytes_written = wl_android_process_natoe_cmd(net, command,
12635 				priv_cmd.total_len);
12636 	}
12637 #endif /* WL_NATOE */
12638 #ifdef CONNECTION_STATISTICS
12639 	else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
12640 		strlen(CMD_GET_CONNECTION_STATS)) == 0) {
12641 		bytes_written = wl_android_get_connection_stats(net, command,
12642 			priv_cmd.total_len);
12643 	}
12644 #endif
12645 #ifdef DHD_LOG_DUMP
12646 	else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
12647 		strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
12648 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12649 		/* check whether it has more command */
12650 		if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
12651 			/* compare unwanted/disconnected command */
12652 			if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12653 				SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
12654 				dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
12655 			} else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12656 				SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
12657 				dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
12658 			} else {
12659 				dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12660 			}
12661 		} else {
12662 			dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12663 		}
12664 	}
12665 #endif /* DHD_LOG_DUMP */
12666 #ifdef DHD_STATUS_LOGGING
12667 	else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) {
12668 		dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
12669 	}
12670 	else if (strnicmp(command, CMD_QUERY_STATUS_LOG, strlen(CMD_QUERY_STATUS_LOG)) == 0) {
12671 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12672 		bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
12673 	}
12674 #endif /* DHD_STATUS_LOGGING */
12675 #if defined(CONFIG_TIZEN)
12676 	else if (strnicmp(command, CMD_POWERSAVEMODE_SET,
12677 			strlen(CMD_POWERSAVEMODE_SET)) == 0) {
12678 		bytes_written = wl_android_set_powersave_mode(net, command,
12679 			priv_cmd.total_len);
12680 	}
12681 	else if (strnicmp(command, CMD_POWERSAVEMODE_GET,
12682 			strlen(CMD_POWERSAVEMODE_GET)) == 0) {
12683 		bytes_written = wl_android_get_powersave_mode(net, command,
12684 			priv_cmd.total_len);
12685 	}
12686 #endif /* CONFIG_TIZEN */
12687 #ifdef SET_PCIE_IRQ_CPU_CORE
12688 	else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
12689 		int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
12690 		wl_android_set_irq_cpucore(net, affinity_cmd);
12691 	}
12692 #endif /* SET_PCIE_IRQ_CPU_CORE */
12693 #if defined(DHD_HANG_SEND_UP_TEST)
12694 	else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
12695 		int skip = strlen(CMD_MAKE_HANG) + 1;
12696 		wl_android_make_hang_with_reason(net, (const char*)command+skip);
12697 	}
12698 #endif /* DHD_HANG_SEND_UP_TEST */
12699 #ifdef SUPPORT_LQCM
12700 	else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
12701 		int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
12702 		bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
12703 	}
12704 	else if (strnicmp(command, CMD_GET_LQCM_REPORT,
12705 			strlen(CMD_GET_LQCM_REPORT)) == 0) {
12706 		bytes_written = wl_android_get_lqcm_report(net, command,
12707 			priv_cmd.total_len);
12708 	}
12709 #endif
12710 	else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
12711 		bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
12712 	}
12713 #ifdef WLADPS_PRIVATE_CMD
12714 	else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
12715 		int skip = strlen(CMD_SET_ADPS) + 1;
12716 		bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
12717 	}
12718 	else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
12719 		bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
12720 	}
12721 #ifdef WLADPS_ENERGY_GAIN
12722 	else if (strnicmp(command, CMD_GET_GAIN_ADPS, strlen(CMD_GET_GAIN_ADPS)) == 0) {
12723 		bytes_written = wl_android_get_gain_adps(net, command, priv_cmd.total_len);
12724 	}
12725 	else if (strnicmp(command, CMD_RESET_GAIN_ADPS, strlen(CMD_RESET_GAIN_ADPS)) == 0) {
12726 		bytes_written = wl_android_reset_gain_adps(net, command);
12727 	}
12728 #endif	/* WLADPS_ENERGY_GAIN */
12729 #endif /* WLADPS_PRIVATE_CMD */
12730 #ifdef DHD_PKT_LOGGING
12731 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
12732 		strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
12733 		bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
12734 	}
12735 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
12736 		strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
12737 		bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
12738 	}
12739 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
12740 		strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
12741 		bytes_written =
12742 			wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
12743 	}
12744 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
12745 		strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
12746 		bytes_written =
12747 			wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
12748 	}
12749 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
12750 		bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
12751 	}
12752 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DEL, strlen(CMD_PKTLOG_FILTER_DEL)) == 0) {
12753 		bytes_written = wl_android_pktlog_filter_del(net, command, priv_cmd.total_len);
12754 	}
12755 	else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
12756 		bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
12757 	}
12758 	else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
12759 		bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
12760 	}
12761 	else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
12762 		bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
12763 	}
12764 	else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
12765 		bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
12766 	}
12767 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
12768 		strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
12769 		bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
12770 	}
12771 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
12772 		strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
12773 		bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
12774 	}
12775 	else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
12776 		strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
12777 		bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
12778 	}
12779 	else if (strnicmp(command, CMD_PKTLOG_DEBUG_DUMP, strlen(CMD_PKTLOG_DEBUG_DUMP)) == 0) {
12780 		bytes_written = wl_android_pktlog_dbg_dump(net, command, priv_cmd.total_len);
12781 	}
12782 #endif /* DHD_PKT_LOGGING */
12783 #ifdef WL_CFG80211
12784 	else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
12785 		int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
12786 		bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
12787 	}
12788 #endif /* WL_CFG80211 */
12789 #ifdef DHD_EVENT_LOG_FILTER
12790 	else if (strnicmp(command, CMD_EWP_FILTER,
12791 		strlen(CMD_EWP_FILTER)) == 0) {
12792 		bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
12793 	}
12794 #endif /* DHD_EVENT_LOG_FILTER */
12795 #ifdef WL_BCNRECV
12796 	else if (strnicmp(command, CMD_BEACON_RECV,
12797 		strlen(CMD_BEACON_RECV)) == 0) {
12798 		char *data = (command + strlen(CMD_BEACON_RECV) + 1);
12799 		bytes_written = wl_android_bcnrecv_config(net,
12800 				data, priv_cmd.total_len);
12801 	}
12802 #endif /* WL_BCNRECV */
12803 #ifdef WL_MBO
12804 	else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
12805 		bytes_written = wl_android_process_mbo_cmd(net, command,
12806 			priv_cmd.total_len);
12807 	}
12808 #endif /* WL_MBO */
12809 #ifdef WL_CAC_TS
12810 	else if (strnicmp(command, CMD_CAC_TSPEC,
12811 		strlen(CMD_CAC_TSPEC)) == 0) {
12812 		char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
12813 		bytes_written = wl_android_cac_ts_config(net,
12814 				data, priv_cmd.total_len);
12815 	}
12816 #endif /* WL_CAC_TS */
12817 #ifdef WL_GET_CU
12818 	else if (strnicmp(command, CMD_GET_CHAN_UTIL,
12819 		strlen(CMD_GET_CHAN_UTIL)) == 0) {
12820 		bytes_written = wl_android_get_channel_util(net,
12821 			command, priv_cmd.total_len);
12822 	}
12823 #endif /* WL_GET_CU */
12824 #ifdef RTT_GEOFENCE_INTERVAL
12825 #if defined (RTT_SUPPORT) && defined(WL_NAN)
12826 	else if (strnicmp(command, CMD_GEOFENCE_INTERVAL,
12827 			strlen(CMD_GEOFENCE_INTERVAL)) == 0) {
12828 		(void)wl_android_set_rtt_geofence_interval(net, command);
12829 	}
12830 #endif /* RTT_SUPPORT && WL_NAN */
12831 #endif /* RTT_GEOFENCE_INTERVAL */
12832 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
12833 	else if (strnicmp(command, CMD_SET_SOFTAP_ELNA_BYPASS,
12834 			strlen(CMD_SET_SOFTAP_ELNA_BYPASS)) == 0) {
12835 		bytes_written =
12836 			wl_android_set_softap_elna_bypass(net, command, priv_cmd.total_len);
12837 	}
12838 	else if (strnicmp(command, CMD_GET_SOFTAP_ELNA_BYPASS,
12839 			strlen(CMD_GET_SOFTAP_ELNA_BYPASS)) == 0) {
12840 		bytes_written =
12841 			wl_android_get_softap_elna_bypass(net, command, priv_cmd.total_len);
12842 	}
12843 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
12844 #ifdef WL_NAN
12845 	else if (strnicmp(command, CMD_GET_NAN_STATUS,
12846 			strlen(CMD_GET_NAN_STATUS)) == 0) {
12847 		bytes_written =
12848 			wl_android_get_nan_status(net, command, priv_cmd.total_len);
12849 	}
12850 #endif /* WL_NAN */
12851 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
12852 	else if (strnicmp(command, CMD_NAN_RANGING_SET_BW, strlen(CMD_NAN_RANGING_SET_BW)) == 0) {
12853 		int bw_cmd = *(command + strlen(CMD_NAN_RANGING_SET_BW) + 1) - '0';
12854 		bytes_written = wl_nan_ranging_bw(net, bw_cmd, command);
12855 	}
12856 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
12857 	else if (strnicmp(command, CMD_GET_FACTORY_MAC, strlen(CMD_GET_FACTORY_MAC)) == 0) {
12858 		bytes_written = wl_android_get_factory_mac_addr(net, command, priv_cmd.total_len);
12859 	}
12860 	else if (strnicmp(command, CMD_HAPD_SET_AX_MODE, strlen(CMD_HAPD_SET_AX_MODE)) == 0) {
12861 		int skip = strlen(CMD_HAPD_SET_AX_MODE) + 1;
12862 		bytes_written = wl_android_set_softap_ax_mode(net, command + skip);
12863 	}
12864 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
12865 	else if (strnicmp(command, CMD_SET_LATENCY_CRITICAL_DATA,
12866 		strlen(CMD_SET_LATENCY_CRITICAL_DATA)) == 0) {
12867 		int enable = *(command + strlen(CMD_SET_LATENCY_CRITICAL_DATA) + 1) - '0';
12868 		bytes_written = wl_android_set_latency_crt_data(net, enable);
12869 	}
12870 	else if  (strnicmp(command, CMD_GET_LATENCY_CRITICAL_DATA,
12871 		strlen(CMD_GET_LATENCY_CRITICAL_DATA)) == 0) {
12872 		bytes_written = wl_android_get_latency_crt_data(net, command, priv_cmd.total_len);
12873 	}
12874 #endif	/* SUPPORT_LATENCY_CRITICAL_DATA */
12875 #ifdef WL_TWT
12876 	else if (strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) {
12877 		bytes_written = wl_android_twt_setup(net, command, priv_cmd.total_len);
12878 	}
12879 	else if (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) {
12880 		bytes_written = wl_android_twt_teardown(net, command, priv_cmd.total_len);
12881 	}
12882 	else if (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0) {
12883 		bytes_written = wl_android_twt_info(net, command, priv_cmd.total_len);
12884 	}
12885 	else if (strnicmp(command, CMD_TWT_STATUS_QUERY, strlen(CMD_TWT_STATUS_QUERY)) == 0) {
12886 		bytes_written = wl_android_twt_status_query(net, command, priv_cmd.total_len);
12887 	}
12888 	else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) {
12889 		bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len);
12890 	}
12891 #endif /* WL_TWT */
12892 #ifdef WL_P2P_6G
12893 	else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) {
12894 		int enable = *(command + strlen(CMD_ENABLE_6G_P2P) + 1) - '0';
12895 		bytes_written = wl_android_enable_p2p_6g(net, enable);
12896 	}
12897 #endif /* WL_P2P_6G */
12898 	else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len, &bytes_written) == 0) {
12899 	}
12900 	else {
12901 		ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
12902 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
12903 	}
12904 
12905 	return bytes_written;
12906 }
12907 
wl_android_init(void)12908 int wl_android_init(void)
12909 {
12910 	int ret = 0;
12911 
12912 #ifdef ENABLE_INSMOD_NO_POWER_OFF
12913 	dhd_download_fw_on_driverload = TRUE;
12914 #elif defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE)
12915 	dhd_download_fw_on_driverload = FALSE;
12916 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
12917 	if (!iface_name[0]) {
12918 		bzero(iface_name, IFNAMSIZ);
12919 		bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
12920 	}
12921 
12922 #ifdef CUSTOMER_HW4_DEBUG
12923 	/* No Kernel Panic from ASSERT() on customer platform. */
12924 	g_assert_type = 1;
12925 #endif /* CUSTOMER_HW4_DEBUG */
12926 
12927 #ifdef WL_GENL
12928 	wl_genl_init();
12929 #endif
12930 #ifdef WL_RELMCAST
12931 	wl_netlink_init();
12932 #endif /* WL_RELMCAST */
12933 
12934 	return ret;
12935 }
12936 
wl_android_exit(void)12937 int wl_android_exit(void)
12938 {
12939 	int ret = 0;
12940 	struct io_cfg *cur, *q;
12941 
12942 #ifdef WL_GENL
12943 	wl_genl_deinit();
12944 #endif /* WL_GENL */
12945 #ifdef WL_RELMCAST
12946 	wl_netlink_deinit();
12947 #endif /* WL_RELMCAST */
12948 
12949 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
12950 	list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
12951 		GCC_DIAGNOSTIC_POP();
12952 		list_del(&cur->list);
12953 		kfree(cur);
12954 	}
12955 
12956 	return ret;
12957 }
12958 
wl_android_post_init(void)12959 void wl_android_post_init(void)
12960 {
12961 
12962 #ifdef ENABLE_4335BT_WAR
12963 	bcm_bt_unlock(lock_cookie_wifi);
12964 	ANDROID_ERROR(("%s: btlock released\n", __FUNCTION__));
12965 #endif /* ENABLE_4335BT_WAR */
12966 
12967 	if (!dhd_download_fw_on_driverload) {
12968 		g_wifi_on = FALSE;
12969 	}
12970 }
12971 
12972 #ifdef WL_GENL
12973 /* Generic Netlink Initializaiton */
wl_genl_init(void)12974 static int wl_genl_init(void)
12975 {
12976 	int ret;
12977 
12978 	ANDROID_INFO(("GEN Netlink Init\n\n"));
12979 
12980 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
12981 	/* register new family */
12982 	ret = genl_register_family(&wl_genl_family);
12983 	if (ret != 0)
12984 		goto failure;
12985 
12986 	/* register functions (commands) of the new family */
12987 	ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
12988 	if (ret != 0) {
12989 		ANDROID_ERROR(("register ops failed: %i\n", ret));
12990 		genl_unregister_family(&wl_genl_family);
12991 		goto failure;
12992 	}
12993 
12994 	ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
12995 #else
12996 	ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
12997 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
12998 	if (ret != 0) {
12999 		ANDROID_ERROR(("register mc_group failed: %i\n", ret));
13000 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13001 		genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
13002 #endif
13003 		genl_unregister_family(&wl_genl_family);
13004 		goto failure;
13005 	}
13006 
13007 	return 0;
13008 
13009 failure:
13010 	ANDROID_ERROR(("Registering Netlink failed!!\n"));
13011 	return -1;
13012 }
13013 
13014 /* Generic netlink deinit */
wl_genl_deinit(void)13015 static int wl_genl_deinit(void)
13016 {
13017 
13018 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13019 	if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
13020 		ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13021 #endif
13022 	if (genl_unregister_family(&wl_genl_family) < 0)
13023 		ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13024 
13025 	return 0;
13026 }
13027 
wl_event_to_bcm_event(u16 event_type)13028 s32 wl_event_to_bcm_event(u16 event_type)
13029 {
13030 	/* When you add any new event, please mention the
13031 	 * version of BCM supplicant supporting it
13032 	 */
13033 	u16 event = -1;
13034 
13035 	switch (event_type) {
13036 		case WLC_E_SERVICE_FOUND:
13037 			event = BCM_E_SVC_FOUND;
13038 			break;
13039 		case WLC_E_P2PO_ADD_DEVICE:
13040 			event = BCM_E_DEV_FOUND;
13041 			break;
13042 		case WLC_E_P2PO_DEL_DEVICE:
13043 			event = BCM_E_DEV_LOST;
13044 			break;
13045 	/* Above events are supported from BCM Supp ver 47 Onwards */
13046 #ifdef BT_WIFI_HANDOVER
13047 		case WLC_E_BT_WIFI_HANDOVER_REQ:
13048 			event = BCM_E_DEV_BT_WIFI_HO_REQ;
13049 			break;
13050 #endif /* BT_WIFI_HANDOVER */
13051 
13052 		default:
13053 			ANDROID_ERROR(("Event not supported\n"));
13054 	}
13055 
13056 	return event;
13057 }
13058 
13059 s32
wl_genl_send_msg(struct net_device * ndev,u32 event_type,const u8 * buf,u16 len,u8 * subhdr,u16 subhdr_len)13060 wl_genl_send_msg(
13061 	struct net_device *ndev,
13062 	u32 event_type,
13063 	const u8 *buf,
13064 	u16 len,
13065 	u8 *subhdr,
13066 	u16 subhdr_len)
13067 {
13068 	int ret = 0;
13069 	struct sk_buff *skb;
13070 	void *msg;
13071 	u32 attr_type = 0;
13072 	bcm_event_hdr_t *hdr = NULL;
13073 	int mcast = 1; /* By default sent as mutlicast type */
13074 	int pid = 0;
13075 	u8 *ptr = NULL, *p = NULL;
13076 	u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
13077 	u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13078 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13079 
13080 	ANDROID_INFO(("Enter \n"));
13081 
13082 	/* Decide between STRING event and Data event */
13083 	if (event_type == 0)
13084 		attr_type = BCM_GENL_ATTR_STRING;
13085 	else
13086 		attr_type = BCM_GENL_ATTR_MSG;
13087 
13088 	skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
13089 	if (skb == NULL) {
13090 		ret = -ENOMEM;
13091 		goto out;
13092 	}
13093 
13094 	msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
13095 	if (msg == NULL) {
13096 		ret = -ENOMEM;
13097 		goto out;
13098 	}
13099 
13100 	if (attr_type == BCM_GENL_ATTR_STRING) {
13101 		/* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
13102 		 * make sure it is null terminated
13103 		 */
13104 		if (subhdr || subhdr_len) {
13105 			ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n"));
13106 			ret =  -EINVAL;
13107 			goto out;
13108 		}
13109 
13110 		ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
13111 		if (ret != 0) {
13112 			ANDROID_ERROR(("nla_put_string failed\n"));
13113 			goto out;
13114 		}
13115 	} else {
13116 		/* ATTR_MSG */
13117 
13118 		/* Create a single buffer for all */
13119 		p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
13120 		if (!ptr) {
13121 			ret = -ENOMEM;
13122 			ANDROID_ERROR(("ENOMEM!!\n"));
13123 			goto out;
13124 		}
13125 
13126 		/* Include the bcm event header */
13127 		hdr = (bcm_event_hdr_t *)ptr;
13128 		hdr->event_type = wl_event_to_bcm_event(event_type);
13129 		hdr->len = len + subhdr_len;
13130 		ptr += sizeof(bcm_event_hdr_t);
13131 
13132 		/* Copy subhdr (if any) */
13133 		if (subhdr && subhdr_len) {
13134 			memcpy(ptr, subhdr, subhdr_len);
13135 			ptr += subhdr_len;
13136 		}
13137 
13138 		/* Copy the data */
13139 		if (buf && len) {
13140 			memcpy(ptr, buf, len);
13141 		}
13142 
13143 		ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
13144 		if (ret != 0) {
13145 			ANDROID_ERROR(("nla_put_string failed\n"));
13146 			goto out;
13147 		}
13148 	}
13149 
13150 	if (mcast) {
13151 		int err = 0;
13152 		/* finalize the message */
13153 		genlmsg_end(skb, msg);
13154 		/* NETLINK_CB(skb).dst_group = 1; */
13155 
13156 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
13157 		if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
13158 #else
13159 		if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
13160 #endif
13161 			ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
13162 				attr_type, err));
13163 		else
13164 			ANDROID_INFO(("Multicast msg sent successfully. attr_type:%d len:%d \n",
13165 				attr_type, tot_len));
13166 	} else {
13167 		NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
13168 
13169 		/* finalize the message */
13170 		genlmsg_end(skb, msg);
13171 
13172 		/* send the message back */
13173 		if (genlmsg_unicast(&init_net, skb, pid) < 0)
13174 			ANDROID_ERROR(("genlmsg_unicast failed\n"));
13175 	}
13176 
13177 out:
13178 	if (p) {
13179 		MFREE(cfg->osh, p, tot_len);
13180 	}
13181 	if (ret)
13182 		nlmsg_free(skb);
13183 
13184 	return ret;
13185 }
13186 
13187 static s32
wl_genl_handle_msg(struct sk_buff * skb,struct genl_info * info)13188 wl_genl_handle_msg(
13189 	struct sk_buff *skb,
13190 	struct genl_info *info)
13191 {
13192 	struct nlattr *na;
13193 	u8 *data = NULL;
13194 
13195 	ANDROID_INFO(("Enter \n"));
13196 
13197 	if (info == NULL) {
13198 		return -EINVAL;
13199 	}
13200 
13201 	na = info->attrs[BCM_GENL_ATTR_MSG];
13202 	if (!na) {
13203 		ANDROID_ERROR(("nlattribute NULL\n"));
13204 		return -EINVAL;
13205 	}
13206 
13207 	data = (char *)nla_data(na);
13208 	if (!data) {
13209 		ANDROID_ERROR(("Invalid data\n"));
13210 		return -EINVAL;
13211 	} else {
13212 		/* Handle the data */
13213 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || \
13214 	defined(WL_COMPAT_WIRELESS)
13215 		ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13216 			info->snd_pid));
13217 #else
13218 		ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13219 			info->snd_portid));
13220 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
13221 	}
13222 
13223 	return 0;
13224 }
13225 #endif /* WL_GENL */
13226 
wl_fatal_error(void * wl,int rc)13227 int wl_fatal_error(void * wl, int rc)
13228 {
13229 	return FALSE;
13230 }
13231 
13232 void
wl_android_set_wifi_on_flag(bool enable)13233 wl_android_set_wifi_on_flag(bool enable)
13234 {
13235 	ANDROID_ERROR(("%s: %d\n", __FUNCTION__, enable));
13236 	g_wifi_on = enable;
13237 }
13238 
13239 #ifdef WL_STATIC_IF
13240 #include <dhd_linux_priv.h>
13241 struct net_device *
wl_cfg80211_register_static_if(struct bcm_cfg80211 * cfg,u16 iftype,char * ifname)13242 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname)
13243 {
13244 	struct net_device *ndev;
13245 	struct wireless_dev *wdev = NULL;
13246 	int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
13247 	u8 mac_addr[ETH_ALEN];
13248 	struct net_device *primary_ndev;
13249 #ifdef DHD_USE_RANDMAC
13250 	struct ether_addr ea_addr;
13251 #endif /* DHD_USE_RANDMAC */
13252 #ifdef CUSTOM_MULTI_MAC
13253 	char hw_ether[62];
13254 	dhd_pub_t *dhd = cfg->pub;
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 #ifdef DHD_USE_RANDMAC
13266 	wl_cfg80211_generate_mac_addr(&ea_addr);
13267 	(void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN);
13268 #else
13269 #if defined(CUSTOM_MULTI_MAC)
13270 	if (wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, "wlan1")) {
13271 #endif
13272 	/* Use primary mac with locally admin bit set */
13273 	(void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
13274 	mac_addr[0] |= 0x02;
13275 #if defined(CUSTOM_MULTI_MAC)
13276 	} else {
13277 		(void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN);
13278 	}
13279 #endif
13280 #endif /* DHD_USE_RANDMAC */
13281 
13282 	ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
13283 		WL_BSSIDX_MAX, NULL);
13284 	if (unlikely(!ndev)) {
13285 		ANDROID_ERROR(("Failed to allocate static_if\n"));
13286 		goto fail;
13287 	}
13288 	wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
13289 	if (unlikely(!wdev)) {
13290 		ANDROID_ERROR(("Failed to allocate wdev for static_if\n"));
13291 		goto fail;
13292 	}
13293 
13294 	wdev->wiphy = cfg->wdev->wiphy;
13295 	wdev->iftype = iftype;
13296 
13297 	ndev->ieee80211_ptr = wdev;
13298 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
13299 	wdev->netdev = ndev;
13300 
13301 	if (wl_cfg80211_register_if(cfg, ifidx,
13302 		ndev, TRUE) != BCME_OK) {
13303 		ANDROID_ERROR(("ndev registration failed!\n"));
13304 		goto fail;
13305 	}
13306 
13307 	cfg->static_ndev = ndev;
13308 	cfg->static_ndev_state = NDEV_STATE_OS_IF_CREATED;
13309 	wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
13310 		ifname, NDEV_STATE_OS_IF_CREATED);
13311 	ANDROID_INFO(("Static I/F (%s) Registered\n", ndev->name));
13312 	return ndev;
13313 
13314 fail:
13315 	wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
13316 	return NULL;
13317 }
13318 
13319 void
wl_cfg80211_unregister_static_if(struct bcm_cfg80211 * cfg)13320 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
13321 {
13322 	ANDROID_INFO(("[STATIC_IF] Enter\n"));
13323 	if (!cfg || !cfg->static_ndev) {
13324 		ANDROID_ERROR(("invalid input\n"));
13325 		return;
13326 	}
13327 
13328 	/* wdev free will happen from notifier context */
13329 	/* free_netdev(cfg->static_ndev);
13330 	*/
13331 	unregister_netdev(cfg->static_ndev);
13332 }
13333 
13334 s32
wl_cfg80211_static_if_open(struct net_device * net)13335 wl_cfg80211_static_if_open(struct net_device *net)
13336 {
13337 	struct wireless_dev *wdev = NULL;
13338 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13339 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13340 	u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
13341 	u16 wl_iftype, wl_mode;
13342 #ifdef CUSTOM_MULTI_MAC
13343 	dhd_pub_t *dhd = dhd_get_pub(net);
13344 	char hw_ether[62];
13345 #endif
13346 
13347 	ANDROID_INFO(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
13348 	ASSERT(cfg->static_ndev == net);
13349 
13350 	if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) <  0) {
13351 		return BCME_ERROR;
13352 	}
13353 	if (cfg->static_ndev_state != NDEV_STATE_FW_IF_CREATED) {
13354 #ifdef CUSTOM_MULTI_MAC
13355 		if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, net->name))
13356 			memcpy(net->dev_addr, hw_ether, ETHER_ADDR_LEN);
13357 #endif
13358 		wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr);
13359 		if (!wdev) {
13360 			ANDROID_ERROR(("[STATIC_IF] wdev is NULL, can't proceed"));
13361 			return BCME_ERROR;
13362 		}
13363 	} else {
13364 		ANDROID_INFO(("Fw IF for static netdev already created\n"));
13365 	}
13366 
13367 	return BCME_OK;
13368 }
13369 
13370 s32
wl_cfg80211_static_if_close(struct net_device * net)13371 wl_cfg80211_static_if_close(struct net_device *net)
13372 {
13373 	int ret = BCME_OK;
13374 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13375 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13376 
13377 	if (cfg->static_ndev_state == NDEV_STATE_FW_IF_CREATED) {
13378 		if (mutex_is_locked(&cfg->if_sync) == TRUE) {
13379 			ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13380 		} else {
13381 			ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13382 		}
13383 
13384 		if (unlikely(ret)) {
13385 			ANDROID_ERROR(("Del iface failed for static_if %d\n", ret));
13386 		}
13387 	}
13388 
13389 	return ret;
13390 }
13391 struct net_device *
wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 * cfg,wl_if_event_info * event,u8 * addr,s32 iface_type)13392 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
13393 	wl_if_event_info *event, u8 *addr, s32 iface_type)
13394 {
13395 	struct net_device *new_ndev = NULL;
13396 	struct wireless_dev *wdev = NULL;
13397 
13398 	ANDROID_INFO(("Updating static iface after Fw IF create \n"));
13399 	new_ndev = cfg->static_ndev;
13400 
13401 	if (new_ndev) {
13402 		wdev = new_ndev->ieee80211_ptr;
13403 		ASSERT(wdev);
13404 		wdev->iftype = iface_type;
13405 		(void)memcpy_s(new_ndev->dev_addr, ETH_ALEN, addr, ETH_ALEN);
13406 	}
13407 
13408 	cfg->static_ndev_state = NDEV_STATE_FW_IF_CREATED;
13409 	wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
13410 		event->name, NDEV_STATE_FW_IF_CREATED);
13411 	return new_ndev;
13412 }
13413 s32
wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 * cfg,struct net_device * ndev)13414 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13415 {
13416 	cfg->static_ndev_state = NDEV_STATE_FW_IF_DELETED;
13417 	wl_cfg80211_update_iflist_info(cfg, ndev, WL_STATIC_IFIDX, NULL,
13418 		WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
13419 	wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
13420 	wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
13421 	return BCME_OK;
13422 }
13423 #endif /* WL_STATIC_IF */
13424 
13425 #ifdef WBTEXT
13426 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)13427 wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
13428 	uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size)
13429 {
13430 	int err = BCME_OK;
13431 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13432 	u8 *ioctl_buf = NULL;
13433 
13434 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13435 	if (unlikely(!ioctl_buf)) {
13436 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13437 		err =  -ENOMEM;
13438 		goto exit;
13439 	}
13440 	rp->v1.band = band;
13441 	rp->v1.len = 0;
13442 	/* Getting roam profile from fw */
13443 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13444 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13445 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13446 		goto exit;
13447 	}
13448 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13449 	/* roam_prof version get */
13450 	if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13451 		ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13452 		err = BCME_VERSION;
13453 		goto exit;
13454 	}
13455 	switch (rp->v1.ver) {
13456 		case WL_ROAM_PROF_VER_0:
13457 		{
13458 			*roam_prof_size = sizeof(wl_roam_prof_v1_t);
13459 			*roam_prof_ver = WL_ROAM_PROF_VER_0;
13460 		}
13461 		break;
13462 		case WL_ROAM_PROF_VER_1:
13463 		{
13464 			*roam_prof_size = sizeof(wl_roam_prof_v2_t);
13465 			*roam_prof_ver = WL_ROAM_PROF_VER_1;
13466 		}
13467 		break;
13468 		case WL_ROAM_PROF_VER_2:
13469 		{
13470 			*roam_prof_size = sizeof(wl_roam_prof_v3_t);
13471 			*roam_prof_ver = WL_ROAM_PROF_VER_2;
13472 		}
13473 		break;
13474 		case WL_ROAM_PROF_VER_3:
13475 		{
13476 			*roam_prof_size = sizeof(wl_roam_prof_v4_t);
13477 			*roam_prof_ver = WL_ROAM_PROF_VER_3;
13478 		}
13479 		break;
13480 		default:
13481 			ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13482 			err = BCME_VERSION;
13483 			goto exit;
13484 	}
13485 	ANDROID_INFO(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size));
13486 	if ((rp->v1.len % *roam_prof_size) != 0) {
13487 		ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13488 		err = BCME_BADLEN;
13489 	}
13490 exit:
13491 	if (ioctl_buf) {
13492 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13493 	}
13494 	return err;
13495 }
13496 
13497 s32
wl_cfg80211_wbtext_set_default(struct net_device * ndev)13498 wl_cfg80211_wbtext_set_default(struct net_device *ndev)
13499 {
13500 	char *commandp = NULL;
13501 	s32 ret = BCME_OK;
13502 	char *data;
13503 	u8 *ioctl_buf = NULL;
13504 	wl_roamprof_band_t rp;
13505 	uint8 bandidx = 0;
13506 	int wnmmask = 0;
13507 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13508 
13509 	ANDROID_INFO(("set wbtext to default\n"));
13510 
13511 	commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13512 	if (unlikely(!commandp)) {
13513 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13514 		ret =  -ENOMEM;
13515 		goto exit;
13516 	}
13517 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13518 	if (unlikely(!ioctl_buf)) {
13519 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13520 		ret =  -ENOMEM;
13521 		goto exit;
13522 	}
13523 
13524 	rp.v1.band = WLC_BAND_2G;
13525 	rp.v1.len = 0;
13526 	/* Getting roam profile from fw */
13527 	if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp),
13528 		ioctl_buf, WLC_IOCTL_SMLEN, NULL))) {
13529 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", ret));
13530 		goto exit;
13531 	}
13532 	memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp));
13533 	for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
13534 		switch (rp.v1.ver) {
13535 			case WL_ROAM_PROF_VER_1:
13536 			{
13537 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13538 				if (bandidx == BAND_5G_INDEX) {
13539 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13540 						CMD_WBTEXT_PROFILE_CONFIG,
13541 						DEFAULT_WBTEXT_PROFILE_A_V2);
13542 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13543 				} else {
13544 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13545 						CMD_WBTEXT_PROFILE_CONFIG,
13546 						DEFAULT_WBTEXT_PROFILE_B_V2);
13547 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13548 				}
13549 			}
13550 			break;
13551 			case WL_ROAM_PROF_VER_2:
13552 			case WL_ROAM_PROF_VER_3:
13553 			{
13554 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13555 				if (bandidx == BAND_5G_INDEX) {
13556 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13557 						CMD_WBTEXT_PROFILE_CONFIG,
13558 						DEFAULT_WBTEXT_PROFILE_A_V3);
13559 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13560 				} else {
13561 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13562 						CMD_WBTEXT_PROFILE_CONFIG,
13563 						DEFAULT_WBTEXT_PROFILE_B_V3);
13564 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13565 				}
13566 			}
13567 			break;
13568 			default:
13569 				ANDROID_ERROR(("No Support for roam prof ver = %d \n", rp.v1.ver));
13570 				ret = -EINVAL;
13571 				goto exit;
13572 		}
13573 		/* set roam profile */
13574 		ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13575 		if (ret != BCME_OK) {
13576 			ANDROID_ERROR(("%s: Failed to set roam_prof %s error = %d\n",
13577 				__FUNCTION__, data, ret));
13578 			goto exit;
13579 		}
13580 	}
13581 
13582 	/* wbtext code for backward compatibility. Newer firmwares set default value
13583 	* from fw init
13584 	*/
13585 	/* set RSSI weight */
13586 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13587 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13588 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
13589 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13590 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13591 	if (ret != BCME_OK) {
13592 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13593 			__FUNCTION__, data, ret));
13594 		goto exit;
13595 	}
13596 
13597 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13598 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13599 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
13600 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13601 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13602 	if (ret != BCME_OK) {
13603 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13604 			__FUNCTION__, data, ret));
13605 		goto exit;
13606 	}
13607 
13608 	/* set CU weight */
13609 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13610 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13611 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
13612 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13613 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13614 	if (ret != BCME_OK) {
13615 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13616 			__FUNCTION__, data, ret));
13617 		goto exit;
13618 	}
13619 
13620 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13621 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13622 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
13623 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13624 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13625 	if (ret != BCME_OK) {
13626 		ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13627 			__FUNCTION__, data, ret));
13628 		goto exit;
13629 	}
13630 
13631 	ret = wldev_iovar_getint(ndev, "wnm", &wnmmask);
13632 	if (ret != BCME_OK) {
13633 		ANDROID_ERROR(("%s: Failed to get wnmmask error = %d\n", __func__, ret));
13634 		goto exit;
13635 	}
13636 	/* set ESTM DL weight. */
13637 	if (wnmmask & WL_WNM_ESTM) {
13638 		ANDROID_ERROR(("Setting ESTM wt\n"));
13639 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13640 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13641 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A);
13642 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13643 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13644 		if (ret != BCME_OK) {
13645 			ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13646 				__FUNCTION__, data, ret));
13647 			goto exit;
13648 		}
13649 
13650 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13651 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13652 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B);
13653 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13654 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13655 		if (ret != BCME_OK) {
13656 			ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13657 				__FUNCTION__, data, ret));
13658 			goto exit;
13659 		}
13660 	}
13661 
13662 	/* set RSSI table */
13663 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13664 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13665 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
13666 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13667 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13668 	if (ret != BCME_OK) {
13669 		ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13670 			__FUNCTION__, data, ret));
13671 		goto exit;
13672 	}
13673 
13674 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13675 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13676 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
13677 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13678 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13679 	if (ret != BCME_OK) {
13680 		ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13681 			__FUNCTION__, data, ret));
13682 		goto exit;
13683 	}
13684 
13685 	/* set CU table */
13686 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13687 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13688 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
13689 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13690 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13691 	if (ret != BCME_OK) {
13692 		ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13693 			__FUNCTION__, data, ret));
13694 		goto exit;
13695 	}
13696 
13697 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13698 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13699 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
13700 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13701 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13702 	if (ret != BCME_OK) {
13703 		ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13704 			__FUNCTION__, data, ret));
13705 		goto exit;
13706 	}
13707 
13708 exit:
13709 	if (commandp) {
13710 		MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
13711 	}
13712 	if (ioctl_buf) {
13713 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_SMLEN);
13714 	}
13715 	return ret;
13716 }
13717 
13718 s32
wl_cfg80211_wbtext_config(struct net_device * ndev,char * data,char * command,int total_len)13719 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
13720 {
13721 	uint i = 0;
13722 	long int rssi_lower, roam_trigger;
13723 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13724 	wl_roamprof_band_t *rp = NULL;
13725 	int err = -EINVAL, bytes_written = 0;
13726 	size_t len = strlen(data);
13727 	int rp_len = 0;
13728 	u8 *ioctl_buf = NULL;
13729 	uint8 roam_prof_size = 0, roam_prof_ver = 0, fs_per = 0, prof_cnt = 0;
13730 
13731 	data[len] = '\0';
13732 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13733 	if (unlikely(!ioctl_buf)) {
13734 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13735 		err =  -ENOMEM;
13736 		goto exit;
13737 	}
13738 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
13739 	if (unlikely(!rp)) {
13740 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13741 		err =  -ENOMEM;
13742 		goto exit;
13743 	}
13744 	if (*data && (!strncmp(data, "b", 1))) {
13745 		rp->v1.band = WLC_BAND_2G;
13746 	} else if (*data && (!strncmp(data, "a", 1))) {
13747 		rp->v1.band = WLC_BAND_5G;
13748 	} else {
13749 		err = snprintf(command, total_len, "Missing band\n");
13750 		goto exit;
13751 	}
13752 	data++;
13753 	rp->v1.len = 0;
13754 	/* Getting roam profile from fw */
13755 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13756 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13757 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13758 		goto exit;
13759 	}
13760 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13761 	/* roam_prof version get */
13762 	if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13763 		ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13764 		err = -EINVAL;
13765 		goto exit;
13766 	}
13767 	switch (rp->v1.ver) {
13768 		case WL_ROAM_PROF_VER_0:
13769 		{
13770 			roam_prof_size = sizeof(wl_roam_prof_v1_t);
13771 			roam_prof_ver = WL_ROAM_PROF_VER_0;
13772 		}
13773 		break;
13774 		case WL_ROAM_PROF_VER_1:
13775 		{
13776 			roam_prof_size = sizeof(wl_roam_prof_v2_t);
13777 			roam_prof_ver = WL_ROAM_PROF_VER_1;
13778 		}
13779 		break;
13780 		case WL_ROAM_PROF_VER_2:
13781 		{
13782 			roam_prof_size = sizeof(wl_roam_prof_v3_t);
13783 			roam_prof_ver = WL_ROAM_PROF_VER_2;
13784 		}
13785 		break;
13786 		case WL_ROAM_PROF_VER_3:
13787 		{
13788 			roam_prof_size = sizeof(wl_roam_prof_v4_t);
13789 			roam_prof_ver = WL_ROAM_PROF_VER_3;
13790 		}
13791 		break;
13792 		default:
13793 			ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13794 			goto exit;
13795 	}
13796 	ANDROID_INFO(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size));
13797 	if ((rp->v1.len % roam_prof_size) != 0) {
13798 		ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13799 		err = -EINVAL;
13800 		goto exit;
13801 	}
13802 	for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13803 		/* printing contents of roam profile data from fw and exits
13804 		 * if code hits any of one of the below condtion. If remaining
13805 		 * length of buffer is less than roam profile size or
13806 		 * if there is no valid entry.
13807 		 */
13808 		if (((i * roam_prof_size) > rp->v1.len)) {
13809 			break;
13810 		}
13811 		if (roam_prof_ver == WL_ROAM_PROF_VER_0) {
13812 			fs_per = rp->v1.roam_prof[i].fullscan_period;
13813 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13814 			fs_per = rp->v2.roam_prof[i].fullscan_period;
13815 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13816 			fs_per = rp->v3.roam_prof[i].fullscan_period;
13817 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13818 			fs_per = rp->v4.roam_prof[i].fullscan_period;
13819 		}
13820 		if (fs_per == 0) {
13821 			break;
13822 		}
13823 		prof_cnt++;
13824 	}
13825 
13826 	if (!*data) {
13827 		for (i = 0; (i < prof_cnt) && (i < WL_MAX_ROAM_PROF_BRACKETS); i++) {
13828 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13829 				bytes_written += scnprintf(command+bytes_written,
13830 					total_len - bytes_written,
13831 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13832 					rp->v2.roam_prof[i].roam_trigger,
13833 					rp->v2.roam_prof[i].rssi_lower,
13834 					rp->v2.roam_prof[i].channel_usage,
13835 					rp->v2.roam_prof[i].cu_avg_calc_dur);
13836 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13837 				bytes_written += scnprintf(command+bytes_written,
13838 					total_len - bytes_written,
13839 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13840 					rp->v3.roam_prof[i].roam_trigger,
13841 					rp->v3.roam_prof[i].rssi_lower,
13842 					rp->v3.roam_prof[i].channel_usage,
13843 					rp->v3.roam_prof[i].cu_avg_calc_dur);
13844 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13845 				bytes_written += snprintf(command+bytes_written,
13846 					total_len - bytes_written,
13847 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13848 					rp->v4.roam_prof[i].roam_trigger,
13849 					rp->v4.roam_prof[i].rssi_lower,
13850 					rp->v4.roam_prof[i].channel_usage,
13851 					rp->v4.roam_prof[i].cu_avg_calc_dur);
13852 			}
13853 		}
13854 		bytes_written += scnprintf(command+bytes_written, total_len - bytes_written, "\n");
13855 		err = bytes_written;
13856 		goto exit;
13857 	} else {
13858 		/* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
13859 		if (prof_cnt != 2) {
13860 			ANDROID_ERROR(("FW must have 2 rows to fill roam_prof\n"));
13861 			err = -EINVAL;
13862 			goto exit;
13863 		}
13864 		/* setting roam profile to fw */
13865 		data++;
13866 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13867 			roam_trigger = simple_strtol(data, &data, 10);
13868 			if (roam_trigger >= 0) {
13869 				ANDROID_ERROR(("roam trigger[%d] value must be negative\n", i));
13870 				err = -EINVAL;
13871 				goto exit;
13872 			}
13873 			data++;
13874 			rssi_lower = simple_strtol(data, &data, 10);
13875 			if (rssi_lower >= 0) {
13876 				ANDROID_ERROR(("rssi lower[%d] value must be negative\n", i));
13877 				err = -EINVAL;
13878 				goto exit;
13879 			}
13880 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13881 				rp->v2.roam_prof[i].roam_trigger = roam_trigger;
13882 				rp->v2.roam_prof[i].rssi_lower = rssi_lower;
13883 				data++;
13884 				rp->v2.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13885 				data++;
13886 				rp->v2.roam_prof[i].cu_avg_calc_dur =
13887 					simple_strtol(data, &data, 10);
13888 			}
13889 			if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13890 				rp->v3.roam_prof[i].roam_trigger = roam_trigger;
13891 				rp->v3.roam_prof[i].rssi_lower = rssi_lower;
13892 				data++;
13893 				rp->v3.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13894 				data++;
13895 				rp->v3.roam_prof[i].cu_avg_calc_dur =
13896 					simple_strtol(data, &data, 10);
13897 			}
13898 			if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13899 				rp->v4.roam_prof[i].roam_trigger = roam_trigger;
13900 				rp->v4.roam_prof[i].rssi_lower = rssi_lower;
13901 				data++;
13902 				rp->v4.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13903 				data++;
13904 				rp->v4.roam_prof[i].cu_avg_calc_dur =
13905 					simple_strtol(data, &data, 10);
13906 			}
13907 
13908 			rp_len += roam_prof_size;
13909 
13910 			if (*data == '\0') {
13911 				break;
13912 			}
13913 			data++;
13914 		}
13915 		if (i != 1) {
13916 			ANDROID_ERROR(("Only two roam_prof rows supported.\n"));
13917 			err = -EINVAL;
13918 			goto exit;
13919 		}
13920 		rp->v1.len = rp_len;
13921 		if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
13922 				sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
13923 				&cfg->ioctl_buf_sync)) < 0) {
13924 			ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
13925 		}
13926 	}
13927 exit:
13928 	if (rp) {
13929 		MFREE(cfg->osh, rp, sizeof(*rp));
13930 	}
13931 	if (ioctl_buf) {
13932 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13933 	}
13934 	return err;
13935 }
13936 
wl_cfg80211_wbtext_weight_config(struct net_device * ndev,char * data,char * command,int total_len)13937 int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
13938 		char *command, int total_len)
13939 {
13940 	int bytes_written = 0, err = -EINVAL, argc = 0;
13941 	char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
13942 	char *endptr = NULL;
13943 	wnm_bss_select_weight_cfg_t *bwcfg;
13944 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
13945 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13946 
13947 	bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
13948 	if (unlikely(!bwcfg)) {
13949 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13950 		err = -ENOMEM;
13951 		goto exit;
13952 	}
13953 	bwcfg->version =  WNM_BSSLOAD_MONITOR_VERSION;
13954 	bwcfg->type = 0;
13955 	bwcfg->weight = 0;
13956 
13957 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
13958 
13959 	if (!strcasecmp(rssi, "rssi"))
13960 		bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
13961 	else if (!strcasecmp(rssi, "cu"))
13962 		bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
13963 	else if (!strcasecmp(rssi, "estm_dl"))
13964 		bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL;
13965 	else {
13966 		/* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu/estm_dl> <band> <weight> */
13967 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
13968 		goto exit;
13969 	}
13970 
13971 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &bwcfg->band)) {
13972 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
13973 		goto exit;
13974 	}
13975 
13976 	if (argc == 2) {
13977 		/* If there is no data after band, getting wnm_bss_select_weight from fw */
13978 		if (bwcfg->band == WLC_BAND_ALL) {
13979 			ANDROID_ERROR(("band option \"all\" is for set only, not get\n"));
13980 			goto exit;
13981 		}
13982 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
13983 				sizeof(*bwcfg),
13984 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
13985 			ANDROID_ERROR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
13986 			goto exit;
13987 		}
13988 		memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
13989 		bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
13990 			(bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" :
13991 			(bwcfg->type == WNM_BSS_SELECT_TYPE_CU) ? "CU": "ESTM_DL",
13992 			wl_android_get_band_str(bwcfg->band), bwcfg->weight);
13993 		err = bytes_written;
13994 		goto exit;
13995 	} else {
13996 		/* if weight is non integer returns command usage error */
13997 		bwcfg->weight = simple_strtol(weight, &endptr, 0);
13998 		if (*endptr != '\0') {
13999 			ANDROID_ERROR(("%s: Command usage error", __func__));
14000 			goto exit;
14001 		}
14002 		/* setting weight for iovar wnm_bss_select_weight to fw */
14003 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
14004 				sizeof(*bwcfg),
14005 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14006 			ANDROID_ERROR(("setting wnm_bss_select_weight failed with err=%d\n", err));
14007 		}
14008 	}
14009 exit:
14010 	if (bwcfg) {
14011 		MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
14012 	}
14013 	return err;
14014 }
14015 
14016 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
14017 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
14018 
wl_cfg80211_wbtext_table_config(struct net_device * ndev,char * data,char * command,int total_len)14019 int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
14020 	char *command, int total_len)
14021 {
14022 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14023 	int bytes_written = 0, err = -EINVAL;
14024 	char rssi[BUFSZN], band[BUFSZN];
14025 	int btcfg_len = 0, i = 0, parsed_len = 0;
14026 	wnm_bss_select_factor_cfg_t *btcfg;
14027 	size_t slen = strlen(data);
14028 	char *start_addr = NULL;
14029 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
14030 
14031 	data[slen] = '\0';
14032 	btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
14033 		(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14034 	if (unlikely(!btcfg)) {
14035 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14036 		err = -ENOMEM;
14037 		goto exit;
14038 	}
14039 
14040 	btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
14041 	btcfg->band = WLC_BAND_AUTO;
14042 	btcfg->type = 0;
14043 	btcfg->count = 0;
14044 
14045 	sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
14046 
14047 	if (!strcasecmp(rssi, "rssi")) {
14048 		btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
14049 	}
14050 	else if (!strcasecmp(rssi, "cu")) {
14051 		btcfg->type = WNM_BSS_SELECT_TYPE_CU;
14052 	}
14053 	else {
14054 		ANDROID_ERROR(("%s: Command usage error\n", __func__));
14055 		goto exit;
14056 	}
14057 
14058 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &btcfg->band)) {
14059 		ANDROID_ERROR(("%s: Command usage, Wrong band\n", __func__));
14060 		goto exit;
14061 	}
14062 
14063 	if ((slen - 1) == (strlen(rssi) + strlen(band))) {
14064 		/* Getting factor table using iovar 'wnm_bss_select_table' from fw */
14065 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
14066 				sizeof(*btcfg),
14067 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
14068 			ANDROID_ERROR(("Getting wnm_bss_select_table failed with err=%d \n", err));
14069 			goto exit;
14070 		}
14071 		memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
14072 		memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
14073 
14074 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14075 					"No of entries in table: %d\n", btcfg->count);
14076 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14077 				"%s factor table\n",
14078 				(btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
14079 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14080 					"low\thigh\tfactor\n");
14081 		for (i = 0; i <= btcfg->count-1; i++) {
14082 			bytes_written += snprintf(command + bytes_written,
14083 				total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
14084 				btcfg->params[i].high, btcfg->params[i].factor);
14085 		}
14086 		err = bytes_written;
14087 		goto exit;
14088 	} else {
14089 		uint16 len = (sizeof(wnm_bss_select_factor_params_t) * WL_FACTOR_TABLE_MAX_LIMIT);
14090 		memset_s(btcfg->params, len, 0, len);
14091 		data += (strlen(rssi) + strlen(band) + 2);
14092 		start_addr = data;
14093 		slen = slen - (strlen(rssi) + strlen(band) + 2);
14094 		for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
14095 			if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
14096 				btcfg->params[i].low = simple_strtol(data, &data, 10);
14097 				data++;
14098 				btcfg->params[i].high = simple_strtol(data, &data, 10);
14099 				data++;
14100 				btcfg->params[i].factor = simple_strtol(data, &data, 10);
14101 				btcfg->count++;
14102 				if (*data == '\0') {
14103 					break;
14104 				}
14105 				data++;
14106 				parsed_len = data - start_addr;
14107 			} else {
14108 				ANDROID_ERROR(("%s:Command usage:less no of args\n", __func__));
14109 				goto exit;
14110 			}
14111 		}
14112 		btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
14113 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
14114 				cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
14115 			ANDROID_ERROR(("seting wnm_bss_select_table failed with err %d\n", err));
14116 			goto exit;
14117 		}
14118 	}
14119 exit:
14120 	if (btcfg) {
14121 		MFREE(cfg->osh, btcfg,
14122 			(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14123 	}
14124 	return err;
14125 }
14126 
14127 s32
wl_cfg80211_wbtext_delta_config(struct net_device * ndev,char * data,char * command,int total_len)14128 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
14129 {
14130 	uint i = 0;
14131 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14132 	int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
14133 	char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
14134 	wl_roamprof_band_t *rp = NULL;
14135 	uint8 band_val = 0, roam_prof_size = 0, roam_prof_ver = 0;
14136 
14137 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
14138 	if (unlikely(!rp)) {
14139 		ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14140 		err = -ENOMEM;
14141 		goto exit;
14142 	}
14143 
14144 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
14145 	if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &band_val)) {
14146 		ANDROID_ERROR(("%s: Missing band\n", __func__));
14147 		goto exit;
14148 	}
14149 	if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver,
14150 		&roam_prof_size))) {
14151 		ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
14152 		err = -EINVAL;
14153 		goto exit;
14154 	}
14155 	if (argc == 2) {
14156 		/* if delta is non integer returns command usage error */
14157 		val = simple_strtol(delta, &endptr, 0);
14158 		if (*endptr != '\0') {
14159 			ANDROID_ERROR(("%s: Command usage error", __func__));
14160 			goto exit;
14161 		}
14162 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
14163 		/*
14164 		 * Checking contents of roam profile data from fw and exits
14165 		 * if code hits below condtion. If remaining length of buffer is
14166 		 * less than roam profile size or if there is no valid entry.
14167 		 */
14168 			if (len >= rp->v1.len) {
14169 				break;
14170 			}
14171 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14172 				if (rp->v2.roam_prof[i].fullscan_period == 0) {
14173 					break;
14174 				}
14175 				if (rp->v2.roam_prof[i].channel_usage != 0) {
14176 					rp->v2.roam_prof[i].roam_delta = val;
14177 				}
14178 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14179 				if (rp->v3.roam_prof[i].fullscan_period == 0) {
14180 					break;
14181 				}
14182 				if (rp->v3.roam_prof[i].channel_usage != 0) {
14183 					rp->v3.roam_prof[i].roam_delta = val;
14184 				}
14185 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14186 				if (rp->v4.roam_prof[i].fullscan_period == 0) {
14187 					break;
14188 				}
14189 				if (rp->v4.roam_prof[i].channel_usage != 0) {
14190 					rp->v4.roam_prof[i].roam_delta = val;
14191 				}
14192 			}
14193 			len += roam_prof_size;
14194 		}
14195 	}
14196 	else {
14197 		if (rp->v2.roam_prof[0].channel_usage != 0) {
14198 			bytes_written = snprintf(command, total_len,
14199 				"%s Delta %d\n", wl_android_get_band_str(rp->v1.band),
14200 				rp->v2.roam_prof[0].roam_delta);
14201 		}
14202 		err = bytes_written;
14203 		goto exit;
14204 	}
14205 	rp->v1.len = len;
14206 	if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
14207 			sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
14208 			&cfg->ioctl_buf_sync)) < 0) {
14209 		ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
14210 	}
14211 exit :
14212 	if (rp) {
14213 		MFREE(cfg->osh, rp, sizeof(*rp));
14214 	}
14215 	return err;
14216 }
14217 #endif /* WBTEXT */
14218