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