xref: /OK3568_Linux_fs/external/rkwifibt/drivers/infineon/wl_android.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Linux cfg80211 driver - Android related functions
3  *
4  * Portions of this code are copyright (c) 2021 Cypress Semiconductor Corporation
5  *
6  * Copyright (C) 1999-2017, Broadcom Corporation
7  *
8  *      Unless you and Broadcom execute a separate written software license
9  * agreement governing use of this software, this software is licensed to you
10  * under the terms of the GNU General Public License version 2 (the "GPL"),
11  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12  * following added to such license:
13  *
14  *      As a special exception, the copyright holders of this software give you
15  * permission to link this software with independent modules, and to copy and
16  * distribute the resulting executable under terms of your choice, provided that
17  * you also meet, for each linked independent module, the terms and conditions of
18  * the license of that module.  An independent module is a module which is not
19  * derived from this software.  The special exception does not apply to any
20  * modifications of the software.
21  *
22  *      Notwithstanding the above, under no circumstances may you combine this
23  * software in any way with any other Broadcom software provided under a license
24  * other than the GPL, without Broadcom's express prior written consent.
25  *
26  *
27  * <<Broadcom-WL-IPTag/Open:>>
28  *
29  * $Id: wl_android.c 814826 2019-04-15 05:25:59Z $
30  */
31 
32 #include <linux/string.h>
33 #include <linux/module.h>
34 #include <linux/netdevice.h>
35 #include <net/netlink.h>
36 
37 #include <wl_android.h>
38 #include <wldev_common.h>
39 #include <wlioctl.h>
40 #include <wlioctl_utils.h>
41 #include <bcmutils.h>
42 #include <bcmstdlib_s.h>
43 #include <linux_osl.h>
44 #include <dhd_dbg.h>
45 #include <dngl_stats.h>
46 #include <dhd.h>
47 #include <bcmip.h>
48 #ifdef PNO_SUPPORT
49 #include <dhd_pno.h>
50 #endif // endif
51 #ifdef BCMSDIO
52 #include <bcmsdbus.h>
53 #endif // endif
54 #ifdef WL_CFG80211
55 #include <wl_cfg80211.h>
56 #include <wl_cfgscan.h>
57 #endif // endif
58 #ifdef WL_NAN
59 #include <wl_cfgnan.h>
60 #endif /* WL_NAN */
61 #ifdef DHDTCPACK_SUPPRESS
62 #include <dhd_ip.h>
63 #endif /* DHDTCPACK_SUPPRESS */
64 #include <bcmwifi_rspec.h>
65 #include <bcmwifi_channels.h>
66 #include <dhd_linux.h>
67 #include <bcmiov.h>
68 #ifdef DHD_PKT_LOGGING
69 #include <dhd_pktlog.h>
70 #endif /* DHD_PKT_LOGGING */
71 #ifdef WL_BCNRECV
72 #include <wl_cfgvendor.h>
73 #include <brcm_nl80211.h>
74 #endif /* WL_BCNRECV */
75 #ifdef WL_MBO
76 #include <mbo.h>
77 #endif /* WL_MBO */
78 
79 #ifdef DHD_BANDSTEER
80 #include <dhd_bandsteer.h>
81 #endif /* DHD_BANDSTEER */
82 
83 #ifdef WL_STATIC_IF
84 #define WL_BSSIDX_MAX	16
85 #endif /* WL_STATIC_IF */
86 /*
87  * Android private command strings, PLEASE define new private commands here
88  * so they can be updated easily in the future (if needed)
89  */
90 
91 #define CMD_START		"START"
92 #define CMD_STOP		"STOP"
93 
94 #ifdef AUTOMOTIVE_FEATURE
95 #define CMD_SCAN_ACTIVE         "SCAN-ACTIVE"
96 #define CMD_SCAN_PASSIVE        "SCAN-PASSIVE"
97 #define CMD_RSSI                "RSSI"
98 #define CMD_LINKSPEED		"LINKSPEED"
99 #endif /* AUTOMOTIVE_FEATURE */
100 
101 #define CMD_RXFILTER_START	"RXFILTER-START"
102 #define CMD_RXFILTER_STOP	"RXFILTER-STOP"
103 #define CMD_RXFILTER_ADD	"RXFILTER-ADD"
104 #define CMD_RXFILTER_REMOVE	"RXFILTER-REMOVE"
105 #define CMD_BTCOEXSCAN_START	"BTCOEXSCAN-START"
106 #define CMD_BTCOEXSCAN_STOP	"BTCOEXSCAN-STOP"
107 #define CMD_BTCOEXMODE		"BTCOEXMODE"
108 #define CMD_SETSUSPENDOPT	"SETSUSPENDOPT"
109 #define CMD_SETSUSPENDMODE      "SETSUSPENDMODE"
110 #define CMD_SETDTIM_IN_SUSPEND  "SET_DTIM_IN_SUSPEND"
111 #define CMD_MAXDTIM_IN_SUSPEND  "MAX_DTIM_IN_SUSPEND"
112 #define CMD_DISDTIM_IN_SUSPEND  "DISABLE_DTIM_IN_SUSPEND"
113 #define CMD_P2P_DEV_ADDR	"P2P_DEV_ADDR"
114 #define CMD_SETFWPATH		"SETFWPATH"
115 #define CMD_SETBAND		"SETBAND"
116 #define CMD_GETBAND		"GETBAND"
117 #define CMD_COUNTRY		"COUNTRY"
118 #define CMD_CHANNELS_IN_CC      "CHANNELS_IN_CC"
119 #define CMD_P2P_SET_NOA		"P2P_SET_NOA"
120 #if !defined WL_ENABLE_P2P_IF
121 #define CMD_P2P_GET_NOA			"P2P_GET_NOA"
122 #endif /* WL_ENABLE_P2P_IF */
123 #define CMD_P2P_SD_OFFLOAD		"P2P_SD_"
124 #define CMD_P2P_LISTEN_OFFLOAD		"P2P_LO_"
125 #define CMD_P2P_SET_PS		"P2P_SET_PS"
126 #define CMD_P2P_ECSA		"P2P_ECSA"
127 #define CMD_P2P_INC_BW		"P2P_INCREASE_BW"
128 #define CMD_SET_AP_WPS_P2P_IE 		"SET_AP_WPS_P2P_IE"
129 #define CMD_SETROAMMODE 	"SETROAMMODE"
130 #define CMD_SETIBSSBEACONOUIDATA	"SETIBSSBEACONOUIDATA"
131 #define CMD_MIRACAST		"MIRACAST"
132 #ifdef WL_NAN
133 #define CMD_NAN         "NAN_"
134 #endif /* WL_NAN */
135 #define CMD_COUNTRY_DELIMITER "/"
136 
137 #if defined(WL_SUPPORT_AUTO_CHANNEL)
138 #define CMD_GET_BEST_CHANNELS	"GET_BEST_CHANNELS"
139 #endif /* WL_SUPPORT_AUTO_CHANNEL */
140 
141 #define CMD_CHANSPEC      "CHANSPEC"
142 #ifdef AUTOMOTIVE_FEATURE
143 #define CMD_DATARATE      "DATARATE"
144 #define CMD_80211_MODE    "MODE"  /* 802.11 mode a/b/g/n/ac */
145 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
146 #endif /* AUTOMOTIVE_FEATURE */
147 #define CMD_SET_CSA       "SETCSA"
148 #define CMD_RSDB_MODE	"RSDB_MODE"
149 #ifdef WL_SUPPORT_AUTO_CHANNEL
150 #define CMD_SET_HAPD_AUTO_CHANNEL	"HAPD_AUTO_CHANNEL"
151 #endif /* WL_SUPPORT_AUTO_CHANNEL */
152 #ifdef CUSTOMER_HW4_PRIVATE_CMD
153 /* Hostapd private command */
154 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
155 #define CMD_HAPD_STA_DISASSOC		"HAPD_STA_DISASSOC"
156 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
157 #ifdef SUPPORT_SET_LPC
158 #define CMD_HAPD_LPC_ENABLED		"HAPD_LPC_ENABLED"
159 #endif /* SUPPORT_SET_LPC */
160 #ifdef SUPPORT_TRIGGER_HANG_EVENT
161 #define CMD_TEST_FORCE_HANG		"TEST_FORCE_HANG"
162 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
163 #ifdef SUPPORT_LTECX
164 #define CMD_LTECX_SET		"LTECOEX"
165 #endif /* SUPPORT_LTECX */
166 #ifdef TEST_TX_POWER_CONTROL
167 #define CMD_TEST_SET_TX_POWER		"TEST_SET_TX_POWER"
168 #define CMD_TEST_GET_TX_POWER		"TEST_GET_TX_POWER"
169 #endif /* TEST_TX_POWER_CONTROL */
170 #define CMD_SARLIMIT_TX_CONTROL		"SET_TX_POWER_CALLING"
171 #ifdef SUPPORT_SET_TID
172 #define CMD_SET_TID		"SET_TID"
173 #define CMD_GET_TID		"GET_TID"
174 #endif /* SUPPORT_SET_TID */
175 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
176 #define CMD_KEEP_ALIVE		"KEEPALIVE"
177 #ifdef SUPPORT_HIDDEN_AP
178 #define CMD_SET_HAPD_MAX_NUM_STA	"MAX_NUM_STA"
179 #define CMD_SET_HAPD_SSID		"HAPD_SSID"
180 #define CMD_SET_HAPD_HIDE_SSID		"HIDE_SSID"
181 #endif /* SUPPORT_HIDDEN_AP */
182 #ifdef PNO_SUPPORT
183 #define CMD_PNOSSIDCLR_SET	"PNOSSIDCLR"
184 #define CMD_PNOSETUP_SET	"PNOSETUP "
185 #define CMD_PNOENABLE_SET	"PNOFORCE"
186 #define CMD_PNODEBUG_SET	"PNODEBUG"
187 #define CMD_WLS_BATCHING	"WLS_BATCHING"
188 #endif /* PNO_SUPPORT */
189 
190 #ifdef AUTOMOTIVE_FEATURE
191 #define	CMD_HAPD_MAC_FILTER	"HAPD_MAC_FILTER"
192 #endif /* AUTOMOTIVE_FEATURE */
193 #define CMD_ADDIE		"ADD_IE"
194 #define CMD_DELIE		"DEL_IE"
195 
196 #if defined(CUSTOMER_HW4_PRIVATE_CMD) || defined(IGUANA_LEGACY_CHIPS)
197 
198 #ifdef ROAM_API
199 #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
200 #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
201 #define CMD_ROAMDELTA_SET "SETROAMDELTA"
202 #define CMD_ROAMDELTA_GET "GETROAMDELTA"
203 #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
204 #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
205 #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
206 #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
207 #ifdef AUTOMOTIVE_FEATURE
208 #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
209 #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
210 #endif /* AUTOMOTIVE_FEATURE */
211 #endif /* ROAM_API */
212 
213 #if defined(SUPPORT_RANDOM_MAC_SCAN)
214 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
215 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
216 #endif /* SUPPORT_RANDOM_MAC_SCAN */
217 
218 #ifdef WES_SUPPORT
219 #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
220 #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
221 #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
222 #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
223 
224 #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
225 #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
226 #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
227 #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
228 #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
229 #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
230 #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
231 #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
232 #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
233 #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
234 #define CMD_GETSCANNPROBES "GETSCANNPROBES"
235 #define CMD_SETSCANNPROBES "SETSCANNPROBES"
236 #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
237 #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
238 #define CMD_SETJOINPREFER "SETJOINPREFER"
239 
240 #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
241 #define CMD_REASSOC "REASSOC"
242 
243 #define CMD_GETWESMODE "GETWESMODE"
244 #define CMD_SETWESMODE "SETWESMODE"
245 
246 #define CMD_GETOKCMODE "GETOKCMODE"
247 #define CMD_SETOKCMODE "SETOKCMODE"
248 
249 #define CMD_OKC_SET_PMK         "SET_PMK"
250 #define CMD_OKC_ENABLE          "OKC_ENABLE"
251 
252 typedef struct android_wifi_reassoc_params {
253 	unsigned char bssid[18];
254 	int channel;
255 } android_wifi_reassoc_params_t;
256 
257 #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
258 
259 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
260 
261 typedef struct android_wifi_af_params {
262 	unsigned char bssid[18];
263 	int channel;
264 	int dwell_time;
265 	int len;
266 	unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
267 } android_wifi_af_params_t;
268 
269 #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
270 #endif /* WES_SUPPORT */
271 #ifdef SUPPORT_AMPDU_MPDU_CMD
272 #define CMD_AMPDU_MPDU		"AMPDU_MPDU"
273 #endif /* SUPPORT_AMPDU_MPDU_CMD */
274 
275 #define CMD_CHANGE_RL 	"CHANGE_RL"
276 #define CMD_RESTORE_RL  "RESTORE_RL"
277 
278 #define CMD_SET_RMC_ENABLE			"SETRMCENABLE"
279 #define CMD_SET_RMC_TXRATE			"SETRMCTXRATE"
280 #define CMD_SET_RMC_ACTPERIOD		"SETRMCACTIONPERIOD"
281 #define CMD_SET_RMC_IDLEPERIOD		"SETRMCIDLEPERIOD"
282 #define CMD_SET_RMC_LEADER			"SETRMCLEADER"
283 #define CMD_SET_RMC_EVENT			"SETRMCEVENT"
284 
285 #define CMD_SET_SCSCAN		"SETSINGLEANT"
286 #define CMD_GET_SCSCAN		"GETSINGLEANT"
287 #ifdef WLTDLS
288 #define CMD_TDLS_RESET "TDLS_RESET"
289 #endif /* WLTDLS */
290 
291 #ifdef CONFIG_SILENT_ROAM
292 #define CMD_SROAM_TURN_ON	"SROAMTURNON"
293 #define CMD_SROAM_SET_INFO	"SROAMSETINFO"
294 #define CMD_SROAM_GET_INFO	"SROAMGETINFO"
295 #endif /* CONFIG_SILENT_ROAM */
296 
297 #define CMD_SET_DISCONNECT_IES  "SET_DISCONNECT_IES"
298 
299 #ifdef FCC_PWR_LIMIT_2G
300 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
301 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
302 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
303 #define CUSTOMER_HW4_ENABLE		0
304 #define CUSTOMER_HW4_DISABLE	-1
305 #define CUSTOMER_HW4_EN_CONVERT(i)	(i += 1)
306 #endif /* FCC_PWR_LIMIT_2G */
307 
308 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
309 
310 #ifdef WLFBT
311 #define CMD_GET_FTKEY      "GET_FTKEY"
312 #endif // endif
313 
314 #ifdef WLAIBSS
315 #define CMD_SETIBSSTXFAILEVENT		"SETIBSSTXFAILEVENT"
316 #define CMD_GET_IBSS_PEER_INFO		"GETIBSSPEERINFO"
317 #define CMD_GET_IBSS_PEER_INFO_ALL	"GETIBSSPEERINFOALL"
318 #define CMD_SETIBSSROUTETABLE		"SETIBSSROUTETABLE"
319 #define CMD_SETIBSSAMPDU			"SETIBSSAMPDU"
320 #define CMD_SETIBSSANTENNAMODE		"SETIBSSANTENNAMODE"
321 #endif /* WLAIBSS */
322 
323 #define CMD_ROAM_OFFLOAD			"SETROAMOFFLOAD"
324 #define CMD_INTERFACE_CREATE			"INTERFACE_CREATE"
325 #define CMD_INTERFACE_DELETE			"INTERFACE_DELETE"
326 #define CMD_GET_LINK_STATUS			"GETLINKSTATUS"
327 
328 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
329 #define CMD_GET_BSS_INFO            "GETBSSINFO"
330 #define CMD_GET_ASSOC_REJECT_INFO   "GETASSOCREJECTINFO"
331 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
332 #define CMD_GET_STA_INFO   "GETSTAINFO"
333 
334 /* related with CMD_GET_LINK_STATUS */
335 #define WL_ANDROID_LINK_VHT					0x01
336 #define WL_ANDROID_LINK_MIMO					0x02
337 #define WL_ANDROID_LINK_AP_VHT_SUPPORT		0x04
338 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT	0x08
339 
340 #ifdef P2PRESP_WFDIE_SRC
341 #define CMD_P2P_SET_WFDIE_RESP      "P2P_SET_WFDIE_RESP"
342 #define CMD_P2P_GET_WFDIE_RESP      "P2P_GET_WFDIE_RESP"
343 #endif /* P2PRESP_WFDIE_SRC */
344 
345 #define CMD_DFS_AP_MOVE			"DFS_AP_MOVE"
346 #define CMD_WBTEXT_ENABLE		"WBTEXT_ENABLE"
347 #define CMD_WBTEXT_PROFILE_CONFIG	"WBTEXT_PROFILE_CONFIG"
348 #define CMD_WBTEXT_WEIGHT_CONFIG	"WBTEXT_WEIGHT_CONFIG"
349 #define CMD_WBTEXT_TABLE_CONFIG		"WBTEXT_TABLE_CONFIG"
350 #define CMD_WBTEXT_DELTA_CONFIG		"WBTEXT_DELTA_CONFIG"
351 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD	"WBTEXT_BTM_TIMER_THRESHOLD"
352 #define CMD_WBTEXT_BTM_DELTA		"WBTEXT_BTM_DELTA"
353 #define CMD_WBTEXT_ESTM_ENABLE	"WBTEXT_ESTM_ENABLE"
354 
355 #ifdef WBTEXT
356 #define CMD_WBTEXT_PROFILE_CONFIG	"WBTEXT_PROFILE_CONFIG"
357 #define CMD_WBTEXT_WEIGHT_CONFIG	"WBTEXT_WEIGHT_CONFIG"
358 #define CMD_WBTEXT_TABLE_CONFIG		"WBTEXT_TABLE_CONFIG"
359 #define CMD_WBTEXT_DELTA_CONFIG		"WBTEXT_DELTA_CONFIG"
360 #define DEFAULT_WBTEXT_PROFILE_A_V2		"a -70 -75 70 10 -75 -128 0 10"
361 #define DEFAULT_WBTEXT_PROFILE_B_V2		"b -60 -75 70 10 -75 -128 0 10"
362 #define DEFAULT_WBTEXT_PROFILE_A_V3		"a -70 -75 70 10 -75 -128 0 10"
363 #define DEFAULT_WBTEXT_PROFILE_B_V3		"b -60 -75 70 10 -75 -128 0 10"
364 #define DEFAULT_WBTEXT_WEIGHT_RSSI_A	"RSSI a 65"
365 #define DEFAULT_WBTEXT_WEIGHT_RSSI_B	"RSSI b 65"
366 #define DEFAULT_WBTEXT_WEIGHT_CU_A	"CU a 35"
367 #define DEFAULT_WBTEXT_WEIGHT_CU_B	"CU b 35"
368 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A	"ESTM_DL a 70"
369 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B	"ESTM_DL b 70"
370 #ifdef WBTEXT_SCORE_V2
371 #define DEFAULT_WBTEXT_TABLE_RSSI_A	"RSSI a 0 55 100 55 60 90 \
372 60 70 60 70 80 20 80 128 20"
373 #define DEFAULT_WBTEXT_TABLE_RSSI_B	"RSSI b 0 55 100 55 60 90 \
374 60 70 60 70 80 20 80 128 20"
375 #define DEFAULT_WBTEXT_TABLE_CU_A	"CU a 0 30 100 30 80 20 \
376 80 100 20"
377 #define DEFAULT_WBTEXT_TABLE_CU_B	"CU b 0 10 100 10 70 20 \
378 70 100 20"
379 #else
380 #define DEFAULT_WBTEXT_TABLE_RSSI_A	"RSSI a 0 55 100 55 60 90 \
381 60 65 70 65 70 50 70 128 20"
382 #define DEFAULT_WBTEXT_TABLE_RSSI_B	"RSSI b 0 55 100 55 60 90 \
383 60 65 70 65 70 50 70 128 20"
384 #define DEFAULT_WBTEXT_TABLE_CU_A	"CU a 0 30 100 30 50 90 \
385 50 60 70 60 80 50 80 100 20"
386 #define DEFAULT_WBTEXT_TABLE_CU_B	"CU b 0 10 100 10 25 90 \
387 25 40 70 40 70 50 70 100 20"
388 #endif /* WBTEXT_SCORE_V2 */
389 #endif /* WBTEXT */
390 
391 #define BUFSZ 8
392 #define BUFSZN	BUFSZ + 1
393 
394 #define _S(x) #x
395 #define S(x) _S(x)
396 
397 #define  MAXBANDS    2  /**< Maximum #of bands */
398 #define BAND_2G_INDEX      0
399 #define BAND_5G_INDEX      0
400 
401 typedef union {
402 	wl_roam_prof_band_v1_t v1;
403 	wl_roam_prof_band_v2_t v2;
404 	wl_roam_prof_band_v3_t v3;
405 } wl_roamprof_band_t;
406 
407 #ifdef WLWFDS
408 #define CMD_ADD_WFDS_HASH	"ADD_WFDS_HASH"
409 #define CMD_DEL_WFDS_HASH	"DEL_WFDS_HASH"
410 #endif /* WLWFDS */
411 
412 #ifdef SET_RPS_CPUS
413 #define CMD_RPSMODE  "RPSMODE"
414 #endif /* SET_RPS_CPUS */
415 
416 #ifdef BT_WIFI_HANDOVER
417 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
418 #endif /* BT_WIFI_HANDOVER */
419 
420 #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
421 
422 #ifdef SUPPORT_RSSI_SUM_REPORT
423 #define CMD_SET_RSSI_LOGGING				"SET_RSSI_LOGGING"
424 #define CMD_GET_RSSI_LOGGING				"GET_RSSI_LOGGING"
425 #define CMD_GET_RSSI_PER_ANT				"GET_RSSI_PER_ANT"
426 #endif /* SUPPORT_RSSI_SUM_REPORT */
427 
428 #define CMD_GET_SNR							"GET_SNR"
429 
430 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
431 #define CMD_SET_AP_BEACONRATE				"SET_AP_BEACONRATE"
432 #define CMD_GET_AP_BASICRATE				"GET_AP_BASICRATE"
433 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
434 
435 #ifdef SUPPORT_AP_RADIO_PWRSAVE
436 #define CMD_SET_AP_RPS						"SET_AP_RPS"
437 #define CMD_GET_AP_RPS						"GET_AP_RPS"
438 #define CMD_SET_AP_RPS_PARAMS				"SET_AP_RPS_PARAMS"
439 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
440 
441 #ifdef DHD_BANDSTEER
442 #define CMD_BANDSTEER   "BANDSTEER"
443 #define CMD_BANDSTEER_TRIGGER  "TRIGGER_BANDSTEER"
444 #endif /* DHD_BANDSTEER */
445 /* miracast related definition */
446 #define MIRACAST_MODE_OFF	0
447 #define MIRACAST_MODE_SOURCE	1
448 #define MIRACAST_MODE_SINK	2
449 
450 #define CMD_CHANNEL_WIDTH "CHANNEL_WIDTH"
451 #define CMD_TRANSITION_DISABLE "TRANSITION_DISABLE"
452 
453 #ifdef ENABLE_HOGSQS
454 #define CMD_AP_HOGSQS  "HOGSQS"
455 #endif /* ENABLE_HOGSQS */
456 
457 #ifdef CONNECTION_STATISTICS
458 #define CMD_GET_CONNECTION_STATS	"GET_CONNECTION_STATS"
459 
460 struct connection_stats {
461 	u32 txframe;
462 	u32 txbyte;
463 	u32 txerror;
464 	u32 rxframe;
465 	u32 rxbyte;
466 	u32 txfail;
467 	u32 txretry;
468 	u32 txretrie;
469 	u32 txrts;
470 	u32 txnocts;
471 	u32 txexptime;
472 	u32 txrate;
473 	u8	chan_idle;
474 };
475 #endif /* CONNECTION_STATISTICS */
476 
477 #ifdef SUPPORT_LQCM
478 #define CMD_SET_LQCM_ENABLE			"SET_LQCM_ENABLE"
479 #define CMD_GET_LQCM_REPORT			"GET_LQCM_REPORT"
480 #endif // endif
481 
482 static LIST_HEAD(miracast_resume_list);
483 static u8 miracast_cur_mode;
484 
485 #ifdef DHD_LOG_DUMP
486 #define CMD_NEW_DEBUG_PRINT_DUMP	"DEBUG_DUMP"
487 #define SUBCMD_UNWANTED			"UNWANTED"
488 #define SUBCMD_DISCONNECTED		"DISCONNECTED"
489 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
490 #endif /* DHD_LOG_DUMP */
491 
492 #ifdef DHD_STATUS_LOGGING
493 #define CMD_DUMP_STATUS_LOG		"DUMP_STAT_LOG"
494 #define CMD_QUERY_STATUS_LOG		"QUERY_STAT_LOG"
495 #endif /* DHD_STATUS_LOGGING */
496 
497 #ifdef DHD_HANG_SEND_UP_TEST
498 #define CMD_MAKE_HANG  "MAKE_HANG"
499 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
500 #ifdef DHD_DEBUG_UART
501 extern bool dhd_debug_uart_is_running(struct net_device *dev);
502 #endif	/* DHD_DEBUG_UART */
503 
504 struct io_cfg {
505 	s8 *iovar;
506 	s32 param;
507 	u32 ioctl;
508 	void *arg;
509 	u32 len;
510 	struct list_head list;
511 };
512 
513 typedef enum {
514 	HEAD_SAR_BACKOFF_DISABLE = -1,
515 	HEAD_SAR_BACKOFF_ENABLE = 0,
516 	GRIP_SAR_BACKOFF_DISABLE,
517 	GRIP_SAR_BACKOFF_ENABLE,
518 	NR_mmWave_SAR_BACKOFF_DISABLE,
519 	NR_mmWave_SAR_BACKOFF_ENABLE,
520 	NR_Sub6_SAR_BACKOFF_DISABLE,
521 	NR_Sub6_SAR_BACKOFF_ENABLE,
522 	SAR_BACKOFF_DISABLE_ALL
523 } sar_modes;
524 
525 #if defined(BCMFW_ROAM_ENABLE)
526 #define CMD_SET_ROAMPREF	"SET_ROAMPREF"
527 
528 #define MAX_NUM_SUITES		10
529 #define WIDTH_AKM_SUITE		8
530 #define JOIN_PREF_RSSI_LEN		0x02
531 #define JOIN_PREF_RSSI_SIZE		4	/* RSSI pref header size in bytes */
532 #define JOIN_PREF_WPA_HDR_SIZE		4 /* WPA pref header size in bytes */
533 #define JOIN_PREF_WPA_TUPLE_SIZE	12	/* Tuple size in bytes */
534 #define JOIN_PREF_MAX_WPA_TUPLES	16
535 #define MAX_BUF_SIZE		(JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +	\
536 				           (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
537 #endif /* BCMFW_ROAM_ENABLE */
538 
539 #define CMD_DEBUG_VERBOSE          "DEBUG_VERBOSE"
540 #ifdef WL_NATOE
541 
542 #define CMD_NATOE		"NATOE"
543 
544 #define NATOE_MAX_PORT_NUM	65535
545 
546 /* natoe command info structure */
547 typedef struct wl_natoe_cmd_info {
548 	uint8  *command;        /* pointer to the actual command */
549 	uint16 tot_len;        /* total length of the command */
550 	uint16 bytes_written;  /* Bytes written for get response */
551 } wl_natoe_cmd_info_t;
552 
553 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
554 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
555 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
556 
557 struct wl_natoe_sub_cmd {
558 	char *name;
559 	uint8  version;              /* cmd  version */
560 	uint16 id;                   /* id for the dongle f/w switch/case */
561 	uint16 type;                 /* base type of argument */
562 	natoe_cmd_handler_t *handler; /* cmd handler  */
563 };
564 
565 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
566 static int wl_android_process_natoe_cmd(struct net_device *dev,
567 		char *command, int total_len);
568 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
569 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
570 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
571 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
572 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
573 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
574 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
575 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
576 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
577 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
578 
579 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
580 	/* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
581 	{"enable", 0x01, WL_NATOE_CMD_ENABLE,
582 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
583 	},
584 	{"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
585 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
586 	},
587 	{"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
588 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
589 	},
590 	{"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
591 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
592 	},
593 	{"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
594 	IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
595 	},
596 	{NULL, 0, 0, 0, NULL}
597 };
598 
599 #endif /* WL_NATOE */
600 
601 static int
602 wl_android_get_channel_list(struct net_device *dev, char *command, int total_len);
603 
604 #ifdef SET_PCIE_IRQ_CPU_CORE
605 #define CMD_PCIE_IRQ_CORE	"PCIE_IRQ_CORE"
606 #endif /* SET_PCIE_IRQ_CPU_CORE */
607 
608 #ifdef WLADPS_PRIVATE_CMD
609 #define CMD_SET_ADPS	"SET_ADPS"
610 #define CMD_GET_ADPS	"GET_ADPS"
611 #endif /* WLADPS_PRIVATE_CMD */
612 
613 #ifdef DHD_PKT_LOGGING
614 #define CMD_PKTLOG_FILTER_ENABLE	"PKTLOG_FILTER_ENABLE"
615 #define CMD_PKTLOG_FILTER_DISABLE	"PKTLOG_FILTER_DISABLE"
616 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE	"PKTLOG_FILTER_PATTERN_ENABLE"
617 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE	"PKTLOG_FILTER_PATTERN_DISABLE"
618 #define CMD_PKTLOG_FILTER_ADD	"PKTLOG_FILTER_ADD"
619 #define CMD_PKTLOG_FILTER_DEL	"PKTLOG_FILTER_DEL"
620 #define CMD_PKTLOG_FILTER_INFO	"PKTLOG_FILTER_INFO"
621 #define CMD_PKTLOG_START	"PKTLOG_START"
622 #define CMD_PKTLOG_STOP		"PKTLOG_STOP"
623 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
624 #define CMD_PKTLOG_MINMIZE_ENABLE	"PKTLOG_MINMIZE_ENABLE"
625 #define CMD_PKTLOG_MINMIZE_DISABLE	"PKTLOG_MINMIZE_DISABLE"
626 #define CMD_PKTLOG_CHANGE_SIZE	"PKTLOG_CHANGE_SIZE"
627 #endif /* DHD_PKT_LOGGING */
628 
629 #ifdef DHD_EVENT_LOG_FILTER
630 #define CMD_EWP_FILTER		"EWP_FILTER"
631 #endif /* DHD_EVENT_LOG_FILTER */
632 
633 #ifdef WL_BCNRECV
634 #define CMD_BEACON_RECV "BEACON_RECV"
635 #endif /* WL_BCNRECV */
636 #ifdef WL_CAC_TS
637 #define CMD_CAC_TSPEC "CAC_TSPEC"
638 #endif /* WL_CAC_TS */
639 #ifdef WL_CHAN_UTIL
640 #define CMD_GET_CHAN_UTIL "GET_CU"
641 #endif /* WL_CHAN_UTIL */
642 
643 /* drv command info structure */
644 typedef struct wl_drv_cmd_info {
645 	uint8  *command;        /* pointer to the actual command */
646 	uint16 tot_len;         /* total length of the command */
647 	uint16 bytes_written;   /* Bytes written for get response */
648 } wl_drv_cmd_info_t;
649 
650 typedef struct wl_drv_sub_cmd wl_drv_sub_cmd_t;
651 typedef int (drv_cmd_handler_t)(struct net_device *dev,
652 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
653 
654 struct wl_drv_sub_cmd {
655 	char *name;
656 	uint8  version;              /* cmd  version */
657 	uint16 id;                   /* id for the dongle f/w switch/case */
658 	uint16 type;                 /* base type of argument */
659 	drv_cmd_handler_t *handler;  /* cmd handler  */
660 };
661 
662 #ifdef WL_MBO
663 
664 #define CMD_MBO		"MBO"
665 enum {
666 	WL_MBO_CMD_NON_CHAN_PREF = 1,
667 	WL_MBO_CMD_CELL_DATA_CAP = 2
668 };
669 #define WL_ANDROID_MBO_FUNC(suffix) wl_android_mbo_subcmd_ ##suffix
670 
671 static int wl_android_process_mbo_cmd(struct net_device *dev,
672 		char *command, int total_len);
673 static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
674 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
675 static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
676 		const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
677 
678 static const wl_drv_sub_cmd_t mbo_cmd_list[] = {
679 	{"non_pref_chan", 0x01, WL_MBO_CMD_NON_CHAN_PREF,
680 	IOVT_BUFFER, WL_ANDROID_MBO_FUNC(non_pref_chan)
681 	},
682 	{"cell_data_cap", 0x01, WL_MBO_CMD_CELL_DATA_CAP,
683 	IOVT_BUFFER, WL_ANDROID_MBO_FUNC(cell_data_cap)
684 	},
685 	{NULL, 0, 0, 0, NULL}
686 };
687 
688 #endif /* WL_MBO */
689 
690 #ifdef WL_GENL
691 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
692 static int wl_genl_init(void);
693 static int wl_genl_deinit(void);
694 
695 extern struct net init_net;
696 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
697  * possible values defined in net/netlink.h
698  */
699 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
700 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
701 	[BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
702 	[BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
703 };
704 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)) */
705 
706 #define WL_GENL_VER 1
707 /* family definition */
708 static struct genl_family wl_genl_family = {
709 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
710 	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
711 #endif // endif
712 	.hdrsize = 0,
713 	.name = "bcm-genl",        /* Netlink I/F for Android */
714 	.version = WL_GENL_VER,     /* Version Number */
715 	.maxattr = BCM_GENL_ATTR_MAX,
716 };
717 
718 /* commands: mapping between the command enumeration and the actual function */
719 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
720 struct genl_ops wl_genl_ops[] = {
721 	{
722 	.cmd = BCM_GENL_CMD_MSG,
723 	.flags = 0,
724 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
725 	.policy = wl_genl_policy,
726 #else
727 	.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
728 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)) */
729 	.doit = wl_genl_handle_msg,
730 	.dumpit = NULL,
731 	},
732 };
733 #else
734 struct genl_ops wl_genl_ops = {
735 	.cmd = BCM_GENL_CMD_MSG,
736 	.flags = 0,
737 	.policy = wl_genl_policy,
738 	.doit = wl_genl_handle_msg,
739 	.dumpit = NULL,
740 
741 };
742 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
743 
744 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
745 static struct genl_multicast_group wl_genl_mcast[] = {
746 	 { .name = "bcm-genl-mcast", },
747 };
748 #else
749 static struct genl_multicast_group wl_genl_mcast = {
750 	.id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
751 	.name = "bcm-genl-mcast",
752 };
753 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
754 #endif /* WL_GENL */
755 
756 #ifdef SUPPORT_LQCM
757 #define LQCM_ENAB_MASK			0x000000FF	/* LQCM enable flag mask */
758 #define LQCM_TX_INDEX_MASK		0x0000FF00	/* LQCM tx index mask */
759 #define LQCM_RX_INDEX_MASK		0x00FF0000	/* LQCM rx index mask */
760 
761 #define LQCM_TX_INDEX_SHIFT		8	/* LQCM tx index shift */
762 #define LQCM_RX_INDEX_SHIFT		16	/* LQCM rx index shift */
763 #endif /* SUPPORT_LQCM */
764 
765 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
766 #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS	7
767 static int priv_cmd_errors = 0;
768 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
769 
770 /**
771  * Extern function declarations (TODO: move them to dhd_linux.h)
772  */
773 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
774 int dhd_dev_init_ioctl(struct net_device *dev);
775 #ifdef WL_CFG80211
776 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
777 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
778 #ifdef WES_SUPPORT
779 int wl_cfg80211_set_wes_mode(int mode);
780 int wl_cfg80211_get_wes_mode(void);
781 #endif /* WES_SUPPORT */
782 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)783 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
784 { return 0; }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)785 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
786 { return 0; }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)787 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
788 { return 0; }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)789 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
790 { return 0; }
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)791 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
792 { return 0; }
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)793 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
794 { return 0; }
795 #endif /* WK_CFG80211 */
796 #ifdef WBTEXT
797 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
798 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
799 	char *command, int total_len);
800 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
801 	char *command, int total_len);
802 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
803 	char *command, int total_len);
804 static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
805 	uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size);
806 #endif /* WBTEXT */
807 #ifdef WES_SUPPORT
808 /* wl_roam.c */
809 extern int get_roamscan_mode(struct net_device *dev, int *mode);
810 extern int set_roamscan_mode(struct net_device *dev, int mode);
811 extern int get_roamscan_channel_list(struct net_device *dev,
812 	unsigned char channels[], int n_channels);
813 extern int set_roamscan_channel_list(struct net_device *dev, unsigned char n,
814 	unsigned char channels[], int ioctl_ver);
815 #endif /* WES_SUPPORT */
816 #ifdef ROAM_CHANNEL_CACHE
817 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
818 #endif /* ROAM_CHANNEL_CACHE */
819 
820 #ifdef ENABLE_4335BT_WAR
821 extern int bcm_bt_lock(int cookie);
822 extern void bcm_bt_unlock(int cookie);
823 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24;	/* cookie is "WiFi" */
824 #endif /* ENABLE_4335BT_WAR */
825 
826 extern bool ap_fw_loaded;
827 extern char iface_name[IFNAMSIZ];
828 #ifdef DHD_PM_CONTROL_FROM_FILE
829 extern bool g_pm_control;
830 #endif	/* DHD_PM_CONTROL_FROM_FILE */
831 
832 /* private command support for restoring roam/scan parameters */
833 #ifdef SUPPORT_RESTORE_SCAN_PARAMS
834 #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
835 
836 typedef int (*PRIV_CMD_HANDLER) (struct net_device *dev, char *command);
837 typedef int (*PRIV_CMD_HANDLER_WITH_LEN) (struct net_device *dev, char *command, int total_len);
838 
839 enum {
840 	RESTORE_TYPE_UNSPECIFIED = 0,
841 	RESTORE_TYPE_PRIV_CMD = 1,
842 	RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
843 };
844 
845 typedef struct android_restore_scan_params {
846 	char command[64];
847 	int parameter;
848 	int cmd_type;
849 	union {
850 		PRIV_CMD_HANDLER cmd_handler;
851 		PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
852 	};
853 } android_restore_scan_params_t;
854 
855 /* function prototypes of private command handler */
856 static int wl_android_set_roam_trigger(struct net_device *dev, char* command);
857 int wl_android_set_roam_delta(struct net_device *dev, char* command);
858 int wl_android_set_roam_scan_period(struct net_device *dev, char* command);
859 int wl_android_set_full_roam_scan_period(struct net_device *dev, char* command, int total_len);
860 int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
861 int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
862 int wl_android_set_scan_home_time(struct net_device *dev, char *command);
863 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
864 int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
865 static int wl_android_set_band(struct net_device *dev, char *command);
866 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
867 int wl_android_set_wes_mode(struct net_device *dev, char *command);
868 int wl_android_set_okc_mode(struct net_device *dev, char *command);
869 
870 /* default values */
871 #ifdef ROAM_API
872 #define DEFAULT_ROAM_TIRGGER	-75
873 #define DEFAULT_ROAM_DELTA	10
874 #define DEFAULT_ROAMSCANPERIOD	10
875 #define DEFAULT_FULLROAMSCANPERIOD_SET	120
876 #endif /* ROAM_API */
877 #ifdef WES_SUPPORT
878 #define DEFAULT_ROAMSCANCONTROL	0
879 #define DEFAULT_SCANCHANNELTIME	40
880 #ifdef BCM4361_CHIP
881 #define DEFAULT_SCANHOMETIME	60
882 #else
883 #define DEFAULT_SCANHOMETIME	45
884 #endif /* BCM4361_CHIP */
885 #define DEFAULT_SCANHOMEAWAYTIME	100
886 #define DEFAULT_SCANPROBES	2
887 #define DEFAULT_DFSSCANMODE	1
888 #define DEFAULT_WESMODE		0
889 #define DEFAULT_OKCMODE		1
890 #endif /* WES_SUPPORT */
891 #define DEFAULT_BAND		0
892 #ifdef WBTEXT
893 #define DEFAULT_WBTEXT_ENABLE	1
894 #endif /* WBTEXT */
895 
896 /* restoring parameter list, please don't change order */
897 static android_restore_scan_params_t restore_params[] =
898 {
899 /* wbtext need to be disabled while updating roam/scan parameters */
900 #ifdef WBTEXT
901 	{ CMD_WBTEXT_ENABLE, 0, RESTORE_TYPE_PRIV_CMD_WITH_LEN,
902 		.cmd_handler_w_len = wl_android_wbtext},
903 #endif /* WBTEXT */
904 #ifdef ROAM_API
905 	{ CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER,
906 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_trigger},
907 	{ CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA,
908 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_delta},
909 	{ CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD,
910 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_period},
911 	{ CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
912 		RESTORE_TYPE_PRIV_CMD_WITH_LEN,
913 		.cmd_handler_w_len = wl_android_set_full_roam_scan_period},
914 #endif /* ROAM_API */
915 #ifdef WES_SUPPORT
916 	{ CMD_SETROAMSCANCONTROL, DEFAULT_ROAMSCANCONTROL,
917 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_control},
918 	{ CMD_SETSCANCHANNELTIME, DEFAULT_SCANCHANNELTIME,
919 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time},
920 	{ CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME,
921 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time},
922 	{ CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME,
923 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time},
924 	{ CMD_SETSCANNPROBES, DEFAULT_SCANPROBES,
925 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes},
926 	{ CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE,
927 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode},
928 	{ CMD_SETWESMODE, DEFAULT_WESMODE,
929 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode},
930 	{ CMD_SETOKCMODE, DEFAULT_OKCMODE,
931 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_okc_mode},
932 #endif /* WES_SUPPORT */
933 	{ CMD_SETBAND, DEFAULT_BAND,
934 		RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band},
935 #ifdef WBTEXT
936 	{ CMD_WBTEXT_ENABLE, DEFAULT_WBTEXT_ENABLE,
937 		RESTORE_TYPE_PRIV_CMD_WITH_LEN, .cmd_handler_w_len = wl_android_wbtext},
938 #endif /* WBTEXT */
939 	{ "\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}
940 };
941 #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
942 
943 /**
944  * Local (static) functions and variables
945  */
946 
947 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
948  * time (only) in dhd_open, subsequential wifi on will be handled by
949  * wl_android_wifi_on
950  */
951 static int g_wifi_on = TRUE;
952 
953 /**
954  * Local (static) function definitions
955  */
956 
957 static int
wl_android_set_channel_width(struct net_device * dev,char * command,int total_len)958 wl_android_set_channel_width(struct net_device *dev, char *command, int total_len)
959 {
960 	u32 channel_width = 0;
961 	struct wireless_dev *wdev = dev->ieee80211_ptr;
962 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
963 	command = (command + strlen(CMD_CHANNEL_WIDTH));
964 	command++;
965 	channel_width = bcm_atoi(command);
966 	if (channel_width == 80)
967 		wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_80);
968 	else if (channel_width == 40)
969 		wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_40);
970 	else if (channel_width == 20)
971 		wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_20);
972 	else
973 		return 0;
974 	DHD_INFO(("%s : channel width = %d\n", __FUNCTION__, channel_width));
975 	return 0;
976 }
977 
978 #ifdef ENABLE_HOGSQS
979 #define M_HOGSQS_DURATION (M_HOGSQS_CFG + 0x2)
980 #define M_HOGSQS_DUR_THR (M_HOGSQS_CFG + 0x4)
981 #define M_HOGSQS_STAT (M_HOGSQS_CFG + 0x6)
982 #define M_HOGSQS_TXCFE_DET_CNT (M_HOGSQS_CFG + 0xe)
983 static int
wl_android_hogsqs(struct net_device * dev,char * command,int total_len)984 wl_android_hogsqs(struct net_device *dev, char *command, int total_len)
985 {
986 	int ret = 0, bytes_written = 0;
987 	s32 value = 0;
988 	uint32 reg = 0;
989 	uint32 set_val = 0;
990 	uint32 set_val2 = 0;
991 	char *pos = command;
992 	char *pos2 = NULL;
993 
994 	if (*(command + strlen(CMD_AP_HOGSQS)) == '\0') {
995 		DHD_ERROR(("%s: Error argument is required on %s \n", __FUNCTION__, CMD_AP_HOGSQS));
996 		return -EINVAL;
997 	} else {
998 		pos = pos + strlen(CMD_AP_HOGSQS) + 1;
999 		if (!strncmp(pos, "cfg", strlen("cfg"))) {
1000 			reg = M_HOGSQS_CFG;
1001 			pos2 = pos + strlen("cfg");
1002 		} else if (!strncmp(pos, "duration", strlen("duration"))) {
1003 			reg = M_HOGSQS_DURATION;
1004 			pos2 = pos + strlen("duration");
1005 		} else if (!strncmp(pos, "durth", strlen("durth"))) {
1006 			reg = M_HOGSQS_DUR_THR;
1007 			pos2 = pos + strlen("durth");
1008 		} else if (!strncmp(pos, "count", strlen("count"))) {
1009 			reg = M_HOGSQS_TXCFE_DET_CNT;
1010 			pos2 = pos + strlen("count");
1011 		} else {
1012 			DHD_ERROR(("%s: Error wrong argument is on %s \n", __FUNCTION__,
1013 			CMD_AP_HOGSQS));
1014 			return -EINVAL;
1015 		}
1016 		value = reg;
1017 
1018 		if (*pos2 == '\0') {
1019 		/* Get operation */
1020 			ret = wldev_iovar_getint(dev, "hogsqs", &value);
1021 			if (ret) {
1022 				DHD_ERROR(("%s: Failed to get hogsqs\n", __FUNCTION__));
1023 				return -EINVAL;
1024 			}
1025 
1026 			if (reg == M_HOGSQS_TXCFE_DET_CNT)
1027 				bytes_written = snprintf(command, total_len, " %s 0x%x/0x%x",
1028 					CMD_AP_HOGSQS, (value&0x00FF), ((value&0xFF00)>> 8));
1029 			else
1030 				bytes_written = snprintf(command, total_len, " %s 0x%x",
1031 						CMD_AP_HOGSQS, value);
1032 
1033 			return bytes_written;
1034 		} else {
1035 		/* Set operation */
1036 			pos2 = pos2 + 1;
1037 			set_val = (uint32)simple_strtol(pos2, NULL, 0);
1038 
1039 			set_val2 = (reg & 0xFFFF) << 16;
1040 			set_val2 |= set_val;
1041 
1042 			ret = wldev_iovar_setint(dev, "hogsqs", set_val2);
1043 			if (ret != BCME_OK) {
1044 				DHD_ERROR(("%s: hogsqs set returned (%d)\n", __FUNCTION__, ret));
1045 				return BCME_ERROR;
1046 			}
1047 		}
1048 	}
1049 	return 0;
1050 }
1051 #endif /* ENABLE_HOGSQS */
1052 
1053 #ifdef DHD_BANDSTEER
1054 static int
wl_android_set_bandsteer(struct net_device * dev,char * command,int total_len)1055 wl_android_set_bandsteer(struct net_device *dev, char *command, int total_len)
1056 {
1057 	char *iftype;
1058 	char *token1, *context1 = NULL;
1059 	int val;
1060 	int ret = 0;
1061 
1062 	struct wireless_dev *__wdev = (struct wireless_dev *)(dev)->ieee80211_ptr;
1063 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(__wdev->wiphy);
1064 
1065 	command = (command + strlen(CMD_BANDSTEER));
1066 	command++;
1067 	token1 = command;
1068 
1069 	iftype = bcmstrtok(&token1, " ", context1);
1070 	val = bcm_atoi(token1);
1071 
1072 	if (val < 0 || val > 1) {
1073 		DHD_ERROR(("%s : invalid val\n", __FUNCTION__));
1074 		return -1;
1075 	}
1076 
1077 	if (!strncmp(iftype, "p2p", 3)) {
1078 		cfg->ap_bs = 0;
1079 		cfg->p2p_bs = 1;
1080 
1081 		if (val) {
1082 			ret = dhd_bandsteer_module_init(dev, cfg->ap_bs, cfg->p2p_bs);
1083 			if (ret == BCME_ERROR) {
1084 				DHD_ERROR(("%s: Failed to enable %s bandsteer\n", __FUNCTION__,
1085 				cfg->ap_bs ? "ap":"p2p"));
1086 				return ret;
1087 			} else {
1088 				DHD_ERROR(("%s: Successfully enabled %s bandsteer\n", __FUNCTION__,
1089 				cfg->ap_bs ? "ap":"p2p"));
1090 			}
1091 		} else {
1092 			ret = dhd_bandsteer_module_deinit(dev, cfg->ap_bs, cfg->p2p_bs);
1093 			if (ret == BCME_ERROR) {
1094 				DHD_ERROR(("%s: Failed to disable %s bandsteer\n", __FUNCTION__,
1095 				cfg->ap_bs ? "ap":"p2p"));
1096 				return ret;
1097 			} else {
1098 				DHD_ERROR(("%s: Successfully disabled %s bandsteer\n", __FUNCTION__,
1099 				cfg->ap_bs ? "ap":"p2p"));
1100 			}
1101 		}
1102 	} else if (!strncmp(iftype, "ap", 2)) {
1103 		cfg->ap_bs = 1;
1104 		cfg->p2p_bs = 0;
1105 
1106 		if (val) {
1107 			ret = dhd_bandsteer_module_init(dev, cfg->ap_bs, cfg->p2p_bs);
1108 			if (ret == BCME_ERROR) {
1109 				DHD_ERROR(("%s: Failed to enable %s bandsteer\n", __FUNCTION__,
1110 				cfg->ap_bs ? "ap":"p2p"));
1111 				return ret;
1112 			} else {
1113 				DHD_ERROR(("%s: Successfully enabled %s bandsteer\n", __FUNCTION__,
1114 				cfg->ap_bs ? "ap":"p2p"));
1115 			}
1116 		} else {
1117 			ret = dhd_bandsteer_module_deinit(dev, cfg->ap_bs, cfg->p2p_bs);
1118 			if (ret == BCME_ERROR) {
1119 				DHD_ERROR(("%s: Failed to disable %s bandsteer\n", __FUNCTION__,
1120 				cfg->ap_bs ? "ap":"p2p"));
1121 				return ret;
1122 			} else {
1123 				DHD_ERROR(("%s: Successfully disabled %s bandsteer\n", __FUNCTION__,
1124 				cfg->ap_bs ? "ap":"p2p"));
1125 			}
1126 		}
1127 	} else if (!strncmp(iftype, "1", 1)) {
1128 		cfg->ap_bs = 1;
1129 		cfg->p2p_bs = 1;
1130 		ret = dhd_bandsteer_module_init(dev, cfg->ap_bs, cfg->p2p_bs);
1131 		if (ret == BCME_ERROR) {
1132 			DHD_ERROR(("%s: Failed to enable bandsteer\n", __FUNCTION__));
1133 			return ret;
1134 		} else {
1135 			DHD_ERROR(("%s: Successfully enabled bandsteer\n", __FUNCTION__));
1136 		}
1137 	} else if (!strncmp(iftype, "0", 1)) {
1138 		cfg->ap_bs = 1;
1139 		cfg->p2p_bs = 1;
1140 		ret = dhd_bandsteer_module_deinit(dev, cfg->ap_bs, cfg->p2p_bs);
1141 		if (ret == BCME_ERROR) {
1142 			DHD_ERROR(("%s: Failed to diable bandsteer\n", __FUNCTION__));
1143 			return ret;
1144 		} else {
1145 			DHD_ERROR(("%s: Successfully disabled  bandsteer\n", __FUNCTION__));
1146 		}
1147 	} else {
1148 		DHD_ERROR(("%s: Invalid bandsteer iftype\n", __FUNCTION__));
1149 		return -1;
1150 	}
1151 	return ret;
1152 }
1153 #endif /* DHD_BANDSTEER */
1154 
1155 #ifdef WLWFDS
wl_android_set_wfds_hash(struct net_device * dev,char * command,bool enable)1156 static int wl_android_set_wfds_hash(
1157 	struct net_device *dev, char *command, bool enable)
1158 {
1159 	int error = 0;
1160 	wl_p2p_wfds_hash_t *wfds_hash = NULL;
1161 	char *smbuf = NULL;
1162 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1163 
1164 	smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
1165 	if (smbuf == NULL) {
1166 		DHD_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n",
1167 			WLC_IOCTL_MAXLEN));
1168 		return -ENOMEM;
1169 	}
1170 
1171 	if (enable) {
1172 		wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
1173 		error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
1174 			sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1175 	}
1176 	else {
1177 		wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
1178 		error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
1179 			sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1180 	}
1181 
1182 	if (error) {
1183 		DHD_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error));
1184 	}
1185 
1186 	if (smbuf) {
1187 		MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
1188 	}
1189 	return error;
1190 }
1191 #endif /* WLWFDS */
1192 
1193 #ifdef AUTOMOTIVE_FEATURE
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)1194 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
1195 {
1196 	int link_speed;
1197 	int bytes_written;
1198 	int error;
1199 
1200 	error = wldev_get_link_speed(net, &link_speed);
1201 	if (error) {
1202 		DHD_ERROR(("Get linkspeed failed \n"));
1203 		return -1;
1204 	}
1205 
1206 	/* Convert Kbps to Android Mbps */
1207 	link_speed = link_speed / 1000;
1208 	bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
1209 	DHD_INFO(("wl_android_get_link_speed: command result is %s\n", command));
1210 	return bytes_written;
1211 }
1212 
wl_android_get_rssi(struct net_device * net,char * command,int total_len)1213 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
1214 {
1215 	wlc_ssid_t ssid = {0, {0}};
1216 	int bytes_written = 0;
1217 	int error = 0;
1218 	scb_val_t scbval;
1219 	char *delim = NULL;
1220 	struct net_device *target_ndev = net;
1221 #ifdef WL_VIRTUAL_APSTA
1222 	char *pos = NULL;
1223 	struct bcm_cfg80211 *cfg;
1224 #endif /* WL_VIRTUAL_APSTA */
1225 
1226 	delim = strchr(command, ' ');
1227 	/* For Ap mode rssi command would be
1228 	 * driver rssi <sta_mac_addr>
1229 	 * for STA/GC mode
1230 	 * driver rssi
1231 	*/
1232 	if (delim) {
1233 		/* Ap/GO mode
1234 		* driver rssi <sta_mac_addr>
1235 		*/
1236 		DHD_TRACE(("wl_android_get_rssi: cmd:%s\n", delim));
1237 		/* skip space from delim after finding char */
1238 		delim++;
1239 		if (!(bcm_ether_atoe((delim), &scbval.ea))) {
1240 			DHD_ERROR(("wl_android_get_rssi: address err\n"));
1241 			return -1;
1242 		}
1243 		scbval.val = htod32(0);
1244 		DHD_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet)));
1245 #ifdef WL_VIRTUAL_APSTA
1246 		/* RSDB AP may have another virtual interface
1247 		 * In this case, format of private command is as following,
1248 		 * DRIVER rssi <sta_mac_addr> <AP interface name>
1249 		 */
1250 
1251 		/* Current position is start of MAC address string */
1252 		pos = delim;
1253 		delim = strchr(pos, ' ');
1254 		if (delim) {
1255 			/* skip space from delim after finding char */
1256 			delim++;
1257 			if (strnlen(delim, IFNAMSIZ)) {
1258 				cfg = wl_get_cfg(net);
1259 				target_ndev = wl_get_ap_netdev(cfg, delim);
1260 				if (target_ndev == NULL)
1261 					target_ndev = net;
1262 			}
1263 		}
1264 #endif /* WL_VIRTUAL_APSTA */
1265 	}
1266 	else {
1267 		/* STA/GC mode */
1268 		bzero(&scbval, sizeof(scb_val_t));
1269 	}
1270 
1271 	error = wldev_get_rssi(target_ndev, &scbval);
1272 	if (error)
1273 		return -1;
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 		DHD_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 	DHD_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written));
1294 	return bytes_written;
1295 }
1296 #endif /* AUTOMOTIVE_FEATURE */
1297 
wl_android_set_suspendopt(struct net_device * dev,char * command)1298 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
1299 {
1300 	int suspend_flag;
1301 	int ret_now;
1302 	int ret = 0;
1303 
1304 	suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
1305 
1306 	if (suspend_flag != 0) {
1307 		suspend_flag = 1;
1308 	}
1309 	ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1310 
1311 	if (ret_now != suspend_flag) {
1312 		if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
1313 			DHD_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n",
1314 				ret_now, suspend_flag));
1315 		} else {
1316 			DHD_ERROR(("wl_android_set_suspendopt: failed %d\n", ret));
1317 		}
1318 	}
1319 
1320 	return ret;
1321 }
1322 
wl_android_set_suspendmode(struct net_device * dev,char * command)1323 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
1324 {
1325 	int ret = 0;
1326 
1327 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
1328 	int suspend_flag;
1329 
1330 	suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
1331 	if (suspend_flag != 0)
1332 		suspend_flag = 1;
1333 
1334 	if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
1335 		DHD_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag));
1336 	else
1337 		DHD_ERROR(("wl_android_set_suspendmode: failed %d\n", ret));
1338 #endif // endif
1339 
1340 	return ret;
1341 }
1342 
1343 #ifdef AUTOMOTIVE_FEATURE
wl_android_get_80211_mode(struct net_device * dev,char * command,int total_len)1344 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
1345 {
1346 	uint8 mode[5];
1347 	int  error = 0;
1348 	int bytes_written = 0;
1349 
1350 	error = wldev_get_mode(dev, mode, sizeof(mode));
1351 	if (error)
1352 		return -1;
1353 
1354 	DHD_INFO(("wl_android_get_80211_mode: mode:%s\n", mode));
1355 	bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
1356 	DHD_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command));
1357 	return bytes_written;
1358 
1359 }
1360 #endif /* AUTOMOTIVE_FEATURE */
1361 
1362 extern chanspec_t
1363 wl_chspec_driver_to_host(chanspec_t chanspec);
wl_android_get_chanspec(struct net_device * dev,char * command,int total_len)1364 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
1365 {
1366 	int error = 0;
1367 	int bytes_written = 0;
1368 	int chsp = {0};
1369 	uint16 band = 0;
1370 	uint16 bw = 0;
1371 	uint16 channel = 0;
1372 	u32 sb = 0;
1373 	chanspec_t chanspec;
1374 
1375 	/* command is
1376 	 * driver chanspec
1377 	 */
1378 	error = wldev_iovar_getint(dev, "chanspec", &chsp);
1379 	if (error)
1380 		return -1;
1381 
1382 	chanspec = wl_chspec_driver_to_host(chsp);
1383 	DHD_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec));
1384 
1385 	channel = chanspec & WL_CHANSPEC_CHAN_MASK;
1386 	band = chanspec & WL_CHANSPEC_BAND_MASK;
1387 	bw = chanspec & WL_CHANSPEC_BW_MASK;
1388 
1389 	DHD_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n",
1390 		channel, band, bw));
1391 
1392 	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 	if (bw == WL_CH_BANDWIDTH_40MHZ) {
1402 		if (CHSPEC_SB_UPPER(chanspec)) {
1403 			channel += CH_10MHZ_APART;
1404 		} else {
1405 			channel -= CH_10MHZ_APART;
1406 		}
1407 	}
1408 	else if (bw == WL_CH_BANDWIDTH_80MHZ) {
1409 		sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
1410 		if (sb == WL_CHANSPEC_CTL_SB_LL) {
1411 			channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
1412 		} else if (sb == WL_CHANSPEC_CTL_SB_LU) {
1413 			channel -= CH_10MHZ_APART;
1414 		} else if (sb == WL_CHANSPEC_CTL_SB_UL) {
1415 			channel += CH_10MHZ_APART;
1416 		} else {
1417 			/* WL_CHANSPEC_CTL_SB_UU */
1418 			channel += (CH_10MHZ_APART + CH_20MHZ_APART);
1419 		}
1420 	}
1421 	bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
1422 		channel, band == WL_CHANSPEC_BAND_5G ? "5G":"2G", bw);
1423 
1424 	DHD_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command));
1425 	return bytes_written;
1426 
1427 }
1428 
1429 /* returns whether rsdb supported or not */
wl_android_get_rsdb_mode(struct net_device * dev,char * command,int total_len)1430 int wl_android_get_rsdb_mode(struct net_device *dev, char *command, int total_len)
1431 {
1432 	int bytes_written = 0;
1433 	dhd_pub_t *dhd = wl_cfg80211_get_dhdp(dev);
1434 	int rsdb_mode = 0;
1435 
1436 	if (FW_SUPPORTED(dhd, rsdb)) {
1437 		rsdb_mode = 1;
1438 	}
1439 	DHD_INFO(("wl_android_get_rsdb_mode: rsdb_mode:%d\n", rsdb_mode));
1440 
1441 	bytes_written = snprintf(command, total_len, "%d", rsdb_mode);
1442 	return bytes_written;
1443 }
1444 
1445 /* returns current datarate datarate returned from firmware are in 500kbps */
1446 #ifdef AUTOMOTIVE_FEATURE
wl_android_get_datarate(struct net_device * dev,char * command,int total_len)1447 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
1448 {
1449 	int  error = 0;
1450 	int datarate = 0;
1451 	int bytes_written = 0;
1452 
1453 	error = wldev_get_datarate(dev, &datarate);
1454 	if (error)
1455 		return -1;
1456 
1457 	DHD_INFO(("wl_android_get_datarate: datarate:%d\n", datarate));
1458 
1459 	bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
1460 	return bytes_written;
1461 }
1462 
wl_android_get_assoclist(struct net_device * dev,char * command,int total_len)1463 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
1464 {
1465 	int  error = 0;
1466 	int bytes_written = 0;
1467 	uint i;
1468 	int len = 0;
1469 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
1470 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
1471 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1472 
1473 	DHD_TRACE(("wl_android_get_assoclist: ENTER\n"));
1474 
1475 	assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
1476 
1477 	error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
1478 	if (error)
1479 		return -1;
1480 
1481 	assoc_maclist->count = dtoh32(assoc_maclist->count);
1482 	bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
1483 		CMD_ASSOC_CLIENTS, assoc_maclist->count);
1484 
1485 	for (i = 0; i < assoc_maclist->count; i++) {
1486 		len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
1487 			MAC2STRDBG(assoc_maclist->ea[i].octet));
1488 		/* A return value of '(total_len - bytes_written)' or more means that the
1489 		 * output was truncated
1490 		 */
1491 		if ((len > 0) && (len < (total_len - bytes_written))) {
1492 			bytes_written += len;
1493 		} else {
1494 			DHD_ERROR(("wl_android_get_assoclist: Insufficient buffer %d,"
1495 				" bytes_written %d\n",
1496 				total_len, bytes_written));
1497 			bytes_written = -1;
1498 			break;
1499 		}
1500 	}
1501 	return bytes_written;
1502 }
1503 #endif /* AUTOMOTIVE_FEATURE */
wl_android_get_channel_list(struct net_device * dev,char * command,int total_len)1504 static int wl_android_get_channel_list(struct net_device *dev, char *command, int total_len)
1505 {
1506 
1507 	int error = 0, len = 0, i;
1508 	char smbuf[WLC_IOCTL_SMLEN] = {0};
1509 	wl_channels_in_country_t *cic;
1510 	char band[2];
1511 	char *pos = command;
1512 
1513 	cic = (wl_channels_in_country_t *)smbuf;
1514 
1515 	pos = pos + strlen(CMD_CHANNELS_IN_CC) + 1;
1516 
1517 	sscanf(pos, "%s %s", cic->country_abbrev, band);
1518 	DHD_INFO(("%s:country  %s  and mode %s \n", __FUNCTION__, cic->country_abbrev, band));
1519 	len = strlen(cic->country_abbrev);
1520 	if ((len > 3) || (len < 2)) {
1521 		DHD_ERROR(("%s :invalid country abbrev\n", __FUNCTION__));
1522 		return -1;
1523 	}
1524 
1525 	if (!strcmp(band, "a") || !strcmp(band, "A"))
1526 		cic->band = WLC_BAND_5G;
1527 	else if (!strcmp(band, "b") || !strcmp(band, "B"))
1528 		cic->band = WLC_BAND_2G;
1529 	else {
1530 		DHD_ERROR(("%s: unsupported band: \n", __FUNCTION__));
1531 		return -1;
1532 	}
1533 
1534 	cic->count = 0;
1535 	cic->buflen = WL_EXTRA_BUF_MAX;
1536 
1537 	error = wldev_ioctl_get(dev, WLC_GET_CHANNELS_IN_COUNTRY, cic, sizeof(smbuf));
1538 	if (error) {
1539 		DHD_ERROR(("%s :Failed to get channels \n", __FUNCTION__));
1540 		return -1;
1541 	}
1542 
1543 	if (cic->count == 0)
1544 		return -1;
1545 
1546 	for (i = 0; i < (cic->count); i++) {
1547 		pos += snprintf(pos, total_len, " %d", (cic->channel[i]));
1548 	}
1549 	return (pos - command);
1550 }
1551 
1552 extern chanspec_t
1553 wl_chspec_host_to_driver(chanspec_t chanspec);
wl_android_set_csa(struct net_device * dev,char * command)1554 static int wl_android_set_csa(struct net_device *dev, char *command)
1555 {
1556 	int error = 0;
1557 	char smbuf[WLC_IOCTL_SMLEN];
1558 	wl_chan_switch_t csa_arg;
1559 	u32 chnsp = 0;
1560 	int err = 0;
1561 	char *str, str_chan[8];
1562 	uint default_bw = WL_CHANSPEC_BW_20;
1563 #if !defined(DISALBE_11H) && defined(DHD_NOSCAN_DURING_CSA)
1564 	struct wireless_dev *wdev = dev->ieee80211_ptr;
1565 	struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
1566 #endif // endif
1567 
1568 	DHD_INFO(("wl_android_set_csa: command:%s\n", command));
1569 
1570 #if !defined(DISALBE_11H) && defined(DHD_NOSCAN_DURING_CSA)
1571 	if (!(wdev->iftype == NL80211_IFTYPE_AP || wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
1572 		DHD_ERROR(("%s:error csa is for only AP/AGO mode(%d)\n", __FUNCTION__,
1573 					wdev->iftype));
1574 		return -1;
1575 	}
1576 #endif // endif
1577 
1578 	/*
1579 	 * SETCSA driver command provides support for AP/AGO to switch its channel
1580 	 * as well as connected STAs channel. This command will send CSA frame and
1581 	 * based on this connected STA will switch to channel which we will pass in
1582 	 * CSA frame.
1583 	 * Usage:
1584 	 * > IFNAME=<group_iface_name> DRIVER SETCSA mode count channel frame_type
1585 	 * > IFNAME=<group_iface_name> DRIVER SETCSA 0 10 1 u
1586 	 * If no frame type is specified, frame_type=0 (Broadcast frame type)
1587 	 */
1588 
1589 	command = (command + strlen(CMD_SET_CSA));
1590 	/* Order is mode, count channel */
1591 	if (!*++command) {
1592 		DHD_ERROR(("wl_android_set_csa:error missing arguments\n"));
1593 		return -1;
1594 	}
1595 	csa_arg.mode = bcm_atoi(command);
1596 
1597 	if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1598 		DHD_ERROR(("Invalid mode\n"));
1599 		return -1;
1600 	}
1601 
1602 	if (!*++command) {
1603 		DHD_ERROR(("wl_android_set_csa: error missing count\n"));
1604 		return -1;
1605 	}
1606 	command++;
1607 	csa_arg.count = bcm_atoi(command);
1608 
1609 	csa_arg.reg = 0;
1610 	csa_arg.chspec = 0;
1611 
1612 	str = strchr(command, ' ');
1613 	if (str == NULL) {
1614 		DHD_ERROR(("wl_android_set_csa: error missing channel\n"));
1615 		return -1;
1616 	}
1617 	command = ++str;
1618 
1619 	str = strchr(command, ' ');
1620 	if (str != NULL){
1621 		strncpy(str_chan, command, (str-command));
1622 	}else {
1623 		strncpy(str_chan, command, strlen(command));
1624 	}
1625 
1626 	/* Get current chanspec to retrieve the current bandwidth */
1627 	error = wldev_iovar_getint(dev, "chanspec", &chnsp);
1628 	if (error == BCME_OK) {
1629 		chnsp = wl_chspec_driver_to_host(chnsp);
1630 		/* Use current bandwidth as default if it is not specified in cmd string */
1631 		default_bw = chnsp & WL_CHANSPEC_BW_MASK;
1632 	}
1633 
1634 	chnsp = wf_chspec_aton_ex(str_chan, default_bw);
1635 
1636 	if (chnsp == 0) {
1637 		DHD_ERROR(("wl_android_set_csa:chsp is not correct\n"));
1638 		return -1;
1639 	}
1640 	chnsp = wl_chspec_host_to_driver(chnsp);
1641 	csa_arg.chspec = chnsp;
1642 
1643 	/* csa action frame type */
1644 	if (str != NULL){
1645 		if (strcmp(++str, "u") == 0) {
1646 			csa_arg.frame_type = CSA_UNICAST_ACTION_FRAME;
1647 		} else {
1648 			DHD_ERROR(("%s:error: invalid frame type: %s\n",
1649 						__FUNCTION__, command));
1650 			return -1;
1651 		}
1652 	} else {
1653 		csa_arg.frame_type = CSA_BROADCAST_ACTION_FRAME;
1654 	}
1655 
1656 	if (chnsp & WL_CHANSPEC_BAND_5G) {
1657 		u32 chanspec = wf_chspec_ctlchan(chnsp);
1658 		err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1659 		if (!err) {
1660 			if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1661 				DHD_ERROR(("Channel is radar sensitive\n"));
1662 				return -1;
1663 			}
1664 			if (chanspec == 0) {
1665 				DHD_ERROR(("Invalid hw channel\n"));
1666 				return -1;
1667 			}
1668 		} else  {
1669 			DHD_ERROR(("does not support per_chan_info\n"));
1670 			return -1;
1671 		}
1672 		DHD_INFO(("non radar sensitivity\n"));
1673 	}
1674 	error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
1675 			smbuf, sizeof(smbuf), NULL);
1676 	if (error) {
1677 		DHD_ERROR(("wl_android_set_csa:set csa failed:%d\n", error));
1678 		return -1;
1679 	}
1680 
1681 #if !defined(DISALBE_11H) && defined(DHD_NOSCAN_DURING_CSA)
1682 	cfg->in_csa = TRUE;
1683 	mod_timer(&cfg->csa_timeout, jiffies + msecs_to_jiffies(100 * (csa_arg.count+2)));
1684 #endif // endif
1685 	return 0;
1686 }
1687 
1688 static int
wl_android_set_bcn_li_dtim(struct net_device * dev,char * command)1689 wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1690 {
1691 	int ret = 0;
1692 	int dtim;
1693 
1694 	dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1695 
1696 	if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1697 		DHD_ERROR(("%s: failed, invalid dtim %d\n",
1698 			__FUNCTION__, dtim));
1699 		return BCME_ERROR;
1700 	}
1701 
1702 	if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1703 		DHD_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
1704 			__FUNCTION__, dtim));
1705 	} else {
1706 		DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1707 	}
1708 
1709 	return ret;
1710 }
1711 
1712 static int
wl_android_set_max_dtim(struct net_device * dev,char * command)1713 wl_android_set_max_dtim(struct net_device *dev, char *command)
1714 {
1715 	int ret = 0;
1716 	int dtim_flag;
1717 
1718 	dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1719 
1720 	if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1721 		DHD_TRACE(("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n",
1722 			(dtim_flag ? "Enable" : "Disable")));
1723 	} else {
1724 		DHD_ERROR(("wl_android_set_max_dtim: failed %d\n", ret));
1725 	}
1726 
1727 	return ret;
1728 }
1729 
1730 #ifdef DISABLE_DTIM_IN_SUSPEND
1731 static int
wl_android_set_disable_dtim_in_suspend(struct net_device * dev,char * command)1732 wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command)
1733 {
1734 	int ret = 0;
1735 	int dtim_flag;
1736 
1737 	dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
1738 
1739 	if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
1740 		DHD_TRACE(("wl_android_set_disable_dtim_in_suspend: "
1741 			"use Disable bcn_li_dtim in suspend %s\n",
1742 			(dtim_flag ? "Enable" : "Disable")));
1743 	} else {
1744 		DHD_ERROR(("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret));
1745 	}
1746 
1747 	return ret;
1748 }
1749 #endif /* DISABLE_DTIM_IN_SUSPEND */
1750 
wl_android_get_band(struct net_device * dev,char * command,int total_len)1751 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
1752 {
1753 	uint band;
1754 	int bytes_written;
1755 	int error;
1756 
1757 	error = wldev_get_band(dev, &band);
1758 	if (error)
1759 		return -1;
1760 	bytes_written = snprintf(command, total_len, "Band %d", band);
1761 	return bytes_written;
1762 }
1763 
1764 static int
wl_android_set_band(struct net_device * dev,char * command)1765 wl_android_set_band(struct net_device *dev, char *command)
1766 {
1767 	int error = 0;
1768 	uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1769 #ifdef WL_HOST_BAND_MGMT
1770 	int ret = 0;
1771 	if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
1772 		if (ret == BCME_UNSUPPORTED) {
1773 			/* If roam_var is unsupported, fallback to the original method */
1774 			WL_ERR(("WL_HOST_BAND_MGMT defined, "
1775 				"but roam_band iovar unsupported in the firmware\n"));
1776 		} else {
1777 			error = -1;
1778 		}
1779 	}
1780 	if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
1781 		/* Apply if roam_band iovar is not supported or band setting is AUTO */
1782 		error = wldev_set_band(dev, band);
1783 	}
1784 #else
1785 	error = wl_cfg80211_set_if_band(dev, band);
1786 #endif /* WL_HOST_BAND_MGMT */
1787 #ifdef ROAM_CHANNEL_CACHE
1788 	wl_update_roamscan_cache_by_band(dev, band);
1789 #endif /* ROAM_CHANNEL_CACHE */
1790 	return error;
1791 }
1792 
wl_android_add_vendor_ie(struct net_device * dev,char * command,int total_len)1793 static int wl_android_add_vendor_ie(struct net_device *dev, char *command, int total_len)
1794 {
1795 	char ie_buf[VNDR_IE_MAX_LEN];
1796 	char *ioctl_buf = NULL;
1797 	char hex[] = "XX";
1798 	char *pcmd = NULL;
1799 	int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
1800 	vndr_ie_setbuf_t *vndr_ie = NULL;
1801 	s32 iecount;
1802 	uint32 pktflag;
1803 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1804 	s32 err = BCME_OK;
1805 
1806 	/*
1807 	 * ADD_IE driver command provides support for addition of vendor elements
1808 	 * to different management frames via wpa_cli
1809 	 * Usage:
1810 	 * Create softap/AGO
1811 	 * wpa_cli> IFNAME=<group_iface_name> DRIVER ADD_IE <flag> <OUI> <DATA>
1812 	 * Here Flag is 802.11 Mgmt packet flags values
1813 	 * Beacon: 0
1814 	 * Probe Rsp: 1
1815 	 * Assoc Rsp: 2
1816 	 * Auth Rsp: 4
1817 	 * Probe Req: 8
1818 	 * Assoc Req: 16
1819 	 * E.g
1820 	 * wpa_cli> IFNAME=bcm0 DRIVER ADD_IE 1 998877 1122334455667788
1821 	 */
1822 	pcmd = command + strlen(CMD_ADDIE) + 1;
1823 	pktflag = simple_strtoul(pcmd, &pcmd, 16);
1824 	pcmd = pcmd + 1;
1825 
1826 	for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
1827 		hex[0] = *pcmd++;
1828 		hex[1] = *pcmd++;
1829 		ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
1830 	}
1831 	pcmd++;
1832 	while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
1833 		hex[0] = *pcmd++;
1834 		hex[1] = *pcmd++;
1835 		ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
1836 		datalen++;
1837 	}
1838 
1839 	tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
1840 
1841 	if (tot_len > VNDR_IE_MAX_LEN) {
1842 		WL_ERR(("Invalid IE total length %d\n", tot_len));
1843 		return -ENOMEM;
1844 	}
1845 
1846 	vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
1847 	if (!vndr_ie) {
1848 		WL_ERR(("IE memory alloc failed\n"));
1849 		return -ENOMEM;
1850 	}
1851 	/* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1852 	strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1);
1853 	vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
1854 
1855 	/* Set the IE count - the buffer contains only 1 IE */
1856 	iecount = htod32(1);
1857 	memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
1858 
1859 	/* Set packet flag to indicate the appropriate frame will contain this IE */
1860 	pktflag = htod32(1<<pktflag);
1861 	memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
1862 		sizeof(u32));
1863 
1864 	/* Set the IE ID */
1865 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
1866 
1867 	/* Set the OUI */
1868 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
1869 		DOT11_OUI_LEN);
1870 	/* Set the Data */
1871 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
1872 		&ie_buf[DOT11_OUI_LEN], datalen);
1873 
1874 	ielen = DOT11_OUI_LEN + datalen;
1875 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
1876 
1877 	ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
1878 	if (!ioctl_buf) {
1879 		WL_ERR(("ioctl memory alloc failed\n"));
1880 		if (vndr_ie) {
1881 			kfree(vndr_ie);
1882 		}
1883 		return -ENOMEM;
1884 	}
1885 	memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
1886 	err = wldev_iovar_setbuf(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
1887 		WLC_IOCTL_MEDLEN, NULL);
1888 
1889 	if (err != BCME_OK) {
1890 		err = -EINVAL;
1891 	}
1892 
1893 	if (vndr_ie) {
1894 		kfree(vndr_ie);
1895 	}
1896 
1897 	if (ioctl_buf) {
1898 		kfree(ioctl_buf);
1899 	}
1900 
1901 	return err;
1902 }
1903 
wl_android_del_vendor_ie(struct net_device * dev,char * command,int total_len)1904 static int wl_android_del_vendor_ie(struct net_device *dev, char *command, int total_len)
1905 {
1906 	char ie_buf[VNDR_IE_MAX_LEN];
1907 	char *ioctl_buf = NULL;
1908 	char hex[] = "XX";
1909 	char *pcmd = NULL;
1910 	int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
1911 	vndr_ie_setbuf_t *vndr_ie = NULL;
1912 	s32 iecount;
1913 	uint32 pktflag;
1914 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1915 	s32 err = BCME_OK;
1916 
1917 	/*
1918 	 * DEL_IE driver command provides support for deletoon of vendor elements
1919 	 * from different management frames via wpa_cli
1920 	 * Usage:
1921 	 * Create softap/AGO
1922 	 * wpa_cli> IFNAME=<group_iface_name> DRIVER DEL_IE <flag> <OUI> <DATA>
1923 	 * Here Flag is 802.11 Mgmt packet flags values
1924 	 * Beacon: 1
1925 	 * Probe Rsp: 2
1926 	 * Assoc Rsp: 4
1927 	 * Auth Rsp: 8
1928 	 * Probe Req: 16
1929 	 * Assoc Req: 32
1930 	 * E.g
1931 	 * wpa_cli> IFNAME=bcm0 DRIVER DEL_IE 1 998877 1122334455667788
1932 	 */
1933 	pcmd = command + strlen(CMD_DELIE) + 1;
1934 
1935 	pktflag = simple_strtoul(pcmd, &pcmd, 16);
1936 	pcmd = pcmd + 1;
1937 
1938 	for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
1939 		hex[0] = *pcmd++;
1940 		hex[1] = *pcmd++;
1941 		ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
1942 	}
1943 	pcmd++;
1944 	while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
1945 		hex[0] = *pcmd++;
1946 		hex[1] = *pcmd++;
1947 		ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
1948 		datalen++;
1949 	}
1950 
1951 	tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
1952 	if (tot_len > VNDR_IE_MAX_LEN) {
1953 		WL_ERR(("Invalid IE total length %d\n", tot_len));
1954 		return -ENOMEM;
1955 	}
1956 	vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
1957 	if (!vndr_ie) {
1958 		WL_ERR(("IE memory alloc failed\n"));
1959 		return -ENOMEM;
1960 	}
1961 	/* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1962 	strncpy(vndr_ie->cmd, "del", VNDR_IE_CMD_LEN - 1);
1963 	vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
1964 
1965 	/* Set the IE count - the buffer contains only 1 IE */
1966 	iecount = htod32(1);
1967 	memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
1968 
1969 	/* Set packet flag to indicate the appropriate frame will contain this IE */
1970 	pktflag = htod32(1<<(pktflag-1));
1971 	memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
1972 		sizeof(u32));
1973 
1974 	/* Set the IE ID */
1975 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
1976 
1977 	/* Set the OUI */
1978 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
1979 		DOT11_OUI_LEN);
1980 
1981 	/* Set the Data */
1982 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
1983 		&ie_buf[DOT11_OUI_LEN], datalen);
1984 
1985 	ielen = DOT11_OUI_LEN + datalen;
1986 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
1987 
1988 	ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
1989 	if (!ioctl_buf) {
1990 		WL_ERR(("ioctl memory alloc failed\n"));
1991 		if (vndr_ie) {
1992 			kfree(vndr_ie);
1993 		}
1994 		return -ENOMEM;
1995 	}
1996 	memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
1997 	err = wldev_iovar_setbuf(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
1998 		WLC_IOCTL_MEDLEN, NULL);
1999 
2000 	if (err != BCME_OK) {
2001 		err = -EINVAL;
2002 	}
2003 
2004 	if (vndr_ie) {
2005 		kfree(vndr_ie);
2006 	}
2007 
2008 	if (ioctl_buf) {
2009 		kfree(ioctl_buf);
2010 	}
2011 	return err;
2012 }
2013 
2014 #if defined(CUSTOMER_HW4_PRIVATE_CMD) || defined(IGUANA_LEGACY_CHIPS)
2015 #ifdef ROAM_API
wl_android_check_wbtext(struct net_device * dev)2016 static bool wl_android_check_wbtext(struct net_device *dev)
2017 {
2018 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
2019 	return dhdp->wbtext_support;
2020 }
2021 
wl_android_set_roam_trigger(struct net_device * dev,char * command)2022 static int wl_android_set_roam_trigger(
2023 	struct net_device *dev, char* command)
2024 {
2025 	int roam_trigger[2] = {0, 0};
2026 	int error;
2027 
2028 #ifdef WBTEXT
2029 	if (wl_android_check_wbtext(dev)) {
2030 		WL_ERR(("blocked to set roam trigger. try with setting roam profile\n"));
2031 		return BCME_ERROR;
2032 	}
2033 #endif /* WBTEXT */
2034 
2035 	sscanf(command, "%*s %10d", &roam_trigger[0]);
2036 	if (roam_trigger[0] >= 0) {
2037 		WL_ERR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
2038 		return BCME_ERROR;
2039 	}
2040 
2041 	roam_trigger[1] = WLC_BAND_ALL;
2042 	error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
2043 		sizeof(roam_trigger));
2044 	if (error != BCME_OK) {
2045 		WL_ERR(("failed to set roam trigger (%d)\n", error));
2046 		return BCME_ERROR;
2047 	}
2048 
2049 	return BCME_OK;
2050 }
2051 
wl_android_get_roam_trigger(struct net_device * dev,char * command,int total_len)2052 static int wl_android_get_roam_trigger(
2053 	struct net_device *dev, char *command, int total_len)
2054 {
2055 	int bytes_written, error;
2056 	int roam_trigger[2] = {0, 0};
2057 	uint16 band = 0;
2058 	int chsp = {0};
2059 	chanspec_t chanspec;
2060 #ifdef WBTEXT
2061 	int i;
2062 	wl_roamprof_band_t rp;
2063 	uint8 roam_prof_ver = 0, roam_prof_size = 0;
2064 #endif /* WBTEXT */
2065 
2066 	error = wldev_iovar_getint(dev, "chanspec", &chsp);
2067 	if (error != BCME_OK) {
2068 		WL_ERR(("failed to get chanspec (%d)\n", error));
2069 		return BCME_ERROR;
2070 	}
2071 
2072 	chanspec = wl_chspec_driver_to_host(chsp);
2073 	band = chanspec & WL_CHANSPEC_BAND_MASK;
2074 	if (band == WL_CHANSPEC_BAND_5G)
2075 		band = WLC_BAND_5G;
2076 	else
2077 		band = WLC_BAND_2G;
2078 
2079 	if (wl_android_check_wbtext(dev)) {
2080 #ifdef WBTEXT
2081 		memset_s(&rp, sizeof(rp), 0, sizeof(rp));
2082 		if ((error = wlc_wbtext_get_roam_prof(dev, &rp, band, &roam_prof_ver,
2083 			&roam_prof_size))) {
2084 			WL_ERR(("Getting roam_profile failed with err=%d \n", error));
2085 			return -EINVAL;
2086 		}
2087 		switch (roam_prof_ver) {
2088 			case WL_ROAM_PROF_VER_1:
2089 			{
2090 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
2091 					if (rp.v2.roam_prof[i].channel_usage == 0) {
2092 						roam_trigger[0] = rp.v2.roam_prof[i].roam_trigger;
2093 						break;
2094 					}
2095 				}
2096 			}
2097 			break;
2098 			case WL_ROAM_PROF_VER_2:
2099 			{
2100 				for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
2101 					if (rp.v3.roam_prof[i].channel_usage == 0) {
2102 						roam_trigger[0] = rp.v3.roam_prof[i].roam_trigger;
2103 						break;
2104 					}
2105 				}
2106 			}
2107 			break;
2108 			default:
2109 				WL_ERR(("bad version = %d \n", roam_prof_ver));
2110 				return BCME_VERSION;
2111 		}
2112 #endif /* WBTEXT */
2113 		if (roam_trigger[0] == 0) {
2114 			WL_ERR(("roam trigger was not set properly\n"));
2115 			return BCME_ERROR;
2116 		}
2117 	} else {
2118 		roam_trigger[1] = band;
2119 		error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
2120 			sizeof(roam_trigger));
2121 		if (error != BCME_OK) {
2122 			WL_ERR(("failed to get roam trigger (%d)\n", error));
2123 			return BCME_ERROR;
2124 		}
2125 	}
2126 
2127 	bytes_written = snprintf(command, total_len, "%s %d",
2128 		CMD_ROAMTRIGGER_GET, roam_trigger[0]);
2129 
2130 	return bytes_written;
2131 }
2132 
wl_android_set_roam_delta(struct net_device * dev,char * command)2133 int wl_android_set_roam_delta(
2134 	struct net_device *dev, char* command)
2135 {
2136 	int roam_delta[2];
2137 
2138 	sscanf(command, "%*s %10d", &roam_delta[0]);
2139 	roam_delta[1] = WLC_BAND_ALL;
2140 
2141 	return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
2142 		sizeof(roam_delta));
2143 }
2144 
wl_android_get_roam_delta(struct net_device * dev,char * command,int total_len)2145 static int wl_android_get_roam_delta(
2146 	struct net_device *dev, char *command, int total_len)
2147 {
2148 	int bytes_written;
2149 	int roam_delta[2] = {0, 0};
2150 
2151 	roam_delta[1] = WLC_BAND_2G;
2152 	if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
2153 		sizeof(roam_delta))) {
2154 		roam_delta[1] = WLC_BAND_5G;
2155 		if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
2156 		                    sizeof(roam_delta)))
2157 			return -1;
2158 	}
2159 
2160 	bytes_written = snprintf(command, total_len, "%s %d",
2161 		CMD_ROAMDELTA_GET, roam_delta[0]);
2162 
2163 	return bytes_written;
2164 }
2165 
wl_android_set_roam_scan_period(struct net_device * dev,char * command)2166 int wl_android_set_roam_scan_period(
2167 	struct net_device *dev, char* command)
2168 {
2169 	int roam_scan_period = 0;
2170 
2171 	sscanf(command, "%*s %10d", &roam_scan_period);
2172 	return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
2173 		sizeof(roam_scan_period));
2174 }
2175 
wl_android_get_roam_scan_period(struct net_device * dev,char * command,int total_len)2176 static int wl_android_get_roam_scan_period(
2177 	struct net_device *dev, char *command, int total_len)
2178 {
2179 	int bytes_written;
2180 	int roam_scan_period = 0;
2181 
2182 	if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
2183 		sizeof(roam_scan_period)))
2184 		return -1;
2185 
2186 	bytes_written = snprintf(command, total_len, "%s %d",
2187 		CMD_ROAMSCANPERIOD_GET, roam_scan_period);
2188 
2189 	return bytes_written;
2190 }
2191 
wl_android_set_full_roam_scan_period(struct net_device * dev,char * command,int total_len)2192 int wl_android_set_full_roam_scan_period(
2193 	struct net_device *dev, char* command, int total_len)
2194 {
2195 	int error = 0;
2196 	int full_roam_scan_period = 0;
2197 	char smbuf[WLC_IOCTL_SMLEN];
2198 
2199 	sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
2200 	WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
2201 
2202 	error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
2203 		sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
2204 	if (error) {
2205 		DHD_ERROR(("Failed to set full roam scan period, error = %d\n", error));
2206 	}
2207 
2208 	return error;
2209 }
2210 
wl_android_get_full_roam_scan_period(struct net_device * dev,char * command,int total_len)2211 static int wl_android_get_full_roam_scan_period(
2212 	struct net_device *dev, char *command, int total_len)
2213 {
2214 	int error;
2215 	int bytes_written;
2216 	int full_roam_scan_period = 0;
2217 
2218 	error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
2219 
2220 	if (error) {
2221 		DHD_ERROR(("%s: get full roam scan period failed code %d\n",
2222 			__func__, error));
2223 		return -1;
2224 	} else {
2225 		DHD_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
2226 	}
2227 
2228 	bytes_written = snprintf(command, total_len, "%s %d",
2229 		CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
2230 
2231 	return bytes_written;
2232 }
2233 
2234 #ifdef AUTOMOTIVE_FEATURE
wl_android_set_country_rev(struct net_device * dev,char * command)2235 int wl_android_set_country_rev(
2236 	struct net_device *dev, char* command)
2237 {
2238 	int error = 0;
2239 	wl_country_t cspec = {{0}, 0, {0} };
2240 	char country_code[WLC_CNTRY_BUF_SZ];
2241 	char smbuf[WLC_IOCTL_SMLEN];
2242 	int rev = 0;
2243 
2244 	/*
2245 	 * SETCOUNTRYREV driver command provides support setting the country.
2246 	 * e.g US, DE, JP etc via supplicant. Once set, band and channels
2247 	 * too automatically gets updated based on the country.
2248 	 * Usage:
2249 	 * > IFNAME=wlan0 DRIVER SETCOUNTRYREV JP
2250 	 * OK
2251 	 */
2252 
2253 	bzero(country_code, sizeof(country_code));
2254 	sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
2255 	WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
2256 
2257 	memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
2258 	memcpy(cspec.ccode, country_code, sizeof(country_code));
2259 	cspec.rev = rev;
2260 
2261 	error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
2262 		sizeof(cspec), smbuf, sizeof(smbuf), NULL);
2263 
2264 	if (error) {
2265 		DHD_ERROR(("wl_android_set_country_rev: set country '%s/%d' failed code %d\n",
2266 			cspec.ccode, cspec.rev, error));
2267 	} else {
2268 		dhd_bus_country_set(dev, &cspec, true);
2269 		DHD_INFO(("wl_android_set_country_rev: set country '%s/%d'\n",
2270 			cspec.ccode, cspec.rev));
2271 	}
2272 
2273 	return error;
2274 }
2275 
wl_android_get_country_rev(struct net_device * dev,char * command,int total_len)2276 static int wl_android_get_country_rev(
2277 	struct net_device *dev, char *command, int total_len)
2278 {
2279 	int error;
2280 	int bytes_written;
2281 	char smbuf[WLC_IOCTL_SMLEN];
2282 	wl_country_t cspec;
2283 
2284 	/*
2285 	 * GETCOUNTRYREV driver command provides support getting the country.
2286 	 * e.g US, DE, JP etc via supplicant.
2287 	 * Usage:
2288 	 * > IFNAME=wlan0 DRIVER GETCOUNTRYREV
2289 	 * GETCOUNTRYREV JP 0
2290 	 */
2291 
2292 	error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
2293 		sizeof(smbuf), NULL);
2294 
2295 	if (error) {
2296 		DHD_ERROR(("wl_android_get_country_rev: get country failed code %d\n",
2297 			error));
2298 		return -1;
2299 	} else {
2300 		memcpy(&cspec, smbuf, sizeof(cspec));
2301 		DHD_INFO(("wl_android_get_country_rev: get country '%c%c %d'\n",
2302 			cspec.ccode[0], cspec.ccode[1], cspec.rev));
2303 	}
2304 
2305 	bytes_written = snprintf(command, total_len, "%s %c%c %d",
2306 		CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
2307 
2308 	return bytes_written;
2309 }
2310 #endif /* AUTOMOTIVE_FEATURE */
2311 #endif /* ROAM_API */
2312 
2313 #ifdef WES_SUPPORT
wl_android_get_roam_scan_control(struct net_device * dev,char * command,int total_len)2314 int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
2315 {
2316 	int error = 0;
2317 	int bytes_written = 0;
2318 	int mode = 0;
2319 
2320 	error = get_roamscan_mode(dev, &mode);
2321 	if (error) {
2322 		DHD_ERROR(("wl_android_get_roam_scan_control: Failed to get Scan Control,"
2323 			" error = %d\n", error));
2324 		return -1;
2325 	}
2326 
2327 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
2328 
2329 	return bytes_written;
2330 }
2331 
wl_android_set_roam_scan_control(struct net_device * dev,char * command)2332 int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
2333 {
2334 	int error = 0;
2335 	int mode = 0;
2336 
2337 	if (sscanf(command, "%*s %d", &mode) != 1) {
2338 		DHD_ERROR(("wl_android_set_roam_scan_control: Failed to get Parameter\n"));
2339 		return -1;
2340 	}
2341 
2342 	error = set_roamscan_mode(dev, mode);
2343 	if (error) {
2344 		DHD_ERROR(("wl_android_set_roam_scan_control: Failed to set Scan Control %d,"
2345 		" error = %d\n",
2346 		 mode, error));
2347 		return -1;
2348 	}
2349 
2350 	return 0;
2351 }
2352 
wl_android_get_roam_scan_channels(struct net_device * dev,char * command,int total_len)2353 int wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len)
2354 {
2355 	int bytes_written = 0;
2356 	unsigned char channels[MAX_ROAM_CHANNEL] = {0};
2357 	int channel_cnt = 0;
2358 	int i = 0;
2359 	int buf_avail, len;
2360 
2361 	channel_cnt = get_roamscan_channel_list(dev, channels, MAX_ROAM_CHANNEL);
2362 	bytes_written = snprintf(command, total_len, "%s %d",
2363 		CMD_GETROAMSCANCHANNELS, channel_cnt);
2364 	buf_avail = total_len - bytes_written;
2365 	for (i = 0; i < channel_cnt; i++) {
2366 		/* A return value of 'buf_avail' or more means that the output was truncated */
2367 		len = snprintf(command + bytes_written, buf_avail, " %d", channels[i]);
2368 		if (len >= buf_avail) {
2369 			WL_ERR(("wl_android_get_roam_scan_channels: Insufficient memory,"
2370 				" %d bytes\n",
2371 				total_len));
2372 			bytes_written = -1;
2373 			break;
2374 		}
2375 		/* 'buf_avail' decremented by number of bytes written */
2376 		buf_avail -= len;
2377 		bytes_written += len;
2378 	}
2379 	WL_INFORM(("wl_android_get_roam_scan_channels: %s\n", command));
2380 	return bytes_written;
2381 }
2382 
wl_android_set_roam_scan_channels(struct net_device * dev,char * command)2383 int wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
2384 {
2385 	int error = 0;
2386 	unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
2387 	int get_ioctl_version = wl_cfg80211_get_ioctl_version();
2388 	error = set_roamscan_channel_list(dev, p[0], &p[1], get_ioctl_version);
2389 	if (error) {
2390 		DHD_ERROR(("wl_android_set_roam_scan_channels: Failed to set Scan Channels %d,"
2391 		" error = %d\n",
2392 		 p[0], error));
2393 		return -1;
2394 	}
2395 
2396 	return 0;
2397 }
2398 
wl_android_get_scan_channel_time(struct net_device * dev,char * command,int total_len)2399 int wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
2400 {
2401 	int error = 0;
2402 	int bytes_written = 0;
2403 	int time = 0;
2404 
2405 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2406 	if (error) {
2407 		DHD_ERROR(("wl_android_get_scan_channel_time: Failed to get Scan Channel Time,"
2408 		" error = %d\n",
2409 		error));
2410 		return -1;
2411 	}
2412 
2413 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
2414 
2415 	return bytes_written;
2416 }
2417 
wl_android_set_scan_channel_time(struct net_device * dev,char * command)2418 int wl_android_set_scan_channel_time(struct net_device *dev, char *command)
2419 {
2420 	int error = 0;
2421 	int time = 0;
2422 
2423 	if (sscanf(command, "%*s %d", &time) != 1) {
2424 		DHD_ERROR(("wl_android_set_scan_channel_time: Failed to get Parameter\n"));
2425 		return -1;
2426 	}
2427 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2428 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
2429 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2430 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2431 	if (error) {
2432 		DHD_ERROR(("wl_android_set_scan_channel_time: Failed to set Scan Channel Time %d,"
2433 		" error = %d\n",
2434 		time, error));
2435 		return -1;
2436 	}
2437 
2438 	return 0;
2439 }
2440 
2441 int
wl_android_get_scan_unassoc_time(struct net_device * dev,char * command,int total_len)2442 wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
2443 {
2444 	int error = 0;
2445 	int bytes_written = 0;
2446 	int time = 0;
2447 
2448 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2449 	if (error) {
2450 		DHD_ERROR(("wl_android_get_scan_unassoc_time: Failed to get Scan Unassoc"
2451 		" Time, error = %d\n",
2452 			error));
2453 		return -1;
2454 	}
2455 
2456 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
2457 
2458 	return bytes_written;
2459 }
2460 
2461 int
wl_android_set_scan_unassoc_time(struct net_device * dev,char * command)2462 wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
2463 {
2464 	int error = 0;
2465 	int time = 0;
2466 
2467 	if (sscanf(command, "%*s %d", &time) != 1) {
2468 		DHD_ERROR(("wl_android_set_scan_unassoc_time: Failed to get Parameter\n"));
2469 		return -1;
2470 	}
2471 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2472 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
2473 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2474 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2475 	if (error) {
2476 		DHD_ERROR(("wl_android_set_scan_unassoc_time: Failed to set Scan Unassoc Time %d,"
2477 			" error = %d\n",
2478 			time, error));
2479 		return -1;
2480 	}
2481 
2482 	return 0;
2483 }
2484 
2485 int
wl_android_get_scan_passive_time(struct net_device * dev,char * command,int total_len)2486 wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
2487 {
2488 	int error = 0;
2489 	int bytes_written = 0;
2490 	int time = 0;
2491 
2492 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2493 	if (error) {
2494 		DHD_ERROR(("wl_android_get_scan_passive_time: Failed to get Scan Passive Time,"
2495 			" error = %d\n",
2496 			error));
2497 		return -1;
2498 	}
2499 
2500 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
2501 
2502 	return bytes_written;
2503 }
2504 
2505 int
wl_android_set_scan_passive_time(struct net_device * dev,char * command)2506 wl_android_set_scan_passive_time(struct net_device *dev, char *command)
2507 {
2508 	int error = 0;
2509 	int time = 0;
2510 
2511 	if (sscanf(command, "%*s %d", &time) != 1) {
2512 		DHD_ERROR(("wl_android_set_scan_passive_time: Failed to get Parameter\n"));
2513 		return -1;
2514 	}
2515 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2516 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
2517 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2518 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2519 	if (error) {
2520 		DHD_ERROR(("wl_android_set_scan_passive_time: Failed to set Scan Passive Time %d,"
2521 			" error = %d\n",
2522 			time, error));
2523 		return -1;
2524 	}
2525 
2526 	return 0;
2527 }
2528 
wl_android_get_scan_home_time(struct net_device * dev,char * command,int total_len)2529 int wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
2530 {
2531 	int error = 0;
2532 	int bytes_written = 0;
2533 	int time = 0;
2534 
2535 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
2536 	if (error) {
2537 		DHD_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
2538 		return -1;
2539 	}
2540 
2541 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
2542 
2543 	return bytes_written;
2544 }
2545 
wl_android_set_scan_home_time(struct net_device * dev,char * command)2546 int wl_android_set_scan_home_time(struct net_device *dev, char *command)
2547 {
2548 	int error = 0;
2549 	int time = 0;
2550 
2551 	if (sscanf(command, "%*s %d", &time) != 1) {
2552 		DHD_ERROR(("wl_android_set_scan_home_time: Failed to get Parameter\n"));
2553 		return -1;
2554 	}
2555 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2556 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
2557 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
2558 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2559 	if (error) {
2560 		DHD_ERROR(("wl_android_set_scan_home_time: Failed to set Scan Home Time %d,"
2561 		" error = %d\n",
2562 		time, error));
2563 		return -1;
2564 	}
2565 
2566 	return 0;
2567 }
2568 
wl_android_get_scan_home_away_time(struct net_device * dev,char * command,int total_len)2569 int wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
2570 {
2571 	int error = 0;
2572 	int bytes_written = 0;
2573 	int time = 0;
2574 
2575 	error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
2576 	if (error) {
2577 		DHD_ERROR(("wl_android_get_scan_home_away_time: Failed to get Scan Home Away Time,"
2578 		" error = %d\n",
2579 		error));
2580 		return -1;
2581 	}
2582 
2583 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
2584 
2585 	return bytes_written;
2586 }
2587 
wl_android_set_scan_home_away_time(struct net_device * dev,char * command)2588 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
2589 {
2590 	int error = 0;
2591 	int time = 0;
2592 
2593 	if (sscanf(command, "%*s %d", &time) != 1) {
2594 		DHD_ERROR(("wl_android_set_scan_home_away_time: Failed to get Parameter\n"));
2595 		return -1;
2596 	}
2597 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2598 	wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
2599 	error = wldev_iovar_setint(dev, "scan_home_away_time", time);
2600 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2601 	if (error) {
2602 		DHD_ERROR(("wl_android_set_scan_home_away_time: Failed to set Scan Home Away"
2603 		" Time %d, error = %d\n",
2604 		 time, error));
2605 		return -1;
2606 	}
2607 
2608 	return 0;
2609 }
2610 
wl_android_get_scan_nprobes(struct net_device * dev,char * command,int total_len)2611 int wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
2612 {
2613 	int error = 0;
2614 	int bytes_written = 0;
2615 	int num = 0;
2616 
2617 	error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
2618 	if (error) {
2619 		DHD_ERROR(("wl_android_get_scan_nprobes: Failed to get Scan NProbes,"
2620 		" error = %d\n", error));
2621 		return -1;
2622 	}
2623 
2624 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
2625 
2626 	return bytes_written;
2627 }
2628 
wl_android_set_scan_nprobes(struct net_device * dev,char * command)2629 int wl_android_set_scan_nprobes(struct net_device *dev, char *command)
2630 {
2631 	int error = 0;
2632 	int num = 0;
2633 
2634 	if (sscanf(command, "%*s %d", &num) != 1) {
2635 		DHD_ERROR(("wl_android_set_scan_nprobes: Failed to get Parameter\n"));
2636 		return -1;
2637 	}
2638 
2639 	error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
2640 	if (error) {
2641 		DHD_ERROR(("wl_android_set_scan_nprobes: Failed to set Scan NProbes %d,"
2642 		" error = %d\n",
2643 		num, error));
2644 		return -1;
2645 	}
2646 
2647 	return 0;
2648 }
2649 
wl_android_get_scan_dfs_channel_mode(struct net_device * dev,char * command,int total_len)2650 int wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
2651 {
2652 	int error = 0;
2653 	int bytes_written = 0;
2654 	int mode = 0;
2655 	int scan_passive_time = 0;
2656 
2657 	error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
2658 	if (error) {
2659 		DHD_ERROR(("wl_android_get_scan_dfs_channel_mode: Failed to get Passive Time,"
2660 		" error = %d\n", error));
2661 		return -1;
2662 	}
2663 
2664 	if (scan_passive_time == 0) {
2665 		mode = 0;
2666 	} else {
2667 		mode = 1;
2668 	}
2669 
2670 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
2671 
2672 	return bytes_written;
2673 }
2674 
wl_android_set_scan_dfs_channel_mode(struct net_device * dev,char * command)2675 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
2676 {
2677 	int error = 0;
2678 	int mode = 0;
2679 	int scan_passive_time = 0;
2680 
2681 	if (sscanf(command, "%*s %d", &mode) != 1) {
2682 		DHD_ERROR(("wl_android_set_scan_dfs_channel_mode: Failed to get Parameter\n"));
2683 		return -1;
2684 	}
2685 
2686 	if (mode == 1) {
2687 		scan_passive_time = DHD_SCAN_PASSIVE_TIME;
2688 	} else if (mode == 0) {
2689 		scan_passive_time = 0;
2690 	} else {
2691 		DHD_ERROR(("wl_android_set_scan_dfs_channel_mode: Failed to set Scan DFS"
2692 		" channel mode %d, error = %d\n",
2693 		 mode, error));
2694 		return -1;
2695 	}
2696 	error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
2697 	if (error) {
2698 		DHD_ERROR(("wl_android_set_scan_dfs_channel_mode: Failed to set Scan"
2699 		" Passive Time %d, error = %d\n",
2700 		scan_passive_time, error));
2701 		return -1;
2702 	}
2703 
2704 	return 0;
2705 }
2706 
2707 #define JOINPREFFER_BUF_SIZE 12
2708 
2709 static int
wl_android_set_join_prefer(struct net_device * dev,char * command)2710 wl_android_set_join_prefer(struct net_device *dev, char *command)
2711 {
2712 	int error = BCME_OK;
2713 	char smbuf[WLC_IOCTL_SMLEN];
2714 	uint8 buf[JOINPREFFER_BUF_SIZE];
2715 	char *pcmd;
2716 	int total_len_left;
2717 	int i;
2718 	char hex[] = "XX";
2719 #ifdef WBTEXT
2720 	char commandp[WLC_IOCTL_SMLEN];
2721 	char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
2722 #endif /* WBTEXT */
2723 
2724 	pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
2725 	total_len_left = strlen(pcmd);
2726 
2727 	bzero(buf, sizeof(buf));
2728 
2729 	if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
2730 		DHD_ERROR(("wl_android_set_join_prefer: Failed to get Parameter\n"));
2731 		return BCME_ERROR;
2732 	}
2733 
2734 	/* Store the MSB first, as required by join_pref */
2735 	for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
2736 		hex[0] = *pcmd++;
2737 		hex[1] = *pcmd++;
2738 		buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
2739 	}
2740 
2741 #ifdef WBTEXT
2742 	/* No coexistance between 11kv and join pref */
2743 	if (wl_android_check_wbtext(dev)) {
2744 		bzero(commandp, sizeof(commandp));
2745 		if (memcmp(buf, clear, sizeof(buf)) == 0) {
2746 			snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
2747 		} else {
2748 			snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
2749 		}
2750 		if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
2751 			DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
2752 			return error;
2753 		}
2754 	}
2755 #endif /* WBTEXT */
2756 
2757 	prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
2758 	error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
2759 		smbuf, sizeof(smbuf), NULL);
2760 	if (error) {
2761 		DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
2762 	}
2763 
2764 	return error;
2765 }
2766 
wl_android_send_action_frame(struct net_device * dev,char * command,int total_len)2767 int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
2768 {
2769 	int error = -1;
2770 	android_wifi_af_params_t *params = NULL;
2771 	wl_action_frame_t *action_frame = NULL;
2772 	wl_af_params_t *af_params = NULL;
2773 	char *smbuf = NULL;
2774 	struct ether_addr tmp_bssid;
2775 	int tmp_channel = 0;
2776 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2777 
2778 	if (total_len <
2779 			(strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
2780 		DHD_ERROR(("wl_android_send_action_frame: Invalid parameters \n"));
2781 		goto send_action_frame_out;
2782 	}
2783 
2784 	params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
2785 
2786 	if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
2787 		DHD_ERROR(("wl_android_send_action_frame: Requested action frame len"
2788 			" was out of range(%d)\n",
2789 			params->len));
2790 		goto send_action_frame_out;
2791 	}
2792 
2793 	smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
2794 	if (smbuf == NULL) {
2795 		DHD_ERROR(("wl_android_send_action_frame: failed to allocated memory %d bytes\n",
2796 		WLC_IOCTL_MAXLEN));
2797 		goto send_action_frame_out;
2798 	}
2799 
2800 	af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
2801 	if (af_params == NULL) {
2802 		DHD_ERROR(("wl_android_send_action_frame: unable to allocate frame\n"));
2803 		goto send_action_frame_out;
2804 	}
2805 
2806 	bzero(&tmp_bssid, ETHER_ADDR_LEN);
2807 	if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
2808 		bzero(&tmp_bssid, ETHER_ADDR_LEN);
2809 
2810 		error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2811 		if (error) {
2812 			bzero(&tmp_bssid, ETHER_ADDR_LEN);
2813 			DHD_ERROR(("wl_android_send_action_frame: failed to get bssid,"
2814 				" error=%d\n", error));
2815 			goto send_action_frame_out;
2816 		}
2817 	}
2818 
2819 	if (params->channel < 0) {
2820 		struct channel_info ci;
2821 		bzero(&ci, sizeof(ci));
2822 		error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
2823 		if (error) {
2824 			DHD_ERROR(("wl_android_send_action_frame: failed to get channel,"
2825 				" error=%d\n", error));
2826 			goto send_action_frame_out;
2827 		}
2828 
2829 		tmp_channel = ci.hw_channel;
2830 	}
2831 	else {
2832 		tmp_channel = params->channel;
2833 	}
2834 
2835 	af_params->channel = tmp_channel;
2836 	af_params->dwell_time = params->dwell_time;
2837 	memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2838 	action_frame = &af_params->action_frame;
2839 
2840 	action_frame->packetId = 0;
2841 	memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
2842 	action_frame->len = (uint16)params->len;
2843 	memcpy(action_frame->data, params->data, action_frame->len);
2844 
2845 	error = wldev_iovar_setbuf(dev, "actframe", af_params,
2846 		sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
2847 	if (error) {
2848 		DHD_ERROR(("wl_android_send_action_frame: failed to set action frame,"
2849 			" error=%d\n", error));
2850 	}
2851 
2852 send_action_frame_out:
2853 	if (af_params) {
2854 		MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
2855 	}
2856 
2857 	if (smbuf) {
2858 		MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
2859 	}
2860 
2861 	if (error)
2862 		return -1;
2863 	else
2864 		return 0;
2865 }
2866 
wl_android_reassoc(struct net_device * dev,char * command,int total_len)2867 int wl_android_reassoc(struct net_device *dev, char *command, int total_len)
2868 {
2869 	int error = 0;
2870 	android_wifi_reassoc_params_t *params = NULL;
2871 	uint band;
2872 	chanspec_t channel;
2873 	u32 params_size;
2874 	wl_reassoc_params_t reassoc_params;
2875 
2876 	if (total_len <
2877 			(strlen(CMD_REASSOC) + 1 + sizeof(android_wifi_reassoc_params_t))) {
2878 		DHD_ERROR(("wl_android_reassoc: Invalid parameters \n"));
2879 		return -1;
2880 	}
2881 	params = (android_wifi_reassoc_params_t *)(command + strlen(CMD_REASSOC) + 1);
2882 
2883 	bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
2884 
2885 	if (bcm_ether_atoe((const char *)params->bssid,
2886 	(struct ether_addr *)&reassoc_params.bssid) == 0) {
2887 		DHD_ERROR(("wl_android_reassoc: Invalid bssid \n"));
2888 		return -1;
2889 	}
2890 
2891 	if (params->channel < 0) {
2892 		DHD_ERROR(("wl_android_reassoc: Invalid Channel \n"));
2893 		return -1;
2894 	}
2895 
2896 	reassoc_params.chanspec_num = 1;
2897 
2898 	channel = params->channel;
2899 #ifdef D11AC_IOTYPES
2900 	if (wl_cfg80211_get_ioctl_version() == 1) {
2901 		band = ((channel <= CH_MAX_2G_CHANNEL) ?
2902 		WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G);
2903 		reassoc_params.chanspec_list[0] = channel |
2904 		band | WL_LCHANSPEC_BW_20 | WL_LCHANSPEC_CTL_SB_NONE;
2905 	}
2906 	else {
2907 		band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
2908 		reassoc_params.chanspec_list[0] = channel | band | WL_CHANSPEC_BW_20;
2909 	}
2910 #else
2911 	band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
2912 	reassoc_params.chanspec_list[0] = channel |
2913 	band | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
2914 #endif /* D11AC_IOTYPES */
2915 	params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
2916 
2917 	error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
2918 	if (error) {
2919 		DHD_ERROR(("wl_android_reassoc: failed to reassoc, error=%d\n", error));
2920 		return -1;
2921 	}
2922 	return 0;
2923 }
2924 
wl_android_get_wes_mode(struct net_device * dev,char * command,int total_len)2925 int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
2926 {
2927 	int bytes_written = 0;
2928 	int mode = 0;
2929 
2930 	mode = wl_cfg80211_get_wes_mode();
2931 
2932 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
2933 
2934 	return bytes_written;
2935 }
2936 
wl_android_set_wes_mode(struct net_device * dev,char * command)2937 int wl_android_set_wes_mode(struct net_device *dev, char *command)
2938 {
2939 	int error = 0;
2940 	int mode = 0;
2941 #ifdef WBTEXT
2942 	char commandp[WLC_IOCTL_SMLEN];
2943 #endif /* WBTEXT */
2944 
2945 	if (sscanf(command, "%*s %d", &mode) != 1) {
2946 		DHD_ERROR(("wl_android_set_wes_mode: Failed to get Parameter\n"));
2947 		return -1;
2948 	}
2949 
2950 	error = wl_cfg80211_set_wes_mode(mode);
2951 	if (error) {
2952 		DHD_ERROR(("wl_android_set_wes_mode: Failed to set WES Mode %d, error = %d\n",
2953 		mode, error));
2954 		return -1;
2955 	}
2956 
2957 #ifdef WBTEXT
2958 	/* No coexistance between 11kv and FMC */
2959 	if (wl_android_check_wbtext(dev)) {
2960 		bzero(commandp, sizeof(commandp));
2961 		if (!mode) {
2962 			snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 1");
2963 		} else {
2964 			snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE 0");
2965 		}
2966 		if ((error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN)) != BCME_OK) {
2967 			DHD_ERROR(("Failed to set WBTEXT = %d\n", error));
2968 			return error;
2969 		}
2970 	}
2971 #endif /* WBTEXT */
2972 
2973 	return 0;
2974 }
2975 
wl_android_get_okc_mode(struct net_device * dev,char * command,int total_len)2976 int wl_android_get_okc_mode(struct net_device *dev, char *command, int total_len)
2977 {
2978 	int error = 0;
2979 	int bytes_written = 0;
2980 	int mode = 0;
2981 
2982 	error = wldev_iovar_getint(dev, "okc_enable", &mode);
2983 	if (error) {
2984 		DHD_ERROR(("wl_android_get_okc_mode: Failed to get OKC Mode, error = %d\n", error));
2985 		return -1;
2986 	}
2987 
2988 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GETOKCMODE, mode);
2989 
2990 	return bytes_written;
2991 }
2992 
wl_android_set_okc_mode(struct net_device * dev,char * command)2993 int wl_android_set_okc_mode(struct net_device *dev, char *command)
2994 {
2995 	int error = 0;
2996 	int mode = 0;
2997 
2998 	if (sscanf(command, "%*s %d", &mode) != 1) {
2999 		DHD_ERROR(("wl_android_set_okc_mode: Failed to get Parameter\n"));
3000 		return -1;
3001 	}
3002 
3003 	error = wldev_iovar_setint(dev, "okc_enable", mode);
3004 	if (error) {
3005 		DHD_ERROR(("wl_android_set_okc_mode: Failed to set OKC Mode %d, error = %d\n",
3006 		mode, error));
3007 		return -1;
3008 	}
3009 
3010 	return error;
3011 }
3012 static int
wl_android_set_pmk(struct net_device * dev,char * command,int total_len)3013 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
3014 {
3015 	uchar pmk[33];
3016 	int error = 0;
3017 	char smbuf[WLC_IOCTL_SMLEN];
3018 	dhd_pub_t *dhdp;
3019 #ifdef OKC_DEBUG
3020 	int i = 0;
3021 #endif // endif
3022 
3023 	if (total_len < (strlen("SET_PMK ") + 32)) {
3024 		DHD_ERROR(("wl_android_set_pmk: Invalid argument\n"));
3025 		return -1;
3026 	}
3027 
3028 	dhdp = wl_cfg80211_get_dhdp(dev);
3029 	if (!dhdp) {
3030 		DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3031 		return -1;
3032 	}
3033 
3034 	bzero(pmk, sizeof(pmk));
3035 	DHD_STATLOG_CTRL(dhdp, ST(INSTALL_OKC_PMK), dhd_net2idx(dhdp->info, dev), 0);
3036 	memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
3037 	error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
3038 	if (error) {
3039 		DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
3040 	}
3041 #ifdef OKC_DEBUG
3042 	DHD_ERROR(("PMK is "));
3043 	for (i = 0; i < 32; i++)
3044 		DHD_ERROR(("%02X ", pmk[i]));
3045 
3046 	DHD_ERROR(("\n"));
3047 #endif // endif
3048 	return error;
3049 }
3050 
3051 static int
wl_android_okc_enable(struct net_device * dev,char * command)3052 wl_android_okc_enable(struct net_device *dev, char *command)
3053 {
3054 	int error = 0;
3055 	char okc_enable = 0;
3056 
3057 	okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
3058 	error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
3059 	if (error) {
3060 		DHD_ERROR(("Failed to %s OKC, error = %d\n",
3061 			okc_enable ? "enable" : "disable", error));
3062 	}
3063 
3064 	return error;
3065 }
3066 #endif /* WES_SUPPORT */
3067 
3068 #ifdef SUPPORT_RESTORE_SCAN_PARAMS
3069 	static int
wl_android_restore_scan_params(struct net_device * dev,char * command,int total_len)3070 wl_android_restore_scan_params(struct net_device *dev, char *command, int total_len)
3071 {
3072 	int error = 0;
3073 	uint error_cnt = 0;
3074 	int cnt = 0;
3075 	char restore_command[WLC_IOCTL_SMLEN];
3076 
3077 	while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) {
3078 		sprintf(restore_command, "%s %d", restore_params[cnt].command,
3079 			restore_params[cnt].parameter);
3080 		if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) {
3081 			error = restore_params[cnt].cmd_handler(dev, restore_command);
3082 		}  else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) {
3083 			error = restore_params[cnt].cmd_handler_w_len(dev,
3084 				restore_command, total_len);
3085 		} else {
3086 			DHD_ERROR(("Unknown restore command handler\n"));
3087 			error = -1;
3088 		}
3089 		if (error) {
3090 			DHD_ERROR(("Failed to restore scan parameters %s, error : %d\n",
3091 				restore_command, error));
3092 			error_cnt++;
3093 		}
3094 		cnt++;
3095 	}
3096 	if (error_cnt > 0) {
3097 		DHD_ERROR(("Got %d error(s) while restoring scan parameters\n",
3098 			error_cnt));
3099 		error = -1;
3100 	}
3101 	return error;
3102 }
3103 #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
3104 
3105 #ifdef WLTDLS
wl_android_tdls_reset(struct net_device * dev)3106 int wl_android_tdls_reset(struct net_device *dev)
3107 {
3108 	int ret = 0;
3109 	ret = dhd_tdls_enable(dev, false, false, NULL);
3110 	if (ret < 0) {
3111 		DHD_ERROR(("Disable tdls failed. %d\n", ret));
3112 		return ret;
3113 	}
3114 	ret = dhd_tdls_enable(dev, true, true, NULL);
3115 	if (ret < 0) {
3116 		DHD_ERROR(("enable tdls failed. %d\n", ret));
3117 		return ret;
3118 	}
3119 	return 0;
3120 }
3121 #endif /* WLTDLS */
3122 
3123 #ifdef CONFIG_SILENT_ROAM
3124 int
wl_android_sroam_turn_on(struct net_device * dev,const char * turn)3125 wl_android_sroam_turn_on(struct net_device *dev, const char* turn)
3126 {
3127 	int ret = BCME_OK, sroam_mode;
3128 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3129 
3130 	sroam_mode = bcm_atoi(turn);
3131 	dhdp->sroam_turn_on = sroam_mode;
3132 	DHD_INFO(("%s Silent mode %s\n", __FUNCTION__,
3133 		sroam_mode ? "enable" : "disable"));
3134 
3135 	if (!sroam_mode) {
3136 		ret = dhd_sroam_set_mon(dhdp, FALSE);
3137 		if (ret) {
3138 			DHD_ERROR(("%s Failed to Set sroam %d\n",
3139 				__FUNCTION__, ret));
3140 		}
3141 	}
3142 
3143 	return ret;
3144 }
3145 
3146 int
wl_android_sroam_set_info(struct net_device * dev,char * data,char * command,int total_len)3147 wl_android_sroam_set_info(struct net_device *dev, char *data,
3148 	char *command, int total_len)
3149 {
3150 	int ret = BCME_OK;
3151 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3152 	size_t slen = strlen(data);
3153 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
3154 	wlc_sroam_t *psroam;
3155 	wlc_sroam_info_t *sroam;
3156 	uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3157 
3158 	data[slen] = '\0';
3159 	psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3160 	if (!psroam) {
3161 		WL_ERR(("%s Fail to malloc buffer\n", __FUNCTION__));
3162 		ret = BCME_NOMEM;
3163 		goto done;
3164 	}
3165 
3166 	psroam->ver = WLC_SILENT_ROAM_CUR_VER;
3167 	psroam->len = sizeof(*sroam);
3168 	sroam = (wlc_sroam_info_t *)psroam->data;
3169 
3170 	sroam->sroam_on = FALSE;
3171 	if (*data && *data != '\0') {
3172 		sroam->sroam_min_rssi = simple_strtol(data, &data, 10);
3173 		WL_DBG(("1.Minimum RSSI %d\n", sroam->sroam_min_rssi));
3174 		data++;
3175 	}
3176 	if (*data && *data != '\0') {
3177 		sroam->sroam_rssi_range = simple_strtol(data, &data, 10);
3178 		WL_DBG(("2.RSSI Range %d\n", sroam->sroam_rssi_range));
3179 		data++;
3180 	}
3181 	if (*data && *data != '\0') {
3182 		sroam->sroam_score_delta = simple_strtol(data, &data, 10);
3183 		WL_DBG(("3.Score Delta %d\n", sroam->sroam_score_delta));
3184 		data++;
3185 	}
3186 	if (*data && *data != '\0') {
3187 		sroam->sroam_period_time = simple_strtol(data, &data, 10);
3188 		WL_DBG(("4.Sroam period %d\n", sroam->sroam_period_time));
3189 		data++;
3190 	}
3191 	if (*data && *data != '\0') {
3192 		sroam->sroam_band = simple_strtol(data, &data, 10);
3193 		WL_DBG(("5.Sroam Band %d\n", sroam->sroam_band));
3194 		data++;
3195 	}
3196 	if (*data && *data != '\0') {
3197 		sroam->sroam_inact_cnt = simple_strtol(data, &data, 10);
3198 		WL_DBG(("6.Inactivity Count %d\n", sroam->sroam_inact_cnt));
3199 		data++;
3200 	}
3201 
3202 	if (*data != '\0') {
3203 		ret = BCME_BADARG;
3204 		goto done;
3205 	}
3206 
3207 	ret = wldev_iovar_setbuf(dev, "sroam", psroam, sroamlen, ioctl_buf,
3208 		sizeof(ioctl_buf), NULL);
3209 	if (ret) {
3210 		WL_ERR(("Failed to set silent roam info(%d)\n", ret));
3211 		goto done;
3212 	}
3213 done:
3214 	if (psroam) {
3215 		MFREE(dhdp->osh, psroam, sroamlen);
3216 	}
3217 
3218 	return ret;
3219 }
3220 
3221 int
wl_android_sroam_get_info(struct net_device * dev,char * command,int total_len)3222 wl_android_sroam_get_info(struct net_device *dev, char *command, int total_len)
3223 {
3224 	int ret = BCME_OK;
3225 	int bytes_written = 0;
3226 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3227 	wlc_sroam_t *psroam;
3228 	wlc_sroam_info_t *sroam;
3229 	uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3230 
3231 	psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3232 	if (!psroam) {
3233 		WL_ERR(("%s Fail to malloc buffer\n", __FUNCTION__));
3234 		ret = BCME_NOMEM;
3235 		goto done;
3236 	}
3237 
3238 	ret = wldev_iovar_getbuf(dev, "sroam", NULL, 0, psroam, sroamlen, NULL);
3239 	if (ret) {
3240 		WL_ERR(("Failed to get silent roam info(%d)\n", ret));
3241 		goto done;
3242 	}
3243 
3244 	if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) {
3245 		ret = BCME_VERSION;
3246 		WL_ERR(("Ver(%d:%d). mismatch silent roam info(%d)\n",
3247 			psroam->ver, WLC_SILENT_ROAM_CUR_VER, ret));
3248 		goto done;
3249 	}
3250 
3251 	sroam = (wlc_sroam_info_t *)psroam->data;
3252 	bytes_written = snprintf(command, total_len,
3253 		"%s %d %d %d %d %d %d %d\n",
3254 		CMD_SROAM_GET_INFO, sroam->sroam_on, sroam->sroam_min_rssi, sroam->sroam_rssi_range,
3255 		sroam->sroam_score_delta, sroam->sroam_period_time, sroam->sroam_band,
3256 		sroam->sroam_inact_cnt);
3257 	ret = bytes_written;
3258 
3259 	WL_DBG(("%s", command));
3260 done:
3261 	if (psroam) {
3262 		MFREE(dhdp->osh, psroam, sroamlen);
3263 	}
3264 
3265 	return ret;
3266 }
3267 #endif /* CONFIG_SILENT_ROAM */
3268 
3269 static int
get_int_bytes(uchar * oui_str,uchar * oui,int len)3270 get_int_bytes(uchar *oui_str, uchar *oui, int len)
3271 {
3272 	int idx;
3273 	uchar val;
3274 	uchar *src, *dest;
3275 	char hexstr[3];
3276 
3277 	if ((oui_str == NULL) || (oui == NULL) || (len == 0)) {
3278 		return BCME_BADARG;
3279 	}
3280 	src = oui_str;
3281 	dest = oui;
3282 
3283 	for (idx = 0; idx < len; idx++) {
3284 		if (*src == '\0') {
3285 			*dest = '\0';
3286 			break;
3287 		}
3288 		hexstr[0] = src[0];
3289 		hexstr[1] = src[1];
3290 		hexstr[2] = '\0';
3291 
3292 		val = (uchar)bcm_strtoul(hexstr, NULL, 16);
3293 		if (val == (uchar)-1) {
3294 			return BCME_ERROR;
3295 		}
3296 		*dest++ = val;
3297 		src += 2;
3298 	}
3299 	return BCME_OK;
3300 }
3301 
3302 #define TAG_BYTE 0
3303 static int
wl_android_set_disconnect_ies(struct net_device * dev,char * command)3304 wl_android_set_disconnect_ies(struct net_device *dev, char *command)
3305 {
3306 	int cmd_prefix_len = 0;
3307 	char ie_len = 0;
3308 	int hex_ie_len = 0;
3309 	int total_len = 0;
3310 	int max_len = 0;
3311 	int cmd_len = 0;
3312 	uchar disassoc_ie[VNDR_IE_MAX_LEN] = {0};
3313 	s32 bssidx = 0;
3314 	struct bcm_cfg80211 *cfg = NULL;
3315 	s32 ret = 0;
3316 	cfg = wl_get_cfg(dev);
3317 
3318 	cmd_prefix_len = strlen("SET_DISCONNECT_IES ");
3319 	cmd_len = strlen(command);
3320 	/*
3321 	 * <CMD> + <IES in HEX format>
3322 	 * IES in hex format has to be in following format
3323 	 * First byte = Tag, Second Byte = len and rest of
3324 	 * bytes will be value. For ex: SET_DISCONNECT_IES dd0411223344
3325 	 * tag = dd, len =04. Total IEs len = len + 2
3326 	 */
3327 	WL_DBG(("cmd recv = %s\n", command));
3328 	max_len = MIN(cmd_len, VNDR_IE_MAX_LEN);
3329 	/* Validate IEs len */
3330 	get_int_bytes(&command[cmd_prefix_len + 2], &ie_len, 1);
3331 	WL_INFORM_MEM(("ie_len = %d \n", ie_len));
3332 	if (ie_len <= 0 || ie_len > max_len) {
3333 		ret = BCME_BADLEN;
3334 		return ret;
3335 	}
3336 
3337 	/* Total len in hex is sum of double binary len, tag and len byte */
3338 	hex_ie_len = (ie_len * 2) + 4;
3339 	total_len = cmd_prefix_len + hex_ie_len;
3340 	if (command[total_len] != '\0' || (cmd_len != total_len)) {
3341 		WL_ERR(("command recv not matching with len, command = %s"
3342 			"total_len = %d, cmd_len = %d\n", command, total_len, cmd_len));
3343 		ret = BCME_BADARG;
3344 		return ret;
3345 	}
3346 
3347 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3348 		WL_ERR(("Find index failed\n"));
3349 		ret = -EINVAL;
3350 		return ret;
3351 	}
3352 
3353 	/* Tag and len bytes are also part of total len of ies in binary */
3354 	ie_len = ie_len + 2;
3355 	/* Convert IEs in binary */
3356 	get_int_bytes(&command[cmd_prefix_len], disassoc_ie, ie_len);
3357 	if (disassoc_ie[TAG_BYTE] != 0xdd) {
3358 		WL_ERR(("Wrong tag recv, tag = 0x%02x\n", disassoc_ie[TAG_BYTE]));
3359 		ret = BCME_UNSUPPORTED;
3360 		return ret;
3361 	}
3362 
3363 	ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
3364 		ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, disassoc_ie, ie_len);
3365 
3366 	return ret;
3367 }
3368 
3369 #ifdef FCC_PWR_LIMIT_2G
3370 int
wl_android_set_fcc_pwr_limit_2g(struct net_device * dev,char * command)3371 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
3372 {
3373 	int error = 0;
3374 	int enable = 0;
3375 
3376 	sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
3377 
3378 	if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
3379 		DHD_ERROR(("wl_android_set_fcc_pwr_limit_2g: Invalid data\n"));
3380 		return BCME_ERROR;
3381 	}
3382 
3383 	CUSTOMER_HW4_EN_CONVERT(enable);
3384 
3385 	DHD_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g set (%d)\n", enable));
3386 	error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
3387 	if (error) {
3388 		DHD_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g"
3389 			" set returned (%d)\n", error));
3390 		return BCME_ERROR;
3391 	}
3392 
3393 	return error;
3394 }
3395 
3396 int
wl_android_get_fcc_pwr_limit_2g(struct net_device * dev,char * command,int total_len)3397 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
3398 {
3399 	int error = 0;
3400 	int enable = 0;
3401 	int bytes_written = 0;
3402 
3403 	error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
3404 	if (error) {
3405 		DHD_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get"
3406 			" error (%d)\n", error));
3407 		return BCME_ERROR;
3408 	}
3409 	DHD_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get (%d)\n", enable));
3410 
3411 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
3412 
3413 	return bytes_written;
3414 }
3415 #endif /* FCC_PWR_LIMIT_2G */
3416 
3417 s32
wl_cfg80211_get_sta_info(struct net_device * dev,char * command,int total_len)3418 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
3419 {
3420 	int bytes_written = -1, ret = 0;
3421 	char *pcmd = command;
3422 	char *str;
3423 	sta_info_v4_t *sta = NULL;
3424 	const wl_cnt_wlc_t* wlc_cnt = NULL;
3425 	struct ether_addr mac;
3426 	char *iovar_buf;
3427 	/* Client information */
3428 	uint16 cap = 0;
3429 	uint32 rxrtry = 0;
3430 	uint32 rxmulti = 0;
3431 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3432 
3433 #ifdef BIGDATA_SOFTAP
3434 	void *data = NULL;
3435 	int get_bigdata_softap = FALSE;
3436 	wl_ap_sta_data_t *sta_data = NULL;
3437 	struct bcm_cfg80211 *bcm_cfg = wl_get_cfg(dev);
3438 #endif /* BIGDATA_SOFTAP */
3439 
3440 	WL_DBG(("%s\n", command));
3441 
3442 	iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
3443 	if (iovar_buf == NULL) {
3444 		DHD_ERROR(("wl_cfg80211_get_sta_info: failed to allocated memory %d bytes\n",
3445 		WLC_IOCTL_MAXLEN));
3446 		goto error;
3447 	}
3448 
3449 	str = bcmstrtok(&pcmd, " ", NULL);
3450 	if (str) {
3451 		str = bcmstrtok(&pcmd, " ", NULL);
3452 		/* If GETSTAINFO subcmd name is not provided, return error */
3453 		if (str == NULL) {
3454 			WL_ERR(("GETSTAINFO subcmd not provided wl_cfg80211_get_sta_info\n"));
3455 			goto error;
3456 		}
3457 
3458 		bzero(&mac, ETHER_ADDR_LEN);
3459 		if ((bcm_ether_atoe((str), &mac))) {
3460 			/* get the sta info */
3461 			ret = wldev_iovar_getbuf(dev, "sta_info",
3462 				(struct ether_addr *)mac.octet,
3463 				ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
3464 #ifdef BIGDATA_SOFTAP
3465 			get_bigdata_softap = TRUE;
3466 #endif /* BIGDATA_SOFTAP */
3467 			if (ret < 0) {
3468 				WL_ERR(("Get sta_info ERR %d\n", ret));
3469 #ifndef BIGDATA_SOFTAP
3470 				goto error;
3471 #else
3472 				goto get_bigdata;
3473 #endif /* BIGDATA_SOFTAP */
3474 			}
3475 
3476 			sta = (sta_info_v4_t *)iovar_buf;
3477 			if (dtoh16(sta->ver) != WL_STA_VER_4) {
3478 				WL_ERR(("sta_info struct version mismatch, "
3479 					"host ver : %d, fw ver : %d\n", WL_STA_VER_4,
3480 					dtoh16(sta->ver)));
3481 				goto error;
3482 			}
3483 			cap = dtoh16(sta->cap);
3484 			rxrtry = dtoh32(sta->rx_pkts_retried);
3485 			rxmulti = dtoh32(sta->rx_mcast_pkts);
3486 		} else if ((!strncmp(str, "all", 3)) || (!strncmp(str, "ALL", 3))) {
3487 			/* get counters info */
3488 			ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
3489 				iovar_buf, WLC_IOCTL_MAXLEN, NULL);
3490 			if (unlikely(ret)) {
3491 				WL_ERR(("counters error (%d) - size = %zu\n",
3492 					ret, sizeof(wl_cnt_wlc_t)));
3493 				goto error;
3494 			}
3495 			ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
3496 			if (ret != BCME_OK) {
3497 				WL_ERR(("wl_cntbuf_to_xtlv_format ERR %d\n", ret));
3498 				goto error;
3499 			}
3500 			if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
3501 				WL_ERR(("wlc_cnt NULL!\n"));
3502 				goto error;
3503 			}
3504 
3505 			rxrtry = dtoh32(wlc_cnt->rxrtry);
3506 			rxmulti = dtoh32(wlc_cnt->rxmulti);
3507 		} else {
3508 			WL_ERR(("Get address fail\n"));
3509 			goto error;
3510 		}
3511 	} else {
3512 		WL_ERR(("Command ERR\n"));
3513 		goto error;
3514 	}
3515 
3516 #ifdef BIGDATA_SOFTAP
3517 get_bigdata:
3518 	if (get_bigdata_softap) {
3519 		WL_ERR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
3520 		if (wl_get_ap_stadata(bcm_cfg, &mac, &data) == BCME_OK) {
3521 			sta_data = (wl_ap_sta_data_t *)data;
3522 			bytes_written = snprintf(command, total_len,
3523 					"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
3524 					"CAP=%04x "MACOUI" %d %s %d %d %d %d %d %d\n",
3525 					CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap,
3526 					MACOUI2STR((char*)&sta_data->mac),
3527 					sta_data->channel,
3528 					wf_chspec_to_bw_str(sta_data->chanspec),
3529 					sta_data->rssi, sta_data->rate,
3530 					sta_data->mode_80211, sta_data->nss, sta_data->mimo,
3531 					sta_data->reason_code);
3532 			WL_ERR_KERN(("command %s\n", command));
3533 			goto error;
3534 		}
3535 	}
3536 #endif /* BIGDATA_SOFTAP */
3537 	bytes_written = snprintf(command, total_len,
3538 		"%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x\n",
3539 		CMD_GET_STA_INFO, str, rxrtry, rxmulti, cap);
3540 
3541 	WL_DBG(("%s", command));
3542 
3543 error:
3544 	if (iovar_buf) {
3545 		MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
3546 
3547 	}
3548 	return bytes_written;
3549 }
3550 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
3551 
3552 #ifdef WBTEXT
wl_android_wbtext(struct net_device * dev,char * command,int total_len)3553 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
3554 {
3555 	int error = BCME_OK, argc = 0;
3556 	int data, bytes_written;
3557 	int roam_trigger[2];
3558 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3559 
3560 	argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
3561 	if (!argc) {
3562 		error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
3563 		if (error) {
3564 			DHD_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
3565 				error));
3566 			return error;
3567 		}
3568 		bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
3569 				(data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
3570 				"ENABLED" : "DISABLED");
3571 		return bytes_written;
3572 	} else {
3573 		if (data) {
3574 			data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
3575 		}
3576 
3577 		if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
3578 			DHD_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
3579 				error));
3580 			return error;
3581 		}
3582 
3583 		if (data) {
3584 			/* reset roam_prof when wbtext is on */
3585 			if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
3586 				return error;
3587 			}
3588 			dhdp->wbtext_support = TRUE;
3589 		} else {
3590 			/* reset legacy roam trigger when wbtext is off */
3591 			roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
3592 			roam_trigger[1] = WLC_BAND_ALL;
3593 			if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
3594 					sizeof(roam_trigger))) != BCME_OK) {
3595 				DHD_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n",
3596 					error));
3597 				return error;
3598 			}
3599 			dhdp->wbtext_support = FALSE;
3600 		}
3601 	}
3602 	return error;
3603 }
3604 
wl_cfg80211_wbtext_btm_timer_threshold(struct net_device * dev,char * command,int total_len)3605 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
3606 	char *command, int total_len)
3607 {
3608 	int error = BCME_OK, argc = 0;
3609 	int data, bytes_written;
3610 
3611 	argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
3612 	if (!argc) {
3613 		error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
3614 		if (error) {
3615 			WL_ERR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
3616 			return error;
3617 		}
3618 		bytes_written = snprintf(command, total_len, "%d\n", data);
3619 		return bytes_written;
3620 	} else {
3621 		if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
3622 				data)) != BCME_OK) {
3623 			WL_ERR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
3624 			return error;
3625 		}
3626 	}
3627 	return error;
3628 }
3629 
wl_cfg80211_wbtext_btm_delta(struct net_device * dev,char * command,int total_len)3630 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
3631 	char *command, int total_len)
3632 {
3633 	int error = BCME_OK, argc = 0;
3634 	int data = 0, bytes_written;
3635 
3636 	argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
3637 	if (!argc) {
3638 		error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
3639 		if (error) {
3640 			WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error));
3641 			return error;
3642 		}
3643 		bytes_written = snprintf(command, total_len, "%d\n", data);
3644 		return bytes_written;
3645 	} else {
3646 		if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
3647 				data)) != BCME_OK) {
3648 			WL_ERR(("Failed to set wnm_btmdelta (%d)\n", error));
3649 			return error;
3650 		}
3651 	}
3652 	return error;
3653 }
3654 
wl_cfg80211_wbtext_estm_enable(struct net_device * dev,char * command,int total_len)3655 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
3656 	char *command, int total_len)
3657 {
3658 	int error = BCME_OK;
3659 	int data = 0, bytes_written = 0;
3660 	int wnmmask = 0;
3661 	char *pcmd = command;
3662 
3663 	bcmstrtok(&pcmd, " ", NULL);
3664 
3665 	error = wldev_iovar_getint(dev, "wnm", &wnmmask);
3666 	if (error) {
3667 		WL_ERR(("Failed to get wnm_btmdelta (%d)\n", error));
3668 		return error;
3669 	}
3670 	WL_DBG(("wnmmask %x\n", wnmmask));
3671 	if (*pcmd == WL_IOCTL_ACTION_GET) {
3672 		bytes_written = snprintf(command, total_len, "wbtext_estm_enable %d\n",
3673 			(wnmmask & WL_WNM_ESTM) ? 1:0);
3674 		return bytes_written;
3675 	} else {
3676 		data = bcm_atoi(pcmd);
3677 		if (data == 0) {
3678 			wnmmask &= ~WL_WNM_ESTM;
3679 		} else {
3680 			wnmmask |= WL_WNM_ESTM;
3681 		}
3682 		WL_DBG(("wnmmask %x\n", wnmmask));
3683 		if ((error = wldev_iovar_setint(dev, "wnm", wnmmask)) != BCME_OK) {
3684 			WL_ERR(("Failed to set wnm mask (%d)\n", error));
3685 			return error;
3686 		}
3687 	}
3688 	return error;
3689 }
3690 #endif /* WBTEXT */
3691 
3692 #ifdef PNO_SUPPORT
3693 #define PNO_PARAM_SIZE 50
3694 #define VALUE_SIZE 50
3695 #define LIMIT_STR_FMT  ("%50s %50s")
3696 static int
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)3697 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
3698 {
3699 	int err = BCME_OK;
3700 	uint i, tokens, len_remain;
3701 	char *pos, *pos2, *token, *token2, *delim;
3702 	char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
3703 	struct dhd_pno_batch_params batch_params;
3704 
3705 	DHD_PNO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len));
3706 	len_remain = total_len;
3707 	if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
3708 		pos = command + strlen(CMD_WLS_BATCHING) + 1;
3709 		len_remain -= strlen(CMD_WLS_BATCHING) + 1;
3710 	} else {
3711 		WL_ERR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len));
3712 		err = BCME_ERROR;
3713 		goto exit;
3714 	}
3715 	bzero(&batch_params, sizeof(struct dhd_pno_batch_params));
3716 	if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
3717 		if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
3718 			pos += strlen(PNO_BATCHING_SET) + 1;
3719 		} else {
3720 			WL_ERR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n",
3721 				PNO_BATCHING_SET, total_len));
3722 			err = BCME_ERROR;
3723 			goto exit;
3724 		}
3725 		while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
3726 			bzero(param, sizeof(param));
3727 			bzero(value, sizeof(value));
3728 			if (token == NULL || !*token)
3729 				break;
3730 			if (*token == '\0')
3731 				continue;
3732 			delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
3733 			if (delim != NULL)
3734 				*delim = ' ';
3735 
3736 			tokens = sscanf(token, LIMIT_STR_FMT, param, value);
3737 			if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
3738 				batch_params.scan_fr = simple_strtol(value, NULL, 0);
3739 				DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr));
3740 			} else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
3741 				batch_params.bestn = simple_strtol(value, NULL, 0);
3742 				DHD_PNO(("bestn : %d\n", batch_params.bestn));
3743 			} else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
3744 				batch_params.mscan = simple_strtol(value, NULL, 0);
3745 				DHD_PNO(("mscan : %d\n", batch_params.mscan));
3746 			} else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
3747 				i = 0;
3748 				pos2 = value;
3749 				tokens = sscanf(value, "<%s>", value);
3750 				if (tokens != 1) {
3751 					err = BCME_ERROR;
3752 					DHD_ERROR(("wls_parse_batching_cmd: invalid format"
3753 					" for channel"
3754 					" <> params\n"));
3755 					goto exit;
3756 				}
3757 				while ((token2 = strsep(&pos2,
3758 						PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
3759 					if (token2 == NULL || !*token2)
3760 						break;
3761 					if (*token2 == '\0')
3762 						continue;
3763 					if (*token2 == 'A' || *token2 == 'B') {
3764 						batch_params.band = (*token2 == 'A')?
3765 							WLC_BAND_5G : WLC_BAND_2G;
3766 						DHD_PNO(("band : %s\n",
3767 							(*token2 == 'A')? "A" : "B"));
3768 					} else {
3769 						if ((batch_params.nchan >= WL_NUMCHANNELS) ||
3770 							(i >= WL_NUMCHANNELS)) {
3771 							DHD_ERROR(("Too many nchan %d\n",
3772 								batch_params.nchan));
3773 							err = BCME_BUFTOOSHORT;
3774 							goto exit;
3775 						}
3776 						batch_params.chan_list[i++] =
3777 							simple_strtol(token2, NULL, 0);
3778 						batch_params.nchan++;
3779 						DHD_PNO(("channel :%d\n",
3780 							batch_params.chan_list[i-1]));
3781 					}
3782 				 }
3783 			} else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
3784 				batch_params.rtt = simple_strtol(value, NULL, 0);
3785 				DHD_PNO(("rtt : %d\n", batch_params.rtt));
3786 			} else {
3787 				DHD_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param));
3788 				err = BCME_ERROR;
3789 				goto exit;
3790 			}
3791 		}
3792 		err = dhd_dev_pno_set_for_batch(dev, &batch_params);
3793 		if (err < 0) {
3794 			DHD_ERROR(("failed to configure batch scan\n"));
3795 		} else {
3796 			bzero(command, total_len);
3797 			err = snprintf(command, total_len, "%d", err);
3798 		}
3799 	} else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
3800 		err = dhd_dev_pno_get_for_batch(dev, command, total_len);
3801 		if (err < 0) {
3802 			DHD_ERROR(("failed to getting batching results\n"));
3803 		} else {
3804 			err = strlen(command);
3805 		}
3806 	} else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
3807 		err = dhd_dev_pno_stop_for_batch(dev);
3808 		if (err < 0) {
3809 			DHD_ERROR(("failed to stop batching scan\n"));
3810 		} else {
3811 			bzero(command, total_len);
3812 			err = snprintf(command, total_len, "OK");
3813 		}
3814 	} else {
3815 		DHD_ERROR(("wls_parse_batching_cmd : unknown command\n"));
3816 		err = BCME_ERROR;
3817 		goto exit;
3818 	}
3819 exit:
3820 	return err;
3821 }
3822 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)3823 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
3824 {
3825 	wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
3826 	int res = -1;
3827 	int nssid = 0;
3828 	cmd_tlv_t *cmd_tlv_temp;
3829 	char *str_ptr;
3830 	int tlv_size_left;
3831 	int pno_time = 0;
3832 	int pno_repeat = 0;
3833 	int pno_freq_expo_max = 0;
3834 
3835 #ifdef PNO_SET_DEBUG
3836 	int i;
3837 	char pno_in_example[] = {
3838 		'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
3839 		'S', '1', '2', '0',
3840 		'S',
3841 		0x05,
3842 		'd', 'l', 'i', 'n', 'k',
3843 		'S',
3844 		0x04,
3845 		'G', 'O', 'O', 'G',
3846 		'T',
3847 		'0', 'B',
3848 		'R',
3849 		'2',
3850 		'M',
3851 		'2',
3852 		0x00
3853 		};
3854 #endif /* PNO_SET_DEBUG */
3855 	DHD_PNO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len));
3856 
3857 	if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
3858 		DHD_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len));
3859 		goto exit_proc;
3860 	}
3861 #ifdef PNO_SET_DEBUG
3862 	memcpy(command, pno_in_example, sizeof(pno_in_example));
3863 	total_len = sizeof(pno_in_example);
3864 #endif // endif
3865 	str_ptr = command + strlen(CMD_PNOSETUP_SET);
3866 	tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
3867 
3868 	cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
3869 	bzero(ssids_local, sizeof(ssids_local));
3870 
3871 	if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
3872 		(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
3873 		(cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
3874 
3875 		str_ptr += sizeof(cmd_tlv_t);
3876 		tlv_size_left -= sizeof(cmd_tlv_t);
3877 
3878 		if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
3879 			MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
3880 			DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
3881 			goto exit_proc;
3882 		} else {
3883 			if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
3884 				DHD_ERROR(("wl_android_set_pno_setup: scan duration corrupted"
3885 					" field size %d\n",
3886 					tlv_size_left));
3887 				goto exit_proc;
3888 			}
3889 			str_ptr++;
3890 			pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
3891 			DHD_PNO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time));
3892 
3893 			if (str_ptr[0] != 0) {
3894 				if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
3895 					DHD_ERROR(("wl_android_set_pno_setup: pno repeat:"
3896 						" corrupted field\n"));
3897 					goto exit_proc;
3898 				}
3899 				str_ptr++;
3900 				pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
3901 				DHD_PNO(("wl_android_set_pno_setup: got pno_repeat=%d\n",
3902 					pno_repeat));
3903 				if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
3904 					DHD_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX"
3905 						" corrupted field size\n"));
3906 					goto exit_proc;
3907 				}
3908 				str_ptr++;
3909 				pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
3910 				DHD_PNO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n",
3911 					pno_freq_expo_max));
3912 			}
3913 		}
3914 	} else {
3915 		DHD_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n"));
3916 		goto exit_proc;
3917 	}
3918 
3919 	res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
3920 		pno_freq_expo_max, NULL, 0);
3921 exit_proc:
3922 	return res;
3923 }
3924 #endif /* !WL_SCHED_SCAN */
3925 #endif /* PNO_SUPPORT  */
3926 
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)3927 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
3928 {
3929 	int ret;
3930 	struct ether_addr p2pdev_addr;
3931 
3932 #define MAC_ADDR_STR_LEN 18
3933 	if (total_len < MAC_ADDR_STR_LEN) {
3934 		DHD_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n",
3935 			total_len));
3936 		return -1;
3937 	}
3938 
3939 	ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
3940 	if (ret) {
3941 		DHD_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n"));
3942 		return -1;
3943 	}
3944 	return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
3945 }
3946 
3947 int
wl_android_set_ap_mac_list(struct net_device * dev,int macmode,struct maclist * maclist)3948 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
3949 {
3950 	int i, j, match;
3951 	int ret	= 0;
3952 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
3953 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
3954 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
3955 
3956 	/* set filtering mode */
3957 	if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
3958 		DHD_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret));
3959 		return ret;
3960 	}
3961 	if (macmode != MACLIST_MODE_DISABLED) {
3962 		/* set the MAC filter list */
3963 		if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
3964 			sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
3965 			DHD_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret));
3966 			return ret;
3967 		}
3968 		/* get the current list of associated STAs */
3969 		assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
3970 		if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
3971 			sizeof(mac_buf))) != 0) {
3972 			DHD_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n",
3973 				ret));
3974 			return ret;
3975 		}
3976 		/* do we have any STA associated?  */
3977 		if (assoc_maclist->count) {
3978 			/* iterate each associated STA */
3979 			for (i = 0; i < assoc_maclist->count; i++) {
3980 				match = 0;
3981 				/* compare with each entry */
3982 				for (j = 0; j < maclist->count; j++) {
3983 					DHD_INFO(("wl_android_set_ap_mac_list: associated="MACDBG
3984 					"list = "MACDBG "\n",
3985 					MAC2STRDBG(assoc_maclist->ea[i].octet),
3986 					MAC2STRDBG(maclist->ea[j].octet)));
3987 					if (memcmp(assoc_maclist->ea[i].octet,
3988 						maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
3989 						match = 1;
3990 						break;
3991 					}
3992 				}
3993 				/* do conditional deauth */
3994 				/*   "if not in the allow list" or "if in the deny list" */
3995 				if ((macmode == MACLIST_MODE_ALLOW && !match) ||
3996 					(macmode == MACLIST_MODE_DENY && match)) {
3997 					scb_val_t scbval;
3998 
3999 					scbval.val = htod32(1);
4000 					memcpy(&scbval.ea, &assoc_maclist->ea[i],
4001 						ETHER_ADDR_LEN);
4002 					if ((ret = wldev_ioctl_set(dev,
4003 						WLC_SCB_DEAUTHENTICATE_FOR_REASON,
4004 						&scbval, sizeof(scb_val_t))) != 0)
4005 						DHD_ERROR(("wl_android_set_ap_mac_list:"
4006 							" WLC_SCB_DEAUTHENTICATE"
4007 							" error=%d\n",
4008 							ret));
4009 				}
4010 			}
4011 		}
4012 	}
4013 	return ret;
4014 }
4015 
4016 /*
4017  * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
4018  *
4019  */
4020 #ifdef AUTOMOTIVE_FEATURE
4021 static int
wl_android_set_mac_address_filter(struct net_device * dev,char * str)4022 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
4023 {
4024 	int i;
4025 	int ret = 0;
4026 	int macnum = 0;
4027 	int macmode = MACLIST_MODE_DISABLED;
4028 	struct maclist *list;
4029 	char eabuf[ETHER_ADDR_STR_LEN];
4030 	const char *token;
4031 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4032 
4033 	/* string should look like below (macmode/macnum/maclist) */
4034 	/*   1 2 00:11:22:33:44:55 00:11:22:33:44:ff  */
4035 
4036 	/* get the MAC filter mode */
4037 	token = strsep((char**)&str, " ");
4038 	if (!token) {
4039 		return -1;
4040 	}
4041 	macmode = bcm_atoi(token);
4042 
4043 	if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
4044 		DHD_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode));
4045 		return -1;
4046 	}
4047 
4048 	token = strsep((char**)&str, " ");
4049 	if (!token) {
4050 		return -1;
4051 	}
4052 	macnum = bcm_atoi(token);
4053 	if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
4054 		DHD_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC"
4055 			" address entries %d\n",
4056 			macnum));
4057 		return -1;
4058 	}
4059 	/* allocate memory for the MAC list */
4060 	list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
4061 		sizeof(struct ether_addr) * macnum);
4062 	if (!list) {
4063 		DHD_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n"));
4064 		return -1;
4065 	}
4066 	/* prepare the MAC list */
4067 	list->count = htod32(macnum);
4068 	bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
4069 	for (i = 0; i < list->count; i++) {
4070 		token = strsep((char**)&str, " ");
4071 		if (token == NULL) {
4072 			DHD_ERROR(("wl_android_set_mac_address_filter : No mac address present\n"));
4073 			ret = -EINVAL;
4074 			goto exit;
4075 		}
4076 		strlcpy(eabuf, token, sizeof(eabuf));
4077 		if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
4078 			DHD_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d,"
4079 				" addr=%s\n",
4080 				i, eabuf));
4081 			list->count = i;
4082 			break;
4083 		}
4084 		DHD_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s",
4085 			i, list->count, eabuf));
4086 	}
4087 	if (i == 0)
4088 		goto exit;
4089 
4090 	/* set the list */
4091 	if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
4092 		DHD_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n",
4093 			ret));
4094 
4095 exit:
4096 	MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
4097 
4098 	return ret;
4099 }
4100 #endif /* AUTOMOTIVE_FEATURE */
4101 /**
4102  * Global function definitions (declared in wl_android.h)
4103  */
4104 
wl_android_wifi_on(struct net_device * dev)4105 int wl_android_wifi_on(struct net_device *dev)
4106 {
4107 	int ret = 0;
4108 	int retry = POWERUP_MAX_RETRY;
4109 
4110 	DHD_ERROR(("wl_android_wifi_on in\n"));
4111 	if (!dev) {
4112 		DHD_ERROR(("wl_android_wifi_on: dev is null\n"));
4113 		return -EINVAL;
4114 	}
4115 
4116 	dhd_net_if_lock(dev);
4117 	if (!g_wifi_on) {
4118 		do {
4119 			dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
4120 #ifdef BCMSDIO
4121 			ret = dhd_net_bus_resume(dev, 0);
4122 #endif /* BCMSDIO */
4123 #ifdef BCMPCIE
4124 			ret = dhd_net_bus_devreset(dev, FALSE);
4125 #endif /* BCMPCIE */
4126 			if (ret == 0) {
4127 				break;
4128 			}
4129 			DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
4130 				retry));
4131 #ifdef BCMPCIE
4132 			dhd_net_bus_devreset(dev, TRUE);
4133 #endif /* BCMPCIE */
4134 			dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4135 		} while (retry-- > 0);
4136 		if (ret != 0) {
4137 			DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
4138 #ifdef BCM_DETECT_TURN_ON_FAILURE
4139 			BUG_ON(1);
4140 #endif /* BCM_DETECT_TURN_ON_FAILURE */
4141 			goto exit;
4142 		}
4143 #ifdef BCMSDIO
4144 		ret = dhd_net_bus_devreset(dev, FALSE);
4145 		dhd_net_bus_resume(dev, 1);
4146 #endif /* BCMSDIO */
4147 
4148 #ifndef BCMPCIE
4149 		if (!ret) {
4150 			if (dhd_dev_init_ioctl(dev) < 0) {
4151 				ret = -EFAULT;
4152 			}
4153 		}
4154 #endif /* !BCMPCIE */
4155 		g_wifi_on = TRUE;
4156 	}
4157 
4158 exit:
4159 	dhd_net_if_unlock(dev);
4160 
4161 	return ret;
4162 }
4163 
wl_android_wifi_off(struct net_device * dev,bool on_failure)4164 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
4165 {
4166 	int ret = 0;
4167 
4168 	DHD_ERROR(("wl_android_wifi_off in\n"));
4169 	if (!dev) {
4170 		DHD_TRACE(("wl_android_wifi_off: dev is null\n"));
4171 		return -EINVAL;
4172 	}
4173 
4174 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
4175 	ret = dhd_debug_uart_is_running(dev);
4176 	if (ret) {
4177 		DHD_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
4178 		return -EBUSY;
4179 	}
4180 #endif	/* BCMPCIE && DHD_DEBUG_UART */
4181 	dhd_net_if_lock(dev);
4182 	if (g_wifi_on || on_failure) {
4183 #if defined(BCMSDIO) || defined(BCMPCIE)
4184 		ret = dhd_net_bus_devreset(dev, TRUE);
4185 #ifdef BCMSDIO
4186 		dhd_net_bus_suspend(dev);
4187 #endif /* BCMSDIO */
4188 #endif /* BCMSDIO || BCMPCIE */
4189 		dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4190 		g_wifi_on = FALSE;
4191 	}
4192 	dhd_net_if_unlock(dev);
4193 
4194 	return ret;
4195 }
4196 
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)4197 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
4198 {
4199 	if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
4200 		return -1;
4201 	return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
4202 }
4203 
4204 #ifdef CONNECTION_STATISTICS
4205 static int
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)4206 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
4207 {
4208 	int err;
4209 	wl_chanim_stats_t *list;
4210 	/* Parameter _and_ returned buffer of chanim_stats. */
4211 	wl_chanim_stats_t param;
4212 	u8 result[WLC_IOCTL_SMLEN];
4213 	chanim_stats_t *stats;
4214 
4215 	bzero(&param, sizeof(param));
4216 
4217 	param.buflen = htod32(sizeof(wl_chanim_stats_t));
4218 	param.count = htod32(WL_CHANIM_COUNT_ONE);
4219 
4220 	if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
4221 		(char*)result, sizeof(result), 0)) < 0) {
4222 		WL_ERR(("Failed to get chanim results %d \n", err));
4223 		return err;
4224 	}
4225 
4226 	list = (wl_chanim_stats_t*)result;
4227 
4228 	list->buflen = dtoh32(list->buflen);
4229 	list->version = dtoh32(list->version);
4230 	list->count = dtoh32(list->count);
4231 
4232 	if (list->buflen == 0) {
4233 		list->version = 0;
4234 		list->count = 0;
4235 	} else if (list->version != WL_CHANIM_STATS_VERSION) {
4236 		WL_ERR(("Sorry, firmware has wl_chanim_stats version %d "
4237 			"but driver supports only version %d.\n",
4238 				list->version, WL_CHANIM_STATS_VERSION));
4239 		list->buflen = 0;
4240 		list->count = 0;
4241 	}
4242 
4243 	stats = list->stats;
4244 	stats->glitchcnt = dtoh32(stats->glitchcnt);
4245 	stats->badplcp = dtoh32(stats->badplcp);
4246 	stats->chanspec = dtoh16(stats->chanspec);
4247 	stats->timestamp = dtoh32(stats->timestamp);
4248 	stats->chan_idle = dtoh32(stats->chan_idle);
4249 
4250 	WL_INFORM(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
4251 		stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
4252 		stats->timestamp));
4253 
4254 	*chan_idle = stats->chan_idle;
4255 
4256 	return (err);
4257 }
4258 
4259 static int
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)4260 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
4261 {
4262 	static char iovar_buf[WLC_IOCTL_MAXLEN];
4263 	const wl_cnt_wlc_t* wlc_cnt = NULL;
4264 #ifndef DISABLE_IF_COUNTERS
4265 	wl_if_stats_t* if_stats = NULL;
4266 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4267 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4268 #endif /* DISABLE_IF_COUNTERS */
4269 
4270 	int link_speed = 0;
4271 	struct connection_stats *output;
4272 	unsigned int bufsize = 0;
4273 	int bytes_written = -1;
4274 	int ret = 0;
4275 
4276 	WL_INFORM(("wl_android_get_connection_stats: enter Get Connection Stats\n"));
4277 
4278 	if (total_len <= 0) {
4279 		WL_ERR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len));
4280 		goto error;
4281 	}
4282 
4283 	bufsize = total_len;
4284 	if (bufsize < sizeof(struct connection_stats)) {
4285 		WL_ERR(("wl_android_get_connection_stats: not enough buffer size, provided=%u,"
4286 			" requires=%zu\n",
4287 			bufsize,
4288 			sizeof(struct connection_stats)));
4289 		goto error;
4290 	}
4291 
4292 	output = (struct connection_stats *)command;
4293 
4294 #ifndef DISABLE_IF_COUNTERS
4295 	if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
4296 	if (if_stats == NULL) {
4297 		WL_ERR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
4298 		goto error;
4299 	}
4300 	bzero(if_stats, sizeof(*if_stats));
4301 
4302 	if (FW_SUPPORTED(dhdp, ifst)) {
4303 		ret = wl_cfg80211_ifstats_counters(dev, if_stats);
4304 	} else
4305 	{
4306 		ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
4307 			(char *)if_stats, sizeof(*if_stats), NULL);
4308 	}
4309 
4310 	ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
4311 		(char *)if_stats, sizeof(*if_stats), NULL);
4312 	if (ret) {
4313 		WL_ERR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n",
4314 			ret));
4315 
4316 		/* In case if_stats IOVAR is not supported, get information from counters. */
4317 #endif /* DISABLE_IF_COUNTERS */
4318 		ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
4319 			iovar_buf, WLC_IOCTL_MAXLEN, NULL);
4320 		if (unlikely(ret)) {
4321 			WL_ERR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
4322 			goto error;
4323 		}
4324 		ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
4325 		if (ret != BCME_OK) {
4326 			WL_ERR(("wl_android_get_connection_stats:"
4327 			" wl_cntbuf_to_xtlv_format ERR %d\n",
4328 			ret));
4329 			goto error;
4330 		}
4331 
4332 		if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
4333 			WL_ERR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
4334 			goto error;
4335 		}
4336 
4337 		output->txframe   = dtoh32(wlc_cnt->txframe);
4338 		output->txbyte    = dtoh32(wlc_cnt->txbyte);
4339 		output->txerror   = dtoh32(wlc_cnt->txerror);
4340 		output->rxframe   = dtoh32(wlc_cnt->rxframe);
4341 		output->rxbyte    = dtoh32(wlc_cnt->rxbyte);
4342 		output->txfail    = dtoh32(wlc_cnt->txfail);
4343 		output->txretry   = dtoh32(wlc_cnt->txretry);
4344 		output->txretrie  = dtoh32(wlc_cnt->txretrie);
4345 		output->txrts     = dtoh32(wlc_cnt->txrts);
4346 		output->txnocts   = dtoh32(wlc_cnt->txnocts);
4347 		output->txexptime = dtoh32(wlc_cnt->txexptime);
4348 #ifndef DISABLE_IF_COUNTERS
4349 	} else {
4350 		/* Populate from if_stats. */
4351 		if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
4352 			WL_ERR(("wl_android_get_connection_stats: incorrect version of"
4353 				" wl_if_stats_t,"
4354 				" expected=%u got=%u\n",
4355 				WL_IF_STATS_T_VERSION, if_stats->version));
4356 			goto error;
4357 		}
4358 
4359 		output->txframe   = (uint32)dtoh64(if_stats->txframe);
4360 		output->txbyte    = (uint32)dtoh64(if_stats->txbyte);
4361 		output->txerror   = (uint32)dtoh64(if_stats->txerror);
4362 		output->rxframe   = (uint32)dtoh64(if_stats->rxframe);
4363 		output->rxbyte    = (uint32)dtoh64(if_stats->rxbyte);
4364 		output->txfail    = (uint32)dtoh64(if_stats->txfail);
4365 		output->txretry   = (uint32)dtoh64(if_stats->txretry);
4366 		output->txretrie  = (uint32)dtoh64(if_stats->txretrie);
4367 		if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
4368 			output->txexptime = (uint32)dtoh64(if_stats->txexptime);
4369 			output->txrts     = (uint32)dtoh64(if_stats->txrts);
4370 			output->txnocts   = (uint32)dtoh64(if_stats->txnocts);
4371 		} else {
4372 			output->txexptime = 0;
4373 			output->txrts     = 0;
4374 			output->txnocts   = 0;
4375 		}
4376 	}
4377 #endif /* DISABLE_IF_COUNTERS */
4378 
4379 	/* link_speed is in kbps */
4380 	ret = wldev_get_link_speed(dev, &link_speed);
4381 	if (ret || link_speed < 0) {
4382 		WL_ERR(("wl_android_get_connection_stats: wldev_get_link_speed()"
4383 			" failed, ret=%d, speed=%d\n",
4384 			ret, link_speed));
4385 		goto error;
4386 	}
4387 
4388 	output->txrate    = link_speed;
4389 
4390 	/* Channel idle ratio. */
4391 	if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
4392 		output->chan_idle = 0;
4393 	};
4394 
4395 	bytes_written = sizeof(struct connection_stats);
4396 
4397 error:
4398 #ifndef DISABLE_IF_COUNTERS
4399 	if (if_stats) {
4400 		MFREE(cfg->osh, if_stats, sizeof(*if_stats));
4401 	}
4402 #endif /* DISABLE_IF_COUNTERS */
4403 
4404 	return bytes_written;
4405 }
4406 #endif /* CONNECTION_STATISTICS */
4407 
4408 #ifdef WL_NATOE
4409 static int
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)4410 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
4411 {
4412 	int ret = BCME_ERROR;
4413 	char *pcmd = command;
4414 	char *str = NULL;
4415 	wl_natoe_cmd_info_t cmd_info;
4416 	const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
4417 
4418 	/* skip to cmd name after "natoe" */
4419 	str = bcmstrtok(&pcmd, " ", NULL);
4420 
4421 	/* If natoe subcmd name is not provided, return error */
4422 	if (*pcmd == '\0') {
4423 		WL_ERR(("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
4424 		ret = -EINVAL;
4425 		return ret;
4426 	}
4427 
4428 	/* get the natoe command name to str */
4429 	str = bcmstrtok(&pcmd, " ", NULL);
4430 
4431 	while (natoe_cmd->name != NULL) {
4432 		if (strcmp(natoe_cmd->name, str) == 0)  {
4433 			/* dispacth cmd to appropriate handler */
4434 			if (natoe_cmd->handler) {
4435 				cmd_info.command = command;
4436 				cmd_info.tot_len = total_len;
4437 				ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
4438 			}
4439 			return ret;
4440 		}
4441 		natoe_cmd++;
4442 	}
4443 	return ret;
4444 }
4445 
4446 static int
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)4447 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
4448 {
4449 	int res = BCME_OK;
4450 	wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
4451 	uint8 *command = cmd_info->command;
4452 	uint16 total_len = cmd_info->tot_len;
4453 	uint16 bytes_written = 0;
4454 
4455 	UNUSED_PARAMETER(len);
4456 
4457 	switch (type) {
4458 
4459 	case WL_NATOE_XTLV_ENABLE:
4460 	{
4461 		bytes_written = snprintf(command, total_len, "natoe: %s\n",
4462 				*data?"enabled":"disabled");
4463 		cmd_info->bytes_written = bytes_written;
4464 		break;
4465 	}
4466 
4467 	case WL_NATOE_XTLV_CONFIG_IPS:
4468 	{
4469 		wl_natoe_config_ips_t *config_ips;
4470 		uint8 buf[16];
4471 
4472 		config_ips = (wl_natoe_config_ips_t *)data;
4473 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
4474 		bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
4475 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
4476 		bytes_written += snprintf(command + bytes_written, total_len,
4477 				"sta netmask: %s\n", buf);
4478 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
4479 		bytes_written += snprintf(command + bytes_written, total_len,
4480 				"sta router ip: %s\n", buf);
4481 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
4482 		bytes_written += snprintf(command + bytes_written, total_len,
4483 				"sta dns ip: %s\n", buf);
4484 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
4485 		bytes_written += snprintf(command + bytes_written, total_len,
4486 				"ap ip: %s\n", buf);
4487 		bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
4488 		bytes_written += snprintf(command + bytes_written, total_len,
4489 				"ap netmask: %s\n", buf);
4490 		cmd_info->bytes_written = bytes_written;
4491 		break;
4492 	}
4493 
4494 	case WL_NATOE_XTLV_CONFIG_PORTS:
4495 	{
4496 		wl_natoe_ports_config_t *ports_config;
4497 
4498 		ports_config = (wl_natoe_ports_config_t *)data;
4499 		bytes_written = snprintf(command, total_len, "starting port num: %d\n",
4500 				dtoh16(ports_config->start_port_num));
4501 		bytes_written += snprintf(command + bytes_written, total_len,
4502 				"number of ports: %d\n", dtoh16(ports_config->no_of_ports));
4503 		cmd_info->bytes_written = bytes_written;
4504 		break;
4505 	}
4506 
4507 	case WL_NATOE_XTLV_DBG_STATS:
4508 	{
4509 		char *stats_dump = (char *)data;
4510 
4511 		bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
4512 		cmd_info->bytes_written = bytes_written;
4513 		break;
4514 	}
4515 
4516 	case WL_NATOE_XTLV_TBL_CNT:
4517 	{
4518 		bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
4519 				dtoh32(*(uint32 *)data));
4520 		cmd_info->bytes_written = bytes_written;
4521 		break;
4522 	}
4523 
4524 	default:
4525 		/* ignore */
4526 		break;
4527 	}
4528 
4529 	return res;
4530 }
4531 
4532 /*
4533  *   --- common for all natoe get commands ----
4534  */
4535 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)4536 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
4537 		uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
4538 {
4539 	/* for gets we only need to pass ioc header */
4540 	wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
4541 	int res;
4542 
4543 	/*  send getbuf natoe iovar */
4544 	res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
4545 			buflen, NULL);
4546 
4547 	/*  check the response buff  */
4548 	if ((res == BCME_OK)) {
4549 		/* scans ioctl tlvbuf f& invokes the cbfn for processing  */
4550 		res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
4551 				BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
4552 
4553 		if (res == BCME_OK) {
4554 			res = cmd_info->bytes_written;
4555 		}
4556 	}
4557 	else
4558 	{
4559 		DHD_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res));
4560 		res = BCME_ERROR;
4561 	}
4562 
4563 	return res;
4564 }
4565 
4566 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)4567 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
4568 		char *command, wl_natoe_cmd_info_t *cmd_info)
4569 {
4570 	int ret = BCME_OK;
4571 	wl_natoe_ioc_t *natoe_ioc;
4572 	char *pcmd = command;
4573 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
4574 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
4575 	bcm_xtlv_t *pxtlv = NULL;
4576 	char *ioctl_buf = NULL;
4577 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4578 
4579 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
4580 	if (!ioctl_buf) {
4581 		WL_ERR(("ioctl memory alloc failed\n"));
4582 		return -ENOMEM;
4583 	}
4584 
4585 	/* alloc mem for ioctl headr + tlv data */
4586 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
4587 	if (!natoe_ioc) {
4588 		WL_ERR(("ioctl header memory alloc failed\n"));
4589 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4590 		return -ENOMEM;
4591 	}
4592 
4593 	/* make up natoe cmd ioctl header */
4594 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
4595 	natoe_ioc->id = htod16(cmd->id);
4596 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
4597 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
4598 
4599 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
4600 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
4601 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
4602 				WLC_IOCTL_MEDLEN, cmd_info);
4603 		if (ret != BCME_OK) {
4604 			WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
4605 			ret = -EINVAL;
4606 		}
4607 	} else {	/* set */
4608 		uint8 val = bcm_atoi(pcmd);
4609 
4610 		/* buflen is max tlv data we can write, it will be decremented as we pack */
4611 		/* save buflen at start */
4612 		uint16 buflen_at_start = buflen;
4613 
4614 		/* we'll adjust final ioc size at the end */
4615 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
4616 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
4617 
4618 		if (ret != BCME_OK) {
4619 			ret = -EINVAL;
4620 			goto exit;
4621 		}
4622 
4623 		/* adjust iocsz to the end of last data record */
4624 		natoe_ioc->len = (buflen_at_start - buflen);
4625 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
4626 
4627 		ret = wldev_iovar_setbuf(dev, "natoe",
4628 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
4629 		if (ret != BCME_OK) {
4630 			WL_ERR(("Fail to set iovar %d\n", ret));
4631 			ret = -EINVAL;
4632 		}
4633 	}
4634 
4635 exit:
4636 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4637 	MFREE(cfg->osh, natoe_ioc, iocsz);
4638 
4639 	return ret;
4640 }
4641 
4642 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)4643 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
4644 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
4645 {
4646 	int ret = BCME_OK;
4647 	wl_natoe_config_ips_t config_ips;
4648 	wl_natoe_ioc_t *natoe_ioc;
4649 	char *pcmd = command;
4650 	char *str;
4651 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
4652 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
4653 	bcm_xtlv_t *pxtlv = NULL;
4654 	char *ioctl_buf = NULL;
4655 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4656 
4657 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
4658 	if (!ioctl_buf) {
4659 		WL_ERR(("ioctl memory alloc failed\n"));
4660 		return -ENOMEM;
4661 	}
4662 
4663 	/* alloc mem for ioctl headr + tlv data */
4664 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
4665 	if (!natoe_ioc) {
4666 		WL_ERR(("ioctl header memory alloc failed\n"));
4667 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4668 		return -ENOMEM;
4669 	}
4670 
4671 	/* make up natoe cmd ioctl header */
4672 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
4673 	natoe_ioc->id = htod16(cmd->id);
4674 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
4675 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
4676 
4677 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
4678 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
4679 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
4680 				WLC_IOCTL_MEDLEN, cmd_info);
4681 		if (ret != BCME_OK) {
4682 			WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
4683 			ret = -EINVAL;
4684 		}
4685 	} else {	/* set */
4686 		/* buflen is max tlv data we can write, it will be decremented as we pack */
4687 		/* save buflen at start */
4688 		uint16 buflen_at_start = buflen;
4689 
4690 		bzero(&config_ips, sizeof(config_ips));
4691 
4692 		str = bcmstrtok(&pcmd, " ", NULL);
4693 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
4694 			WL_ERR(("Invalid STA IP addr %s\n", str));
4695 			ret = -EINVAL;
4696 			goto exit;
4697 		}
4698 
4699 		str = bcmstrtok(&pcmd, " ", NULL);
4700 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
4701 			WL_ERR(("Invalid STA netmask %s\n", str));
4702 			ret = -EINVAL;
4703 			goto exit;
4704 		}
4705 
4706 		str = bcmstrtok(&pcmd, " ", NULL);
4707 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
4708 			WL_ERR(("Invalid STA router IP addr %s\n", str));
4709 			ret = -EINVAL;
4710 			goto exit;
4711 		}
4712 
4713 		str = bcmstrtok(&pcmd, " ", NULL);
4714 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
4715 			WL_ERR(("Invalid STA DNS IP addr %s\n", str));
4716 			ret = -EINVAL;
4717 			goto exit;
4718 		}
4719 
4720 		str = bcmstrtok(&pcmd, " ", NULL);
4721 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
4722 			WL_ERR(("Invalid AP IP addr %s\n", str));
4723 			ret = -EINVAL;
4724 			goto exit;
4725 		}
4726 
4727 		str = bcmstrtok(&pcmd, " ", NULL);
4728 		if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
4729 			WL_ERR(("Invalid AP netmask %s\n", str));
4730 			ret = -EINVAL;
4731 			goto exit;
4732 		}
4733 
4734 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
4735 				&buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
4736 				&config_ips, BCM_XTLV_OPTION_ALIGN32);
4737 
4738 		if (ret != BCME_OK) {
4739 			ret = -EINVAL;
4740 			goto exit;
4741 		}
4742 
4743 		/* adjust iocsz to the end of last data record */
4744 		natoe_ioc->len = (buflen_at_start - buflen);
4745 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
4746 
4747 		ret = wldev_iovar_setbuf(dev, "natoe",
4748 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
4749 		if (ret != BCME_OK) {
4750 			WL_ERR(("Fail to set iovar %d\n", ret));
4751 			ret = -EINVAL;
4752 		}
4753 	}
4754 
4755 exit:
4756 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4757 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
4758 
4759 	return ret;
4760 }
4761 
4762 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)4763 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
4764 		const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
4765 {
4766 	int ret = BCME_OK;
4767 	wl_natoe_ports_config_t ports_config;
4768 	wl_natoe_ioc_t *natoe_ioc;
4769 	char *pcmd = command;
4770 	char *str;
4771 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
4772 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
4773 	bcm_xtlv_t *pxtlv = NULL;
4774 	char *ioctl_buf = NULL;
4775 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4776 
4777 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
4778 	if (!ioctl_buf) {
4779 		WL_ERR(("ioctl memory alloc failed\n"));
4780 		return -ENOMEM;
4781 	}
4782 
4783 	/* alloc mem for ioctl headr + tlv data */
4784 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
4785 	if (!natoe_ioc) {
4786 		WL_ERR(("ioctl header memory alloc failed\n"));
4787 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4788 		return -ENOMEM;
4789 	}
4790 
4791 	/* make up natoe cmd ioctl header */
4792 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
4793 	natoe_ioc->id = htod16(cmd->id);
4794 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
4795 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
4796 
4797 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
4798 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
4799 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
4800 				WLC_IOCTL_MEDLEN, cmd_info);
4801 		if (ret != BCME_OK) {
4802 			WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
4803 			ret = -EINVAL;
4804 		}
4805 	} else {	/* set */
4806 		/* buflen is max tlv data we can write, it will be decremented as we pack */
4807 		/* save buflen at start */
4808 		uint16 buflen_at_start = buflen;
4809 
4810 		bzero(&ports_config, sizeof(ports_config));
4811 
4812 		str = bcmstrtok(&pcmd, " ", NULL);
4813 		if (!str) {
4814 			WL_ERR(("Invalid port string %s\n", str));
4815 			ret = -EINVAL;
4816 			goto exit;
4817 		}
4818 		ports_config.start_port_num = htod16(bcm_atoi(str));
4819 
4820 		str = bcmstrtok(&pcmd, " ", NULL);
4821 		if (!str) {
4822 			WL_ERR(("Invalid port string %s\n", str));
4823 			ret = -EINVAL;
4824 			goto exit;
4825 		}
4826 		ports_config.no_of_ports = htod16(bcm_atoi(str));
4827 
4828 		if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
4829 				NATOE_MAX_PORT_NUM) {
4830 			WL_ERR(("Invalid port configuration\n"));
4831 			ret = -EINVAL;
4832 			goto exit;
4833 		}
4834 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
4835 				&buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
4836 				&ports_config, BCM_XTLV_OPTION_ALIGN32);
4837 
4838 		if (ret != BCME_OK) {
4839 			ret = -EINVAL;
4840 			goto exit;
4841 		}
4842 
4843 		/* adjust iocsz to the end of last data record */
4844 		natoe_ioc->len = (buflen_at_start - buflen);
4845 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
4846 
4847 		ret = wldev_iovar_setbuf(dev, "natoe",
4848 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
4849 		if (ret != BCME_OK) {
4850 			WL_ERR(("Fail to set iovar %d\n", ret));
4851 			ret = -EINVAL;
4852 		}
4853 	}
4854 
4855 exit:
4856 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4857 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
4858 
4859 	return ret;
4860 }
4861 
4862 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)4863 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
4864 		char *command, wl_natoe_cmd_info_t *cmd_info)
4865 {
4866 	int ret = BCME_OK;
4867 	wl_natoe_ioc_t *natoe_ioc;
4868 	char *pcmd = command;
4869 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
4870 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
4871 	uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
4872 	bcm_xtlv_t *pxtlv = NULL;
4873 	char *ioctl_buf = NULL;
4874 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4875 
4876 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
4877 	if (!ioctl_buf) {
4878 		WL_ERR(("ioctl memory alloc failed\n"));
4879 		return -ENOMEM;
4880 	}
4881 
4882 	/* alloc mem for ioctl headr + tlv data */
4883 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
4884 	if (!natoe_ioc) {
4885 		WL_ERR(("ioctl header memory alloc failed\n"));
4886 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
4887 		return -ENOMEM;
4888 	}
4889 
4890 	/* make up natoe cmd ioctl header */
4891 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
4892 	natoe_ioc->id = htod16(cmd->id);
4893 	natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
4894 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
4895 
4896 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
4897 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
4898 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
4899 				WLC_IOCTL_MAXLEN, cmd_info);
4900 		if (ret != BCME_OK) {
4901 			WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
4902 			ret = -EINVAL;
4903 		}
4904 	} else {	/* set */
4905 		uint8 val = bcm_atoi(pcmd);
4906 
4907 		/* buflen is max tlv data we can write, it will be decremented as we pack */
4908 		/* save buflen at start */
4909 		uint16 buflen_at_start = buflen;
4910 
4911 		/* we'll adjust final ioc size at the end */
4912 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
4913 			sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
4914 
4915 		if (ret != BCME_OK) {
4916 			ret = -EINVAL;
4917 			goto exit;
4918 		}
4919 
4920 		/* adjust iocsz to the end of last data record */
4921 		natoe_ioc->len = (buflen_at_start - buflen);
4922 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
4923 
4924 		ret = wldev_iovar_setbuf(dev, "natoe",
4925 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
4926 		if (ret != BCME_OK) {
4927 			WL_ERR(("Fail to set iovar %d\n", ret));
4928 			ret = -EINVAL;
4929 		}
4930 	}
4931 
4932 exit:
4933 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
4934 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
4935 
4936 	return ret;
4937 }
4938 
4939 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)4940 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
4941 		char *command, wl_natoe_cmd_info_t *cmd_info)
4942 {
4943 	int ret = BCME_OK;
4944 	wl_natoe_ioc_t *natoe_ioc;
4945 	char *pcmd = command;
4946 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
4947 	uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
4948 	uint16 buflen = WL_NATOE_IOC_BUFSZ;
4949 	bcm_xtlv_t *pxtlv = NULL;
4950 	char *ioctl_buf = NULL;
4951 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4952 
4953 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
4954 	if (!ioctl_buf) {
4955 		WL_ERR(("ioctl memory alloc failed\n"));
4956 		return -ENOMEM;
4957 	}
4958 
4959 	/* alloc mem for ioctl headr + tlv data */
4960 	natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
4961 	if (!natoe_ioc) {
4962 		WL_ERR(("ioctl header memory alloc failed\n"));
4963 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
4964 		return -ENOMEM;
4965 	}
4966 
4967 	/* make up natoe cmd ioctl header */
4968 	natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
4969 	natoe_ioc->id = htod16(cmd->id);
4970 	natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
4971 	pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
4972 
4973 	if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
4974 		iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
4975 		ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
4976 				WLC_IOCTL_MEDLEN, cmd_info);
4977 		if (ret != BCME_OK) {
4978 			WL_ERR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
4979 			ret = -EINVAL;
4980 		}
4981 	} else {	/* set */
4982 		uint32 val = bcm_atoi(pcmd);
4983 
4984 		/* buflen is max tlv data we can write, it will be decremented as we pack */
4985 		/* save buflen at start */
4986 		uint16 buflen_at_start = buflen;
4987 
4988 		/* we'll adjust final ioc size at the end */
4989 		ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
4990 			sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
4991 
4992 		if (ret != BCME_OK) {
4993 			ret = -EINVAL;
4994 			goto exit;
4995 		}
4996 
4997 		/* adjust iocsz to the end of last data record */
4998 		natoe_ioc->len = (buflen_at_start - buflen);
4999 		iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5000 
5001 		ret = wldev_iovar_setbuf(dev, "natoe",
5002 				natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5003 		if (ret != BCME_OK) {
5004 			WL_ERR(("Fail to set iovar %d\n", ret));
5005 			ret = -EINVAL;
5006 		}
5007 	}
5008 
5009 exit:
5010 	MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5011 	MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5012 
5013 	return ret;
5014 }
5015 
5016 #endif /* WL_NATOE */
5017 
5018 #ifdef WL_MBO
5019 static int
wl_android_process_mbo_cmd(struct net_device * dev,char * command,int total_len)5020 wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len)
5021 {
5022 	int ret = BCME_ERROR;
5023 	char *pcmd = command;
5024 	char *str = NULL;
5025 	wl_drv_cmd_info_t cmd_info;
5026 	const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
5027 
5028 	/* skip to cmd name after "mbo" */
5029 	str = bcmstrtok(&pcmd, " ", NULL);
5030 
5031 	/* If mbo subcmd name is not provided, return error */
5032 	if (*pcmd == '\0') {
5033 		WL_ERR(("mbo subcmd not provided %s\n", __FUNCTION__));
5034 		ret = -EINVAL;
5035 		return ret;
5036 	}
5037 
5038 	/* get the mbo command name to str */
5039 	str = bcmstrtok(&pcmd, " ", NULL);
5040 
5041 	while (mbo_cmd->name != NULL) {
5042 		if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
5043 			/* dispatch cmd to appropriate handler */
5044 			if (mbo_cmd->handler) {
5045 				cmd_info.command = command;
5046 				cmd_info.tot_len = total_len;
5047 				ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
5048 			}
5049 			return ret;
5050 		}
5051 		mbo_cmd++;
5052 	}
5053 	return ret;
5054 }
5055 
5056 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)5057 wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf,
5058 	uint16 iov_buf_len, uint8 *iov_resp, uint16 iov_resp_len, uint8 sub_elem_type)
5059 {
5060 	int ret = BCME_OK;
5061 	uint8 *pxtlv = NULL;
5062 	uint16 iovlen = 0;
5063 	uint16 buflen = 0, buflen_start = 0;
5064 
5065 	memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
5066 	iov_buf->version = WL_MBO_IOV_VERSION;
5067 	iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
5068 	buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
5069 	pxtlv = (uint8 *)&iov_buf->data[0];
5070 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
5071 		sizeof(sub_elem_type), &sub_elem_type, BCM_XTLV_OPTION_ALIGN32);
5072 	if (ret != BCME_OK) {
5073 		return ret;
5074 	}
5075 	iov_buf->len = buflen_start - buflen;
5076 	iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5077 	ret = wldev_iovar_setbuf(dev, "mbo",
5078 			iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5079 	if (ret != BCME_OK) {
5080 		WL_ERR(("Fail to sent wnm notif %d\n", ret));
5081 	}
5082 	return ret;
5083 }
5084 
5085 static int
wl_android_mbo_resp_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5086 wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5087 {
5088 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
5089 	uint8 *command = cmd_info->command;
5090 	uint16 total_len = cmd_info->tot_len;
5091 	uint16 bytes_written = 0;
5092 
5093 	UNUSED_PARAMETER(len);
5094 	/* TODO: validate data value */
5095 	if (data == NULL) {
5096 		WL_ERR(("%s: Bad argument !!\n", __FUNCTION__));
5097 		return -EINVAL;
5098 	}
5099 	switch (type) {
5100 		case WL_MBO_XTLV_CELL_DATA_CAP:
5101 		{
5102 			bytes_written = snprintf(command, total_len, "cell_data_cap: %u\n", *data);
5103 			cmd_info->bytes_written = bytes_written;
5104 		}
5105 		break;
5106 		default:
5107 			WL_ERR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
5108 	}
5109 	return BCME_OK;
5110 }
5111 
5112 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)5113 wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd_t *cmd,
5114 		char *command, wl_drv_cmd_info_t *cmd_info)
5115 {
5116 	int ret = BCME_OK;
5117 	uint8 *pxtlv = NULL;
5118 	uint16 buflen = 0, buflen_start = 0;
5119 	uint16 iovlen = 0;
5120 	char *pcmd = command;
5121 	bcm_iov_buf_t *iov_buf = NULL;
5122 	bcm_iov_buf_t *p_resp = NULL;
5123 	uint8 *iov_resp = NULL;
5124 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5125 	uint16 version;
5126 
5127 	/* first get the configured value */
5128 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5129 	if (iov_buf == NULL) {
5130 		ret = -ENOMEM;
5131 		WL_ERR(("iov buf memory alloc exited\n"));
5132 		goto exit;
5133 	}
5134 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5135 	if (iov_resp == NULL) {
5136 		ret = -ENOMEM;
5137 		WL_ERR(("iov resp memory alloc exited\n"));
5138 		goto exit;
5139 	}
5140 
5141 	/* fill header */
5142 	iov_buf->version = WL_MBO_IOV_VERSION;
5143 	iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
5144 
5145 	ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
5146 		WLC_IOCTL_MAXLEN,
5147 		NULL);
5148 	if (ret != BCME_OK) {
5149 		goto exit;
5150 	}
5151 	p_resp = (bcm_iov_buf_t *)iov_resp;
5152 
5153 	/* get */
5154 	if (*pcmd == WL_IOCTL_ACTION_GET) {
5155 		/* Check for version */
5156 		version = dtoh16(*(uint16 *)iov_resp);
5157 		if (version != WL_MBO_IOV_VERSION) {
5158 			ret = -EINVAL;
5159 		}
5160 		if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
5161 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
5162 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
5163 				wl_android_mbo_resp_parse_cbfn);
5164 			if (ret == BCME_OK) {
5165 				ret = cmd_info->bytes_written;
5166 			}
5167 		} else {
5168 			ret = -EINVAL;
5169 			WL_ERR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
5170 			goto exit;
5171 		}
5172 	} else {
5173 		uint8 cell_cap = bcm_atoi(pcmd);
5174 		const uint8* old_cell_cap = NULL;
5175 		uint16 len = 0;
5176 
5177 		old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len,
5178 			WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32);
5179 		if (old_cell_cap && *old_cell_cap == cell_cap) {
5180 			WL_ERR(("No change is cellular data capability\n"));
5181 			/* No change in value */
5182 			goto exit;
5183 		}
5184 
5185 		buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
5186 
5187 		if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
5188 			cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
5189 			WL_ERR(("wrong value %u\n", cell_cap));
5190 			ret = -EINVAL;
5191 			goto exit;
5192 		}
5193 		pxtlv = (uint8 *)&iov_buf->data[0];
5194 		ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
5195 			sizeof(cell_cap), &cell_cap, BCM_XTLV_OPTION_ALIGN32);
5196 		if (ret != BCME_OK) {
5197 			goto exit;
5198 		}
5199 		iov_buf->len = buflen_start - buflen;
5200 		iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5201 		ret = wldev_iovar_setbuf(dev, "mbo",
5202 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5203 		if (ret != BCME_OK) {
5204 			WL_ERR(("Fail to set iovar %d\n", ret));
5205 			ret = -EINVAL;
5206 			goto exit;
5207 		}
5208 		/* Skip for CUSTOMER_HW4 - WNM notification
5209 		 * for cellular data capability is handled by host
5210 		 */
5211 		/* send a WNM notification request to associated AP */
5212 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
5213 			WL_INFORM(("Sending WNM Notif\n"));
5214 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
5215 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP);
5216 			if (ret != BCME_OK) {
5217 				WL_ERR(("Fail to send WNM notification %d\n", ret));
5218 				ret = -EINVAL;
5219 			}
5220 		}
5221 	}
5222 exit:
5223 	if (iov_buf) {
5224 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
5225 	}
5226 	if (iov_resp) {
5227 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
5228 	}
5229 	return ret;
5230 }
5231 
5232 static int
wl_android_mbo_non_pref_chan_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5233 wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5234 {
5235 	wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
5236 	uint8 *command = cmd_info->command + cmd_info->bytes_written;
5237 	uint16 total_len = cmd_info->tot_len;
5238 	uint16 bytes_written = 0;
5239 
5240 	WL_DBG(("Total bytes written at begining %u\n", cmd_info->bytes_written));
5241 	UNUSED_PARAMETER(len);
5242 	if (data == NULL) {
5243 		WL_ERR(("%s: Bad argument !!\n", __FUNCTION__));
5244 		return -EINVAL;
5245 	}
5246 	switch (type) {
5247 		case WL_MBO_XTLV_OPCLASS:
5248 		{
5249 			bytes_written = snprintf(command, total_len, "%u:", *data);
5250 			WL_ERR(("wr %u %u\n", bytes_written, *data));
5251 			command += bytes_written;
5252 			cmd_info->bytes_written += bytes_written;
5253 		}
5254 		break;
5255 		case WL_MBO_XTLV_CHAN:
5256 		{
5257 			bytes_written = snprintf(command, total_len, "%u:", *data);
5258 			WL_ERR(("wr %u\n", bytes_written));
5259 			command += bytes_written;
5260 			cmd_info->bytes_written += bytes_written;
5261 		}
5262 		break;
5263 		case WL_MBO_XTLV_PREFERENCE:
5264 		{
5265 			bytes_written = snprintf(command, total_len, "%u:", *data);
5266 			WL_ERR(("wr %u\n", bytes_written));
5267 			command += bytes_written;
5268 			cmd_info->bytes_written += bytes_written;
5269 		}
5270 		break;
5271 		case WL_MBO_XTLV_REASON_CODE:
5272 		{
5273 			bytes_written = snprintf(command, total_len, "%u ", *data);
5274 			WL_ERR(("wr %u\n", bytes_written));
5275 			command += bytes_written;
5276 			cmd_info->bytes_written += bytes_written;
5277 		}
5278 		break;
5279 		default:
5280 			WL_ERR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
5281 	}
5282 	WL_DBG(("Total bytes written %u\n", cmd_info->bytes_written));
5283 	return BCME_OK;
5284 }
5285 
5286 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)5287 wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
5288 		const wl_drv_sub_cmd_t *cmd, char *command,
5289 		wl_drv_cmd_info_t *cmd_info)
5290 {
5291 	int ret = BCME_OK;
5292 	uint8 *pxtlv = NULL;
5293 	uint16 buflen = 0, buflen_start = 0;
5294 	uint16 iovlen = 0;
5295 	char *pcmd = command;
5296 	bcm_iov_buf_t *iov_buf = NULL;
5297 	bcm_iov_buf_t *p_resp = NULL;
5298 	uint8 *iov_resp = NULL;
5299 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5300 	uint16 version;
5301 
5302 	WL_ERR(("%s:%d\n", __FUNCTION__, __LINE__));
5303 	iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5304 	if (iov_buf == NULL) {
5305 		ret = -ENOMEM;
5306 		WL_ERR(("iov buf memory alloc exited\n"));
5307 		goto exit;
5308 	}
5309 	iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5310 	if (iov_resp == NULL) {
5311 		ret = -ENOMEM;
5312 		WL_ERR(("iov resp memory alloc exited\n"));
5313 		goto exit;
5314 	}
5315 	/* get */
5316 	if (*pcmd == WL_IOCTL_ACTION_GET) {
5317 		/* fill header */
5318 		iov_buf->version = WL_MBO_IOV_VERSION;
5319 		iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
5320 
5321 		ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
5322 				WLC_IOCTL_MAXLEN, NULL);
5323 		if (ret != BCME_OK) {
5324 			goto exit;
5325 		}
5326 		p_resp = (bcm_iov_buf_t *)iov_resp;
5327 		/* Check for version */
5328 		version = dtoh16(*(uint16 *)iov_resp);
5329 		if (version != WL_MBO_IOV_VERSION) {
5330 			WL_ERR(("Version mismatch. returned ver %u expected %u\n",
5331 				version, WL_MBO_IOV_VERSION));
5332 			ret = -EINVAL;
5333 		}
5334 		if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
5335 			ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
5336 				p_resp->len, BCM_XTLV_OPTION_ALIGN32,
5337 				wl_android_mbo_non_pref_chan_parse_cbfn);
5338 			if (ret == BCME_OK) {
5339 				ret = cmd_info->bytes_written;
5340 			}
5341 		} else {
5342 			ret = -EINVAL;
5343 			WL_ERR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
5344 			goto exit;
5345 		}
5346 	} else {
5347 		char *str = pcmd;
5348 		uint opcl = 0, ch = 0, pref = 0, rc = 0;
5349 
5350 		str = bcmstrtok(&pcmd, " ", NULL);
5351 		if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) {
5352 			/* delete all configurations */
5353 			iov_buf->version = WL_MBO_IOV_VERSION;
5354 			iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
5355 			iov_buf->len = 0;
5356 			iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5357 			ret = wldev_iovar_setbuf(dev, "mbo",
5358 				iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5359 			if (ret != BCME_OK) {
5360 				WL_ERR(("Fail to set iovar %d\n", ret));
5361 				ret = -EINVAL;
5362 				goto exit;
5363 			}
5364 		} else {
5365 			WL_ERR(("Unknown command %s\n", str));
5366 			goto exit;
5367 		}
5368 		/* parse non pref channel list */
5369 		if (strnicmp(str, "set", 3) == 0) {
5370 			uint8 cnt = 0;
5371 			str = bcmstrtok(&pcmd, " ", NULL);
5372 			while (str != NULL) {
5373 				ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
5374 				WL_ERR(("buflen %u op %u, ch %u, pref %u rc %u\n",
5375 					buflen, opcl, ch, pref, rc));
5376 				if (ret != 4) {
5377 					WL_ERR(("Not all parameter presents\n"));
5378 					ret = -EINVAL;
5379 				}
5380 				/* TODO: add a validation check here */
5381 				memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
5382 				buflen = buflen_start = WLC_IOCTL_MEDLEN;
5383 				pxtlv = (uint8 *)&iov_buf->data[0];
5384 				/* opclass */
5385 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
5386 					sizeof(uint8), (uint8 *)&opcl, BCM_XTLV_OPTION_ALIGN32);
5387 				if (ret != BCME_OK) {
5388 					goto exit;
5389 				}
5390 				/* channel */
5391 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
5392 					sizeof(uint8), (uint8 *)&ch, BCM_XTLV_OPTION_ALIGN32);
5393 				if (ret != BCME_OK) {
5394 					goto exit;
5395 				}
5396 				/* preference */
5397 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
5398 					sizeof(uint8), (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
5399 				if (ret != BCME_OK) {
5400 					goto exit;
5401 				}
5402 				/* reason */
5403 				ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
5404 					sizeof(uint8), (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
5405 				if (ret != BCME_OK) {
5406 					goto exit;
5407 				}
5408 				WL_ERR(("len %u\n", (buflen_start - buflen)));
5409 				/* Now set the new non pref channels */
5410 				iov_buf->version = WL_MBO_IOV_VERSION;
5411 				iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
5412 				iov_buf->len = buflen_start - buflen;
5413 				iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5414 				ret = wldev_iovar_setbuf(dev, "mbo",
5415 					iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL);
5416 				if (ret != BCME_OK) {
5417 					WL_ERR(("Fail to set iovar %d\n", ret));
5418 					ret = -EINVAL;
5419 					goto exit;
5420 				}
5421 				cnt++;
5422 				if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
5423 					break;
5424 				}
5425 				WL_ERR(("%d cnt %u\n", __LINE__, cnt));
5426 				str = bcmstrtok(&pcmd, " ", NULL);
5427 			}
5428 		}
5429 		/* send a WNM notification request to associated AP */
5430 		if (wl_get_drv_status(cfg, CONNECTED, dev)) {
5431 			WL_INFORM(("Sending WNM Notif\n"));
5432 			ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
5433 				iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT);
5434 			if (ret != BCME_OK) {
5435 				WL_ERR(("Fail to send WNM notification %d\n", ret));
5436 				ret = -EINVAL;
5437 			}
5438 		}
5439 	}
5440 exit:
5441 	if (iov_buf) {
5442 		MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
5443 	}
5444 	if (iov_resp) {
5445 		MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
5446 	}
5447 	return ret;
5448 }
5449 #endif /* WL_MBO */
5450 
5451 #ifdef CUSTOMER_HW4_PRIVATE_CMD
5452 #ifdef SUPPORT_AMPDU_MPDU_CMD
5453 /* CMD_AMPDU_MPDU */
5454 static int
wl_android_set_ampdu_mpdu(struct net_device * dev,const char * string_num)5455 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
5456 {
5457 	int err = 0;
5458 	int ampdu_mpdu;
5459 
5460 	ampdu_mpdu = bcm_atoi(string_num);
5461 
5462 	if (ampdu_mpdu > 32) {
5463 		DHD_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n"));
5464 		return -1;
5465 	}
5466 
5467 	DHD_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu));
5468 	err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
5469 	if (err < 0) {
5470 		DHD_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err));
5471 		return -1;
5472 	}
5473 
5474 	return 0;
5475 }
5476 #endif /* SUPPORT_AMPDU_MPDU_CMD */
5477 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
5478 
5479 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
5480 extern int wl_cfg80211_send_msg_to_ril(void);
5481 extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
5482 extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
5483 extern int g_mhs_chan_for_cpcoex;
5484 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
5485 
5486 #if defined(WL_SUPPORT_AUTO_CHANNEL)
5487 /* SoftAP feature */
5488 #define APCS_BAND_2G_LEGACY1	20
5489 #define APCS_BAND_2G_LEGACY2	0
5490 #define APCS_BAND_AUTO		"band=auto"
5491 #define APCS_BAND_2G		"band=2g"
5492 #define APCS_BAND_5G		"band=5g"
5493 #define APCS_MAX_2G_CHANNELS	11
5494 #define APCS_MAX_RETRY		10
5495 #define APCS_DEFAULT_2G_CH	1
5496 #define APCS_DEFAULT_5G_CH	149
5497 static int
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)5498 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
5499 	char* command, int total_len)
5500 {
5501 	int channel = 0;
5502 	int chosen = 0;
5503 	int retry = 0;
5504 	int ret = 0;
5505 	int spect = 0;
5506 	u8 *reqbuf = NULL;
5507 	uint32 band = WLC_BAND_2G;
5508 	uint32 buf_size;
5509 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5510 
5511 	if (cmd_str) {
5512 		WL_INFORM(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
5513 		if (strncmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
5514 			band = WLC_BAND_AUTO;
5515 		} else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
5516 			band = WLC_BAND_5G;
5517 		} else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
5518 			band = WLC_BAND_2G;
5519 		} else {
5520 			/*
5521 			 * For backward compatibility: Some platforms used to issue argument 20 or 0
5522 			 * to enforce the 2G channel selection
5523 			 */
5524 			channel = bcm_atoi(cmd_str);
5525 			if ((channel == APCS_BAND_2G_LEGACY1) ||
5526 				(channel == APCS_BAND_2G_LEGACY2)) {
5527 				band = WLC_BAND_2G;
5528 			} else {
5529 				WL_ERR(("Invalid argument\n"));
5530 				return -EINVAL;
5531 			}
5532 		}
5533 	} else {
5534 		/* If no argument is provided, default to 2G */
5535 		WL_ERR(("No argument given default to 2.4G scan\n"));
5536 		band = WLC_BAND_2G;
5537 	}
5538 	WL_INFORM(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
5539 
5540 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
5541 	wl_cfg80211_register_dev_ril_bridge_event_notifier();
5542 	if (band == WLC_BAND_2G) {
5543 		wl_cfg80211_send_msg_to_ril();
5544 
5545 		if (g_mhs_chan_for_cpcoex) {
5546 			channel = g_mhs_chan_for_cpcoex;
5547 			g_mhs_chan_for_cpcoex = 0;
5548 			goto done2;
5549 		}
5550 	}
5551 	wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
5552 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
5553 
5554 	/* If STA is connected, return is STA channel, else ACS can be issued,
5555 	 * set spect to 0 and proceed with ACS
5556 	 */
5557 	channel = wl_cfg80211_get_sta_channel(cfg);
5558 	if (channel) {
5559 		channel = (channel <= CH_MAX_2G_CHANNEL) ?
5560 			channel : APCS_DEFAULT_2G_CH;
5561 		goto done2;
5562 	}
5563 
5564 	ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
5565 	if (ret) {
5566 		WL_ERR(("ACS: error getting the spect, ret=%d\n", ret));
5567 		goto done;
5568 	}
5569 
5570 	if (spect > 0) {
5571 		ret = wl_cfg80211_set_spect(dev, 0);
5572 		if (ret < 0) {
5573 			WL_ERR(("ACS: error while setting spect, ret=%d\n", ret));
5574 			goto done;
5575 		}
5576 	}
5577 
5578 	reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
5579 	if (reqbuf == NULL) {
5580 		WL_ERR(("failed to allocate chanspec buffer\n"));
5581 		return -ENOMEM;
5582 	}
5583 
5584 	if (band == WLC_BAND_AUTO) {
5585 		WL_DBG(("ACS full channel scan \n"));
5586 		reqbuf[0] = htod32(0);
5587 	} else if (band == WLC_BAND_5G) {
5588 		WL_DBG(("ACS 5G band scan \n"));
5589 		if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
5590 			WL_ERR(("ACS 5g chanspec retreival failed! \n"));
5591 			goto done;
5592 		}
5593 	} else if (band == WLC_BAND_2G) {
5594 		/*
5595 		 * If channel argument is not provided/ argument 20 is provided,
5596 		 * Restrict channel to 2GHz, 20MHz BW, No SB
5597 		 */
5598 		WL_DBG(("ACS 2G band scan \n"));
5599 		if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
5600 			WL_ERR(("ACS 2g chanspec retreival failed! \n"));
5601 			goto done;
5602 		}
5603 	} else {
5604 		WL_ERR(("ACS: No band chosen\n"));
5605 		goto done2;
5606 	}
5607 
5608 	buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
5609 	ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
5610 		buf_size);
5611 	if (ret < 0) {
5612 		WL_ERR(("can't start auto channel scan, err = %d\n", ret));
5613 		channel = 0;
5614 		goto done;
5615 	}
5616 
5617 	/* Wait for auto channel selection, max 3000 ms */
5618 	if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
5619 		OSL_SLEEP(500);
5620 	} else {
5621 		/*
5622 		 * Full channel scan at the minimum takes 1.2secs
5623 		 * even with parallel scan. max wait time: 3500ms
5624 		 */
5625 		OSL_SLEEP(1000);
5626 	}
5627 
5628 	retry = APCS_MAX_RETRY;
5629 	while (retry--) {
5630 		ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
5631 			sizeof(chosen));
5632 		if (ret < 0) {
5633 			chosen = 0;
5634 		} else {
5635 			chosen = dtoh32(chosen);
5636 		}
5637 
5638 		if (chosen) {
5639 			int chosen_band;
5640 			int apcs_band;
5641 #ifdef D11AC_IOTYPES
5642 			if (wl_cfg80211_get_ioctl_version() == 1) {
5643 				channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
5644 			} else {
5645 				channel = CHSPEC_CHANNEL((chanspec_t)chosen);
5646 			}
5647 #else
5648 			channel = CHSPEC_CHANNEL((chanspec_t)chosen);
5649 #endif /* D11AC_IOTYPES */
5650 			apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
5651 			chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
5652 			if (apcs_band == chosen_band) {
5653 				WL_ERR(("selected channel = %d\n", channel));
5654 				break;
5655 			}
5656 		}
5657 		WL_DBG(("%d tried, ret = %d, chosen = 0x%x\n",
5658 			(APCS_MAX_RETRY - retry), ret, chosen));
5659 		OSL_SLEEP(250);
5660 	}
5661 
5662 done:
5663 	if ((retry == 0) || (ret < 0)) {
5664 		/* On failure, fallback to a default channel */
5665 		if (band == WLC_BAND_5G) {
5666 			channel = APCS_DEFAULT_5G_CH;
5667 		} else {
5668 			channel = APCS_DEFAULT_2G_CH;
5669 		}
5670 		WL_ERR(("ACS failed. Fall back to default channel (%d) \n", channel));
5671 	}
5672 done2:
5673 	if (spect > 0) {
5674 		if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
5675 			WL_ERR(("ACS: error while setting spect\n"));
5676 		}
5677 	}
5678 
5679 	if (reqbuf) {
5680 		MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
5681 	}
5682 
5683 	if (channel) {
5684 		ret = snprintf(command, total_len, "%d", channel);
5685 		WL_INFORM(("command result is %s \n", command));
5686 	}
5687 
5688 	return ret;
5689 }
5690 #endif /* WL_SUPPORT_AUTO_CHANNEL */
5691 
5692 #ifdef SUPPORT_HIDDEN_AP
5693 static int
wl_android_set_max_num_sta(struct net_device * dev,const char * string_num)5694 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
5695 {
5696 	int err = BCME_ERROR;
5697 	int max_assoc;
5698 
5699 	max_assoc = bcm_atoi(string_num);
5700 	DHD_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc));
5701 
5702 	err = wldev_iovar_setint(dev, "maxassoc", max_assoc);
5703 	if (err < 0) {
5704 		WL_ERR(("failed to set maxassoc, error:%d\n", err));
5705 	}
5706 
5707 	return err;
5708 }
5709 
5710 static int
wl_android_set_ssid(struct net_device * dev,const char * hapd_ssid)5711 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
5712 {
5713 	wlc_ssid_t ssid;
5714 	s32 ret;
5715 
5716 	ssid.SSID_len = strlen(hapd_ssid);
5717 	if (ssid.SSID_len == 0) {
5718 		WL_ERR(("wl_android_set_ssids : No SSID\n"));
5719 		return -1;
5720 	}
5721 	if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
5722 		ssid.SSID_len = DOT11_MAX_SSID_LEN;
5723 		WL_ERR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid)));
5724 	}
5725 	bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
5726 	DHD_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID));
5727 	ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
5728 	if (ret < 0) {
5729 		WL_ERR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret));
5730 	}
5731 	return 1;
5732 
5733 }
5734 
5735 static int
wl_android_set_hide_ssid(struct net_device * dev,const char * string_num)5736 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
5737 {
5738 	int hide_ssid;
5739 	int enable = 0;
5740 	int err = BCME_ERROR;
5741 
5742 	hide_ssid = bcm_atoi(string_num);
5743 	DHD_INFO(("wl_android_set_hide_ssid: HIDE_SSID = %d\n", hide_ssid));
5744 	if (hide_ssid) {
5745 		enable = 1;
5746 	}
5747 
5748 	err = wldev_iovar_setint(dev, "closednet", enable);
5749 	if (err < 0) {
5750 		WL_ERR(("failed to set closednet, error:%d\n", err));
5751 	}
5752 
5753 	return err;
5754 }
5755 #endif /* SUPPORT_HIDDEN_AP */
5756 
5757 #ifdef CUSTOMER_HW4_PRIVATE_CMD
5758 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
5759 static int
wl_android_sta_diassoc(struct net_device * dev,const char * straddr)5760 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
5761 {
5762 	scb_val_t scbval;
5763 	int error  = 0;
5764 
5765 	DHD_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr));
5766 
5767 	/* Unspecified reason */
5768 	scbval.val = htod32(1);
5769 
5770 	if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
5771 		DHD_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n"));
5772 		return -1;
5773 	}
5774 
5775 	DHD_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n",
5776 		MAC2STRDBG(scbval.ea.octet), scbval.val));
5777 
5778 	error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
5779 		sizeof(scb_val_t));
5780 	if (error) {
5781 		DHD_ERROR(("Fail to DEAUTH station, error = %d\n", error));
5782 	}
5783 
5784 	return 1;
5785 }
5786 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
5787 
5788 #ifdef SUPPORT_SET_LPC
5789 static int
wl_android_set_lpc(struct net_device * dev,const char * string_num)5790 wl_android_set_lpc(struct net_device *dev, const char* string_num)
5791 {
5792 	int lpc_enabled, ret;
5793 	s32 val = 1;
5794 
5795 	lpc_enabled = bcm_atoi(string_num);
5796 	DHD_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled));
5797 
5798 	ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
5799 	if (ret < 0)
5800 		DHD_ERROR(("WLC_DOWN error %d\n", ret));
5801 
5802 	wldev_iovar_setint(dev, "lpc", lpc_enabled);
5803 
5804 	ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
5805 	if (ret < 0)
5806 		DHD_ERROR(("WLC_UP error %d\n", ret));
5807 
5808 	return 1;
5809 }
5810 #endif /* SUPPORT_SET_LPC */
5811 
5812 static int
wl_android_ch_res_rl(struct net_device * dev,bool change)5813 wl_android_ch_res_rl(struct net_device *dev, bool change)
5814 {
5815 	int error = 0;
5816 	s32 srl = 7;
5817 	s32 lrl = 4;
5818 	printk("wl_android_ch_res_rl: enter\n");
5819 	if (change) {
5820 		srl = 4;
5821 		lrl = 2;
5822 	}
5823 
5824 	BCM_REFERENCE(lrl);
5825 
5826 	error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
5827 	if (error) {
5828 		DHD_ERROR(("Failed to set SRL, error = %d\n", error));
5829 	}
5830 #ifndef CUSTOM_LONG_RETRY_LIMIT
5831 	error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
5832 	if (error) {
5833 		DHD_ERROR(("Failed to set LRL, error = %d\n", error));
5834 	}
5835 #endif /* CUSTOM_LONG_RETRY_LIMIT */
5836 	return error;
5837 }
5838 
5839 #ifdef SUPPORT_LTECX
5840 #define DEFAULT_WLANRX_PROT	1
5841 #define DEFAULT_LTERX_PROT	0
5842 #define DEFAULT_LTETX_ADV	1200
5843 
5844 static int
wl_android_set_ltecx(struct net_device * dev,const char * string_num)5845 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
5846 {
5847 	uint16 chan_bitmap;
5848 	int ret;
5849 
5850 	chan_bitmap = bcm_strtoul(string_num, NULL, 16);
5851 
5852 	DHD_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap));
5853 
5854 	if (chan_bitmap) {
5855 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
5856 		if (ret < 0) {
5857 			DHD_ERROR(("mws_coex_bitmap error %d\n", ret));
5858 		}
5859 
5860 		ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
5861 		if (ret < 0) {
5862 			DHD_ERROR(("mws_wlanrx_prot error %d\n", ret));
5863 		}
5864 
5865 		ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
5866 		if (ret < 0) {
5867 			DHD_ERROR(("mws_lterx_prot error %d\n", ret));
5868 		}
5869 
5870 		ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
5871 		if (ret < 0) {
5872 			DHD_ERROR(("mws_ltetx_adv error %d\n", ret));
5873 		}
5874 	} else {
5875 		ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
5876 		if (ret < 0) {
5877 			if (ret == BCME_UNSUPPORTED) {
5878 				DHD_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
5879 			} else {
5880 				DHD_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
5881 			}
5882 		}
5883 	}
5884 	return 1;
5885 }
5886 #endif /* SUPPORT_LTECX */
5887 
5888 #ifdef WL_RELMCAST
5889 static int
wl_android_rmc_enable(struct net_device * net,int rmc_enable)5890 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
5891 {
5892 	int err;
5893 
5894 	err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
5895 	if (err != BCME_OK) {
5896 		DHD_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err));
5897 	}
5898 	return err;
5899 }
5900 
5901 static int
wl_android_rmc_set_leader(struct net_device * dev,const char * straddr)5902 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
5903 {
5904 	int error  = BCME_OK;
5905 	char smbuf[WLC_IOCTL_SMLEN];
5906 	wl_rmc_entry_t rmc_entry;
5907 	DHD_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr));
5908 
5909 	bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
5910 	if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
5911 		if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
5912 			DHD_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n"));
5913 			bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
5914 		} else {
5915 			DHD_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n"));
5916 			return BCME_ERROR;
5917 		}
5918 	}
5919 
5920 	error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
5921 		smbuf, sizeof(smbuf), NULL);
5922 
5923 	if (error != BCME_OK) {
5924 		DHD_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n",
5925 			error));
5926 	}
5927 
5928 	return error;
5929 }
5930 
wl_android_set_rmc_event(struct net_device * dev,char * command)5931 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
5932 {
5933 	int err = 0;
5934 	int pid = 0;
5935 
5936 	if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
5937 		WL_ERR(("Failed to get Parameter from : %s\n", command));
5938 		return -1;
5939 	}
5940 
5941 	/* set pid, and if the event was happened, let's send a notification through netlink */
5942 	wl_cfg80211_set_rmc_pid(dev, pid);
5943 
5944 	WL_DBG(("RMC pid=%d\n", pid));
5945 
5946 	return err;
5947 }
5948 #endif /* WL_RELMCAST */
5949 
wl_android_get_singlecore_scan(struct net_device * dev,char * command,int total_len)5950 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
5951 {
5952 	int error = 0;
5953 	int bytes_written = 0;
5954 	int mode = 0;
5955 
5956 	error = wldev_iovar_getint(dev, "scan_ps", &mode);
5957 	if (error) {
5958 		DHD_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode,"
5959 			" error = %d\n",
5960 			error));
5961 		return -1;
5962 	}
5963 
5964 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
5965 
5966 	return bytes_written;
5967 }
5968 
wl_android_set_singlecore_scan(struct net_device * dev,char * command)5969 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
5970 {
5971 	int error = 0;
5972 	int mode = 0;
5973 
5974 	if (sscanf(command, "%*s %d", &mode) != 1) {
5975 		DHD_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n"));
5976 		return -1;
5977 	}
5978 
5979 	error = wldev_iovar_setint(dev, "scan_ps", mode);
5980 	if (error) {
5981 		DHD_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n",
5982 		mode, error));
5983 		return -1;
5984 	}
5985 
5986 	return error;
5987 }
5988 #ifdef TEST_TX_POWER_CONTROL
5989 static int
wl_android_set_tx_power(struct net_device * dev,const char * string_num)5990 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
5991 {
5992 	int err = 0;
5993 	s32 dbm;
5994 	enum nl80211_tx_power_setting type;
5995 
5996 	dbm = bcm_atoi(string_num);
5997 
5998 	if (dbm < -1) {
5999 		DHD_ERROR(("wl_android_set_tx_power: dbm is negative...\n"));
6000 		return -EINVAL;
6001 	}
6002 
6003 	if (dbm == -1)
6004 		type = NL80211_TX_POWER_AUTOMATIC;
6005 	else
6006 		type = NL80211_TX_POWER_FIXED;
6007 
6008 	err = wl_set_tx_power(dev, type, dbm);
6009 	if (unlikely(err)) {
6010 		DHD_ERROR(("wl_android_set_tx_power: error (%d)\n", err));
6011 		return err;
6012 	}
6013 
6014 	return 1;
6015 }
6016 
6017 static int
wl_android_get_tx_power(struct net_device * dev,char * command,int total_len)6018 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
6019 {
6020 	int err;
6021 	int bytes_written;
6022 	s32 dbm = 0;
6023 
6024 	err = wl_get_tx_power(dev, &dbm);
6025 	if (unlikely(err)) {
6026 		DHD_ERROR(("wl_android_get_tx_power: error (%d)\n", err));
6027 		return err;
6028 	}
6029 
6030 	bytes_written = snprintf(command, total_len, "%s %d",
6031 		CMD_TEST_GET_TX_POWER, dbm);
6032 
6033 	DHD_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm));
6034 
6035 	return bytes_written;
6036 }
6037 #endif /* TEST_TX_POWER_CONTROL */
6038 
6039 static int
wl_android_set_sarlimit_txctrl(struct net_device * dev,const char * string_num)6040 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
6041 {
6042 	int err = BCME_ERROR;
6043 	int setval = 0;
6044 	s32 mode = bcm_atoi(string_num);
6045 	s32 mode_bit = 0;
6046 	int enab = 0;
6047 
6048 	/* As Samsung specific and their requirement,
6049 	 * the mode set as the following form.
6050 	 * -1 : HEAD SAR disabled
6051 	 *  0 : HEAD SAR enabled
6052 	 *  1 : GRIP SAR disabled
6053 	 *  2 : GRIP SAR enabled
6054 	 *  3 : NR mmWave SAR disabled
6055 	 *  4 : NR mmWave SAR enabled
6056 	 *  5 : NR Sub6 SAR disabled
6057 	 *  6 : NR Sub6 SAR enabled
6058 	 *  7 : SAR BACKOFF disabled all
6059 	 * The 'SAR BACKOFF disabled all' index should be the end of the mode.
6060 	 */
6061 	if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) {
6062 		DHD_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num)));
6063 		err = BCME_RANGE;
6064 		goto error;
6065 	}
6066 
6067 	mode_bit = mode + 1;
6068 	enab = mode_bit % 2;
6069 	mode_bit = mode_bit / 2;
6070 
6071 	err = wldev_iovar_getint(dev, "sar_enable", &setval);
6072 	if (unlikely(err)) {
6073 		DHD_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err));
6074 		goto error;
6075 	}
6076 
6077 	if (mode == SAR_BACKOFF_DISABLE_ALL) {
6078 		DHD_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__));
6079 		setval = 0;
6080 	} else {
6081 		DHD_ERROR(("%s: SAR limit control mode %d enab %d\n",
6082 			__FUNCTION__, mode_bit, enab));
6083 		if (enab) {
6084 			setval |= (1 << mode_bit);
6085 		} else {
6086 			setval &= ~(1 << mode_bit);
6087 		}
6088 	}
6089 
6090 	err = wldev_iovar_setint(dev, "sar_enable", setval);
6091 	if (unlikely(err)) {
6092 		DHD_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
6093 		goto error;
6094 	}
6095 error:
6096 	return err;
6097 }
6098 
6099 #ifdef SUPPORT_SET_TID
6100 static int
wl_android_set_tid(struct net_device * dev,char * command)6101 wl_android_set_tid(struct net_device *dev, char* command)
6102 {
6103 	int err = BCME_ERROR;
6104 	char *pos = command;
6105 	char *token = NULL;
6106 	uint8 mode = 0;
6107 	uint32 uid = 0;
6108 	uint8 prio = 0;
6109 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6110 
6111 	if (!dhdp) {
6112 		WL_ERR(("dhd is NULL\n"));
6113 		return err;
6114 	}
6115 
6116 	WL_DBG(("%s: command[%s]\n", __FUNCTION__, command));
6117 
6118 	/* drop command */
6119 	token = bcmstrtok(&pos, " ", NULL);
6120 
6121 	token = bcmstrtok(&pos, " ", NULL);
6122 	if (!token) {
6123 		WL_ERR(("Invalid arguments\n"));
6124 		return err;
6125 	}
6126 
6127 	mode = bcm_atoi(token);
6128 
6129 	if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
6130 		WL_ERR(("Invalid arguments, mode %d\n", mode));
6131 			return err;
6132 	}
6133 
6134 	if (mode) {
6135 		token = bcmstrtok(&pos, " ", NULL);
6136 		if (!token) {
6137 			WL_ERR(("Invalid arguments for target uid\n"));
6138 			return err;
6139 		}
6140 
6141 		uid = bcm_atoi(token);
6142 
6143 		token = bcmstrtok(&pos, " ", NULL);
6144 		if (!token) {
6145 			WL_ERR(("Invalid arguments for target tid\n"));
6146 			return err;
6147 		}
6148 
6149 		prio = bcm_atoi(token);
6150 		if (prio >= 0 && prio <= MAXPRIO) {
6151 			dhdp->tid_mode = mode;
6152 			dhdp->target_uid = uid;
6153 			dhdp->target_tid = prio;
6154 		} else {
6155 			WL_ERR(("Invalid arguments, prio %d\n", prio));
6156 			return err;
6157 		}
6158 	} else {
6159 		dhdp->tid_mode = SET_TID_OFF;
6160 		dhdp->target_uid = 0;
6161 		dhdp->target_tid = 0;
6162 	}
6163 
6164 	WL_DBG(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
6165 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
6166 
6167 	err = BCME_OK;
6168 	return err;
6169 }
6170 
6171 static int
wl_android_get_tid(struct net_device * dev,char * command,int total_len)6172 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
6173 {
6174 	int bytes_written = BCME_ERROR;
6175 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
6176 
6177 	if (!dhdp) {
6178 		WL_ERR(("dhd is NULL\n"));
6179 		return bytes_written;
6180 	}
6181 
6182 	bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
6183 		dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
6184 
6185 	WL_DBG(("%s: command results %s\n", __FUNCTION__, command));
6186 
6187 	return bytes_written;
6188 }
6189 #endif /* SUPPORT_SET_TID */
6190 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
6191 
wl_android_set_roam_mode(struct net_device * dev,char * command)6192 int wl_android_set_roam_mode(struct net_device *dev, char *command)
6193 {
6194 	int error = 0;
6195 	int mode = 0;
6196 
6197 	if (sscanf(command, "%*s %d", &mode) != 1) {
6198 		DHD_ERROR(("wl_android_set_roam_mode: Failed to get Parameter\n"));
6199 		return -1;
6200 	}
6201 
6202 	error = wldev_iovar_setint(dev, "roam_off", mode);
6203 	if (error) {
6204 		DHD_ERROR(("wl_android_set_roam_mode: Failed to set roaming Mode %d, error = %d\n",
6205 		mode, error));
6206 		return -1;
6207 	}
6208 	else
6209 		DHD_ERROR(("wl_android_set_roam_mode: succeeded to set roaming Mode %d,"
6210 		" error = %d\n",
6211 		mode, error));
6212 	return 0;
6213 }
6214 
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)6215 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
6216 {
6217 	char ie_buf[VNDR_IE_MAX_LEN];
6218 	char *ioctl_buf = NULL;
6219 	char hex[] = "XX";
6220 	char *pcmd = NULL;
6221 	int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
6222 	vndr_ie_setbuf_t *vndr_ie = NULL;
6223 	s32 iecount;
6224 	uint32 pktflag;
6225 	s32 err = BCME_OK, bssidx;
6226 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6227 
6228 	/* Check the VSIE (Vendor Specific IE) which was added.
6229 	 *  If exist then send IOVAR to delete it
6230 	 */
6231 	if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
6232 		return -EINVAL;
6233 	}
6234 
6235 	if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
6236 		WL_ERR(("error. total_len:%d\n", total_len));
6237 		return -EINVAL;
6238 	}
6239 
6240 	pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
6241 	for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
6242 		if (*pcmd == '\0') {
6243 			WL_ERR(("error while parsing OUI.\n"));
6244 			return -EINVAL;
6245 		}
6246 		hex[0] = *pcmd++;
6247 		hex[1] = *pcmd++;
6248 		ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
6249 	}
6250 	pcmd++;
6251 	while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
6252 		hex[0] = *pcmd++;
6253 		hex[1] = *pcmd++;
6254 		ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
6255 		datalen++;
6256 	}
6257 
6258 	if (datalen <= 0) {
6259 		WL_ERR(("error. vndr ie len:%d\n", datalen));
6260 		return -EINVAL;
6261 	}
6262 
6263 	tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
6264 	vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
6265 	if (!vndr_ie) {
6266 		WL_ERR(("IE memory alloc failed\n"));
6267 		return -ENOMEM;
6268 	}
6269 	/* Copy the vndr_ie SET command ("add"/"del") to the buffer */
6270 	strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
6271 
6272 	/* Set the IE count - the buffer contains only 1 IE */
6273 	iecount = htod32(1);
6274 	memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
6275 
6276 	/* Set packet flag to indicate that BEACON's will contain this IE */
6277 	pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
6278 	memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
6279 		sizeof(u32));
6280 	/* Set the IE ID */
6281 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
6282 
6283 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
6284 		DOT11_OUI_LEN);
6285 	memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
6286 		&ie_buf[DOT11_OUI_LEN], datalen);
6287 
6288 	ielen = DOT11_OUI_LEN + datalen;
6289 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
6290 
6291 	ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
6292 	if (!ioctl_buf) {
6293 		WL_ERR(("ioctl memory alloc failed\n"));
6294 		if (vndr_ie) {
6295 			MFREE(cfg->osh, vndr_ie, tot_len);
6296 		}
6297 		return -ENOMEM;
6298 	}
6299 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);	/* init the buffer */
6300 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
6301 		WL_ERR(("Find index failed\n"));
6302 		err = BCME_ERROR;
6303 		goto end;
6304 	}
6305 	err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
6306 			WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
6307 end:
6308 	if (err != BCME_OK) {
6309 		err = -EINVAL;
6310 		if (vndr_ie) {
6311 			MFREE(cfg->osh, vndr_ie, tot_len);
6312 		}
6313 	}
6314 	else {
6315 		/* do NOT free 'vndr_ie' for the next process */
6316 		wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
6317 	}
6318 
6319 	if (ioctl_buf) {
6320 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
6321 	}
6322 
6323 	return err;
6324 }
6325 
6326 #if defined(BCMFW_ROAM_ENABLE)
6327 static int
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)6328 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
6329 {
6330 	int error = 0;
6331 	char smbuf[WLC_IOCTL_SMLEN];
6332 	uint8 buf[MAX_BUF_SIZE];
6333 	uint8 *pref = buf;
6334 	char *pcmd;
6335 	int num_ucipher_suites = 0;
6336 	int num_akm_suites = 0;
6337 	wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
6338 	wpa_suite_t akm_suites[MAX_NUM_SUITES];
6339 	int num_tuples = 0;
6340 	int total_bytes = 0;
6341 	int total_len_left;
6342 	int i, j;
6343 	char hex[] = "XX";
6344 
6345 	pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
6346 	total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
6347 
6348 	num_akm_suites = simple_strtoul(pcmd, NULL, 16);
6349 	if (num_akm_suites > MAX_NUM_SUITES) {
6350 		DHD_ERROR(("too many AKM suites = %d\n", num_akm_suites));
6351 		return -1;
6352 	}
6353 
6354 	/* Increment for number of AKM suites field + space */
6355 	pcmd += 3;
6356 	total_len_left -= 3;
6357 
6358 	/* check to make sure pcmd does not overrun */
6359 	if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
6360 		return -1;
6361 
6362 	bzero(buf, sizeof(buf));
6363 	bzero(akm_suites, sizeof(akm_suites));
6364 	bzero(ucipher_suites, sizeof(ucipher_suites));
6365 
6366 	/* Save the AKM suites passed in the command */
6367 	for (i = 0; i < num_akm_suites; i++) {
6368 		/* Store the MSB first, as required by join_pref */
6369 		for (j = 0; j < 4; j++) {
6370 			hex[0] = *pcmd++;
6371 			hex[1] = *pcmd++;
6372 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
6373 		}
6374 		memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
6375 	}
6376 
6377 	total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
6378 	num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
6379 	/* Increment for number of cipher suites field + space */
6380 	pcmd += 3;
6381 	total_len_left -= 3;
6382 
6383 	if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
6384 		return -1;
6385 
6386 	/* Save the cipher suites passed in the command */
6387 	for (i = 0; i < num_ucipher_suites; i++) {
6388 		/* Store the MSB first, as required by join_pref */
6389 		for (j = 0; j < 4; j++) {
6390 			hex[0] = *pcmd++;
6391 			hex[1] = *pcmd++;
6392 			buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
6393 		}
6394 		memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
6395 	}
6396 
6397 	/* Join preference for RSSI
6398 	 * Type	  : 1 byte (0x01)
6399 	 * Length : 1 byte (0x02)
6400 	 * Value  : 2 bytes	(reserved)
6401 	 */
6402 	*pref++ = WL_JOIN_PREF_RSSI;
6403 	*pref++ = JOIN_PREF_RSSI_LEN;
6404 	*pref++ = 0;
6405 	*pref++ = 0;
6406 
6407 	/* Join preference for WPA
6408 	 * Type	  : 1 byte (0x02)
6409 	 * Length : 1 byte (not used)
6410 	 * Value  : (variable length)
6411 	 *		reserved: 1 byte
6412 	 *      count	: 1 byte (no of tuples)
6413 	 *		Tuple1	: 12 bytes
6414 	 *			akm[4]
6415 	 *			ucipher[4]
6416 	 *			mcipher[4]
6417 	 *		Tuple2	: 12 bytes
6418 	 *		Tuplen	: 12 bytes
6419 	 */
6420 	num_tuples = num_akm_suites * num_ucipher_suites;
6421 	if (num_tuples != 0) {
6422 		if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
6423 			*pref++ = WL_JOIN_PREF_WPA;
6424 			*pref++ = 0;
6425 			*pref++ = 0;
6426 			*pref++ = (uint8)num_tuples;
6427 			total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
6428 				(JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
6429 		} else {
6430 			DHD_ERROR(("wl_android_set_roampref: Too many wpa configs"
6431 				" for join_pref \n"));
6432 			return -1;
6433 		}
6434 	} else {
6435 		/* No WPA config, configure only RSSI preference */
6436 		total_bytes = JOIN_PREF_RSSI_SIZE;
6437 	}
6438 
6439 	/* akm-ucipher-mcipher tuples in the format required for join_pref */
6440 	for (i = 0; i < num_ucipher_suites; i++) {
6441 		for (j = 0; j < num_akm_suites; j++) {
6442 			memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
6443 			pref += WPA_SUITE_LEN;
6444 			memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
6445 			pref += WPA_SUITE_LEN;
6446 			/* Set to 0 to match any available multicast cipher */
6447 			bzero(pref, WPA_SUITE_LEN);
6448 			pref += WPA_SUITE_LEN;
6449 		}
6450 	}
6451 
6452 	prhex("join pref", (uint8 *)buf, total_bytes);
6453 	error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
6454 	if (error) {
6455 		DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
6456 	}
6457 	return error;
6458 }
6459 #endif /* defined(BCMFW_ROAM_ENABLE */
6460 
6461 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)6462 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
6463 {
6464 	struct io_cfg *resume_cfg;
6465 	s32 ret;
6466 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6467 
6468 	resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
6469 	if (!resume_cfg)
6470 		return -ENOMEM;
6471 
6472 	if (config->iovar) {
6473 		ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
6474 		if (ret) {
6475 			DHD_ERROR(("wl_android_iolist_add: Failed to get current %s value\n",
6476 				config->iovar));
6477 			goto error;
6478 		}
6479 
6480 		ret = wldev_iovar_setint(dev, config->iovar, config->param);
6481 		if (ret) {
6482 			DHD_ERROR(("wl_android_iolist_add: Failed to set %s to %d\n",
6483 				config->iovar, config->param));
6484 			goto error;
6485 		}
6486 
6487 		resume_cfg->iovar = config->iovar;
6488 	} else {
6489 		resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
6490 		if (!resume_cfg->arg) {
6491 			ret = -ENOMEM;
6492 			goto error;
6493 		}
6494 		ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
6495 		if (ret) {
6496 			DHD_ERROR(("wl_android_iolist_add: Failed to get ioctl %d\n",
6497 				config->ioctl));
6498 			goto error;
6499 		}
6500 		ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
6501 		if (ret) {
6502 			DHD_ERROR(("wl_android_iolist_add: Failed to set %s to %d\n",
6503 				config->iovar, config->param));
6504 			goto error;
6505 		}
6506 		if (config->ioctl + 1 == WLC_SET_PM)
6507 			wl_cfg80211_update_power_mode(dev);
6508 		resume_cfg->ioctl = config->ioctl;
6509 		resume_cfg->len = config->len;
6510 	}
6511 
6512 	list_add(&resume_cfg->list, head);
6513 
6514 	return 0;
6515 error:
6516 	MFREE(cfg->osh, resume_cfg->arg, config->len);
6517 	MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
6518 	return ret;
6519 }
6520 
6521 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)6522 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
6523 {
6524 	struct io_cfg *config;
6525 	struct list_head *cur, *q;
6526 	s32 ret = 0;
6527 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6528 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
6529 	list_for_each_safe(cur, q, head) {
6530 		config = list_entry(cur, struct io_cfg, list);
6531 		GCC_DIAGNOSTIC_POP();
6532 		if (config->iovar) {
6533 			if (!ret)
6534 				ret = wldev_iovar_setint(dev, config->iovar,
6535 					config->param);
6536 		} else {
6537 			if (!ret)
6538 				ret = wldev_ioctl_set(dev, config->ioctl + 1,
6539 					config->arg, config->len);
6540 			if (config->ioctl + 1 == WLC_SET_PM)
6541 				wl_cfg80211_update_power_mode(dev);
6542 			MFREE(cfg->osh, config->arg, config->len);
6543 		}
6544 		list_del(cur);
6545 		MFREE(cfg->osh, config, sizeof(struct io_cfg));
6546 	}
6547 }
6548 static int
wl_android_set_miracast(struct net_device * dev,char * command)6549 wl_android_set_miracast(struct net_device *dev, char *command)
6550 {
6551 	int mode, val = 0;
6552 	int ret = 0;
6553 	struct io_cfg config;
6554 
6555 	if (sscanf(command, "%*s %d", &mode) != 1) {
6556 		DHD_ERROR(("wl_android_set_miracasts: Failed to get Parameter\n"));
6557 		return -1;
6558 	}
6559 
6560 	DHD_INFO(("wl_android_set_miracast: enter miracast mode %d\n", mode));
6561 
6562 	if (miracast_cur_mode == mode) {
6563 		return 0;
6564 	}
6565 
6566 	wl_android_iolist_resume(dev, &miracast_resume_list);
6567 	miracast_cur_mode = MIRACAST_MODE_OFF;
6568 
6569 	bzero((void *)&config, sizeof(config));
6570 	switch (mode) {
6571 	case MIRACAST_MODE_SOURCE:
6572 #ifdef MIRACAST_MCHAN_ALGO
6573 		/* setting mchan_algo to platform specific value */
6574 		config.iovar = "mchan_algo";
6575 
6576 		ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
6577 		if (!ret && val > 100) {
6578 			config.param = 0;
6579 			DHD_ERROR(("wl_android_set_miracast: Connected station's beacon interval: "
6580 				"%d and set mchan_algo to %d \n",
6581 				val, config.param));
6582 		} else {
6583 			config.param = MIRACAST_MCHAN_ALGO;
6584 		}
6585 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
6586 		if (ret) {
6587 			goto resume;
6588 		}
6589 #endif /* MIRACAST_MCHAN_ALGO */
6590 
6591 #ifdef MIRACAST_MCHAN_BW
6592 		/* setting mchan_bw to platform specific value */
6593 		config.iovar = "mchan_bw";
6594 		config.param = MIRACAST_MCHAN_BW;
6595 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
6596 		if (ret) {
6597 			goto resume;
6598 		}
6599 #endif /* MIRACAST_MCHAN_BW */
6600 
6601 #ifdef MIRACAST_AMPDU_SIZE
6602 		/* setting apmdu to platform specific value */
6603 		config.iovar = "ampdu_mpdu";
6604 		config.param = MIRACAST_AMPDU_SIZE;
6605 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
6606 		if (ret) {
6607 			goto resume;
6608 		}
6609 #endif /* MIRACAST_AMPDU_SIZE */
6610 
6611 		/* Source mode shares most configurations with sink mode.
6612 		 * Fall through here to avoid code duplication
6613 		 */
6614 		/* fall through */
6615 	case MIRACAST_MODE_SINK:
6616 		/* disable internal roaming */
6617 		config.iovar = "roam_off";
6618 		config.param = 1;
6619 		config.arg = NULL;
6620 		config.len = 0;
6621 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
6622 		if (ret) {
6623 			goto resume;
6624 		}
6625 
6626 		/* tunr off pm */
6627 		ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
6628 		if (ret) {
6629 			goto resume;
6630 		}
6631 
6632 		if (val != PM_OFF) {
6633 			val = PM_OFF;
6634 			config.iovar = NULL;
6635 			config.ioctl = WLC_GET_PM;
6636 			config.arg = &val;
6637 			config.len = sizeof(int);
6638 			ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
6639 			if (ret) {
6640 				goto resume;
6641 			}
6642 		}
6643 		break;
6644 	case MIRACAST_MODE_OFF:
6645 	default:
6646 		break;
6647 	}
6648 	miracast_cur_mode = mode;
6649 
6650 	return 0;
6651 
6652 resume:
6653 	DHD_ERROR(("wl_android_set_miracast: turnoff miracast mode because of err%d\n", ret));
6654 	wl_android_iolist_resume(dev, &miracast_resume_list);
6655 	return ret;
6656 }
6657 
6658 #define NETLINK_OXYGEN     30
6659 #define AIBSS_BEACON_TIMEOUT	10
6660 
6661 static struct sock *nl_sk = NULL;
6662 
wl_netlink_recv(struct sk_buff * skb)6663 static void wl_netlink_recv(struct sk_buff *skb)
6664 {
6665 	WL_ERR(("netlink_recv called\n"));
6666 }
6667 
wl_netlink_init(void)6668 static int wl_netlink_init(void)
6669 {
6670 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
6671 	struct netlink_kernel_cfg cfg = {
6672 		.input	= wl_netlink_recv,
6673 	};
6674 #endif // endif
6675 
6676 	if (nl_sk != NULL) {
6677 		WL_ERR(("nl_sk already exist\n"));
6678 		return BCME_ERROR;
6679 	}
6680 
6681 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
6682 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
6683 		0, wl_netlink_recv, NULL, THIS_MODULE);
6684 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
6685 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
6686 #else
6687 	nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
6688 #endif // endif
6689 
6690 	if (nl_sk == NULL) {
6691 		WL_ERR(("nl_sk is not ready\n"));
6692 		return BCME_ERROR;
6693 	}
6694 
6695 	return BCME_OK;
6696 }
6697 
wl_netlink_deinit(void)6698 static void wl_netlink_deinit(void)
6699 {
6700 	if (nl_sk) {
6701 		netlink_kernel_release(nl_sk);
6702 		nl_sk = NULL;
6703 	}
6704 }
6705 
6706 s32
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)6707 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
6708 {
6709 	struct sk_buff *skb = NULL;
6710 	struct nlmsghdr *nlh = NULL;
6711 	int ret = -1;
6712 
6713 	if (nl_sk == NULL) {
6714 		WL_ERR(("nl_sk was not initialized\n"));
6715 		goto nlmsg_failure;
6716 	}
6717 
6718 	skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
6719 	if (skb == NULL) {
6720 		WL_ERR(("failed to allocate memory\n"));
6721 		goto nlmsg_failure;
6722 	}
6723 
6724 	nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
6725 	if (nlh == NULL) {
6726 		WL_ERR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
6727 			skb_tailroom(skb), nlmsg_total_size(size)));
6728 		dev_kfree_skb(skb);
6729 		goto nlmsg_failure;
6730 	}
6731 
6732 	memcpy(nlmsg_data(nlh), data, size);
6733 	nlh->nlmsg_seq = seq;
6734 	nlh->nlmsg_type = type;
6735 
6736 	/* netlink_unicast() takes ownership of the skb and frees it itself. */
6737 	ret = netlink_unicast(nl_sk, skb, pid, 0);
6738 	WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
6739 
6740 nlmsg_failure:
6741 	return ret;
6742 }
6743 
6744 #ifdef WLAIBSS
wl_android_set_ibss_txfail_event(struct net_device * dev,char * command,int total_len)6745 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
6746 {
6747 	int err = 0;
6748 	int retry = 0;
6749 	int pid = 0;
6750 	aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
6751 	char smbuf[WLC_IOCTL_SMLEN];
6752 
6753 	if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
6754 		WL_ERR(("Failed to get Parameter from : %s\n", command));
6755 		return -1;
6756 	}
6757 
6758 	/* set pid, and if the event was happened, let's send a notification through netlink */
6759 	wl_cfg80211_set_txfail_pid(dev, pid);
6760 
6761 #ifdef WL_RELMCAST
6762 	/* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
6763 	wl_cfg80211_set_rmc_pid(dev, pid);
6764 #endif /* WL_RELMCAST */
6765 
6766 	/* If retry value is 0, it disables the functionality for TX Fail. */
6767 	if (retry > 0) {
6768 		txfail_config.max_tx_retry = retry;
6769 		txfail_config.bcn_timeout = 0;	/* 0 : disable tx fail from beacon */
6770 	}
6771 	txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
6772 	txfail_config.len = sizeof(txfail_config);
6773 
6774 	err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
6775 		sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
6776 	WL_DBG(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
6777 
6778 	return ((err == 0)?total_len:err);
6779 }
6780 
wl_android_get_ibss_peer_info(struct net_device * dev,char * command,int total_len,bool bAll)6781 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
6782 	int total_len, bool bAll)
6783 {
6784 	int error;
6785 	int bytes_written = 0;
6786 	void *buf = NULL;
6787 	bss_peer_list_info_t peer_list_info;
6788 	bss_peer_info_t *peer_info;
6789 	int i;
6790 	bool found = false;
6791 	struct ether_addr mac_ea;
6792 	char *str = command;
6793 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6794 
6795 	WL_DBG(("get ibss peer info(%s)\n", bAll?"true":"false"));
6796 
6797 	if (!bAll) {
6798 		if (bcmstrtok(&str, " ", NULL) == NULL) {
6799 			WL_ERR(("invalid command\n"));
6800 			return -1;
6801 		}
6802 
6803 		if (!str || !bcm_ether_atoe(str, &mac_ea)) {
6804 			WL_ERR(("invalid MAC address\n"));
6805 			return -1;
6806 		}
6807 	}
6808 
6809 	if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) {
6810 		WL_ERR(("kmalloc failed\n"));
6811 		return -1;
6812 	}
6813 
6814 	error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
6815 	if (unlikely(error)) {
6816 		WL_ERR(("could not get ibss peer info (%d)\n", error));
6817 		MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
6818 		return -1;
6819 	}
6820 
6821 	memcpy(&peer_list_info, buf, sizeof(peer_list_info));
6822 	peer_list_info.version = htod16(peer_list_info.version);
6823 	peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
6824 	peer_list_info.count = htod32(peer_list_info.count);
6825 
6826 	WL_DBG(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
6827 		peer_list_info.bss_peer_info_len, peer_list_info.count));
6828 
6829 	if (peer_list_info.count > 0) {
6830 		if (bAll)
6831 			bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
6832 				peer_list_info.count);
6833 
6834 		peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
6835 
6836 		for (i = 0; i < peer_list_info.count; i++) {
6837 
6838 			WL_DBG(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
6839 				peer_info->tx_rate, peer_info->rx_rate));
6840 
6841 			if (!bAll &&
6842 				memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
6843 				found = true;
6844 			}
6845 
6846 			if (bAll || found) {
6847 				bytes_written += snprintf(&command[bytes_written],
6848 					total_len - bytes_written,
6849 					MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
6850 					peer_info->tx_rate/1000, peer_info->rssi);
6851 				if (bytes_written >= total_len) {
6852 					WL_ERR(("wl_android_get_ibss_peer_info: Insufficient"
6853 						" memory, %d bytes\n",
6854 						total_len));
6855 					bytes_written = -1;
6856 					break;
6857 				}
6858 			}
6859 
6860 			if (found)
6861 				break;
6862 
6863 			peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
6864 		}
6865 	}
6866 	else {
6867 		WL_ERR(("could not get ibss peer info : no item\n"));
6868 	}
6869 	WL_DBG(("command(%u):%s\n", total_len, command));
6870 	WL_DBG(("bytes_written:%d\n", bytes_written));
6871 
6872 	MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
6873 	return bytes_written;
6874 }
6875 
wl_android_set_ibss_routetable(struct net_device * dev,char * command)6876 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
6877 {
6878 
6879 	char *pcmd = command;
6880 	char *str = NULL;
6881 	ibss_route_tbl_t *route_tbl = NULL;
6882 	char *ioctl_buf = NULL;
6883 	s32 err = BCME_OK;
6884 	uint32 route_tbl_len;
6885 	uint32 entries;
6886 	char *endptr;
6887 	uint32 i = 0;
6888 	struct ipv4_addr  dipaddr;
6889 	struct ether_addr ea;
6890 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6891 
6892 	route_tbl_len = sizeof(ibss_route_tbl_t) +
6893 		(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
6894 	route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
6895 	if (!route_tbl) {
6896 		WL_ERR(("Route TBL alloc failed\n"));
6897 		return -ENOMEM;
6898 	}
6899 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
6900 	if (!ioctl_buf) {
6901 		WL_ERR(("ioctl memory alloc failed\n"));
6902 		if (route_tbl) {
6903 			MFREE(cfg->osh, route_tbl, route_tbl_len);
6904 		}
6905 		return -ENOMEM;
6906 	}
6907 	bzero(ioctl_buf, WLC_IOCTL_MEDLEN);
6908 
6909 	/* drop command */
6910 	str = bcmstrtok(&pcmd, " ", NULL);
6911 
6912 	/* get count */
6913 	str = bcmstrtok(&pcmd, " ",  NULL);
6914 	if (!str) {
6915 		WL_ERR(("Invalid number parameter %s\n", str));
6916 		err = -EINVAL;
6917 		goto exit;
6918 	}
6919 	entries = bcm_strtoul(str, &endptr, 0);
6920 	if (*endptr != '\0') {
6921 		WL_ERR(("Invalid number parameter %s\n", str));
6922 		err = -EINVAL;
6923 		goto exit;
6924 	}
6925 	if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
6926 		WL_ERR(("Invalid entries number %u\n", entries));
6927 		err = -EINVAL;
6928 		goto exit;
6929 	}
6930 
6931 	WL_INFORM(("Routing table count:%u\n", entries));
6932 	route_tbl->num_entry = entries;
6933 
6934 	for (i = 0; i < entries; i++) {
6935 		str = bcmstrtok(&pcmd, " ", NULL);
6936 		if (!str || !bcm_atoipv4(str, &dipaddr)) {
6937 			WL_ERR(("Invalid ip string %s\n", str));
6938 			err = -EINVAL;
6939 			goto exit;
6940 		}
6941 
6942 		str = bcmstrtok(&pcmd, " ", NULL);
6943 		if (!str || !bcm_ether_atoe(str, &ea)) {
6944 			WL_ERR(("Invalid ethernet string %s\n", str));
6945 			err = -EINVAL;
6946 			goto exit;
6947 		}
6948 		bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
6949 		bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
6950 	}
6951 
6952 	route_tbl_len = sizeof(ibss_route_tbl_t) +
6953 		((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
6954 	err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
6955 		route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
6956 	if (err != BCME_OK) {
6957 		WL_ERR(("Fail to set iovar %d\n", err));
6958 		err = -EINVAL;
6959 	}
6960 
6961 exit:
6962 	if (route_tbl) {
6963 		MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
6964 			(MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
6965 	}
6966 	if (ioctl_buf) {
6967 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
6968 	}
6969 	return err;
6970 
6971 }
6972 
6973 int
wl_android_set_ibss_ampdu(struct net_device * dev,char * command,int total_len)6974 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
6975 {
6976 	char *pcmd = command;
6977 	char *str = NULL, *endptr = NULL;
6978 	struct ampdu_aggr aggr;
6979 	char smbuf[WLC_IOCTL_SMLEN];
6980 	int idx;
6981 	int err = 0;
6982 	int wme_AC2PRIO[AC_COUNT][2] = {
6983 		{PRIO_8021D_VO, PRIO_8021D_NC},		/* AC_VO - 3 */
6984 		{PRIO_8021D_CL, PRIO_8021D_VI},		/* AC_VI - 2 */
6985 		{PRIO_8021D_BK, PRIO_8021D_NONE},	/* AC_BK - 1 */
6986 		{PRIO_8021D_BE, PRIO_8021D_EE}};	/* AC_BE - 0 */
6987 
6988 	WL_DBG(("set ibss ampdu:%s\n", command));
6989 
6990 	bzero(&aggr, sizeof(aggr));
6991 	/* Cofigure all priorities */
6992 	aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
6993 
6994 	/* acquire parameters */
6995 	/* drop command */
6996 	str = bcmstrtok(&pcmd, " ", NULL);
6997 
6998 	for (idx = 0; idx < AC_COUNT; idx++) {
6999 		bool on;
7000 		str = bcmstrtok(&pcmd, " ", NULL);
7001 		if (!str) {
7002 			WL_ERR(("Invalid parameter : %s\n", pcmd));
7003 			return -EINVAL;
7004 		}
7005 		on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
7006 		if (*endptr != '\0') {
7007 			WL_ERR(("Invalid number format %s\n", str));
7008 			return -EINVAL;
7009 		}
7010 		if (on) {
7011 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
7012 			setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
7013 		}
7014 	}
7015 
7016 	err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
7017 	sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
7018 
7019 	return ((err == 0) ? total_len : err);
7020 }
7021 
wl_android_set_ibss_antenna(struct net_device * dev,char * command,int total_len)7022 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
7023 {
7024 	char *pcmd = command;
7025 	char *str = NULL;
7026 	int txchain, rxchain;
7027 	int err = 0;
7028 
7029 	WL_DBG(("set ibss antenna:%s\n", command));
7030 
7031 	/* acquire parameters */
7032 	/* drop command */
7033 	str = bcmstrtok(&pcmd, " ", NULL);
7034 
7035 	/* TX chain */
7036 	str = bcmstrtok(&pcmd, " ", NULL);
7037 	if (!str) {
7038 		WL_ERR(("Invalid parameter : %s\n", pcmd));
7039 		return -EINVAL;
7040 	}
7041 	txchain = bcm_atoi(str);
7042 
7043 	/* RX chain */
7044 	str = bcmstrtok(&pcmd, " ", NULL);
7045 	if (!str) {
7046 		WL_ERR(("Invalid parameter : %s\n", pcmd));
7047 		return -EINVAL;
7048 	}
7049 	rxchain = bcm_atoi(str);
7050 
7051 	err = wldev_iovar_setint(dev, "txchain", txchain);
7052 	if (err != 0)
7053 		return err;
7054 	err = wldev_iovar_setint(dev, "rxchain", rxchain);
7055 	return ((err == 0)?total_len:err);
7056 }
7057 #endif /* WLAIBSS */
7058 
wl_keep_alive_set(struct net_device * dev,char * extra)7059 int wl_keep_alive_set(struct net_device *dev, char* extra)
7060 {
7061 	wl_mkeep_alive_pkt_t	mkeep_alive_pkt;
7062 	int ret;
7063 	uint period_msec = 0;
7064 	char *buf;
7065 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7066 
7067 	if (extra == NULL) {
7068 		 DHD_ERROR(("wl_keep_alive_set: extra is NULL\n"));
7069 		 return -1;
7070 	}
7071 	if (sscanf(extra, "%d", &period_msec) != 1) {
7072 		 DHD_ERROR(("wl_keep_alive_set: sscanf error. check period_msec value\n"));
7073 		 return -EINVAL;
7074 	}
7075 	DHD_ERROR(("wl_keep_alive_set: period_msec is %d\n", period_msec));
7076 
7077 	bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
7078 
7079 	mkeep_alive_pkt.period_msec = period_msec;
7080 	mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
7081 	mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
7082 
7083 	/* Setup keep alive zero for null packet generation */
7084 	mkeep_alive_pkt.keep_alive_id = 0;
7085 	mkeep_alive_pkt.len_bytes = 0;
7086 
7087 	buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_SMLEN);
7088 	if (!buf) {
7089 		DHD_ERROR(("wl_keep_alive_set: buffer alloc failed\n"));
7090 		return BCME_NOMEM;
7091 	}
7092 	ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
7093 			WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
7094 	if (ret < 0)
7095 		DHD_ERROR(("wl_keep_alive_set:keep_alive set failed:%d\n", ret));
7096 	else
7097 		DHD_TRACE(("wl_keep_alive_set: keep_alive set ok\n"));
7098 	MFREE(cfg->osh, buf, WLC_IOCTL_SMLEN);
7099 	return ret;
7100 }
7101 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)7102 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
7103 {
7104 	int error = 0;
7105 	int bytes_written = 0;
7106 	int only_resp_wfdsrc = 0;
7107 
7108 	error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
7109 	if (error) {
7110 		DHD_ERROR(("wl_android_get_wfdie_resp: Failed to get the mode"
7111 			" for only_resp_wfdsrc, error = %d\n",
7112 			error));
7113 		return -1;
7114 	}
7115 
7116 	bytes_written = snprintf(command, total_len, "%s %d",
7117 		CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
7118 
7119 	return bytes_written;
7120 }
7121 
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)7122 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
7123 {
7124 	int error = 0;
7125 
7126 	error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
7127 	if (error) {
7128 		DHD_ERROR(("wl_android_set_wfdie_resp: Failed to set only_resp_wfdsrc %d,"
7129 			" error = %d\n",
7130 			only_resp_wfdsrc, error));
7131 		return -1;
7132 	}
7133 
7134 	return 0;
7135 }
7136 #endif /* P2PRESP_WFDIE_SRC */
7137 
7138 #ifdef BT_WIFI_HANDOVER
7139 static int
wl_tbow_teardown(struct net_device * dev)7140 wl_tbow_teardown(struct net_device *dev)
7141 {
7142 	int err = BCME_OK;
7143 	char buf[WLC_IOCTL_SMLEN];
7144 	tbow_setup_netinfo_t netinfo;
7145 	bzero(&netinfo, sizeof(netinfo));
7146 	netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
7147 
7148 	err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
7149 			sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
7150 	if (err < 0) {
7151 		WL_ERR(("tbow_doho iovar error %d\n", err));
7152 		return err;
7153 	}
7154 	return err;
7155 }
7156 #endif /* BT_WIFI_HANOVER */
7157 
7158 #ifdef SET_RPS_CPUS
7159 static int
wl_android_set_rps_cpus(struct net_device * dev,char * command)7160 wl_android_set_rps_cpus(struct net_device *dev, char *command)
7161 {
7162 	int error, enable;
7163 
7164 	enable = command[strlen(CMD_RPSMODE) + 1] - '0';
7165 	error = dhd_rps_cpus_enable(dev, enable);
7166 
7167 #if defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE) && defined(WL_CFG80211)
7168 	if (!error) {
7169 		void *dhdp = wl_cfg80211_get_dhdp(net);
7170 		if (enable) {
7171 			DHD_TRACE(("wl_android_set_rps_cpus: set ack suppress."
7172 			" TCPACK_SUP_HOLD.\n"));
7173 			dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD);
7174 		} else {
7175 			DHD_TRACE(("wl_android_set_rps_cpus: clear ack suppress.\n"));
7176 			dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
7177 		}
7178 	}
7179 #endif /* DHDTCPACK_SUPPRESS && BCMPCIE && WL_CFG80211 */
7180 
7181 	return error;
7182 }
7183 #endif /* SET_RPS_CPUS */
7184 
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)7185 static int wl_android_get_link_status(struct net_device *dev, char *command,
7186 	int total_len)
7187 {
7188 	int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
7189 	uint32 rspec;
7190 	uint encode, txexp;
7191 	wl_bss_info_t *bi;
7192 	int datalen;
7193 	char buf[sizeof(uint32) + sizeof(wl_bss_info_t)];
7194 
7195 	datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
7196 
7197 	bzero(buf, datalen);
7198 	/* get BSS information */
7199 	*(u32 *) buf = htod32(datalen);
7200 	error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
7201 	if (unlikely(error)) {
7202 		WL_ERR(("Could not get bss info %d\n", error));
7203 		return -1;
7204 	}
7205 
7206 	bi = (wl_bss_info_t*) (buf + sizeof(uint32));
7207 
7208 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
7209 		if (bi->BSSID.octet[i] > 0) {
7210 			break;
7211 		}
7212 	}
7213 
7214 	if (i == ETHER_ADDR_LEN) {
7215 		WL_DBG(("No BSSID\n"));
7216 		return -1;
7217 	}
7218 
7219 	/* check VHT capability at beacon */
7220 	if (bi->vht_cap) {
7221 		if (CHSPEC_IS5G(bi->chanspec)) {
7222 			result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
7223 		}
7224 	}
7225 
7226 	/* get a rspec (radio spectrum) rate */
7227 	error = wldev_iovar_getint(dev, "nrate", &rspec);
7228 	if (unlikely(error) || rspec == 0) {
7229 		WL_ERR(("get link status error (%d)\n", error));
7230 		return -1;
7231 	}
7232 
7233 	encode = (rspec & WL_RSPEC_ENCODING_MASK);
7234 	txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
7235 
7236 	switch (encode) {
7237 	case WL_RSPEC_ENCODE_HT:
7238 		/* check Rx MCS Map for HT */
7239 		for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
7240 			int8 bitmap = 0xFF;
7241 			if (i == MAX_STREAMS_SUPPORTED-1) {
7242 				bitmap = 0x7F;
7243 			}
7244 			if (bi->basic_mcs[i] & bitmap) {
7245 				nss++;
7246 			}
7247 		}
7248 		break;
7249 	case WL_RSPEC_ENCODE_VHT:
7250 		/* check Rx MCS Map for VHT */
7251 		for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
7252 			mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
7253 			if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
7254 				nss++;
7255 			}
7256 		}
7257 		break;
7258 	}
7259 
7260 	/* check MIMO capability with nss in beacon */
7261 	if (nss > 1) {
7262 		result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
7263 	}
7264 
7265 	single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
7266 		((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
7267 		((encode == WL_RSPEC_ENCODE_VHT) &&
7268 		((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
7269 
7270 	if (txexp == 0) {
7271 		if ((rspec & WL_RSPEC_STBC) && single_stream) {
7272 			stf = OLD_NRATE_STF_STBC;
7273 		} else {
7274 			stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
7275 		}
7276 	} else if (txexp == 1 && single_stream) {
7277 		stf = OLD_NRATE_STF_CDD;
7278 	}
7279 
7280 	/* check 11ac (VHT) */
7281 	if (encode == WL_RSPEC_ENCODE_VHT) {
7282 		if (CHSPEC_IS5G(bi->chanspec)) {
7283 			result |= WL_ANDROID_LINK_VHT;
7284 		}
7285 	}
7286 
7287 	/* check MIMO */
7288 	if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
7289 		switch (stf) {
7290 		case OLD_NRATE_STF_SISO:
7291 			break;
7292 		case OLD_NRATE_STF_CDD:
7293 		case OLD_NRATE_STF_STBC:
7294 			result |= WL_ANDROID_LINK_MIMO;
7295 			break;
7296 		case OLD_NRATE_STF_SDM:
7297 			if (!single_stream) {
7298 				result |= WL_ANDROID_LINK_MIMO;
7299 			}
7300 			break;
7301 		}
7302 	}
7303 
7304 	WL_DBG(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
7305 		__FUNCTION__, result, stf, single_stream, nss));
7306 
7307 	bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
7308 
7309 	return bytes_written;
7310 }
7311 
7312 #ifdef P2P_LISTEN_OFFLOADING
7313 
7314 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 * cfg)7315 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
7316 {
7317 	s32 bssidx;
7318 	int ret = 0;
7319 	int p2plo_pause = 0;
7320 	dhd_pub_t *dhd = NULL;
7321 	if (!cfg || !cfg->p2p) {
7322 		WL_ERR(("Wl %p or cfg->p2p %p is null\n",
7323 			cfg, cfg ? cfg->p2p : 0));
7324 		return 0;
7325 	}
7326 
7327 	dhd =  (dhd_pub_t *)(cfg->pub);
7328 	if (!dhd->up) {
7329 		WL_ERR(("bus is already down\n"));
7330 		return ret;
7331 	}
7332 
7333 	bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
7334 	ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
7335 			"p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
7336 			cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
7337 	if (ret < 0) {
7338 		WL_ERR(("p2po_stop Failed :%d\n", ret));
7339 	}
7340 
7341 	return  ret;
7342 }
7343 s32
wl_cfg80211_p2plo_listen_start(struct net_device * dev,u8 * buf,int len)7344 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
7345 {
7346 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7347 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
7348 	wl_p2plo_listen_t p2plo_listen;
7349 	int ret = -EAGAIN;
7350 	int channel = 0;
7351 	int period = 0;
7352 	int interval = 0;
7353 	int count = 0;
7354 	if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
7355 		WL_ERR(("Sending Action Frames. Try it again.\n"));
7356 		goto exit;
7357 	}
7358 
7359 	if (wl_get_drv_status_all(cfg, SCANNING)) {
7360 		WL_ERR(("Scanning already\n"));
7361 		goto exit;
7362 	}
7363 
7364 	if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
7365 		WL_ERR(("Scanning being aborted\n"));
7366 		goto exit;
7367 	}
7368 
7369 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
7370 		WL_ERR(("p2p listen offloading already running\n"));
7371 		goto exit;
7372 	}
7373 
7374 	/* Just in case if it is not enabled */
7375 	if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
7376 		WL_ERR(("cfgp2p_enable discovery failed"));
7377 		goto exit;
7378 	}
7379 
7380 	bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
7381 
7382 	if (len) {
7383 		sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
7384 		if ((channel == 0) || (period == 0) ||
7385 				(interval == 0) || (count == 0)) {
7386 			WL_ERR(("Wrong argument %d/%d/%d/%d \n",
7387 				channel, period, interval, count));
7388 			ret = -EAGAIN;
7389 			goto exit;
7390 		}
7391 		p2plo_listen.period = period;
7392 		p2plo_listen.interval = interval;
7393 		p2plo_listen.count = count;
7394 
7395 		WL_ERR(("channel:%d period:%d, interval:%d count:%d\n",
7396 			channel, period, interval, count));
7397 	} else {
7398 		WL_ERR(("Argument len is wrong.\n"));
7399 		ret = -EAGAIN;
7400 		goto exit;
7401 	}
7402 
7403 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
7404 			sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
7405 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
7406 		WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
7407 		goto exit;
7408 	}
7409 
7410 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
7411 			sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
7412 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
7413 		WL_ERR(("p2po_listen Failed :%d\n", ret));
7414 		goto exit;
7415 	}
7416 
7417 	wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
7418 exit :
7419 	return ret;
7420 }
7421 s32
wl_cfg80211_p2plo_listen_stop(struct net_device * dev)7422 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
7423 {
7424 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7425 	s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
7426 	int ret = -EAGAIN;
7427 
7428 	if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
7429 			0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
7430 			bssidx, &cfg->ioctl_buf_sync)) < 0) {
7431 		WL_ERR(("p2po_stop Failed :%d\n", ret));
7432 		goto exit;
7433 	}
7434 
7435 exit:
7436 	return ret;
7437 }
7438 
7439 s32
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)7440 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
7441 {
7442 	int ret = 0;
7443 
7444 	WL_ERR(("Entry cmd:%s arg_len:%d \n", cmd, len));
7445 
7446 	if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
7447 		ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
7448 	} else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
7449 		ret = wl_cfg80211_p2plo_listen_stop(dev);
7450 	} else {
7451 		WL_ERR(("Request for Unsupported CMD:%s \n", buf));
7452 		ret = -EINVAL;
7453 	}
7454 	return ret;
7455 }
7456 void
wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 * cfg)7457 wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
7458 {
7459 	struct wireless_dev *wdev;
7460 	if (!cfg) {
7461 		return;
7462 	}
7463 
7464 	wdev = bcmcfg_to_p2p_wdev(cfg);
7465 
7466 	if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
7467 		WL_INFORM_MEM(("P2P_FIND: Discovery offload is already in progress."
7468 					"it aborted\n"));
7469 		wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
7470 		if (wdev != NULL) {
7471 #if defined(WL_CFG80211_P2P_DEV_IF)
7472 			cfg80211_remain_on_channel_expired(wdev,
7473 					cfg->last_roc_id,
7474 					&cfg->remain_on_chan, GFP_KERNEL);
7475 #else
7476 			cfg80211_remain_on_channel_expired(wdev,
7477 					cfg->last_roc_id,
7478 					&cfg->remain_on_chan,
7479 					cfg->remain_on_chan_type, GFP_KERNEL);
7480 #endif /* WL_CFG80211_P2P_DEV_IF */
7481 		}
7482 		wl_cfg80211_p2plo_deinit(cfg);
7483 	}
7484 }
7485 #endif /* P2P_LISTEN_OFFLOADING */
7486 
7487 #ifdef WL_MURX
7488 int
wl_android_murx_bfe_cap(struct net_device * dev,int val)7489 wl_android_murx_bfe_cap(struct net_device *dev, int val)
7490 {
7491 	int err = BCME_OK;
7492 	int iface_count = wl_cfg80211_iface_count(dev);
7493 	struct ether_addr bssid;
7494 	wl_reassoc_params_t params;
7495 
7496 	if (iface_count > 1) {
7497 		WL_ERR(("murx_bfe_cap change is not allowed when "
7498 				"there are multiple interfaces\n"));
7499 		return -EINVAL;
7500 	}
7501 	/* Now there is only single interface */
7502 	err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
7503 	if (unlikely(err)) {
7504 		WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d,"
7505 				"error %d\n", val, err));
7506 		return err;
7507 	}
7508 
7509 	/* If successful intiate a reassoc */
7510 	bzero(&bssid, ETHER_ADDR_LEN);
7511 	if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
7512 		WL_ERR(("Failed to get bssid, error=%d\n", err));
7513 		return err;
7514 	}
7515 
7516 	bzero(&params, sizeof(wl_reassoc_params_t));
7517 	memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
7518 
7519 	if ((err = wldev_ioctl_set(dev, WLC_REASSOC, &params,
7520 		sizeof(wl_reassoc_params_t))) < 0) {
7521 		WL_ERR(("reassoc failed err:%d \n", err));
7522 	} else {
7523 		WL_DBG(("reassoc issued successfully\n"));
7524 	}
7525 
7526 	return err;
7527 }
7528 #endif /* WL_MURX */
7529 
7530 #ifdef SUPPORT_RSSI_SUM_REPORT
7531 int
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)7532 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
7533 {
7534 	wl_rssi_ant_mimo_t rssi_ant_mimo;
7535 	char *ifname = NULL;
7536 	char *peer_mac = NULL;
7537 	char *mimo_cmd = "mimo";
7538 	char *pos, *token;
7539 	int err = BCME_OK;
7540 	int bytes_written = 0;
7541 	bool mimo_rssi = FALSE;
7542 
7543 	bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
7544 	/*
7545 	 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
7546 	 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
7547 	 */
7548 	pos = command;
7549 
7550 	/* drop command */
7551 	token = bcmstrtok(&pos, " ", NULL);
7552 
7553 	/* get the interface name */
7554 	token = bcmstrtok(&pos, " ", NULL);
7555 	if (!token) {
7556 		WL_ERR(("Invalid arguments\n"));
7557 		return -EINVAL;
7558 	}
7559 	ifname = token;
7560 
7561 	/* Optional: Check the MIMO RSSI mode or peer MAC address */
7562 	token = bcmstrtok(&pos, " ", NULL);
7563 	if (token) {
7564 		/* Check the MIMO RSSI mode */
7565 		if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
7566 			mimo_rssi = TRUE;
7567 		} else {
7568 			peer_mac = token;
7569 		}
7570 	}
7571 
7572 	/* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
7573 	token = bcmstrtok(&pos, " ", NULL);
7574 	if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
7575 		mimo_rssi = TRUE;
7576 	}
7577 
7578 	err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
7579 	if (unlikely(err)) {
7580 		WL_ERR(("Failed to get RSSI info, err=%d\n", err));
7581 		return err;
7582 	}
7583 
7584 	/* Parse the results */
7585 	WL_DBG(("ifname %s, version %d, count %d, mimo rssi %d\n",
7586 		ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
7587 	if (mimo_rssi) {
7588 		WL_DBG(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
7589 		bytes_written = snprintf(command, total_len, "%s MIMO %d",
7590 			CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
7591 	} else {
7592 		int cnt;
7593 		bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
7594 		for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
7595 			WL_DBG(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
7596 			bytes_written = snprintf(command, total_len, "%d ",
7597 				rssi_ant_mimo.rssi_ant[cnt]);
7598 		}
7599 	}
7600 
7601 	return bytes_written;
7602 }
7603 
7604 int
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)7605 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
7606 {
7607 	rssilog_set_param_t set_param;
7608 	char *pos, *token;
7609 	int err = BCME_OK;
7610 
7611 	bzero(&set_param, sizeof(rssilog_set_param_t));
7612 	/*
7613 	 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
7614 	 */
7615 	pos = command;
7616 
7617 	/* drop command */
7618 	token = bcmstrtok(&pos, " ", NULL);
7619 
7620 	/* enable/disable */
7621 	token = bcmstrtok(&pos, " ", NULL);
7622 	if (!token) {
7623 		WL_ERR(("Invalid arguments\n"));
7624 		return -EINVAL;
7625 	}
7626 	set_param.enable = bcm_atoi(token);
7627 
7628 	/* RSSI Threshold */
7629 	token = bcmstrtok(&pos, " ", NULL);
7630 	if (!token) {
7631 		WL_ERR(("Invalid arguments\n"));
7632 		return -EINVAL;
7633 	}
7634 	set_param.rssi_threshold = bcm_atoi(token);
7635 
7636 	/* Time Threshold */
7637 	token = bcmstrtok(&pos, " ", NULL);
7638 	if (!token) {
7639 		WL_ERR(("Invalid arguments\n"));
7640 		return -EINVAL;
7641 	}
7642 	set_param.time_threshold = bcm_atoi(token);
7643 
7644 	WL_DBG(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
7645 		set_param.rssi_threshold, set_param.time_threshold));
7646 
7647 	err = wl_set_rssi_logging(dev, (void *)&set_param);
7648 	if (unlikely(err)) {
7649 		WL_ERR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
7650 			" Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
7651 			set_param.time_threshold));
7652 	}
7653 
7654 	return err;
7655 }
7656 
7657 int
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)7658 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
7659 {
7660 	rssilog_get_param_t get_param;
7661 	int err = BCME_OK;
7662 	int bytes_written = 0;
7663 
7664 	err = wl_get_rssi_logging(dev, (void *)&get_param);
7665 	if (unlikely(err)) {
7666 		WL_ERR(("Failed to get RSSI logging info\n"));
7667 		return BCME_ERROR;
7668 	}
7669 
7670 	WL_DBG(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
7671 		get_param.report_count, get_param.enable, get_param.rssi_threshold,
7672 		get_param.time_threshold));
7673 
7674 	/* Parse the parameter */
7675 	if (!get_param.enable) {
7676 		WL_DBG(("RSSI LOGGING: Feature is disables\n"));
7677 		bytes_written = snprintf(command, total_len,
7678 			"%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
7679 	} else if (get_param.enable &
7680 		(RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
7681 		if (!get_param.report_count) {
7682 			WL_DBG(("[PASS] RSSI difference across antennas is within"
7683 				" threshold limits\n"));
7684 			bytes_written = snprintf(command, total_len, "%s PASS\n",
7685 				CMD_GET_RSSI_LOGGING);
7686 		} else {
7687 			WL_DBG(("[FAIL] RSSI difference across antennas found "
7688 				"to be greater than %3d dB\n", get_param.rssi_threshold));
7689 			WL_DBG(("[FAIL] RSSI difference check have failed for "
7690 				"%d out of %d times\n", get_param.report_count,
7691 				get_param.time_threshold));
7692 			WL_DBG(("[FAIL] RSSI difference is being monitored once "
7693 				"per second, for a %d secs window\n", get_param.time_threshold));
7694 			bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
7695 				"%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
7696 				get_param.rssi_threshold, get_param.report_count,
7697 				get_param.time_threshold);
7698 		}
7699 	} else {
7700 		WL_DBG(("[BUSY] Reprot is not ready\n"));
7701 		bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
7702 			CMD_GET_RSSI_LOGGING);
7703 	}
7704 
7705 	return bytes_written;
7706 }
7707 #endif /* SUPPORT_RSSI_SUM_REPORT */
7708 
7709 #ifdef SET_PCIE_IRQ_CPU_CORE
7710 void
wl_android_set_irq_cpucore(struct net_device * net,int affinity_cmd)7711 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
7712 {
7713 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
7714 	if (!dhdp) {
7715 		WL_ERR(("dhd is NULL\n"));
7716 		return;
7717 	}
7718 
7719 	if (affinity_cmd < PCIE_IRQ_AFFINITY_OFF || affinity_cmd > PCIE_IRQ_AFFINITY_LAST) {
7720 		WL_ERR(("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__));
7721 		return;
7722 	}
7723 
7724 	dhd_set_irq_cpucore(dhdp, affinity_cmd);
7725 }
7726 #endif /* SET_PCIE_IRQ_CPU_CORE */
7727 
7728 #ifdef SUPPORT_LQCM
7729 static int
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)7730 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
7731 {
7732 	int err = 0;
7733 
7734 	err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
7735 	if (err != BCME_OK) {
7736 		WL_ERR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
7737 		return -EIO;
7738 	}
7739 	return err;
7740 }
7741 
7742 static int
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)7743 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
7744 {
7745 	int bytes_written, err = 0;
7746 	uint32 lqcm_report = 0;
7747 	uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
7748 
7749 	err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
7750 	if (err != BCME_OK) {
7751 		WL_ERR(("failed to get lqcm report, error = %d\n", err));
7752 		return -EIO;
7753 	}
7754 	lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
7755 	tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
7756 	rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
7757 
7758 	WL_DBG(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
7759 
7760 	bytes_written = snprintf(command, total_len, "%s %d",
7761 			CMD_GET_LQCM_REPORT, lqcm_report);
7762 
7763 	return bytes_written;
7764 }
7765 #endif /* SUPPORT_LQCM */
7766 
7767 int
wl_android_get_snr(struct net_device * dev,char * command,int total_len)7768 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
7769 {
7770 	int bytes_written, error = 0;
7771 	s32 snr = 0;
7772 
7773 	error = wldev_iovar_getint(dev, "snr", &snr);
7774 	if (error) {
7775 		DHD_ERROR(("wl_android_get_snr: Failed to get SNR %d, error = %d\n",
7776 			snr, error));
7777 		return -EIO;
7778 	}
7779 
7780 	bytes_written = snprintf(command, total_len, "snr %d", snr);
7781 	DHD_INFO(("wl_android_get_snr: command result is %s\n", command));
7782 	return bytes_written;
7783 }
7784 
7785 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
7786 int
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)7787 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
7788 {
7789 	int rate = 0;
7790 	char *pos, *token;
7791 	char *ifname = NULL;
7792 	int err = BCME_OK;
7793 
7794 	/*
7795 	 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
7796 	 */
7797 	pos = command;
7798 
7799 	/* drop command */
7800 	token = bcmstrtok(&pos, " ", NULL);
7801 
7802 	/* Rate */
7803 	token = bcmstrtok(&pos, " ", NULL);
7804 	if (!token)
7805 		return -EINVAL;
7806 	rate = bcm_atoi(token);
7807 
7808 	/* get the interface name */
7809 	token = bcmstrtok(&pos, " ", NULL);
7810 	if (!token)
7811 		return -EINVAL;
7812 	ifname = token;
7813 
7814 	WL_DBG(("rate %d, ifacename %s\n", rate, ifname));
7815 
7816 	err = wl_set_ap_beacon_rate(dev, rate, ifname);
7817 	if (unlikely(err)) {
7818 		WL_ERR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
7819 	}
7820 
7821 	return err;
7822 }
7823 
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)7824 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
7825 {
7826 	char *pos, *token;
7827 	char *ifname = NULL;
7828 	int bytes_written = 0;
7829 	/*
7830 	 * DRIVER GET_AP_BASICRATE <ifname>
7831 	 */
7832 	pos = command;
7833 
7834 	/* drop command */
7835 	token = bcmstrtok(&pos, " ", NULL);
7836 
7837 	/* get the interface name */
7838 	token = bcmstrtok(&pos, " ", NULL);
7839 	if (!token)
7840 		return -EINVAL;
7841 	ifname = token;
7842 
7843 	WL_DBG(("ifacename %s\n", ifname));
7844 
7845 	bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
7846 	if (bytes_written < 1) {
7847 		WL_ERR(("Failed to get ap basic rate, error = %d\n", bytes_written));
7848 		return -EPROTO;
7849 	}
7850 
7851 	return bytes_written;
7852 }
7853 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
7854 
7855 #ifdef SUPPORT_AP_RADIO_PWRSAVE
7856 int
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)7857 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
7858 {
7859 	char *pos, *token;
7860 	char *ifname = NULL;
7861 	int bytes_written = 0;
7862 	char name[IFNAMSIZ];
7863 	/*
7864 	 * DRIVER GET_AP_RPS <ifname>
7865 	 */
7866 	pos = command;
7867 
7868 	/* drop command */
7869 	token = bcmstrtok(&pos, " ", NULL);
7870 
7871 	/* get the interface name */
7872 	token = bcmstrtok(&pos, " ", NULL);
7873 	if (!token)
7874 		return -EINVAL;
7875 	ifname = token;
7876 
7877 	strlcpy(name, ifname, sizeof(name));
7878 	WL_DBG(("ifacename %s\n", name));
7879 
7880 	bytes_written = wl_get_ap_rps(dev, command, name, total_len);
7881 	if (bytes_written < 1) {
7882 		WL_ERR(("Failed to get rps, error = %d\n", bytes_written));
7883 		return -EPROTO;
7884 	}
7885 
7886 	return bytes_written;
7887 
7888 }
7889 
7890 int
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)7891 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
7892 {
7893 	int enable = 0;
7894 	char *pos, *token;
7895 	char *ifname = NULL;
7896 	int err = BCME_OK;
7897 	char name[IFNAMSIZ];
7898 
7899 	/*
7900 	 * DRIVER SET_AP_RPS <0/1> <ifname>
7901 	 */
7902 	pos = command;
7903 
7904 	/* drop command */
7905 	token = bcmstrtok(&pos, " ", NULL);
7906 
7907 	/* Enable */
7908 	token = bcmstrtok(&pos, " ", NULL);
7909 	if (!token)
7910 		return -EINVAL;
7911 	enable = bcm_atoi(token);
7912 
7913 	/* get the interface name */
7914 	token = bcmstrtok(&pos, " ", NULL);
7915 	if (!token)
7916 		return -EINVAL;
7917 	ifname = token;
7918 
7919 	strlcpy(name, ifname, sizeof(name));
7920 	WL_DBG(("enable %d, ifacename %s\n", enable, name));
7921 
7922 	err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
7923 	if (unlikely(err)) {
7924 		WL_ERR(("Failed to set rps, enable %d, error = %d\n", enable, err));
7925 	}
7926 
7927 	return err;
7928 }
7929 
7930 int
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)7931 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
7932 {
7933 	ap_rps_info_t rps;
7934 	char *pos, *token;
7935 	char *ifname = NULL;
7936 	int err = BCME_OK;
7937 	char name[IFNAMSIZ];
7938 
7939 	bzero(&rps, sizeof(rps));
7940 	/*
7941 	 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
7942 	 */
7943 	pos = command;
7944 
7945 	/* drop command */
7946 	token = bcmstrtok(&pos, " ", NULL);
7947 
7948 	/* pps */
7949 	token = bcmstrtok(&pos, " ", NULL);
7950 	if (!token)
7951 		return -EINVAL;
7952 	rps.pps = bcm_atoi(token);
7953 
7954 	/* level */
7955 	token = bcmstrtok(&pos, " ", NULL);
7956 	if (!token)
7957 		return -EINVAL;
7958 	rps.level = bcm_atoi(token);
7959 
7960 	/* quiettime */
7961 	token = bcmstrtok(&pos, " ", NULL);
7962 	if (!token)
7963 		return -EINVAL;
7964 	rps.quiet_time = bcm_atoi(token);
7965 
7966 	/* sta assoc check */
7967 	token = bcmstrtok(&pos, " ", NULL);
7968 	if (!token)
7969 		return -EINVAL;
7970 	rps.sta_assoc_check = bcm_atoi(token);
7971 
7972 	/* get the interface name */
7973 	token = bcmstrtok(&pos, " ", NULL);
7974 	if (!token)
7975 		return -EINVAL;
7976 	ifname = token;
7977 	strlcpy(name, ifname, sizeof(name));
7978 
7979 	WL_DBG(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
7980 		"ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
7981 		rps.sta_assoc_check, name));
7982 
7983 	err = wl_update_ap_rps_params(dev, &rps, name);
7984 	if (unlikely(err)) {
7985 		WL_ERR(("Failed to update rps, pps %d, level %d, quiettime %d, "
7986 			"sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
7987 			rps.sta_assoc_check, err));
7988 	}
7989 
7990 	return err;
7991 }
7992 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
7993 
7994 #if defined(DHD_HANG_SEND_UP_TEST)
7995 void
wl_android_make_hang_with_reason(struct net_device * dev,const char * string_num)7996 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
7997 {
7998 	dhd_make_hang_with_reason(dev, string_num);
7999 }
8000 #endif /* DHD_HANG_SEND_UP_TEST */
8001 
8002 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
8003 static void
wl_android_check_priv_cmd_errors(struct net_device * dev)8004 wl_android_check_priv_cmd_errors(struct net_device *dev)
8005 {
8006 	dhd_pub_t *dhdp;
8007 	int memdump_mode;
8008 
8009 	if (!dev) {
8010 		WL_ERR(("dev is NULL\n"));
8011 		return;
8012 	}
8013 
8014 	dhdp = wl_cfg80211_get_dhdp(dev);
8015 	if (!dhdp) {
8016 		WL_ERR(("dhdp is NULL\n"));
8017 		return;
8018 	}
8019 
8020 #ifdef DHD_FW_COREDUMP
8021 	memdump_mode = dhdp->memdump_enabled;
8022 #else
8023 	/* Default enable if DHD doesn't support SOCRAM dump */
8024 	memdump_mode = 1;
8025 #endif /* DHD_FW_COREDUMP */
8026 
8027 	if (report_hang_privcmd_err) {
8028 		priv_cmd_errors++;
8029 	} else {
8030 		priv_cmd_errors = 0;
8031 	}
8032 
8033 	/* Trigger HANG event only if memdump mode is enabled
8034 	 * due to customer's request
8035 	 */
8036 	if (memdump_mode == DUMP_MEMFILE_BUGON &&
8037 		(priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
8038 		WL_ERR(("Send HANG event due to sequential private cmd errors\n"));
8039 		priv_cmd_errors = 0;
8040 #ifdef DHD_FW_COREDUMP
8041 		/* Take a SOCRAM dump */
8042 		dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
8043 		dhd_common_socram_dump(dhdp);
8044 #endif /* DHD_FW_COREDUMP */
8045 		/* Send the HANG event to upper layer */
8046 		dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
8047 		dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
8048 	}
8049 }
8050 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
8051 
8052 #ifdef DHD_PKT_LOGGING
8053 static int
wl_android_pktlog_filter_enable(struct net_device * dev,char * command,int total_len)8054 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
8055 {
8056 	int bytes_written = 0;
8057 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8058 	dhd_pktlog_filter_t *filter;
8059 	int err = BCME_OK;
8060 
8061 	if (!dhdp || !dhdp->pktlog) {
8062 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8063 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8064 		return -EINVAL;
8065 	}
8066 
8067 	filter = dhdp->pktlog->pktlog_filter;
8068 
8069 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
8070 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
8071 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
8072 
8073 	if (err == BCME_OK) {
8074 		bytes_written = snprintf(command, total_len, "OK");
8075 		DHD_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
8076 	} else {
8077 		DHD_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
8078 		return BCME_ERROR;
8079 	}
8080 
8081 	return bytes_written;
8082 }
8083 
8084 static int
wl_android_pktlog_filter_disable(struct net_device * dev,char * command,int total_len)8085 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
8086 {
8087 	int bytes_written = 0;
8088 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8089 	dhd_pktlog_filter_t *filter;
8090 	int err = BCME_OK;
8091 
8092 	if (!dhdp || !dhdp->pktlog) {
8093 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8094 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8095 		return -EINVAL;
8096 	}
8097 
8098 	filter = dhdp->pktlog->pktlog_filter;
8099 
8100 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
8101 	err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
8102 	err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
8103 
8104 	if (err == BCME_OK) {
8105 		bytes_written = snprintf(command, total_len, "OK");
8106 		DHD_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
8107 	} else {
8108 		DHD_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
8109 		return BCME_ERROR;
8110 	}
8111 
8112 	return bytes_written;
8113 }
8114 
8115 static int
wl_android_pktlog_filter_pattern_enable(struct net_device * dev,char * command,int total_len)8116 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
8117 {
8118 	int bytes_written = 0;
8119 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8120 	dhd_pktlog_filter_t *filter;
8121 	int err = BCME_OK;
8122 
8123 	if (!dhdp || !dhdp->pktlog) {
8124 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8125 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8126 		return -EINVAL;
8127 	}
8128 
8129 	filter = dhdp->pktlog->pktlog_filter;
8130 
8131 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
8132 		return BCME_ERROR;
8133 	}
8134 
8135 	err = dhd_pktlog_filter_pattern_enable(filter,
8136 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
8137 
8138 	if (err == BCME_OK) {
8139 		bytes_written = snprintf(command, total_len, "OK");
8140 		DHD_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
8141 	} else {
8142 		DHD_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
8143 		return BCME_ERROR;
8144 	}
8145 
8146 	return bytes_written;
8147 }
8148 
8149 static int
wl_android_pktlog_filter_pattern_disable(struct net_device * dev,char * command,int total_len)8150 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
8151 {
8152 	int bytes_written = 0;
8153 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8154 	dhd_pktlog_filter_t *filter;
8155 	int err = BCME_OK;
8156 
8157 	if (!dhdp || !dhdp->pktlog) {
8158 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8159 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8160 		return -EINVAL;
8161 	}
8162 
8163 	filter = dhdp->pktlog->pktlog_filter;
8164 
8165 	if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
8166 		return BCME_ERROR;
8167 	}
8168 
8169 	err = dhd_pktlog_filter_pattern_enable(filter,
8170 			command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
8171 
8172 	if (err == BCME_OK) {
8173 		bytes_written = snprintf(command, total_len, "OK");
8174 		DHD_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
8175 	} else {
8176 		DHD_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
8177 		return BCME_ERROR;
8178 	}
8179 
8180 	return bytes_written;
8181 }
8182 
8183 static int
wl_android_pktlog_filter_add(struct net_device * dev,char * command,int total_len)8184 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
8185 {
8186 	int bytes_written = 0;
8187 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8188 	dhd_pktlog_filter_t *filter;
8189 	int err = BCME_OK;
8190 
8191 	if (!dhdp || !dhdp->pktlog) {
8192 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8193 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8194 		return -EINVAL;
8195 	}
8196 
8197 	filter = dhdp->pktlog->pktlog_filter;
8198 
8199 	if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
8200 		return BCME_ERROR;
8201 	}
8202 
8203 	err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
8204 
8205 	if (err == BCME_OK) {
8206 		bytes_written = snprintf(command, total_len, "OK");
8207 		DHD_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
8208 	} else {
8209 		DHD_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
8210 		return BCME_ERROR;
8211 	}
8212 
8213 	return bytes_written;
8214 }
8215 
8216 static int
wl_android_pktlog_filter_del(struct net_device * dev,char * command,int total_len)8217 wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_len)
8218 {
8219 	int bytes_written = 0;
8220 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8221 	dhd_pktlog_filter_t *filter;
8222 	int err = BCME_OK;
8223 
8224 	if (!dhdp || !dhdp->pktlog) {
8225 		DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n",
8226 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8227 		return -EINVAL;
8228 	}
8229 
8230 	filter = dhdp->pktlog->pktlog_filter;
8231 
8232 	if (strlen(CMD_PKTLOG_FILTER_DEL) + 1 > total_len) {
8233 		DHD_PKT_LOG(("%s(): wrong cmd length %d found\n",
8234 			__FUNCTION__, (int)strlen(CMD_PKTLOG_FILTER_DEL)));
8235 		return BCME_ERROR;
8236 	}
8237 
8238 	err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1);
8239 	if (err == BCME_OK) {
8240 		bytes_written = snprintf(command, total_len, "OK");
8241 		DHD_ERROR(("%s: pktlog filter del success\n", __FUNCTION__));
8242 	} else {
8243 		DHD_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__));
8244 		return BCME_ERROR;
8245 	}
8246 
8247 	return bytes_written;
8248 }
8249 
8250 static int
wl_android_pktlog_filter_info(struct net_device * dev,char * command,int total_len)8251 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
8252 {
8253 	int bytes_written = 0;
8254 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8255 	dhd_pktlog_filter_t *filter;
8256 	int err = BCME_OK;
8257 
8258 	if (!dhdp || !dhdp->pktlog) {
8259 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8260 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8261 		return -EINVAL;
8262 	}
8263 
8264 	filter = dhdp->pktlog->pktlog_filter;
8265 
8266 	err = dhd_pktlog_filter_info(filter);
8267 
8268 	if (err == BCME_OK) {
8269 		bytes_written = snprintf(command, total_len, "OK");
8270 		DHD_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
8271 	} else {
8272 		DHD_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
8273 		return BCME_ERROR;
8274 	}
8275 
8276 	return bytes_written;
8277 }
8278 
8279 static int
wl_android_pktlog_start(struct net_device * dev,char * command,int total_len)8280 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
8281 {
8282 	int bytes_written = 0;
8283 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8284 
8285 	if (!dhdp || !dhdp->pktlog) {
8286 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8287 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8288 		return -EINVAL;
8289 	}
8290 
8291 	if (!dhdp->pktlog->pktlog_ring) {
8292 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
8293 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
8294 		return -EINVAL;
8295 	}
8296 
8297 	atomic_set(&dhdp->pktlog->pktlog_ring->start, TRUE);
8298 
8299 	bytes_written = snprintf(command, total_len, "OK");
8300 
8301 	DHD_ERROR(("%s: pktlog start success\n", __FUNCTION__));
8302 
8303 	return bytes_written;
8304 }
8305 
8306 static int
wl_android_pktlog_stop(struct net_device * dev,char * command,int total_len)8307 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
8308 {
8309 	int bytes_written = 0;
8310 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8311 
8312 	if (!dhdp || !dhdp->pktlog) {
8313 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8314 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8315 		return -EINVAL;
8316 	}
8317 
8318 	if (!dhdp->pktlog->pktlog_ring) {
8319 		DHD_PKT_LOG(("%s(): _pktlog_ring=%p\n",
8320 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
8321 		return -EINVAL;
8322 	}
8323 
8324 	atomic_set(&dhdp->pktlog->pktlog_ring->start, FALSE);
8325 
8326 	bytes_written = snprintf(command, total_len, "OK");
8327 
8328 	DHD_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
8329 
8330 	return bytes_written;
8331 }
8332 
8333 static int
wl_android_pktlog_filter_exist(struct net_device * dev,char * command,int total_len)8334 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
8335 {
8336 	int bytes_written = 0;
8337 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8338 	dhd_pktlog_filter_t *filter;
8339 	uint32 id;
8340 	bool exist = FALSE;
8341 
8342 	if (!dhdp || !dhdp->pktlog) {
8343 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8344 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8345 		return -EINVAL;
8346 	}
8347 
8348 	filter = dhdp->pktlog->pktlog_filter;
8349 
8350 	if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
8351 		return BCME_ERROR;
8352 	}
8353 
8354 	exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
8355 			&id);
8356 
8357 	if (exist) {
8358 		bytes_written = snprintf(command, total_len, "TRUE");
8359 		DHD_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
8360 	} else {
8361 		bytes_written = snprintf(command, total_len, "FALSE");
8362 		DHD_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
8363 	}
8364 
8365 	return bytes_written;
8366 }
8367 
8368 static int
wl_android_pktlog_minmize_enable(struct net_device * dev,char * command,int total_len)8369 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
8370 {
8371 	int bytes_written = 0;
8372 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8373 
8374 	if (!dhdp || !dhdp->pktlog) {
8375 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8376 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8377 		return -EINVAL;
8378 	}
8379 
8380 	if (!dhdp->pktlog->pktlog_ring) {
8381 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
8382 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
8383 		return -EINVAL;
8384 	}
8385 
8386 	dhdp->pktlog->pktlog_ring->pktlog_minmize = TRUE;
8387 
8388 	bytes_written = snprintf(command, total_len, "OK");
8389 
8390 	DHD_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
8391 
8392 	return bytes_written;
8393 }
8394 
8395 static int
wl_android_pktlog_minmize_disable(struct net_device * dev,char * command,int total_len)8396 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
8397 {
8398 	int bytes_written = 0;
8399 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8400 
8401 	if (!dhdp || !dhdp->pktlog) {
8402 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8403 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8404 		return -EINVAL;
8405 	}
8406 
8407 	if (!dhdp->pktlog->pktlog_ring) {
8408 		DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
8409 			__FUNCTION__, dhdp->pktlog->pktlog_ring));
8410 		return -EINVAL;
8411 	}
8412 
8413 	dhdp->pktlog->pktlog_ring->pktlog_minmize = FALSE;
8414 
8415 	bytes_written = snprintf(command, total_len, "OK");
8416 
8417 	DHD_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
8418 
8419 	return bytes_written;
8420 }
8421 
8422 static int
wl_android_pktlog_change_size(struct net_device * dev,char * command,int total_len)8423 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
8424 {
8425 	int bytes_written = 0;
8426 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8427 	int err = BCME_OK;
8428 	int size;
8429 
8430 	if (!dhdp || !dhdp->pktlog) {
8431 		DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
8432 			__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
8433 		return -EINVAL;
8434 	}
8435 
8436 	if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
8437 		return BCME_ERROR;
8438 	}
8439 
8440 	size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
8441 
8442 	dhdp->pktlog->pktlog_ring =
8443 		dhd_pktlog_ring_change_size(dhdp->pktlog->pktlog_ring, size);
8444 	if (!dhdp->pktlog->pktlog_ring) {
8445 		err = BCME_ERROR;
8446 	}
8447 
8448 	if (err == BCME_OK) {
8449 		bytes_written = snprintf(command, total_len, "OK");
8450 		DHD_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
8451 	} else {
8452 		DHD_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
8453 		return BCME_ERROR;
8454 	}
8455 
8456 	return bytes_written;
8457 }
8458 #endif /* DHD_PKT_LOGGING */
8459 
8460 #ifdef DHD_EVENT_LOG_FILTER
8461 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
8462 
8463 #ifdef DHD_EWPR_VER2
8464 uint32 dhd_event_log_filter_serialize_bit(dhd_pub_t *dhdp, char *buf, uint32 tot_len,
8465 	int index1, int index2, int index3);
8466 #endif // endif
8467 
8468 static int
wl_android_ewp_filter(struct net_device * dev,char * command,uint32 tot_len)8469 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
8470 {
8471 	uint32 bytes_written = 0;
8472 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8473 #ifdef DHD_EWPR_VER2
8474 	int index1 = 0, index2 = 0, index3 = 0;
8475 	unsigned char *index_str = (unsigned char *)(command +
8476 		strlen(CMD_EWP_FILTER) + 1);
8477 #else
8478 	int type = 0;
8479 #endif // endif
8480 
8481 	if (!dhdp || !command) {
8482 		DHD_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
8483 		return -EINVAL;
8484 	}
8485 
8486 #ifdef DHD_EWPR_VER2
8487 	if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) {
8488 		sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3);
8489 		DHD_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__,
8490 			index1, index2, index3));
8491 	}
8492 	bytes_written += dhd_event_log_filter_serialize_bit(dhdp,
8493 		&command[bytes_written], tot_len - bytes_written, index1, index2, index3);
8494 #else
8495 	/* NEED TO GET TYPE if EXIST */
8496 	type = 0;
8497 
8498 	bytes_written += dhd_event_log_filter_serialize(dhdp,
8499 		&command[bytes_written], tot_len - bytes_written, type);
8500 #endif // endif
8501 
8502 	return (int)bytes_written;
8503 }
8504 #endif /* DHD_EVENT_LOG_FILTER */
8505 
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr)8506 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
8507 {
8508 #define PRIVATE_COMMAND_MAX_LEN	8192
8509 #define PRIVATE_COMMAND_DEF_LEN	4096
8510 	int ret = 0;
8511 	char *command = NULL;
8512 	int bytes_written = 0;
8513 	android_wifi_priv_cmd priv_cmd;
8514 	int buf_size = 0;
8515 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
8516 
8517 	net_os_wake_lock(net);
8518 
8519 	if (!capable(CAP_NET_ADMIN)) {
8520 		ret = -EPERM;
8521 		goto exit;
8522 	}
8523 
8524 	if (!ifr->ifr_data) {
8525 		ret = -EINVAL;
8526 		goto exit;
8527 	}
8528 
8529 	{
8530 		if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
8531 			ret = -EFAULT;
8532 			goto exit;
8533 		}
8534 	}
8535 	if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
8536 		DHD_ERROR(("wl_android_priv_cmd: buf length invalid:%d\n",
8537 			priv_cmd.total_len));
8538 		ret = -EINVAL;
8539 		goto exit;
8540 	}
8541 
8542 	buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
8543 	command = (char *)MALLOC(cfg->osh, (buf_size + 1));
8544 	if (!command) {
8545 		DHD_ERROR(("wl_android_priv_cmd: failed to allocate memory\n"));
8546 		ret = -ENOMEM;
8547 		goto exit;
8548 	}
8549 	if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
8550 		ret = -EFAULT;
8551 		goto exit;
8552 	}
8553 	command[priv_cmd.total_len] = '\0';
8554 
8555 	DHD_ERROR(("wl_android_priv_cmd: Android private cmd \"%s\" on %s\n",
8556 		command, ifr->ifr_name));
8557 
8558 	bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
8559 	if (bytes_written >= 0) {
8560 		if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
8561 			command[0] = '\0';
8562 		}
8563 		if (bytes_written >= priv_cmd.total_len) {
8564 			DHD_ERROR(("wl_android_priv_cmd: err. bytes_written:%d >= total_len:%d,"
8565 				" buf_size:%d \n", bytes_written, priv_cmd.total_len, buf_size));
8566 			ret = BCME_BUFTOOSHORT;
8567 			goto exit;
8568 		}
8569 		bytes_written++;
8570 		priv_cmd.used_len = bytes_written;
8571 		if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
8572 			DHD_ERROR(("wl_android_priv_cmd: failed to copy data to user buffer\n"));
8573 			ret = -EFAULT;
8574 		}
8575 	}
8576 	else {
8577 		/* Propagate the error */
8578 		ret = bytes_written;
8579 	}
8580 
8581 exit:
8582 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
8583 	if (ret) {
8584 		/* Avoid incrementing priv_cmd_errors in case of unsupported feature */
8585 		if (ret != BCME_UNSUPPORTED) {
8586 			wl_android_check_priv_cmd_errors(net);
8587 		}
8588 	} else {
8589 		priv_cmd_errors = 0;
8590 	}
8591 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
8592 	net_os_wake_unlock(net);
8593 	MFREE(cfg->osh, command, (buf_size + 1));
8594 	return ret;
8595 }
8596 #ifdef WLADPS_PRIVATE_CMD
8597 static int
wl_android_set_adps_mode(struct net_device * dev,const char * string_num)8598 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
8599 {
8600 	int err = 0, adps_mode;
8601 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
8602 #ifdef DHD_PM_CONTROL_FROM_FILE
8603 	if (g_pm_control) {
8604 		return -EPERM;
8605 	}
8606 #endif	/* DHD_PM_CONTROL_FROM_FILE */
8607 
8608 	adps_mode = bcm_atoi(string_num);
8609 	WL_ERR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
8610 
8611 	if ((adps_mode < 0) && (1 < adps_mode)) {
8612 		WL_ERR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode));
8613 		return -EINVAL;
8614 	}
8615 
8616 	err = dhd_enable_adps(dhdp, adps_mode);
8617 	if (err != BCME_OK) {
8618 		WL_ERR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
8619 		return -EIO;
8620 	}
8621 	return err;
8622 }
8623 static int
wl_android_get_adps_mode(struct net_device * dev,char * command,int total_len)8624 wl_android_get_adps_mode(
8625 	struct net_device *dev, char *command, int total_len)
8626 {
8627 	int bytes_written, err = 0;
8628 	uint len;
8629 	char buf[WLC_IOCTL_SMLEN];
8630 
8631 	bcm_iov_buf_t iov_buf;
8632 	bcm_iov_buf_t *ptr = NULL;
8633 	wl_adps_params_v1_t *data = NULL;
8634 
8635 	uint8 *pdata = NULL;
8636 	uint8 band, mode = 0;
8637 
8638 	bzero(&iov_buf, sizeof(iov_buf));
8639 
8640 	len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
8641 
8642 	iov_buf.version = WL_ADPS_IOV_VER;
8643 	iov_buf.len = sizeof(band);
8644 	iov_buf.id = WL_ADPS_IOV_MODE;
8645 
8646 	pdata = (uint8 *)&iov_buf.data;
8647 
8648 	for (band = 1; band <= MAX_BANDS; band++) {
8649 		pdata[0] = band;
8650 		err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
8651 			buf, WLC_IOCTL_SMLEN, NULL);
8652 		if (err != BCME_OK) {
8653 			WL_ERR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n",
8654 					band, err));
8655 			return -EIO;
8656 		}
8657 		ptr = (bcm_iov_buf_t *) buf;
8658 		data = (wl_adps_params_v1_t *) ptr->data;
8659 		mode = data->mode;
8660 		if (mode != OFF) {
8661 			break;
8662 		}
8663 	}
8664 
8665 	bytes_written = snprintf(command, total_len, "%s %d",
8666 		CMD_GET_ADPS, mode);
8667 	return bytes_written;
8668 }
8669 #endif /* WLADPS_PRIVATE_CMD */
8670 
8671 #ifdef WL_BCNRECV
8672 #define BCNRECV_ATTR_HDR_LEN 30
8673 int
wl_android_bcnrecv_event(struct net_device * ndev,uint attr_type,uint status,uint reason,uint8 * data,uint data_len)8674 wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
8675 		uint status, uint reason, uint8 *data, uint data_len)
8676 {
8677 	s32 err = BCME_OK;
8678 	struct sk_buff *skb;
8679 	gfp_t kflags;
8680 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
8681 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
8682 	uint len;
8683 
8684 	len = BCNRECV_ATTR_HDR_LEN + data_len;
8685 
8686 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
8687 	skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
8688 		BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
8689 	if (!skb) {
8690 		WL_ERR(("skb alloc failed"));
8691 		return -ENOMEM;
8692 	}
8693 	if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
8694 		/* send bcn info to upper layer */
8695 		nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
8696 	} else if (attr_type == BCNRECV_ATTR_STATUS) {
8697 		nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
8698 		if (reason) {
8699 			nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
8700 		}
8701 	} else {
8702 		WL_ERR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
8703 		kfree_skb(skb);
8704 		return -EINVAL;
8705 	}
8706 	cfg80211_vendor_event(skb, kflags);
8707 	return err;
8708 }
8709 
8710 static int
_wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool user_trigger)8711 _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
8712 {
8713 	s32 err = BCME_OK;
8714 
8715 	/* check any scan is in progress before beacon recv scan trigger IOVAR */
8716 	if (wl_get_drv_status_all(cfg, SCANNING)) {
8717 		err = BCME_UNSUPPORTED;
8718 		WL_ERR(("Scan in progress, Aborting beacon recv start, "
8719 			"error:%d\n", err));
8720 		goto exit;
8721 	}
8722 
8723 	if (wl_get_p2p_status(cfg, SCANNING)) {
8724 		err = BCME_UNSUPPORTED;
8725 		WL_ERR(("P2P Scan in progress, Aborting beacon recv start, "
8726 			"error:%d\n", err));
8727 		goto exit;
8728 	}
8729 
8730 	if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
8731 		err = BCME_UNSUPPORTED;
8732 		WL_ERR(("P2P remain on channel, Aborting beacon recv start, "
8733 			"error:%d\n", err));
8734 		goto exit;
8735 	}
8736 
8737 	/* check STA is in connected state, Beacon recv required connected state
8738 	 * else exit from beacon recv scan
8739 	 */
8740 	if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
8741 		err = BCME_UNSUPPORTED;
8742 		WL_ERR(("STA is in not associated state error:%d\n", err));
8743 		goto exit;
8744 	}
8745 
8746 #ifdef WL_NAN
8747 	/* Check NAN is enabled, if enabled exit else continue */
8748 	if (wl_cfgnan_check_state(cfg)) {
8749 		err = BCME_UNSUPPORTED;
8750 		WL_ERR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
8751 		goto exit;
8752 	}
8753 #endif /* WL_NAN */
8754 
8755 	/* Triggering an sendup_bcn iovar */
8756 	err = wldev_iovar_setint(ndev, "sendup_bcn", 1);
8757 	if (unlikely(err)) {
8758 		WL_ERR(("sendup_bcn failed to set, error:%d\n", err));
8759 	} else {
8760 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
8761 		WL_INFORM_MEM(("bcnrecv started. user_trigger:%d\n", user_trigger));
8762 		if (user_trigger) {
8763 			if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS,
8764 					WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
8765 				WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
8766 			}
8767 		}
8768 	}
8769 exit:
8770 	/*
8771 	 * BCNRECV start request can be rejected from dongle
8772 	 * in various conditions.
8773 	 * Error code need to be overridden to BCME_UNSUPPORTED
8774 	 * to avoid hang event from continous private
8775 	 * command error
8776 	 */
8777 	if (err) {
8778 		err = BCME_UNSUPPORTED;
8779 	}
8780 	return err;
8781 }
8782 
8783 int
_wl_android_bcnrecv_stop(struct bcm_cfg80211 * cfg,struct net_device * ndev,uint reason)8784 _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
8785 {
8786 	s32 err = BCME_OK;
8787 	u32 status;
8788 
8789 	/* Send sendup_bcn iovar for all cases except W_BCNRECV_ROAMABORT reason -
8790 	 * fw generates roam abort event after aborting the bcnrecv.
8791 	 */
8792 	if (reason != WL_BCNRECV_ROAMABORT) {
8793 		/* Triggering an sendup_bcn iovar */
8794 		err = wldev_iovar_setint(ndev, "sendup_bcn", 0);
8795 		if (unlikely(err)) {
8796 			WL_ERR(("sendup_bcn failed to set error:%d\n", err));
8797 			goto exit;
8798 		}
8799 	}
8800 
8801 	/* Send notification for all cases */
8802 	if (reason == WL_BCNRECV_SUSPEND) {
8803 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
8804 		status = WL_BCNRECV_SUSPENDED;
8805 	} else {
8806 		cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
8807 		WL_INFORM_MEM(("bcnrecv stopped\n"));
8808 		if (reason == WL_BCNRECV_USER_TRIGGER) {
8809 			status = WL_BCNRECV_STOPPED;
8810 		} else {
8811 			status = WL_BCNRECV_ABORTED;
8812 		}
8813 	}
8814 	if ((err = wl_android_bcnrecv_event(ndev, BCNRECV_ATTR_STATUS, status,
8815 			reason, NULL, 0)) != BCME_OK) {
8816 		WL_ERR(("failed to send bcnrecv event, error:%d\n", err));
8817 	}
8818 exit:
8819 	return err;
8820 }
8821 
8822 static int
wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev)8823 wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
8824 {
8825 	s32 err = BCME_OK;
8826 
8827 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
8828 	mutex_lock(&cfg->scan_sync);
8829 	mutex_lock(&cfg->bcn_sync);
8830 	err = _wl_android_bcnrecv_start(cfg, ndev, true);
8831 	mutex_unlock(&cfg->bcn_sync);
8832 	mutex_unlock(&cfg->scan_sync);
8833 	return err;
8834 }
8835 
8836 int
wl_android_bcnrecv_stop(struct net_device * ndev,uint reason)8837 wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
8838 {
8839 	s32 err = BCME_OK;
8840 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
8841 
8842 	mutex_lock(&cfg->bcn_sync);
8843 	if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
8844 	   (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
8845 		err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
8846 	}
8847 	mutex_unlock(&cfg->bcn_sync);
8848 	return err;
8849 }
8850 
8851 int
wl_android_bcnrecv_suspend(struct net_device * ndev)8852 wl_android_bcnrecv_suspend(struct net_device *ndev)
8853 {
8854 	s32 ret = BCME_OK;
8855 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
8856 
8857 	mutex_lock(&cfg->bcn_sync);
8858 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
8859 		WL_INFORM_MEM(("bcnrecv suspend\n"));
8860 		ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
8861 	}
8862 	mutex_unlock(&cfg->bcn_sync);
8863 	return ret;
8864 }
8865 
8866 int
wl_android_bcnrecv_resume(struct net_device * ndev)8867 wl_android_bcnrecv_resume(struct net_device *ndev)
8868 {
8869 	s32 ret = BCME_OK;
8870 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
8871 
8872 	/* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
8873 	mutex_lock(&cfg->scan_sync);
8874 	mutex_lock(&cfg->bcn_sync);
8875 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
8876 		WL_INFORM_MEM(("bcnrecv resume\n"));
8877 		ret = _wl_android_bcnrecv_start(cfg, ndev, false);
8878 	}
8879 	mutex_unlock(&cfg->bcn_sync);
8880 	mutex_unlock(&cfg->scan_sync);
8881 	return ret;
8882 }
8883 
8884 /* Beacon recv functionality code implementation */
8885 int
wl_android_bcnrecv_config(struct net_device * ndev,char * cmd_argv,int total_len)8886 wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
8887 {
8888 	struct bcm_cfg80211 *cfg = NULL;
8889 	uint err = BCME_OK;
8890 
8891 	if (!ndev) {
8892 		WL_ERR(("ndev is NULL\n"));
8893 		return -EINVAL;
8894 	}
8895 
8896 	cfg = wl_get_cfg(ndev);
8897 	if (!cfg) {
8898 		WL_ERR(("cfg is NULL\n"));
8899 		return -EINVAL;
8900 	}
8901 
8902 	/* sync commands from user space */
8903 	mutex_lock(&cfg->usr_sync);
8904 	if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
8905 		WL_INFORM(("BCNRECV start\n"));
8906 		err = wl_android_bcnrecv_start(cfg, ndev);
8907 		if (err != BCME_OK) {
8908 			WL_ERR(("Failed to process the start command, error:%d\n", err));
8909 			goto exit;
8910 		}
8911 	} else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
8912 		WL_INFORM(("BCNRECV stop\n"));
8913 		err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
8914 		if (err != BCME_OK) {
8915 			WL_ERR(("Failed to stop the bcn recv, error:%d\n", err));
8916 			goto exit;
8917 		}
8918 	} else {
8919 		err = BCME_ERROR;
8920 	}
8921 exit:
8922 	mutex_unlock(&cfg->usr_sync);
8923 	return err;
8924 }
8925 #endif /* WL_BCNRECV */
8926 
8927 #ifdef WL_CAC_TS
8928 /* CAC TSPEC functionality code implementation */
8929 static void
wl_android_update_tsinfo(uint8 access_category,tspec_arg_t * tspec_arg)8930 wl_android_update_tsinfo(uint8 access_category, tspec_arg_t *tspec_arg)
8931 {
8932 	uint8 tspec_id;
8933 	/* Using direction as bidirectional by default */
8934 	uint8 direction = TSPEC_BI_DIRECTION;
8935 	/* Using U-APSD as the default power save mode */
8936 	uint8 user_psb = TSPEC_UAPSD_PSB;
8937 	uint8 ADDTS_AC2PRIO[4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI, PRIO_8021D_VO};
8938 
8939 	/* Map tspec_id from access category */
8940 	tspec_id = ADDTS_AC2PRIO[access_category];
8941 
8942 	/* Update the tsinfo */
8943 	tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
8944 		(tspec_id << TSPEC_TSINFO_TID_SHIFT));
8945 	tspec_arg->tsinfo.octets[1] = (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) |
8946 		user_psb);
8947 	tspec_arg->tsinfo.octets[2] = 0x00;
8948 }
8949 
8950 static s32
wl_android_handle_cac_action(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * argv)8951 wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev, char * argv)
8952 {
8953 	tspec_arg_t tspec_arg;
8954 	s32 err = BCME_ERROR;
8955 	u8 ts_cmd[12] = "cac_addts";
8956 	uint8 access_category;
8957 	s32 bssidx;
8958 
8959 	/* Following handling is done only for the primary interface */
8960 	memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
8961 	if (strncmp(argv, "addts", strlen("addts")) == 0) {
8962 		tspec_arg.version = TSPEC_ARG_VERSION;
8963 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
8964 		/* Read the params passed */
8965 		sscanf(argv, "%*s %hhu %hu %hu", &access_category,
8966 			&tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
8967 		if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
8968 			((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
8969 			(tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
8970 			(tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
8971 			WL_ERR(("Invalid params access_category %hhu nom_msdu_size %hu"
8972 				" surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size,
8973 				tspec_arg.surplus_bw));
8974 			return BCME_USAGE_ERROR;
8975 		}
8976 
8977 		/* Update tsinfo */
8978 		wl_android_update_tsinfo(access_category, &tspec_arg);
8979 		/* Update other tspec parameters */
8980 		tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
8981 		tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
8982 		tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
8983 	} else if (strncmp(argv, "delts", strlen("delts")) == 0) {
8984 		snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
8985 		tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
8986 		tspec_arg.version = TSPEC_ARG_VERSION;
8987 		/* Read the params passed */
8988 		sscanf(argv, "%*s %hhu", &access_category);
8989 
8990 		if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
8991 			WL_INFORM_MEM(("Invalide param, access_category %hhu\n", access_category));
8992 			return BCME_USAGE_ERROR;
8993 		}
8994 		/* Update tsinfo */
8995 		wl_android_update_tsinfo(access_category, &tspec_arg);
8996 	}
8997 
8998 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
8999 		WL_ERR(("Find index failed\n"));
9000 		err = BCME_ERROR;
9001 		return err;
9002 	}
9003 	err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
9004 			cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
9005 	if (unlikely(err)) {
9006 		WL_ERR(("%s error (%d)\n", ts_cmd, err));
9007 	}
9008 
9009 	return err;
9010 }
9011 
9012 static s32
wl_android_cac_ts_config(struct net_device * ndev,char * cmd_argv,int total_len)9013 wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len)
9014 {
9015 	struct bcm_cfg80211 *cfg = NULL;
9016 	s32 err = BCME_OK;
9017 
9018 	if (!ndev) {
9019 		WL_ERR(("ndev is NULL\n"));
9020 		return -EINVAL;
9021 	}
9022 
9023 	cfg = wl_get_cfg(ndev);
9024 	if (!cfg) {
9025 		WL_ERR(("cfg is NULL\n"));
9026 		return -EINVAL;
9027 	}
9028 
9029 	/* Request supported only for primary interface */
9030 	if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
9031 		WL_ERR(("Request on non-primary interface\n"));
9032 		return -1;
9033 	}
9034 
9035 	/* sync commands from user space */
9036 	mutex_lock(&cfg->usr_sync);
9037 	err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
9038 	mutex_unlock(&cfg->usr_sync);
9039 
9040 	return err;
9041 }
9042 #endif /* WL_CAC_TS */
9043 
9044 #ifdef WL_GET_CU
9045 /* Implementation to get channel usage from framework */
9046 static s32
wl_android_get_channel_util(struct net_device * ndev,char * command,int total_len)9047 wl_android_get_channel_util(struct net_device *ndev, char *command, int total_len)
9048 {
9049 	s32 bytes_written, err = 0;
9050 	wl_bssload_t bssload;
9051 	u8 smbuf[WLC_IOCTL_SMLEN];
9052 	u8 chan_use_percentage = 0;
9053 
9054 	if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL,
9055 		0, smbuf, WLC_IOCTL_SMLEN, NULL))) {
9056 		WL_ERR(("Getting bssload report failed with err=%d \n", err));
9057 		return err;
9058 	}
9059 
9060 	(void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
9061 	/* Convert channel usage to percentage value */
9062 	chan_use_percentage = (bssload.chan_util * 100) / 255;
9063 
9064 	bytes_written = snprintf(command, total_len, "CU %hhu",
9065 		chan_use_percentage);
9066 	WL_DBG(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage));
9067 
9068 	return bytes_written;
9069 }
9070 #endif /* WL_GET_CU */
9071 
9072 int
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)9073 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
9074 {
9075 	int bytes_written = 0;
9076 	android_wifi_priv_cmd priv_cmd;
9077 
9078 	bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
9079 	priv_cmd.total_len = cmd_len;
9080 
9081 	if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
9082 		DHD_INFO(("wl_handle_private_cmd, Received regular START command\n"));
9083 #ifdef SUPPORT_DEEP_SLEEP
9084 		trigger_deep_sleep = 1;
9085 #else
9086 #ifdef  BT_OVER_SDIO
9087 		bytes_written = dhd_net_bus_get(net);
9088 #else
9089 		bytes_written = wl_android_wifi_on(net);
9090 #endif /* BT_OVER_SDIO */
9091 #endif /* SUPPORT_DEEP_SLEEP */
9092 	}
9093 	else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
9094 		bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
9095 	}
9096 
9097 	if (!g_wifi_on) {
9098 		DHD_ERROR(("wl_handle_private_cmd: Ignore private cmd \"%s\" - iface is down\n",
9099 			command));
9100 		return 0;
9101 	}
9102 
9103 	if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
9104 #ifdef SUPPORT_DEEP_SLEEP
9105 		trigger_deep_sleep = 1;
9106 #else
9107 #ifdef  BT_OVER_SDIO
9108 		bytes_written = dhd_net_bus_put(net);
9109 #else
9110 		bytes_written = wl_android_wifi_off(net, FALSE);
9111 #endif /* BT_OVER_SDIO */
9112 #endif /* SUPPORT_DEEP_SLEEP */
9113 	}
9114 #ifdef AUTOMOTIVE_FEATURE
9115 	else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
9116 		wl_cfg80211_set_passive_scan(net, command);
9117 	}
9118 	else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
9119 		wl_cfg80211_set_passive_scan(net, command);
9120 	}
9121 	else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
9122 		bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
9123 	}
9124 	else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
9125 		bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
9126 	}
9127 #endif /* AUTOMOTIVE_FEATURE */
9128 #ifdef PKT_FILTER_SUPPORT
9129 	else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
9130 		bytes_written = net_os_enable_packet_filter(net, 1);
9131 	}
9132 	else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
9133 		bytes_written = net_os_enable_packet_filter(net, 0);
9134 	}
9135 	else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
9136 		int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
9137 		bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
9138 	}
9139 	else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
9140 		int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
9141 		bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
9142 	}
9143 #endif /* PKT_FILTER_SUPPORT */
9144 	else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
9145 		/* TBD: BTCOEXSCAN-START */
9146 	}
9147 	else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
9148 		/* TBD: BTCOEXSCAN-STOP */
9149 	}
9150 	else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
9151 #ifdef WL_CFG80211
9152 		void *dhdp = wl_cfg80211_get_dhdp(net);
9153 		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
9154 #else
9155 #ifdef PKT_FILTER_SUPPORT
9156 		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
9157 
9158 		if (mode == 1)
9159 			net_os_enable_packet_filter(net, 0); /* DHCP starts */
9160 		else
9161 			net_os_enable_packet_filter(net, 1); /* DHCP ends */
9162 #endif /* PKT_FILTER_SUPPORT */
9163 #endif /* WL_CFG80211 */
9164 	}
9165 	else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
9166 		bytes_written = wl_android_set_suspendopt(net, command);
9167 	}
9168 	else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
9169 		bytes_written = wl_android_set_suspendmode(net, command);
9170 	}
9171 	else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
9172 		bytes_written = wl_android_set_bcn_li_dtim(net, command);
9173 	}
9174 	else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
9175 		bytes_written = wl_android_set_max_dtim(net, command);
9176 	}
9177 #ifdef DISABLE_DTIM_IN_SUSPEND
9178 	else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
9179 		bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
9180 	}
9181 #endif /* DISABLE_DTIM_IN_SUSPEND */
9182 	else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
9183 		bytes_written = wl_android_set_band(net, command);
9184 	}
9185 	else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
9186 		bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
9187 	}
9188 	else if (strnicmp(command, CMD_ADDIE, strlen(CMD_ADDIE)) == 0) {
9189 		bytes_written = wl_android_add_vendor_ie(net, command, priv_cmd.total_len);
9190 	}
9191 	else if (strnicmp(command, CMD_DELIE, strlen(CMD_DELIE)) == 0) {
9192 		bytes_written = wl_android_del_vendor_ie(net, command, priv_cmd.total_len);
9193 	}
9194 #ifdef WL_CFG80211
9195 #ifndef CUSTOMER_SET_COUNTRY
9196 	/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
9197 	else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
9198 		/*
9199 		 * Usage examples:
9200 		 * DRIVER COUNTRY US
9201 		 * DRIVER COUNTRY US/7
9202 		 */
9203 		char *country_code = command + strlen(CMD_COUNTRY) + 1;
9204 		char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
9205 		int revinfo = -1;
9206 #if defined(DHD_BLOB_EXISTENCE_CHECK)
9207 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9208 
9209 		if (dhdp->is_blob) {
9210 			revinfo = 0;
9211 		} else
9212 #endif /* DHD_BLOB_EXISTENCE_CHECK */
9213 		if ((rev_info_delim) &&
9214 			(strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
9215 			strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
9216 			(rev_info_delim + 1)) {
9217 			revinfo  = bcm_atoi(rev_info_delim + 1);
9218 		}
9219 #ifdef SAVE_CONNECTION_WHEN_CC_UPDATE
9220 		wl_check_valid_channel_in_country(net, country_code, true);
9221 		bytes_written = wl_cfg80211_set_country_code(net, country_code,
9222 				true, false, revinfo);
9223 
9224 		wl_update_ap_chandef(net);
9225 #else
9226 		bytes_written = wl_cfg80211_set_country_code(net, country_code,
9227 				true, true, revinfo);
9228 #endif // endif
9229 #ifdef CUSTOMER_HW4_PRIVATE_CMD
9230 #ifdef FCC_PWR_LIMIT_2G
9231 		if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
9232 			DHD_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
9233 		} else {
9234 			DHD_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
9235 		}
9236 #endif /* FCC_PWR_LIMIT_2G */
9237 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
9238 	}
9239 #endif /* CUSTOMER_SET_COUNTRY */
9240 #endif /* WL_CFG80211 */
9241 	else if (strnicmp(command, CMD_CHANNELS_IN_CC, strlen(CMD_CHANNELS_IN_CC)) == 0) {
9242 		bytes_written = wl_android_get_channel_list(net, command, priv_cmd.total_len);
9243 	} else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
9244 		bytes_written = wl_android_set_csa(net, command);
9245 	} else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
9246 		bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
9247 	}
9248 #ifdef AUTOMOTIVE_FEATURE
9249 	 else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
9250 		bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
9251 	} else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
9252 		bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
9253 	} else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
9254 		bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
9255 	}
9256 #endif /* AUTOMOTIVE_FEATURE */
9257 	 else if (strnicmp(command, CMD_RSDB_MODE, strlen(CMD_RSDB_MODE)) == 0) {
9258 		bytes_written = wl_android_get_rsdb_mode(net, command, priv_cmd.total_len);
9259 	}
9260 
9261 #if defined(CUSTOMER_HW4_PRIVATE_CMD) || defined(IGUANA_LEGACY_CHIPS)
9262 #ifdef ROAM_API
9263 	else if (strnicmp(command, CMD_ROAMTRIGGER_SET,
9264 		strlen(CMD_ROAMTRIGGER_SET)) == 0) {
9265 		bytes_written = wl_android_set_roam_trigger(net, command);
9266 	} else if (strnicmp(command, CMD_ROAMTRIGGER_GET,
9267 		strlen(CMD_ROAMTRIGGER_GET)) == 0) {
9268 		bytes_written = wl_android_get_roam_trigger(net, command,
9269 		priv_cmd.total_len);
9270 	} else if (strnicmp(command, CMD_ROAMDELTA_SET,
9271 		strlen(CMD_ROAMDELTA_SET)) == 0) {
9272 		bytes_written = wl_android_set_roam_delta(net, command);
9273 	} else if (strnicmp(command, CMD_ROAMDELTA_GET,
9274 		strlen(CMD_ROAMDELTA_GET)) == 0) {
9275 		bytes_written = wl_android_get_roam_delta(net, command,
9276 		priv_cmd.total_len);
9277 	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
9278 		strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
9279 		bytes_written = wl_android_set_roam_scan_period(net, command);
9280 	} else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
9281 		strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
9282 		bytes_written = wl_android_get_roam_scan_period(net, command,
9283 		priv_cmd.total_len);
9284 	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
9285 		strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
9286 		bytes_written = wl_android_set_full_roam_scan_period(net, command,
9287 		priv_cmd.total_len);
9288 	} else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
9289 		strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
9290 		bytes_written = wl_android_get_full_roam_scan_period(net, command,
9291 		priv_cmd.total_len);
9292 	}
9293 #ifdef AUTOMOTIVE_FEATURE
9294 	 else if (strnicmp(command, CMD_COUNTRYREV_SET,
9295 		strlen(CMD_COUNTRYREV_SET)) == 0) {
9296 		bytes_written = wl_android_set_country_rev(net, command);
9297 #ifdef FCC_PWR_LIMIT_2G
9298 		if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
9299 			DHD_ERROR(("wl_handle_private_cmd: fccpwrlimit2g"
9300 				" deactivation is failed\n"));
9301 		} else {
9302 			DHD_ERROR(("wl_handle_private_cmd: fccpwrlimit2g is deactivated\n"));
9303 		}
9304 #endif /* FCC_PWR_LIMIT_2G */
9305 	} else if (strnicmp(command, CMD_COUNTRYREV_GET,
9306 		strlen(CMD_COUNTRYREV_GET)) == 0) {
9307 		bytes_written = wl_android_get_country_rev(net, command,
9308 		priv_cmd.total_len);
9309 	}
9310 #endif /* AUTOMOTIVE_FEATURE */
9311 #endif /* ROAM_API */
9312 #ifdef WES_SUPPORT
9313 	else if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
9314 		bytes_written = wl_android_get_roam_scan_control(net, command, priv_cmd.total_len);
9315 	}
9316 	else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
9317 		bytes_written = wl_android_set_roam_scan_control(net, command);
9318 	}
9319 	else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
9320 		bytes_written = wl_android_get_roam_scan_channels(net, command, priv_cmd.total_len);
9321 	}
9322 	else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
9323 		bytes_written = wl_android_set_roam_scan_channels(net, command);
9324 	}
9325 	else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
9326 		bytes_written = wl_android_send_action_frame(net, command, priv_cmd.total_len);
9327 	}
9328 	else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
9329 		bytes_written = wl_android_reassoc(net, command, priv_cmd.total_len);
9330 	}
9331 	else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
9332 		bytes_written = wl_android_get_scan_channel_time(net, command, priv_cmd.total_len);
9333 	}
9334 	else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
9335 		bytes_written = wl_android_set_scan_channel_time(net, command);
9336 	}
9337 	else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
9338 		bytes_written = wl_android_get_scan_unassoc_time(net, command, priv_cmd.total_len);
9339 	}
9340 	else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
9341 		bytes_written = wl_android_set_scan_unassoc_time(net, command);
9342 	}
9343 	else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
9344 		bytes_written = wl_android_get_scan_passive_time(net, command, priv_cmd.total_len);
9345 	}
9346 	else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
9347 		bytes_written = wl_android_set_scan_passive_time(net, command);
9348 	}
9349 	else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
9350 		bytes_written = wl_android_get_scan_home_time(net, command, priv_cmd.total_len);
9351 	}
9352 	else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
9353 		bytes_written = wl_android_set_scan_home_time(net, command);
9354 	}
9355 	else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
9356 		bytes_written = wl_android_get_scan_home_away_time(net, command,
9357 			priv_cmd.total_len);
9358 	}
9359 	else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
9360 		bytes_written = wl_android_set_scan_home_away_time(net, command);
9361 	}
9362 	else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
9363 		bytes_written = wl_android_get_scan_nprobes(net, command, priv_cmd.total_len);
9364 	}
9365 	else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
9366 		bytes_written = wl_android_set_scan_nprobes(net, command);
9367 	}
9368 	else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
9369 		bytes_written = wl_android_get_scan_dfs_channel_mode(net, command,
9370 			priv_cmd.total_len);
9371 	}
9372 	else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
9373 		bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
9374 	}
9375 	else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
9376 		bytes_written = wl_android_set_join_prefer(net, command);
9377 	}
9378 	else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
9379 		bytes_written = wl_android_get_wes_mode(net, command, priv_cmd.total_len);
9380 	}
9381 	else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
9382 		bytes_written = wl_android_set_wes_mode(net, command);
9383 	}
9384 	else if (strnicmp(command, CMD_GETOKCMODE, strlen(CMD_GETOKCMODE)) == 0) {
9385 		bytes_written = wl_android_get_okc_mode(net, command, priv_cmd.total_len);
9386 	}
9387 	else if (strnicmp(command, CMD_SETOKCMODE, strlen(CMD_SETOKCMODE)) == 0) {
9388 		bytes_written = wl_android_set_okc_mode(net, command);
9389 	}
9390 	else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
9391 		bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
9392 	}
9393 	else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
9394 		bytes_written = wl_android_okc_enable(net, command);
9395 	}
9396 #endif /* WES_SUPPORT */
9397 #ifdef SUPPORT_RESTORE_SCAN_PARAMS
9398 	else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
9399 		bytes_written = wl_android_restore_scan_params(net, command, priv_cmd.total_len);
9400 	}
9401 #endif /* SUPPORT_RESTORE_SCAN_PARAMS */
9402 #ifdef WLTDLS
9403 	else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
9404 		bytes_written = wl_android_tdls_reset(net);
9405 	}
9406 #endif /* WLTDLS */
9407 #ifdef CONFIG_SILENT_ROAM
9408 	else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) {
9409 		int skip = strlen(CMD_SROAM_TURN_ON) + 1;
9410 		bytes_written = wl_android_sroam_turn_on(net, (const char*)command+skip);
9411 	}
9412 	else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) {
9413 		char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1);
9414 		bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len);
9415 	}
9416 	else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) {
9417 		bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len);
9418 	}
9419 #endif /* CONFIG_SILENT_ROAM */
9420 	else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) {
9421 		bytes_written = wl_android_set_disconnect_ies(net, command);
9422 	}
9423 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
9424 
9425 #ifdef PNO_SUPPORT
9426 	else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
9427 		bytes_written = dhd_dev_pno_stop_for_ssid(net);
9428 	}
9429 #ifndef WL_SCHED_SCAN
9430 	else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
9431 		bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
9432 	}
9433 #endif /* !WL_SCHED_SCAN */
9434 	else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
9435 		int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
9436 		bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
9437 	}
9438 	else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
9439 		bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
9440 	}
9441 #endif /* PNO_SUPPORT */
9442 	else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
9443 		bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
9444 	}
9445 	else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
9446 		int skip = strlen(CMD_P2P_SET_NOA) + 1;
9447 		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
9448 			priv_cmd.total_len - skip);
9449 	}
9450 #ifdef P2P_LISTEN_OFFLOADING
9451 	else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
9452 		u8 *sub_command = strchr(command, ' ');
9453 		bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
9454 				sub_command ? strlen(sub_command) : 0);
9455 	}
9456 #endif /* P2P_LISTEN_OFFLOADING */
9457 #if !defined WL_ENABLE_P2P_IF
9458 	else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
9459 		bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
9460 	}
9461 #endif /* WL_ENABLE_P2P_IF */
9462 	else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
9463 		int skip = strlen(CMD_P2P_SET_PS) + 1;
9464 		bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
9465 			priv_cmd.total_len - skip);
9466 	}
9467 	else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
9468 		int skip = strlen(CMD_P2P_ECSA) + 1;
9469 		bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
9470 			priv_cmd.total_len - skip);
9471 	}
9472 	else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
9473 		int skip = strlen(CMD_P2P_INC_BW) + 1;
9474 		bytes_written = wl_cfg80211_increase_p2p_bw(net,
9475 				command + skip, priv_cmd.total_len - skip);
9476 	}
9477 #ifdef WL_CFG80211
9478 	else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
9479 		strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
9480 		int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
9481 		bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
9482 			priv_cmd.total_len - skip, *(command + skip - 2) - '0');
9483 	}
9484 #ifdef WLFBT
9485 	else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
9486 		bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
9487 	}
9488 #endif /* WLFBT */
9489 #endif /* WL_CFG80211 */
9490 #if defined(WL_SUPPORT_AUTO_CHANNEL)
9491 	else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
9492 		strlen(CMD_GET_BEST_CHANNELS)) == 0) {
9493 		bytes_written = wl_cfg80211_get_best_channels(net, command,
9494 			priv_cmd.total_len);
9495 	}
9496 #endif /* WL_SUPPORT_AUTO_CHANNEL */
9497 #if defined(WL_SUPPORT_AUTO_CHANNEL)
9498 	else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
9499 		strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
9500 		int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
9501 		bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
9502 			priv_cmd.total_len);
9503 	}
9504 #endif /* WL_SUPPORT_AUTO_CHANNEL */
9505 #ifdef CUSTOMER_HW4_PRIVATE_CMD
9506 #ifdef SUPPORT_AMPDU_MPDU_CMD
9507 	/* CMD_AMPDU_MPDU */
9508 	else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
9509 		int skip = strlen(CMD_AMPDU_MPDU) + 1;
9510 		bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
9511 	}
9512 #endif /* SUPPORT_AMPDU_MPDU_CMD */
9513 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
9514 	else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
9515 		strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
9516 		int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
9517 		wl_android_sta_diassoc(net, (const char*)command+skip);
9518 	}
9519 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
9520 #ifdef SUPPORT_SET_LPC
9521 	else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
9522 		strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
9523 		int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
9524 		wl_android_set_lpc(net, (const char*)command+skip);
9525 	}
9526 #endif /* SUPPORT_SET_LPC */
9527 #ifdef SUPPORT_TRIGGER_HANG_EVENT
9528 	else if (strnicmp(command, CMD_TEST_FORCE_HANG,
9529 		strlen(CMD_TEST_FORCE_HANG)) == 0) {
9530 		int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
9531 		net_os_send_hang_message_reason(net, (const char*)command+skip);
9532 	}
9533 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
9534 	else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
9535 		bytes_written = wl_android_ch_res_rl(net, true);
9536 	else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
9537 		bytes_written = wl_android_ch_res_rl(net, false);
9538 #ifdef SUPPORT_LTECX
9539 	else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
9540 		int skip = strlen(CMD_LTECX_SET) + 1;
9541 		bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
9542 	}
9543 #endif /* SUPPORT_LTECX */
9544 #ifdef WL_RELMCAST
9545 	else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
9546 		int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
9547 		bytes_written = wl_android_rmc_enable(net, rmc_enable);
9548 	}
9549 	else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
9550 		int rmc_txrate;
9551 		sscanf(command, "%*s %10d", &rmc_txrate);
9552 		bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
9553 	}
9554 	else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
9555 		int actperiod;
9556 		sscanf(command, "%*s %10d", &actperiod);
9557 		bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
9558 	}
9559 	else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
9560 		int acktimeout;
9561 		sscanf(command, "%*s %10d", &acktimeout);
9562 		acktimeout *= 1000;
9563 		bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
9564 	}
9565 	else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
9566 		int skip = strlen(CMD_SET_RMC_LEADER) + 1;
9567 		bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
9568 	}
9569 	else if (strnicmp(command, CMD_SET_RMC_EVENT,
9570 		strlen(CMD_SET_RMC_EVENT)) == 0) {
9571 		bytes_written = wl_android_set_rmc_event(net, command);
9572 	}
9573 #endif /* WL_RELMCAST */
9574 	else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
9575 		bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
9576 	}
9577 	else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
9578 		bytes_written = wl_android_set_singlecore_scan(net, command);
9579 	}
9580 #ifdef TEST_TX_POWER_CONTROL
9581 	else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
9582 		strlen(CMD_TEST_SET_TX_POWER)) == 0) {
9583 		int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
9584 		wl_android_set_tx_power(net, (const char*)command+skip);
9585 	}
9586 	else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
9587 		strlen(CMD_TEST_GET_TX_POWER)) == 0) {
9588 		wl_android_get_tx_power(net, command, priv_cmd.total_len);
9589 	}
9590 #endif /* TEST_TX_POWER_CONTROL */
9591 	else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
9592 		strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
9593 		int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
9594 		bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
9595 	}
9596 #ifdef SUPPORT_SET_TID
9597 	else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
9598 		bytes_written = wl_android_set_tid(net, command);
9599 	}
9600 	else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
9601 		bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
9602 	}
9603 #endif /* SUPPORT_SET_TID */
9604 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
9605 #if defined(SUPPORT_HIDDEN_AP)
9606 	else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
9607 		strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
9608 		int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
9609 		wl_android_set_max_num_sta(net, (const char*)command+skip);
9610 	}
9611 	else if (strnicmp(command, CMD_SET_HAPD_SSID,
9612 		strlen(CMD_SET_HAPD_SSID)) == 0) {
9613 		int skip = strlen(CMD_SET_HAPD_SSID) + 3;
9614 		wl_android_set_ssid(net, (const char*)command+skip);
9615 	}
9616 	else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
9617 		strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
9618 		int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 1;
9619 		wl_android_set_hide_ssid(net, (const char*)(command+skip));
9620 	}
9621 #endif /* SUPPORT_HIDDEN_AP */
9622 #ifdef AUTOMOTIVE_FEATURE
9623 	else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
9624 		int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
9625 		wl_android_set_mac_address_filter(net, command+skip);
9626 	}
9627 #endif /* AUTOMOTIVE_FEATURE */
9628 	else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
9629 		bytes_written = wl_android_set_roam_mode(net, command);
9630 #if defined(BCMFW_ROAM_ENABLE)
9631 	else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
9632 		bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
9633 	}
9634 #endif /* BCMFW_ROAM_ENABLE */
9635 	else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
9636 		bytes_written = wl_android_set_miracast(net, command);
9637 	else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
9638 		bytes_written = wl_android_set_ibss_beacon_ouidata(net,
9639 		command, priv_cmd.total_len);
9640 #ifdef WLAIBSS
9641 	else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
9642 		strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
9643 		bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
9644 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
9645 		strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
9646 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
9647 			TRUE);
9648 	else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
9649 		strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
9650 		bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
9651 			FALSE);
9652 	else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
9653 		strlen(CMD_SETIBSSROUTETABLE)) == 0)
9654 		bytes_written = wl_android_set_ibss_routetable(net, command);
9655 	else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
9656 		bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
9657 	else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
9658 		bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
9659 #endif /* WLAIBSS */
9660 	else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
9661 		int skip = strlen(CMD_KEEP_ALIVE) + 1;
9662 		bytes_written = wl_keep_alive_set(net, command + skip);
9663 	}
9664 	else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
9665 		int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
9666 		bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
9667 	}
9668 	else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
9669 		char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
9670 		WL_INFORM(("Creating %s interface\n", name));
9671 		if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
9672 				name, NULL) == NULL) {
9673 			bytes_written = -ENODEV;
9674 		} else {
9675 			/* Return success */
9676 			bytes_written = 0;
9677 		}
9678 	}
9679 	else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
9680 		char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
9681 		WL_INFORM(("Deleteing %s interface\n", name));
9682 		bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
9683 	}
9684 	else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
9685 		bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
9686 	}
9687 #ifdef P2PRESP_WFDIE_SRC
9688 	else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
9689 		strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
9690 		int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
9691 		bytes_written = wl_android_set_wfdie_resp(net, mode);
9692 	} else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
9693 		strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
9694 		bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
9695 	}
9696 #endif /* P2PRESP_WFDIE_SRC */
9697 	else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
9698 		char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
9699 		bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
9700 	}
9701 #ifdef WBTEXT
9702 	else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
9703 		bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
9704 	}
9705 	else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
9706 			strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
9707 		char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
9708 		bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
9709 	}
9710 	else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
9711 			strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
9712 		char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
9713 		bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
9714 				command, priv_cmd.total_len);
9715 	}
9716 	else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
9717 			strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
9718 		char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
9719 		bytes_written = wl_cfg80211_wbtext_table_config(net, data,
9720 				command, priv_cmd.total_len);
9721 	}
9722 	else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
9723 			strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
9724 		char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
9725 		bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
9726 				command, priv_cmd.total_len);
9727 	}
9728 	else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
9729 			strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
9730 		bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
9731 			priv_cmd.total_len);
9732 	}
9733 	else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
9734 			strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
9735 		bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
9736 			priv_cmd.total_len);
9737 	}
9738 	else if (strnicmp(command, CMD_WBTEXT_ESTM_ENABLE,
9739 			strlen(CMD_WBTEXT_ESTM_ENABLE)) == 0) {
9740 		bytes_written = wl_cfg80211_wbtext_estm_enable(net, command,
9741 			priv_cmd.total_len);
9742 	}
9743 #endif /* WBTEXT */
9744 #ifdef SET_RPS_CPUS
9745 	else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) {
9746 		bytes_written = wl_android_set_rps_cpus(net, command);
9747 	}
9748 #endif /* SET_RPS_CPUS */
9749 #ifdef WLWFDS
9750 	else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
9751 		bytes_written = wl_android_set_wfds_hash(net, command, 1);
9752 	}
9753 	else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
9754 		bytes_written = wl_android_set_wfds_hash(net, command, 0);
9755 	}
9756 #endif /* WLWFDS */
9757 #ifdef BT_WIFI_HANDOVER
9758 	else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
9759 	    bytes_written = wl_tbow_teardown(net);
9760 	}
9761 #endif /* BT_WIFI_HANDOVER */
9762 #ifdef CUSTOMER_HW4_PRIVATE_CMD
9763 #ifdef FCC_PWR_LIMIT_2G
9764 	else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
9765 		strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
9766 		bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
9767 	}
9768 	else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
9769 		strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
9770 		bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
9771 	}
9772 #endif /* FCC_PWR_LIMIT_2G */
9773 	else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
9774 		bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
9775 	}
9776 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
9777 	else if (strnicmp(command, CMD_MURX_BFE_CAP,
9778 			strlen(CMD_MURX_BFE_CAP)) == 0) {
9779 #ifdef WL_MURX
9780 		uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
9781 		bytes_written = wl_android_murx_bfe_cap(net, val);
9782 #else
9783 		return BCME_UNSUPPORTED;
9784 #endif /* WL_MURX */
9785 	}
9786 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
9787 	else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
9788 		bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
9789 	}
9790 	else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
9791 		bytes_written = wl_android_set_ap_beaconrate(net, command);
9792 	}
9793 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
9794 #ifdef SUPPORT_AP_RADIO_PWRSAVE
9795 	else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
9796 		bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
9797 	}
9798 	else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
9799 		bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
9800 	}
9801 	else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
9802 		bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
9803 	}
9804 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
9805 #ifdef SUPPORT_RSSI_SUM_REPORT
9806 	else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
9807 		bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
9808 	}
9809 	else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
9810 		bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
9811 	}
9812 	else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
9813 		bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
9814 	}
9815 #endif /* SUPPORT_RSSI_SUM_REPORT */
9816 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
9817 	else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
9818 		bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
9819 	}
9820 	else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
9821 			== 0) {
9822 		bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
9823 				priv_cmd.total_len);
9824 	}
9825 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
9826 #if defined(SUPPORT_RANDOM_MAC_SCAN)
9827 	else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
9828 		bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
9829 	} else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
9830 		bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
9831 	}
9832 #endif /* SUPPORT_RANDOM_MAC_SCAN */
9833 #ifdef DHD_BANDSTEER
9834 	else if (strnicmp(command, CMD_BANDSTEER, strlen(CMD_BANDSTEER)) == 0) {
9835 		bytes_written = wl_android_set_bandsteer(net, command, priv_cmd.total_len);
9836 	}
9837 	else if (strnicmp(command, CMD_BANDSTEER_TRIGGER, strlen(CMD_BANDSTEER_TRIGGER)) == 0) {
9838 		uint8 *p = command + strlen(CMD_BANDSTEER_TRIGGER)+1;
9839 		struct ether_addr ea;
9840 		char eabuf[ETHER_ADDR_STR_LEN];
9841 		bytes_written = 0;
9842 
9843 		bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
9844 		strncpy(eabuf, p, ETHER_ADDR_STR_LEN - 1);
9845 
9846 		if (!bcm_ether_atoe(eabuf, &ea)) {
9847 			DHD_ERROR(("BANDSTEER: ERROR while parsing macaddr cmd %s - ignored\n",
9848 					command));
9849 			return BCME_BADARG;
9850 		}
9851 		bytes_written = dhd_bandsteer_trigger_bandsteer(net, ea.octet);
9852 	}
9853 #endif /* DHD_BANDSTEER */
9854 #ifdef ENABLE_HOGSQS
9855 	else if (strnicmp(command, CMD_AP_HOGSQS, strlen(CMD_AP_HOGSQS)) == 0) {
9856 		bytes_written = wl_android_hogsqs(net, command, priv_cmd.total_len);
9857 	}
9858 #endif /* ENABLE_HOGSQS */
9859 #ifdef WL_NATOE
9860 	else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
9861 		bytes_written = wl_android_process_natoe_cmd(net, command,
9862 				priv_cmd.total_len);
9863 	}
9864 #endif /* WL_NATOE */
9865 #ifdef CONNECTION_STATISTICS
9866 	else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
9867 		strlen(CMD_GET_CONNECTION_STATS)) == 0) {
9868 		bytes_written = wl_android_get_connection_stats(net, command,
9869 			priv_cmd.total_len);
9870 	}
9871 #endif // endif
9872 #ifdef DHD_LOG_DUMP
9873 	else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
9874 		strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
9875 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9876 		/* check whether it has more command */
9877 		if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
9878 			/* compare unwanted/disconnected command */
9879 			if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
9880 				SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
9881 				dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
9882 			} else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
9883 				SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
9884 				dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
9885 			} else {
9886 				dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
9887 			}
9888 		} else {
9889 			dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
9890 		}
9891 	}
9892 #endif /* DHD_LOG_DUMP */
9893 #ifdef DHD_STATUS_LOGGING
9894 	else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) {
9895 		dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
9896 	}
9897 	else if (strnicmp(command, CMD_QUERY_STATUS_LOG, strlen(CMD_QUERY_STATUS_LOG)) == 0) {
9898 		dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9899 		bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
9900 	}
9901 #endif /* DHD_STATUS_LOGGING */
9902 #ifdef SET_PCIE_IRQ_CPU_CORE
9903 	else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
9904 		int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
9905 		wl_android_set_irq_cpucore(net, affinity_cmd);
9906 	}
9907 #endif /* SET_PCIE_IRQ_CPU_CORE */
9908 #if defined(DHD_HANG_SEND_UP_TEST)
9909 	else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
9910 		int skip = strlen(CMD_MAKE_HANG) + 1;
9911 		wl_android_make_hang_with_reason(net, (const char*)command+skip);
9912 	}
9913 #endif /* DHD_HANG_SEND_UP_TEST */
9914 #ifdef SUPPORT_LQCM
9915 	else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
9916 		int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
9917 		bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
9918 	}
9919 	else if (strnicmp(command, CMD_GET_LQCM_REPORT,
9920 			strlen(CMD_GET_LQCM_REPORT)) == 0) {
9921 		bytes_written = wl_android_get_lqcm_report(net, command,
9922 			priv_cmd.total_len);
9923 	}
9924 #endif // endif
9925 	else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
9926 		bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
9927 	}
9928 #ifdef WLADPS_PRIVATE_CMD
9929 	else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
9930 		int skip = strlen(CMD_SET_ADPS) + 1;
9931 		bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
9932 	}
9933 	else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
9934 		bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
9935 	}
9936 #endif /* WLADPS_PRIVATE_CMD */
9937 #ifdef DHD_PKT_LOGGING
9938 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
9939 		strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
9940 		bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
9941 	}
9942 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
9943 		strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
9944 		bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
9945 	}
9946 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
9947 		strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
9948 		bytes_written =
9949 			wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
9950 	}
9951 	else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
9952 		strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
9953 		bytes_written =
9954 			wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
9955 	}
9956 	else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
9957 		bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
9958 	}
9959 	else if (strnicmp(command, CMD_PKTLOG_FILTER_DEL, strlen(CMD_PKTLOG_FILTER_DEL)) == 0) {
9960 		bytes_written = wl_android_pktlog_filter_del(net, command, priv_cmd.total_len);
9961 	}
9962 	else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
9963 		bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
9964 	}
9965 	else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
9966 		bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
9967 	}
9968 	else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
9969 		bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
9970 	}
9971 	else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
9972 		bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
9973 	}
9974 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
9975 		strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
9976 		bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
9977 	}
9978 	else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
9979 		strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
9980 		bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
9981 	}
9982 	else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
9983 		strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
9984 		bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
9985 	}
9986 #endif /* DHD_PKT_LOGGING */
9987 	else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
9988 		int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
9989 		bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
9990 	}
9991 #ifdef DHD_EVENT_LOG_FILTER
9992 	else if (strnicmp(command, CMD_EWP_FILTER,
9993 		strlen(CMD_EWP_FILTER)) == 0) {
9994 		bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
9995 	}
9996 #endif /* DHD_EVENT_LOG_FILTER */
9997 #ifdef WL_BCNRECV
9998 	else if (strnicmp(command, CMD_BEACON_RECV,
9999 		strlen(CMD_BEACON_RECV)) == 0) {
10000 		char *data = (command + strlen(CMD_BEACON_RECV) + 1);
10001 		bytes_written = wl_android_bcnrecv_config(net,
10002 				data, priv_cmd.total_len);
10003 	}
10004 #endif /* WL_BCNRECV */
10005 #ifdef WL_MBO
10006 	else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
10007 		bytes_written = wl_android_process_mbo_cmd(net, command,
10008 			priv_cmd.total_len);
10009 	}
10010 #endif /* WL_MBO */
10011 #ifdef WL_CAC_TS
10012 	else if (strnicmp(command, CMD_CAC_TSPEC,
10013 		strlen(CMD_CAC_TSPEC)) == 0) {
10014 		char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
10015 		bytes_written = wl_android_cac_ts_config(net,
10016 				data, priv_cmd.total_len);
10017 	}
10018 #endif /* WL_CAC_TS */
10019 #ifdef WL_GET_CU
10020 	else if (strnicmp(command, CMD_GET_CHAN_UTIL,
10021 		strlen(CMD_GET_CHAN_UTIL)) == 0) {
10022 		bytes_written = wl_android_get_channel_util(net,
10023 			command, priv_cmd.total_len);
10024 	}
10025 #endif /* WL_GET_CU */
10026 	else if (strnicmp(command, CMD_CHANNEL_WIDTH, strlen(CMD_CHANNEL_WIDTH)) == 0) {
10027 		bytes_written = wl_android_set_channel_width(net, command, priv_cmd.total_len);
10028 	}
10029 	else if (strnicmp(command, CMD_TRANSITION_DISABLE, strlen(CMD_TRANSITION_DISABLE)) == 0) {
10030 		int transition_disabled = *(command + strlen(CMD_TRANSITION_DISABLE) + 1) - '0';
10031 		bytes_written = wl_cfg80211_set_transition_mode(net, transition_disabled);
10032 	}
10033 	else {
10034 		DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
10035 		bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
10036 	}
10037 
10038 	return bytes_written;
10039 }
10040 
wl_android_init(void)10041 int wl_android_init(void)
10042 {
10043 	int ret = 0;
10044 
10045 #ifdef ENABLE_INSMOD_NO_FW_LOAD
10046 	dhd_download_fw_on_driverload = FALSE;
10047 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
10048 	if (!iface_name[0]) {
10049 		bzero(iface_name, IFNAMSIZ);
10050 		bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
10051 	}
10052 
10053 #ifdef CUSTOMER_HW4_DEBUG
10054 	g_assert_type = 1;
10055 #endif /* CUSTOMER_HW4_DEBUG */
10056 
10057 #ifdef WL_GENL
10058 	wl_genl_init();
10059 #endif // endif
10060 	wl_netlink_init();
10061 
10062 	return ret;
10063 }
10064 
wl_android_exit(void)10065 int wl_android_exit(void)
10066 {
10067 	int ret = 0;
10068 	struct io_cfg *cur, *q;
10069 
10070 #ifdef WL_GENL
10071 	wl_genl_deinit();
10072 #endif /* WL_GENL */
10073 	wl_netlink_deinit();
10074 
10075 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
10076 	list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
10077 		GCC_DIAGNOSTIC_POP();
10078 		list_del(&cur->list);
10079 		kfree(cur);
10080 	}
10081 
10082 	return ret;
10083 }
10084 
wl_android_post_init(void)10085 void wl_android_post_init(void)
10086 {
10087 
10088 #ifdef ENABLE_4335BT_WAR
10089 	bcm_bt_unlock(lock_cookie_wifi);
10090 	printk("wl_android_post_init: btlock released\n");
10091 #endif /* ENABLE_4335BT_WAR */
10092 
10093 	if (!dhd_download_fw_on_driverload)
10094 		g_wifi_on = FALSE;
10095 }
10096 
10097 #ifdef WL_GENL
10098 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
10099 static int
wl_genl_register_family_with_ops_groups(struct genl_family * family,const struct genl_ops * ops,size_t n_ops,const struct genl_multicast_group * mcgrps,size_t n_mcgrps)10100 wl_genl_register_family_with_ops_groups(struct genl_family *family,
10101 	const struct genl_ops *ops, size_t n_ops,
10102 	const struct genl_multicast_group *mcgrps,
10103 	size_t n_mcgrps)
10104 {
10105 	family->module = THIS_MODULE;
10106 	family->ops = ops;
10107 	family->n_ops = n_ops;
10108 	family->mcgrps = mcgrps;
10109 	family->n_mcgrps = n_mcgrps;
10110 	return genl_register_family(family);
10111 }
10112 #endif // endif
10113 
10114 /* Generic Netlink Initializaiton */
wl_genl_init(void)10115 static int wl_genl_init(void)
10116 {
10117 	int ret;
10118 
10119 	WL_DBG(("GEN Netlink Init\n\n"));
10120 
10121 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
10122 	/* register new family */
10123 	ret = genl_register_family(&wl_genl_family);
10124 	if (ret != 0)
10125 		goto failure;
10126 
10127 	/* register functions (commands) of the new family */
10128 	ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
10129 	if (ret != 0) {
10130 		WL_ERR(("register ops failed: %i\n", ret));
10131 		genl_unregister_family(&wl_genl_family);
10132 		goto failure;
10133 	}
10134 
10135 	ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
10136 #elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) && \
10137 	(LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)))
10138 	ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
10139 #else
10140 	ret = wl_genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops,
10141 		ARRAY_SIZE(wl_genl_ops), wl_genl_mcast, ARRAY_SIZE(wl_genl_mcast));
10142 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
10143 	if (ret != 0) {
10144 		WL_ERR(("register mc_group failed: %i\n", ret));
10145 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
10146 		genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
10147 #endif // endif
10148 		genl_unregister_family(&wl_genl_family);
10149 		goto failure;
10150 	}
10151 
10152 	return 0;
10153 
10154 failure:
10155 	WL_ERR(("Registering Netlink failed!!\n"));
10156 	return -1;
10157 }
10158 
10159 /* Generic netlink deinit */
wl_genl_deinit(void)10160 static int wl_genl_deinit(void)
10161 {
10162 
10163 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
10164 	if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
10165 		WL_ERR(("Unregister wl_genl_ops failed\n"));
10166 #endif // endif
10167 	if (genl_unregister_family(&wl_genl_family) < 0)
10168 		WL_ERR(("Unregister wl_genl_ops failed\n"));
10169 
10170 	return 0;
10171 }
10172 
wl_event_to_bcm_event(u16 event_type)10173 s32 wl_event_to_bcm_event(u16 event_type)
10174 {
10175 	u16 event = -1;
10176 
10177 	switch (event_type) {
10178 		case WLC_E_SERVICE_FOUND:
10179 			event = BCM_E_SVC_FOUND;
10180 			break;
10181 		case WLC_E_P2PO_ADD_DEVICE:
10182 			event = BCM_E_DEV_FOUND;
10183 			break;
10184 		case WLC_E_P2PO_DEL_DEVICE:
10185 			event = BCM_E_DEV_LOST;
10186 			break;
10187 	/* Above events are supported from BCM Supp ver 47 Onwards */
10188 #ifdef BT_WIFI_HANDOVER
10189 		case WLC_E_BT_WIFI_HANDOVER_REQ:
10190 			event = BCM_E_DEV_BT_WIFI_HO_REQ;
10191 			break;
10192 #endif /* BT_WIFI_HANDOVER */
10193 
10194 		default:
10195 			WL_ERR(("Event not supported\n"));
10196 	}
10197 
10198 	return event;
10199 }
10200 
10201 s32
wl_genl_send_msg(struct net_device * ndev,u32 event_type,const u8 * buf,u16 len,u8 * subhdr,u16 subhdr_len)10202 wl_genl_send_msg(
10203 	struct net_device *ndev,
10204 	u32 event_type,
10205 	const u8 *buf,
10206 	u16 len,
10207 	u8 *subhdr,
10208 	u16 subhdr_len)
10209 {
10210 	int ret = 0;
10211 	struct sk_buff *skb;
10212 	void *msg;
10213 	u32 attr_type = 0;
10214 	bcm_event_hdr_t *hdr = NULL;
10215 	int mcast = 1; /* By default sent as mutlicast type */
10216 	int pid = 0;
10217 	u8 *ptr = NULL, *p = NULL;
10218 	u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
10219 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10220 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10221 
10222 	WL_DBG(("Enter \n"));
10223 
10224 	/* Decide between STRING event and Data event */
10225 	if (event_type == 0)
10226 		attr_type = BCM_GENL_ATTR_STRING;
10227 	else
10228 		attr_type = BCM_GENL_ATTR_MSG;
10229 
10230 	skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
10231 	if (skb == NULL) {
10232 		ret = -ENOMEM;
10233 		goto out;
10234 	}
10235 
10236 	msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
10237 	if (msg == NULL) {
10238 		ret = -ENOMEM;
10239 		goto out;
10240 	}
10241 
10242 	if (attr_type == BCM_GENL_ATTR_STRING) {
10243 		/* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
10244 		 * make sure it is null terminated
10245 		 */
10246 		if (subhdr || subhdr_len) {
10247 			WL_ERR(("No sub hdr support for the ATTR STRING type \n"));
10248 			ret =  -EINVAL;
10249 			goto out;
10250 		}
10251 
10252 		ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
10253 		if (ret != 0) {
10254 			WL_ERR(("nla_put_string failed\n"));
10255 			goto out;
10256 		}
10257 	} else {
10258 		/* ATTR_MSG */
10259 
10260 		/* Create a single buffer for all */
10261 		p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
10262 		if (!ptr) {
10263 			ret = -ENOMEM;
10264 			WL_ERR(("ENOMEM!!\n"));
10265 			goto out;
10266 		}
10267 
10268 		/* Include the bcm event header */
10269 		hdr = (bcm_event_hdr_t *)ptr;
10270 		hdr->event_type = wl_event_to_bcm_event(event_type);
10271 		hdr->len = len + subhdr_len;
10272 		ptr += sizeof(bcm_event_hdr_t);
10273 
10274 		/* Copy subhdr (if any) */
10275 		if (subhdr && subhdr_len) {
10276 			memcpy(ptr, subhdr, subhdr_len);
10277 			ptr += subhdr_len;
10278 		}
10279 
10280 		/* Copy the data */
10281 		if (buf && len) {
10282 			memcpy(ptr, buf, len);
10283 		}
10284 
10285 		ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
10286 		if (ret != 0) {
10287 			WL_ERR(("nla_put_string failed\n"));
10288 			goto out;
10289 		}
10290 	}
10291 
10292 	if (mcast) {
10293 		int err = 0;
10294 		/* finalize the message */
10295 		genlmsg_end(skb, msg);
10296 		/* NETLINK_CB(skb).dst_group = 1; */
10297 
10298 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
10299 		if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
10300 #else
10301 		if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
10302 #endif // endif
10303 			WL_ERR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
10304 				attr_type, err));
10305 		else
10306 			WL_DBG(("Multicast msg sent successfully. attr_type:%d len:%d \n",
10307 				attr_type, tot_len));
10308 	} else {
10309 		NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
10310 
10311 		/* finalize the message */
10312 		genlmsg_end(skb, msg);
10313 
10314 		/* send the message back */
10315 		if (genlmsg_unicast(&init_net, skb, pid) < 0)
10316 			WL_ERR(("genlmsg_unicast failed\n"));
10317 	}
10318 
10319 out:
10320 	if (p) {
10321 		MFREE(cfg->osh, p, tot_len);
10322 	}
10323 	if (ret)
10324 		nlmsg_free(skb);
10325 
10326 	return ret;
10327 }
10328 
10329 static s32
wl_genl_handle_msg(struct sk_buff * skb,struct genl_info * info)10330 wl_genl_handle_msg(
10331 	struct sk_buff *skb,
10332 	struct genl_info *info)
10333 {
10334 	struct nlattr *na;
10335 	u8 *data = NULL;
10336 
10337 	WL_DBG(("Enter \n"));
10338 
10339 	if (info == NULL) {
10340 		return -EINVAL;
10341 	}
10342 
10343 	na = info->attrs[BCM_GENL_ATTR_MSG];
10344 	if (!na) {
10345 		WL_ERR(("nlattribute NULL\n"));
10346 		return -EINVAL;
10347 	}
10348 
10349 	data = (char *)nla_data(na);
10350 	if (!data) {
10351 		WL_ERR(("Invalid data\n"));
10352 		return -EINVAL;
10353 	} else {
10354 		/* Handle the data */
10355 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS)
10356 		WL_DBG(("%s: Data received from pid (%d) \n", __func__,
10357 			info->snd_pid));
10358 #else
10359 		WL_DBG(("%s: Data received from pid (%d) \n", __func__,
10360 			info->snd_portid));
10361 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
10362 	}
10363 
10364 	return 0;
10365 }
10366 #endif /* WL_GENL */
10367 
wl_fatal_error(void * wl,int rc)10368 int wl_fatal_error(void * wl, int rc)
10369 {
10370 	return FALSE;
10371 }
10372 
10373 #if defined(BT_OVER_SDIO)
10374 void
wl_android_set_wifi_on_flag(bool enable)10375 wl_android_set_wifi_on_flag(bool enable)
10376 {
10377 	g_wifi_on = enable;
10378 }
10379 #endif /* BT_OVER_SDIO */
10380 
10381 #ifdef WL_STATIC_IF
10382 struct net_device *
wl_cfg80211_register_static_if(struct bcm_cfg80211 * cfg,u16 iftype,char * ifname,int ifidx)10383 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname, int ifidx)
10384 {
10385 	struct net_device *ndev;
10386 	struct wireless_dev *wdev = NULL;
10387 	u8 mac_addr[ETH_ALEN];
10388 	struct net_device *primary_ndev;
10389 
10390 	WL_INFORM_MEM(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
10391 
10392 	if (!cfg) {
10393 		WL_ERR(("cfg null\n"));
10394 		return NULL;
10395 	}
10396 
10397 	/* Use primary mac with locally admin bit set */
10398 	primary_ndev = bcmcfg_to_prmry_ndev(cfg);
10399 	(void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
10400 	mac_addr[0] |= 0x02;
10401 
10402 	ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
10403 		WL_BSSIDX_MAX, NULL);
10404 	if (unlikely(!ndev)) {
10405 		WL_ERR(("Failed to allocate static_if\n"));
10406 		goto fail;
10407 	}
10408 	wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
10409 	if (unlikely(!wdev)) {
10410 		WL_ERR(("Failed to allocate wdev for static_if\n"));
10411 		goto fail;
10412 	}
10413 
10414 	wdev->wiphy = cfg->wdev->wiphy;
10415 	wdev->iftype = iftype;
10416 
10417 	ndev->ieee80211_ptr = wdev;
10418 	SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
10419 	wdev->netdev = ndev;
10420 
10421 	if (wl_cfg80211_register_if(cfg, ifidx,
10422 		ndev, TRUE) != BCME_OK) {
10423 		WL_ERR(("ndev registration failed!\n"));
10424 		goto fail;
10425 	}
10426 
10427 	cfg->static_ndev[ifidx - DHD_MAX_IFS] = ndev;
10428 	cfg->static_ndev_state[ifidx - DHD_MAX_IFS] = NDEV_STATE_OS_IF_CREATED;
10429 	wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
10430 		ifname, NDEV_STATE_OS_IF_CREATED);
10431 	WL_INFORM_MEM(("Static I/F (%s) Registered\n", ndev->name));
10432 	return ndev;
10433 
10434 fail:
10435 	wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
10436 	return NULL;
10437 }
10438 
10439 void
wl_cfg80211_unregister_static_if(struct bcm_cfg80211 * cfg)10440 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
10441 {
10442 	int i = 0;
10443 	WL_INFORM_MEM(("[STATIC_IF] Enter\n"));
10444 	for (i = 0; i < DHD_NUM_STATIC_IFACES; i++) {
10445 		if (!cfg || !cfg->static_ndev[i]) {
10446 			WL_ERR(("invalid input\n"));
10447 			continue;
10448 		}
10449 
10450 		/* wdev free will happen from notifier context */
10451 		/* free_netdev(cfg->static_ndev);
10452 		*/
10453 		unregister_netdev(cfg->static_ndev[i]);
10454 	}
10455 }
10456 
10457 s32
wl_cfg80211_static_if_open(struct net_device * net)10458 wl_cfg80211_static_if_open(struct net_device *net)
10459 {
10460 	struct wireless_dev *wdev = NULL;
10461 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
10462 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
10463 	u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
10464 	u16 wl_iftype, wl_mode;
10465 
10466 	WL_INFORM_MEM(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
10467 	ASSERT(is_static_iface(cfg, net));
10468 
10469 	if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) <  0) {
10470 		return BCME_ERROR;
10471 	}
10472 	if (static_if_ndev_get_state(cfg, net) != NDEV_STATE_FW_IF_CREATED) {
10473 		wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, NULL);
10474 		if (!wdev) {
10475 			WL_ERR(("[STATIC_IF] wdev is NULL, can't proceed"));
10476 			return BCME_ERROR;
10477 		}
10478 	} else {
10479 		WL_INFORM_MEM(("Fw IF for static netdev already created\n"));
10480 	}
10481 
10482 	return BCME_OK;
10483 }
10484 
10485 s32
wl_cfg80211_static_if_close(struct net_device * net)10486 wl_cfg80211_static_if_close(struct net_device *net)
10487 {
10488 	int ret = BCME_OK;
10489 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
10490 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
10491 
10492 	if (static_if_ndev_get_state(cfg, net) == NDEV_STATE_FW_IF_CREATED) {
10493 		if (mutex_is_locked(&cfg->if_sync) == TRUE) {
10494 			ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
10495 		} else {
10496 			ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
10497 		}
10498 
10499 		if (unlikely(ret)) {
10500 			WL_ERR(("Del iface failed for static_if %d\n", ret));
10501 		}
10502 	}
10503 
10504 	return ret;
10505 }
10506 struct net_device *
wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 * cfg,wl_if_event_info * event,u8 * addr,s32 iface_type,const char * iface_name)10507 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
10508 	wl_if_event_info *event, u8 *addr, s32 iface_type, const char *iface_name)
10509 {
10510 	struct net_device *new_ndev = NULL;
10511 	struct wireless_dev *wdev = NULL;
10512 
10513 	int iface_num = 0;
10514 	/* Checks if iface number returned is valid or not */
10515 	if ((iface_num = get_iface_num(iface_name, cfg)) < 0) {
10516 		return NULL;
10517 	}
10518 
10519 	WL_INFORM_MEM(("Updating static iface after Fw IF create \n"));
10520 
10521 	new_ndev = cfg->static_ndev[iface_num];
10522 	if (new_ndev) {
10523 		wdev = new_ndev->ieee80211_ptr;
10524 		ASSERT(wdev);
10525 		wdev->iftype = iface_type;
10526 		(void)memcpy_s(new_ndev->dev_addr, ETH_ALEN, addr, ETH_ALEN);
10527 	}
10528 
10529 	cfg->static_ndev_state[iface_num] = NDEV_STATE_FW_IF_CREATED;
10530 	wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
10531 		event->name, NDEV_STATE_FW_IF_CREATED);
10532 	return new_ndev;
10533 }
10534 s32
wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 * cfg,struct net_device * ndev)10535 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
10536 {
10537 	int iface_num = 0;
10538 	if ((iface_num = get_iface_num(ndev->name, cfg)) < 0) {
10539 		return BCME_ERROR;
10540 	}
10541 
10542 	cfg->static_ndev_state[iface_num] = NDEV_STATE_FW_IF_DELETED;
10543 	wl_cfg80211_update_iflist_info(cfg, ndev, (DHD_MAX_IFS + iface_num), NULL,
10544 	WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
10545 	wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
10546 	wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
10547 	return BCME_OK;
10548 }
10549 #endif /* WL_STATIC_IF */
10550 
10551 #ifdef WBTEXT
10552 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)10553 wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
10554 	uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size)
10555 {
10556 	int err = BCME_OK;
10557 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10558 	u8 *ioctl_buf = NULL;
10559 
10560 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
10561 	if (unlikely(!ioctl_buf)) {
10562 		WL_ERR(("%s: failed to allocate memory\n", __func__));
10563 		err =  -ENOMEM;
10564 		goto exit;
10565 	}
10566 	rp->v1.band = band;
10567 	rp->v1.len = 0;
10568 	/* Getting roam profile from fw */
10569 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
10570 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
10571 		WL_ERR(("Getting roam_profile failed with err=%d \n", err));
10572 		goto exit;
10573 	}
10574 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
10575 	/* roam_prof version get */
10576 	if (rp->v1.ver > WL_ROAM_PROF_VER_2) {
10577 		WL_ERR(("bad version (=%d) in return data\n", rp->v1.ver));
10578 		err = BCME_VERSION;
10579 		goto exit;
10580 	}
10581 	switch (rp->v1.ver) {
10582 		case WL_ROAM_PROF_VER_0:
10583 		{
10584 			*roam_prof_size = sizeof(wl_roam_prof_v1_t);
10585 			*roam_prof_ver = WL_ROAM_PROF_VER_0;
10586 		}
10587 		break;
10588 		case WL_ROAM_PROF_VER_1:
10589 		{
10590 			*roam_prof_size = sizeof(wl_roam_prof_v2_t);
10591 			*roam_prof_ver = WL_ROAM_PROF_VER_1;
10592 		}
10593 		break;
10594 		case WL_ROAM_PROF_VER_2:
10595 		{
10596 			*roam_prof_size = sizeof(wl_roam_prof_v3_t);
10597 			*roam_prof_ver = WL_ROAM_PROF_VER_2;
10598 		}
10599 		break;
10600 		default:
10601 			WL_ERR(("bad version = %d \n", rp->v1.ver));
10602 			err = BCME_VERSION;
10603 			goto exit;
10604 	}
10605 	WL_DBG(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size));
10606 	if ((rp->v1.len % *roam_prof_size) != 0) {
10607 		WL_ERR(("bad length (=%d) in return data\n", rp->v1.len));
10608 		err = BCME_BADLEN;
10609 	}
10610 exit:
10611 	if (ioctl_buf) {
10612 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
10613 	}
10614 	return err;
10615 }
10616 
10617 s32
wl_cfg80211_wbtext_set_default(struct net_device * ndev)10618 wl_cfg80211_wbtext_set_default(struct net_device *ndev)
10619 {
10620 	char *commandp = NULL;
10621 	s32 ret = BCME_OK;
10622 	char *data;
10623 	u8 *ioctl_buf = NULL;
10624 	wl_roamprof_band_t rp;
10625 	uint8 bandidx = 0;
10626 	int wnmmask = 0;
10627 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10628 
10629 	WL_DBG(("set wbtext to default\n"));
10630 
10631 	commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
10632 	if (unlikely(!commandp)) {
10633 		WL_ERR(("%s: failed to allocate memory\n", __func__));
10634 		ret =  -ENOMEM;
10635 		goto exit;
10636 	}
10637 	ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
10638 	if (unlikely(!ioctl_buf)) {
10639 		WL_ERR(("%s: failed to allocate memory\n", __func__));
10640 		ret =  -ENOMEM;
10641 		goto exit;
10642 	}
10643 
10644 	rp.v1.band = WLC_BAND_2G;
10645 	rp.v1.len = 0;
10646 	/* Getting roam profile from fw */
10647 	if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp),
10648 		ioctl_buf, WLC_IOCTL_SMLEN, NULL))) {
10649 		WL_ERR(("Getting roam_profile failed with err=%d \n", ret));
10650 		goto exit;
10651 	}
10652 	memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp));
10653 	for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
10654 		switch (rp.v1.ver) {
10655 			case WL_ROAM_PROF_VER_1:
10656 			{
10657 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10658 				if (bandidx == BAND_5G_INDEX) {
10659 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10660 						CMD_WBTEXT_PROFILE_CONFIG,
10661 						DEFAULT_WBTEXT_PROFILE_A_V2);
10662 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
10663 				} else {
10664 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10665 						CMD_WBTEXT_PROFILE_CONFIG,
10666 						DEFAULT_WBTEXT_PROFILE_B_V2);
10667 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
10668 				}
10669 			}
10670 			break;
10671 			case WL_ROAM_PROF_VER_2:
10672 			{
10673 				memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10674 				if (bandidx == BAND_5G_INDEX) {
10675 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10676 						CMD_WBTEXT_PROFILE_CONFIG,
10677 						DEFAULT_WBTEXT_PROFILE_A_V3);
10678 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
10679 				} else {
10680 					snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10681 						CMD_WBTEXT_PROFILE_CONFIG,
10682 						DEFAULT_WBTEXT_PROFILE_B_V3);
10683 					data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
10684 				}
10685 			}
10686 			break;
10687 			default:
10688 				WL_ERR(("No Support for roam prof ver = %d \n", rp.v1.ver));
10689 				ret = -EINVAL;
10690 				goto exit;
10691 		}
10692 		/* set roam profile */
10693 		ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10694 		if (ret != BCME_OK) {
10695 			WL_ERR(("%s: Failed to set roam_prof %s error = %d\n",
10696 				__FUNCTION__, data, ret));
10697 			goto exit;
10698 		}
10699 	}
10700 
10701 	/* set RSSI weight */
10702 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10703 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10704 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
10705 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
10706 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10707 	if (ret != BCME_OK) {
10708 		WL_ERR(("%s: Failed to set weight config %s error = %d\n",
10709 			__FUNCTION__, data, ret));
10710 		goto exit;
10711 	}
10712 
10713 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10714 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10715 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
10716 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
10717 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10718 	if (ret != BCME_OK) {
10719 		WL_ERR(("%s: Failed to set weight config %s error = %d\n",
10720 			__FUNCTION__, data, ret));
10721 		goto exit;
10722 	}
10723 
10724 	/* set CU weight */
10725 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10726 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10727 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
10728 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
10729 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10730 	if (ret != BCME_OK) {
10731 		WL_ERR(("%s: Failed to set weight config %s error = %d\n",
10732 			__FUNCTION__, data, ret));
10733 		goto exit;
10734 	}
10735 
10736 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10737 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10738 		CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
10739 	data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
10740 	ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10741 	if (ret != BCME_OK) {
10742 		WL_ERR(("%s: Failed to set weight config %s error = %d\n",
10743 			__FUNCTION__, data, ret));
10744 		goto exit;
10745 	}
10746 
10747 	ret = wldev_iovar_getint(ndev, "wnm", &wnmmask);
10748 	if (ret != BCME_OK) {
10749 		WL_ERR(("%s: Failed to get wnmmask error = %d\n", __func__, ret));
10750 		goto exit;
10751 	}
10752 	/* set ESTM DL weight. */
10753 	if (wnmmask & WL_WNM_ESTM) {
10754 		WL_ERR(("Setting ESTM wt\n"));
10755 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10756 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10757 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A);
10758 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
10759 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10760 		if (ret != BCME_OK) {
10761 			WL_ERR(("%s: Failed to set weight config %s error = %d\n",
10762 				__FUNCTION__, data, ret));
10763 			goto exit;
10764 		}
10765 
10766 		memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10767 		snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10768 			CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B);
10769 		data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
10770 		ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10771 		if (ret != BCME_OK) {
10772 			WL_ERR(("%s: Failed to set weight config %s error = %d\n",
10773 				__FUNCTION__, data, ret));
10774 			goto exit;
10775 		}
10776 	}
10777 
10778 	/* set RSSI table */
10779 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10780 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10781 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
10782 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
10783 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10784 	if (ret != BCME_OK) {
10785 		WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
10786 			__FUNCTION__, data, ret));
10787 		goto exit;
10788 	}
10789 
10790 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10791 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10792 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
10793 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
10794 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10795 	if (ret != BCME_OK) {
10796 		WL_ERR(("%s: Failed to set RSSI table %s error = %d\n",
10797 			__FUNCTION__, data, ret));
10798 		goto exit;
10799 	}
10800 
10801 	/* set CU table */
10802 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10803 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10804 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
10805 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
10806 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10807 	if (ret != BCME_OK) {
10808 		WL_ERR(("%s: Failed to set CU table %s error = %d\n",
10809 			__FUNCTION__, data, ret));
10810 		goto exit;
10811 	}
10812 
10813 	memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
10814 	snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
10815 		CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
10816 	data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
10817 	ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
10818 	if (ret != BCME_OK) {
10819 		WL_ERR(("%s: Failed to set CU table %s error = %d\n",
10820 			__FUNCTION__, data, ret));
10821 		goto exit;
10822 	}
10823 
10824 exit:
10825 	if (commandp) {
10826 		MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
10827 	}
10828 	if (ioctl_buf) {
10829 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_SMLEN);
10830 	}
10831 	return ret;
10832 }
10833 
10834 s32
wl_cfg80211_wbtext_config(struct net_device * ndev,char * data,char * command,int total_len)10835 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
10836 {
10837 	uint i = 0;
10838 	long int rssi_lower, roam_trigger;
10839 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10840 	wl_roamprof_band_t *rp = NULL;
10841 	int err = -EINVAL, bytes_written = 0;
10842 	size_t len = strlen(data);
10843 	int rp_len = 0;
10844 	u8 *ioctl_buf = NULL;
10845 	uint8 roam_prof_size = 0, roam_prof_ver = 0, fs_per = 0, prof_cnt = 0;
10846 
10847 	data[len] = '\0';
10848 	ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
10849 	if (unlikely(!ioctl_buf)) {
10850 		WL_ERR(("%s: failed to allocate memory\n", __func__));
10851 		err =  -ENOMEM;
10852 		goto exit;
10853 	}
10854 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
10855 	if (unlikely(!rp)) {
10856 		WL_ERR(("%s: failed to allocate memory\n", __func__));
10857 		err =  -ENOMEM;
10858 		goto exit;
10859 	}
10860 	if (*data && (!strncmp(data, "b", 1))) {
10861 		rp->v1.band = WLC_BAND_2G;
10862 	} else if (*data && (!strncmp(data, "a", 1))) {
10863 		rp->v1.band = WLC_BAND_5G;
10864 	} else {
10865 		err = snprintf(command, total_len, "Missing band\n");
10866 		goto exit;
10867 	}
10868 	data++;
10869 	rp->v1.len = 0;
10870 	/* Getting roam profile from fw */
10871 	if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
10872 		ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
10873 		WL_ERR(("Getting roam_profile failed with err=%d \n", err));
10874 		goto exit;
10875 	}
10876 	memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
10877 	/* roam_prof version get */
10878 	if (rp->v1.ver > WL_ROAM_PROF_VER_2) {
10879 		WL_ERR(("bad version (=%d) in return data\n", rp->v1.ver));
10880 		err = -EINVAL;
10881 		goto exit;
10882 	}
10883 	switch (rp->v1.ver) {
10884 		case WL_ROAM_PROF_VER_0:
10885 		{
10886 			roam_prof_size = sizeof(wl_roam_prof_v1_t);
10887 			roam_prof_ver = WL_ROAM_PROF_VER_0;
10888 		}
10889 		break;
10890 		case WL_ROAM_PROF_VER_1:
10891 		{
10892 			roam_prof_size = sizeof(wl_roam_prof_v2_t);
10893 			roam_prof_ver = WL_ROAM_PROF_VER_1;
10894 		}
10895 		break;
10896 		case WL_ROAM_PROF_VER_2:
10897 		{
10898 			roam_prof_size = sizeof(wl_roam_prof_v3_t);
10899 			roam_prof_ver = WL_ROAM_PROF_VER_2;
10900 		}
10901 		break;
10902 		default:
10903 			WL_ERR(("bad version = %d \n", rp->v1.ver));
10904 			goto exit;
10905 	}
10906 	WL_DBG(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size));
10907 	if ((rp->v1.len % roam_prof_size) != 0) {
10908 		WL_ERR(("bad length (=%d) in return data\n", rp->v1.len));
10909 		err = -EINVAL;
10910 		goto exit;
10911 	}
10912 	for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
10913 		/* printing contents of roam profile data from fw and exits
10914 		 * if code hits any of one of the below condtion. If remaining
10915 		 * length of buffer is less than roam profile size or
10916 		 * if there is no valid entry.
10917 		 */
10918 		if (((i * roam_prof_size) > rp->v1.len)) {
10919 			break;
10920 		}
10921 		if (roam_prof_ver == WL_ROAM_PROF_VER_0) {
10922 			fs_per = rp->v1.roam_prof[i].fullscan_period;
10923 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
10924 			fs_per = rp->v2.roam_prof[i].fullscan_period;
10925 		} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
10926 			fs_per = rp->v3.roam_prof[i].fullscan_period;
10927 		}
10928 		if (fs_per == 0) {
10929 			break;
10930 		}
10931 		prof_cnt++;
10932 	}
10933 
10934 	if (!*data) {
10935 		for (i = 0; (i < prof_cnt) && (i < WL_MAX_ROAM_PROF_BRACKETS); i++) {
10936 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
10937 				bytes_written += snprintf(command+bytes_written,
10938 					total_len - bytes_written,
10939 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
10940 					rp->v2.roam_prof[i].roam_trigger,
10941 					rp->v2.roam_prof[i].rssi_lower,
10942 					rp->v2.roam_prof[i].channel_usage,
10943 					rp->v2.roam_prof[i].cu_avg_calc_dur);
10944 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
10945 				bytes_written += snprintf(command+bytes_written,
10946 					total_len - bytes_written,
10947 					"RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
10948 					rp->v3.roam_prof[i].roam_trigger,
10949 					rp->v3.roam_prof[i].rssi_lower,
10950 					rp->v3.roam_prof[i].channel_usage,
10951 					rp->v3.roam_prof[i].cu_avg_calc_dur);
10952 			}
10953 		}
10954 		err = bytes_written;
10955 		goto exit;
10956 	} else {
10957 		/* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
10958 		if (prof_cnt != 2) {
10959 			WL_ERR(("FW must have 2 rows to fill roam_prof\n"));
10960 			err = -EINVAL;
10961 			goto exit;
10962 		}
10963 		/* setting roam profile to fw */
10964 		data++;
10965 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
10966 			roam_trigger = simple_strtol(data, &data, 10);
10967 			if (roam_trigger >= 0) {
10968 				WL_ERR(("roam trigger[%d] value must be negative\n", i));
10969 				err = -EINVAL;
10970 				goto exit;
10971 			}
10972 			data++;
10973 			rssi_lower = simple_strtol(data, &data, 10);
10974 			if (rssi_lower >= 0) {
10975 				WL_ERR(("rssi lower[%d] value must be negative\n", i));
10976 				err = -EINVAL;
10977 				goto exit;
10978 			}
10979 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
10980 				rp->v2.roam_prof[i].roam_trigger = roam_trigger;
10981 				rp->v2.roam_prof[i].rssi_lower = rssi_lower;
10982 				data++;
10983 				rp->v2.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
10984 				data++;
10985 				rp->v2.roam_prof[i].cu_avg_calc_dur =
10986 					simple_strtol(data, &data, 10);
10987 			}
10988 			if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
10989 				rp->v3.roam_prof[i].roam_trigger = roam_trigger;
10990 				rp->v3.roam_prof[i].rssi_lower = rssi_lower;
10991 				data++;
10992 				rp->v3.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
10993 				data++;
10994 				rp->v3.roam_prof[i].cu_avg_calc_dur =
10995 					simple_strtol(data, &data, 10);
10996 			}
10997 
10998 			rp_len += roam_prof_size;
10999 
11000 			if (*data == '\0') {
11001 				break;
11002 			}
11003 			data++;
11004 		}
11005 		if (i != 1) {
11006 			WL_ERR(("Only two roam_prof rows supported.\n"));
11007 			err = -EINVAL;
11008 			goto exit;
11009 		}
11010 		rp->v1.len = rp_len;
11011 		if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
11012 				sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
11013 				&cfg->ioctl_buf_sync)) < 0) {
11014 			WL_ERR(("seting roam_profile failed with err %d\n", err));
11015 		}
11016 	}
11017 exit:
11018 	if (rp) {
11019 		MFREE(cfg->osh, rp, sizeof(*rp));
11020 	}
11021 	if (ioctl_buf) {
11022 		MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
11023 	}
11024 	return err;
11025 }
11026 
wl_cfg80211_wbtext_weight_config(struct net_device * ndev,char * data,char * command,int total_len)11027 int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
11028 		char *command, int total_len)
11029 {
11030 	int bytes_written = 0, err = -EINVAL, argc = 0;
11031 	char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
11032 	char *endptr = NULL;
11033 	wnm_bss_select_weight_cfg_t *bwcfg;
11034 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
11035 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11036 
11037 	bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
11038 	if (unlikely(!bwcfg)) {
11039 		WL_ERR(("%s: failed to allocate memory\n", __func__));
11040 		err = -ENOMEM;
11041 		goto exit;
11042 	}
11043 	bwcfg->version =  WNM_BSSLOAD_MONITOR_VERSION;
11044 	bwcfg->type = 0;
11045 	bwcfg->weight = 0;
11046 
11047 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
11048 
11049 	if (!strcasecmp(rssi, "rssi"))
11050 		bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
11051 	else if (!strcasecmp(rssi, "cu"))
11052 		bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
11053 	else if (!strcasecmp(rssi, "estm_dl"))
11054 		bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL;
11055 	else {
11056 		/* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu/estm_dl> <band> <weight> */
11057 		WL_ERR(("%s: Command usage error\n", __func__));
11058 		goto exit;
11059 	}
11060 
11061 	if (!strcasecmp(band, "a"))
11062 		bwcfg->band = WLC_BAND_5G;
11063 	else if (!strcasecmp(band, "b"))
11064 		bwcfg->band = WLC_BAND_2G;
11065 	else if (!strcasecmp(band, "all"))
11066 		bwcfg->band = WLC_BAND_ALL;
11067 	else {
11068 		WL_ERR(("%s: Command usage error\n", __func__));
11069 		goto exit;
11070 	}
11071 
11072 	if (argc == 2) {
11073 		/* If there is no data after band, getting wnm_bss_select_weight from fw */
11074 		if (bwcfg->band == WLC_BAND_ALL) {
11075 			WL_ERR(("band option \"all\" is for set only, not get\n"));
11076 			goto exit;
11077 		}
11078 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
11079 				sizeof(*bwcfg),
11080 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
11081 			WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
11082 			goto exit;
11083 		}
11084 		memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
11085 		bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
11086 			(bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" :
11087 			(bwcfg->type == WNM_BSS_SELECT_TYPE_CU) ? "CU": "ESTM_DL",
11088 			(bwcfg->band == WLC_BAND_2G) ? "2G" : "5G", bwcfg->weight);
11089 		err = bytes_written;
11090 		goto exit;
11091 	} else {
11092 		/* if weight is non integer returns command usage error */
11093 		bwcfg->weight = simple_strtol(weight, &endptr, 0);
11094 		if (*endptr != '\0') {
11095 			WL_ERR(("%s: Command usage error", __func__));
11096 			goto exit;
11097 		}
11098 		/* setting weight for iovar wnm_bss_select_weight to fw */
11099 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
11100 				sizeof(*bwcfg),
11101 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
11102 			WL_ERR(("setting wnm_bss_select_weight failed with err=%d\n", err));
11103 		}
11104 	}
11105 exit:
11106 	if (bwcfg) {
11107 		MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
11108 	}
11109 	return err;
11110 }
11111 
11112 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
11113 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
11114 
wl_cfg80211_wbtext_table_config(struct net_device * ndev,char * data,char * command,int total_len)11115 int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
11116 	char *command, int total_len)
11117 {
11118 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11119 	int bytes_written = 0, err = -EINVAL;
11120 	char rssi[BUFSZN], band[BUFSZN];
11121 	int btcfg_len = 0, i = 0, parsed_len = 0;
11122 	wnm_bss_select_factor_cfg_t *btcfg;
11123 	size_t slen = strlen(data);
11124 	char *start_addr = NULL;
11125 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
11126 
11127 	data[slen] = '\0';
11128 	btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
11129 		(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
11130 	if (unlikely(!btcfg)) {
11131 		WL_ERR(("%s: failed to allocate memory\n", __func__));
11132 		err = -ENOMEM;
11133 		goto exit;
11134 	}
11135 
11136 	btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
11137 	btcfg->band = WLC_BAND_AUTO;
11138 	btcfg->type = 0;
11139 	btcfg->count = 0;
11140 
11141 	sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
11142 
11143 	if (!strcasecmp(rssi, "rssi")) {
11144 		btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
11145 	}
11146 	else if (!strcasecmp(rssi, "cu")) {
11147 		btcfg->type = WNM_BSS_SELECT_TYPE_CU;
11148 	}
11149 	else {
11150 		WL_ERR(("%s: Command usage error\n", __func__));
11151 		goto exit;
11152 	}
11153 
11154 	if (!strcasecmp(band, "a")) {
11155 		btcfg->band = WLC_BAND_5G;
11156 	}
11157 	else if (!strcasecmp(band, "b")) {
11158 		btcfg->band = WLC_BAND_2G;
11159 	}
11160 	else if (!strcasecmp(band, "all")) {
11161 		btcfg->band = WLC_BAND_ALL;
11162 	}
11163 	else {
11164 		WL_ERR(("%s: Command usage, Wrong band\n", __func__));
11165 		goto exit;
11166 	}
11167 
11168 	if ((slen - 1) == (strlen(rssi) + strlen(band))) {
11169 		/* Getting factor table using iovar 'wnm_bss_select_table' from fw */
11170 		if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
11171 				sizeof(*btcfg),
11172 				ioctl_buf, sizeof(ioctl_buf), NULL))) {
11173 			WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err));
11174 			goto exit;
11175 		}
11176 		memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
11177 		memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
11178 
11179 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
11180 					"No of entries in table: %d\n", btcfg->count);
11181 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
11182 				"%s factor table\n",
11183 				(btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
11184 		bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
11185 					"low\thigh\tfactor\n");
11186 		for (i = 0; i <= btcfg->count-1; i++) {
11187 			bytes_written += snprintf(command + bytes_written,
11188 				total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
11189 				btcfg->params[i].high, btcfg->params[i].factor);
11190 		}
11191 		err = bytes_written;
11192 		goto exit;
11193 	} else {
11194 		uint16 len = (sizeof(wnm_bss_select_factor_params_t) * WL_FACTOR_TABLE_MAX_LIMIT);
11195 		memset_s(btcfg->params, len, 0, len);
11196 		data += (strlen(rssi) + strlen(band) + 2);
11197 		start_addr = data;
11198 		slen = slen - (strlen(rssi) + strlen(band) + 2);
11199 		for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
11200 			if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
11201 				btcfg->params[i].low = simple_strtol(data, &data, 10);
11202 				data++;
11203 				btcfg->params[i].high = simple_strtol(data, &data, 10);
11204 				data++;
11205 				btcfg->params[i].factor = simple_strtol(data, &data, 10);
11206 				btcfg->count++;
11207 				if (*data == '\0') {
11208 					break;
11209 				}
11210 				data++;
11211 				parsed_len = data - start_addr;
11212 			} else {
11213 				WL_ERR(("%s:Command usage:less no of args\n", __func__));
11214 				goto exit;
11215 			}
11216 		}
11217 		btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
11218 		if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
11219 				cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
11220 			WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err));
11221 			goto exit;
11222 		}
11223 	}
11224 exit:
11225 	if (btcfg) {
11226 		MFREE(cfg->osh, btcfg,
11227 			(sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
11228 	}
11229 	return err;
11230 }
11231 
11232 s32
wl_cfg80211_wbtext_delta_config(struct net_device * ndev,char * data,char * command,int total_len)11233 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
11234 {
11235 	uint i = 0;
11236 	struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11237 	int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
11238 	char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
11239 	wl_roamprof_band_t *rp = NULL;
11240 	uint8 band_val = 0, roam_prof_size = 0, roam_prof_ver = 0;
11241 
11242 	rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
11243 	if (unlikely(!rp)) {
11244 		WL_ERR(("%s: failed to allocate memory\n", __func__));
11245 		err = -ENOMEM;
11246 		goto exit;
11247 	}
11248 
11249 	argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
11250 	if (!strcasecmp(band, "a"))
11251 		band_val = WLC_BAND_5G;
11252 	else if (!strcasecmp(band, "b"))
11253 		band_val = WLC_BAND_2G;
11254 	else {
11255 		WL_ERR(("%s: Missing band\n", __func__));
11256 		goto exit;
11257 	}
11258 	if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver,
11259 		&roam_prof_size))) {
11260 		WL_ERR(("Getting roam_profile failed with err=%d \n", err));
11261 		err = -EINVAL;
11262 		goto exit;
11263 	}
11264 	if (argc == 2) {
11265 		/* if delta is non integer returns command usage error */
11266 		val = simple_strtol(delta, &endptr, 0);
11267 		if (*endptr != '\0') {
11268 			WL_ERR(("%s: Command usage error", __func__));
11269 			goto exit;
11270 		}
11271 		for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
11272 		/*
11273 		 * Checking contents of roam profile data from fw and exits
11274 		 * if code hits below condtion. If remaining length of buffer is
11275 		 * less than roam profile size or if there is no valid entry.
11276 		 */
11277 			if (((i * roam_prof_size) > rp->v1.len) ||
11278 				(rp->v1.roam_prof[i].fullscan_period == 0)) {
11279 				break;
11280 			}
11281 			if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
11282 				if (rp->v2.roam_prof[i].channel_usage != 0) {
11283 					rp->v2.roam_prof[i].roam_delta = val;
11284 				}
11285 			} else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
11286 				if (rp->v3.roam_prof[i].channel_usage != 0) {
11287 					rp->v3.roam_prof[i].roam_delta = val;
11288 				}
11289 			}
11290 			len += roam_prof_size;
11291 		}
11292 	}
11293 	else {
11294 		if (rp->v2.roam_prof[0].channel_usage != 0) {
11295 			bytes_written = snprintf(command, total_len,
11296 				"%s Delta %d\n", (rp->v1.band == WLC_BAND_2G) ? "2G" : "5G",
11297 				rp->v2.roam_prof[0].roam_delta);
11298 		}
11299 		err = bytes_written;
11300 		goto exit;
11301 	}
11302 	rp->v1.len = len;
11303 	if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
11304 			sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
11305 			&cfg->ioctl_buf_sync)) < 0) {
11306 		WL_ERR(("seting roam_profile failed with err %d\n", err));
11307 	}
11308 exit :
11309 	if (rp) {
11310 		MFREE(cfg->osh, rp, sizeof(*rp));
11311 	}
11312 	return err;
11313 }
11314 #endif /* WBTEXT */
11315