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