1 /*
2 * Linux cfg80211 driver - Android related functions
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23
24 #include <linux/module.h>
25 #include <linux/netdevice.h>
26 #include <net/netlink.h>
27 #ifdef CONFIG_COMPAT
28 #include <linux/compat.h>
29 #endif
30
31 #include <wl_android.h>
32 #include <wldev_common.h>
33 #include <wlioctl.h>
34 #include <wlioctl_utils.h>
35 #include <bcmutils.h>
36 #include <bcmstdlib_s.h>
37 #include <linux_osl.h>
38 #include <dhd_dbg.h>
39 #include <dngl_stats.h>
40 #include <dhd.h>
41 #include <dhd_config.h>
42 #include <bcmip.h>
43 #ifdef PNO_SUPPORT
44 #include <dhd_pno.h>
45 #endif
46 #ifdef BCMSDIO
47 #include <bcmsdbus.h>
48 #endif
49 #ifdef WL_CFG80211
50 #include <wl_cfg80211.h>
51 #include <wl_cfgscan.h>
52 #include <wl_cfgvif.h>
53 #endif
54 #ifdef WL_NAN
55 #include <wl_cfgnan.h>
56 #endif /* WL_NAN */
57 #ifdef DHDTCPACK_SUPPRESS
58 #include <dhd_ip.h>
59 #endif /* DHDTCPACK_SUPPRESS */
60 #include <bcmwifi_rspec.h>
61 #include <dhd_linux.h>
62 #include <bcmiov.h>
63 #ifdef DHD_PKT_LOGGING
64 #include <dhd_pktlog.h>
65 #endif /* DHD_PKT_LOGGING */
66 #ifdef WL_BCNRECV
67 #include <wl_cfgvendor.h>
68 #include <brcm_nl80211.h>
69 #endif /* WL_BCNRECV */
70 #ifdef WL_MBO
71 #include <mbo.h>
72 #endif /* WL_MBO */
73 #ifdef RTT_SUPPORT
74 #include <dhd_rtt.h>
75 #endif /* RTT_SUPPORT */
76 #ifdef DHD_EVENT_LOG_FILTER
77 #include <dhd_event_log_filter.h>
78 #endif /* DHD_EVENT_LOG_FILTER */
79 #ifdef WL_ESCAN
80 #include <wl_escan.h>
81 #endif
82
83 #ifdef WL_TWT
84 #include <802.11ah.h>
85 #endif /* WL_TWT */
86
87 #ifdef WL_STATIC_IF
88 #define WL_BSSIDX_MAX 16
89 #endif /* WL_STATIC_IF */
90
91 uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL;
92
93 #define ANDROID_ERROR_MSG(x, args...) \
94 do { \
95 if (android_msg_level & ANDROID_ERROR_LEVEL) { \
96 printk(KERN_ERR DHD_LOG_PREFIXS "ANDROID-ERROR) " x, ## args); \
97 } \
98 } while (0)
99 #define ANDROID_TRACE_MSG(x, args...) \
100 do { \
101 if (android_msg_level & ANDROID_TRACE_LEVEL) { \
102 printk(KERN_INFO DHD_LOG_PREFIXS "ANDROID-TRACE) " x, ## args); \
103 } \
104 } while (0)
105 #define ANDROID_INFO_MSG(x, args...) \
106 do { \
107 if (android_msg_level & ANDROID_INFO_LEVEL) { \
108 printk(KERN_INFO DHD_LOG_PREFIXS "ANDROID-INFO) " x, ## args); \
109 } \
110 } while (0)
111 #define ANDROID_ERROR(x) ANDROID_ERROR_MSG x
112 #define ANDROID_TRACE(x) ANDROID_TRACE_MSG x
113 #define ANDROID_INFO(x) ANDROID_INFO_MSG x
114
115 /*
116 * Android private command strings, PLEASE define new private commands here
117 * so they can be updated easily in the future (if needed)
118 */
119
120 #define CMD_START "START"
121 #define CMD_STOP "STOP"
122 #define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
123 #define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
124 #define CMD_RSSI "RSSI"
125 #define CMD_LINKSPEED "LINKSPEED"
126 #define CMD_RXFILTER_START "RXFILTER-START"
127 #define CMD_RXFILTER_STOP "RXFILTER-STOP"
128 #define CMD_RXFILTER_ADD "RXFILTER-ADD"
129 #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
130 #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
131 #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
132 #define CMD_BTCOEXMODE "BTCOEXMODE"
133 #define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
134 #define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
135 #define CMD_SETDTIM_IN_SUSPEND "SET_DTIM_IN_SUSPEND"
136 #define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
137 #define CMD_DISDTIM_IN_SUSPEND "DISABLE_DTIM_IN_SUSPEND"
138 #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
139 #define CMD_SETFWPATH "SETFWPATH"
140 #define CMD_SETBAND "SETBAND"
141 #define CMD_GETBAND "GETBAND"
142 #define CMD_COUNTRY "COUNTRY"
143 #define CMD_P2P_SET_NOA "P2P_SET_NOA"
144 #if !defined WL_ENABLE_P2P_IF
145 #define CMD_P2P_GET_NOA "P2P_GET_NOA"
146 #endif /* WL_ENABLE_P2P_IF */
147 #define CMD_P2P_SD_OFFLOAD "P2P_SD_"
148 #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_"
149 #define CMD_P2P_SET_PS "P2P_SET_PS"
150 #define CMD_P2P_ECSA "P2P_ECSA"
151 #define CMD_P2P_INC_BW "P2P_INCREASE_BW"
152 #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
153 #define CMD_SETROAMMODE "SETROAMMODE"
154 #define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
155 #define CMD_MIRACAST "MIRACAST"
156 #ifdef WL_NAN
157 #define CMD_NAN "NAN_"
158 #endif /* WL_NAN */
159 #define CMD_COUNTRY_DELIMITER "/"
160
161 #if defined (WL_SUPPORT_AUTO_CHANNEL)
162 #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
163 #endif /* WL_SUPPORT_AUTO_CHANNEL */
164
165 #define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */
166 #define CMD_CHANSPEC "CHANSPEC"
167 #define CMD_DATARATE "DATARATE"
168 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
169 #define CMD_SET_CSA "SETCSA"
170 #ifdef WL_SUPPORT_AUTO_CHANNEL
171 #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL"
172 #endif /* WL_SUPPORT_AUTO_CHANNEL */
173 #ifdef CUSTOMER_HW4_PRIVATE_CMD
174 #ifdef WL_WTC
175 #define CMD_WTC_CONFIG "SETWTCMODE"
176 #endif /* WL_WTC */
177 #ifdef SUPPORT_HIDDEN_AP
178 /* Hostapd private command */
179 #define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA"
180 #define CMD_SET_HAPD_SSID "HAPD_SSID"
181 #define CMD_SET_HAPD_HIDE_SSID "HAPD_HIDE_SSID"
182 #endif /* SUPPORT_HIDDEN_AP */
183 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
184 #define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC"
185 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
186 #ifdef SUPPORT_SET_LPC
187 #define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED"
188 #endif /* SUPPORT_SET_LPC */
189 #ifdef SUPPORT_TRIGGER_HANG_EVENT
190 #define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG"
191 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
192 #ifdef SUPPORT_LTECX
193 #define CMD_LTECX_SET "LTECOEX"
194 #endif /* SUPPORT_LTECX */
195 #ifdef TEST_TX_POWER_CONTROL
196 #define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER"
197 #define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER"
198 #endif /* TEST_TX_POWER_CONTROL */
199 #define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING"
200 #ifdef SUPPORT_SET_TID
201 #define CMD_SET_TID "SET_TID"
202 #define CMD_GET_TID "GET_TID"
203 #endif /* SUPPORT_SET_TID */
204 #define CMD_ROAM_VSIE_ENAB_SET "SET_ROAMING_REASON_ENABLED"
205 #define CMD_ROAM_VSIE_ENAB_GET "GET_ROAMING_REASON_ENABLED"
206 #define CMD_BR_VSIE_ENAB_SET "SET_BR_ERR_REASON_ENABLED"
207 #define CMD_BR_VSIE_ENAB_GET "GET_BR_ERR_REASON_ENABLED"
208 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
209 #define CMD_KEEP_ALIVE "KEEPALIVE"
210
211 #ifdef PNO_SUPPORT
212 #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
213 #define CMD_PNOSETUP_SET "PNOSETUP "
214 #define CMD_PNOENABLE_SET "PNOFORCE"
215 #define CMD_PNODEBUG_SET "PNODEBUG"
216 #define CMD_WLS_BATCHING "WLS_BATCHING"
217 #endif /* PNO_SUPPORT */
218
219 #define CMD_HAPD_SET_AX_MODE "HAPD_SET_AX_MODE"
220
221 #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
222
223 #if defined(SUPPORT_RANDOM_MAC_SCAN)
224 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
225 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
226 #endif /* SUPPORT_RANDOM_MAC_SCAN */
227 #define CMD_GET_FACTORY_MAC "FACTORY_MAC"
228 #ifdef CUSTOMER_HW4_PRIVATE_CMD
229
230 #ifdef ROAM_API
231 #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
232 #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
233 #define CMD_ROAMDELTA_SET "SETROAMDELTA"
234 #define CMD_ROAMDELTA_GET "GETROAMDELTA"
235 #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
236 #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
237 #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
238 #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
239 #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
240 #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
241 #endif /* ROAM_API */
242
243 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
244 #define CMD_NAN_RANGING_SET_BW "NAN_RANGING_SET_BW"
245 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
246
247 #ifdef WES_SUPPORT
248 #define CMD_GETSCANCHANNELTIMELEGACY "GETSCANCHANNELTIME_LEGACY"
249 #define CMD_SETSCANCHANNELTIMELEGACY "SETSCANCHANNELTIME_LEGACY"
250 #define CMD_GETSCANUNASSOCTIMELEGACY "GETSCANUNASSOCTIME_LEGACY"
251 #define CMD_SETSCANUNASSOCTIMELEGACY "SETSCANUNASSOCTIME_LEGACY"
252 #define CMD_GETSCANPASSIVETIMELEGACY "GETSCANPASSIVETIME_LEGACY"
253 #define CMD_SETSCANPASSIVETIMELEGACY "SETSCANPASSIVETIME_LEGACY"
254 #define CMD_GETSCANHOMETIMELEGACY "GETSCANHOMETIME_LEGACY"
255 #define CMD_SETSCANHOMETIMELEGACY "SETSCANHOMETIME_LEGACY"
256 #define CMD_GETSCANHOMEAWAYTIMELEGACY "GETSCANHOMEAWAYTIME_LEGACY"
257 #define CMD_SETSCANHOMEAWAYTIMELEGACY "SETSCANHOMEAWAYTIME_LEGACY"
258 #define CMD_GETROAMSCANCHLEGACY "GETROAMSCANCHANNELS_LEGACY"
259 #define CMD_ADDROAMSCANCHLEGACY "ADDROAMSCANCHANNELS_LEGACY"
260 #define CMD_GETROAMSCANFQLEGACY "GETROAMSCANFREQUENCIES_LEGACY"
261 #define CMD_ADDROAMSCANFQLEGACY "ADDROAMSCANFREQUENCIES_LEGACY"
262 #define CMD_GETROAMTRIGLEGACY "GETROAMTRIGGER_LEGACY"
263 #define CMD_SETROAMTRIGLEGACY "SETROAMTRIGGER_LEGACY"
264 #define CMD_REASSOCLEGACY "REASSOC_LEGACY"
265
266 #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
267 #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
268 #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
269 #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
270 #define CMD_ADDROAMSCANCHANNELS "ADDROAMSCANCHANNELS"
271 #define CMD_GETROAMSCANFREQS "GETROAMSCANFREQUENCIES"
272 #define CMD_SETROAMSCANFREQS "SETROAMSCANFREQUENCIES"
273 #define CMD_ADDROAMSCANFREQS "ADDROAMSCANFREQUENCIES"
274 #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
275 #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
276 #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
277 #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
278 #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
279 #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
280 #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
281 #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
282 #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
283 #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
284 #define CMD_GETSCANNPROBES "GETSCANNPROBES"
285 #define CMD_SETSCANNPROBES "SETSCANNPROBES"
286 #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
287 #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
288 #define CMD_SETJOINPREFER "SETJOINPREFER"
289
290 #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
291 #define CMD_REASSOC "REASSOC"
292
293 #define CMD_GETWESMODE "GETWESMODE"
294 #define CMD_SETWESMODE "SETWESMODE"
295 #define CMD_GETNCHOMODE "GETNCHOMODE"
296 #define CMD_SETNCHOMODE "SETNCHOMODE"
297
298 /* Customer requested to Remove OKCMODE command */
299 #define CMD_GETOKCMODE "GETOKCMODE"
300 #define CMD_SETOKCMODE "SETOKCMODE"
301
302 #define CMD_OKC_SET_PMK "SET_PMK"
303 #define CMD_OKC_ENABLE "OKC_ENABLE"
304
305 typedef struct android_wifi_reassoc_params {
306 unsigned char bssid[18];
307 int channel;
308 } android_wifi_reassoc_params_t;
309
310 #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
311
312 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
313
314 typedef struct android_wifi_af_params {
315 unsigned char bssid[18];
316 int channel;
317 int dwell_time;
318 int len;
319 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
320 } android_wifi_af_params_t;
321
322 #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
323 #endif /* WES_SUPPORT */
324 #ifdef SUPPORT_AMPDU_MPDU_CMD
325 #define CMD_AMPDU_MPDU "AMPDU_MPDU"
326 #endif /* SUPPORT_AMPDU_MPDU_CMD */
327
328 #define CMD_CHANGE_RL "CHANGE_RL"
329 #define CMD_RESTORE_RL "RESTORE_RL"
330
331 #define CMD_SET_RMC_ENABLE "SETRMCENABLE"
332 #define CMD_SET_RMC_TXRATE "SETRMCTXRATE"
333 #define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD"
334 #define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD"
335 #define CMD_SET_RMC_LEADER "SETRMCLEADER"
336 #define CMD_SET_RMC_EVENT "SETRMCEVENT"
337
338 #define CMD_SET_SCSCAN "SETSINGLEANT"
339 #define CMD_GET_SCSCAN "GETSINGLEANT"
340 #ifdef WLTDLS
341 #define CMD_TDLS_RESET "TDLS_RESET"
342 #endif /* WLTDLS */
343
344 #ifdef CONFIG_SILENT_ROAM
345 #define CMD_SROAM_TURN_ON "SROAMTURNON"
346 #define CMD_SROAM_SET_INFO "SROAMSETINFO"
347 #define CMD_SROAM_GET_INFO "SROAMGETINFO"
348 #endif /* CONFIG_SILENT_ROAM */
349
350 #ifdef CONFIG_ROAM_RSSI_LIMIT
351 #define CMD_ROAM_RSSI_LMT "ROAMRSSILIMIT"
352 #endif /* CONFIG_ROAM_RSSI_LIMIT */
353 #ifdef CONFIG_ROAM_MIN_DELTA
354 #define CMD_ROAM_MIN_DELTA "ROAMMINSCOREDELTA"
355 #endif /* CONFIG_ROAM_MIN_DELTA */
356
357 #define CMD_SET_DISCONNECT_IES "SET_DISCONNECT_IES"
358
359 #ifdef FCC_PWR_LIMIT_2G
360 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
361 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
362 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
363 #define CUSTOMER_HW4_ENABLE 0
364 #define CUSTOMER_HW4_DISABLE -1
365 #endif /* FCC_PWR_LIMIT_2G */
366 #define CUSTOMER_HW4_EN_CONVERT(i) (i += 1)
367 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
368
369 #ifdef WLFBT
370 #define CMD_GET_FTKEY "GET_FTKEY"
371 #endif
372
373 #ifdef WLAIBSS
374 #define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT"
375 #define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO"
376 #define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL"
377 #define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE"
378 #define CMD_SETIBSSAMPDU "SETIBSSAMPDU"
379 #define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE"
380 #endif /* WLAIBSS */
381
382 #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
383 #define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
384 #define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
385 #define CMD_GET_LINK_STATUS "GETLINKSTATUS"
386
387 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
388 #define CMD_GET_BSS_INFO "GETBSSINFO"
389 #define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO"
390 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
391 #define CMD_GET_STA_INFO "GETSTAINFO"
392
393 /* related with CMD_GET_LINK_STATUS */
394 #define WL_ANDROID_LINK_VHT 0x01
395 #define WL_ANDROID_LINK_MIMO 0x02
396 #define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
397 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
398
399 #ifdef P2PRESP_WFDIE_SRC
400 #define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
401 #define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
402 #endif /* P2PRESP_WFDIE_SRC */
403
404 #define CMD_DFS_AP_MOVE "DFS_AP_MOVE"
405 #define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE"
406 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
407 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
408 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
409 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
410 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD"
411 #define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA"
412 #define CMD_WBTEXT_ESTM_ENABLE "WBTEXT_ESTM_ENABLE"
413
414 #ifdef WBTEXT
415 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
416 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
417 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
418 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
419 #define DEFAULT_WBTEXT_PROFILE_A_V2 "a -70 -75 70 10 -75 -128 0 10"
420 #define DEFAULT_WBTEXT_PROFILE_B_V2 "b -60 -75 70 10 -75 -128 0 10"
421 #define DEFAULT_WBTEXT_PROFILE_A_V3 "a -70 -75 70 10 -75 -128 0 10"
422 #define DEFAULT_WBTEXT_PROFILE_B_V3 "b -60 -75 70 10 -75 -128 0 10"
423 #define DEFAULT_WBTEXT_WEIGHT_RSSI_A "RSSI a 65"
424 #define DEFAULT_WBTEXT_WEIGHT_RSSI_B "RSSI b 65"
425 #define DEFAULT_WBTEXT_WEIGHT_CU_A "CU a 35"
426 #define DEFAULT_WBTEXT_WEIGHT_CU_B "CU b 35"
427 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A "ESTM_DL a 70"
428 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B "ESTM_DL b 70"
429 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_A -70
430 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_B -60
431 #ifdef WBTEXT_SCORE_V2
432 #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
433 60 70 60 70 80 20 80 90 0 90 128 0"
434 #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
435 60 70 60 70 80 20 80 90 0 90 128 0"
436 #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 80 20 \
437 80 100 20"
438 #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 70 20 \
439 70 100 20"
440 #else
441 #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
442 60 65 70 65 70 50 70 128 20"
443 #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
444 60 65 70 65 70 50 70 128 20"
445 #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 50 90 \
446 50 60 70 60 80 50 80 100 20"
447 #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 25 90 \
448 25 40 70 40 70 50 70 100 20"
449 #endif /* WBTEXT_SCORE_V2 */
450 #endif /* WBTEXT */
451
452 #define BUFSZ 8
453 #define BUFSZN BUFSZ + 1
454
455 #define _S(x) #x
456 #define S(x) _S(x)
457
458 #define MAXBANDS 2 /**< Maximum #of bands */
459 #define BAND_2G_INDEX 1
460 #define BAND_5G_INDEX 0
461
462 typedef union {
463 wl_roam_prof_band_v1_t v1;
464 wl_roam_prof_band_v2_t v2;
465 wl_roam_prof_band_v3_t v3;
466 wl_roam_prof_band_v4_t v4;
467 } wl_roamprof_band_t;
468
469 #ifdef WLWFDS
470 #define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH"
471 #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH"
472 #endif /* WLWFDS */
473
474 #ifdef BT_WIFI_HANDOVER
475 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
476 #endif /* BT_WIFI_HANDOVER */
477
478 #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
479
480 #ifdef SUPPORT_RSSI_SUM_REPORT
481 #define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING"
482 #define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING"
483 #define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT"
484 #endif /* SUPPORT_RSSI_SUM_REPORT */
485
486 #define CMD_GET_SNR "GET_SNR"
487
488 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
489 #define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE"
490 #define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE"
491 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
492
493 #ifdef SUPPORT_AP_RADIO_PWRSAVE
494 #define CMD_SET_AP_RPS "SET_AP_RPS"
495 #define CMD_GET_AP_RPS "GET_AP_RPS"
496 #define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS"
497 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
498
499 #ifdef SUPPORT_AP_SUSPEND
500 #define CMD_SET_AP_SUSPEND "SET_AP_SUSPEND"
501 #endif /* SUPPORT_AP_SUSPEND */
502
503 #ifdef SUPPORT_AP_BWCTRL
504 #define CMD_SET_AP_BW "SET_AP_BW"
505 #define CMD_GET_AP_BW "GET_AP_BW"
506 #endif /* SUPPORT_AP_BWCTRL */
507
508 /* miracast related definition */
509 #define MIRACAST_MODE_OFF 0
510 #define MIRACAST_MODE_SOURCE 1
511 #define MIRACAST_MODE_SINK 2
512
513 #ifdef CONNECTION_STATISTICS
514 #define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
515
516 struct connection_stats {
517 u32 txframe;
518 u32 txbyte;
519 u32 txerror;
520 u32 rxframe;
521 u32 rxbyte;
522 u32 txfail;
523 u32 txretry;
524 u32 txretrie;
525 u32 txrts;
526 u32 txnocts;
527 u32 txexptime;
528 u32 txrate;
529 u8 chan_idle;
530 };
531 #endif /* CONNECTION_STATISTICS */
532
533 #ifdef SUPPORT_LQCM
534 #define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE"
535 #define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT"
536 #endif
537
538 static LIST_HEAD(miracast_resume_list);
539 #ifdef WL_CFG80211
540 static u8 miracast_cur_mode;
541 #endif /* WL_CFG80211 */
542
543 #ifdef DHD_LOG_DUMP
544 #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP"
545 #define SUBCMD_UNWANTED "UNWANTED"
546 #define SUBCMD_DISCONNECTED "DISCONNECTED"
547 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
548 #endif /* DHD_LOG_DUMP */
549
550 #ifdef DHD_STATUS_LOGGING
551 #define CMD_DUMP_STATUS_LOG "DUMP_STAT_LOG"
552 #define CMD_QUERY_STATUS_LOG "QUERY_STAT_LOG"
553 #endif /* DHD_STATUS_LOGGING */
554
555 #ifdef DHD_HANG_SEND_UP_TEST
556 #define CMD_MAKE_HANG "MAKE_HANG"
557 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
558 #ifdef DHD_DEBUG_UART
559 extern bool dhd_debug_uart_is_running(struct net_device *dev);
560 #endif /* DHD_DEBUG_UART */
561
562 #ifdef RTT_GEOFENCE_INTERVAL
563 #if defined (RTT_SUPPORT) && defined(WL_NAN)
564 #define CMD_GEOFENCE_INTERVAL "GEOFENCE_INT"
565 #endif /* RTT_SUPPORT && WL_NAN */
566 #endif /* RTT_GEOFENCE_INTERVAL */
567
568 struct io_cfg {
569 s8 *iovar;
570 s32 param;
571 u32 ioctl;
572 void *arg;
573 u32 len;
574 struct list_head list;
575 };
576
577 #if defined(BCMFW_ROAM_ENABLE)
578 #define CMD_SET_ROAMPREF "SET_ROAMPREF"
579
580 #define MAX_NUM_SUITES 10
581 #define WIDTH_AKM_SUITE 8
582 #define JOIN_PREF_RSSI_LEN 0x02
583 #define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */
584 #define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */
585 #define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */
586 #define JOIN_PREF_MAX_WPA_TUPLES 16
587 #define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
588 (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
589 #endif /* BCMFW_ROAM_ENABLE */
590
591 #if defined(CONFIG_TIZEN)
592 /*
593 * adding these private commands corresponding to atd-server's implementation
594 * __atd_control_pm_state()
595 */
596 #define CMD_POWERSAVEMODE_SET "SETPOWERSAVEMODE"
597 #define CMD_POWERSAVEMODE_GET "GETPOWERSAVEMODE"
598 #endif /* CONFIG_TIZEN */
599
600 #define CMD_DEBUG_VERBOSE "DEBUG_VERBOSE"
601 #ifdef WL_NATOE
602
603 #define CMD_NATOE "NATOE"
604
605 #define NATOE_MAX_PORT_NUM 65535
606
607 /* natoe command info structure */
608 typedef struct wl_natoe_cmd_info {
609 uint8 *command; /* pointer to the actual command */
610 uint16 tot_len; /* total length of the command */
611 uint16 bytes_written; /* Bytes written for get response */
612 } wl_natoe_cmd_info_t;
613
614 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
615 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
616 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
617
618 struct wl_natoe_sub_cmd {
619 char *name;
620 uint8 version; /* cmd version */
621 uint16 id; /* id for the dongle f/w switch/case */
622 uint16 type; /* base type of argument */
623 natoe_cmd_handler_t *handler; /* cmd handler */
624 };
625
626 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
627 static int wl_android_process_natoe_cmd(struct net_device *dev,
628 char *command, int total_len);
629 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
630 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
631 static int wl_android_natoe_subcmd_config_ips(struct net_device *dev,
632 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
633 static int wl_android_natoe_subcmd_config_ports(struct net_device *dev,
634 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
635 static int wl_android_natoe_subcmd_dbg_stats(struct net_device *dev,
636 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
637 static int wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev,
638 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
639
640 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
641 /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
642 {"enable", 0x01, WL_NATOE_CMD_ENABLE,
643 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
644 },
645 {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
646 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
647 },
648 {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
649 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
650 },
651 {"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
652 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
653 },
654 {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
655 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
656 },
657 {NULL, 0, 0, 0, NULL}
658 };
659
660 #endif /* WL_NATOE */
661
662 #ifdef SET_PCIE_IRQ_CPU_CORE
663 #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE"
664 #endif /* SET_PCIE_IRQ_CPU_CORE */
665
666 #ifdef WLADPS_PRIVATE_CMD
667 #define CMD_SET_ADPS "SET_ADPS"
668 #define CMD_GET_ADPS "GET_ADPS"
669 #ifdef WLADPS_ENERGY_GAIN
670 #define CMD_GET_GAIN_ADPS "GET_GAIN_ADPS"
671 #define CMD_RESET_GAIN_ADPS "RESET_GAIN_ADPS"
672 #ifndef ADPS_GAIN_2G_PM0_IDLE
673 #define ADPS_GAIN_2G_PM0_IDLE 0
674 #endif
675 #ifndef ADPS_GAIN_5G_PM0_IDLE
676 #define ADPS_GAIN_5G_PM0_IDLE 0
677 #endif
678 #ifndef ADPS_GAIN_2G_TX_PSPOLL
679 #define ADPS_GAIN_2G_TX_PSPOLL 0
680 #endif
681 #ifndef ADPS_GAIN_5G_TX_PSPOLL
682 #define ADPS_GAIN_5G_TX_PSPOLL 0
683 #endif
684 #endif /* WLADPS_ENERGY_GAIN */
685 #endif /* WLADPS_PRIVATE_CMD */
686
687 #ifdef DHD_PKT_LOGGING
688 #define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE"
689 #define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE"
690 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE "PKTLOG_FILTER_PATTERN_ENABLE"
691 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE "PKTLOG_FILTER_PATTERN_DISABLE"
692 #define CMD_PKTLOG_FILTER_ADD "PKTLOG_FILTER_ADD"
693 #define CMD_PKTLOG_FILTER_DEL "PKTLOG_FILTER_DEL"
694 #define CMD_PKTLOG_FILTER_INFO "PKTLOG_FILTER_INFO"
695 #define CMD_PKTLOG_START "PKTLOG_START"
696 #define CMD_PKTLOG_STOP "PKTLOG_STOP"
697 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
698 #define CMD_PKTLOG_MINMIZE_ENABLE "PKTLOG_MINMIZE_ENABLE"
699 #define CMD_PKTLOG_MINMIZE_DISABLE "PKTLOG_MINMIZE_DISABLE"
700 #define CMD_PKTLOG_CHANGE_SIZE "PKTLOG_CHANGE_SIZE"
701 #define CMD_PKTLOG_DEBUG_DUMP "PKTLOG_DEBUG_DUMP"
702 #endif /* DHD_PKT_LOGGING */
703
704 #ifdef DHD_EVENT_LOG_FILTER
705 #define CMD_EWP_FILTER "EWP_FILTER"
706 #endif /* DHD_EVENT_LOG_FILTER */
707
708 #ifdef WL_BCNRECV
709 #define CMD_BEACON_RECV "BEACON_RECV"
710 #endif /* WL_BCNRECV */
711 #ifdef WL_CAC_TS
712 #define CMD_CAC_TSPEC "CAC_TSPEC"
713 #endif /* WL_CAC_TS */
714 #ifdef WL_GET_CU
715 #define CMD_GET_CHAN_UTIL "GET_CU"
716 #endif /* WL_GET_CU */
717
718 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
719 #define CMD_SET_SOFTAP_ELNA_BYPASS "SET_SOFTAP_ELNA_BYPASS"
720 #define CMD_GET_SOFTAP_ELNA_BYPASS "GET_SOFTAP_ELNA_BYPASS"
721 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
722
723 #ifdef WL_NAN
724 #define CMD_GET_NAN_STATUS "GET_NAN_STATUS"
725 #endif /* WL_NAN */
726
727 #ifdef WL_TWT
728 #define CMD_TWT_SETUP "TWT_SETUP"
729 #define CMD_TWT_TEARDOWN "TWT_TEARDOWN"
730 #define CMD_TWT_INFO "TWT_INFO_FRM"
731 #define CMD_TWT_STATUS_QUERY "TWT_STATUS"
732 #define CMD_TWT_CAPABILITY "TWT_CAP"
733 #endif /* WL_TWT */
734
735 /* drv command info structure */
736 typedef struct wl_drv_cmd_info {
737 uint8 *command; /* pointer to the actual command */
738 uint16 tot_len; /* total length of the command */
739 uint16 bytes_written; /* Bytes written for get response */
740 } wl_drv_cmd_info_t;
741
742 typedef struct wl_drv_sub_cmd wl_drv_sub_cmd_t;
743 typedef int (drv_cmd_handler_t)(struct net_device *dev,
744 const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
745
746 struct wl_drv_sub_cmd {
747 char *name;
748 uint8 version; /* cmd version */
749 uint16 id; /* id for the dongle f/w switch/case */
750 uint16 type; /* base type of argument */
751 drv_cmd_handler_t *handler; /* cmd handler */
752 };
753
754 #ifdef WL_MBO
755
756 #define CMD_MBO "MBO"
757 enum {
758 WL_MBO_CMD_NON_CHAN_PREF = 1,
759 WL_MBO_CMD_CELL_DATA_CAP = 2
760 };
761 #define WL_ANDROID_MBO_FUNC(suffix) wl_android_mbo_subcmd_ ##suffix
762
763 static int wl_android_process_mbo_cmd(struct net_device *dev,
764 char *command, int total_len);
765 static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
766 const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
767 static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
768 const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
769
770 static const wl_drv_sub_cmd_t mbo_cmd_list[] = {
771 {"non_pref_chan", 0x01, WL_MBO_CMD_NON_CHAN_PREF,
772 IOVT_BUFFER, WL_ANDROID_MBO_FUNC(non_pref_chan)
773 },
774 {"cell_data_cap", 0x01, WL_MBO_CMD_CELL_DATA_CAP,
775 IOVT_BUFFER, WL_ANDROID_MBO_FUNC(cell_data_cap)
776 },
777 {NULL, 0, 0, 0, NULL}
778 };
779
780 #endif /* WL_MBO */
781
782 #ifdef WL_GENL
783 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
784 static int wl_genl_init(void);
785 static int wl_genl_deinit(void);
786
787 extern struct net init_net;
788 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
789 * possible values defined in net/netlink.h
790 */
791 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
792 [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
793 [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
794 };
795
796 #define WL_GENL_VER 1
797 /* family definition */
798 static struct genl_family wl_genl_family = {
799 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
800 .hdrsize = 0,
801 .name = "bcm-genl", /* Netlink I/F for Android */
802 .version = WL_GENL_VER, /* Version Number */
803 .maxattr = BCM_GENL_ATTR_MAX,
804 };
805
806 /* commands: mapping between the command enumeration and the actual function */
807 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
808 struct genl_ops wl_genl_ops[] = {
809 {
810 .cmd = BCM_GENL_CMD_MSG,
811 .flags = 0,
812 .policy = wl_genl_policy,
813 .doit = wl_genl_handle_msg,
814 .dumpit = NULL,
815 },
816 };
817 #else
818 struct genl_ops wl_genl_ops = {
819 .cmd = BCM_GENL_CMD_MSG,
820 .flags = 0,
821 .policy = wl_genl_policy,
822 .doit = wl_genl_handle_msg,
823 .dumpit = NULL,
824
825 };
826 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
827
828 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
829 static struct genl_multicast_group wl_genl_mcast[] = {
830 { .name = "bcm-genl-mcast", },
831 };
832 #else
833 static struct genl_multicast_group wl_genl_mcast = {
834 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
835 .name = "bcm-genl-mcast",
836 };
837 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
838 #endif /* WL_GENL */
839
840 #ifdef SUPPORT_LQCM
841 #define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */
842 #define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */
843 #define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */
844
845 #define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */
846 #define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */
847 #endif /* SUPPORT_LQCM */
848
849 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
850 #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS 7
851 static int priv_cmd_errors = 0;
852 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
853
854 #ifdef WL_P2P_6G
855 #define CMD_ENABLE_6G_P2P "ENABLE_6G_P2P"
856 #endif /* WL_P2P_6G */
857
858 /**
859 * Extern function declarations (TODO: move them to dhd_linux.h)
860 */
861 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
862 int dhd_dev_init_ioctl(struct net_device *dev);
863 #ifdef WL_CFG80211
864 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
865 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
866 #ifdef WES_SUPPORT
867 int wl_cfg80211_set_wes_mode(struct net_device *dev, int mode);
868 int wl_cfg80211_get_wes_mode(struct net_device *dev);
869 int wl_cfg80211_set_ncho_mode(struct net_device *dev, int mode);
870 int wl_cfg80211_get_ncho_mode(struct net_device *dev);
871 #endif /* WES_SUPPORT */
872 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)873 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
874 { return 0; }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)875 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
876 { return 0; }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)877 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
878 { return 0; }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)879 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
880 { return 0; }
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)881 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
882 { return 0; }
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)883 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
884 { return 0; }
885 #endif /* WL_CFG80211 */
886 #if defined(WL_WTC) && defined(CUSTOMER_HW4_PRIVATE_CMD)
887 static int wl_android_wtc_config(struct net_device *dev, char *command, int total_len);
888 #endif /* WL_WTC && CUSTOMER_HW4_PRIVATE_CMD */
889 #ifdef WBTEXT
890 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
891 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
892 char *command, int total_len);
893 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
894 char *command, int total_len);
895 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
896 char *command, int total_len);
897 static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
898 uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size);
899 static int wl_android_wbtext_enable(struct net_device *dev, int mode);
900 #endif /* WBTEXT */
901 #ifdef WES_SUPPORT
902 /* wl_roam.c */
903 extern int get_roamscan_mode(struct net_device *dev, int *mode);
904 extern int set_roamscan_mode(struct net_device *dev, int mode);
905 extern int get_roamscan_chanspec_list(struct net_device *dev, chanspec_t *chanspecs);
906 extern int set_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
907 extern int add_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
908
909 static char* legacy_cmdlist[] =
910 {
911 CMD_GETROAMSCANCHLEGACY, CMD_ADDROAMSCANCHLEGACY,
912 CMD_GETROAMSCANFQLEGACY, CMD_ADDROAMSCANFQLEGACY,
913 CMD_GETROAMTRIGLEGACY, CMD_SETROAMTRIGLEGACY,
914 CMD_REASSOCLEGACY,
915 CMD_GETSCANCHANNELTIMELEGACY, CMD_SETSCANCHANNELTIMELEGACY,
916 CMD_GETSCANUNASSOCTIMELEGACY, CMD_SETSCANUNASSOCTIMELEGACY,
917 CMD_GETSCANPASSIVETIMELEGACY, CMD_SETSCANPASSIVETIMELEGACY,
918 CMD_GETSCANHOMETIMELEGACY, CMD_SETSCANHOMETIMELEGACY,
919 CMD_GETSCANHOMEAWAYTIMELEGACY, CMD_SETSCANHOMEAWAYTIMELEGACY,
920 "\0"
921 };
922
923 static char* ncho_cmdlist[] =
924 {
925 CMD_ROAMTRIGGER_GET, CMD_ROAMTRIGGER_SET,
926 CMD_ROAMDELTA_GET, CMD_ROAMDELTA_SET,
927 CMD_ROAMSCANPERIOD_GET, CMD_ROAMSCANPERIOD_SET,
928 CMD_FULLROAMSCANPERIOD_GET, CMD_FULLROAMSCANPERIOD_SET,
929 CMD_COUNTRYREV_GET, CMD_COUNTRYREV_SET,
930 CMD_GETROAMSCANCONTROL, CMD_SETROAMSCANCONTROL,
931 CMD_GETROAMSCANCHANNELS, CMD_SETROAMSCANCHANNELS, CMD_ADDROAMSCANCHANNELS,
932 CMD_GETROAMSCANFREQS, CMD_SETROAMSCANFREQS, CMD_ADDROAMSCANFREQS,
933 CMD_SENDACTIONFRAME,
934 CMD_REASSOC,
935 CMD_GETSCANCHANNELTIME, CMD_SETSCANCHANNELTIME,
936 CMD_GETSCANUNASSOCTIME, CMD_SETSCANUNASSOCTIME,
937 CMD_GETSCANPASSIVETIME, CMD_SETSCANPASSIVETIME,
938 CMD_GETSCANHOMETIME, CMD_SETSCANHOMETIME,
939 CMD_GETSCANHOMEAWAYTIME, CMD_SETSCANHOMEAWAYTIME,
940 CMD_GETSCANNPROBES, CMD_SETSCANNPROBES,
941 CMD_GETDFSSCANMODE, CMD_SETDFSSCANMODE,
942 CMD_SETJOINPREFER,
943 CMD_GETWESMODE, CMD_SETWESMODE,
944 "\0"
945 };
946 #endif /* WES_SUPPORT */
947 #ifdef ROAM_CHANNEL_CACHE
948 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
949 #endif /* ROAM_CHANNEL_CACHE */
950
951 int wl_android_priority_roam_enable(struct net_device *dev, int mode);
952 #ifdef CONFIG_SILENT_ROAM
953 int wl_android_sroam_turn_on(struct net_device *dev, int mode);
954 #endif /* CONFIG_SILENT_ROAM */
955 int wl_android_rcroam_turn_on(struct net_device *dev, int mode);
956
957 #ifdef ENABLE_4335BT_WAR
958 extern int bcm_bt_lock(int cookie);
959 extern void bcm_bt_unlock(int cookie);
960 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
961 #endif /* ENABLE_4335BT_WAR */
962
963 extern bool ap_fw_loaded;
964 extern char iface_name[IFNAMSIZ];
965 #ifdef DHD_PM_CONTROL_FROM_FILE
966 extern bool g_pm_control;
967 #endif /* DHD_PM_CONTROL_FROM_FILE */
968
969 /* private command support for restoring roam/scan parameters */
970 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
971 #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
972
973 typedef int (*PRIV_CMD_HANDLER) (struct net_device *dev, char *command);
974 typedef int (*PRIV_CMD_HANDLER_WITH_LEN) (struct net_device *dev, char *command, int total_len);
975
976 enum {
977 RESTORE_TYPE_UNSPECIFIED = 0,
978 RESTORE_TYPE_PRIV_CMD = 1,
979 RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
980 };
981
982 typedef struct android_restore_scan_params {
983 char command[64];
984 int parameter;
985 int cmd_type;
986 union {
987 PRIV_CMD_HANDLER cmd_handler;
988 PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
989 };
990 } android_restore_scan_params_t;
991
992 /* function prototypes of private command handler */
993 static int wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len);
994 static int wl_android_set_roam_trigger(struct net_device *dev, char* command);
995 int wl_android_set_roam_delta(struct net_device *dev, char* command);
996 int wl_android_set_roam_scan_period(struct net_device *dev, char* command);
997 int wl_android_set_full_roam_scan_period(struct net_device *dev, char* command);
998 int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
999 int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
1000 int wl_android_set_scan_home_time(struct net_device *dev, char *command);
1001 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
1002 int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
1003 static int wl_android_set_band(struct net_device *dev, char *command);
1004 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
1005 int wl_android_set_wes_mode(struct net_device *dev, char *command);
1006 int wl_android_set_okc_mode(struct net_device *dev, char *command);
1007
1008 /* default values */
1009 #ifdef ROAM_API
1010 #define DEFAULT_ROAM_TIRGGER -75
1011 #define DEFAULT_ROAM_DELTA 10
1012 #define DEFAULT_ROAMSCANPERIOD 10
1013 #define DEFAULT_FULLROAMSCANPERIOD_SET 120
1014 #endif /* ROAM_API */
1015 #ifdef WES_SUPPORT
1016 #define DEFAULT_ROAMSCANCONTROL 0
1017 #define DEFAULT_SCANCHANNELTIME 40
1018 #ifdef BCM4361_CHIP
1019 #define DEFAULT_SCANHOMETIME 60
1020 #else
1021 #define DEFAULT_SCANHOMETIME 45
1022 #endif /* BCM4361_CHIP */
1023 #define DEFAULT_SCANHOMEAWAYTIME 100
1024 #define DEFAULT_SCANPROBES 2
1025 #define DEFAULT_DFSSCANMODE 1
1026 #define DEFAULT_WESMODE 0
1027 #define DEFAULT_OKCMODE 1
1028 #endif /* WES_SUPPORT */
1029 #define DEFAULT_BAND 0
1030 #ifdef WBTEXT
1031 #define DEFAULT_WBTEXT_ENABLE 1
1032 #endif /* WBTEXT */
1033
1034 /* restoring parameter list, please don't change order */
1035 static android_restore_scan_params_t restore_params[] =
1036 {
1037 /* wbtext need to be disabled while updating roam/scan parameters */
1038 #ifdef WBTEXT
1039 { CMD_WBTEXT_ENABLE, 0, RESTORE_TYPE_PRIV_CMD_WITH_LEN,
1040 .cmd_handler_w_len = wl_android_wbtext},
1041 #endif /* WBTEXT */
1042 #ifdef ROAM_API
1043 { CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER,
1044 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_trigger},
1045 { CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA,
1046 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_delta},
1047 { CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD,
1048 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_period},
1049 { CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
1050 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_full_roam_scan_period},
1051 #endif /* ROAM_API */
1052 #ifdef WES_SUPPORT
1053 { CMD_SETROAMSCANCONTROL, DEFAULT_ROAMSCANCONTROL,
1054 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_control},
1055 { CMD_SETSCANCHANNELTIME, DEFAULT_SCANCHANNELTIME,
1056 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time},
1057 { CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME,
1058 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time},
1059 { CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME,
1060 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time},
1061 { CMD_SETSCANNPROBES, DEFAULT_SCANPROBES,
1062 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes},
1063 { CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE,
1064 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode},
1065 { CMD_SETWESMODE, DEFAULT_WESMODE,
1066 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode},
1067 #endif /* WES_SUPPORT */
1068 { CMD_SETBAND, DEFAULT_BAND,
1069 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band},
1070 #ifdef WBTEXT
1071 { CMD_WBTEXT_ENABLE, DEFAULT_WBTEXT_ENABLE,
1072 RESTORE_TYPE_PRIV_CMD_WITH_LEN, .cmd_handler_w_len = wl_android_wbtext},
1073 #endif /* WBTEXT */
1074 { "\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}
1075 };
1076 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
1077
1078 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1079 #define CMD_GET_LATENCY_CRITICAL_DATA "GET_LATENCY_CRT_DATA"
1080 #define CMD_SET_LATENCY_CRITICAL_DATA "SET_LATENCY_CRT_DATA"
1081 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
1082
1083 typedef struct android_priv_cmd_log_cfg_table {
1084 char command[64];
1085 int enable;
1086 } android_priv_cmd_log_cfg_table_t;
1087
1088 static android_priv_cmd_log_cfg_table_t loging_params[] = {
1089 {CMD_GET_SNR, FALSE},
1090 #ifdef SUPPORT_LQCM
1091 {CMD_GET_LQCM_REPORT, FALSE},
1092 #endif
1093 #ifdef WL_GET_CU
1094 {CMD_GET_CHAN_UTIL, FALSE},
1095 #endif
1096 {"\0", FALSE}
1097 };
1098
1099 /**
1100 * Local (static) functions and variables
1101 */
1102
1103 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
1104 * time (only) in dhd_open, subsequential wifi on will be handled by
1105 * wl_android_wifi_on
1106 */
1107 int g_wifi_on = TRUE;
1108
1109 /**
1110 * Local (static) function definitions
1111 */
1112
wl_android_get_band_str(u16 band)1113 static char* wl_android_get_band_str(u16 band)
1114 {
1115 switch (band) {
1116 #ifdef WL_6G_BAND
1117 case WLC_BAND_6G:
1118 return "6G";
1119 #endif /* WL_6G_BAND */
1120 case WLC_BAND_5G:
1121 return "5G";
1122 case WLC_BAND_2G:
1123 return "2G";
1124 default:
1125 ANDROID_ERROR(("Unkown band: %d \n", band));
1126 return "Unknown band";
1127 }
1128 }
1129
1130 #ifdef WBTEXT
wl_android_bandstr_to_fwband(char * band,u8 * fw_band)1131 static int wl_android_bandstr_to_fwband(char *band, u8 *fw_band)
1132 {
1133 int err = BCME_OK;
1134
1135 if (!strcasecmp(band, "a")) {
1136 *fw_band = WLC_BAND_5G;
1137 } else if (!strcasecmp(band, "b")) {
1138 *fw_band = WLC_BAND_2G;
1139 #ifdef WL_6G_BAND
1140 } else if (!strcasecmp(band, "6g")) {
1141 *fw_band = WLC_BAND_6G;
1142 #endif /* WL_6G_BAND */
1143 } else if (!strcasecmp(band, "all")) {
1144 *fw_band = WLC_BAND_ALL;
1145 } else {
1146 err = BCME_BADBAND;
1147 }
1148
1149 return err;
1150 }
1151 #endif /* WBTEXT */
1152
1153 #ifdef WLWFDS
wl_android_set_wfds_hash(struct net_device * dev,char * command,bool enable)1154 static int wl_android_set_wfds_hash(
1155 struct net_device *dev, char *command, bool enable)
1156 {
1157 int error = 0;
1158 wl_p2p_wfds_hash_t *wfds_hash = NULL;
1159 char *smbuf = NULL;
1160 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1161
1162 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
1163 if (smbuf == NULL) {
1164 ANDROID_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n",
1165 WLC_IOCTL_MAXLEN));
1166 return -ENOMEM;
1167 }
1168
1169 if (enable) {
1170 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
1171 error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
1172 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1173 }
1174 else {
1175 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
1176 error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
1177 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1178 }
1179
1180 if (error) {
1181 ANDROID_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error));
1182 }
1183
1184 if (smbuf) {
1185 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
1186 }
1187 return error;
1188 }
1189 #endif /* WLWFDS */
1190
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)1191 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
1192 {
1193 int link_speed;
1194 int bytes_written;
1195 int error;
1196
1197 error = wldev_get_link_speed(net, &link_speed);
1198 if (error) {
1199 ANDROID_ERROR(("Get linkspeed failed \n"));
1200 return -1;
1201 }
1202
1203 /* Convert Kbps to Android Mbps */
1204 link_speed = link_speed / 1000;
1205 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
1206 ANDROID_INFO(("wl_android_get_link_speed: command result is %s\n", command));
1207 return bytes_written;
1208 }
1209
wl_android_get_rssi(struct net_device * net,char * command,int total_len)1210 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
1211 {
1212 wlc_ssid_t ssid = {0, {0}};
1213 int bytes_written = 0;
1214 int error = 0;
1215 scb_val_t scbval;
1216 char *delim = NULL;
1217 struct net_device *target_ndev = net;
1218 #ifdef WL_VIRTUAL_APSTA
1219 char *pos = NULL;
1220 struct bcm_cfg80211 *cfg;
1221 #endif /* WL_VIRTUAL_APSTA */
1222
1223 delim = strchr(command, ' ');
1224 /* For Ap mode rssi command would be
1225 * driver rssi <sta_mac_addr>
1226 * for STA/GC mode
1227 * driver rssi
1228 */
1229 if (delim) {
1230 /* Ap/GO mode
1231 * driver rssi <sta_mac_addr>
1232 */
1233 ANDROID_TRACE(("wl_android_get_rssi: cmd:%s\n", delim));
1234 /* skip space from delim after finding char */
1235 delim++;
1236 if (!(bcm_ether_atoe((delim), &scbval.ea))) {
1237 ANDROID_ERROR(("wl_android_get_rssi: address err\n"));
1238 return -1;
1239 }
1240 scbval.val = htod32(0);
1241 ANDROID_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet)));
1242 #ifdef WL_VIRTUAL_APSTA
1243 /* RSDB AP may have another virtual interface
1244 * In this case, format of private command is as following,
1245 * DRIVER rssi <sta_mac_addr> <AP interface name>
1246 */
1247
1248 /* Current position is start of MAC address string */
1249 pos = delim;
1250 delim = strchr(pos, ' ');
1251 if (delim) {
1252 /* skip space from delim after finding char */
1253 delim++;
1254 if (strnlen(delim, IFNAMSIZ)) {
1255 cfg = wl_get_cfg(net);
1256 target_ndev = wl_get_ap_netdev(cfg, delim);
1257 if (target_ndev == NULL)
1258 target_ndev = net;
1259 }
1260 }
1261 #endif /* WL_VIRTUAL_APSTA */
1262 }
1263 else {
1264 /* STA/GC mode */
1265 bzero(&scbval, sizeof(scb_val_t));
1266 }
1267
1268 error = wldev_get_rssi(target_ndev, &scbval);
1269 if (error)
1270 return -1;
1271 #if defined(RSSIOFFSET)
1272 scbval.val = wl_update_rssi_offset(net, scbval.val);
1273 #endif
1274
1275 error = wldev_get_ssid(target_ndev, &ssid);
1276 if (error)
1277 return -1;
1278 if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
1279 ANDROID_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n"));
1280 } else if (total_len <= ssid.SSID_len) {
1281 return -ENOMEM;
1282 } else {
1283 memcpy(command, ssid.SSID, ssid.SSID_len);
1284 bytes_written = ssid.SSID_len;
1285 }
1286 if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
1287 return -ENOMEM;
1288
1289 bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
1290 " rssi %d", scbval.val);
1291 command[bytes_written] = '\0';
1292
1293 ANDROID_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written));
1294 return bytes_written;
1295 }
1296
wl_android_set_suspendopt(struct net_device * dev,char * command)1297 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
1298 {
1299 int suspend_flag;
1300 int ret_now;
1301 int ret = 0;
1302
1303 suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
1304
1305 if (suspend_flag != 0) {
1306 suspend_flag = 1;
1307 }
1308 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1309
1310 if (ret_now != suspend_flag) {
1311 if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
1312 ANDROID_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n",
1313 ret_now, suspend_flag));
1314 } else {
1315 ANDROID_ERROR(("wl_android_set_suspendopt: failed %d\n", ret));
1316 }
1317 }
1318
1319 return ret;
1320 }
1321
wl_android_set_suspendmode(struct net_device * dev,char * command)1322 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
1323 {
1324 int ret = 0;
1325
1326 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
1327 int suspend_flag;
1328
1329 suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
1330 if (suspend_flag != 0)
1331 suspend_flag = 1;
1332
1333 if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
1334 ANDROID_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag));
1335 else
1336 ANDROID_ERROR(("wl_android_set_suspendmode: failed %d\n", ret));
1337 #endif
1338
1339 return ret;
1340 }
1341
1342 #ifdef WL_CFG80211
wl_android_get_80211_mode(struct net_device * dev,char * command,int total_len)1343 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
1344 {
1345 uint8 mode[5];
1346 int error = 0;
1347 int bytes_written = 0;
1348
1349 error = wldev_get_mode(dev, mode, sizeof(mode));
1350 if (error)
1351 return -1;
1352
1353 ANDROID_INFO(("wl_android_get_80211_mode: mode:%s\n", mode));
1354 bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
1355 ANDROID_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command));
1356 return bytes_written;
1357
1358 }
1359
1360 extern chanspec_t
1361 wl_chspec_driver_to_host(chanspec_t chanspec);
wl_android_get_chanspec(struct net_device * dev,char * command,int total_len)1362 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
1363 {
1364 int error = 0;
1365 int bytes_written = 0;
1366 int chsp = {0};
1367 uint16 band = 0;
1368 uint16 bw = 0;
1369 uint16 channel = 0;
1370 u32 sb = 0;
1371 chanspec_t chanspec;
1372
1373 /* command is
1374 * driver chanspec
1375 */
1376 error = wldev_iovar_getint(dev, "chanspec", &chsp);
1377 if (error)
1378 return -1;
1379
1380 chanspec = wl_chspec_driver_to_host(chsp);
1381 ANDROID_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec));
1382
1383 channel = chanspec & WL_CHANSPEC_CHAN_MASK;
1384 band = chanspec & WL_CHANSPEC_BAND_MASK;
1385 bw = chanspec & WL_CHANSPEC_BW_MASK;
1386
1387 ANDROID_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n",
1388 channel, band, bw));
1389
1390 if (bw == WL_CHANSPEC_BW_160) {
1391 bw = WL_CH_BANDWIDTH_160MHZ;
1392 } else if (bw == WL_CHANSPEC_BW_80) {
1393 bw = WL_CH_BANDWIDTH_80MHZ;
1394 } else if (bw == WL_CHANSPEC_BW_40) {
1395 bw = WL_CH_BANDWIDTH_40MHZ;
1396 } else if (bw == WL_CHANSPEC_BW_20) {
1397 bw = WL_CH_BANDWIDTH_20MHZ;
1398 } else {
1399 bw = WL_CH_BANDWIDTH_20MHZ;
1400 }
1401
1402 if (bw == WL_CH_BANDWIDTH_40MHZ) {
1403 if (CHSPEC_SB_UPPER(chanspec)) {
1404 channel += CH_10MHZ_APART;
1405 } else {
1406 channel -= CH_10MHZ_APART;
1407 }
1408 }
1409 else if (bw == WL_CH_BANDWIDTH_80MHZ) {
1410 sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
1411 if (sb == WL_CHANSPEC_CTL_SB_LL) {
1412 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
1413 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
1414 channel -= CH_10MHZ_APART;
1415 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
1416 channel += CH_10MHZ_APART;
1417 } else {
1418 /* WL_CHANSPEC_CTL_SB_UU */
1419 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
1420 }
1421 } else if (bw == WL_CH_BANDWIDTH_160MHZ) {
1422 channel = wf_chspec_primary20_chan(chanspec);
1423 }
1424 bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
1425 channel, wl_android_get_band_str(CHSPEC2WLC_BAND(chanspec)), bw);
1426
1427 ANDROID_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command));
1428 return bytes_written;
1429
1430 }
1431 #endif /* WL_CFG80211 */
1432
1433 /* returns current datarate datarate returned from firmware are in 500kbps */
wl_android_get_datarate(struct net_device * dev,char * command,int total_len)1434 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
1435 {
1436 int error = 0;
1437 int datarate = 0;
1438 int bytes_written = 0;
1439
1440 error = wldev_get_datarate(dev, &datarate);
1441 if (error)
1442 return -1;
1443
1444 ANDROID_INFO(("wl_android_get_datarate: datarate:%d\n", datarate));
1445
1446 bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
1447 return bytes_written;
1448 }
wl_android_get_assoclist(struct net_device * dev,char * command,int total_len)1449 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
1450 {
1451 int error = 0;
1452 int bytes_written = 0;
1453 uint i;
1454 int len = 0;
1455 char mac_buf[MAX_NUM_OF_ASSOCLIST *
1456 sizeof(struct ether_addr) + sizeof(uint)] = {0};
1457 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1458
1459 ANDROID_TRACE(("wl_android_get_assoclist: ENTER\n"));
1460
1461 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
1462
1463 error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
1464 if (error)
1465 return -1;
1466
1467 assoc_maclist->count = dtoh32(assoc_maclist->count);
1468 bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
1469 CMD_ASSOC_CLIENTS, assoc_maclist->count);
1470
1471 for (i = 0; i < assoc_maclist->count; i++) {
1472 len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
1473 MAC2STRDBG(assoc_maclist->ea[i].octet));
1474 /* A return value of '(total_len - bytes_written)' or more means that the
1475 * output was truncated
1476 */
1477 if ((len > 0) && (len < (total_len - bytes_written))) {
1478 bytes_written += len;
1479 } else {
1480 ANDROID_ERROR(("wl_android_get_assoclist: Insufficient buffer %d,"
1481 " bytes_written %d\n",
1482 total_len, bytes_written));
1483 bytes_written = -1;
1484 break;
1485 }
1486 }
1487 return bytes_written;
1488 }
1489
1490 #ifdef WL_CFG80211
1491 extern chanspec_t
1492 wl_chspec_host_to_driver(chanspec_t chanspec);
wl_android_set_csa(struct net_device * dev,char * command)1493 static int wl_android_set_csa(struct net_device *dev, char *command)
1494 {
1495 int error = 0;
1496 char smbuf[WLC_IOCTL_SMLEN];
1497 wl_chan_switch_t csa_arg;
1498 u32 chnsp = 0;
1499 int err = 0;
1500
1501 ANDROID_INFO(("wl_android_set_csa: command:%s\n", command));
1502
1503 command = (command + strlen(CMD_SET_CSA));
1504 /* Order is mode, count channel */
1505 if (!*++command) {
1506 ANDROID_ERROR(("wl_android_set_csa:error missing arguments\n"));
1507 return -1;
1508 }
1509 csa_arg.mode = bcm_atoi(command);
1510
1511 if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1512 ANDROID_ERROR(("Invalid mode\n"));
1513 return -1;
1514 }
1515
1516 if (!*++command) {
1517 ANDROID_ERROR(("wl_android_set_csa: error missing count\n"));
1518 return -1;
1519 }
1520 command++;
1521 csa_arg.count = bcm_atoi(command);
1522
1523 csa_arg.reg = 0;
1524 csa_arg.chspec = 0;
1525 command += 2;
1526 if (!*command) {
1527 ANDROID_ERROR(("wl_android_set_csa: error missing channel\n"));
1528 return -1;
1529 }
1530
1531 chnsp = wf_chspec_aton(command);
1532 if (chnsp == 0) {
1533 ANDROID_ERROR(("wl_android_set_csa:chsp is not correct\n"));
1534 return -1;
1535 }
1536 chnsp = wl_chspec_host_to_driver(chnsp);
1537 csa_arg.chspec = chnsp;
1538
1539 if (chnsp & WL_CHANSPEC_BAND_5G) {
1540 u32 chanspec = chnsp;
1541 err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1542 if (!err) {
1543 if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1544 ANDROID_ERROR(("Channel is radar sensitive\n"));
1545 return -1;
1546 }
1547 if (chanspec == 0) {
1548 ANDROID_ERROR(("Invalid hw channel\n"));
1549 return -1;
1550 }
1551 } else {
1552 ANDROID_ERROR(("does not support per_chan_info\n"));
1553 return -1;
1554 }
1555 ANDROID_INFO(("non radar sensitivity\n"));
1556 }
1557 error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
1558 smbuf, sizeof(smbuf), NULL);
1559 if (error) {
1560 ANDROID_ERROR(("wl_android_set_csa:set csa failed:%d\n", error));
1561 return -1;
1562 }
1563 return 0;
1564 }
1565 #endif /* WL_CFG80211 */
1566
1567 static int
wl_android_set_bcn_li_dtim(struct net_device * dev,char * command)1568 wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1569 {
1570 int ret = 0;
1571 int dtim;
1572
1573 dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1574
1575 if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1576 ANDROID_ERROR(("%s: failed, invalid dtim %d\n",
1577 __FUNCTION__, dtim));
1578 return BCME_ERROR;
1579 }
1580
1581 if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1582 ANDROID_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
1583 __FUNCTION__, dtim));
1584 } else {
1585 ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1586 }
1587
1588 return ret;
1589 }
1590
1591 static int
wl_android_set_max_dtim(struct net_device * dev,char * command)1592 wl_android_set_max_dtim(struct net_device *dev, char *command)
1593 {
1594 int ret = 0;
1595 int dtim_flag;
1596
1597 dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1598
1599 if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1600 ANDROID_TRACE(("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n",
1601 (dtim_flag ? "Enable" : "Disable")));
1602 } else {
1603 ANDROID_ERROR(("wl_android_set_max_dtim: failed %d\n", ret));
1604 }
1605
1606 return ret;
1607 }
1608
1609 #ifdef DISABLE_DTIM_IN_SUSPEND
1610 static int
wl_android_set_disable_dtim_in_suspend(struct net_device * dev,char * command)1611 wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command)
1612 {
1613 int ret = 0;
1614 int dtim_flag;
1615
1616 dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
1617
1618 if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
1619 ANDROID_TRACE(("wl_android_set_disable_dtim_in_suspend: "
1620 "use Disable bcn_li_dtim in suspend %s\n",
1621 (dtim_flag ? "Enable" : "Disable")));
1622 } else {
1623 ANDROID_ERROR(("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret));
1624 }
1625
1626 return ret;
1627 }
1628 #endif /* DISABLE_DTIM_IN_SUSPEND */
1629
wl_android_get_band(struct net_device * dev,char * command,int total_len)1630 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
1631 {
1632 uint band;
1633 int bytes_written;
1634 int error = BCME_OK;
1635
1636 error = wldev_iovar_getint(dev, "if_band", &band);
1637 if (error == BCME_UNSUPPORTED) {
1638 error = wldev_get_band(dev, &band);
1639 if (error) {
1640 return error;
1641 }
1642 }
1643 bytes_written = snprintf(command, total_len, "Band %d", band);
1644 return bytes_written;
1645 }
1646
1647 #ifdef WL_CFG80211
1648 static int
wl_android_set_band(struct net_device * dev,char * command)1649 wl_android_set_band(struct net_device *dev, char *command)
1650 {
1651 int error = 0;
1652 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1653 #ifdef WL_HOST_BAND_MGMT
1654 int ret = 0;
1655 if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
1656 if (ret == BCME_UNSUPPORTED) {
1657 /* If roam_var is unsupported, fallback to the original method */
1658 ANDROID_ERROR(("WL_HOST_BAND_MGMT defined, "
1659 "but roam_band iovar unsupported in the firmware\n"));
1660 } else {
1661 error = -1;
1662 }
1663 }
1664 if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
1665 /* Apply if roam_band iovar is not supported or band setting is AUTO */
1666 error = wldev_set_band(dev, band);
1667 }
1668 #else
1669 error = wl_cfg80211_set_if_band(dev, band);
1670 #endif /* WL_HOST_BAND_MGMT */
1671 #ifdef ROAM_CHANNEL_CACHE
1672 wl_update_roamscan_cache_by_band(dev, band);
1673 #endif /* ROAM_CHANNEL_CACHE */
1674 return error;
1675 }
1676 #endif /* WL_CFG80211 */
1677
1678 #ifdef CUSTOMER_HW4_PRIVATE_CMD
1679 #ifdef ROAM_API
1680 #ifdef WBTEXT
wl_android_check_wbtext_support(struct net_device * dev)1681 static bool wl_android_check_wbtext_support(struct net_device *dev)
1682 {
1683 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1684 return dhdp->wbtext_support;
1685 }
1686 #endif /* WBTEXT */
1687
1688 static bool
wl_android_check_wbtext_policy(struct net_device * dev)1689 wl_android_check_wbtext_policy(struct net_device *dev)
1690 {
1691 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1692 if (dhdp->wbtext_policy == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
1693 return TRUE;
1694 }
1695
1696 return FALSE;
1697 }
1698
1699 static int
wl_android_set_roam_trigger(struct net_device * dev,char * command)1700 wl_android_set_roam_trigger(struct net_device *dev, char* command)
1701 {
1702 int roam_trigger[2] = {0, 0};
1703 int error;
1704
1705 #ifdef WBTEXT
1706 if (wl_android_check_wbtext_policy(dev)) {
1707 ANDROID_ERROR(("blocked to set roam trigger. try with setting roam profile\n"));
1708 return BCME_ERROR;
1709 }
1710 #endif /* WBTEXT */
1711
1712 sscanf(command, "%*s %10d", &roam_trigger[0]);
1713 if (roam_trigger[0] >= 0) {
1714 ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1715 return BCME_ERROR;
1716 }
1717
1718 roam_trigger[1] = WLC_BAND_ALL;
1719 error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1720 sizeof(roam_trigger));
1721 if (error != BCME_OK) {
1722 ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1723 return BCME_ERROR;
1724 }
1725
1726 return BCME_OK;
1727 }
1728
1729 static int
wl_android_get_roam_trigger(struct net_device * dev,char * command,int total_len)1730 wl_android_get_roam_trigger(struct net_device *dev, char *command, int total_len)
1731 {
1732 int bytes_written, error;
1733 int roam_trigger[2] = {0, 0};
1734 uint16 band = 0;
1735 int chsp = {0};
1736 chanspec_t chanspec;
1737 #ifdef WBTEXT
1738 int i;
1739 wl_roamprof_band_t rp;
1740 uint8 roam_prof_ver = 0, roam_prof_size = 0;
1741 #endif /* WBTEXT */
1742
1743 error = wldev_iovar_getint(dev, "chanspec", &chsp);
1744 if (error != BCME_OK) {
1745 ANDROID_ERROR(("failed to get chanspec (%d)\n", error));
1746 return BCME_ERROR;
1747 }
1748
1749 chanspec = wl_chspec_driver_to_host(chsp);
1750 band = CHSPEC2WLC_BAND(chanspec);
1751
1752 if (wl_android_check_wbtext_policy(dev)) {
1753 #ifdef WBTEXT
1754 memset_s(&rp, sizeof(rp), 0, sizeof(rp));
1755 if ((error = wlc_wbtext_get_roam_prof(dev, &rp, band, &roam_prof_ver,
1756 &roam_prof_size))) {
1757 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", error));
1758 return -EINVAL;
1759 }
1760 switch (roam_prof_ver) {
1761 case WL_ROAM_PROF_VER_1:
1762 {
1763 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1764 if (rp.v2.roam_prof[i].channel_usage == 0) {
1765 roam_trigger[0] = rp.v2.roam_prof[i].roam_trigger;
1766 break;
1767 }
1768 }
1769 }
1770 break;
1771 case WL_ROAM_PROF_VER_2:
1772 {
1773 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1774 if (rp.v3.roam_prof[i].channel_usage == 0) {
1775 roam_trigger[0] = rp.v3.roam_prof[i].roam_trigger;
1776 break;
1777 }
1778 }
1779 }
1780 break;
1781 case WL_ROAM_PROF_VER_3:
1782 {
1783 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1784 if (rp.v4.roam_prof[i].channel_usage == 0) {
1785 roam_trigger[0] = rp.v4.roam_prof[i].roam_trigger;
1786 break;
1787 }
1788 }
1789 }
1790 break;
1791 default:
1792 ANDROID_ERROR(("bad version = %d \n", roam_prof_ver));
1793 return BCME_VERSION;
1794 }
1795 #endif /* WBTEXT */
1796 if (roam_trigger[0] == 0) {
1797 ANDROID_ERROR(("roam trigger was not set properly\n"));
1798 return BCME_ERROR;
1799 }
1800 } else {
1801 roam_trigger[1] = band;
1802 error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
1803 sizeof(roam_trigger));
1804 if (error != BCME_OK) {
1805 ANDROID_ERROR(("failed to get roam trigger (%d)\n", error));
1806 return BCME_ERROR;
1807 }
1808 }
1809
1810 bytes_written = snprintf(command, total_len, "%s %d",
1811 CMD_ROAMTRIGGER_GET, roam_trigger[0]);
1812
1813 return bytes_written;
1814 }
1815
1816 #ifdef WBTEXT
1817 s32
wl_cfg80211_wbtext_roam_trigger_config(struct net_device * ndev,int roam_trigger)1818 wl_cfg80211_wbtext_roam_trigger_config(struct net_device *ndev, int roam_trigger)
1819 {
1820 char *commandp = NULL;
1821 s32 ret = BCME_OK;
1822 char *data;
1823 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1824 uint8 bandidx = 0;
1825
1826 commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
1827 if (unlikely(!commandp)) {
1828 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
1829 ret = -ENOMEM;
1830 goto exit;
1831 }
1832
1833 ANDROID_INFO(("roam trigger %d\n", roam_trigger));
1834 if (roam_trigger > 0) {
1835 ANDROID_ERROR(("Invalid roam trigger value %d\n", roam_trigger));
1836 goto exit;
1837 }
1838
1839 for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
1840 char *band;
1841 int tri0, tri1, low0, low1, cu0, cu1, dur0, dur1;
1842 int tri0_dflt;
1843 if (bandidx == BAND_5G_INDEX) {
1844 band = "a";
1845 tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_A;
1846 } else {
1847 band = "b";
1848 tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_B;
1849 }
1850
1851 /* Get ROAM Profile
1852 * WBTEXT_PROFILE_CONFIG band
1853 */
1854 bzero(commandp, WLC_IOCTL_SMLEN);
1855 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
1856 CMD_WBTEXT_PROFILE_CONFIG, band);
1857 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
1858 wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1859
1860 /* Set ROAM Profile
1861 * WBTEXT_PROFILE_CONFIG band -70 roam_trigger 70 10 roam_trigger -128 0 10
1862 */
1863 sscanf(commandp, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)"
1864 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
1865 &tri0, &low0, &cu0, &dur0, &tri1, &low1, &cu1, &dur1);
1866
1867 if (tri0_dflt <= roam_trigger) {
1868 tri0 = roam_trigger + 1;
1869 } else {
1870 tri0 = tri0_dflt;
1871 }
1872
1873 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
1874 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s %d %d %d %d %d %d %d %d",
1875 CMD_WBTEXT_PROFILE_CONFIG, band,
1876 tri0, roam_trigger, cu0, dur0, roam_trigger, low1, cu1, dur1);
1877
1878 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1879 if (ret != BCME_OK) {
1880 ANDROID_ERROR(("Failed to set roam_prof %s error = %d\n", data, ret));
1881 goto exit;
1882 }
1883 }
1884
1885 exit:
1886 if (commandp) {
1887 MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
1888 }
1889 return ret;
1890 }
1891 #endif /* WBTEXT */
1892
1893 static int
wl_android_set_roam_trigger_legacy(struct net_device * dev,char * command)1894 wl_android_set_roam_trigger_legacy(struct net_device *dev, char* command)
1895 {
1896 int roam_trigger[2] = {0, 0};
1897 int error;
1898
1899 sscanf(command, "%*s %10d", &roam_trigger[0]);
1900 if (roam_trigger[0] >= 0) {
1901 ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1902 return BCME_ERROR;
1903 }
1904
1905 if (wl_android_check_wbtext_policy(dev)) {
1906 #ifdef WBTEXT
1907 error = wl_cfg80211_wbtext_roam_trigger_config(dev, roam_trigger[0]);
1908 if (error != BCME_OK) {
1909 ANDROID_ERROR(("failed to set roam prof trigger (%d)\n", error));
1910 return BCME_ERROR;
1911 }
1912 #endif /* WBTEXT */
1913 } else {
1914 if (roam_trigger[0] >= 0) {
1915 ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1916 return BCME_ERROR;
1917 }
1918
1919 roam_trigger[1] = WLC_BAND_ALL;
1920 error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1921 sizeof(roam_trigger));
1922 if (error != BCME_OK) {
1923 ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1924 return BCME_ERROR;
1925 }
1926 }
1927
1928 return BCME_OK;
1929 }
1930
wl_android_set_roam_delta(struct net_device * dev,char * command)1931 int wl_android_set_roam_delta(
1932 struct net_device *dev, char* command)
1933 {
1934 int roam_delta[2];
1935
1936 sscanf(command, "%*s %10d", &roam_delta[0]);
1937 roam_delta[1] = WLC_BAND_ALL;
1938
1939 return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
1940 sizeof(roam_delta));
1941 }
1942
wl_android_get_roam_delta(struct net_device * dev,char * command,int total_len)1943 static int wl_android_get_roam_delta(
1944 struct net_device *dev, char *command, int total_len)
1945 {
1946 int bytes_written;
1947 int roam_delta[2] = {0, 0};
1948
1949 roam_delta[1] = WLC_BAND_2G;
1950 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1951 sizeof(roam_delta))) {
1952 roam_delta[1] = WLC_BAND_5G;
1953 #ifdef WL_6G_BAND
1954 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1955 sizeof(roam_delta))) {
1956 roam_delta[1] = WLC_BAND_6G;
1957 #endif /* WL_6G_BAND */
1958 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1959 sizeof(roam_delta))) {
1960 return -1;
1961 }
1962 #ifdef WL_6G_BAND
1963 }
1964 #endif /* WL_6G_BAND */
1965 }
1966
1967 bytes_written = snprintf(command, total_len, "%s %d",
1968 CMD_ROAMDELTA_GET, roam_delta[0]);
1969
1970 return bytes_written;
1971 }
1972
wl_android_set_roam_scan_period(struct net_device * dev,char * command)1973 int wl_android_set_roam_scan_period(
1974 struct net_device *dev, char* command)
1975 {
1976 int roam_scan_period = 0;
1977
1978 sscanf(command, "%*s %10d", &roam_scan_period);
1979 return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
1980 sizeof(roam_scan_period));
1981 }
1982
wl_android_get_roam_scan_period(struct net_device * dev,char * command,int total_len)1983 static int wl_android_get_roam_scan_period(
1984 struct net_device *dev, char *command, int total_len)
1985 {
1986 int bytes_written;
1987 int roam_scan_period = 0;
1988
1989 if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
1990 sizeof(roam_scan_period)))
1991 return -1;
1992
1993 bytes_written = snprintf(command, total_len, "%s %d",
1994 CMD_ROAMSCANPERIOD_GET, roam_scan_period);
1995
1996 return bytes_written;
1997 }
1998
wl_android_set_full_roam_scan_period(struct net_device * dev,char * command)1999 int wl_android_set_full_roam_scan_period(
2000 struct net_device *dev, char* command)
2001 {
2002 int error = 0;
2003 int full_roam_scan_period = 0;
2004 char smbuf[WLC_IOCTL_SMLEN];
2005
2006 sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
2007 WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
2008
2009 error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
2010 sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
2011 if (error) {
2012 ANDROID_ERROR(("Failed to set full roam scan period, error = %d\n", error));
2013 }
2014
2015 return error;
2016 }
2017
wl_android_get_full_roam_scan_period(struct net_device * dev,char * command,int total_len)2018 static int wl_android_get_full_roam_scan_period(
2019 struct net_device *dev, char *command, int total_len)
2020 {
2021 int error;
2022 int bytes_written;
2023 int full_roam_scan_period = 0;
2024
2025 error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
2026
2027 if (error) {
2028 ANDROID_ERROR(("%s: get full roam scan period failed code %d\n",
2029 __func__, error));
2030 return -1;
2031 } else {
2032 ANDROID_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
2033 }
2034
2035 bytes_written = snprintf(command, total_len, "%s %d",
2036 CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
2037
2038 return bytes_written;
2039 }
2040
wl_android_set_country_rev(struct net_device * dev,char * command)2041 int wl_android_set_country_rev(
2042 struct net_device *dev, char* command)
2043 {
2044 int error = 0;
2045 wl_country_t cspec = {{0}, 0, {0} };
2046 char country_code[WLC_CNTRY_BUF_SZ];
2047 char smbuf[WLC_IOCTL_SMLEN];
2048 int rev = 0;
2049
2050 bzero(country_code, sizeof(country_code));
2051 sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
2052 WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
2053
2054 memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
2055 memcpy(cspec.ccode, country_code, sizeof(country_code));
2056 cspec.rev = rev;
2057
2058 error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
2059 sizeof(cspec), smbuf, sizeof(smbuf), NULL);
2060
2061 if (error) {
2062 ANDROID_ERROR(("wl_android_set_country_rev: set country '%s/%d' failed code %d\n",
2063 cspec.ccode, cspec.rev, error));
2064 } else {
2065 dhd_bus_country_set(dev, &cspec, true);
2066 ANDROID_INFO(("wl_android_set_country_rev: set country '%s/%d'\n",
2067 cspec.ccode, cspec.rev));
2068 }
2069
2070 return error;
2071 }
2072
wl_android_get_country_rev(struct net_device * dev,char * command,int total_len)2073 static int wl_android_get_country_rev(
2074 struct net_device *dev, char *command, int total_len)
2075 {
2076 int error;
2077 int bytes_written;
2078 char smbuf[WLC_IOCTL_SMLEN];
2079 wl_country_t cspec;
2080
2081 error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
2082 sizeof(smbuf), NULL);
2083
2084 if (error) {
2085 ANDROID_ERROR(("wl_android_get_country_rev: get country failed code %d\n",
2086 error));
2087 return -1;
2088 } else {
2089 memcpy(&cspec, smbuf, sizeof(cspec));
2090 ANDROID_INFO(("wl_android_get_country_rev: get country '%c%c %d'\n",
2091 cspec.ccode[0], cspec.ccode[1], cspec.rev));
2092 }
2093
2094 bytes_written = snprintf(command, total_len, "%s %c%c %d",
2095 CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
2096
2097 return bytes_written;
2098 }
2099 #endif /* ROAM_API */
2100
2101 #ifdef WES_SUPPORT
wl_android_get_roam_scan_control(struct net_device * dev,char * command,int total_len)2102 int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
2103 {
2104 int error = 0;
2105 int bytes_written = 0;
2106 int mode = 0;
2107
2108 error = get_roamscan_mode(dev, &mode);
2109 if (error) {
2110 ANDROID_ERROR(("wl_android_get_roam_scan_control: Failed to get Scan Control,"
2111 " error = %d\n", error));
2112 return -1;
2113 }
2114
2115 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
2116
2117 return bytes_written;
2118 }
2119
wl_android_set_roam_scan_control(struct net_device * dev,char * command)2120 int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
2121 {
2122 int error = 0;
2123 int mode = 0;
2124
2125 if (sscanf(command, "%*s %d", &mode) != 1) {
2126 ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to get Parameter\n"));
2127 return -1;
2128 }
2129
2130 error = set_roamscan_mode(dev, mode);
2131 if (error) {
2132 ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to set Scan Control %d,"
2133 " error = %d\n",
2134 mode, error));
2135 return -1;
2136 }
2137
2138 return 0;
2139 }
2140
2141 int
wl_android_get_roam_scan_channels(struct net_device * dev,char * command,int total_len,char * cmd)2142 wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len, char *cmd)
2143 {
2144 int bytes_written = 0;
2145 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2146 int nchan = 0, i = 0;
2147 int buf_avail, len;
2148
2149 nchan = get_roamscan_chanspec_list(dev, chanspecs);
2150 if (nchan < 0) {
2151 ANDROID_ERROR(("Failed to Set roamscan channels, n_chan = %d\n", nchan));
2152 return BCME_ERROR;
2153 }
2154
2155 bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2156
2157 buf_avail = total_len - bytes_written;
2158 for (i = 0; i < nchan; i++) {
2159 /* A return value of 'buf_avail' or more means that the output was truncated */
2160 len = snprintf(command + bytes_written, buf_avail, " %d",
2161 CHSPEC_CHANNEL(chanspecs[i]));
2162 if (len >= buf_avail) {
2163 ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2164 ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2165 bytes_written = -1;
2166 break;
2167 }
2168 /* 'buf_avail' decremented by number of bytes written */
2169 buf_avail -= len;
2170 bytes_written += len;
2171 }
2172 ANDROID_INFO(("%s\n", command));
2173 return bytes_written;
2174 }
2175
2176 #define CHANNEL_IDX 1
2177 int
wl_android_set_roam_scan_channels(struct net_device * dev,char * command)2178 wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
2179 {
2180 int error = BCME_OK, i;
2181 unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
2182 uint16 nchan = 0, channel = 0;
2183 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2184
2185 nchan = p[0];
2186 if (nchan > MAX_ROAM_CHANNEL) {
2187 ANDROID_ERROR(("Failed to Set roamscan channnels, n_chan = %d\n", nchan));
2188 return BCME_BADARG;
2189 }
2190
2191 for (i = 0; i < nchan; i++) {
2192 channel = p[i + CHANNEL_IDX];
2193 /* Convert chanspec from channel */
2194 chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2195 }
2196
2197 error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2198 if (error) {
2199 ANDROID_ERROR(("Failed to Set Scan Channels %d, error = %d\n", p[0], error));
2200 return error;
2201 }
2202
2203 return error;
2204 }
2205
2206 int
wl_android_add_roam_scan_channels(struct net_device * dev,char * command,uint cmdlen)2207 wl_android_add_roam_scan_channels(struct net_device *dev, char *command, uint cmdlen)
2208 {
2209 int i, error = BCME_OK;
2210 char *pcmd, *token;
2211 uint16 nchan = 0, channel = 0;
2212 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2213
2214 pcmd = (command + cmdlen + 1);
2215 /* Parse roam channel count */
2216 token = bcmstrtok(&pcmd, " ", NULL);
2217 if (!token) {
2218 ANDROID_ERROR(("Bad argument!\n"));
2219 return BCME_BADARG;
2220 }
2221 nchan = bcm_atoi(token);
2222 if (nchan > MAX_ROAM_CHANNEL) {
2223 ANDROID_ERROR(("Failed to Add roamscan channnels, n_chan = %d\n", nchan));
2224 return BCME_BADARG;
2225 }
2226
2227 for (i = 0; i < nchan; i++) {
2228 /* Parse roam channel list */
2229 token = bcmstrtok(&pcmd, " ", NULL);
2230 if (!token) {
2231 ANDROID_ERROR(("Bad argument!\n"));
2232 return BCME_BADARG;
2233 }
2234 channel = bcm_atoi(token);
2235 /* Convert chanspec from channel */
2236 if (channel > 0) {
2237 chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2238 }
2239 }
2240
2241 error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2242 if (error) {
2243 ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2244 }
2245
2246 return error;
2247 }
2248
2249 int
wl_android_get_roam_scan_freqs(struct net_device * dev,char * command,int total_len,char * cmd)2250 wl_android_get_roam_scan_freqs(struct net_device *dev, char *command, int total_len, char *cmd)
2251 {
2252 int bytes_written = 0;
2253 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2254 int nchan = 0, i = 0;
2255 int buf_avail, len;
2256 u32 freq = 0;
2257 uint start_factor = 0;
2258
2259 nchan = get_roamscan_chanspec_list(dev, chanspecs);
2260 if (nchan < 0) {
2261 ANDROID_ERROR(("Failed to Get roamscan frequencies, n_chan = %d\n", nchan));
2262 return BCME_ERROR;
2263 }
2264
2265 bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2266
2267 buf_avail = total_len - bytes_written;
2268 for (i = 0; i < nchan; i++) {
2269 start_factor = WF_CHAN_FACTOR_2_4_G;
2270 if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_5G) {
2271 start_factor = WF_CHAN_FACTOR_5_G;
2272 } else if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_6G) {
2273 start_factor = WF_CHAN_FACTOR_6_G;
2274 }
2275 freq = wf_channel2mhz(CHSPEC_CHANNEL(chanspecs[i]), start_factor);
2276 /* A return value of 'buf_avail' or more means that the output was truncated */
2277 len = snprintf(command + bytes_written, buf_avail, " %d", freq);
2278 if (len >= buf_avail) {
2279 ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2280 bytes_written = -1;
2281 break;
2282 }
2283 /* 'buf_avail' decremented by number of bytes written */
2284 buf_avail -= len;
2285 bytes_written += len;
2286 }
2287 ANDROID_INFO(("%s\n", command));
2288 return bytes_written;
2289 }
2290
2291 int
wl_android_set_roam_scan_freqs(struct net_device * dev,char * command)2292 wl_android_set_roam_scan_freqs(struct net_device *dev, char *command)
2293 {
2294 int error = BCME_OK, i;
2295 char *pcmd, *token;
2296 uint16 nchan = 0, freq = 0;
2297 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2298
2299 pcmd = (command + strlen(CMD_SETROAMSCANFREQS) + 1);
2300 /* Parse roam channel count */
2301 token = bcmstrtok(&pcmd, " ", NULL);
2302 if (!token) {
2303 ANDROID_ERROR(("Bad argument!\n"));
2304 return BCME_BADARG;
2305 }
2306 nchan = bcm_atoi(token);
2307 if (nchan > MAX_ROAM_CHANNEL) {
2308 ANDROID_ERROR(("Failed to Set roamscan frequencies, n_chan = %d\n", nchan));
2309 return BCME_BADARG;
2310 }
2311
2312 for (i = 0; i < nchan; i++) {
2313 /* Parse roam channel list */
2314 token = bcmstrtok(&pcmd, " ", NULL);
2315 if (!token) {
2316 ANDROID_ERROR(("Bad argument!\n"));
2317 return BCME_BADARG;
2318 }
2319 freq = bcm_atoi(token);
2320 /* Convert chanspec from frequency */
2321 chanspecs[i] = wl_freq_to_chanspec(freq);
2322 }
2323
2324 error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2325 if (error) {
2326 ANDROID_ERROR(("Failed to set Scan Channels %d, error = %d\n", nchan, error));
2327 return error;
2328 }
2329
2330 return error;
2331 }
2332
2333 int
wl_android_add_roam_scan_freqs(struct net_device * dev,char * command,uint cmdlen)2334 wl_android_add_roam_scan_freqs(struct net_device *dev, char *command, uint cmdlen)
2335 {
2336 int i, error = BCME_OK;
2337 char *pcmd, *token;
2338 uint16 nchan = 0, freq = 0;
2339 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2340
2341 pcmd = (command + cmdlen + 1);
2342 /* Parse roam channel count */
2343 token = bcmstrtok(&pcmd, " ", NULL);
2344 if (!token) {
2345 ANDROID_ERROR(("Bad argument!\n"));
2346 return BCME_BADARG;
2347 }
2348 nchan = bcm_atoi(token);
2349 if (nchan > MAX_ROAM_CHANNEL) {
2350 ANDROID_ERROR(("Failed to Add roamscan frequencies, n_chan = %d\n", nchan));
2351 return BCME_BADARG;
2352 }
2353
2354 for (i = 0; i < nchan; i++) {
2355 /* Parse roam channel list */
2356 token = bcmstrtok(&pcmd, " ", NULL);
2357 if (!token) {
2358 ANDROID_ERROR(("Bad argument!\n"));
2359 return BCME_BADARG;
2360 }
2361 freq = bcm_atoi(token);
2362 /* Convert chanspec from channel */
2363 if (freq > 0) {
2364 chanspecs[i] = wl_freq_to_chanspec(freq);
2365 }
2366 }
2367
2368 error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2369 if (error) {
2370 ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2371 }
2372
2373 return error;
2374 }
2375
2376 int
wl_android_get_scan_channel_time(struct net_device * dev,char * command,int total_len)2377 wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
2378 {
2379 int error = BCME_OK;
2380 int bytes_written = 0;
2381 int time = 0;
2382
2383 error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2384 if (error) {
2385 ANDROID_ERROR(("Failed to get Scan Channel Time, error = %d\n", error));
2386 return BCME_ERROR;
2387 }
2388
2389 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
2390
2391 return bytes_written;
2392 }
2393
2394 int
wl_android_set_scan_channel_time(struct net_device * dev,char * command)2395 wl_android_set_scan_channel_time(struct net_device *dev, char *command)
2396 {
2397 int error = BCME_OK;
2398 int time = 0;
2399
2400 if (sscanf(command, "%*s %d", &time) != 1) {
2401 ANDROID_ERROR(("Failed to get Parameter\n"));
2402 return BCME_ERROR;
2403 }
2404
2405 if (time == 0) {
2406 /* Set default value when Private param is 0. */
2407 time = DHD_SCAN_ASSOC_ACTIVE_TIME;
2408 }
2409 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2410 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
2411 error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2412 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2413 if (error) {
2414 ANDROID_ERROR(("Failed to set Scan Channel Time %d, error = %d\n", time, error));
2415 return BCME_ERROR;
2416 }
2417
2418 return error;
2419 }
2420
2421 int
wl_android_get_scan_unassoc_time(struct net_device * dev,char * command,int total_len)2422 wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
2423 {
2424 int error = BCME_OK;
2425 int bytes_written = 0;
2426 int time = 0;
2427
2428 error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2429 if (error) {
2430 ANDROID_ERROR(("Failed to get Scan Unassoc Time, error = %d\n", error));
2431 return BCME_ERROR;
2432 }
2433
2434 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
2435
2436 return bytes_written;
2437 }
2438
2439 int
wl_android_set_scan_unassoc_time(struct net_device * dev,char * command)2440 wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
2441 {
2442 int error = BCME_OK;
2443 int time = 0;
2444
2445 if (sscanf(command, "%*s %d", &time) != 1) {
2446 ANDROID_ERROR(("Failed to get Parameter\n"));
2447 return BCME_ERROR;
2448 }
2449 if (time == 0) {
2450 /* Set default value when Private param is 0. */
2451 time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
2452 }
2453 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2454 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
2455 error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2456 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2457 if (error) {
2458 ANDROID_ERROR(("Failed to set Scan Unassoc Time %d, error = %d\n", time, error));
2459 return BCME_ERROR;
2460 }
2461
2462 return error;
2463 }
2464
2465 int
wl_android_get_scan_passive_time(struct net_device * dev,char * command,int total_len)2466 wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
2467 {
2468 int error = BCME_OK;
2469 int bytes_written = 0;
2470 int time = 0;
2471
2472 error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2473 if (error) {
2474 ANDROID_ERROR(("Failed to get Scan Passive Time, error = %d\n", error));
2475 return BCME_ERROR;
2476 }
2477
2478 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
2479
2480 return bytes_written;
2481 }
2482
2483 int
wl_android_set_scan_passive_time(struct net_device * dev,char * command)2484 wl_android_set_scan_passive_time(struct net_device *dev, char *command)
2485 {
2486 int error = BCME_OK;
2487 int time = 0;
2488
2489 if (sscanf(command, "%*s %d", &time) != 1) {
2490 ANDROID_ERROR(("Failed to get Parameter\n"));
2491 return BCME_ERROR;
2492 }
2493 if (time == 0) {
2494 /* Set default value when Private param is 0. */
2495 time = DHD_SCAN_PASSIVE_TIME;
2496 }
2497 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2498 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
2499 error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2500 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2501 if (error) {
2502 ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n", time, error));
2503 return BCME_ERROR;
2504 }
2505
2506 return error;
2507 }
2508
2509 int
wl_android_get_scan_home_time(struct net_device * dev,char * command,int total_len)2510 wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
2511 {
2512 int error = BCME_OK;
2513 int bytes_written = 0;
2514 int time = 0;
2515
2516 error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
2517 if (error) {
2518 ANDROID_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
2519 return BCME_ERROR;
2520 }
2521
2522 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
2523
2524 return bytes_written;
2525 }
2526
wl_android_set_scan_home_time(struct net_device * dev,char * command)2527 int wl_android_set_scan_home_time(struct net_device *dev, char *command)
2528 {
2529 int error = BCME_OK;
2530 int time = 0;
2531
2532 if (sscanf(command, "%*s %d", &time) != 1) {
2533 ANDROID_ERROR(("Failed to get Parameter\n"));
2534 return BCME_ERROR;
2535 }
2536 if (time == 0) {
2537 /* Set default value when Private param is 0. */
2538 time = DHD_SCAN_HOME_TIME;
2539 }
2540 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2541 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
2542 error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
2543 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2544 if (error) {
2545 ANDROID_ERROR(("Failed to set Scan Home Time %d, error = %d\n", time, error));
2546 return BCME_ERROR;
2547 }
2548
2549 return error;
2550 }
2551
2552 int
wl_android_get_scan_home_away_time(struct net_device * dev,char * command,int total_len)2553 wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
2554 {
2555 int error = BCME_OK;
2556 int bytes_written = 0;
2557 int time = 0;
2558
2559 error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
2560 if (error) {
2561 ANDROID_ERROR(("Failed to get Scan Home Away Time, error = %d\n", error));
2562 return BCME_ERROR;
2563 }
2564
2565 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
2566
2567 return bytes_written;
2568 }
2569
2570 int
wl_android_set_scan_home_away_time(struct net_device * dev,char * command)2571 wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
2572 {
2573 int error = BCME_OK;
2574 int time = 0;
2575
2576 if (sscanf(command, "%*s %d", &time) != 1) {
2577 ANDROID_ERROR(("Failed to get Parameter\n"));
2578 return BCME_ERROR;
2579 }
2580 if (time == 0) {
2581 /* Set default value when Private param is 0. */
2582 time = DHD_SCAN_HOME_AWAY_TIME;
2583 }
2584 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2585 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
2586 error = wldev_iovar_setint(dev, "scan_home_away_time", time);
2587 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2588 if (error) {
2589 ANDROID_ERROR(("Failed to set Scan Home Away Time %d, error = %d\n", time, error));
2590 return BCME_ERROR;
2591 }
2592
2593 return error;
2594 }
2595
2596 int
wl_android_get_scan_nprobes(struct net_device * dev,char * command,int total_len)2597 wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
2598 {
2599 int error = BCME_OK;
2600 int bytes_written = 0;
2601 int num = 0;
2602
2603 error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
2604 if (error) {
2605 ANDROID_ERROR(("Failed to get Scan NProbes, error = %d\n", error));
2606 return BCME_ERROR;
2607 }
2608
2609 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
2610
2611 return bytes_written;
2612 }
2613
2614 int
wl_android_set_scan_nprobes(struct net_device * dev,char * command)2615 wl_android_set_scan_nprobes(struct net_device *dev, char *command)
2616 {
2617 int error = BCME_OK;
2618 int num = 0;
2619
2620 if (sscanf(command, "%*s %d", &num) != 1) {
2621 ANDROID_ERROR(("Failed to get Parameter\n"));
2622 return BCME_ERROR;
2623 }
2624
2625 error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
2626 if (error) {
2627 ANDROID_ERROR(("Failed to set Scan NProbes %d, error = %d\n", num, error));
2628 return BCME_ERROR;
2629 }
2630
2631 return error;
2632 }
2633
2634 int
wl_android_get_scan_dfs_channel_mode(struct net_device * dev,char * command,int total_len)2635 wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
2636 {
2637 int error = BCME_OK;
2638 int bytes_written = 0;
2639 int mode = 0;
2640 int scan_passive_time = 0;
2641
2642 error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
2643 if (error) {
2644 ANDROID_ERROR(("Failed to get Passive Time, error = %d\n", error));
2645 return BCME_ERROR;
2646 }
2647
2648 if (scan_passive_time == 0) {
2649 mode = 0;
2650 } else {
2651 mode = 1;
2652 }
2653
2654 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
2655
2656 return bytes_written;
2657 }
2658
2659 int
wl_android_set_scan_dfs_channel_mode(struct net_device * dev,char * command)2660 wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
2661 {
2662 int error = BCME_OK;
2663 int mode = 0;
2664 int scan_passive_time = 0;
2665
2666 if (sscanf(command, "%*s %d", &mode) != 1) {
2667 ANDROID_ERROR(("Failed to get Parameter\n"));
2668 return BCME_ERROR;
2669 }
2670
2671 if (mode == 1) {
2672 scan_passive_time = DHD_SCAN_PASSIVE_TIME;
2673 } else if (mode == 0) {
2674 scan_passive_time = 0;
2675 } else {
2676 ANDROID_ERROR(("Failed to set Scan DFS channel mode %d\n", mode));
2677 return BCME_ERROR;
2678 }
2679 error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
2680 if (error) {
2681 ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n",
2682 scan_passive_time, error));
2683 return BCME_ERROR;
2684 }
2685
2686 return error;
2687 }
2688
2689 #define JOINPREFFER_BUF_SIZE 12
2690
2691 static int
wl_android_set_join_prefer(struct net_device * dev,char * command)2692 wl_android_set_join_prefer(struct net_device *dev, char *command)
2693 {
2694 int error = BCME_OK;
2695 char smbuf[WLC_IOCTL_SMLEN];
2696 uint8 buf[JOINPREFFER_BUF_SIZE];
2697 char *pcmd;
2698 int total_len_left;
2699 int i;
2700 char hex[] = "XX";
2701 #ifdef WBTEXT
2702 int turn_on = OFF;
2703 char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
2704 #endif /* WBTEXT */
2705
2706 pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
2707 total_len_left = strlen(pcmd);
2708
2709 bzero(buf, sizeof(buf));
2710
2711 if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
2712 ANDROID_ERROR(("wl_android_set_join_prefer: Failed to get Parameter\n"));
2713 return BCME_ERROR;
2714 }
2715
2716 /* Store the MSB first, as required by join_pref */
2717 for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
2718 hex[0] = *pcmd++;
2719 hex[1] = *pcmd++;
2720 buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
2721 }
2722
2723 #ifdef WBTEXT
2724 /* Set WBTEXT mode */
2725 turn_on = memcmp(buf, clear, sizeof(buf)) == 0 ? TRUE : FALSE;
2726 error = wl_android_wbtext_enable(dev, turn_on);
2727 if (error) {
2728 ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2729 error, (turn_on ? "Enable" : "Disable")));
2730 }
2731 #endif /* WBTEXT */
2732
2733 prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
2734 error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
2735 smbuf, sizeof(smbuf), NULL);
2736 if (error) {
2737 ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
2738 }
2739
2740 return error;
2741 }
2742
wl_android_send_action_frame(struct net_device * dev,char * command,int total_len)2743 int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
2744 {
2745 int error = -1;
2746 android_wifi_af_params_t *params = NULL;
2747 wl_action_frame_t *action_frame = NULL;
2748 wl_af_params_t *af_params = NULL;
2749 char *smbuf = NULL;
2750 struct ether_addr tmp_bssid;
2751 int tmp_channel = 0;
2752 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2753
2754 if (total_len <
2755 (strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
2756 ANDROID_ERROR(("wl_android_send_action_frame: Invalid parameters \n"));
2757 goto send_action_frame_out;
2758 }
2759
2760 params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
2761
2762 if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
2763 ANDROID_ERROR(("wl_android_send_action_frame: Requested action frame len"
2764 " was out of range(%d)\n",
2765 params->len));
2766 goto send_action_frame_out;
2767 }
2768
2769 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
2770 if (smbuf == NULL) {
2771 ANDROID_ERROR(("wl_android_send_action_frame: failed to allocated memory %d bytes\n",
2772 WLC_IOCTL_MAXLEN));
2773 goto send_action_frame_out;
2774 }
2775
2776 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
2777 if (af_params == NULL) {
2778 ANDROID_ERROR(("wl_android_send_action_frame: unable to allocate frame\n"));
2779 goto send_action_frame_out;
2780 }
2781
2782 bzero(&tmp_bssid, ETHER_ADDR_LEN);
2783 if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
2784 bzero(&tmp_bssid, ETHER_ADDR_LEN);
2785
2786 error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2787 if (error) {
2788 bzero(&tmp_bssid, ETHER_ADDR_LEN);
2789 ANDROID_ERROR(("wl_android_send_action_frame: failed to get bssid,"
2790 " error=%d\n", error));
2791 goto send_action_frame_out;
2792 }
2793 }
2794
2795 if (params->channel < 0) {
2796 struct channel_info ci;
2797 bzero(&ci, sizeof(ci));
2798 error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
2799 if (error) {
2800 ANDROID_ERROR(("wl_android_send_action_frame: failed to get channel,"
2801 " error=%d\n", error));
2802 goto send_action_frame_out;
2803 }
2804
2805 tmp_channel = ci.hw_channel;
2806 }
2807 else {
2808 tmp_channel = params->channel;
2809 }
2810
2811 af_params->channel = tmp_channel;
2812 af_params->dwell_time = params->dwell_time;
2813 memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2814 action_frame = &af_params->action_frame;
2815
2816 action_frame->packetId = 0;
2817 memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
2818 action_frame->len = (uint16)params->len;
2819 memcpy(action_frame->data, params->data, action_frame->len);
2820
2821 error = wldev_iovar_setbuf(dev, "actframe", af_params,
2822 sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
2823 if (error) {
2824 ANDROID_ERROR(("wl_android_send_action_frame: failed to set action frame,"
2825 " error=%d\n", error));
2826 }
2827
2828 send_action_frame_out:
2829 if (af_params) {
2830 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
2831 }
2832
2833 if (smbuf) {
2834 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
2835 }
2836
2837 if (error)
2838 return -1;
2839 else
2840 return 0;
2841 }
2842
2843 int
wl_android_reassoc(struct net_device * dev,char * command,int total_len)2844 wl_android_reassoc(struct net_device *dev, char *command, int total_len)
2845 {
2846 int error = BCME_OK;
2847 android_wifi_reassoc_params_t *params = NULL;
2848 chanspec_t channel;
2849 u32 params_size;
2850 wl_reassoc_params_t reassoc_params;
2851 char pcmd[WL_PRIV_CMD_LEN + 1];
2852
2853 sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s *", pcmd);
2854 if (total_len < (strlen(pcmd) + 1 + sizeof(android_wifi_reassoc_params_t))) {
2855 ANDROID_ERROR(("Invalid parameters %s\n", command));
2856 return BCME_ERROR;
2857 }
2858 params = (android_wifi_reassoc_params_t *)(command + strlen(pcmd) + 1);
2859
2860 bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
2861
2862 if (bcm_ether_atoe((const char *)params->bssid,
2863 (struct ether_addr *)&reassoc_params.bssid) == 0) {
2864 ANDROID_ERROR(("Invalid bssid \n"));
2865 return BCME_BADARG;
2866 }
2867
2868 if (params->channel < 0) {
2869 ANDROID_ERROR(("Invalid Channel %d\n", params->channel));
2870 return BCME_BADARG;
2871 }
2872
2873 reassoc_params.chanspec_num = 1;
2874
2875 channel = params->channel;
2876 if (CHANNEL_IS_2G(channel) || CHANNEL_IS_5G(channel)) {
2877 /* If reassoc Param is BSSID and Channel */
2878 reassoc_params.chanspec_list[0] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2879 } else {
2880 /* If reassoc Param is BSSID and Frequency */
2881 reassoc_params.chanspec_list[0] = wl_freq_to_chanspec(channel);
2882 }
2883 params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
2884
2885 error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
2886 if (error) {
2887 ANDROID_ERROR(("failed to reassoc, error=%d\n", error));
2888 return error;
2889 }
2890 return error;
2891 }
2892
wl_android_get_wes_mode(struct net_device * dev,char * command,int total_len)2893 int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
2894 {
2895 int bytes_written = 0;
2896 int mode = 0;
2897
2898 mode = wl_cfg80211_get_wes_mode(dev);
2899
2900 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
2901
2902 return bytes_written;
2903 }
2904
wl_android_set_wes_mode(struct net_device * dev,char * command)2905 int wl_android_set_wes_mode(struct net_device *dev, char *command)
2906 {
2907 int error = 0;
2908 int mode = 0;
2909
2910 if (sscanf(command, "%*s %d", &mode) != 1) {
2911 ANDROID_ERROR(("wl_android_set_wes_mode: Failed to get Parameter\n"));
2912 return -1;
2913 }
2914
2915 error = wl_cfg80211_set_wes_mode(dev, mode);
2916 if (error) {
2917 ANDROID_ERROR(("wl_android_set_wes_mode: Failed to set WES Mode %d, error = %d\n",
2918 mode, error));
2919 return -1;
2920 }
2921
2922 return 0;
2923 }
2924
2925 int
wl_android_get_ncho_mode(struct net_device * dev,char * command,int total_len)2926 wl_android_get_ncho_mode(struct net_device *dev, char *command, int total_len)
2927 {
2928 int bytes_written = 0;
2929 int mode = 0;
2930
2931 mode = wl_cfg80211_get_ncho_mode(dev);
2932
2933 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETNCHOMODE, mode);
2934
2935 return bytes_written;
2936 }
2937
2938 int
wl_android_set_ncho_mode(struct net_device * dev,int mode)2939 wl_android_set_ncho_mode(struct net_device *dev, int mode)
2940 {
2941 char cmd[WLC_IOCTL_SMLEN];
2942 int error = BCME_OK;
2943
2944 #ifdef WBTEXT
2945 /* Set WBTEXT mode */
2946 error = wl_android_wbtext_enable(dev, !mode);
2947 if (error) {
2948 ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2949 error, (mode ? "Disable" : "Enable")));
2950 }
2951 #endif /* WBTEXT */
2952 /* Set Piority roam mode */
2953 error = wl_android_priority_roam_enable(dev, !mode);
2954 if (error) {
2955 ANDROID_ERROR(("Failed to set Priority Roam(%d) = %s\n",
2956 error, (mode ? "Disable" : "Enable")));
2957 }
2958 #ifdef CONFIG_SILENT_ROAM
2959 /* Set Silent roam mode */
2960 error = wl_android_sroam_turn_on(dev, !mode);
2961 if (error) {
2962 ANDROID_ERROR(("Failed to set SROAM(%d) = %s\n",
2963 error, (mode ? "Disable" : "Enable")));
2964 }
2965 #endif /* CONFIG_SILENT_ROAM */
2966 /* Set RCROAM(ROAMEXT) mode */
2967 error = wl_android_rcroam_turn_on(dev, !mode);
2968 if (error) {
2969 ANDROID_ERROR(("Failed to set RCROAM(%d) = %s\n",
2970 error, (mode ? "Disable" : "Enable")));
2971 }
2972
2973 if (mode == OFF) {
2974 /* restore NCHO set parameters */
2975 bzero(cmd, WLC_IOCTL_SMLEN);
2976 snprintf(cmd, WLC_IOCTL_SMLEN, "%s", CMD_RESTORE_SCAN_PARAMS);
2977 error = wl_android_default_set_scan_params(dev, cmd, WLC_IOCTL_SMLEN);
2978 if (error) {
2979 ANDROID_ERROR(("Failed to set RESTORE_SCAN_PARAMS(%d)\n", error));
2980 }
2981
2982 wl_cfg80211_set_wes_mode(dev, OFF);
2983 set_roamscan_mode(dev, ROAMSCAN_MODE_NORMAL);
2984 }
2985
2986 error = wl_cfg80211_set_ncho_mode(dev, mode);
2987 if (error) {
2988 ANDROID_ERROR(("Failed to set NCHO Mode %d, error = %d\n", mode, error));
2989 }
2990
2991 return error;
2992 }
2993
2994 static int
wl_android_set_pmk(struct net_device * dev,char * command,int total_len)2995 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
2996 {
2997 uchar pmk[33];
2998 int error = 0;
2999 char smbuf[WLC_IOCTL_SMLEN];
3000 dhd_pub_t *dhdp;
3001 #ifdef OKC_DEBUG
3002 int i = 0;
3003 #endif
3004
3005 if (total_len < (strlen("SET_PMK ") + 32)) {
3006 ANDROID_ERROR(("wl_android_set_pmk: Invalid argument\n"));
3007 return -1;
3008 }
3009
3010 dhdp = wl_cfg80211_get_dhdp(dev);
3011 if (!dhdp) {
3012 ANDROID_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3013 return -1;
3014 }
3015
3016 bzero(pmk, sizeof(pmk));
3017 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_OKC_PMK), dhd_net2idx(dhdp->info, dev), 0);
3018 memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
3019 error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
3020 if (error) {
3021 ANDROID_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
3022 }
3023 #ifdef OKC_DEBUG
3024 ANDROID_ERROR(("PMK is "));
3025 for (i = 0; i < 32; i++)
3026 ANDROID_ERROR(("%02X ", pmk[i]));
3027
3028 ANDROID_ERROR(("\n"));
3029 #endif
3030 return error;
3031 }
3032
3033 static int
wl_android_okc_enable(struct net_device * dev,char * command)3034 wl_android_okc_enable(struct net_device *dev, char *command)
3035 {
3036 int error = 0;
3037 char okc_enable = 0;
3038
3039 okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
3040 error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
3041 if (error) {
3042 ANDROID_ERROR(("Failed to %s OKC, error = %d\n",
3043 okc_enable ? "enable" : "disable", error));
3044 }
3045
3046 return error;
3047 }
3048
3049 static int
wl_android_legacy_check_command(struct net_device * dev,char * command)3050 wl_android_legacy_check_command(struct net_device *dev, char *command)
3051 {
3052 int cnt = 0;
3053
3054 while (strlen(legacy_cmdlist[cnt]) > 0) {
3055 if (strnicmp(command, legacy_cmdlist[cnt], strlen(legacy_cmdlist[cnt])) == 0) {
3056 char cmd[WL_PRIV_CMD_LEN + 1];
3057 sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3058 if (strlen(legacy_cmdlist[cnt]) == strlen(cmd)) {
3059 return TRUE;
3060 }
3061 }
3062 cnt++;
3063 }
3064 return FALSE;
3065 }
3066
3067 static int
wl_android_legacy_private_command(struct net_device * net,char * command,int total_len)3068 wl_android_legacy_private_command(struct net_device *net, char *command, int total_len)
3069 {
3070 int bytes_written = 0;
3071 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3072
3073 if (cfg->ncho_mode == ON) {
3074 ANDROID_ERROR(("Enabled NCHO mode\n"));
3075 /* In order to avoid Sequential error HANG event. */
3076 return BCME_UNSUPPORTED;
3077 }
3078
3079 /* ROAMSCAN CHANNELS Add, Get Command */
3080 if (strnicmp(command, CMD_ADDROAMSCANCHLEGACY, strlen(CMD_ADDROAMSCANCHLEGACY)) == 0) {
3081 bytes_written = wl_android_add_roam_scan_channels(net, command,
3082 strlen(CMD_ADDROAMSCANCHLEGACY));
3083 }
3084 else if (strnicmp(command, CMD_GETROAMSCANCHLEGACY, strlen(CMD_GETROAMSCANCHLEGACY)) == 0) {
3085 bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3086 CMD_GETROAMSCANCHLEGACY);
3087 }
3088 /* ROAMSCAN FREQUENCIES Add, Get Command */
3089 else if (strnicmp(command, CMD_ADDROAMSCANFQLEGACY, strlen(CMD_ADDROAMSCANFQLEGACY)) == 0) {
3090 bytes_written = wl_android_add_roam_scan_freqs(net, command,
3091 strlen(CMD_ADDROAMSCANFQLEGACY));
3092 }
3093 else if (strnicmp(command, CMD_GETROAMSCANFQLEGACY, strlen(CMD_GETROAMSCANFQLEGACY)) == 0) {
3094 bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3095 CMD_GETROAMSCANFQLEGACY);
3096 }
3097 else if (strnicmp(command, CMD_GETROAMTRIGLEGACY, strlen(CMD_GETROAMTRIGLEGACY)) == 0) {
3098 bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3099 }
3100 else if (strnicmp(command, CMD_SETROAMTRIGLEGACY, strlen(CMD_SETROAMTRIGLEGACY)) == 0) {
3101 bytes_written = wl_android_set_roam_trigger_legacy(net, command);
3102 }
3103 else if (strnicmp(command, CMD_REASSOCLEGACY, strlen(CMD_REASSOCLEGACY)) == 0) {
3104 bytes_written = wl_android_reassoc(net, command, total_len);
3105 }
3106 else if (strnicmp(command, CMD_GETSCANCHANNELTIMELEGACY,
3107 strlen(CMD_GETSCANCHANNELTIMELEGACY)) == 0) {
3108 bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3109 }
3110 else if (strnicmp(command, CMD_SETSCANCHANNELTIMELEGACY,
3111 strlen(CMD_SETSCANCHANNELTIMELEGACY)) == 0) {
3112 bytes_written = wl_android_set_scan_channel_time(net, command);
3113 }
3114 else if (strnicmp(command, CMD_GETSCANUNASSOCTIMELEGACY,
3115 strlen(CMD_GETSCANUNASSOCTIMELEGACY)) == 0) {
3116 bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3117 }
3118 else if (strnicmp(command, CMD_SETSCANUNASSOCTIMELEGACY,
3119 strlen(CMD_SETSCANUNASSOCTIMELEGACY)) == 0) {
3120 bytes_written = wl_android_set_scan_unassoc_time(net, command);
3121 }
3122 else if (strnicmp(command, CMD_GETSCANPASSIVETIMELEGACY,
3123 strlen(CMD_GETSCANPASSIVETIMELEGACY)) == 0) {
3124 bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3125 }
3126 else if (strnicmp(command, CMD_SETSCANPASSIVETIMELEGACY,
3127 strlen(CMD_SETSCANPASSIVETIMELEGACY)) == 0) {
3128 bytes_written = wl_android_set_scan_passive_time(net, command);
3129 }
3130 else if (strnicmp(command, CMD_GETSCANHOMETIMELEGACY,
3131 strlen(CMD_GETSCANHOMETIMELEGACY)) == 0) {
3132 bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3133 }
3134 else if (strnicmp(command, CMD_SETSCANHOMETIMELEGACY,
3135 strlen(CMD_SETSCANHOMETIMELEGACY)) == 0) {
3136 bytes_written = wl_android_set_scan_home_time(net, command);
3137 }
3138 else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIMELEGACY,
3139 strlen(CMD_GETSCANHOMEAWAYTIMELEGACY)) == 0) {
3140 bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3141 }
3142 else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIMELEGACY,
3143 strlen(CMD_SETSCANHOMEAWAYTIMELEGACY)) == 0) {
3144 bytes_written = wl_android_set_scan_home_away_time(net, command);
3145 }
3146 else {
3147 ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3148 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3149 }
3150
3151 return bytes_written;
3152 }
3153
3154 static int
wl_android_ncho_check_command(struct net_device * dev,char * command)3155 wl_android_ncho_check_command(struct net_device *dev, char *command)
3156 {
3157 int cnt = 0;
3158
3159 while (strlen(ncho_cmdlist[cnt]) > 0) {
3160 if (strnicmp(command, ncho_cmdlist[cnt], strlen(ncho_cmdlist[cnt])) == 0) {
3161 char cmd[WL_PRIV_CMD_LEN + 1];
3162 sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3163 if (strlen(ncho_cmdlist[cnt]) == strlen(cmd)) {
3164 return TRUE;
3165 }
3166 }
3167 cnt++;
3168 }
3169 return FALSE;
3170 }
3171
3172 static int
wl_android_ncho_private_command(struct net_device * net,char * command,int total_len)3173 wl_android_ncho_private_command(struct net_device *net, char *command, int total_len)
3174 {
3175 int bytes_written = 0;
3176 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3177
3178 if (cfg->ncho_mode == OFF) {
3179 ANDROID_ERROR(("Disable NCHO mode\n"));
3180 /* In order to avoid Sequential error HANG event. */
3181 return BCME_UNSUPPORTED;
3182 }
3183
3184 #ifdef ROAM_API
3185 if (strnicmp(command, CMD_ROAMTRIGGER_SET, strlen(CMD_ROAMTRIGGER_SET)) == 0) {
3186 bytes_written = wl_android_set_roam_trigger(net, command);
3187 } else if (strnicmp(command, CMD_ROAMTRIGGER_GET, strlen(CMD_ROAMTRIGGER_GET)) == 0) {
3188 bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3189 } else if (strnicmp(command, CMD_ROAMDELTA_SET, strlen(CMD_ROAMDELTA_SET)) == 0) {
3190 bytes_written = wl_android_set_roam_delta(net, command);
3191 } else if (strnicmp(command, CMD_ROAMDELTA_GET, strlen(CMD_ROAMDELTA_GET)) == 0) {
3192 bytes_written = wl_android_get_roam_delta(net, command, total_len);
3193 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
3194 strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
3195 bytes_written = wl_android_set_roam_scan_period(net, command);
3196 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
3197 strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
3198 bytes_written = wl_android_get_roam_scan_period(net, command, total_len);
3199 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
3200 strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
3201 bytes_written = wl_android_set_full_roam_scan_period(net, command);
3202 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
3203 strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
3204 bytes_written = wl_android_get_full_roam_scan_period(net, command, total_len);
3205 } else if (strnicmp(command, CMD_COUNTRYREV_SET, strlen(CMD_COUNTRYREV_SET)) == 0) {
3206 bytes_written = wl_android_set_country_rev(net, command);
3207 #ifdef FCC_PWR_LIMIT_2G
3208 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
3209 ANDROID_ERROR(("fccpwrlimit2g deactivation is failed\n"));
3210 } else {
3211 ANDROID_ERROR(("fccpwrlimit2g is deactivated\n"));
3212 }
3213 #endif /* FCC_PWR_LIMIT_2G */
3214 } else if (strnicmp(command, CMD_COUNTRYREV_GET, strlen(CMD_COUNTRYREV_GET)) == 0) {
3215 bytes_written = wl_android_get_country_rev(net, command, total_len);
3216 } else
3217 #endif /* ROAM_API */
3218 if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
3219 bytes_written = wl_android_get_roam_scan_control(net, command, total_len);
3220 }
3221 else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
3222 bytes_written = wl_android_set_roam_scan_control(net, command);
3223 }
3224 /* ROAMSCAN CHANNELS Add, Get, Set Command */
3225 else if (strnicmp(command, CMD_ADDROAMSCANCHANNELS, strlen(CMD_ADDROAMSCANCHANNELS)) == 0) {
3226 bytes_written = wl_android_add_roam_scan_channels(net, command,
3227 strlen(CMD_ADDROAMSCANCHANNELS));
3228 }
3229 else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
3230 bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3231 CMD_GETROAMSCANCHANNELS);
3232 }
3233 else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
3234 bytes_written = wl_android_set_roam_scan_channels(net, command);
3235 }
3236 /* ROAMSCAN FREQUENCIES Add, Get, Set Command */
3237 else if (strnicmp(command, CMD_ADDROAMSCANFREQS, strlen(CMD_ADDROAMSCANFREQS)) == 0) {
3238 bytes_written = wl_android_add_roam_scan_freqs(net, command,
3239 strlen(CMD_ADDROAMSCANFREQS));
3240 }
3241 else if (strnicmp(command, CMD_GETROAMSCANFREQS, strlen(CMD_GETROAMSCANFREQS)) == 0) {
3242 bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3243 CMD_GETROAMSCANFREQS);
3244 }
3245 else if (strnicmp(command, CMD_SETROAMSCANFREQS, strlen(CMD_SETROAMSCANFREQS)) == 0) {
3246 bytes_written = wl_android_set_roam_scan_freqs(net, command);
3247 }
3248 else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
3249 bytes_written = wl_android_send_action_frame(net, command, total_len);
3250 }
3251 else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
3252 bytes_written = wl_android_reassoc(net, command, total_len);
3253 }
3254 else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
3255 bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3256 }
3257 else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
3258 bytes_written = wl_android_set_scan_channel_time(net, command);
3259 }
3260 else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
3261 bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3262 }
3263 else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
3264 bytes_written = wl_android_set_scan_unassoc_time(net, command);
3265 }
3266 else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
3267 bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3268 }
3269 else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
3270 bytes_written = wl_android_set_scan_passive_time(net, command);
3271 }
3272 else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
3273 bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3274 }
3275 else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
3276 bytes_written = wl_android_set_scan_home_time(net, command);
3277 }
3278 else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
3279 bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3280 }
3281 else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
3282 bytes_written = wl_android_set_scan_home_away_time(net, command);
3283 }
3284 else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
3285 bytes_written = wl_android_get_scan_nprobes(net, command, total_len);
3286 }
3287 else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
3288 bytes_written = wl_android_set_scan_nprobes(net, command);
3289 }
3290 else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
3291 bytes_written = wl_android_get_scan_dfs_channel_mode(net, command, total_len);
3292 }
3293 else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
3294 bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
3295 }
3296 else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
3297 bytes_written = wl_android_set_join_prefer(net, command);
3298 }
3299 else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
3300 bytes_written = wl_android_get_wes_mode(net, command, total_len);
3301 }
3302 else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
3303 bytes_written = wl_android_set_wes_mode(net, command);
3304 }
3305 else {
3306 ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3307 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3308 }
3309
3310 return bytes_written;
3311 }
3312 #endif /* WES_SUPPORT */
3313
3314 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
3315 static int
wl_android_default_set_scan_params(struct net_device * dev,char * command,int total_len)3316 wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len)
3317 {
3318 int error = 0;
3319 uint error_cnt = 0;
3320 int cnt = 0;
3321 char restore_command[WLC_IOCTL_SMLEN];
3322
3323 while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) {
3324 snprintf(restore_command, WLC_IOCTL_SMLEN, "%s %d",
3325 restore_params[cnt].command, restore_params[cnt].parameter);
3326 if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) {
3327 error = restore_params[cnt].cmd_handler(dev, restore_command);
3328 } else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) {
3329 error = restore_params[cnt].cmd_handler_w_len(dev,
3330 restore_command, total_len);
3331 } else {
3332 ANDROID_ERROR(("Unknown restore command handler\n"));
3333 error = -1;
3334 }
3335 if (error) {
3336 ANDROID_ERROR(("Failed to restore scan parameters %s, error : %d\n",
3337 restore_command, error));
3338 error_cnt++;
3339 }
3340 cnt++;
3341 }
3342 if (error_cnt > 0) {
3343 ANDROID_ERROR(("Got %d error(s) while restoring scan parameters\n",
3344 error_cnt));
3345 error = -1;
3346 }
3347 return error;
3348 }
3349 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
3350
3351 #ifdef WLTDLS
wl_android_tdls_reset(struct net_device * dev)3352 int wl_android_tdls_reset(struct net_device *dev)
3353 {
3354 int ret = 0;
3355 ret = dhd_tdls_enable(dev, false, false, NULL);
3356 if (ret < 0) {
3357 ANDROID_ERROR(("Disable tdls failed. %d\n", ret));
3358 return ret;
3359 }
3360 ret = dhd_tdls_enable(dev, true, true, NULL);
3361 if (ret < 0) {
3362 ANDROID_ERROR(("enable tdls failed. %d\n", ret));
3363 return ret;
3364 }
3365 return 0;
3366 }
3367 #endif /* WLTDLS */
3368
3369 int
wl_android_rcroam_turn_on(struct net_device * dev,int rcroam_enab)3370 wl_android_rcroam_turn_on(struct net_device *dev, int rcroam_enab)
3371 {
3372 int ret = BCME_OK;
3373 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3374 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3375 wlc_rcroam_t *prcroam;
3376 wlc_rcroam_info_v1_t *rcroam;
3377 uint rcroamlen = sizeof(*rcroam) + RCROAM_HDRLEN;
3378
3379 ANDROID_INFO(("RCROAM mode %s\n", rcroam_enab ? "enable" : "disable"));
3380
3381 prcroam = (wlc_rcroam_t *)MALLOCZ(dhdp->osh, rcroamlen);
3382 if (!prcroam) {
3383 ANDROID_ERROR(("Fail to malloc buffer\n"));
3384 return BCME_NOMEM;
3385 }
3386
3387 /* Get RCROAM param */
3388 ret = wldev_iovar_getbuf(dev, "rcroam", NULL, 0, prcroam, rcroamlen, NULL);
3389 if (ret) {
3390 ANDROID_ERROR(("Failed to get RCROAM info(%d)\n", ret));
3391 goto done;
3392 }
3393
3394 if (prcroam->ver != WLC_RC_ROAM_CUR_VER) {
3395 ret = BCME_VERSION;
3396 ANDROID_ERROR(("Ver(%d:%d). mismatch RCROAM info(%d)\n",
3397 prcroam->ver, WLC_RC_ROAM_CUR_VER, ret));
3398 goto done;
3399 }
3400
3401 /* Set RCROAM param */
3402 rcroam = (wlc_rcroam_info_v1_t *)prcroam->data;
3403 prcroam->ver = WLC_RC_ROAM_CUR_VER;
3404 prcroam->len = sizeof(*rcroam);
3405 rcroam->enab = rcroam_enab;
3406
3407 ret = wldev_iovar_setbuf(dev, "rcroam", prcroam, rcroamlen,
3408 ioctl_buf, sizeof(ioctl_buf), NULL);
3409 if (ret) {
3410 ANDROID_ERROR(("Failed to set RCROAM %s(%d)\n",
3411 rcroam_enab ? "Enable" : "Disable", ret));
3412 goto done;
3413 }
3414 done:
3415 if (prcroam) {
3416 MFREE(dhdp->osh, prcroam, rcroamlen);
3417 }
3418
3419 return ret;
3420 }
3421
3422 #ifdef CONFIG_SILENT_ROAM
3423 int
wl_android_sroam_turn_on(struct net_device * dev,int sroam_mode)3424 wl_android_sroam_turn_on(struct net_device *dev, int sroam_mode)
3425 {
3426 int ret = BCME_OK;
3427 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3428
3429 dhdp->sroam_turn_on = sroam_mode;
3430 ANDROID_INFO(("%s Silent mode %s\n", __FUNCTION__,
3431 sroam_mode ? "enable" : "disable"));
3432
3433 if (!sroam_mode) {
3434 ret = dhd_sroam_set_mon(dhdp, FALSE);
3435 if (ret) {
3436 ANDROID_ERROR(("%s Failed to Set sroam %d\n",
3437 __FUNCTION__, ret));
3438 }
3439 }
3440
3441 return ret;
3442 }
3443
3444 int
wl_android_sroam_set_info(struct net_device * dev,char * data,char * command,int total_len)3445 wl_android_sroam_set_info(struct net_device *dev, char *data,
3446 char *command, int total_len)
3447 {
3448 int ret = BCME_OK;
3449 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3450 size_t slen = strlen(data);
3451 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3452 wlc_sroam_t *psroam;
3453 wlc_sroam_info_t *sroam;
3454 uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3455
3456 data[slen] = '\0';
3457 psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3458 if (!psroam) {
3459 ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3460 ret = BCME_NOMEM;
3461 goto done;
3462 }
3463
3464 psroam->ver = WLC_SILENT_ROAM_CUR_VER;
3465 psroam->len = sizeof(*sroam);
3466 sroam = (wlc_sroam_info_t *)psroam->data;
3467
3468 sroam->sroam_on = FALSE;
3469 if (*data && *data != '\0') {
3470 sroam->sroam_min_rssi = simple_strtol(data, &data, 10);
3471 ANDROID_INFO(("1.Minimum RSSI %d\n", sroam->sroam_min_rssi));
3472 data++;
3473 }
3474 if (*data && *data != '\0') {
3475 sroam->sroam_rssi_range = simple_strtol(data, &data, 10);
3476 ANDROID_INFO(("2.RSSI Range %d\n", sroam->sroam_rssi_range));
3477 data++;
3478 }
3479 if (*data && *data != '\0') {
3480 sroam->sroam_score_delta = simple_strtol(data, &data, 10);
3481 ANDROID_INFO(("3.Score Delta %d\n", sroam->sroam_score_delta));
3482 data++;
3483 }
3484 if (*data && *data != '\0') {
3485 sroam->sroam_period_time = simple_strtol(data, &data, 10);
3486 ANDROID_INFO(("4.Sroam period %d\n", sroam->sroam_period_time));
3487 data++;
3488 }
3489 if (*data && *data != '\0') {
3490 sroam->sroam_band = simple_strtol(data, &data, 10);
3491 ANDROID_INFO(("5.Sroam Band %d\n", sroam->sroam_band));
3492 data++;
3493 }
3494 if (*data && *data != '\0') {
3495 sroam->sroam_inact_cnt = simple_strtol(data, &data, 10);
3496 ANDROID_INFO(("6.Inactivity Count %d\n", sroam->sroam_inact_cnt));
3497 data++;
3498 }
3499
3500 if (*data != '\0') {
3501 ret = BCME_BADARG;
3502 goto done;
3503 }
3504
3505 ret = wldev_iovar_setbuf(dev, "sroam", psroam, sroamlen, ioctl_buf,
3506 sizeof(ioctl_buf), NULL);
3507 if (ret) {
3508 ANDROID_ERROR(("Failed to set silent roam info(%d)\n", ret));
3509 goto done;
3510 }
3511 done:
3512 if (psroam) {
3513 MFREE(dhdp->osh, psroam, sroamlen);
3514 }
3515
3516 return ret;
3517 }
3518
3519 int
wl_android_sroam_get_info(struct net_device * dev,char * command,int total_len)3520 wl_android_sroam_get_info(struct net_device *dev, char *command, int total_len)
3521 {
3522 int ret = BCME_OK;
3523 int bytes_written = 0;
3524 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3525 wlc_sroam_t *psroam;
3526 wlc_sroam_info_t *sroam;
3527 uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3528
3529 psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3530 if (!psroam) {
3531 ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3532 ret = BCME_NOMEM;
3533 goto done;
3534 }
3535
3536 ret = wldev_iovar_getbuf(dev, "sroam", NULL, 0, psroam, sroamlen, NULL);
3537 if (ret) {
3538 ANDROID_ERROR(("Failed to get silent roam info(%d)\n", ret));
3539 goto done;
3540 }
3541
3542 if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) {
3543 ret = BCME_VERSION;
3544 ANDROID_ERROR(("Ver(%d:%d). mismatch silent roam info(%d)\n",
3545 psroam->ver, WLC_SILENT_ROAM_CUR_VER, ret));
3546 goto done;
3547 }
3548
3549 sroam = (wlc_sroam_info_t *)psroam->data;
3550 bytes_written = snprintf(command, total_len,
3551 "%s %d %d %d %d %d %d %d\n",
3552 CMD_SROAM_GET_INFO, sroam->sroam_on, sroam->sroam_min_rssi, sroam->sroam_rssi_range,
3553 sroam->sroam_score_delta, sroam->sroam_period_time, sroam->sroam_band,
3554 sroam->sroam_inact_cnt);
3555 ret = bytes_written;
3556
3557 ANDROID_INFO(("%s", command));
3558 done:
3559 if (psroam) {
3560 MFREE(dhdp->osh, psroam, sroamlen);
3561 }
3562
3563 return ret;
3564 }
3565 #endif /* CONFIG_SILENT_ROAM */
3566
3567 int
wl_android_priority_roam_enable(struct net_device * dev,int mode)3568 wl_android_priority_roam_enable(struct net_device *dev, int mode)
3569 {
3570 int error = BCME_OK;
3571 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3572 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3573 wl_prio_roam_prof_v1_t *prio_roam;
3574 uint buf_len = sizeof(wl_prio_roam_prof_v1_t) + (uint)strlen("priority_roam") + 1;
3575
3576 prio_roam = (wl_prio_roam_prof_v1_t *)MALLOCZ(dhdp->osh, buf_len);
3577 if (!prio_roam) {
3578 ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3579 error = BCME_NOMEM;
3580 goto done;
3581 }
3582
3583 error = wldev_iovar_getbuf(dev, "priority_roam", NULL, 0, prio_roam, buf_len, NULL);
3584 if (error == BCME_UNSUPPORTED) {
3585 ANDROID_ERROR(("Priority Roam Unsupport\n"));
3586 error = BCME_OK;
3587 goto done;
3588 } else if (prio_roam->version != WL_PRIO_ROAM_PROF_V1) {
3589 ANDROID_ERROR(("Priority Roam Version mismatch\n"));
3590 goto done;
3591 } else if (prio_roam->prio_roam_mode == mode) {
3592 ANDROID_INFO(("Priority Roam already set(mode:%d)\n", mode));
3593 goto done;
3594 }
3595
3596 prio_roam->version = WL_PRIO_ROAM_PROF_V1;
3597 prio_roam->length = sizeof(wl_prio_roam_prof_v1_t);
3598 prio_roam->prio_roam_mode = mode;
3599
3600 error = wldev_iovar_setbuf(dev, "priority_roam", prio_roam,
3601 sizeof(wl_prio_roam_prof_v1_t), ioctl_buf, sizeof(ioctl_buf), NULL);
3602 if (error) {
3603 ANDROID_ERROR(("Failed to set Priority Roam %s(%d)\n",
3604 mode ? "Enable" : "Disable", error));
3605 goto done;
3606 }
3607 done:
3608 if (prio_roam) {
3609 MFREE(dhdp->osh, prio_roam, sizeof(wl_prio_roam_prof_v1_t));
3610 }
3611
3612 return error;
3613 }
3614
3615 #ifdef CONFIG_ROAM_RSSI_LIMIT
3616 int
wl_android_roam_rssi_limit(struct net_device * dev,char * command,int total_len)3617 wl_android_roam_rssi_limit(struct net_device *dev, char *command, int total_len)
3618 {
3619 int ret = BCME_OK;
3620 int argc, bytes_written = 0;
3621 int lmt2g, lmt5g;
3622 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3623
3624 argc = sscanf(command, CMD_ROAM_RSSI_LMT " %d %d\n", &lmt2g, &lmt5g);
3625
3626 if (!argc) {
3627 ret = dhd_roam_rssi_limit_get(dhdp, &lmt2g, &lmt5g);
3628 if (ret) {
3629 ANDROID_ERROR(("Failed to Get roam_rssi_limit (%d)\n", ret));
3630 return ret;
3631 }
3632 bytes_written = snprintf(command, total_len, "%d, %d\n", lmt2g, lmt5g);
3633 /* Get roam rssi limit */
3634 return bytes_written;
3635 } else {
3636 /* Set roam rssi limit */
3637 ret = dhd_roam_rssi_limit_set(dhdp, lmt2g, lmt5g);
3638 if (ret) {
3639 ANDROID_ERROR(("Failed to Set roam_rssi_limit (%d)\n", ret));
3640 return ret;
3641 }
3642 }
3643
3644 return ret;
3645 }
3646 #endif /* CONFIG_ROAM_RSSI_LIMIT */
3647
3648 #ifdef CONFIG_ROAM_MIN_DELTA
3649 int
wl_android_roam_min_delta(struct net_device * dev,char * command,int total_len)3650 wl_android_roam_min_delta(struct net_device *dev, char *command, int total_len)
3651 {
3652 int ret = BCME_OK;
3653 int argc, bytes_written = 0;
3654 uint32 delta2g = 0, delta5g = 0, delta = 0;
3655 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3656
3657 argc = sscanf(command, CMD_ROAM_MIN_DELTA " %d\n", &delta);
3658
3659 if (!argc) {
3660 /* Get Minimum ROAM score delta */
3661 ret = dhd_roam_min_delta_get(dhdp, &delta2g, &delta5g);
3662 if (ret) {
3663 ANDROID_ERROR(("Failed to Get roam_min_delta (%d)\n", ret));
3664 return ret;
3665 }
3666 bytes_written = snprintf(command, total_len, "%d, %d\n", delta2g, delta5g);
3667 return bytes_written;
3668 } else {
3669 /* Set Minimum ROAM score delta
3670 * Framework set one parameter # wpa_cli driver ROAMMINSCOREDELTA <value>
3671 */
3672 ret = dhd_roam_min_delta_set(dhdp, delta, delta);
3673 if (ret) {
3674 ANDROID_ERROR(("Failed to Set roam_min_delta (%d)\n", ret));
3675 return ret;
3676 }
3677 }
3678
3679 return ret;
3680 }
3681 #endif /* CONFIG_ROAM_MIN_DELTA */
3682
3683 static int
get_int_bytes(uchar * oui_str,uchar * oui,int len)3684 get_int_bytes(uchar *oui_str, uchar *oui, int len)
3685 {
3686 int idx;
3687 uchar val;
3688 uchar *src, *dest;
3689 char hexstr[3];
3690
3691 if ((oui_str == NULL) || (oui == NULL) || (len == 0)) {
3692 return BCME_BADARG;
3693 }
3694 src = oui_str;
3695 dest = oui;
3696
3697 for (idx = 0; idx < len; idx++) {
3698 if (*src == '\0') {
3699 *dest = '\0';
3700 break;
3701 }
3702 hexstr[0] = src[0];
3703 hexstr[1] = src[1];
3704 hexstr[2] = '\0';
3705
3706 val = (uchar)bcm_strtoul(hexstr, NULL, 16);
3707 if (val == (uchar)-1) {
3708 return BCME_ERROR;
3709 }
3710 *dest++ = val;
3711 src += 2;
3712 }
3713 return BCME_OK;
3714 }
3715
3716 #define TAG_BYTE 0
3717 static int
wl_android_set_disconnect_ies(struct net_device * dev,char * command)3718 wl_android_set_disconnect_ies(struct net_device *dev, char *command)
3719 {
3720 int cmd_prefix_len = 0;
3721 char ie_len = 0;
3722 int hex_ie_len = 0;
3723 int total_len = 0;
3724 int max_len = 0;
3725 int cmd_len = 0;
3726 uchar disassoc_ie[VNDR_IE_MAX_LEN] = {0};
3727 s32 bssidx = 0;
3728 struct bcm_cfg80211 *cfg = NULL;
3729 s32 ret = 0;
3730 cfg = wl_get_cfg(dev);
3731
3732 cmd_prefix_len = strlen("SET_DISCONNECT_IES ");
3733 cmd_len = strlen(command);
3734 /*
3735 * <CMD> + <IES in HEX format>
3736 * IES in hex format has to be in following format
3737 * First byte = Tag, Second Byte = len and rest of
3738 * bytes will be value. For ex: SET_DISCONNECT_IES dd0411223344
3739 * tag = dd, len =04. Total IEs len = len + 2
3740 */
3741 ANDROID_INFO(("cmd recv = %s\n", command));
3742 max_len = MIN(cmd_len, VNDR_IE_MAX_LEN);
3743 /* Validate IEs len */
3744 get_int_bytes(&command[cmd_prefix_len + 2], &ie_len, 1);
3745 ANDROID_INFO(("ie_len = %d \n", ie_len));
3746 if (ie_len <= 0 || ie_len > max_len) {
3747 ret = BCME_BADLEN;
3748 return ret;
3749 }
3750
3751 /* Total len in hex is sum of double binary len, tag and len byte */
3752 hex_ie_len = (ie_len * 2) + 4;
3753 total_len = cmd_prefix_len + hex_ie_len;
3754 if (command[total_len] != '\0' || (cmd_len != total_len)) {
3755 ANDROID_ERROR(("command recv not matching with len, command = %s"
3756 "total_len = %d, cmd_len = %d\n", command, total_len, cmd_len));
3757 ret = BCME_BADARG;
3758 return ret;
3759 }
3760
3761 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3762 ANDROID_ERROR(("Find index failed\n"));
3763 ret = -EINVAL;
3764 return ret;
3765 }
3766
3767 /* Tag and len bytes are also part of total len of ies in binary */
3768 ie_len = ie_len + 2;
3769 /* Convert IEs in binary */
3770 get_int_bytes(&command[cmd_prefix_len], disassoc_ie, ie_len);
3771 if (disassoc_ie[TAG_BYTE] != 0xdd) {
3772 ANDROID_ERROR(("Wrong tag recv, tag = 0x%02x\n", disassoc_ie[TAG_BYTE]));
3773 ret = BCME_UNSUPPORTED;
3774 return ret;
3775 }
3776
3777 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
3778 ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, disassoc_ie, ie_len);
3779
3780 return ret;
3781 }
3782
3783 #ifdef FCC_PWR_LIMIT_2G
3784 int
wl_android_set_fcc_pwr_limit_2g(struct net_device * dev,char * command)3785 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
3786 {
3787 int error = 0;
3788 int enable = 0;
3789
3790 sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
3791
3792 if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
3793 ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: Invalid data\n"));
3794 return BCME_ERROR;
3795 }
3796
3797 CUSTOMER_HW4_EN_CONVERT(enable);
3798
3799 ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g set (%d)\n", enable));
3800 error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
3801 if (error) {
3802 ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g"
3803 " set returned (%d)\n", error));
3804 return BCME_ERROR;
3805 }
3806
3807 return error;
3808 }
3809
3810 int
wl_android_get_fcc_pwr_limit_2g(struct net_device * dev,char * command,int total_len)3811 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
3812 {
3813 int error = 0;
3814 int enable = 0;
3815 int bytes_written = 0;
3816
3817 error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
3818 if (error) {
3819 ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get"
3820 " error (%d)\n", error));
3821 return BCME_ERROR;
3822 }
3823 ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get (%d)\n", enable));
3824
3825 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
3826
3827 return bytes_written;
3828 }
3829 #endif /* FCC_PWR_LIMIT_2G */
3830
3831 /* Additional format of sta_info
3832 * tx_pkts, tx_failures, tx_rate(kbps), rssi(main), rssi(aux), tx_pkts_retried,
3833 * tx_pkts_retry_exhausted, rx_lastpkt_rssi(main), rx_lastpkt_rssi(aux),
3834 * tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
3835 * tx_pkts_fw_retry_exhausted
3836 */
3837 #define STA_INFO_ADD_FMT "%d %d %d %d %d %d %d %d %d %d %d %d %d %d"
3838
3839 #ifdef BIGDATA_SOFTAP
3840 #define BIGDATA_SOFTAP_FMT MACOUI " %d %s %d %d %d %d %d %d"
3841 #endif /* BIGDATA_SOFTAP */
3842
3843 #define STAINFO_BAND_2G 0x0001
3844 #define STAINFO_BAND_5G 0x0002
3845 #define STAINFO_BAND_6G 0x0004
3846 #define STAINFO_BAND_60G 0x0008
3847 s32
wl_cfg80211_get_sta_info(struct net_device * dev,char * command,int total_len)3848 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
3849 {
3850 int bytes_written = -1, ret = 0;
3851 char *pos, *token, *cmdstr;
3852 bool is_macaddr = FALSE;
3853 sta_info_v4_t *sta = NULL;
3854 struct ether_addr mac;
3855 char *iovar_buf = NULL;
3856 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3857 struct net_device *apdev = NULL;
3858 #ifdef BCMDONGLEHOST
3859 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3860 #endif /* BCMDONGLEHOST */
3861
3862 #ifdef BIGDATA_SOFTAP
3863 void *data = NULL;
3864 wl_ap_sta_data_t *sta_data = NULL;
3865 #endif /* BIGDATA_SOFTAP */
3866
3867 /* Client information */
3868 uint16 cap = 0;
3869 uint32 rxrtry = 0, rxmulti = 0;
3870 uint32 tx_pkts = 0, tx_failures = 0, tx_rate = 0;
3871 uint32 tx_pkts_retried = 0, tx_pkts_retry_exhausted = 0;
3872 uint32 tx_pkts_total = 0, tx_pkts_retries = 0;
3873 uint32 tx_pkts_fw_total = 0, tx_pkts_fw_retries = 0;
3874 uint32 tx_pkts_fw_retry_exhausted = 0;
3875 int8 rssi[WL_STA_ANT_MAX] = {0};
3876 int8 rx_lastpkt_rssi[WL_STA_ANT_MAX] = {0};
3877 wl_if_stats_t *if_stats = NULL;
3878 u16 bands = 0;
3879 u32 sta_flags = 0;
3880 char mac_buf[MAX_NUM_OF_ASSOCLIST *
3881 sizeof(struct ether_addr) + sizeof(uint)] = {0};
3882 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
3883
3884 BCM_REFERENCE(if_stats);
3885 /* This Command used during only SoftAP mode. */
3886 ANDROID_INFO(("%s\n", command));
3887
3888 /* Check the current op_mode */
3889 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
3890 ANDROID_ERROR(("unsupported op mode: %d\n", dhdp->op_mode));
3891 return BCME_NOTAP;
3892 }
3893
3894 /*
3895 * DRIVER GETSTAINFO [client MAC or ALL] [ifname]
3896 */
3897 pos = command;
3898
3899 /* drop command */
3900 token = bcmstrtok(&pos, " ", NULL);
3901
3902 /* Client MAC or ALL */
3903 token = bcmstrtok(&pos, " ", NULL);
3904 if (!token) {
3905 ANDROID_ERROR(("GETSTAINFO subcmd not provided wl_cfg80211_get_sta_info\n"));
3906 return -EINVAL;
3907 }
3908 cmdstr = token;
3909
3910 bzero(&mac, ETHER_ADDR_LEN);
3911 if ((!strncmp(token, "all", 3)) || (!strncmp(token, "ALL", 3))) {
3912 is_macaddr = FALSE;
3913 } else if ((bcm_ether_atoe(token, &mac))) {
3914 is_macaddr = TRUE;
3915 } else {
3916 ANDROID_ERROR(("Failed to get address\n"));
3917 return -EINVAL;
3918 }
3919
3920 /* get the interface name */
3921 token = bcmstrtok(&pos, " ", NULL);
3922 if (!token) {
3923 /* assign requested dev for compatibility */
3924 apdev = dev;
3925 } else {
3926 /* Find a net_device for SoftAP by interface name */
3927 apdev = wl_get_ap_netdev(cfg, token);
3928 if (!apdev) {
3929 ANDROID_ERROR(("cannot find a net_device for SoftAP\n"));
3930 return -EINVAL;
3931 }
3932 }
3933
3934 iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
3935 if (!iovar_buf) {
3936 ANDROID_ERROR(("Failed to allocated memory %d bytes\n",
3937 WLC_IOCTL_MAXLEN));
3938 return BCME_NOMEM;
3939 }
3940
3941 if (is_macaddr) {
3942 int cnt;
3943
3944 /* get the sta info */
3945 ret = wldev_iovar_getbuf(apdev, "sta_info",
3946 (struct ether_addr *)mac.octet, ETHER_ADDR_LEN,
3947 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
3948 if (ret < 0) {
3949 ANDROID_ERROR(("Get sta_info ERR %d\n", ret));
3950
3951 #ifdef BIGDATA_SOFTAP
3952 /* Customer wants to send basic client information
3953 * to the framework even if DHD cannot get the sta_info.
3954 */
3955 goto get_bigdata;
3956 #endif /* BIGDATA_SOFTAP */
3957
3958 #ifndef BIGDATA_SOFTAP
3959 goto error;
3960 #endif /* BIGDATA_SOFTAP */
3961 }
3962
3963 sta = (sta_info_v4_t *)iovar_buf;
3964 if (dtoh16(sta->ver) != WL_STA_VER_4) {
3965 ANDROID_ERROR(("sta_info struct version mismatch, "
3966 "host ver : %d, fw ver : %d\n", WL_STA_VER_4,
3967 dtoh16(sta->ver)));
3968
3969 #ifdef BIGDATA_SOFTAP
3970 /* Customer wants to send basic client information
3971 * to the framework even if DHD cannot get the sta_info.
3972 */
3973 goto get_bigdata;
3974 #endif /* BIGDATA_SOFTAP */
3975
3976 #ifndef BIGDATA_SOFTAP
3977 goto error;
3978 #endif /* BIGDATA_SOFTAP */
3979 }
3980 cap = dtoh16(sta->cap);
3981 rxrtry = dtoh32(sta->rx_pkts_retried);
3982 rxmulti = dtoh32(sta->rx_mcast_pkts);
3983 tx_pkts = dtoh32(sta->tx_pkts);
3984 tx_failures = dtoh32(sta->tx_failures);
3985 tx_rate = dtoh32(sta->tx_rate);
3986 tx_pkts_retried = dtoh32(sta->tx_pkts_retried);
3987 tx_pkts_retry_exhausted = dtoh32(sta->tx_pkts_retry_exhausted);
3988 tx_pkts_total = dtoh32(sta->tx_pkts_total);
3989 tx_pkts_retries = dtoh32(sta->tx_pkts_retries);
3990 tx_pkts_fw_total = dtoh32(sta->tx_pkts_fw_total);
3991 tx_pkts_fw_retries = dtoh32(sta->tx_pkts_fw_retries);
3992 tx_pkts_fw_retry_exhausted = dtoh32(sta->tx_pkts_fw_retry_exhausted);
3993 sta_flags = dtoh32(sta->flags);
3994 if (sta_flags & WL_STA_IS_2G) {
3995 bands |= STAINFO_BAND_2G;
3996 }
3997 if (sta_flags & WL_STA_IS_5G) {
3998 bands |= STAINFO_BAND_5G;
3999 }
4000 if (sta_flags & WL_STA_IS_6G) {
4001 bands |= STAINFO_BAND_6G;
4002 }
4003 for (cnt = WL_ANT_IDX_1; cnt < WL_RSSI_ANT_MAX; cnt++) {
4004 rssi[cnt] = sta->rssi[cnt];
4005 rx_lastpkt_rssi[cnt] = sta->rx_lastpkt_rssi[cnt];
4006 }
4007 } else {
4008 int i;
4009
4010 /* Check if there is an associated STA or not */
4011 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
4012 ret = wldev_ioctl_get(apdev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
4013
4014 if (ret < 0) {
4015 ANDROID_ERROR(("Fail to get assoc list: %d\n", ret));
4016 goto error;
4017 }
4018
4019 assoc_maclist->count = dtoh32(assoc_maclist->count);
4020 ANDROID_INFO(("Assoc count : %d\n", assoc_maclist->count));
4021
4022 for (i = 0; i < assoc_maclist->count; i++) {
4023 /* get the sta info */
4024 ret = wldev_iovar_getbuf(apdev, "sta_info",
4025 (struct ether_addr *)assoc_maclist->ea[i].octet, ETHER_ADDR_LEN,
4026 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
4027
4028 if (ret < 0) {
4029 ANDROID_ERROR(("sta_info err : %d", ret));
4030 continue;
4031 }
4032 sta = (sta_info_v4_t *)iovar_buf;
4033 if (dtoh16(sta->ver) == WL_STA_VER_4) {
4034 rxrtry += dtoh32(sta->rx_pkts_retried);
4035 rxmulti += dtoh32(sta->rx_mcast_pkts);
4036 tx_pkts += dtoh32(sta->tx_pkts);
4037 tx_failures += dtoh32(sta->tx_failures);
4038 tx_pkts_total += dtoh32(sta->tx_pkts_total);
4039 tx_pkts_retries += dtoh32(sta->tx_pkts_retries);
4040 tx_pkts_fw_total += dtoh32(sta->tx_pkts_fw_total);
4041 tx_pkts_fw_retries += dtoh32(sta->tx_pkts_fw_retries);
4042 tx_pkts_fw_retry_exhausted +=
4043 dtoh32(sta->tx_pkts_fw_retry_exhausted);
4044 }
4045 }
4046 }
4047
4048 #ifdef BIGDATA_SOFTAP
4049 get_bigdata:
4050
4051 if (is_macaddr && wl_get_ap_stadata(cfg, &mac, &data) == BCME_OK) {
4052 ANDROID_ERROR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
4053 sta_data = (wl_ap_sta_data_t *)data;
4054 #ifdef STAINFO_LEGACY
4055 bytes_written = snprintf(command, total_len,
4056 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4057 "CAP=%04x " BIGDATA_SOFTAP_FMT " " STA_INFO_ADD_FMT
4058 "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4059 MACOUI2STR((char*)&sta_data->mac),
4060 sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4061 sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4062 sta_data->nss, sta_data->mimo, sta_data->reason_code,
4063 tx_pkts, tx_failures, tx_rate,
4064 (int32)rssi[WL_ANT_IDX_1], (int32)rssi[WL_ANT_IDX_2],
4065 tx_pkts_retried, tx_pkts_retry_exhausted,
4066 (int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4067 (int32)rx_lastpkt_rssi[WL_ANT_IDX_2],
4068 tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total,
4069 tx_pkts_fw_retries, tx_pkts_fw_retry_exhausted);
4070 #else
4071 bytes_written = snprintf(command, total_len,
4072 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4073 "CAP=%04x " BIGDATA_SOFTAP_FMT " %d\n",
4074 CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4075 MACOUI2STR((char*)&sta_data->mac),
4076 sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4077 sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4078 sta_data->nss, sta_data->mimo, sta_data->reason_code, bands);
4079 #endif /* STAINFO_LEGACY */
4080 } else
4081 #endif /* BIGDATA_SOFTAP */
4082 {
4083 ANDROID_ERROR(("ALL\n"));
4084 bytes_written = snprintf(command, total_len,
4085 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x "
4086 STA_INFO_ADD_FMT "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4087 tx_pkts, tx_failures, tx_rate, (int32)rssi[WL_ANT_IDX_1],
4088 (int32)rssi[WL_ANT_IDX_2], tx_pkts_retried,
4089 tx_pkts_retry_exhausted, (int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4090 (int32)rx_lastpkt_rssi[WL_ANT_IDX_2], tx_pkts_total,
4091 tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
4092 tx_pkts_fw_retry_exhausted);
4093 }
4094 WL_ERR_KERN(("Command: %s", command));
4095
4096 error:
4097 if (iovar_buf) {
4098 MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
4099 }
4100 if (if_stats) {
4101 MFREE(cfg->osh, if_stats, sizeof(*if_stats));
4102 }
4103
4104 return bytes_written;
4105 }
4106
4107 #ifdef WL_WTC
4108 /*
4109 * CMD Format
4110 * Enable format for 3 band and 2 band respectively:
4111 * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G 6G>
4112 * DRIVER SETWTCMODE 0 1 -80 -70 -65 -60
4113 * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G>
4114 * DRIVER SETWTCMODE 0 1 -80 -70 -65
4115 * Disable format for 3 band and 2 band respectively:
4116 * DRIVER SETWTCMODE 1 0 0 0 0 0
4117 * DRIVER SETWTCMODE 1 0 0 0 0
4118 */
4119 #define WL_TRIBAND 3
4120 #define WL_DUALBAND 2
4121
4122 /* For WTC disable, any value >= 1 */
4123 #define WL_WTC_ENABLE 0
4124 static int
wl_android_wtc_config(struct net_device * dev,char * command,int total_len)4125 wl_android_wtc_config(struct net_device *dev, char *command, int total_len)
4126 {
4127 s32 bw;
4128 char *token, *pos;
4129 wlc_wtc_args_t *wtc_params;
4130 wlc_wtcconfig_info_v1_t *wtc_config;
4131 u32 i, wtc_paramslen, maxbands = WL_DUALBAND;
4132 u8 buf[WLC_IOCTL_SMLEN] = {0};
4133 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4134
4135 WL_DBG_MEM(("Enter. cmd:%s\n", command));
4136 #ifdef WL_6G_BAND
4137 if (cfg->band_6g_supported) {
4138 maxbands = WL_TRIBAND;
4139 }
4140 #endif /* WL_6G_BAND */
4141 wtc_paramslen = sizeof(wlc_wtcconfig_info_v1_t) + WLC_WTC_ROAM_CONFIG_HDRLEN;
4142 wtc_params = (wlc_wtc_args_t*)MALLOCZ(cfg->osh, wtc_paramslen);
4143 if (!wtc_params) {
4144 ANDROID_ERROR(("Error allocating wtc_params\n"));
4145 return -ENOMEM;
4146 }
4147
4148 wtc_config = (wlc_wtcconfig_info_v1_t *)wtc_params->data;
4149 /* Get wtc config information and check version compatibility */
4150 bw = wldev_iovar_getbuf(dev, "wnm_wbtext_wtc_config",
4151 (char*)&wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, 0);
4152 if (bw) {
4153 ANDROID_ERROR(("Error querying wnm_wbtext_wtc_config: %d\n", bw));
4154 goto exit;
4155 }
4156
4157 (void)memcpy_s(wtc_params, wtc_paramslen, buf, wtc_paramslen);
4158 if (wtc_params->ver != WLC_WTC_ROAM_VER_1) {
4159 ANDROID_ERROR(("Wrong version:%d\n", wtc_params->ver));
4160 bw = -EINVAL;
4161 goto exit;
4162 }
4163
4164 if (wtc_params->len != sizeof(wlc_wtcconfig_info_v1_t)) {
4165 ANDROID_ERROR(("Bad len\n"));
4166 bw = -EINVAL;
4167 goto exit;
4168 }
4169
4170 if (strlen(command) == strlen(CMD_WTC_CONFIG)) {
4171 /* No additional arguments given. GET case */
4172 bw += scnprintf(command, (total_len - bw), "%u %u",
4173 wtc_config->mode, wtc_config->scantype);
4174 bw += scnprintf(command + bw, (total_len - bw), " %d",
4175 wtc_config->rssithresh[0]);
4176 for (i = 0; i < maxbands; i++) {
4177 bw += scnprintf(command + bw, (total_len - bw), " %d",
4178 wtc_config->ap_rssithresh[i]);
4179 }
4180 bw += scnprintf(command + bw, (total_len - bw), "\n");
4181 } else {
4182 /* SET */
4183 pos = command + sizeof(CMD_WTC_CONFIG);
4184
4185 /* mode */
4186 token = strsep((char**)&pos, " ");
4187 if (!token) {
4188 ANDROID_ERROR(("No mode present\n"));
4189 bw = -EINVAL;
4190 goto exit;
4191 }
4192 wtc_config->mode = (u8)bcm_atoi(token);
4193
4194 /* scantype */
4195 token = strsep((char**)&pos, " ");
4196 if (!token) {
4197 ANDROID_ERROR(("No scantype present\n"));
4198 bw = -EINVAL;
4199 goto exit;
4200 }
4201 wtc_config->scantype = (u8)bcm_atoi(token);
4202
4203 /* rssithreshold */
4204 token = strsep((char**)&pos, " ");
4205 if (!token) {
4206 ANDROID_ERROR(("Invalid arg for rssi threshold\n"));
4207 bw = -EINVAL;
4208 goto exit;
4209 }
4210 for (i = 0; i < maxbands; i++) {
4211 wtc_config->rssithresh[i] = (s8)bcm_atoi(token);
4212 }
4213
4214 /* AP rssithreshold */
4215 for (i = 0; i < maxbands; i++) {
4216 token = strsep((char**)&pos, " ");
4217 if (!token) {
4218 ANDROID_ERROR(("Invalid arg for ap threshold\n"));
4219 bw = -EINVAL;
4220 goto exit;
4221 }
4222 wtc_config->ap_rssithresh[i] = (s8)bcm_atoi(token);
4223 }
4224
4225 bw = wldev_iovar_setbuf(dev, "wnm_wbtext_wtc_config",
4226 (char*)wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, NULL);
4227 if (bw) {
4228 ANDROID_ERROR(("wtc config set failed. ret:%d\n", bw));
4229 }
4230 }
4231
4232 exit:
4233 if (wtc_params) {
4234 MFREE(cfg->osh, wtc_params, wtc_paramslen);
4235 }
4236 return bw;
4237 }
4238 #endif /* WL_WTC */
4239 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4240
4241 #ifdef WBTEXT
wl_android_wbtext(struct net_device * dev,char * command,int total_len)4242 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
4243 {
4244 int error = BCME_OK, argc = 0;
4245 int data, bytes_written;
4246 int roam_trigger[2];
4247 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4248
4249 argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
4250 if (!argc) {
4251 error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
4252 if (error) {
4253 ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4254 error));
4255 return error;
4256 }
4257 bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
4258 (data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
4259 "ENABLED" : "DISABLED");
4260 return bytes_written;
4261 } else {
4262 if (data) {
4263 data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
4264 }
4265
4266 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
4267 ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4268 error));
4269 return error;
4270 }
4271
4272 if (data) {
4273 /* reset roam_prof when wbtext is on */
4274 if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
4275 return error;
4276 }
4277 } else {
4278 /* reset legacy roam trigger when wbtext is off */
4279 roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
4280 roam_trigger[1] = WLC_BAND_ALL;
4281 if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
4282 sizeof(roam_trigger))) != BCME_OK) {
4283 ANDROID_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n",
4284 error));
4285 return error;
4286 }
4287 }
4288 dhdp->wbtext_policy = data;
4289 }
4290 return error;
4291 }
4292
4293 static int
wl_android_wbtext_enable(struct net_device * dev,int mode)4294 wl_android_wbtext_enable(struct net_device *dev, int mode)
4295 {
4296 int error = BCME_OK;
4297 char commandp[WLC_IOCTL_SMLEN];
4298
4299 if (wl_android_check_wbtext_support(dev)) {
4300 bzero(commandp, sizeof(commandp));
4301 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE %d", mode);
4302 error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN);
4303 if (error) {
4304 ANDROID_ERROR(("Failed to set WBTEXT = %d\n", error));
4305 return error;
4306 }
4307 }
4308
4309 return error;
4310 }
4311
wl_cfg80211_wbtext_btm_timer_threshold(struct net_device * dev,char * command,int total_len)4312 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
4313 char *command, int total_len)
4314 {
4315 int error = BCME_OK, argc = 0;
4316 int data, bytes_written;
4317
4318 argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
4319 if (!argc) {
4320 error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
4321 if (error) {
4322 ANDROID_ERROR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
4323 return error;
4324 }
4325 bytes_written = snprintf(command, total_len, "%d\n", data);
4326 return bytes_written;
4327 } else {
4328 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
4329 data)) != BCME_OK) {
4330 ANDROID_ERROR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
4331 return error;
4332 }
4333 }
4334 return error;
4335 }
4336
wl_cfg80211_wbtext_btm_delta(struct net_device * dev,char * command,int total_len)4337 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
4338 char *command, int total_len)
4339 {
4340 int error = BCME_OK, argc = 0;
4341 int data = 0, bytes_written;
4342
4343 argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
4344 if (!argc) {
4345 error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
4346 if (error) {
4347 ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4348 return error;
4349 }
4350 bytes_written = snprintf(command, total_len, "%d\n", data);
4351 return bytes_written;
4352 } else {
4353 if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
4354 data)) != BCME_OK) {
4355 ANDROID_ERROR(("Failed to set wnm_btmdelta (%d)\n", error));
4356 return error;
4357 }
4358 }
4359 return error;
4360 }
4361
wl_cfg80211_wbtext_estm_enable(struct net_device * dev,char * command,int total_len)4362 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
4363 char *command, int total_len)
4364 {
4365 int error = BCME_OK;
4366 int data = 0, bytes_written = 0;
4367 int wnmmask = 0;
4368 char *pcmd = command;
4369
4370 bcmstrtok(&pcmd, " ", NULL);
4371
4372 error = wldev_iovar_getint(dev, "wnm", &wnmmask);
4373 if (error) {
4374 ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4375 return error;
4376 }
4377 ANDROID_INFO(("wnmmask %x\n", wnmmask));
4378 if (*pcmd == WL_IOCTL_ACTION_GET) {
4379 bytes_written = snprintf(command, total_len, "wbtext_estm_enable %d\n",
4380 (wnmmask & WL_WNM_ESTM) ? 1:0);
4381 return bytes_written;
4382 } else {
4383 data = bcm_atoi(pcmd);
4384 if (data == 0) {
4385 wnmmask &= ~WL_WNM_ESTM;
4386 } else {
4387 wnmmask |= WL_WNM_ESTM;
4388 }
4389 ANDROID_INFO(("wnmmask %x\n", wnmmask));
4390 if ((error = wldev_iovar_setint(dev, "wnm", wnmmask)) != BCME_OK) {
4391 ANDROID_ERROR(("Failed to set wnm mask (%d)\n", error));
4392 return error;
4393 }
4394 }
4395 return error;
4396 }
4397 #endif /* WBTEXT */
4398
4399 #ifdef PNO_SUPPORT
4400 #define PNO_PARAM_SIZE 50
4401 #define VALUE_SIZE 50
4402 #define LIMIT_STR_FMT ("%50s %50s")
4403 static int
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)4404 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
4405 {
4406 int err = BCME_OK;
4407 uint i, tokens, len_remain;
4408 char *pos, *pos2, *token, *token2, *delim;
4409 char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
4410 struct dhd_pno_batch_params batch_params;
4411
4412 ANDROID_INFO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len));
4413 len_remain = total_len;
4414 if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
4415 pos = command + strlen(CMD_WLS_BATCHING) + 1;
4416 len_remain -= strlen(CMD_WLS_BATCHING) + 1;
4417 } else {
4418 ANDROID_ERROR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len));
4419 err = BCME_ERROR;
4420 goto exit;
4421 }
4422 bzero(&batch_params, sizeof(struct dhd_pno_batch_params));
4423 if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
4424 if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
4425 pos += strlen(PNO_BATCHING_SET) + 1;
4426 } else {
4427 ANDROID_ERROR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n",
4428 PNO_BATCHING_SET, total_len));
4429 err = BCME_ERROR;
4430 goto exit;
4431 }
4432 while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
4433 bzero(param, sizeof(param));
4434 bzero(value, sizeof(value));
4435 if (token == NULL || !*token)
4436 break;
4437 if (*token == '\0')
4438 continue;
4439 delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
4440 if (delim != NULL)
4441 *delim = ' ';
4442
4443 tokens = sscanf(token, LIMIT_STR_FMT, param, value);
4444 if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
4445 batch_params.scan_fr = simple_strtol(value, NULL, 0);
4446 ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
4447 } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
4448 batch_params.bestn = simple_strtol(value, NULL, 0);
4449 ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
4450 } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
4451 batch_params.mscan = simple_strtol(value, NULL, 0);
4452 ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
4453 } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
4454 i = 0;
4455 pos2 = value;
4456 tokens = sscanf(value, "<%s>", value);
4457 if (tokens != 1) {
4458 err = BCME_ERROR;
4459 ANDROID_ERROR(("wls_parse_batching_cmd: invalid format"
4460 " for channel"
4461 " <> params\n"));
4462 goto exit;
4463 }
4464 while ((token2 = strsep(&pos2,
4465 PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
4466 if (token2 == NULL || !*token2)
4467 break;
4468 if (*token2 == '\0')
4469 continue;
4470 if (*token2 == 'A' || *token2 == 'B') {
4471 batch_params.band = (*token2 == 'A')?
4472 WLC_BAND_5G : WLC_BAND_2G;
4473 ANDROID_INFO(("band : %s\n",
4474 (*token2 == 'A')? "A" : "B"));
4475 } else {
4476 if ((batch_params.nchan >= WL_NUMCHANNELS) ||
4477 (i >= WL_NUMCHANNELS)) {
4478 ANDROID_ERROR(("Too many nchan %d\n",
4479 batch_params.nchan));
4480 err = BCME_BUFTOOSHORT;
4481 goto exit;
4482 }
4483 batch_params.chan_list[i++] =
4484 simple_strtol(token2, NULL, 0);
4485 batch_params.nchan++;
4486 ANDROID_INFO(("channel :%d\n",
4487 batch_params.chan_list[i-1]));
4488 }
4489 }
4490 } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
4491 batch_params.rtt = simple_strtol(value, NULL, 0);
4492 ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
4493 } else {
4494 ANDROID_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param));
4495 err = BCME_ERROR;
4496 goto exit;
4497 }
4498 }
4499 err = dhd_dev_pno_set_for_batch(dev, &batch_params);
4500 if (err < 0) {
4501 ANDROID_ERROR(("failed to configure batch scan\n"));
4502 } else {
4503 bzero(command, total_len);
4504 err = snprintf(command, total_len, "%d", err);
4505 }
4506 } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
4507 err = dhd_dev_pno_get_for_batch(dev, command, total_len);
4508 if (err < 0) {
4509 ANDROID_ERROR(("failed to getting batching results\n"));
4510 } else {
4511 err = strlen(command);
4512 }
4513 } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
4514 err = dhd_dev_pno_stop_for_batch(dev);
4515 if (err < 0) {
4516 ANDROID_ERROR(("failed to stop batching scan\n"));
4517 } else {
4518 bzero(command, total_len);
4519 err = snprintf(command, total_len, "OK");
4520 }
4521 } else {
4522 ANDROID_ERROR(("wls_parse_batching_cmd : unknown command\n"));
4523 err = BCME_ERROR;
4524 goto exit;
4525 }
4526 exit:
4527 return err;
4528 }
4529
4530 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)4531 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
4532 {
4533 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
4534 int res = -1;
4535 int nssid = 0;
4536 cmd_tlv_t *cmd_tlv_temp;
4537 char *str_ptr;
4538 int tlv_size_left;
4539 int pno_time = 0;
4540 int pno_repeat = 0;
4541 int pno_freq_expo_max = 0;
4542
4543 #ifdef PNO_SET_DEBUG
4544 int i;
4545 char pno_in_example[] = {
4546 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
4547 'S', '1', '2', '0',
4548 'S',
4549 0x05,
4550 'd', 'l', 'i', 'n', 'k',
4551 'S',
4552 0x04,
4553 'G', 'O', 'O', 'G',
4554 'T',
4555 '0', 'B',
4556 'R',
4557 '2',
4558 'M',
4559 '2',
4560 0x00
4561 };
4562 #endif /* PNO_SET_DEBUG */
4563 ANDROID_INFO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len));
4564
4565 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
4566 ANDROID_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len));
4567 goto exit_proc;
4568 }
4569 #ifdef PNO_SET_DEBUG
4570 memcpy(command, pno_in_example, sizeof(pno_in_example));
4571 total_len = sizeof(pno_in_example);
4572 #endif
4573 str_ptr = command + strlen(CMD_PNOSETUP_SET);
4574 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
4575
4576 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
4577 bzero(ssids_local, sizeof(ssids_local));
4578
4579 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
4580 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
4581 (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
4582
4583 str_ptr += sizeof(cmd_tlv_t);
4584 tlv_size_left -= sizeof(cmd_tlv_t);
4585
4586 if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
4587 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
4588 ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
4589 goto exit_proc;
4590 } else {
4591 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
4592 ANDROID_ERROR(("wl_android_set_pno_setup: scan duration corrupted"
4593 " field size %d\n",
4594 tlv_size_left));
4595 goto exit_proc;
4596 }
4597 str_ptr++;
4598 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
4599 ANDROID_INFO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time));
4600
4601 if (str_ptr[0] != 0) {
4602 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
4603 ANDROID_ERROR(("wl_android_set_pno_setup: pno repeat:"
4604 " corrupted field\n"));
4605 goto exit_proc;
4606 }
4607 str_ptr++;
4608 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
4609 ANDROID_INFO(("wl_android_set_pno_setup: got pno_repeat=%d\n",
4610 pno_repeat));
4611 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
4612 ANDROID_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX"
4613 " corrupted field size\n"));
4614 goto exit_proc;
4615 }
4616 str_ptr++;
4617 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
4618 ANDROID_INFO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n",
4619 pno_freq_expo_max));
4620 }
4621 }
4622 } else {
4623 ANDROID_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n"));
4624 goto exit_proc;
4625 }
4626
4627 res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
4628 pno_freq_expo_max, NULL, 0);
4629 exit_proc:
4630 return res;
4631 }
4632 #endif /* !WL_SCHED_SCAN */
4633 #endif /* PNO_SUPPORT */
4634
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)4635 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
4636 {
4637 int ret;
4638 struct ether_addr p2pdev_addr;
4639
4640 #define MAC_ADDR_STR_LEN 18
4641 if (total_len < MAC_ADDR_STR_LEN) {
4642 ANDROID_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n",
4643 total_len));
4644 return -1;
4645 }
4646
4647 ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
4648 if (ret) {
4649 ANDROID_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n"));
4650 return -1;
4651 }
4652 return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
4653 }
4654
4655 int
wl_android_set_ap_mac_list(struct net_device * dev,int macmode,struct maclist * maclist)4656 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
4657 {
4658 int i, j, match;
4659 int ret = 0;
4660 char mac_buf[MAX_NUM_OF_ASSOCLIST *
4661 sizeof(struct ether_addr) + sizeof(uint)] = {0};
4662 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
4663
4664 /* set filtering mode */
4665 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
4666 ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret));
4667 return ret;
4668 }
4669 if (macmode != MACLIST_MODE_DISABLED) {
4670 /* set the MAC filter list */
4671 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
4672 sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
4673 ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret));
4674 return ret;
4675 }
4676 /* get the current list of associated STAs */
4677 assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
4678 if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
4679 sizeof(mac_buf))) != 0) {
4680 ANDROID_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n",
4681 ret));
4682 return ret;
4683 }
4684 /* do we have any STA associated? */
4685 if (assoc_maclist->count) {
4686 /* iterate each associated STA */
4687 for (i = 0; i < assoc_maclist->count; i++) {
4688 match = 0;
4689 /* compare with each entry */
4690 for (j = 0; j < maclist->count; j++) {
4691 ANDROID_INFO(("wl_android_set_ap_mac_list: associated="MACDBG
4692 "list = "MACDBG "\n",
4693 MAC2STRDBG(assoc_maclist->ea[i].octet),
4694 MAC2STRDBG(maclist->ea[j].octet)));
4695 if (memcmp(assoc_maclist->ea[i].octet,
4696 maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
4697 match = 1;
4698 break;
4699 }
4700 }
4701 /* do conditional deauth */
4702 /* "if not in the allow list" or "if in the deny list" */
4703 if ((macmode == MACLIST_MODE_ALLOW && !match) ||
4704 (macmode == MACLIST_MODE_DENY && match)) {
4705 scb_val_t scbval;
4706
4707 scbval.val = htod32(1);
4708 memcpy(&scbval.ea, &assoc_maclist->ea[i],
4709 ETHER_ADDR_LEN);
4710 if ((ret = wldev_ioctl_set(dev,
4711 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
4712 &scbval, sizeof(scb_val_t))) != 0)
4713 ANDROID_ERROR(("wl_android_set_ap_mac_list:"
4714 " WLC_SCB_DEAUTHENTICATE"
4715 " error=%d\n",
4716 ret));
4717 }
4718 }
4719 }
4720 }
4721 return ret;
4722 }
4723
4724 /*
4725 * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
4726 *
4727 */
4728 static int
wl_android_set_mac_address_filter(struct net_device * dev,char * str)4729 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
4730 {
4731 int i;
4732 int ret = 0;
4733 int macnum = 0;
4734 int macmode = MACLIST_MODE_DISABLED;
4735 struct maclist *list;
4736 char eabuf[ETHER_ADDR_STR_LEN];
4737 const char *token;
4738 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4739
4740 /* string should look like below (macmode/macnum/maclist) */
4741 /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */
4742
4743 /* get the MAC filter mode */
4744 token = strsep((char**)&str, " ");
4745 if (!token) {
4746 return -1;
4747 }
4748 macmode = bcm_atoi(token);
4749
4750 if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
4751 ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode));
4752 return -1;
4753 }
4754
4755 token = strsep((char**)&str, " ");
4756 if (!token) {
4757 return -1;
4758 }
4759 macnum = bcm_atoi(token);
4760 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
4761 ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC"
4762 " address entries %d\n",
4763 macnum));
4764 return -1;
4765 }
4766 /* allocate memory for the MAC list */
4767 list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
4768 sizeof(struct ether_addr) * macnum);
4769 if (!list) {
4770 ANDROID_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n"));
4771 return -1;
4772 }
4773 /* prepare the MAC list */
4774 list->count = htod32(macnum);
4775 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
4776 for (i = 0; i < list->count; i++) {
4777 token = strsep((char**)&str, " ");
4778 if (token == NULL) {
4779 ANDROID_ERROR(("wl_android_set_mac_address_filter : No mac address present\n"));
4780 ret = -EINVAL;
4781 goto exit;
4782 }
4783 strlcpy(eabuf, token, sizeof(eabuf));
4784 if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
4785 ANDROID_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d,"
4786 " addr=%s\n",
4787 i, eabuf));
4788 list->count = i;
4789 break;
4790 }
4791 ANDROID_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s",
4792 i, list->count, eabuf));
4793 }
4794 if (i == 0)
4795 goto exit;
4796
4797 /* set the list */
4798 if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
4799 ANDROID_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n",
4800 ret));
4801
4802 exit:
4803 MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
4804
4805 return ret;
4806 }
4807
wl_android_get_factory_mac_addr(struct net_device * ndev,char * command,int total_len)4808 static int wl_android_get_factory_mac_addr(struct net_device *ndev, char *command, int total_len)
4809 {
4810 int ret;
4811 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
4812
4813 if (total_len < ETHER_ADDR_STR_LEN) {
4814 ANDROID_ERROR(("wl_android_get_factory_mac_addr buflen %d"
4815 "is less than factory mac addr\n", total_len));
4816 return BCME_ERROR;
4817 }
4818 ret = snprintf(command, total_len, MACDBG,
4819 MAC2STRDBG(bcmcfg_to_prmry_ndev(cfg)->perm_addr));
4820 return ret;
4821 }
4822
4823 #if defined(WLAN_ACCEL_BOOT)
wl_android_wifi_accel_on(struct net_device * dev,bool force_reg_on)4824 int wl_android_wifi_accel_on(struct net_device *dev, bool force_reg_on)
4825 {
4826 int ret = 0;
4827
4828 ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4829 if (!dev) {
4830 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4831 return -EINVAL;
4832 }
4833
4834 if (force_reg_on) {
4835 /* First resume the bus if it is in suspended state */
4836 ret = dhd_net_bus_resume(dev, 0);
4837 if (ret) {
4838 ANDROID_ERROR(("%s: dhd_net_bus_resume failed\n", __FUNCTION__));
4839 }
4840 /* Toggle wl_reg_on */
4841 ret = wl_android_wifi_off(dev, TRUE);
4842 if (ret) {
4843 ANDROID_ERROR(("%s: wl_android_wifi_off failed\n", __FUNCTION__));
4844 }
4845 ret = wl_android_wifi_on(dev);
4846 if (ret) {
4847 ANDROID_ERROR(("%s: wl_android_wifi_on failed\n", __FUNCTION__));
4848 }
4849 } else {
4850 ret = dhd_net_bus_resume(dev, 0);
4851 }
4852
4853 return ret;
4854 }
4855
wl_android_wifi_accel_off(struct net_device * dev,bool force_reg_on)4856 int wl_android_wifi_accel_off(struct net_device *dev, bool force_reg_on)
4857 {
4858 int ret = 0;
4859
4860 ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4861 if (!dev) {
4862 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4863 return -EINVAL;
4864 }
4865
4866 if (force_reg_on) {
4867 ANDROID_ERROR(("%s: do nothing as wl_reg_on will be toggled in UP\n",
4868 __FUNCTION__));
4869 } else {
4870 ret = dhd_net_bus_suspend(dev);
4871 }
4872
4873 return ret;
4874 }
4875 #endif /* WLAN_ACCEL_BOOT */
4876
4877 #ifdef WBRC
4878 extern int wbrc_wl2bt_reset(void);
4879 #endif /* WBRC */
4880
4881 /**
4882 * Global function definitions (declared in wl_android.h)
4883 */
4884
wl_android_wifi_on(struct net_device * dev)4885 int wl_android_wifi_on(struct net_device *dev)
4886 {
4887 int ret = 0;
4888 int retry = POWERUP_MAX_RETRY;
4889 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4890
4891 BCM_REFERENCE(dhdp);
4892 if (!dev) {
4893 ANDROID_ERROR(("wl_android_wifi_on: dev is null\n"));
4894 return -EINVAL;
4895 }
4896
4897 dhd_net_if_lock(dev);
4898 WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on);
4899 if (!g_wifi_on) {
4900 do {
4901 dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
4902 #ifdef BCMSDIO
4903 ret = dhd_net_bus_resume(dev, 0);
4904 #endif /* BCMSDIO */
4905 #ifdef BCMPCIE
4906 ret = dhd_net_bus_devreset(dev, FALSE);
4907 #endif /* BCMPCIE */
4908 #ifdef WBRC
4909 if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ONCE) {
4910 ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4911 __FUNCTION__, dhdp->dhd_induce_bh_error));
4912 /* Forcefully set error */
4913 ret = BCME_ERROR;
4914 /* Clear the induced bh error */
4915 dhdp->dhd_induce_bh_error = DHD_INDUCE_ERROR_CLEAR;
4916 }
4917 if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ALWAYS) {
4918 ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4919 __FUNCTION__, dhdp->dhd_induce_bh_error));
4920 /* Forcefully set error */
4921 ret = BCME_ERROR;
4922 }
4923 #endif /* WBRC */
4924 if (ret == 0) {
4925 break;
4926 }
4927 ANDROID_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
4928 retry));
4929 #ifdef BCMPCIE
4930 dhd_net_bus_devreset(dev, TRUE);
4931 #endif /* BCMPCIE */
4932 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4933 #ifdef WBRC
4934 /* Inform BT reset which will internally wait till BT reset is done */
4935 if (wbrc_wl2bt_reset()) {
4936 ANDROID_ERROR(("Failed to reset BT, nothing to be done!!!!\n"));
4937 }
4938 #endif /* WBRC */
4939 } while (retry-- > 0);
4940 if (ret != 0) {
4941 ANDROID_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
4942 #ifdef BCM_DETECT_TURN_ON_FAILURE
4943 BUG_ON(1);
4944 #endif /* BCM_DETECT_TURN_ON_FAILURE */
4945 goto exit;
4946 }
4947 #if defined(BCMSDIO) || defined(BCMDBUS)
4948 ret = dhd_net_bus_devreset(dev, FALSE);
4949 if (ret)
4950 goto err;
4951 #ifdef BCMSDIO
4952 dhd_net_bus_resume(dev, 1);
4953 #endif /* BCMSDIO */
4954 #endif /* BCMSDIO || BCMDBUS */
4955 #if defined(BCMSDIO) || defined(BCMDBUS)
4956 if (!ret) {
4957 if (dhd_dev_init_ioctl(dev) < 0) {
4958 ret = -EFAULT;
4959 goto err;
4960 }
4961 }
4962 #endif /* BCMSDIO || BCMDBUS */
4963 g_wifi_on = TRUE;
4964 }
4965
4966 exit:
4967 WL_MSG(dev->name, "Success\n");
4968 dhd_net_if_unlock(dev);
4969 return ret;
4970
4971 #if defined(BCMSDIO) || defined(BCMDBUS)
4972 err:
4973 dhd_net_bus_devreset(dev, TRUE);
4974 #ifdef BCMSDIO
4975 dhd_net_bus_suspend(dev);
4976 #endif /* BCMSDIO */
4977 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4978 WL_MSG(dev->name, "Failed\n");
4979 dhd_net_if_unlock(dev);
4980 return ret;
4981 #endif /* BCMSDIO || BCMDBUS */
4982 }
4983
wl_android_wifi_off(struct net_device * dev,bool on_failure)4984 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
4985 {
4986 int ret = 0;
4987
4988 if (!dev) {
4989 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4990 return -EINVAL;
4991 }
4992
4993 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
4994 ret = dhd_debug_uart_is_running(dev);
4995 if (ret) {
4996 ANDROID_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
4997 return -EBUSY;
4998 }
4999 #endif /* BCMPCIE && DHD_DEBUG_UART */
5000 dhd_net_if_lock(dev);
5001 WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure);
5002 if (g_wifi_on || on_failure) {
5003 #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
5004 ret = dhd_net_bus_devreset(dev, TRUE);
5005 #ifdef BCMSDIO
5006 dhd_net_bus_suspend(dev);
5007 #endif /* BCMSDIO */
5008 #endif /* BCMSDIO || BCMPCIE || BCMDBUS */
5009 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
5010 g_wifi_on = FALSE;
5011 }
5012 WL_MSG(dev->name, "out\n");
5013 dhd_net_if_unlock(dev);
5014
5015 return ret;
5016 }
5017
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)5018 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
5019 {
5020 if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
5021 return -1;
5022 return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
5023 }
5024
5025 #ifdef CONNECTION_STATISTICS
5026 static int
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)5027 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
5028 {
5029 int err;
5030 wl_chanim_stats_t *list;
5031 /* Parameter _and_ returned buffer of chanim_stats. */
5032 wl_chanim_stats_t param;
5033 u8 result[WLC_IOCTL_SMLEN];
5034 chanim_stats_t *stats;
5035
5036 bzero(¶m, sizeof(param));
5037
5038 param.buflen = htod32(sizeof(wl_chanim_stats_t));
5039 param.count = htod32(WL_CHANIM_COUNT_ONE);
5040
5041 if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t),
5042 (char*)result, sizeof(result), 0)) < 0) {
5043 ANDROID_ERROR(("Failed to get chanim results %d \n", err));
5044 return err;
5045 }
5046
5047 list = (wl_chanim_stats_t*)result;
5048
5049 list->buflen = dtoh32(list->buflen);
5050 list->version = dtoh32(list->version);
5051 list->count = dtoh32(list->count);
5052
5053 if (list->buflen == 0) {
5054 list->version = 0;
5055 list->count = 0;
5056 } else if (list->version != WL_CHANIM_STATS_VERSION) {
5057 ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
5058 "but driver supports only version %d.\n",
5059 list->version, WL_CHANIM_STATS_VERSION));
5060 list->buflen = 0;
5061 list->count = 0;
5062 }
5063
5064 stats = list->stats;
5065 stats->glitchcnt = dtoh32(stats->glitchcnt);
5066 stats->badplcp = dtoh32(stats->badplcp);
5067 stats->chanspec = dtoh16(stats->chanspec);
5068 stats->timestamp = dtoh32(stats->timestamp);
5069 stats->chan_idle = dtoh32(stats->chan_idle);
5070
5071 ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
5072 stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
5073 stats->timestamp));
5074
5075 *chan_idle = stats->chan_idle;
5076
5077 return (err);
5078 }
5079
5080 static int
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)5081 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
5082 {
5083 static char iovar_buf[WLC_IOCTL_MAXLEN];
5084 const wl_cnt_wlc_t* wlc_cnt = NULL;
5085 #ifndef DISABLE_IF_COUNTERS
5086 wl_if_stats_t* if_stats = NULL;
5087 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5088 #ifdef BCMDONGLEHOST
5089 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
5090 #endif /* BCMDONGLEHOST */
5091 #endif /* DISABLE_IF_COUNTERS */
5092
5093 int link_speed = 0;
5094 struct connection_stats *output;
5095 unsigned int bufsize = 0;
5096 int bytes_written = -1;
5097 int ret = 0;
5098
5099 ANDROID_INFO(("wl_android_get_connection_stats: enter Get Connection Stats\n"));
5100
5101 if (total_len <= 0) {
5102 ANDROID_ERROR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len));
5103 goto error;
5104 }
5105
5106 bufsize = total_len;
5107 if (bufsize < sizeof(struct connection_stats)) {
5108 ANDROID_ERROR(("wl_android_get_connection_stats: not enough buffer size, provided=%u,"
5109 " requires=%zu\n",
5110 bufsize,
5111 sizeof(struct connection_stats)));
5112 goto error;
5113 }
5114
5115 output = (struct connection_stats *)command;
5116
5117 #ifndef DISABLE_IF_COUNTERS
5118 if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
5119 if (if_stats == NULL) {
5120 ANDROID_ERROR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
5121 goto error;
5122 }
5123 bzero(if_stats, sizeof(*if_stats));
5124
5125 #ifdef BCMDONGLEHOST
5126 if (FW_SUPPORTED(dhdp, ifst)) {
5127 ret = wl_cfg80211_ifstats_counters(dev, if_stats);
5128 } else
5129 #endif /* BCMDONGLEHOST */
5130 {
5131 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5132 (char *)if_stats, sizeof(*if_stats), NULL);
5133 }
5134
5135 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5136 (char *)if_stats, sizeof(*if_stats), NULL);
5137 if (ret) {
5138 ANDROID_ERROR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n",
5139 ret));
5140
5141 /* In case if_stats IOVAR is not supported, get information from counters. */
5142 #endif /* DISABLE_IF_COUNTERS */
5143 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
5144 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
5145 if (unlikely(ret)) {
5146 ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
5147 goto error;
5148 }
5149 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
5150 if (ret != BCME_OK) {
5151 ANDROID_ERROR(("wl_android_get_connection_stats:"
5152 " wl_cntbuf_to_xtlv_format ERR %d\n",
5153 ret));
5154 goto error;
5155 }
5156
5157 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
5158 ANDROID_ERROR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
5159 goto error;
5160 }
5161
5162 output->txframe = dtoh32(wlc_cnt->txframe);
5163 output->txbyte = dtoh32(wlc_cnt->txbyte);
5164 output->txerror = dtoh32(wlc_cnt->txerror);
5165 output->rxframe = dtoh32(wlc_cnt->rxframe);
5166 output->rxbyte = dtoh32(wlc_cnt->rxbyte);
5167 output->txfail = dtoh32(wlc_cnt->txfail);
5168 output->txretry = dtoh32(wlc_cnt->txretry);
5169 output->txretrie = dtoh32(wlc_cnt->txretrie);
5170 output->txrts = dtoh32(wlc_cnt->txrts);
5171 output->txnocts = dtoh32(wlc_cnt->txnocts);
5172 output->txexptime = dtoh32(wlc_cnt->txexptime);
5173 #ifndef DISABLE_IF_COUNTERS
5174 } else {
5175 /* Populate from if_stats. */
5176 if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
5177 ANDROID_ERROR(("wl_android_get_connection_stats: incorrect version of"
5178 " wl_if_stats_t,"
5179 " expected=%u got=%u\n",
5180 WL_IF_STATS_T_VERSION, if_stats->version));
5181 goto error;
5182 }
5183
5184 output->txframe = (uint32)dtoh64(if_stats->txframe);
5185 output->txbyte = (uint32)dtoh64(if_stats->txbyte);
5186 output->txerror = (uint32)dtoh64(if_stats->txerror);
5187 output->rxframe = (uint32)dtoh64(if_stats->rxframe);
5188 output->rxbyte = (uint32)dtoh64(if_stats->rxbyte);
5189 output->txfail = (uint32)dtoh64(if_stats->txfail);
5190 output->txretry = (uint32)dtoh64(if_stats->txretry);
5191 output->txretrie = (uint32)dtoh64(if_stats->txretrie);
5192 if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
5193 output->txexptime = (uint32)dtoh64(if_stats->txexptime);
5194 output->txrts = (uint32)dtoh64(if_stats->txrts);
5195 output->txnocts = (uint32)dtoh64(if_stats->txnocts);
5196 } else {
5197 output->txexptime = 0;
5198 output->txrts = 0;
5199 output->txnocts = 0;
5200 }
5201 }
5202 #endif /* DISABLE_IF_COUNTERS */
5203
5204 /* link_speed is in kbps */
5205 ret = wldev_get_link_speed(dev, &link_speed);
5206 if (ret || link_speed < 0) {
5207 ANDROID_ERROR(("wl_android_get_connection_stats: wldev_get_link_speed()"
5208 " failed, ret=%d, speed=%d\n",
5209 ret, link_speed));
5210 goto error;
5211 }
5212
5213 output->txrate = link_speed;
5214
5215 /* Channel idle ratio. */
5216 if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
5217 output->chan_idle = 0;
5218 };
5219
5220 bytes_written = sizeof(struct connection_stats);
5221
5222 error:
5223 #ifndef DISABLE_IF_COUNTERS
5224 if (if_stats) {
5225 MFREE(cfg->osh, if_stats, sizeof(*if_stats));
5226 }
5227 #endif /* DISABLE_IF_COUNTERS */
5228
5229 return bytes_written;
5230 }
5231 #endif /* CONNECTION_STATISTICS */
5232
5233 #ifdef WL_NATOE
5234 static int
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)5235 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
5236 {
5237 int ret = BCME_ERROR;
5238 char *pcmd = command;
5239 char *str = NULL;
5240 wl_natoe_cmd_info_t cmd_info;
5241 const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
5242
5243 /* skip to cmd name after "natoe" */
5244 str = bcmstrtok(&pcmd, " ", NULL);
5245
5246 /* If natoe subcmd name is not provided, return error */
5247 if (*pcmd == '\0') {
5248 ANDROID_ERROR(("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
5249 ret = -EINVAL;
5250 return ret;
5251 }
5252
5253 /* get the natoe command name to str */
5254 str = bcmstrtok(&pcmd, " ", NULL);
5255
5256 while (natoe_cmd->name != NULL) {
5257 if (strcmp(natoe_cmd->name, str) == 0) {
5258 /* dispacth cmd to appropriate handler */
5259 if (natoe_cmd->handler) {
5260 cmd_info.command = command;
5261 cmd_info.tot_len = total_len;
5262 ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
5263 }
5264 return ret;
5265 }
5266 natoe_cmd++;
5267 }
5268 return ret;
5269 }
5270
5271 static int
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)5272 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
5273 {
5274 int res = BCME_OK;
5275 wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
5276 uint8 *command = cmd_info->command;
5277 uint16 total_len = cmd_info->tot_len;
5278 uint16 bytes_written = 0;
5279
5280 UNUSED_PARAMETER(len);
5281
5282 switch (type) {
5283
5284 case WL_NATOE_XTLV_ENABLE:
5285 {
5286 bytes_written = snprintf(command, total_len, "natoe: %s\n",
5287 *data?"enabled":"disabled");
5288 cmd_info->bytes_written = bytes_written;
5289 break;
5290 }
5291
5292 case WL_NATOE_XTLV_CONFIG_IPS:
5293 {
5294 wl_natoe_config_ips_t *config_ips;
5295 uint8 buf[16];
5296
5297 config_ips = (wl_natoe_config_ips_t *)data;
5298 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
5299 bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
5300 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
5301 bytes_written += snprintf(command + bytes_written, total_len,
5302 "sta netmask: %s\n", buf);
5303 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
5304 bytes_written += snprintf(command + bytes_written, total_len,
5305 "sta router ip: %s\n", buf);
5306 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
5307 bytes_written += snprintf(command + bytes_written, total_len,
5308 "sta dns ip: %s\n", buf);
5309 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
5310 bytes_written += snprintf(command + bytes_written, total_len,
5311 "ap ip: %s\n", buf);
5312 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
5313 bytes_written += snprintf(command + bytes_written, total_len,
5314 "ap netmask: %s\n", buf);
5315 cmd_info->bytes_written = bytes_written;
5316 break;
5317 }
5318
5319 case WL_NATOE_XTLV_CONFIG_PORTS:
5320 {
5321 wl_natoe_ports_config_t *ports_config;
5322
5323 ports_config = (wl_natoe_ports_config_t *)data;
5324 bytes_written = snprintf(command, total_len, "starting port num: %d\n",
5325 dtoh16(ports_config->start_port_num));
5326 bytes_written += snprintf(command + bytes_written, total_len,
5327 "number of ports: %d\n", dtoh16(ports_config->no_of_ports));
5328 cmd_info->bytes_written = bytes_written;
5329 break;
5330 }
5331
5332 case WL_NATOE_XTLV_DBG_STATS:
5333 {
5334 char *stats_dump = (char *)data;
5335
5336 bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
5337 cmd_info->bytes_written = bytes_written;
5338 break;
5339 }
5340
5341 case WL_NATOE_XTLV_TBL_CNT:
5342 {
5343 bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
5344 dtoh32(*(uint32 *)data));
5345 cmd_info->bytes_written = bytes_written;
5346 break;
5347 }
5348
5349 default:
5350 /* ignore */
5351 break;
5352 }
5353
5354 return res;
5355 }
5356
5357 /*
5358 * --- common for all natoe get commands ----
5359 */
5360 static int
wl_natoe_get_ioctl(struct net_device * dev,wl_natoe_ioc_t * natoe_ioc,uint16 iocsz,uint8 * buf,uint16 buflen,wl_natoe_cmd_info_t * cmd_info)5361 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
5362 uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
5363 {
5364 /* for gets we only need to pass ioc header */
5365 wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
5366 int res;
5367
5368 /* send getbuf natoe iovar */
5369 res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
5370 buflen, NULL);
5371
5372 /* check the response buff */
5373 if ((res == BCME_OK)) {
5374 /* scans ioctl tlvbuf f& invokes the cbfn for processing */
5375 res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
5376 BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
5377
5378 if (res == BCME_OK) {
5379 res = cmd_info->bytes_written;
5380 }
5381 }
5382 else
5383 {
5384 ANDROID_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res));
5385 res = BCME_ERROR;
5386 }
5387
5388 return res;
5389 }
5390
5391 static int
wl_android_natoe_subcmd_enable(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5392 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5393 char *command, wl_natoe_cmd_info_t *cmd_info)
5394 {
5395 int ret = BCME_OK;
5396 wl_natoe_ioc_t *natoe_ioc;
5397 char *pcmd = command;
5398 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5399 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5400 bcm_xtlv_t *pxtlv = NULL;
5401 char *ioctl_buf = NULL;
5402 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5403
5404 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5405 if (!ioctl_buf) {
5406 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5407 return -ENOMEM;
5408 }
5409
5410 /* alloc mem for ioctl headr + tlv data */
5411 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5412 if (!natoe_ioc) {
5413 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5414 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5415 return -ENOMEM;
5416 }
5417
5418 /* make up natoe cmd ioctl header */
5419 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5420 natoe_ioc->id = htod16(cmd->id);
5421 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5422 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5423
5424 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5425 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5426 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5427 WLC_IOCTL_MEDLEN, cmd_info);
5428 if (ret != BCME_OK) {
5429 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
5430 ret = -EINVAL;
5431 }
5432 } else { /* set */
5433 uint8 val = bcm_atoi(pcmd);
5434
5435 /* buflen is max tlv data we can write, it will be decremented as we pack */
5436 /* save buflen at start */
5437 uint16 buflen_at_start = buflen;
5438
5439 /* we'll adjust final ioc size at the end */
5440 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5441 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5442
5443 if (ret != BCME_OK) {
5444 ret = -EINVAL;
5445 goto exit;
5446 }
5447
5448 /* adjust iocsz to the end of last data record */
5449 natoe_ioc->len = (buflen_at_start - buflen);
5450 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5451
5452 ret = wldev_iovar_setbuf(dev, "natoe",
5453 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5454 if (ret != BCME_OK) {
5455 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5456 ret = -EINVAL;
5457 }
5458 }
5459
5460 exit:
5461 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5462 MFREE(cfg->osh, natoe_ioc, iocsz);
5463
5464 return ret;
5465 }
5466
5467 static int
wl_android_natoe_subcmd_config_ips(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5468 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
5469 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5470 {
5471 int ret = BCME_OK;
5472 wl_natoe_config_ips_t config_ips;
5473 wl_natoe_ioc_t *natoe_ioc;
5474 char *pcmd = command;
5475 char *str;
5476 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5477 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5478 bcm_xtlv_t *pxtlv = NULL;
5479 char *ioctl_buf = NULL;
5480 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5481
5482 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5483 if (!ioctl_buf) {
5484 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5485 return -ENOMEM;
5486 }
5487
5488 /* alloc mem for ioctl headr + tlv data */
5489 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5490 if (!natoe_ioc) {
5491 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5492 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5493 return -ENOMEM;
5494 }
5495
5496 /* make up natoe cmd ioctl header */
5497 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5498 natoe_ioc->id = htod16(cmd->id);
5499 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5500 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5501
5502 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5503 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5504 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5505 WLC_IOCTL_MEDLEN, cmd_info);
5506 if (ret != BCME_OK) {
5507 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
5508 ret = -EINVAL;
5509 }
5510 } else { /* set */
5511 /* buflen is max tlv data we can write, it will be decremented as we pack */
5512 /* save buflen at start */
5513 uint16 buflen_at_start = buflen;
5514
5515 bzero(&config_ips, sizeof(config_ips));
5516
5517 str = bcmstrtok(&pcmd, " ", NULL);
5518 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
5519 ANDROID_ERROR(("Invalid STA IP addr %s\n", str));
5520 ret = -EINVAL;
5521 goto exit;
5522 }
5523
5524 str = bcmstrtok(&pcmd, " ", NULL);
5525 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_netmask)) {
5526 ANDROID_ERROR(("Invalid STA netmask %s\n", str));
5527 ret = -EINVAL;
5528 goto exit;
5529 }
5530
5531 str = bcmstrtok(&pcmd, " ", NULL);
5532 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_router_ip)) {
5533 ANDROID_ERROR(("Invalid STA router IP addr %s\n", str));
5534 ret = -EINVAL;
5535 goto exit;
5536 }
5537
5538 str = bcmstrtok(&pcmd, " ", NULL);
5539 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_dnsip)) {
5540 ANDROID_ERROR(("Invalid STA DNS IP addr %s\n", str));
5541 ret = -EINVAL;
5542 goto exit;
5543 }
5544
5545 str = bcmstrtok(&pcmd, " ", NULL);
5546 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_ip)) {
5547 ANDROID_ERROR(("Invalid AP IP addr %s\n", str));
5548 ret = -EINVAL;
5549 goto exit;
5550 }
5551
5552 str = bcmstrtok(&pcmd, " ", NULL);
5553 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
5554 ANDROID_ERROR(("Invalid AP netmask %s\n", str));
5555 ret = -EINVAL;
5556 goto exit;
5557 }
5558
5559 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5560 &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
5561 &config_ips, BCM_XTLV_OPTION_ALIGN32);
5562
5563 if (ret != BCME_OK) {
5564 ret = -EINVAL;
5565 goto exit;
5566 }
5567
5568 /* adjust iocsz to the end of last data record */
5569 natoe_ioc->len = (buflen_at_start - buflen);
5570 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5571
5572 ret = wldev_iovar_setbuf(dev, "natoe",
5573 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5574 if (ret != BCME_OK) {
5575 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5576 ret = -EINVAL;
5577 }
5578 }
5579
5580 exit:
5581 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5582 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5583
5584 return ret;
5585 }
5586
5587 static int
wl_android_natoe_subcmd_config_ports(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5588 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
5589 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5590 {
5591 int ret = BCME_OK;
5592 wl_natoe_ports_config_t ports_config;
5593 wl_natoe_ioc_t *natoe_ioc;
5594 char *pcmd = command;
5595 char *str;
5596 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5597 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5598 bcm_xtlv_t *pxtlv = NULL;
5599 char *ioctl_buf = NULL;
5600 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5601
5602 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5603 if (!ioctl_buf) {
5604 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5605 return -ENOMEM;
5606 }
5607
5608 /* alloc mem for ioctl headr + tlv data */
5609 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5610 if (!natoe_ioc) {
5611 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5612 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5613 return -ENOMEM;
5614 }
5615
5616 /* make up natoe cmd ioctl header */
5617 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5618 natoe_ioc->id = htod16(cmd->id);
5619 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5620 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5621
5622 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5623 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5624 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5625 WLC_IOCTL_MEDLEN, cmd_info);
5626 if (ret != BCME_OK) {
5627 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
5628 ret = -EINVAL;
5629 }
5630 } else { /* set */
5631 /* buflen is max tlv data we can write, it will be decremented as we pack */
5632 /* save buflen at start */
5633 uint16 buflen_at_start = buflen;
5634
5635 bzero(&ports_config, sizeof(ports_config));
5636
5637 str = bcmstrtok(&pcmd, " ", NULL);
5638 if (!str) {
5639 ANDROID_ERROR(("Invalid port string %s\n", str));
5640 ret = -EINVAL;
5641 goto exit;
5642 }
5643 ports_config.start_port_num = htod16(bcm_atoi(str));
5644
5645 str = bcmstrtok(&pcmd, " ", NULL);
5646 if (!str) {
5647 ANDROID_ERROR(("Invalid port string %s\n", str));
5648 ret = -EINVAL;
5649 goto exit;
5650 }
5651 ports_config.no_of_ports = htod16(bcm_atoi(str));
5652
5653 if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
5654 NATOE_MAX_PORT_NUM) {
5655 ANDROID_ERROR(("Invalid port configuration\n"));
5656 ret = -EINVAL;
5657 goto exit;
5658 }
5659 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5660 &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
5661 &ports_config, BCM_XTLV_OPTION_ALIGN32);
5662
5663 if (ret != BCME_OK) {
5664 ret = -EINVAL;
5665 goto exit;
5666 }
5667
5668 /* adjust iocsz to the end of last data record */
5669 natoe_ioc->len = (buflen_at_start - buflen);
5670 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5671
5672 ret = wldev_iovar_setbuf(dev, "natoe",
5673 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5674 if (ret != BCME_OK) {
5675 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5676 ret = -EINVAL;
5677 }
5678 }
5679
5680 exit:
5681 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5682 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5683
5684 return ret;
5685 }
5686
5687 static int
wl_android_natoe_subcmd_dbg_stats(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5688 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5689 char *command, wl_natoe_cmd_info_t *cmd_info)
5690 {
5691 int ret = BCME_OK;
5692 wl_natoe_ioc_t *natoe_ioc;
5693 char *pcmd = command;
5694 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5695 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
5696 uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
5697 bcm_xtlv_t *pxtlv = NULL;
5698 char *ioctl_buf = NULL;
5699 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5700
5701 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5702 if (!ioctl_buf) {
5703 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5704 return -ENOMEM;
5705 }
5706
5707 /* alloc mem for ioctl headr + tlv data */
5708 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5709 if (!natoe_ioc) {
5710 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5711 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5712 return -ENOMEM;
5713 }
5714
5715 /* make up natoe cmd ioctl header */
5716 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5717 natoe_ioc->id = htod16(cmd->id);
5718 natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
5719 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5720
5721 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5722 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5723 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5724 WLC_IOCTL_MAXLEN, cmd_info);
5725 if (ret != BCME_OK) {
5726 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
5727 ret = -EINVAL;
5728 }
5729 } else { /* set */
5730 uint8 val = bcm_atoi(pcmd);
5731
5732 /* buflen is max tlv data we can write, it will be decremented as we pack */
5733 /* save buflen at start */
5734 uint16 buflen_at_start = buflen;
5735
5736 /* we'll adjust final ioc size at the end */
5737 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5738 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5739
5740 if (ret != BCME_OK) {
5741 ret = -EINVAL;
5742 goto exit;
5743 }
5744
5745 /* adjust iocsz to the end of last data record */
5746 natoe_ioc->len = (buflen_at_start - buflen);
5747 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5748
5749 ret = wldev_iovar_setbuf(dev, "natoe",
5750 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
5751 if (ret != BCME_OK) {
5752 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5753 ret = -EINVAL;
5754 }
5755 }
5756
5757 exit:
5758 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5759 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
5760
5761 return ret;
5762 }
5763
5764 static int
wl_android_natoe_subcmd_tbl_cnt(struct net_device * dev,const wl_natoe_sub_cmd_t * cmd,char * command,wl_natoe_cmd_info_t * cmd_info)5765 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5766 char *command, wl_natoe_cmd_info_t *cmd_info)
5767 {
5768 int ret = BCME_OK;
5769 wl_natoe_ioc_t *natoe_ioc;
5770 char *pcmd = command;
5771 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5772 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5773 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5774 bcm_xtlv_t *pxtlv = NULL;
5775 char *ioctl_buf = NULL;
5776 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5777
5778 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5779 if (!ioctl_buf) {
5780 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5781 return -ENOMEM;
5782 }
5783
5784 /* alloc mem for ioctl headr + tlv data */
5785 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5786 if (!natoe_ioc) {
5787 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5788 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5789 return -ENOMEM;
5790 }
5791
5792 /* make up natoe cmd ioctl header */
5793 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5794 natoe_ioc->id = htod16(cmd->id);
5795 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5796 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5797
5798 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5799 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5800 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5801 WLC_IOCTL_MEDLEN, cmd_info);
5802 if (ret != BCME_OK) {
5803 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
5804 ret = -EINVAL;
5805 }
5806 } else { /* set */
5807 uint32 val = bcm_atoi(pcmd);
5808
5809 /* buflen is max tlv data we can write, it will be decremented as we pack */
5810 /* save buflen at start */
5811 uint16 buflen_at_start = buflen;
5812
5813 /* we'll adjust final ioc size at the end */
5814 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
5815 sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
5816
5817 if (ret != BCME_OK) {
5818 ret = -EINVAL;
5819 goto exit;
5820 }
5821
5822 /* adjust iocsz to the end of last data record */
5823 natoe_ioc->len = (buflen_at_start - buflen);
5824 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5825
5826 ret = wldev_iovar_setbuf(dev, "natoe",
5827 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5828 if (ret != BCME_OK) {
5829 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5830 ret = -EINVAL;
5831 }
5832 }
5833
5834 exit:
5835 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5836 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5837
5838 return ret;
5839 }
5840
5841 #endif /* WL_NATOE */
5842
5843 #ifdef WL_MBO
5844 static int
wl_android_process_mbo_cmd(struct net_device * dev,char * command,int total_len)5845 wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len)
5846 {
5847 int ret = BCME_ERROR;
5848 char *pcmd = command;
5849 char *str = NULL;
5850 wl_drv_cmd_info_t cmd_info;
5851 const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
5852
5853 /* skip to cmd name after "mbo" */
5854 str = bcmstrtok(&pcmd, " ", NULL);
5855
5856 /* If mbo subcmd name is not provided, return error */
5857 if (*pcmd == '\0') {
5858 ANDROID_ERROR(("mbo subcmd not provided %s\n", __FUNCTION__));
5859 ret = -EINVAL;
5860 return ret;
5861 }
5862
5863 /* get the mbo command name to str */
5864 str = bcmstrtok(&pcmd, " ", NULL);
5865
5866 while (mbo_cmd->name != NULL) {
5867 if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
5868 /* dispatch cmd to appropriate handler */
5869 if (mbo_cmd->handler) {
5870 cmd_info.command = command;
5871 cmd_info.tot_len = total_len;
5872 ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
5873 }
5874 return ret;
5875 }
5876 mbo_cmd++;
5877 }
5878 return ret;
5879 }
5880
5881 static int
wl_android_send_wnm_notif(struct net_device * dev,bcm_iov_buf_t * iov_buf,uint16 iov_buf_len,uint8 * iov_resp,uint16 iov_resp_len,uint8 sub_elem_type)5882 wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf,
5883 uint16 iov_buf_len, uint8 *iov_resp, uint16 iov_resp_len, uint8 sub_elem_type)
5884 {
5885 int ret = BCME_OK;
5886 uint8 *pxtlv = NULL;
5887 uint16 iovlen = 0;
5888 uint16 buflen = 0, buflen_start = 0;
5889
5890 memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
5891 iov_buf->version = WL_MBO_IOV_VERSION;
5892 iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
5893 buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
5894 pxtlv = (uint8 *)&iov_buf->data[0];
5895 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
5896 sizeof(sub_elem_type), &sub_elem_type, BCM_XTLV_OPTION_ALIGN32);
5897 if (ret != BCME_OK) {
5898 return ret;
5899 }
5900 iov_buf->len = buflen_start - buflen;
5901 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5902 ret = wldev_iovar_setbuf(dev, "mbo",
5903 iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5904 if (ret != BCME_OK) {
5905 ANDROID_ERROR(("Fail to sent wnm notif %d\n", ret));
5906 }
5907 return ret;
5908 }
5909
5910 static int
wl_android_mbo_resp_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5911 wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5912 {
5913 wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
5914 uint8 *command = cmd_info->command;
5915 uint16 total_len = cmd_info->tot_len;
5916 uint16 bytes_written = 0;
5917
5918 UNUSED_PARAMETER(len);
5919 /* TODO: validate data value */
5920 if (data == NULL) {
5921 ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
5922 return -EINVAL;
5923 }
5924 switch (type) {
5925 case WL_MBO_XTLV_CELL_DATA_CAP:
5926 {
5927 bytes_written = snprintf(command, total_len, "cell_data_cap: %u\n", *data);
5928 cmd_info->bytes_written = bytes_written;
5929 }
5930 break;
5931 default:
5932 ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
5933 }
5934 return BCME_OK;
5935 }
5936
5937 static int
wl_android_mbo_subcmd_cell_data_cap(struct net_device * dev,const wl_drv_sub_cmd_t * cmd,char * command,wl_drv_cmd_info_t * cmd_info)5938 wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd_t *cmd,
5939 char *command, wl_drv_cmd_info_t *cmd_info)
5940 {
5941 int ret = BCME_OK;
5942 uint8 *pxtlv = NULL;
5943 uint16 buflen = 0, buflen_start = 0;
5944 uint16 iovlen = 0;
5945 char *pcmd = command;
5946 bcm_iov_buf_t *iov_buf = NULL;
5947 bcm_iov_buf_t *p_resp = NULL;
5948 uint8 *iov_resp = NULL;
5949 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5950 uint16 version;
5951
5952 /* first get the configured value */
5953 iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5954 if (iov_buf == NULL) {
5955 ret = -ENOMEM;
5956 ANDROID_ERROR(("iov buf memory alloc exited\n"));
5957 goto exit;
5958 }
5959 iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5960 if (iov_resp == NULL) {
5961 ret = -ENOMEM;
5962 ANDROID_ERROR(("iov resp memory alloc exited\n"));
5963 goto exit;
5964 }
5965
5966 /* fill header */
5967 iov_buf->version = WL_MBO_IOV_VERSION;
5968 iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
5969
5970 ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
5971 WLC_IOCTL_MAXLEN,
5972 NULL);
5973 if (ret != BCME_OK) {
5974 goto exit;
5975 }
5976 p_resp = (bcm_iov_buf_t *)iov_resp;
5977
5978 /* get */
5979 if (*pcmd == WL_IOCTL_ACTION_GET) {
5980 /* Check for version */
5981 version = dtoh16(*(uint16 *)iov_resp);
5982 if (version != WL_MBO_IOV_VERSION) {
5983 ret = -EINVAL;
5984 }
5985 if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
5986 ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
5987 p_resp->len, BCM_XTLV_OPTION_ALIGN32,
5988 wl_android_mbo_resp_parse_cbfn);
5989 if (ret == BCME_OK) {
5990 ret = cmd_info->bytes_written;
5991 }
5992 } else {
5993 ret = -EINVAL;
5994 ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
5995 goto exit;
5996 }
5997 } else {
5998 uint8 cell_cap = bcm_atoi(pcmd);
5999 const uint8* old_cell_cap = NULL;
6000 uint16 len = 0;
6001
6002 old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len,
6003 WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32);
6004 if (old_cell_cap && *old_cell_cap == cell_cap) {
6005 ANDROID_ERROR(("No change is cellular data capability\n"));
6006 /* No change in value */
6007 goto exit;
6008 }
6009
6010 buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
6011
6012 if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
6013 cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
6014 ANDROID_ERROR(("wrong value %u\n", cell_cap));
6015 ret = -EINVAL;
6016 goto exit;
6017 }
6018 pxtlv = (uint8 *)&iov_buf->data[0];
6019 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
6020 sizeof(cell_cap), &cell_cap, BCM_XTLV_OPTION_ALIGN32);
6021 if (ret != BCME_OK) {
6022 goto exit;
6023 }
6024 iov_buf->len = buflen_start - buflen;
6025 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6026 ret = wldev_iovar_setbuf(dev, "mbo",
6027 iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6028 if (ret != BCME_OK) {
6029 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6030 ret = -EINVAL;
6031 goto exit;
6032 }
6033 /* Skip for CUSTOMER_HW4 - WNM notification
6034 * for cellular data capability is handled by host
6035 */
6036 #if !defined(CUSTOMER_HW4)
6037 /* send a WNM notification request to associated AP */
6038 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6039 ANDROID_INFO(("Sending WNM Notif\n"));
6040 ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6041 iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP);
6042 if (ret != BCME_OK) {
6043 ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6044 ret = -EINVAL;
6045 }
6046 }
6047 #endif /* CUSTOMER_HW4 */
6048 }
6049 exit:
6050 if (iov_buf) {
6051 MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6052 }
6053 if (iov_resp) {
6054 MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6055 }
6056 return ret;
6057 }
6058
6059 static int
wl_android_mbo_non_pref_chan_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)6060 wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
6061 {
6062 wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
6063 uint8 *command = cmd_info->command + cmd_info->bytes_written;
6064 uint16 total_len = cmd_info->tot_len;
6065 uint16 bytes_written = 0;
6066
6067 ANDROID_INFO(("Total bytes written at begining %u\n", cmd_info->bytes_written));
6068 UNUSED_PARAMETER(len);
6069 if (data == NULL) {
6070 ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
6071 return -EINVAL;
6072 }
6073 switch (type) {
6074 case WL_MBO_XTLV_OPCLASS:
6075 {
6076 bytes_written = snprintf(command, total_len, "%u:", *data);
6077 ANDROID_ERROR(("wr %u %u\n", bytes_written, *data));
6078 command += bytes_written;
6079 cmd_info->bytes_written += bytes_written;
6080 }
6081 break;
6082 case WL_MBO_XTLV_CHAN:
6083 {
6084 bytes_written = snprintf(command, total_len, "%u:", *data);
6085 ANDROID_ERROR(("wr %u\n", bytes_written));
6086 command += bytes_written;
6087 cmd_info->bytes_written += bytes_written;
6088 }
6089 break;
6090 case WL_MBO_XTLV_PREFERENCE:
6091 {
6092 bytes_written = snprintf(command, total_len, "%u:", *data);
6093 ANDROID_ERROR(("wr %u\n", bytes_written));
6094 command += bytes_written;
6095 cmd_info->bytes_written += bytes_written;
6096 }
6097 break;
6098 case WL_MBO_XTLV_REASON_CODE:
6099 {
6100 bytes_written = snprintf(command, total_len, "%u ", *data);
6101 ANDROID_ERROR(("wr %u\n", bytes_written));
6102 command += bytes_written;
6103 cmd_info->bytes_written += bytes_written;
6104 }
6105 break;
6106 default:
6107 ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
6108 }
6109 ANDROID_INFO(("Total bytes written %u\n", cmd_info->bytes_written));
6110 return BCME_OK;
6111 }
6112
6113 static int
wl_android_mbo_subcmd_non_pref_chan(struct net_device * dev,const wl_drv_sub_cmd_t * cmd,char * command,wl_drv_cmd_info_t * cmd_info)6114 wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
6115 const wl_drv_sub_cmd_t *cmd, char *command,
6116 wl_drv_cmd_info_t *cmd_info)
6117 {
6118 int ret = BCME_OK;
6119 uint8 *pxtlv = NULL;
6120 uint16 buflen = 0, buflen_start = 0;
6121 uint16 iovlen = 0;
6122 char *pcmd = command;
6123 bcm_iov_buf_t *iov_buf = NULL;
6124 bcm_iov_buf_t *p_resp = NULL;
6125 uint8 *iov_resp = NULL;
6126 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6127 uint16 version;
6128
6129 ANDROID_ERROR(("%s:%d\n", __FUNCTION__, __LINE__));
6130 iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
6131 if (iov_buf == NULL) {
6132 ret = -ENOMEM;
6133 ANDROID_ERROR(("iov buf memory alloc exited\n"));
6134 goto exit;
6135 }
6136 iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6137 if (iov_resp == NULL) {
6138 ret = -ENOMEM;
6139 ANDROID_ERROR(("iov resp memory alloc exited\n"));
6140 goto exit;
6141 }
6142 /* get */
6143 if (*pcmd == WL_IOCTL_ACTION_GET) {
6144 /* fill header */
6145 iov_buf->version = WL_MBO_IOV_VERSION;
6146 iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
6147
6148 ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
6149 WLC_IOCTL_MAXLEN, NULL);
6150 if (ret != BCME_OK) {
6151 goto exit;
6152 }
6153 p_resp = (bcm_iov_buf_t *)iov_resp;
6154 /* Check for version */
6155 version = dtoh16(*(uint16 *)iov_resp);
6156 if (version != WL_MBO_IOV_VERSION) {
6157 ANDROID_ERROR(("Version mismatch. returned ver %u expected %u\n",
6158 version, WL_MBO_IOV_VERSION));
6159 ret = -EINVAL;
6160 }
6161 if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
6162 ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
6163 p_resp->len, BCM_XTLV_OPTION_ALIGN32,
6164 wl_android_mbo_non_pref_chan_parse_cbfn);
6165 if (ret == BCME_OK) {
6166 ret = cmd_info->bytes_written;
6167 }
6168 } else {
6169 ret = -EINVAL;
6170 ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
6171 goto exit;
6172 }
6173 } else {
6174 char *str = pcmd;
6175 uint opcl = 0, ch = 0, pref = 0, rc = 0;
6176
6177 str = bcmstrtok(&pcmd, " ", NULL);
6178 if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) {
6179 /* delete all configurations */
6180 iov_buf->version = WL_MBO_IOV_VERSION;
6181 iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
6182 iov_buf->len = 0;
6183 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6184 ret = wldev_iovar_setbuf(dev, "mbo",
6185 iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6186 if (ret != BCME_OK) {
6187 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6188 ret = -EINVAL;
6189 goto exit;
6190 }
6191 } else {
6192 ANDROID_ERROR(("Unknown command %s\n", str));
6193 goto exit;
6194 }
6195 /* parse non pref channel list */
6196 if (strnicmp(str, "set", 3) == 0) {
6197 uint8 cnt = 0;
6198 str = bcmstrtok(&pcmd, " ", NULL);
6199 while (str != NULL) {
6200 ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
6201 ANDROID_ERROR(("buflen %u op %u, ch %u, pref %u rc %u\n",
6202 buflen, opcl, ch, pref, rc));
6203 if (ret != 4) {
6204 ANDROID_ERROR(("Not all parameter presents\n"));
6205 ret = -EINVAL;
6206 }
6207 /* TODO: add a validation check here */
6208 memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
6209 buflen = buflen_start = WLC_IOCTL_MEDLEN;
6210 pxtlv = (uint8 *)&iov_buf->data[0];
6211 /* opclass */
6212 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
6213 sizeof(uint8), (uint8 *)&opcl, BCM_XTLV_OPTION_ALIGN32);
6214 if (ret != BCME_OK) {
6215 goto exit;
6216 }
6217 /* channel */
6218 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
6219 sizeof(uint8), (uint8 *)&ch, BCM_XTLV_OPTION_ALIGN32);
6220 if (ret != BCME_OK) {
6221 goto exit;
6222 }
6223 /* preference */
6224 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
6225 sizeof(uint8), (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
6226 if (ret != BCME_OK) {
6227 goto exit;
6228 }
6229 /* reason */
6230 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
6231 sizeof(uint8), (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
6232 if (ret != BCME_OK) {
6233 goto exit;
6234 }
6235 ANDROID_ERROR(("len %u\n", (buflen_start - buflen)));
6236 /* Now set the new non pref channels */
6237 iov_buf->version = WL_MBO_IOV_VERSION;
6238 iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
6239 iov_buf->len = buflen_start - buflen;
6240 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6241 ret = wldev_iovar_setbuf(dev, "mbo",
6242 iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL);
6243 if (ret != BCME_OK) {
6244 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6245 ret = -EINVAL;
6246 goto exit;
6247 }
6248 cnt++;
6249 if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
6250 break;
6251 }
6252 ANDROID_ERROR(("%d cnt %u\n", __LINE__, cnt));
6253 str = bcmstrtok(&pcmd, " ", NULL);
6254 }
6255 }
6256 /* send a WNM notification request to associated AP */
6257 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6258 ANDROID_INFO(("Sending WNM Notif\n"));
6259 ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6260 iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT);
6261 if (ret != BCME_OK) {
6262 ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6263 ret = -EINVAL;
6264 }
6265 }
6266 }
6267 exit:
6268 if (iov_buf) {
6269 MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6270 }
6271 if (iov_resp) {
6272 MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6273 }
6274 return ret;
6275 }
6276 #endif /* WL_MBO */
6277
6278 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6279 #ifdef SUPPORT_AMPDU_MPDU_CMD
6280 /* CMD_AMPDU_MPDU */
6281 static int
wl_android_set_ampdu_mpdu(struct net_device * dev,const char * string_num)6282 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
6283 {
6284 int err = 0;
6285 int ampdu_mpdu;
6286
6287 ampdu_mpdu = bcm_atoi(string_num);
6288
6289 if (ampdu_mpdu > 32) {
6290 ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n"));
6291 return -1;
6292 }
6293
6294 ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu));
6295 err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
6296 if (err < 0) {
6297 ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err));
6298 return -1;
6299 }
6300
6301 return 0;
6302 }
6303 #endif /* SUPPORT_AMPDU_MPDU_CMD */
6304 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
6305
6306 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6307 extern int wl_cfg80211_send_msg_to_ril(void);
6308 extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
6309 extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
6310 extern int g_mhs_chan_for_cpcoex;
6311 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6312
6313 #if defined (WL_SUPPORT_AUTO_CHANNEL)
6314 static s32
wl_android_set_auto_channel_scan_state(struct net_device * ndev)6315 wl_android_set_auto_channel_scan_state(struct net_device *ndev)
6316 {
6317 u32 val = 0;
6318 s32 ret = BCME_ERROR;
6319 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6320 /* Set interface up, explicitly. */
6321 val = 1;
6322
6323 ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
6324 if (ret < 0) {
6325 ANDROID_ERROR(("set interface up failed, error = %d\n", ret));
6326 goto done;
6327 }
6328
6329 /* Stop all scan explicitly, till auto channel selection complete. */
6330 wl_set_drv_status(cfg, SCANNING, ndev);
6331 if (cfg->escan_info.ndev == NULL) {
6332 ret = BCME_OK;
6333 goto done;
6334 }
6335
6336 wl_cfgscan_cancel_scan(cfg);
6337
6338 done:
6339 return ret;
6340 }
6341
6342 s32
wl_android_get_freq_list_chanspecs(struct net_device * ndev,wl_uint32_list_t * list,s32 buflen,const char * cmd_str,int sta_channel,chanspec_band_t sta_acs_band)6343 wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *list,
6344 s32 buflen, const char* cmd_str, int sta_channel, chanspec_band_t sta_acs_band)
6345 {
6346 u32 freq = 0;
6347 chanspec_t chanspec = 0;
6348 s32 ret = BCME_OK;
6349 int i = 0;
6350 char *pcmd, *token;
6351 int len = buflen;
6352
6353 pcmd = bcmstrstr(cmd_str, FREQ_STR);
6354 pcmd += strlen(FREQ_STR);
6355
6356 len -= sizeof(list->count);
6357
6358 while ((token = strsep(&pcmd, ",")) != NULL) {
6359 if (*token == '\0')
6360 continue;
6361
6362 if (len < sizeof(list->element[i]))
6363 break;
6364
6365 freq = bcm_atoi(token);
6366 /* Convert chanspec from frequency */
6367 if ((freq > 0) &&
6368 ((chanspec = wl_freq_to_chanspec(freq)) != INVCHANSPEC)) {
6369 ANDROID_INFO(("Adding chanspec in list : 0x%x at the index %d\n", chanspec, i));
6370 list->element[i] = chanspec;
6371 len -= sizeof(list->element[i]);
6372 i++;
6373 #ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN
6374 /* Android includes 2g channels even for 5g band configuration. For
6375 * customers using only single channel 5G AP, set the channel and
6376 * return without doing ACS
6377 */
6378 if (CHSPEC_BAND(chanspec) == WL_CHANSPEC_BAND_5G) {
6379 ANDROID_INFO(("Pick default channnel from 5g\n"));
6380 if (!sta_channel) {
6381 list->element[0] = chanspec;
6382 list->count = 1;
6383 return ret;
6384 }
6385 break;
6386 }
6387 #endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */
6388 }
6389 }
6390
6391 list->count = i;
6392 /* valid chanspec present in the list */
6393 if (list->count && sta_channel) {
6394 /* STA associated case. Can't do ACS.
6395 * Frequency list is order of lower to higher band.
6396 * check with the highest band entry.
6397 */
6398 chanspec = list->element[i-1];
6399 if (CHSPEC_BAND(chanspec) == sta_acs_band) {
6400 /* softap request is for same band. Use SCC
6401 * Convert sta channel to freq
6402 */
6403 freq = wl_channel_to_frequency(sta_channel, sta_acs_band);
6404 list->element[0] =
6405 wl_freq_to_chanspec(freq);
6406 ANDROID_INFO(("Softap on same band as STA."
6407 "Use SCC. chanspec:0x%x\n", chanspec));
6408 } else {
6409 list->element[0] = chanspec;
6410 ANDROID_INFO(("RSDB case chanspec:0x%x\n", chanspec));
6411 }
6412 list->count = 1;
6413 return ret;
6414 }
6415 return ret;
6416 }
6417
6418 s32
wl_android_get_band_chanspecs(struct net_device * ndev,void * buf,s32 buflen,chanspec_band_t band,bool acs_req)6419 wl_android_get_band_chanspecs(struct net_device *ndev, void *buf, s32 buflen,
6420 chanspec_band_t band, bool acs_req)
6421 {
6422 u32 channel = 0;
6423 s32 ret = BCME_ERROR;
6424 s32 i = 0;
6425 s32 j = 0;
6426 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6427 wl_uint32_list_t *list = NULL;
6428 chanspec_t chanspec = 0;
6429
6430 if (band != 0xff) {
6431 chanspec |= (band | WL_CHANSPEC_BW_20 |
6432 WL_CHANSPEC_CTL_SB_NONE);
6433 chanspec = wl_chspec_host_to_driver(chanspec);
6434 }
6435
6436 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
6437 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
6438 if (ret < 0) {
6439 ANDROID_ERROR(("get 'chanspecs' failed, error = %d\n", ret));
6440 goto done;
6441 }
6442
6443 list = (wl_uint32_list_t *)buf;
6444 /* Skip DFS and inavlid P2P channel. */
6445 for (i = 0, j = 0; i < dtoh32(list->count); i++) {
6446 if (!CHSPEC_IS20(list->element[i])) {
6447 continue;
6448 }
6449 chanspec = (chanspec_t) dtoh32(list->element[i]);
6450 channel = chanspec | WL_CHANSPEC_BW_20;
6451 channel = wl_chspec_host_to_driver(channel);
6452
6453 ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
6454 if (ret < 0) {
6455 ANDROID_ERROR(("get 'per_chan_info' failed, error = %d\n", ret));
6456 goto done;
6457 }
6458
6459 if (CHSPEC_IS5G(chanspec) && (CHANNEL_IS_RADAR(channel) ||
6460 #ifndef ALLOW_5G_ACS
6461 ((acs_req == true) && (CHSPEC_CHANNEL(chanspec) != APCS_DEFAULT_5G_CH)) ||
6462 #endif /* !ALLOW_5G_ACS */
6463 (0))) {
6464 continue;
6465 } else if (!(CHSPEC_IS2G(chanspec) || CHSPEC_IS5G(chanspec)) &&
6466 !(CHSPEC_IS_6G_PSC(chanspec))) {
6467 continue;
6468 }
6469 else {
6470 list->element[j] = list->element[i];
6471 ANDROID_INFO(("Adding chanspec in list : %x\n", list->element[j]));
6472 }
6473
6474 j++;
6475 }
6476
6477 list->count = j;
6478
6479 done:
6480 return ret;
6481 }
6482
6483 static s32
wl_android_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)6484 wl_android_get_best_channel(struct net_device *ndev, void *buf, int buflen,
6485 int *channel)
6486 {
6487 s32 ret = BCME_ERROR;
6488 int chosen = 0;
6489 int retry = 0;
6490
6491 /* Start auto channel selection scan. */
6492 ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0);
6493 if (ret < 0) {
6494 ANDROID_ERROR(("can't start auto channel scan, error = %d\n", ret));
6495 *channel = 0;
6496 goto done;
6497 }
6498
6499 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
6500 retry = CHAN_SEL_RETRY_COUNT;
6501
6502 while (retry--) {
6503 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
6504 chosen = 0;
6505 ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6506 if ((ret == 0) && (dtoh32(chosen) != 0)) {
6507 *channel = (u16)(chosen & 0x00FF);
6508 ANDROID_INFO(("selected channel = %d\n", *channel));
6509 break;
6510 }
6511 ANDROID_INFO(("attempt = %d, ret = %d, chosen = %d\n",
6512 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
6513 }
6514
6515 if (retry <= 0) {
6516 ANDROID_ERROR(("failure, auto channel selection timed out\n"));
6517 *channel = 0;
6518 ret = BCME_ERROR;
6519 }
6520
6521 done:
6522 return ret;
6523 }
6524
6525 static s32
wl_android_restore_auto_channel_scan_state(struct net_device * ndev)6526 wl_android_restore_auto_channel_scan_state(struct net_device *ndev)
6527 {
6528 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6529 /* Clear scan stop driver status. */
6530 wl_clr_drv_status(cfg, SCANNING, ndev);
6531
6532 return BCME_OK;
6533 }
6534
6535 s32
wl_android_get_best_channels(struct net_device * dev,char * cmd,int total_len)6536 wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len)
6537 {
6538 int channel = 0;
6539 s32 ret = BCME_ERROR;
6540 u8 *buf = NULL;
6541 char *pos = cmd;
6542 struct bcm_cfg80211 *cfg = NULL;
6543 struct net_device *ndev = NULL;
6544
6545 bzero(cmd, total_len);
6546 cfg = wl_get_cfg(dev);
6547
6548 buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
6549 if (buf == NULL) {
6550 ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6551 return -ENOMEM;
6552 }
6553
6554 /*
6555 * Always use primary interface, irrespective of interface on which
6556 * command came.
6557 */
6558 ndev = bcmcfg_to_prmry_ndev(cfg);
6559
6560 /*
6561 * Make sure that FW and driver are in right state to do auto channel
6562 * selection scan.
6563 */
6564 ret = wl_android_set_auto_channel_scan_state(ndev);
6565 if (ret < 0) {
6566 ANDROID_ERROR(("can't set auto channel scan state, error = %d\n", ret));
6567 goto done;
6568 }
6569
6570 /* Best channel selection in 2.4GHz band. */
6571 ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6572 WL_CHANSPEC_BAND_2G, false);
6573 if (ret < 0) {
6574 ANDROID_ERROR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
6575 goto done;
6576 }
6577
6578 ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6579 &channel);
6580 if (ret < 0) {
6581 ANDROID_ERROR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
6582 goto done;
6583 }
6584
6585 if (CHANNEL_IS_2G(channel)) {
6586 channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
6587 } else {
6588 ANDROID_ERROR(("invalid 2.4GHz channel, channel = %d\n", channel));
6589 channel = 0;
6590 }
6591
6592 pos += snprintf(pos, total_len, "%04d ", channel);
6593
6594 /* Best channel selection in 5GHz band. */
6595 ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6596 WL_CHANSPEC_BAND_5G, false);
6597 if (ret < 0) {
6598 ANDROID_ERROR(("can't get chanspecs in 5GHz, error = %d\n", ret));
6599 goto done;
6600 }
6601
6602 ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6603 &channel);
6604 if (ret < 0) {
6605 ANDROID_ERROR(("can't select best channel scan in 5GHz, error = %d\n", ret));
6606 goto done;
6607 }
6608
6609 if (CHANNEL_IS_5G(channel)) {
6610 channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
6611 } else {
6612 ANDROID_ERROR(("invalid 5GHz channel, channel = %d\n", channel));
6613 channel = 0;
6614 }
6615
6616 pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6617
6618 /* Set overall best channel same as 5GHz best channel. */
6619 pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6620
6621 done:
6622 if (NULL != buf) {
6623 MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
6624 }
6625
6626 /* Restore FW and driver back to normal state. */
6627 ret = wl_android_restore_auto_channel_scan_state(ndev);
6628 if (ret < 0) {
6629 ANDROID_ERROR(("can't restore auto channel scan state, error = %d\n", ret));
6630 }
6631
6632 return (pos - cmd);
6633 }
6634
6635 int
wl_android_set_spect(struct net_device * dev,int spect)6636 wl_android_set_spect(struct net_device *dev, int spect)
6637 {
6638 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6639 int wlc_down = 1;
6640 int wlc_up = 1;
6641 int err = BCME_OK;
6642
6643 if (!wl_get_drv_status_all(cfg, CONNECTED)) {
6644 err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
6645 if (err) {
6646 ANDROID_ERROR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
6647 return err;
6648 }
6649
6650 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
6651 if (err) {
6652 ANDROID_ERROR(("%s: error setting spect: code: %d\n", __func__, err));
6653 return err;
6654 }
6655
6656 err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
6657 if (err) {
6658 ANDROID_ERROR(("%s: WLC_UP failed: code: %d\n", __func__, err));
6659 return err;
6660 }
6661 }
6662 return err;
6663 }
6664
6665 static int
wl_android_get_sta_channel(struct bcm_cfg80211 * cfg)6666 wl_android_get_sta_channel(struct bcm_cfg80211 *cfg)
6667 {
6668 chanspec_t *sta_chanspec = NULL;
6669 u32 channel = 0;
6670
6671 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
6672 if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
6673 bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) {
6674 channel = wf_chspec_ctlchan(*sta_chanspec);
6675 }
6676 }
6677 return channel;
6678 }
6679
6680 static int
wl_cfg80211_get_acs_band(int band)6681 wl_cfg80211_get_acs_band(int band)
6682 {
6683 chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6684 switch (band) {
6685 case WLC_BAND_AUTO:
6686 ANDROID_INFO(("ACS full channel scan \n"));
6687 /* Restricting band to 2G in case of hw_mode any */
6688 acs_band = WL_CHANSPEC_BAND_2G;
6689 break;
6690 #ifdef WL_6G_BAND
6691 case WLC_BAND_6G:
6692 ANDROID_INFO(("ACS 6G band scan \n"));
6693 acs_band = WL_CHANSPEC_BAND_6G;
6694 break;
6695 #endif /* WL_6G_BAND */
6696 case WLC_BAND_5G:
6697 ANDROID_INFO(("ACS 5G band scan \n"));
6698 acs_band = WL_CHANSPEC_BAND_5G;
6699 break;
6700 case WLC_BAND_2G:
6701 /*
6702 * If channel argument is not provided/ argument 20 is provided,
6703 * Restrict channel to 2GHz, 20MHz BW, No SB
6704 */
6705 ANDROID_INFO(("ACS 2G band scan \n"));
6706 acs_band = WL_CHANSPEC_BAND_2G;
6707 break;
6708 default:
6709 ANDROID_ERROR(("ACS: No band chosen\n"));
6710 break;
6711 }
6712 ANDROID_INFO(("%s: ACS: band = %d, acs_band = 0x%x\n", __FUNCTION__, band, acs_band));
6713 return acs_band;
6714 }
6715
6716 /* SoftAP feature */
6717 static int
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)6718 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
6719 char* command, int total_len)
6720 {
6721 int channel = 0, sta_channel = 0;
6722 int chosen = 0;
6723 int retry = 0;
6724 int ret = 0;
6725 int spect = 0;
6726 u8 *reqbuf = NULL;
6727 uint32 band = WLC_BAND_INVALID, sta_band = WLC_BAND_INVALID;
6728 chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6729 uint32 buf_size;
6730 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6731 bool acs_freq_list_present = false;
6732 char *pcmd;
6733 int freq = 0;
6734
6735 if (cmd_str) {
6736 ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
6737 pcmd = bcmstrstr(cmd_str, FREQ_STR);
6738 if (pcmd) {
6739 acs_freq_list_present = true;
6740 ANDROID_INFO(("ACS has freq list\n"));
6741 } else if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
6742 band = WLC_BAND_AUTO;
6743 #ifdef WL_6G_BAND
6744 } else if (strnicmp(cmd_str, APCS_BAND_6G, strlen(APCS_BAND_6G)) == 0) {
6745 band = WLC_BAND_6G;
6746 #endif /* WL_6G_BAND */
6747 } else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
6748 band = WLC_BAND_5G;
6749 } else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
6750 band = WLC_BAND_2G;
6751 } else {
6752 /*
6753 * For backward compatibility: Some platforms used to issue argument 20 or 0
6754 * to enforce the 2G channel selection
6755 */
6756 channel = bcm_atoi(cmd_str);
6757 if ((channel == APCS_BAND_2G_LEGACY1) ||
6758 (channel == APCS_BAND_2G_LEGACY2)) {
6759 band = WLC_BAND_2G;
6760 } else {
6761 ANDROID_ERROR(("Invalid argument\n"));
6762 return -EINVAL;
6763 }
6764 }
6765 } else {
6766 /* If no argument is provided, default to 2G */
6767 ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
6768 band = WLC_BAND_2G;
6769 }
6770 ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
6771
6772 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6773 wl_cfg80211_register_dev_ril_bridge_event_notifier();
6774 if (band == WLC_BAND_2G) {
6775 wl_cfg80211_send_msg_to_ril();
6776
6777 if (g_mhs_chan_for_cpcoex) {
6778 channel = g_mhs_chan_for_cpcoex;
6779 g_mhs_chan_for_cpcoex = 0;
6780 goto done2;
6781 }
6782 }
6783 wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
6784 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6785
6786 /* If STA is connected, return is STA channel, else ACS can be issued,
6787 * set spect to 0 and proceed with ACS
6788 */
6789 sta_channel = wl_android_get_sta_channel(cfg);
6790 sta_band = WL_GET_BAND(sta_channel);
6791 if (sta_channel && (band != WLC_BAND_INVALID)) {
6792 switch (sta_band) {
6793 case (WLC_BAND_5G):
6794 #ifdef WL_6G_BAND
6795 case (WLC_BAND_6G):
6796 #endif /* WL_6G_BAND */
6797 {
6798 if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
6799 channel = APCS_DEFAULT_2G_CH;
6800 }
6801 break;
6802 }
6803 case (WLC_BAND_2G): {
6804 if (band == WLC_BAND_5G) {
6805 channel = APCS_DEFAULT_5G_CH;
6806 }
6807 #ifdef WL_6G_BAND
6808 else if (band == WLC_BAND_6G) {
6809 channel = APCS_DEFAULT_6G_CH;
6810 }
6811 #endif /* WL_6G_BAND */
6812 break;
6813 }
6814 default:
6815 /* Intentional fall through to use same sta channel for softap */
6816 channel = sta_channel;
6817 break;
6818 }
6819 WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel);
6820 goto done2;
6821 }
6822
6823 /* If AP is started on wlan0 iface,
6824 * do not issue any iovar to fw and choose default ACS channel for softap
6825 */
6826 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6827 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
6828 ANDROID_INFO(("Softap started on primary iface\n"));
6829 goto done;
6830 }
6831 }
6832
6833 channel = wl_ext_autochannel(dev, ACS_DRV_BIT, band);
6834 if (channel) {
6835 acs_band = CHSPEC_BAND(channel);
6836 goto done2;
6837 } else
6838 goto done;
6839
6840 ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
6841 if (ret) {
6842 ANDROID_ERROR(("ACS: error getting the spect, ret=%d\n", ret));
6843 goto done;
6844 }
6845
6846 if (spect > 0) {
6847 ret = wl_android_set_spect(dev, 0);
6848 if (ret < 0) {
6849 ANDROID_ERROR(("ACS: error while setting spect, ret=%d\n", ret));
6850 goto done;
6851 }
6852 }
6853
6854 reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
6855 if (reqbuf == NULL) {
6856 ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6857 return -ENOMEM;
6858 }
6859
6860 if (acs_freq_list_present) {
6861 wl_uint32_list_t *list = NULL;
6862 bzero(reqbuf, sizeof(*reqbuf));
6863 list = (wl_uint32_list_t *)reqbuf;
6864
6865 ret = wl_android_get_freq_list_chanspecs(dev, list, CHANSPEC_BUF_SIZE,
6866 cmd_str, sta_channel, wl_cfg80211_get_acs_band(sta_band));
6867 if (ret < 0) {
6868 ANDROID_ERROR(("ACS chanspec set failed!\n"));
6869 goto done;
6870 }
6871
6872 /* skip ACS for single channel case */
6873 if (list->count == 1) {
6874 cfg->acs_chspec = (chanspec_t)list->element[0];
6875 channel = wf_chspec_ctlchan((chanspec_t)list->element[0]);
6876 acs_band = CHSPEC_BAND((chanspec_t)list->element[0]);
6877 goto done2;
6878 }
6879 } else {
6880 acs_band = wl_cfg80211_get_acs_band(band);
6881 if (acs_band == WLC_ACS_BAND_INVALID) {
6882 ANDROID_ERROR(("ACS: No band chosen\n"));
6883 goto done2;
6884 }
6885
6886 if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE,
6887 acs_band, true)) < 0) {
6888 ANDROID_ERROR(("ACS chanspec retrieval failed! \n"));
6889 goto done;
6890 }
6891 }
6892
6893 buf_size = CHANSPEC_BUF_SIZE;
6894 ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
6895 buf_size);
6896 if (ret < 0) {
6897 ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
6898 channel = 0;
6899 goto done;
6900 }
6901
6902 /* Wait for auto channel selection, max 3000 ms */
6903 if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) {
6904 OSL_SLEEP(500);
6905 } else {
6906 /*
6907 * Full channel scan at the minimum takes 1.2secs
6908 * even with parallel scan. max wait time: 3500ms
6909 */
6910 OSL_SLEEP(1000);
6911 }
6912
6913 retry = APCS_MAX_RETRY;
6914 while (retry--) {
6915 ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
6916 sizeof(chosen));
6917 if (ret < 0) {
6918 chosen = 0;
6919 } else {
6920 chosen = dtoh32(chosen);
6921 }
6922
6923 if (chosen) {
6924 /* Update chanspec which can be used during softAP bringup with right BW */
6925 cfg->acs_chspec = chosen;
6926 channel = wf_chspec_ctlchan(chosen);
6927 acs_band = CHSPEC_BAND(chosen);
6928 break;
6929 }
6930 ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x, acs_band = 0x%x\n",
6931 (APCS_MAX_RETRY - retry), ret, chosen, acs_band));
6932 OSL_SLEEP(250);
6933 }
6934
6935 done:
6936 if ((retry == 0) || (ret < 0)) {
6937 /* On failure, fallback to a default channel */
6938 if (band == WLC_BAND_5G) {
6939 channel = APCS_DEFAULT_5G_CH;
6940 #ifdef WL_6G_BAND
6941 } else if (band == WLC_BAND_6G) {
6942 channel = APCS_DEFAULT_6G_CH;
6943 #endif /* WL_6G_BAND */
6944 } else {
6945 channel = APCS_DEFAULT_2G_CH;
6946 }
6947 ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel));
6948 }
6949 done2:
6950 if (spect > 0) {
6951 if ((ret = wl_android_set_spect(dev, spect) < 0)) {
6952 ANDROID_ERROR(("ACS: error while setting spect\n"));
6953 }
6954 }
6955
6956 if (reqbuf) {
6957 MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
6958 }
6959
6960 ANDROID_INFO(("ACS: Channel = %d, acs_band = 0x%x\n", channel, acs_band));
6961 if (channel && (acs_band != WLC_ACS_BAND_INVALID)) {
6962 freq = wl_channel_to_frequency(channel, acs_band);
6963 if (!freq) {
6964 ANDROID_ERROR(("ACS: Invalid freq\n"));
6965 return BCME_ERROR;
6966 }
6967 ret = snprintf(command, total_len, "%d freq=%d", channel, freq);
6968 ANDROID_INFO(("command result is %s \n", command));
6969 }
6970
6971 return ret;
6972 }
6973 #endif /* WL_SUPPORT_AUTO_CHANNEL */
6974
6975 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6976 static int
wl_android_set_roam_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)6977 wl_android_set_roam_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
6978 {
6979 s32 err = BCME_OK;
6980 u32 roam_vsie_enable = 0;
6981 u32 cmd_str_len = (u32)strlen(CMD_ROAM_VSIE_ENAB_SET);
6982 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6983
6984 /* <CMD><SPACE><VAL> */
6985 if (!cmd || (cmd_len < (cmd_str_len + 1))) {
6986 ANDROID_ERROR(("wrong arg\n"));
6987 err = -EINVAL;
6988 goto exit;
6989 }
6990
6991 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6992 ANDROID_ERROR(("config not supported on non primary i/f\n"));
6993 err = -ENODEV;
6994 goto exit;
6995 }
6996
6997 roam_vsie_enable = cmd[(cmd_str_len + 1)] - '0';
6998 if (roam_vsie_enable > 1) {
6999 roam_vsie_enable = 1;
7000 }
7001
7002 WL_DBG_MEM(("set roam vsie %d\n", roam_vsie_enable));
7003 err = wldev_iovar_setint(dev, "roam_vsie", roam_vsie_enable);
7004 if (unlikely(err)) {
7005 ANDROID_ERROR(("set roam vsie enable failed. ret:%d\n", err));
7006 }
7007
7008 exit:
7009 return err;
7010 }
7011
7012 static int
wl_android_get_roam_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7013 wl_android_get_roam_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7014 {
7015 s32 err = BCME_OK;
7016 u32 roam_vsie_enable = 0;
7017 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7018 int bytes_written;
7019
7020 /* <CMD> */
7021 if (!cmd) {
7022 ANDROID_ERROR(("wrong arg\n"));
7023 return -1;
7024 }
7025
7026 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7027 ANDROID_ERROR(("config not supported on non primary i/f\n"));
7028 return -1;
7029 }
7030
7031 err = wldev_iovar_getint(dev, "roam_vsie", &roam_vsie_enable);
7032 if (unlikely(err)) {
7033 ANDROID_ERROR(("get roam vsie enable failed. ret:%d\n", err));
7034 return -1;
7035 }
7036 ANDROID_INFO(("get roam vsie %d\n", roam_vsie_enable));
7037
7038 bytes_written = snprintf(cmd, cmd_len, "%s %d",
7039 CMD_ROAM_VSIE_ENAB_GET, roam_vsie_enable);
7040
7041 return bytes_written;
7042 }
7043
7044 static int
wl_android_set_bcn_rpt_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)7045 wl_android_set_bcn_rpt_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
7046 {
7047 s32 err;
7048 u32 bcn_vsie_enable = 0;
7049 u32 cmd_str_len = (u32)strlen(CMD_BR_VSIE_ENAB_SET);
7050 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7051
7052 /* <CMD><SPACE><VAL> */
7053 if (!cmd || (cmd_len < (cmd_str_len + 1))) {
7054 ANDROID_ERROR(("invalid arg\n"));
7055 err = -EINVAL;
7056 goto exit;
7057 }
7058
7059 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7060 ANDROID_ERROR(("config not supported on non primary i/f\n"));
7061 err = -ENODEV;
7062 goto exit;
7063 }
7064
7065 bcn_vsie_enable = cmd[cmd_str_len + 1] - '0';
7066 if (bcn_vsie_enable > 1) {
7067 bcn_vsie_enable = 1;
7068 }
7069
7070 WL_DBG_MEM(("set bcn report vsie %d\n", bcn_vsie_enable));
7071 err = wldev_iovar_setint(dev, "bcnrpt_vsie_en", bcn_vsie_enable);
7072 if (unlikely(err)) {
7073 ANDROID_ERROR(("set bcn vsie failed. ret:%d\n", err));
7074 }
7075
7076 exit:
7077 return err;
7078 }
7079
7080 static int
wl_android_get_bcn_rpt_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7081 wl_android_get_bcn_rpt_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7082 {
7083 s32 err = BCME_OK;
7084 u32 bcn_vsie_enable = 0;
7085 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7086 int bytes_written;
7087
7088 /* <CMD> */
7089 if (!cmd) {
7090 ANDROID_ERROR(("wrong arg\n"));
7091 return -1;
7092 }
7093
7094 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7095 ANDROID_ERROR(("config not supported on non primary i/f\n"));
7096 return -1;
7097 }
7098
7099 err = wldev_iovar_getint(dev, "bcnrpt_vsie_en", &bcn_vsie_enable);
7100 if (unlikely(err)) {
7101 ANDROID_ERROR(("get bcn vsie failed. ret:%d\n", err));
7102 return -1;
7103 }
7104 ANDROID_INFO(("get bcn report vsie %d\n", bcn_vsie_enable));
7105
7106 bytes_written = snprintf(cmd, cmd_len, "%s %d",
7107 CMD_BR_VSIE_ENAB_GET, bcn_vsie_enable);
7108
7109 return bytes_written;
7110 }
7111
7112 #ifdef SUPPORT_HIDDEN_AP
7113 static int
wl_android_set_max_num_sta(struct net_device * dev,const char * string_num)7114 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
7115 {
7116 int err = BCME_ERROR;
7117 int max_assoc;
7118
7119 max_assoc = bcm_atoi(string_num);
7120 ANDROID_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc));
7121
7122 err = wldev_iovar_setint(dev, "maxassoc", max_assoc);
7123 if (err < 0) {
7124 ANDROID_ERROR(("failed to set maxassoc, error:%d\n", err));
7125 }
7126
7127 return err;
7128 }
7129
7130 static int
wl_android_set_ssid(struct net_device * dev,const char * hapd_ssid)7131 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
7132 {
7133 wlc_ssid_t ssid;
7134 s32 ret;
7135
7136 ssid.SSID_len = strlen(hapd_ssid);
7137 if (ssid.SSID_len == 0) {
7138 ANDROID_ERROR(("wl_android_set_ssids : No SSID\n"));
7139 return -1;
7140 }
7141 if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
7142 ssid.SSID_len = DOT11_MAX_SSID_LEN;
7143 ANDROID_ERROR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid)));
7144 }
7145 bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
7146 ANDROID_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID));
7147 ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
7148 if (ret < 0) {
7149 ANDROID_ERROR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret));
7150 }
7151 return 1;
7152
7153 }
7154
7155 static int
wl_android_set_hide_ssid(struct net_device * dev,const char * string_num)7156 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
7157 {
7158 int hide_ssid;
7159 int enable = 0;
7160 int err = BCME_ERROR;
7161
7162 hide_ssid = bcm_atoi(string_num);
7163 ANDROID_INFO(("wl_android_set_hide_ssid: HAPD_HIDE_SSID = %d\n", hide_ssid));
7164 if (hide_ssid) {
7165 enable = 1;
7166 }
7167
7168 err = wldev_iovar_setint(dev, "closednet", enable);
7169 if (err < 0) {
7170 ANDROID_ERROR(("failed to set closednet, error:%d\n", err));
7171 }
7172
7173 return err;
7174 }
7175 #endif /* SUPPORT_HIDDEN_AP */
7176
7177 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
7178 static int
wl_android_sta_diassoc(struct net_device * dev,const char * straddr)7179 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
7180 {
7181 scb_val_t scbval;
7182 int error = 0;
7183
7184 ANDROID_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr));
7185
7186 /* Unspecified reason */
7187 scbval.val = htod32(1);
7188
7189 if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
7190 ANDROID_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n"));
7191 return -1;
7192 }
7193
7194 ANDROID_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n",
7195 MAC2STRDBG(scbval.ea.octet), scbval.val));
7196
7197 error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
7198 sizeof(scb_val_t));
7199 if (error) {
7200 ANDROID_ERROR(("Fail to DEAUTH station, error = %d\n", error));
7201 }
7202
7203 return 1;
7204 }
7205 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
7206
7207 #ifdef SUPPORT_SET_LPC
7208 static int
wl_android_set_lpc(struct net_device * dev,const char * string_num)7209 wl_android_set_lpc(struct net_device *dev, const char* string_num)
7210 {
7211 int lpc_enabled, ret;
7212 s32 val = 1;
7213
7214 lpc_enabled = bcm_atoi(string_num);
7215 ANDROID_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled));
7216
7217 ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
7218 if (ret < 0)
7219 ANDROID_ERROR(("WLC_DOWN error %d\n", ret));
7220
7221 wldev_iovar_setint(dev, "lpc", lpc_enabled);
7222
7223 ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
7224 if (ret < 0)
7225 ANDROID_ERROR(("WLC_UP error %d\n", ret));
7226
7227 return 1;
7228 }
7229 #endif /* SUPPORT_SET_LPC */
7230
7231 static int
wl_android_ch_res_rl(struct net_device * dev,bool change)7232 wl_android_ch_res_rl(struct net_device *dev, bool change)
7233 {
7234 int error = 0;
7235 s32 srl = 7;
7236 s32 lrl = 4;
7237 ANDROID_ERROR(("wl_android_ch_res_rl: enter\n"));
7238 if (change) {
7239 srl = 4;
7240 lrl = 2;
7241 }
7242
7243 BCM_REFERENCE(lrl);
7244
7245 error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
7246 if (error) {
7247 ANDROID_ERROR(("Failed to set SRL, error = %d\n", error));
7248 }
7249 #ifndef CUSTOM_LONG_RETRY_LIMIT
7250 error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
7251 if (error) {
7252 ANDROID_ERROR(("Failed to set LRL, error = %d\n", error));
7253 }
7254 #endif /* CUSTOM_LONG_RETRY_LIMIT */
7255 return error;
7256 }
7257
7258 #ifdef SUPPORT_LTECX
7259 #define DEFAULT_WLANRX_PROT 1
7260 #define DEFAULT_LTERX_PROT 0
7261 #define DEFAULT_LTETX_ADV 1200
7262
7263 static int
wl_android_set_ltecx(struct net_device * dev,const char * string_num)7264 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
7265 {
7266 uint16 chan_bitmap;
7267 int ret;
7268
7269 chan_bitmap = bcm_strtoul(string_num, NULL, 16);
7270
7271 ANDROID_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap));
7272
7273 if (chan_bitmap) {
7274 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7275 if (ret < 0) {
7276 ANDROID_ERROR(("mws_coex_bitmap error %d\n", ret));
7277 }
7278
7279 ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
7280 if (ret < 0) {
7281 ANDROID_ERROR(("mws_wlanrx_prot error %d\n", ret));
7282 }
7283
7284 ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
7285 if (ret < 0) {
7286 ANDROID_ERROR(("mws_lterx_prot error %d\n", ret));
7287 }
7288
7289 ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
7290 if (ret < 0) {
7291 ANDROID_ERROR(("mws_ltetx_adv error %d\n", ret));
7292 }
7293 } else {
7294 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7295 if (ret < 0) {
7296 if (ret == BCME_UNSUPPORTED) {
7297 ANDROID_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
7298 } else {
7299 ANDROID_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
7300 }
7301 }
7302 }
7303 return 1;
7304 }
7305 #endif /* SUPPORT_LTECX */
7306
7307 #ifdef WL_RELMCAST
7308 static int
wl_android_rmc_enable(struct net_device * net,int rmc_enable)7309 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
7310 {
7311 int err;
7312
7313 err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
7314 if (err != BCME_OK) {
7315 ANDROID_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err));
7316 }
7317 return err;
7318 }
7319
7320 static int
wl_android_rmc_set_leader(struct net_device * dev,const char * straddr)7321 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
7322 {
7323 int error = BCME_OK;
7324 char smbuf[WLC_IOCTL_SMLEN];
7325 wl_rmc_entry_t rmc_entry;
7326 ANDROID_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr));
7327
7328 bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7329 if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
7330 if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
7331 ANDROID_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n"));
7332 bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7333 } else {
7334 ANDROID_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n"));
7335 return BCME_ERROR;
7336 }
7337 }
7338
7339 error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
7340 smbuf, sizeof(smbuf), NULL);
7341
7342 if (error != BCME_OK) {
7343 ANDROID_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n",
7344 error));
7345 }
7346
7347 return error;
7348 }
7349
wl_android_set_rmc_event(struct net_device * dev,char * command)7350 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
7351 {
7352 int err = 0;
7353 int pid = 0;
7354
7355 if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
7356 ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
7357 return -1;
7358 }
7359
7360 /* set pid, and if the event was happened, let's send a notification through netlink */
7361 wl_cfg80211_set_rmc_pid(dev, pid);
7362
7363 ANDROID_INFO(("RMC pid=%d\n", pid));
7364
7365 return err;
7366 }
7367 #endif /* WL_RELMCAST */
7368
wl_android_get_singlecore_scan(struct net_device * dev,char * command,int total_len)7369 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
7370 {
7371 int error = 0;
7372 int bytes_written = 0;
7373 int mode = 0;
7374
7375 error = wldev_iovar_getint(dev, "scan_ps", &mode);
7376 if (error) {
7377 ANDROID_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode,"
7378 " error = %d\n",
7379 error));
7380 return -1;
7381 }
7382
7383 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
7384
7385 return bytes_written;
7386 }
7387
wl_android_set_singlecore_scan(struct net_device * dev,char * command)7388 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
7389 {
7390 int error = 0;
7391 int mode = 0;
7392
7393 if (sscanf(command, "%*s %d", &mode) != 1) {
7394 ANDROID_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n"));
7395 return -1;
7396 }
7397
7398 error = wldev_iovar_setint(dev, "scan_ps", mode);
7399 if (error) {
7400 ANDROID_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n",
7401 mode, error));
7402 return -1;
7403 }
7404
7405 return error;
7406 }
7407 #ifdef TEST_TX_POWER_CONTROL
7408 static int
wl_android_set_tx_power(struct net_device * dev,const char * string_num)7409 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
7410 {
7411 int err = 0;
7412 s32 dbm;
7413 enum nl80211_tx_power_setting type;
7414
7415 dbm = bcm_atoi(string_num);
7416
7417 if (dbm < -1) {
7418 ANDROID_ERROR(("wl_android_set_tx_power: dbm is negative...\n"));
7419 return -EINVAL;
7420 }
7421
7422 if (dbm == -1)
7423 type = NL80211_TX_POWER_AUTOMATIC;
7424 else
7425 type = NL80211_TX_POWER_FIXED;
7426
7427 err = wl_set_tx_power(dev, type, dbm);
7428 if (unlikely(err)) {
7429 ANDROID_ERROR(("wl_android_set_tx_power: error (%d)\n", err));
7430 return err;
7431 }
7432
7433 return 1;
7434 }
7435
7436 static int
wl_android_get_tx_power(struct net_device * dev,char * command,int total_len)7437 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
7438 {
7439 int err;
7440 int bytes_written;
7441 s32 dbm = 0;
7442
7443 err = wl_get_tx_power(dev, &dbm);
7444 if (unlikely(err)) {
7445 ANDROID_ERROR(("wl_android_get_tx_power: error (%d)\n", err));
7446 return err;
7447 }
7448
7449 bytes_written = snprintf(command, total_len, "%s %d",
7450 CMD_TEST_GET_TX_POWER, dbm);
7451
7452 ANDROID_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm));
7453
7454 return bytes_written;
7455 }
7456 #endif /* TEST_TX_POWER_CONTROL */
7457
7458 static int
wl_android_set_sarlimit_txctrl(struct net_device * dev,const char * string_num)7459 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
7460 {
7461 int err = BCME_ERROR;
7462 int setval = 0;
7463 s32 mode = bcm_atoi(string_num);
7464 s32 mode_bit = 0;
7465 int enab = 0;
7466
7467 /* As Samsung specific and their requirement,
7468 * the mode set as the following form.
7469 * -1 : HEAD SAR disabled
7470 * 0 : HEAD SAR enabled
7471 * 1 : GRIP SAR disabled
7472 * 2 : GRIP SAR enabled
7473 * 3 : NR mmWave SAR disabled
7474 * 4 : NR mmWave SAR enabled
7475 * 5 : NR Sub6 SAR disabled
7476 * 6 : NR Sub6 SAR enabled
7477 * 7 : SAR BACKOFF disabled all
7478 * The 'SAR BACKOFF disabled all' index should be the end of the mode.
7479 */
7480 if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) {
7481 ANDROID_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num)));
7482 err = BCME_RANGE;
7483 goto error;
7484 }
7485
7486 mode_bit = mode + 1;
7487 enab = mode_bit % 2;
7488 mode_bit = mode_bit / 2;
7489
7490 err = wldev_iovar_getint(dev, "sar_enable", &setval);
7491 if (unlikely(err)) {
7492 ANDROID_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err));
7493 goto error;
7494 }
7495
7496 if (mode == SAR_BACKOFF_DISABLE_ALL) {
7497 ANDROID_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__));
7498 setval = 0;
7499 } else {
7500 ANDROID_ERROR(("%s: SAR limit control mode %d enab %d\n",
7501 __FUNCTION__, mode_bit, enab));
7502 if (enab) {
7503 setval |= (1 << mode_bit);
7504 } else {
7505 setval &= ~(1 << mode_bit);
7506 }
7507 }
7508
7509 err = wldev_iovar_setint(dev, "sar_enable", setval);
7510 if (unlikely(err)) {
7511 ANDROID_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
7512 goto error;
7513 }
7514 err = BCME_OK;
7515 error:
7516 return err;
7517 }
7518
7519 #ifdef SUPPORT_SET_TID
7520 static int
wl_android_set_tid(struct net_device * dev,char * command)7521 wl_android_set_tid(struct net_device *dev, char* command)
7522 {
7523 int err = BCME_ERROR;
7524 char *pos = command;
7525 char *token = NULL;
7526 uint8 mode = 0;
7527 uint32 uid = 0;
7528 uint8 prio = 0;
7529 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7530
7531 if (!dhdp) {
7532 ANDROID_ERROR(("dhd is NULL\n"));
7533 return err;
7534 }
7535
7536 ANDROID_INFO(("%s: command[%s]\n", __FUNCTION__, command));
7537
7538 /* drop command */
7539 token = bcmstrtok(&pos, " ", NULL);
7540
7541 token = bcmstrtok(&pos, " ", NULL);
7542 if (!token) {
7543 ANDROID_ERROR(("Invalid arguments\n"));
7544 return err;
7545 }
7546
7547 mode = bcm_atoi(token);
7548
7549 if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
7550 ANDROID_ERROR(("Invalid arguments, mode %d\n", mode));
7551 return err;
7552 }
7553
7554 if (mode) {
7555 token = bcmstrtok(&pos, " ", NULL);
7556 if (!token) {
7557 ANDROID_ERROR(("Invalid arguments for target uid\n"));
7558 return err;
7559 }
7560
7561 uid = bcm_atoi(token);
7562
7563 token = bcmstrtok(&pos, " ", NULL);
7564 if (!token) {
7565 ANDROID_ERROR(("Invalid arguments for target tid\n"));
7566 return err;
7567 }
7568
7569 prio = bcm_atoi(token);
7570 if (prio >= 0 && prio <= MAXPRIO) {
7571 dhdp->tid_mode = mode;
7572 dhdp->target_uid = uid;
7573 dhdp->target_tid = prio;
7574 } else {
7575 ANDROID_ERROR(("Invalid arguments, prio %d\n", prio));
7576 return err;
7577 }
7578 } else {
7579 dhdp->tid_mode = SET_TID_OFF;
7580 dhdp->target_uid = 0;
7581 dhdp->target_tid = 0;
7582 }
7583
7584 ANDROID_INFO(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
7585 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
7586
7587 err = BCME_OK;
7588 return err;
7589 }
7590
7591 static int
wl_android_get_tid(struct net_device * dev,char * command,int total_len)7592 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
7593 {
7594 int bytes_written = BCME_ERROR;
7595 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7596
7597 if (!dhdp) {
7598 ANDROID_ERROR(("dhd is NULL\n"));
7599 return bytes_written;
7600 }
7601
7602 bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
7603 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
7604
7605 ANDROID_INFO(("%s: command results %s\n", __FUNCTION__, command));
7606
7607 return bytes_written;
7608 }
7609 #endif /* SUPPORT_SET_TID */
7610 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7611
wl_android_set_roam_mode(struct net_device * dev,char * command)7612 int wl_android_set_roam_mode(struct net_device *dev, char *command)
7613 {
7614 int error = 0;
7615 int mode = 0;
7616
7617 if (sscanf(command, "%*s %d", &mode) != 1) {
7618 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7619 return -1;
7620 }
7621
7622 error = wldev_iovar_setint(dev, "roam_off", mode);
7623 if (error) {
7624 ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
7625 __FUNCTION__, mode, error));
7626 return -1;
7627 }
7628 else
7629 ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
7630 __FUNCTION__, mode, error));
7631 return 0;
7632 }
7633
7634 #ifdef WL_CFG80211
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)7635 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
7636 {
7637 char ie_buf[VNDR_IE_MAX_LEN];
7638 char *ioctl_buf = NULL;
7639 char hex[] = "XX";
7640 char *pcmd = NULL;
7641 int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
7642 vndr_ie_setbuf_t *vndr_ie = NULL;
7643 s32 iecount;
7644 uint32 pktflag;
7645 s32 err = BCME_OK, bssidx;
7646 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7647
7648 /* Check the VSIE (Vendor Specific IE) which was added.
7649 * If exist then send IOVAR to delete it
7650 */
7651 if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
7652 return -EINVAL;
7653 }
7654
7655 if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
7656 ANDROID_ERROR(("error. total_len:%d\n", total_len));
7657 return -EINVAL;
7658 }
7659
7660 pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
7661 for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
7662 if (*pcmd == '\0') {
7663 ANDROID_ERROR(("error while parsing OUI.\n"));
7664 return -EINVAL;
7665 }
7666 hex[0] = *pcmd++;
7667 hex[1] = *pcmd++;
7668 ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
7669 }
7670 pcmd++;
7671 while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
7672 hex[0] = *pcmd++;
7673 hex[1] = *pcmd++;
7674 ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
7675 datalen++;
7676 }
7677
7678 if (datalen <= 0) {
7679 ANDROID_ERROR(("error. vndr ie len:%d\n", datalen));
7680 return -EINVAL;
7681 }
7682
7683 tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
7684 vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
7685 if (!vndr_ie) {
7686 ANDROID_ERROR(("IE memory alloc failed\n"));
7687 return -ENOMEM;
7688 }
7689 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
7690 strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
7691
7692 /* Set the IE count - the buffer contains only 1 IE */
7693 iecount = htod32(1);
7694 memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
7695
7696 /* Set packet flag to indicate that BEACON's will contain this IE */
7697 pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
7698 memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
7699 sizeof(u32));
7700 /* Set the IE ID */
7701 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
7702
7703 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
7704 DOT11_OUI_LEN);
7705 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
7706 &ie_buf[DOT11_OUI_LEN], datalen);
7707
7708 ielen = DOT11_OUI_LEN + datalen;
7709 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
7710
7711 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
7712 if (!ioctl_buf) {
7713 ANDROID_ERROR(("ioctl memory alloc failed\n"));
7714 if (vndr_ie) {
7715 MFREE(cfg->osh, vndr_ie, tot_len);
7716 }
7717 return -ENOMEM;
7718 }
7719 bzero(ioctl_buf, WLC_IOCTL_MEDLEN); /* init the buffer */
7720 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7721 ANDROID_ERROR(("Find index failed\n"));
7722 err = BCME_ERROR;
7723 goto end;
7724 }
7725 err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
7726 WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
7727 end:
7728 if (err != BCME_OK) {
7729 err = -EINVAL;
7730 if (vndr_ie) {
7731 MFREE(cfg->osh, vndr_ie, tot_len);
7732 }
7733 }
7734 else {
7735 /* do NOT free 'vndr_ie' for the next process */
7736 wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
7737 }
7738
7739 if (ioctl_buf) {
7740 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
7741 }
7742
7743 return err;
7744 }
7745 #endif /* WL_CFG80211 */
7746
7747 #if defined(BCMFW_ROAM_ENABLE)
7748 static int
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)7749 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
7750 {
7751 int error = 0;
7752 char smbuf[WLC_IOCTL_SMLEN];
7753 uint8 buf[MAX_BUF_SIZE];
7754 uint8 *pref = buf;
7755 char *pcmd;
7756 int num_ucipher_suites = 0;
7757 int num_akm_suites = 0;
7758 wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
7759 wpa_suite_t akm_suites[MAX_NUM_SUITES];
7760 int num_tuples = 0;
7761 int total_bytes = 0;
7762 int total_len_left;
7763 int i, j;
7764 char hex[] = "XX";
7765
7766 pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
7767 total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
7768
7769 num_akm_suites = simple_strtoul(pcmd, NULL, 16);
7770 if (num_akm_suites > MAX_NUM_SUITES) {
7771 ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites));
7772 return -1;
7773 }
7774
7775 /* Increment for number of AKM suites field + space */
7776 pcmd += 3;
7777 total_len_left -= 3;
7778
7779 /* check to make sure pcmd does not overrun */
7780 if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
7781 return -1;
7782
7783 bzero(buf, sizeof(buf));
7784 bzero(akm_suites, sizeof(akm_suites));
7785 bzero(ucipher_suites, sizeof(ucipher_suites));
7786
7787 /* Save the AKM suites passed in the command */
7788 for (i = 0; i < num_akm_suites; i++) {
7789 /* Store the MSB first, as required by join_pref */
7790 for (j = 0; j < 4; j++) {
7791 hex[0] = *pcmd++;
7792 hex[1] = *pcmd++;
7793 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7794 }
7795 memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
7796 }
7797
7798 total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
7799 num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
7800 /* Increment for number of cipher suites field + space */
7801 pcmd += 3;
7802 total_len_left -= 3;
7803
7804 if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
7805 return -1;
7806
7807 /* Save the cipher suites passed in the command */
7808 for (i = 0; i < num_ucipher_suites; i++) {
7809 /* Store the MSB first, as required by join_pref */
7810 for (j = 0; j < 4; j++) {
7811 hex[0] = *pcmd++;
7812 hex[1] = *pcmd++;
7813 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7814 }
7815 memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
7816 }
7817
7818 /* Join preference for RSSI
7819 * Type : 1 byte (0x01)
7820 * Length : 1 byte (0x02)
7821 * Value : 2 bytes (reserved)
7822 */
7823 *pref++ = WL_JOIN_PREF_RSSI;
7824 *pref++ = JOIN_PREF_RSSI_LEN;
7825 *pref++ = 0;
7826 *pref++ = 0;
7827
7828 /* Join preference for WPA
7829 * Type : 1 byte (0x02)
7830 * Length : 1 byte (not used)
7831 * Value : (variable length)
7832 * reserved: 1 byte
7833 * count : 1 byte (no of tuples)
7834 * Tuple1 : 12 bytes
7835 * akm[4]
7836 * ucipher[4]
7837 * mcipher[4]
7838 * Tuple2 : 12 bytes
7839 * Tuplen : 12 bytes
7840 */
7841 num_tuples = num_akm_suites * num_ucipher_suites;
7842 if (num_tuples != 0) {
7843 if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
7844 *pref++ = WL_JOIN_PREF_WPA;
7845 *pref++ = 0;
7846 *pref++ = 0;
7847 *pref++ = (uint8)num_tuples;
7848 total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
7849 (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
7850 } else {
7851 ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
7852 return -1;
7853 }
7854 } else {
7855 /* No WPA config, configure only RSSI preference */
7856 total_bytes = JOIN_PREF_RSSI_SIZE;
7857 }
7858
7859 /* akm-ucipher-mcipher tuples in the format required for join_pref */
7860 for (i = 0; i < num_ucipher_suites; i++) {
7861 for (j = 0; j < num_akm_suites; j++) {
7862 memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
7863 pref += WPA_SUITE_LEN;
7864 memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
7865 pref += WPA_SUITE_LEN;
7866 /* Set to 0 to match any available multicast cipher */
7867 bzero(pref, WPA_SUITE_LEN);
7868 pref += WPA_SUITE_LEN;
7869 }
7870 }
7871
7872 prhex("join pref", (uint8 *)buf, total_bytes);
7873 error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
7874 if (error) {
7875 ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
7876 }
7877 return error;
7878 }
7879 #endif /* defined(BCMFW_ROAM_ENABLE */
7880
7881 #ifdef WL_CFG80211
7882 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)7883 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
7884 {
7885 struct io_cfg *resume_cfg;
7886 s32 ret;
7887 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7888
7889 resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
7890 if (!resume_cfg)
7891 return -ENOMEM;
7892
7893 if (config->iovar) {
7894 ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
7895 if (ret) {
7896 ANDROID_ERROR(("%s: Failed to get current %s value\n",
7897 __FUNCTION__, config->iovar));
7898 goto error;
7899 }
7900
7901 ret = wldev_iovar_setint(dev, config->iovar, config->param);
7902 if (ret) {
7903 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7904 config->iovar, config->param));
7905 goto error;
7906 }
7907
7908 resume_cfg->iovar = config->iovar;
7909 } else {
7910 resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
7911 if (!resume_cfg->arg) {
7912 ret = -ENOMEM;
7913 goto error;
7914 }
7915 ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
7916 if (ret) {
7917 ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
7918 config->ioctl));
7919 goto error;
7920 }
7921 ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
7922 if (ret) {
7923 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7924 config->iovar, config->param));
7925 goto error;
7926 }
7927 if (config->ioctl + 1 == WLC_SET_PM)
7928 wl_cfg80211_update_power_mode(dev);
7929 resume_cfg->ioctl = config->ioctl;
7930 resume_cfg->len = config->len;
7931 }
7932
7933 /* assuming only one active user and no list protection */
7934 list_add(&resume_cfg->list, head);
7935
7936 return 0;
7937 error:
7938 MFREE(cfg->osh, resume_cfg->arg, config->len);
7939 MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
7940 return ret;
7941 }
7942
7943 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)7944 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
7945 {
7946 struct io_cfg *config;
7947 struct list_head *cur, *q;
7948 s32 ret = 0;
7949 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7950 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7951 list_for_each_safe(cur, q, head) {
7952 config = list_entry(cur, struct io_cfg, list);
7953 GCC_DIAGNOSTIC_POP();
7954 if (config->iovar) {
7955 if (!ret)
7956 ret = wldev_iovar_setint(dev, config->iovar,
7957 config->param);
7958 } else {
7959 if (!ret)
7960 ret = wldev_ioctl_set(dev, config->ioctl + 1,
7961 config->arg, config->len);
7962 if (config->ioctl + 1 == WLC_SET_PM)
7963 wl_cfg80211_update_power_mode(dev);
7964 MFREE(cfg->osh, config->arg, config->len);
7965 }
7966 list_del(cur);
7967 MFREE(cfg->osh, config, sizeof(struct io_cfg));
7968 }
7969 }
7970
7971 static int
wl_android_set_miracast(struct net_device * dev,char * command)7972 wl_android_set_miracast(struct net_device *dev, char *command)
7973 {
7974 int mode, val = 0;
7975 int ret = 0;
7976 struct io_cfg config;
7977
7978 if (sscanf(command, "%*s %d", &mode) != 1) {
7979 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7980 return -1;
7981 }
7982
7983 ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
7984
7985 if (miracast_cur_mode == mode) {
7986 return 0;
7987 }
7988
7989 wl_android_iolist_resume(dev, &miracast_resume_list);
7990 miracast_cur_mode = MIRACAST_MODE_OFF;
7991
7992 bzero((void *)&config, sizeof(config));
7993 switch (mode) {
7994 case MIRACAST_MODE_SOURCE:
7995 #ifdef MIRACAST_MCHAN_ALGO
7996 /* setting mchan_algo to platform specific value */
7997 config.iovar = "mchan_algo";
7998
7999 /* check for station's beacon interval(BI)
8000 * If BI is over 100ms, don't use mchan_algo
8001 */
8002 ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
8003 if (!ret && val > 100) {
8004 config.param = 0;
8005 ANDROID_ERROR(("%s: Connected station's beacon interval: "
8006 "%d and set mchan_algo to %d \n",
8007 __FUNCTION__, val, config.param));
8008 } else {
8009 config.param = MIRACAST_MCHAN_ALGO;
8010 }
8011 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8012 if (ret) {
8013 goto resume;
8014 }
8015 #endif /* MIRACAST_MCHAN_ALGO */
8016
8017 #ifdef MIRACAST_MCHAN_BW
8018 /* setting mchan_bw to platform specific value */
8019 config.iovar = "mchan_bw";
8020 config.param = MIRACAST_MCHAN_BW;
8021 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8022 if (ret) {
8023 goto resume;
8024 }
8025 #endif /* MIRACAST_MCHAN_BW */
8026
8027 #ifdef MIRACAST_AMPDU_SIZE
8028 /* setting apmdu to platform specific value */
8029 config.iovar = "ampdu_mpdu";
8030 config.param = MIRACAST_AMPDU_SIZE;
8031 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8032 if (ret) {
8033 goto resume;
8034 }
8035 #endif /* MIRACAST_AMPDU_SIZE */
8036 /* FALLTROUGH */
8037 /* Source mode shares most configurations with sink mode.
8038 * Fall through here to avoid code duplication
8039 */
8040 case MIRACAST_MODE_SINK:
8041 /* disable internal roaming */
8042 config.iovar = "roam_off";
8043 config.param = 1;
8044 config.arg = NULL;
8045 config.len = 0;
8046 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8047 if (ret) {
8048 goto resume;
8049 }
8050
8051 #ifdef CUSTOMER_HW10
8052 /* [CSP#812738] Change scan engine parameters to reduce scan time
8053 * and guarantee more times to mirroring.
8054 */
8055 val = 10;
8056 config.iovar = NULL;
8057 config.ioctl = WLC_GET_SCAN_CHANNEL_TIME;
8058 config.arg = &val;
8059 config.len = sizeof(int);
8060 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8061 if (ret)
8062 goto resume;
8063
8064 val = 180;
8065 config.iovar = NULL;
8066 config.ioctl = WLC_GET_SCAN_HOME_TIME;
8067 config.arg = &val;
8068 config.len = sizeof(int);
8069 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8070 if (ret)
8071 goto resume;
8072
8073 #if defined(BCM4339_CHIP)
8074 config.iovar = "phy_watchdog";
8075 config.param = 0;
8076 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8077 ANDROID_INFO(("%s: do iovar cmd=%s (ret=%d)\n",
8078 __FUNCTION__, config.iovar, ret));
8079 #endif
8080 #endif /* CUSTOMER_HW10 */
8081
8082 #ifndef CUSTOMER_HW10
8083
8084 /* tunr off pm */
8085 ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
8086 if (ret) {
8087 goto resume;
8088 }
8089
8090 if (val != PM_OFF) {
8091 val = PM_OFF;
8092 config.iovar = NULL;
8093 config.ioctl = WLC_GET_PM;
8094 config.arg = &val;
8095 config.len = sizeof(int);
8096 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8097 if (ret) {
8098 goto resume;
8099 }
8100 }
8101 #endif /* CUSTOMER_HW10 */
8102 break;
8103 case MIRACAST_MODE_OFF:
8104 default:
8105 break;
8106 }
8107 miracast_cur_mode = mode;
8108
8109 return 0;
8110
8111 resume:
8112 ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
8113 wl_android_iolist_resume(dev, &miracast_resume_list);
8114 return ret;
8115 }
8116 #endif /* WL_CFG80211 */
8117
8118 #ifdef WL_RELMCAST
8119 #define NETLINK_OXYGEN 30
8120 #define AIBSS_BEACON_TIMEOUT 10
8121
8122 static struct sock *nl_sk = NULL;
8123
wl_netlink_recv(struct sk_buff * skb)8124 static void wl_netlink_recv(struct sk_buff *skb)
8125 {
8126 ANDROID_ERROR(("netlink_recv called\n"));
8127 }
8128
wl_netlink_init(void)8129 static int wl_netlink_init(void)
8130 {
8131 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8132 struct netlink_kernel_cfg cfg = {
8133 .input = wl_netlink_recv,
8134 };
8135 #endif
8136
8137 if (nl_sk != NULL) {
8138 ANDROID_ERROR(("nl_sk already exist\n"));
8139 return BCME_ERROR;
8140 }
8141
8142 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
8143 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
8144 0, wl_netlink_recv, NULL, THIS_MODULE);
8145 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
8146 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
8147 #else
8148 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
8149 #endif
8150
8151 if (nl_sk == NULL) {
8152 ANDROID_ERROR(("nl_sk is not ready\n"));
8153 return BCME_ERROR;
8154 }
8155
8156 return BCME_OK;
8157 }
8158
wl_netlink_deinit(void)8159 static void wl_netlink_deinit(void)
8160 {
8161 if (nl_sk) {
8162 netlink_kernel_release(nl_sk);
8163 nl_sk = NULL;
8164 }
8165 }
8166
8167 s32
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)8168 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
8169 {
8170 struct sk_buff *skb = NULL;
8171 struct nlmsghdr *nlh = NULL;
8172 int ret = -1;
8173
8174 if (nl_sk == NULL) {
8175 ANDROID_ERROR(("nl_sk was not initialized\n"));
8176 goto nlmsg_failure;
8177 }
8178
8179 skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
8180 if (skb == NULL) {
8181 ANDROID_ERROR(("failed to allocate memory\n"));
8182 goto nlmsg_failure;
8183 }
8184
8185 nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
8186 if (nlh == NULL) {
8187 ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
8188 skb_tailroom(skb), nlmsg_total_size(size)));
8189 dev_kfree_skb(skb);
8190 goto nlmsg_failure;
8191 }
8192
8193 memcpy(nlmsg_data(nlh), data, size);
8194 nlh->nlmsg_seq = seq;
8195 nlh->nlmsg_type = type;
8196
8197 /* netlink_unicast() takes ownership of the skb and frees it itself. */
8198 ret = netlink_unicast(nl_sk, skb, pid, 0);
8199 ANDROID_INFO(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
8200
8201 nlmsg_failure:
8202 return ret;
8203 }
8204 #endif /* WL_RELMCAST */
8205
8206 #ifdef WLAIBSS
wl_android_set_ibss_txfail_event(struct net_device * dev,char * command,int total_len)8207 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
8208 {
8209 int err = 0;
8210 int retry = 0;
8211 int pid = 0;
8212 aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
8213 char smbuf[WLC_IOCTL_SMLEN];
8214
8215 if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
8216 ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
8217 return -1;
8218 }
8219
8220 /* set pid, and if the event was happened, let's send a notification through netlink */
8221 wl_cfg80211_set_txfail_pid(dev, pid);
8222
8223 #ifdef WL_RELMCAST
8224 /* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
8225 wl_cfg80211_set_rmc_pid(dev, pid);
8226 #endif /* WL_RELMCAST */
8227
8228 /* If retry value is 0, it disables the functionality for TX Fail. */
8229 if (retry > 0) {
8230 txfail_config.max_tx_retry = retry;
8231 txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */
8232 }
8233 txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
8234 txfail_config.len = sizeof(txfail_config);
8235
8236 err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
8237 sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
8238 ANDROID_INFO(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
8239
8240 return ((err == 0)?total_len:err);
8241 }
8242
wl_android_get_ibss_peer_info(struct net_device * dev,char * command,int total_len,bool bAll)8243 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
8244 int total_len, bool bAll)
8245 {
8246 int error;
8247 int bytes_written = 0;
8248 void *buf = NULL;
8249 bss_peer_list_info_t peer_list_info;
8250 bss_peer_info_t *peer_info;
8251 int i;
8252 bool found = false;
8253 struct ether_addr mac_ea;
8254 char *str = command;
8255 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8256
8257 ANDROID_INFO(("get ibss peer info(%s)\n", bAll?"true":"false"));
8258
8259 if (!bAll) {
8260 if (bcmstrtok(&str, " ", NULL) == NULL) {
8261 ANDROID_ERROR(("invalid command\n"));
8262 return -1;
8263 }
8264
8265 if (!str || !bcm_ether_atoe(str, &mac_ea)) {
8266 ANDROID_ERROR(("invalid MAC address\n"));
8267 return -1;
8268 }
8269 }
8270
8271 if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) {
8272 ANDROID_ERROR(("kmalloc failed\n"));
8273 return -1;
8274 }
8275
8276 error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
8277 if (unlikely(error)) {
8278 ANDROID_ERROR(("could not get ibss peer info (%d)\n", error));
8279 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8280 return -1;
8281 }
8282
8283 memcpy(&peer_list_info, buf, sizeof(peer_list_info));
8284 peer_list_info.version = htod16(peer_list_info.version);
8285 peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
8286 peer_list_info.count = htod32(peer_list_info.count);
8287
8288 ANDROID_INFO(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
8289 peer_list_info.bss_peer_info_len, peer_list_info.count));
8290
8291 if (peer_list_info.count > 0) {
8292 if (bAll)
8293 bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
8294 peer_list_info.count);
8295
8296 peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
8297
8298 for (i = 0; i < peer_list_info.count; i++) {
8299
8300 ANDROID_INFO(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
8301 peer_info->tx_rate, peer_info->rx_rate));
8302
8303 if (!bAll &&
8304 memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
8305 found = true;
8306 }
8307
8308 if (bAll || found) {
8309 bytes_written += snprintf(&command[bytes_written],
8310 total_len - bytes_written,
8311 MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
8312 peer_info->tx_rate/1000, peer_info->rssi);
8313 if (bytes_written >= total_len) {
8314 ANDROID_ERROR(("wl_android_get_ibss_peer_info: Insufficient"
8315 " memory, %d bytes\n",
8316 total_len));
8317 bytes_written = -1;
8318 break;
8319 }
8320 }
8321
8322 if (found)
8323 break;
8324
8325 peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
8326 }
8327 }
8328 else {
8329 ANDROID_ERROR(("could not get ibss peer info : no item\n"));
8330 }
8331 ANDROID_INFO(("command(%u):%s\n", total_len, command));
8332 ANDROID_INFO(("bytes_written:%d\n", bytes_written));
8333
8334 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8335 return bytes_written;
8336 }
8337
wl_android_set_ibss_routetable(struct net_device * dev,char * command)8338 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
8339 {
8340
8341 char *pcmd = command;
8342 char *str = NULL;
8343 ibss_route_tbl_t *route_tbl = NULL;
8344 char *ioctl_buf = NULL;
8345 s32 err = BCME_OK;
8346 uint32 route_tbl_len;
8347 uint32 entries;
8348 char *endptr;
8349 uint32 i = 0;
8350 struct ipv4_addr dipaddr;
8351 struct ether_addr ea;
8352 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8353
8354 route_tbl_len = sizeof(ibss_route_tbl_t) +
8355 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
8356 route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
8357 if (!route_tbl) {
8358 ANDROID_ERROR(("Route TBL alloc failed\n"));
8359 return -ENOMEM;
8360 }
8361 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
8362 if (!ioctl_buf) {
8363 ANDROID_ERROR(("ioctl memory alloc failed\n"));
8364 if (route_tbl) {
8365 MFREE(cfg->osh, route_tbl, route_tbl_len);
8366 }
8367 return -ENOMEM;
8368 }
8369 bzero(ioctl_buf, WLC_IOCTL_MEDLEN);
8370
8371 /* drop command */
8372 str = bcmstrtok(&pcmd, " ", NULL);
8373
8374 /* get count */
8375 str = bcmstrtok(&pcmd, " ", NULL);
8376 if (!str) {
8377 ANDROID_ERROR(("Invalid number parameter %s\n", str));
8378 err = -EINVAL;
8379 goto exit;
8380 }
8381 entries = bcm_strtoul(str, &endptr, 0);
8382 if (*endptr != '\0') {
8383 ANDROID_ERROR(("Invalid number parameter %s\n", str));
8384 err = -EINVAL;
8385 goto exit;
8386 }
8387 if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
8388 ANDROID_ERROR(("Invalid entries number %u\n", entries));
8389 err = -EINVAL;
8390 goto exit;
8391 }
8392
8393 ANDROID_INFO(("Routing table count:%u\n", entries));
8394 route_tbl->num_entry = entries;
8395
8396 for (i = 0; i < entries; i++) {
8397 str = bcmstrtok(&pcmd, " ", NULL);
8398 if (!str || !bcm_atoipv4(str, &dipaddr)) {
8399 ANDROID_ERROR(("Invalid ip string %s\n", str));
8400 err = -EINVAL;
8401 goto exit;
8402 }
8403
8404 str = bcmstrtok(&pcmd, " ", NULL);
8405 if (!str || !bcm_ether_atoe(str, &ea)) {
8406 ANDROID_ERROR(("Invalid ethernet string %s\n", str));
8407 err = -EINVAL;
8408 goto exit;
8409 }
8410 bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
8411 bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
8412 }
8413
8414 route_tbl_len = sizeof(ibss_route_tbl_t) +
8415 ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
8416 err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
8417 route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
8418 if (err != BCME_OK) {
8419 ANDROID_ERROR(("Fail to set iovar %d\n", err));
8420 err = -EINVAL;
8421 }
8422
8423 exit:
8424 if (route_tbl) {
8425 MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
8426 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
8427 }
8428 if (ioctl_buf) {
8429 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
8430 }
8431 return err;
8432
8433 }
8434
8435 int
wl_android_set_ibss_ampdu(struct net_device * dev,char * command,int total_len)8436 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
8437 {
8438 char *pcmd = command;
8439 char *str = NULL, *endptr = NULL;
8440 struct ampdu_aggr aggr;
8441 char smbuf[WLC_IOCTL_SMLEN];
8442 int idx;
8443 int err = 0;
8444 int wme_AC2PRIO[AC_COUNT][2] = {
8445 {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */
8446 {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */
8447 {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */
8448 {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */
8449
8450 ANDROID_INFO(("set ibss ampdu:%s\n", command));
8451
8452 bzero(&aggr, sizeof(aggr));
8453 /* Cofigure all priorities */
8454 aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
8455
8456 /* acquire parameters */
8457 /* drop command */
8458 str = bcmstrtok(&pcmd, " ", NULL);
8459
8460 for (idx = 0; idx < AC_COUNT; idx++) {
8461 bool on;
8462 str = bcmstrtok(&pcmd, " ", NULL);
8463 if (!str) {
8464 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8465 return -EINVAL;
8466 }
8467 on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
8468 if (*endptr != '\0') {
8469 ANDROID_ERROR(("Invalid number format %s\n", str));
8470 return -EINVAL;
8471 }
8472 if (on) {
8473 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
8474 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
8475 }
8476 }
8477
8478 err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
8479 sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
8480
8481 return ((err == 0) ? total_len : err);
8482 }
8483
wl_android_set_ibss_antenna(struct net_device * dev,char * command,int total_len)8484 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
8485 {
8486 char *pcmd = command;
8487 char *str = NULL;
8488 int txchain, rxchain;
8489 int err = 0;
8490
8491 ANDROID_INFO(("set ibss antenna:%s\n", command));
8492
8493 /* acquire parameters */
8494 /* drop command */
8495 str = bcmstrtok(&pcmd, " ", NULL);
8496
8497 /* TX chain */
8498 str = bcmstrtok(&pcmd, " ", NULL);
8499 if (!str) {
8500 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8501 return -EINVAL;
8502 }
8503 txchain = bcm_atoi(str);
8504
8505 /* RX chain */
8506 str = bcmstrtok(&pcmd, " ", NULL);
8507 if (!str) {
8508 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8509 return -EINVAL;
8510 }
8511 rxchain = bcm_atoi(str);
8512
8513 err = wldev_iovar_setint(dev, "txchain", txchain);
8514 if (err != 0)
8515 return err;
8516 err = wldev_iovar_setint(dev, "rxchain", rxchain);
8517 return ((err == 0)?total_len:err);
8518 }
8519 #endif /* WLAIBSS */
8520
wl_keep_alive_set(struct net_device * dev,char * extra)8521 int wl_keep_alive_set(struct net_device *dev, char* extra)
8522 {
8523 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
8524 int ret;
8525 uint period_msec = 0;
8526 char *buf;
8527 dhd_pub_t *dhd = dhd_get_pub(dev);
8528
8529 if (extra == NULL) {
8530 ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
8531 return -1;
8532 }
8533 if (sscanf(extra, "%d", &period_msec) != 1) {
8534 ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
8535 return -EINVAL;
8536 }
8537 ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
8538
8539 bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
8540
8541 mkeep_alive_pkt.period_msec = period_msec;
8542 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
8543 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
8544
8545 /* Setup keep alive zero for null packet generation */
8546 mkeep_alive_pkt.keep_alive_id = 0;
8547 mkeep_alive_pkt.len_bytes = 0;
8548
8549 buf = (char *)MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
8550 if (!buf) {
8551 ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
8552 return BCME_NOMEM;
8553 }
8554 ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
8555 WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8556 if (ret < 0)
8557 ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
8558 else
8559 ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
8560 MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
8561 return ret;
8562 }
8563
8564 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)8565 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
8566 {
8567 int error = 0;
8568 int bytes_written = 0;
8569 int only_resp_wfdsrc = 0;
8570
8571 error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
8572 if (error) {
8573 ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
8574 __FUNCTION__, error));
8575 return -1;
8576 }
8577
8578 bytes_written = snprintf(command, total_len, "%s %d",
8579 CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
8580
8581 return bytes_written;
8582 }
8583
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)8584 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
8585 {
8586 int error = 0;
8587
8588 error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
8589 if (error) {
8590 ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
8591 __FUNCTION__, only_resp_wfdsrc, error));
8592 return -1;
8593 }
8594
8595 return 0;
8596 }
8597 #endif /* P2PRESP_WFDIE_SRC */
8598
8599 #ifdef BT_WIFI_HANDOVER
8600 static int
wl_tbow_teardown(struct net_device * dev)8601 wl_tbow_teardown(struct net_device *dev)
8602 {
8603 int err = BCME_OK;
8604 char buf[WLC_IOCTL_SMLEN];
8605 tbow_setup_netinfo_t netinfo;
8606 bzero(&netinfo, sizeof(netinfo));
8607 netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
8608
8609 err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
8610 sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
8611 if (err < 0) {
8612 ANDROID_ERROR(("tbow_doho iovar error %d\n", err));
8613 return err;
8614 }
8615 return err;
8616 }
8617 #endif /* BT_WIFI_HANOVER */
8618
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)8619 static int wl_android_get_link_status(struct net_device *dev, char *command,
8620 int total_len)
8621 {
8622 int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
8623 uint32 rspec;
8624 uint encode, txexp;
8625 wl_bss_info_t *bi;
8626 int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
8627 char buf[WLC_IOCTL_SMLEN];
8628
8629 if (datalen > WLC_IOCTL_SMLEN) {
8630 ANDROID_ERROR(("data too big\n"));
8631 return -1;
8632 }
8633
8634 bzero(buf, datalen);
8635 /* get BSS information */
8636 *(u32 *) buf = htod32(datalen);
8637 error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
8638 if (unlikely(error)) {
8639 ANDROID_ERROR(("Could not get bss info %d\n", error));
8640 return -1;
8641 }
8642
8643 bi = (wl_bss_info_t*) (buf + sizeof(uint32));
8644
8645 for (i = 0; i < ETHER_ADDR_LEN; i++) {
8646 if (bi->BSSID.octet[i] > 0) {
8647 break;
8648 }
8649 }
8650
8651 if (i == ETHER_ADDR_LEN) {
8652 ANDROID_INFO(("No BSSID\n"));
8653 return -1;
8654 }
8655
8656 /* check VHT capability at beacon */
8657 if (bi->vht_cap) {
8658 if (CHSPEC_IS5G(bi->chanspec)) {
8659 result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
8660 }
8661 }
8662
8663 /* get a rspec (radio spectrum) rate */
8664 error = wldev_iovar_getint(dev, "nrate", &rspec);
8665 if (unlikely(error) || rspec == 0) {
8666 ANDROID_ERROR(("get link status error (%d)\n", error));
8667 return -1;
8668 }
8669
8670 /* referred wl_nrate_print() for the calculation */
8671 encode = (rspec & WL_RSPEC_ENCODING_MASK);
8672 txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
8673
8674 switch (encode) {
8675 case WL_RSPEC_ENCODE_HT:
8676 /* check Rx MCS Map for HT */
8677 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
8678 int8 bitmap = 0xFF;
8679 if (i == MAX_STREAMS_SUPPORTED-1) {
8680 bitmap = 0x7F;
8681 }
8682 if (bi->basic_mcs[i] & bitmap) {
8683 nss++;
8684 }
8685 }
8686 break;
8687 case WL_RSPEC_ENCODE_VHT:
8688 /* check Rx MCS Map for VHT */
8689 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
8690 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
8691 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
8692 nss++;
8693 }
8694 }
8695 break;
8696 }
8697
8698 /* check MIMO capability with nss in beacon */
8699 if (nss > 1) {
8700 result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
8701 }
8702
8703 /* Legacy rates WL_RSPEC_ENCODE_RATE are single stream, and
8704 * HT rates for mcs 0-7 are single stream.
8705 * In case of VHT NSS comes from rspec.
8706 */
8707 single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
8708 ((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
8709 ((encode == WL_RSPEC_ENCODE_VHT) &&
8710 ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
8711
8712 if (txexp == 0) {
8713 if ((rspec & WL_RSPEC_STBC) && single_stream) {
8714 stf = OLD_NRATE_STF_STBC;
8715 } else {
8716 stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
8717 }
8718 } else if (txexp == 1 && single_stream) {
8719 stf = OLD_NRATE_STF_CDD;
8720 }
8721
8722 /* check 11ac (VHT) */
8723 if (encode == WL_RSPEC_ENCODE_VHT) {
8724 if (CHSPEC_IS5G(bi->chanspec)) {
8725 result |= WL_ANDROID_LINK_VHT;
8726 }
8727 }
8728
8729 /* check MIMO */
8730 if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
8731 switch (stf) {
8732 case OLD_NRATE_STF_SISO:
8733 break;
8734 case OLD_NRATE_STF_CDD:
8735 case OLD_NRATE_STF_STBC:
8736 result |= WL_ANDROID_LINK_MIMO;
8737 break;
8738 case OLD_NRATE_STF_SDM:
8739 if (!single_stream) {
8740 result |= WL_ANDROID_LINK_MIMO;
8741 }
8742 break;
8743 }
8744 }
8745
8746 ANDROID_INFO(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
8747 __FUNCTION__, result, stf, single_stream, nss));
8748
8749 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
8750
8751 return bytes_written;
8752 }
8753
8754 #ifdef P2P_LISTEN_OFFLOADING
8755
8756 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 * cfg)8757 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
8758 {
8759 s32 bssidx;
8760 int ret = 0;
8761 int p2plo_pause = 0;
8762 dhd_pub_t *dhd = NULL;
8763 if (!cfg || !cfg->p2p) {
8764 ANDROID_ERROR(("Wl %p or cfg->p2p %p is null\n",
8765 cfg, cfg ? cfg->p2p : 0));
8766 return 0;
8767 }
8768
8769 dhd = (dhd_pub_t *)(cfg->pub);
8770 if (!dhd->up) {
8771 ANDROID_ERROR(("bus is already down\n"));
8772 return ret;
8773 }
8774
8775 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8776 ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
8777 "p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
8778 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
8779 if (ret < 0) {
8780 ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8781 }
8782
8783 return ret;
8784 }
8785 s32
wl_cfg80211_p2plo_listen_start(struct net_device * dev,u8 * buf,int len)8786 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
8787 {
8788 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8789 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8790 wl_p2plo_listen_t p2plo_listen;
8791 int ret = -EAGAIN;
8792 int channel = 0;
8793 int period = 0;
8794 int interval = 0;
8795 int count = 0;
8796 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
8797 ANDROID_ERROR(("Sending Action Frames. Try it again.\n"));
8798 goto exit;
8799 }
8800
8801 if (wl_get_drv_status_all(cfg, SCANNING)) {
8802 ANDROID_ERROR(("Scanning already\n"));
8803 goto exit;
8804 }
8805
8806 if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
8807 ANDROID_ERROR(("Scanning being aborted\n"));
8808 goto exit;
8809 }
8810
8811 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8812 ANDROID_ERROR(("p2p listen offloading already running\n"));
8813 goto exit;
8814 }
8815
8816 /* Just in case if it is not enabled */
8817 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
8818 ANDROID_ERROR(("cfgp2p_enable discovery failed"));
8819 goto exit;
8820 }
8821
8822 bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
8823
8824 if (len) {
8825 sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
8826 if ((channel == 0) || (period == 0) ||
8827 (interval == 0) || (count == 0)) {
8828 ANDROID_ERROR(("Wrong argument %d/%d/%d/%d \n",
8829 channel, period, interval, count));
8830 ret = -EAGAIN;
8831 goto exit;
8832 }
8833 p2plo_listen.period = period;
8834 p2plo_listen.interval = interval;
8835 p2plo_listen.count = count;
8836
8837 ANDROID_ERROR(("channel:%d period:%d, interval:%d count:%d\n",
8838 channel, period, interval, count));
8839 } else {
8840 ANDROID_ERROR(("Argument len is wrong.\n"));
8841 ret = -EAGAIN;
8842 goto exit;
8843 }
8844
8845 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
8846 sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8847 bssidx, &cfg->ioctl_buf_sync)) < 0) {
8848 ANDROID_ERROR(("p2po_listen_channel Failed :%d\n", ret));
8849 goto exit;
8850 }
8851
8852 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
8853 sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8854 bssidx, &cfg->ioctl_buf_sync)) < 0) {
8855 ANDROID_ERROR(("p2po_listen Failed :%d\n", ret));
8856 goto exit;
8857 }
8858
8859 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
8860 exit :
8861 return ret;
8862 }
8863 s32
wl_cfg80211_p2plo_listen_stop(struct net_device * dev)8864 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
8865 {
8866 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8867 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8868 int ret = -EAGAIN;
8869
8870 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
8871 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8872 bssidx, &cfg->ioctl_buf_sync)) < 0) {
8873 ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8874 goto exit;
8875 }
8876
8877 exit:
8878 return ret;
8879 }
8880
8881 s32
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)8882 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
8883 {
8884 int ret = 0;
8885
8886 ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len));
8887
8888 if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
8889 ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
8890 } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
8891 ret = wl_cfg80211_p2plo_listen_stop(dev);
8892 } else {
8893 ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf));
8894 ret = -EINVAL;
8895 }
8896 return ret;
8897 }
8898 void
wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 * cfg)8899 wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
8900 {
8901 struct wireless_dev *wdev;
8902 if (!cfg) {
8903 return;
8904 }
8905
8906 wdev = bcmcfg_to_p2p_wdev(cfg);
8907
8908 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8909 ANDROID_INFO(("P2P_FIND: Discovery offload is already in progress."
8910 "it aborted\n"));
8911 wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
8912 if (wdev != NULL) {
8913 #if defined(WL_CFG80211_P2P_DEV_IF)
8914 cfg80211_remain_on_channel_expired(wdev,
8915 cfg->last_roc_id,
8916 &cfg->remain_on_chan, GFP_KERNEL);
8917 #else
8918 cfg80211_remain_on_channel_expired(wdev,
8919 cfg->last_roc_id,
8920 &cfg->remain_on_chan,
8921 cfg->remain_on_chan_type, GFP_KERNEL);
8922 #endif /* WL_CFG80211_P2P_DEV_IF */
8923 }
8924 wl_cfg80211_p2plo_deinit(cfg);
8925 }
8926 }
8927 #endif /* P2P_LISTEN_OFFLOADING */
8928
8929 #ifdef WL_MURX
8930 int
wl_android_murx_bfe_cap(struct net_device * dev,int val)8931 wl_android_murx_bfe_cap(struct net_device *dev, int val)
8932 {
8933 int err = BCME_OK;
8934 int iface_count = wl_cfg80211_iface_count(dev);
8935 struct ether_addr bssid;
8936 wl_reassoc_params_t params;
8937
8938 if (iface_count > 1) {
8939 ANDROID_ERROR(("murx_bfe_cap change is not allowed when "
8940 "there are multiple interfaces\n"));
8941 return -EINVAL;
8942 }
8943 /* Now there is only single interface */
8944 err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
8945 if (unlikely(err)) {
8946 ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d,"
8947 "error %d\n", val, err));
8948 return err;
8949 }
8950
8951 /* If successful intiate a reassoc */
8952 bzero(&bssid, ETHER_ADDR_LEN);
8953 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
8954 ANDROID_ERROR(("Failed to get bssid, error=%d\n", err));
8955 return err;
8956 }
8957
8958 bzero(¶ms, sizeof(wl_reassoc_params_t));
8959 memcpy(¶ms.bssid, &bssid, ETHER_ADDR_LEN);
8960
8961 if ((err = wldev_ioctl_set(dev, WLC_REASSOC, ¶ms,
8962 sizeof(wl_reassoc_params_t))) < 0) {
8963 ANDROID_ERROR(("reassoc failed err:%d \n", err));
8964 } else {
8965 ANDROID_INFO(("reassoc issued successfully\n"));
8966 }
8967
8968 return err;
8969 }
8970 #endif /* WL_MURX */
8971
8972 #ifdef SUPPORT_RSSI_SUM_REPORT
8973 int
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)8974 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
8975 {
8976 wl_rssi_ant_mimo_t rssi_ant_mimo;
8977 char *ifname = NULL;
8978 char *peer_mac = NULL;
8979 char *mimo_cmd = "mimo";
8980 char *pos, *token;
8981 int err = BCME_OK;
8982 int bytes_written = 0;
8983 bool mimo_rssi = FALSE;
8984
8985 bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
8986 /*
8987 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
8988 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
8989 */
8990 pos = command;
8991
8992 /* drop command */
8993 token = bcmstrtok(&pos, " ", NULL);
8994
8995 /* get the interface name */
8996 token = bcmstrtok(&pos, " ", NULL);
8997 if (!token) {
8998 ANDROID_ERROR(("Invalid arguments\n"));
8999 return -EINVAL;
9000 }
9001 ifname = token;
9002
9003 /* Optional: Check the MIMO RSSI mode or peer MAC address */
9004 token = bcmstrtok(&pos, " ", NULL);
9005 if (token) {
9006 /* Check the MIMO RSSI mode */
9007 if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9008 mimo_rssi = TRUE;
9009 } else {
9010 peer_mac = token;
9011 }
9012 }
9013
9014 /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
9015 token = bcmstrtok(&pos, " ", NULL);
9016 if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9017 mimo_rssi = TRUE;
9018 }
9019
9020 err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
9021 if (unlikely(err)) {
9022 ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err));
9023 return err;
9024 }
9025
9026 /* Parse the results */
9027 ANDROID_INFO(("ifname %s, version %d, count %d, mimo rssi %d\n",
9028 ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
9029 if (mimo_rssi) {
9030 ANDROID_INFO(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
9031 bytes_written = snprintf(command, total_len, "%s MIMO %d",
9032 CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
9033 } else {
9034 int cnt;
9035 bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
9036 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
9037 ANDROID_INFO(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
9038 bytes_written = snprintf(command, total_len, "%d ",
9039 rssi_ant_mimo.rssi_ant[cnt]);
9040 }
9041 }
9042
9043 return bytes_written;
9044 }
9045
9046 int
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)9047 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
9048 {
9049 rssilog_set_param_t set_param;
9050 char *pos, *token;
9051 int err = BCME_OK;
9052
9053 bzero(&set_param, sizeof(rssilog_set_param_t));
9054 /*
9055 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
9056 */
9057 pos = command;
9058
9059 /* drop command */
9060 token = bcmstrtok(&pos, " ", NULL);
9061
9062 /* enable/disable */
9063 token = bcmstrtok(&pos, " ", NULL);
9064 if (!token) {
9065 ANDROID_ERROR(("Invalid arguments\n"));
9066 return -EINVAL;
9067 }
9068 set_param.enable = bcm_atoi(token);
9069
9070 /* RSSI Threshold */
9071 token = bcmstrtok(&pos, " ", NULL);
9072 if (!token) {
9073 ANDROID_ERROR(("Invalid arguments\n"));
9074 return -EINVAL;
9075 }
9076 set_param.rssi_threshold = bcm_atoi(token);
9077
9078 /* Time Threshold */
9079 token = bcmstrtok(&pos, " ", NULL);
9080 if (!token) {
9081 ANDROID_ERROR(("Invalid arguments\n"));
9082 return -EINVAL;
9083 }
9084 set_param.time_threshold = bcm_atoi(token);
9085
9086 ANDROID_INFO(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
9087 set_param.rssi_threshold, set_param.time_threshold));
9088
9089 err = wl_set_rssi_logging(dev, (void *)&set_param);
9090 if (unlikely(err)) {
9091 ANDROID_ERROR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
9092 " Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
9093 set_param.time_threshold));
9094 }
9095
9096 return err;
9097 }
9098
9099 int
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)9100 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
9101 {
9102 rssilog_get_param_t get_param;
9103 int err = BCME_OK;
9104 int bytes_written = 0;
9105
9106 err = wl_get_rssi_logging(dev, (void *)&get_param);
9107 if (unlikely(err)) {
9108 ANDROID_ERROR(("Failed to get RSSI logging info\n"));
9109 return BCME_ERROR;
9110 }
9111
9112 ANDROID_INFO(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
9113 get_param.report_count, get_param.enable, get_param.rssi_threshold,
9114 get_param.time_threshold));
9115
9116 /* Parse the parameter */
9117 if (!get_param.enable) {
9118 ANDROID_INFO(("RSSI LOGGING: Feature is disables\n"));
9119 bytes_written = snprintf(command, total_len,
9120 "%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
9121 } else if (get_param.enable &
9122 (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
9123 if (!get_param.report_count) {
9124 ANDROID_INFO(("[PASS] RSSI difference across antennas is within"
9125 " threshold limits\n"));
9126 bytes_written = snprintf(command, total_len, "%s PASS\n",
9127 CMD_GET_RSSI_LOGGING);
9128 } else {
9129 ANDROID_INFO(("[FAIL] RSSI difference across antennas found "
9130 "to be greater than %3d dB\n", get_param.rssi_threshold));
9131 ANDROID_INFO(("[FAIL] RSSI difference check have failed for "
9132 "%d out of %d times\n", get_param.report_count,
9133 get_param.time_threshold));
9134 ANDROID_INFO(("[FAIL] RSSI difference is being monitored once "
9135 "per second, for a %d secs window\n", get_param.time_threshold));
9136 bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
9137 "%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
9138 get_param.rssi_threshold, get_param.report_count,
9139 get_param.time_threshold);
9140 }
9141 } else {
9142 ANDROID_INFO(("[BUSY] Reprot is not ready\n"));
9143 bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
9144 CMD_GET_RSSI_LOGGING);
9145 }
9146
9147 return bytes_written;
9148 }
9149 #endif /* SUPPORT_RSSI_SUM_REPORT */
9150
9151 #ifdef SET_PCIE_IRQ_CPU_CORE
9152 void
wl_android_set_irq_cpucore(struct net_device * net,int affinity_cmd)9153 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
9154 {
9155 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9156 if (!dhdp) {
9157 ANDROID_ERROR(("dhd is NULL\n"));
9158 return;
9159 }
9160
9161 dhd_set_irq_cpucore(dhdp, affinity_cmd);
9162 }
9163 #endif /* SET_PCIE_IRQ_CPU_CORE */
9164
9165 #ifdef SUPPORT_LQCM
9166 static int
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)9167 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
9168 {
9169 int err = 0;
9170
9171 err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
9172 if (err != BCME_OK) {
9173 ANDROID_ERROR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
9174 return -EIO;
9175 }
9176 return err;
9177 }
9178
9179 static int
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)9180 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
9181 {
9182 int bytes_written, err = 0;
9183 uint32 lqcm_report = 0;
9184 uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
9185
9186 err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
9187 if (err != BCME_OK) {
9188 ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err));
9189 return -EIO;
9190 }
9191 lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
9192 tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
9193 rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
9194
9195 ANDROID_INFO(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
9196
9197 bytes_written = snprintf(command, total_len, "%s %d",
9198 CMD_GET_LQCM_REPORT, lqcm_report);
9199
9200 return bytes_written;
9201 }
9202 #endif /* SUPPORT_LQCM */
9203
9204 int
wl_android_get_snr(struct net_device * dev,char * command,int total_len)9205 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
9206 {
9207 int bytes_written, error = 0;
9208 s32 snr = 0;
9209
9210 error = wldev_iovar_getint(dev, "snr", &snr);
9211 if (error) {
9212 ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n",
9213 __FUNCTION__, snr, error));
9214 return -EIO;
9215 }
9216
9217 bytes_written = snprintf(command, total_len, "snr %d", snr);
9218 ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
9219 return bytes_written;
9220 }
9221
9222 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
9223 int
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)9224 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
9225 {
9226 int rate = 0;
9227 char *pos, *token;
9228 char *ifname = NULL;
9229 int err = BCME_OK;
9230
9231 /*
9232 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
9233 */
9234 pos = command;
9235
9236 /* drop command */
9237 token = bcmstrtok(&pos, " ", NULL);
9238
9239 /* Rate */
9240 token = bcmstrtok(&pos, " ", NULL);
9241 if (!token)
9242 return -EINVAL;
9243 rate = bcm_atoi(token);
9244
9245 /* get the interface name */
9246 token = bcmstrtok(&pos, " ", NULL);
9247 if (!token)
9248 return -EINVAL;
9249 ifname = token;
9250
9251 ANDROID_INFO(("rate %d, ifacename %s\n", rate, ifname));
9252
9253 err = wl_set_ap_beacon_rate(dev, rate, ifname);
9254 if (unlikely(err)) {
9255 ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
9256 }
9257
9258 return err;
9259 }
9260
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)9261 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
9262 {
9263 char *pos, *token;
9264 char *ifname = NULL;
9265 int bytes_written = 0;
9266 /*
9267 * DRIVER GET_AP_BASICRATE <ifname>
9268 */
9269 pos = command;
9270
9271 /* drop command */
9272 token = bcmstrtok(&pos, " ", NULL);
9273
9274 /* get the interface name */
9275 token = bcmstrtok(&pos, " ", NULL);
9276 if (!token)
9277 return -EINVAL;
9278 ifname = token;
9279
9280 ANDROID_INFO(("ifacename %s\n", ifname));
9281
9282 bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
9283 if (bytes_written < 1) {
9284 ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written));
9285 return -EPROTO;
9286 }
9287
9288 return bytes_written;
9289 }
9290 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
9291
9292 #ifdef SUPPORT_AP_RADIO_PWRSAVE
9293 int
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)9294 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
9295 {
9296 char *pos, *token;
9297 char *ifname = NULL;
9298 int bytes_written = 0;
9299 char name[IFNAMSIZ];
9300 /*
9301 * DRIVER GET_AP_RPS <ifname>
9302 */
9303 pos = command;
9304
9305 /* drop command */
9306 token = bcmstrtok(&pos, " ", NULL);
9307
9308 /* get the interface name */
9309 token = bcmstrtok(&pos, " ", NULL);
9310 if (!token)
9311 return -EINVAL;
9312 ifname = token;
9313
9314 strlcpy(name, ifname, sizeof(name));
9315 ANDROID_INFO(("ifacename %s\n", name));
9316
9317 bytes_written = wl_get_ap_rps(dev, command, name, total_len);
9318 if (bytes_written < 1) {
9319 ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written));
9320 return -EPROTO;
9321 }
9322
9323 return bytes_written;
9324
9325 }
9326
9327 int
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)9328 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
9329 {
9330 int enable = 0;
9331 char *pos, *token;
9332 char *ifname = NULL;
9333 int err = BCME_OK;
9334 char name[IFNAMSIZ];
9335
9336 /*
9337 * DRIVER SET_AP_RPS <0/1> <ifname>
9338 */
9339 pos = command;
9340
9341 /* drop command */
9342 token = bcmstrtok(&pos, " ", NULL);
9343
9344 /* Enable */
9345 token = bcmstrtok(&pos, " ", NULL);
9346 if (!token)
9347 return -EINVAL;
9348 enable = bcm_atoi(token);
9349
9350 /* get the interface name */
9351 token = bcmstrtok(&pos, " ", NULL);
9352 if (!token)
9353 return -EINVAL;
9354 ifname = token;
9355
9356 strlcpy(name, ifname, sizeof(name));
9357 ANDROID_INFO(("enable %d, ifacename %s\n", enable, name));
9358
9359 err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
9360 if (unlikely(err)) {
9361 ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err));
9362 }
9363
9364 return err;
9365 }
9366
9367 int
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)9368 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
9369 {
9370 ap_rps_info_t rps;
9371 char *pos, *token;
9372 char *ifname = NULL;
9373 int err = BCME_OK;
9374 char name[IFNAMSIZ];
9375
9376 bzero(&rps, sizeof(rps));
9377 /*
9378 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
9379 */
9380 pos = command;
9381
9382 /* drop command */
9383 token = bcmstrtok(&pos, " ", NULL);
9384
9385 /* pps */
9386 token = bcmstrtok(&pos, " ", NULL);
9387 if (!token)
9388 return -EINVAL;
9389 rps.pps = bcm_atoi(token);
9390
9391 /* level */
9392 token = bcmstrtok(&pos, " ", NULL);
9393 if (!token)
9394 return -EINVAL;
9395 rps.level = bcm_atoi(token);
9396
9397 /* quiettime */
9398 token = bcmstrtok(&pos, " ", NULL);
9399 if (!token)
9400 return -EINVAL;
9401 rps.quiet_time = bcm_atoi(token);
9402
9403 /* sta assoc check */
9404 token = bcmstrtok(&pos, " ", NULL);
9405 if (!token)
9406 return -EINVAL;
9407 rps.sta_assoc_check = bcm_atoi(token);
9408
9409 /* get the interface name */
9410 token = bcmstrtok(&pos, " ", NULL);
9411 if (!token)
9412 return -EINVAL;
9413 ifname = token;
9414 strlcpy(name, ifname, sizeof(name));
9415
9416 ANDROID_INFO(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
9417 "ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
9418 rps.sta_assoc_check, name));
9419
9420 err = wl_update_ap_rps_params(dev, &rps, name);
9421 if (unlikely(err)) {
9422 ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, "
9423 "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
9424 rps.sta_assoc_check, err));
9425 }
9426
9427 return err;
9428 }
9429 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
9430
9431 #if defined(DHD_HANG_SEND_UP_TEST)
9432 void
wl_android_make_hang_with_reason(struct net_device * dev,const char * string_num)9433 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
9434 {
9435 dhd_make_hang_with_reason(dev, string_num);
9436 }
9437 #endif /* DHD_HANG_SEND_UP_TEST */
9438
9439 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
9440 static void
wl_android_check_priv_cmd_errors(struct net_device * dev)9441 wl_android_check_priv_cmd_errors(struct net_device *dev)
9442 {
9443 dhd_pub_t *dhdp;
9444 int memdump_mode;
9445
9446 if (!dev) {
9447 ANDROID_ERROR(("dev is NULL\n"));
9448 return;
9449 }
9450
9451 dhdp = wl_cfg80211_get_dhdp(dev);
9452 if (!dhdp) {
9453 ANDROID_ERROR(("dhdp is NULL\n"));
9454 return;
9455 }
9456
9457 #ifdef DHD_FW_COREDUMP
9458 memdump_mode = dhdp->memdump_enabled;
9459 #else
9460 /* Default enable if DHD doesn't support SOCRAM dump */
9461 memdump_mode = 1;
9462 #endif /* DHD_FW_COREDUMP */
9463
9464 if (report_hang_privcmd_err) {
9465 priv_cmd_errors++;
9466 } else {
9467 priv_cmd_errors = 0;
9468 }
9469
9470 /* Trigger HANG event only if memdump mode is enabled
9471 * due to customer's request
9472 */
9473 if (memdump_mode == DUMP_MEMFILE_BUGON &&
9474 (priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
9475 ANDROID_ERROR(("Send HANG event due to sequential private cmd errors\n"));
9476 priv_cmd_errors = 0;
9477 #ifdef DHD_FW_COREDUMP
9478 /* Take a SOCRAM dump */
9479 dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
9480 dhd_common_socram_dump(dhdp);
9481 #endif /* DHD_FW_COREDUMP */
9482 /* Send the HANG event to upper layer */
9483 dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
9484 dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
9485 }
9486 }
9487 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
9488
9489 #ifdef DHD_PKT_LOGGING
9490 static int
wl_android_pktlog_filter_enable(struct net_device * dev,char * command,int total_len)9491 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
9492 {
9493 int bytes_written = 0;
9494 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9495 dhd_pktlog_filter_t *filter;
9496 int err = BCME_OK;
9497
9498 if (!dhdp || !dhdp->pktlog) {
9499 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9500 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9501 return -EINVAL;
9502 }
9503
9504 filter = dhdp->pktlog->pktlog_filter;
9505
9506 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
9507 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
9508 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
9509
9510 if (err == BCME_OK) {
9511 bytes_written = snprintf(command, total_len, "OK");
9512 ANDROID_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
9513 } else {
9514 ANDROID_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
9515 return BCME_ERROR;
9516 }
9517
9518 return bytes_written;
9519 }
9520
9521 static int
wl_android_pktlog_filter_disable(struct net_device * dev,char * command,int total_len)9522 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
9523 {
9524 int bytes_written = 0;
9525 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9526 dhd_pktlog_filter_t *filter;
9527 int err = BCME_OK;
9528
9529 if (!dhdp || !dhdp->pktlog) {
9530 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9531 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9532 return -EINVAL;
9533 }
9534
9535 filter = dhdp->pktlog->pktlog_filter;
9536
9537 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
9538 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
9539 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
9540
9541 if (err == BCME_OK) {
9542 bytes_written = snprintf(command, total_len, "OK");
9543 ANDROID_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
9544 } else {
9545 ANDROID_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
9546 return BCME_ERROR;
9547 }
9548
9549 return bytes_written;
9550 }
9551
9552 static int
wl_android_pktlog_filter_pattern_enable(struct net_device * dev,char * command,int total_len)9553 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
9554 {
9555 int bytes_written = 0;
9556 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9557 dhd_pktlog_filter_t *filter;
9558 int err = BCME_OK;
9559
9560 if (!dhdp || !dhdp->pktlog) {
9561 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9562 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9563 return -EINVAL;
9564 }
9565
9566 filter = dhdp->pktlog->pktlog_filter;
9567
9568 if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
9569 return BCME_ERROR;
9570 }
9571
9572 err = dhd_pktlog_filter_pattern_enable(filter,
9573 command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
9574
9575 if (err == BCME_OK) {
9576 bytes_written = snprintf(command, total_len, "OK");
9577 ANDROID_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
9578 } else {
9579 ANDROID_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
9580 return BCME_ERROR;
9581 }
9582
9583 return bytes_written;
9584 }
9585
9586 static int
wl_android_pktlog_filter_pattern_disable(struct net_device * dev,char * command,int total_len)9587 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
9588 {
9589 int bytes_written = 0;
9590 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9591 dhd_pktlog_filter_t *filter;
9592 int err = BCME_OK;
9593
9594 if (!dhdp || !dhdp->pktlog) {
9595 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9596 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9597 return -EINVAL;
9598 }
9599
9600 filter = dhdp->pktlog->pktlog_filter;
9601
9602 if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
9603 return BCME_ERROR;
9604 }
9605
9606 err = dhd_pktlog_filter_pattern_enable(filter,
9607 command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
9608
9609 if (err == BCME_OK) {
9610 bytes_written = snprintf(command, total_len, "OK");
9611 ANDROID_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
9612 } else {
9613 ANDROID_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
9614 return BCME_ERROR;
9615 }
9616
9617 return bytes_written;
9618 }
9619
9620 static int
wl_android_pktlog_filter_add(struct net_device * dev,char * command,int total_len)9621 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
9622 {
9623 int bytes_written = 0;
9624 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9625 dhd_pktlog_filter_t *filter;
9626 int err = BCME_OK;
9627
9628 if (!dhdp || !dhdp->pktlog) {
9629 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9630 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9631 return -EINVAL;
9632 }
9633
9634 filter = dhdp->pktlog->pktlog_filter;
9635
9636 if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
9637 return BCME_ERROR;
9638 }
9639
9640 err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
9641
9642 if (err == BCME_OK) {
9643 bytes_written = snprintf(command, total_len, "OK");
9644 ANDROID_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
9645 } else {
9646 ANDROID_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
9647 return BCME_ERROR;
9648 }
9649
9650 return bytes_written;
9651 }
9652
9653 static int
wl_android_pktlog_filter_del(struct net_device * dev,char * command,int total_len)9654 wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_len)
9655 {
9656 int bytes_written = 0;
9657 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9658 dhd_pktlog_filter_t *filter;
9659 int err = BCME_OK;
9660
9661 if (!dhdp || !dhdp->pktlog) {
9662 ANDROID_ERROR(("%s(): dhdp=%p pktlog=%p\n",
9663 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9664 return -EINVAL;
9665 }
9666
9667 filter = dhdp->pktlog->pktlog_filter;
9668
9669 if (strlen(CMD_PKTLOG_FILTER_DEL) + 1 > total_len) {
9670 DHD_PKT_LOG(("%s(): wrong cmd length %d found\n",
9671 __FUNCTION__, (int)strlen(CMD_PKTLOG_FILTER_DEL)));
9672 return BCME_ERROR;
9673 }
9674
9675 err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1);
9676 if (err == BCME_OK) {
9677 bytes_written = snprintf(command, total_len, "OK");
9678 ANDROID_ERROR(("%s: pktlog filter del success\n", __FUNCTION__));
9679 } else {
9680 ANDROID_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__));
9681 return BCME_ERROR;
9682 }
9683
9684 return bytes_written;
9685 }
9686
9687 static int
wl_android_pktlog_filter_info(struct net_device * dev,char * command,int total_len)9688 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
9689 {
9690 int bytes_written = 0;
9691 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9692 dhd_pktlog_filter_t *filter;
9693 int err = BCME_OK;
9694
9695 if (!dhdp || !dhdp->pktlog) {
9696 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9697 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9698 return -EINVAL;
9699 }
9700
9701 filter = dhdp->pktlog->pktlog_filter;
9702
9703 err = dhd_pktlog_filter_info(filter);
9704
9705 if (err == BCME_OK) {
9706 bytes_written = snprintf(command, total_len, "OK");
9707 ANDROID_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
9708 } else {
9709 ANDROID_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
9710 return BCME_ERROR;
9711 }
9712
9713 return bytes_written;
9714 }
9715
9716 static int
wl_android_pktlog_start(struct net_device * dev,char * command,int total_len)9717 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
9718 {
9719 int bytes_written = 0;
9720 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9721
9722 if (!dhdp || !dhdp->pktlog) {
9723 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9724 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9725 return -EINVAL;
9726 }
9727
9728 if (!dhdp->pktlog->pktlog_ring) {
9729 DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9730 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9731 return -EINVAL;
9732 }
9733
9734 atomic_set(&dhdp->pktlog->pktlog_ring->start, TRUE);
9735
9736 bytes_written = snprintf(command, total_len, "OK");
9737
9738 ANDROID_ERROR(("%s: pktlog start success\n", __FUNCTION__));
9739
9740 return bytes_written;
9741 }
9742
9743 static int
wl_android_pktlog_stop(struct net_device * dev,char * command,int total_len)9744 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
9745 {
9746 int bytes_written = 0;
9747 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9748
9749 if (!dhdp || !dhdp->pktlog) {
9750 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9751 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9752 return -EINVAL;
9753 }
9754
9755 if (!dhdp->pktlog->pktlog_ring) {
9756 DHD_PKT_LOG(("%s(): _pktlog_ring=%p\n",
9757 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9758 return -EINVAL;
9759 }
9760
9761 atomic_set(&dhdp->pktlog->pktlog_ring->start, FALSE);
9762
9763 bytes_written = snprintf(command, total_len, "OK");
9764
9765 ANDROID_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
9766
9767 return bytes_written;
9768 }
9769
9770 static int
wl_android_pktlog_filter_exist(struct net_device * dev,char * command,int total_len)9771 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
9772 {
9773 int bytes_written = 0;
9774 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9775 dhd_pktlog_filter_t *filter;
9776 uint32 id;
9777 bool exist = FALSE;
9778
9779 if (!dhdp || !dhdp->pktlog) {
9780 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9781 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9782 return -EINVAL;
9783 }
9784
9785 filter = dhdp->pktlog->pktlog_filter;
9786
9787 if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
9788 return BCME_ERROR;
9789 }
9790
9791 exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
9792 &id);
9793
9794 if (exist) {
9795 bytes_written = snprintf(command, total_len, "TRUE");
9796 ANDROID_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
9797 } else {
9798 bytes_written = snprintf(command, total_len, "FALSE");
9799 ANDROID_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
9800 }
9801
9802 return bytes_written;
9803 }
9804
9805 static int
wl_android_pktlog_minmize_enable(struct net_device * dev,char * command,int total_len)9806 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
9807 {
9808 int bytes_written = 0;
9809 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9810
9811 if (!dhdp || !dhdp->pktlog) {
9812 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9813 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9814 return -EINVAL;
9815 }
9816
9817 if (!dhdp->pktlog->pktlog_ring) {
9818 DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9819 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9820 return -EINVAL;
9821 }
9822
9823 dhdp->pktlog->pktlog_ring->pktlog_minmize = TRUE;
9824
9825 bytes_written = snprintf(command, total_len, "OK");
9826
9827 ANDROID_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
9828
9829 return bytes_written;
9830 }
9831
9832 static int
wl_android_pktlog_minmize_disable(struct net_device * dev,char * command,int total_len)9833 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
9834 {
9835 int bytes_written = 0;
9836 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9837
9838 if (!dhdp || !dhdp->pktlog) {
9839 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9840 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9841 return -EINVAL;
9842 }
9843
9844 if (!dhdp->pktlog->pktlog_ring) {
9845 DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9846 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9847 return -EINVAL;
9848 }
9849
9850 dhdp->pktlog->pktlog_ring->pktlog_minmize = FALSE;
9851
9852 bytes_written = snprintf(command, total_len, "OK");
9853
9854 ANDROID_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
9855
9856 return bytes_written;
9857 }
9858
9859 static int
wl_android_pktlog_change_size(struct net_device * dev,char * command,int total_len)9860 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
9861 {
9862 int bytes_written = 0;
9863 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9864 int err = BCME_OK;
9865 int size;
9866
9867 if (!dhdp || !dhdp->pktlog) {
9868 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9869 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9870 return -EINVAL;
9871 }
9872
9873 if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
9874 return BCME_ERROR;
9875 }
9876
9877 size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
9878
9879 dhdp->pktlog->pktlog_ring =
9880 dhd_pktlog_ring_change_size(dhdp->pktlog->pktlog_ring, size);
9881 if (!dhdp->pktlog->pktlog_ring) {
9882 err = BCME_ERROR;
9883 }
9884
9885 if (err == BCME_OK) {
9886 bytes_written = snprintf(command, total_len, "OK");
9887 ANDROID_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
9888 } else {
9889 ANDROID_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
9890 return BCME_ERROR;
9891 }
9892
9893 return bytes_written;
9894 }
9895
9896 static int
wl_android_pktlog_dbg_dump(struct net_device * dev,char * command,int total_len)9897 wl_android_pktlog_dbg_dump(struct net_device *dev, char *command, int total_len)
9898 {
9899 int bytes_written = 0;
9900 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9901 int err = BCME_OK;
9902
9903 if (!dhdp || !dhdp->pktlog) {
9904 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9905 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9906 return -EINVAL;
9907 }
9908
9909 if (strlen(CMD_PKTLOG_DEBUG_DUMP) + 1 > total_len) {
9910 return BCME_ERROR;
9911 }
9912
9913 err = dhd_pktlog_debug_dump(dhdp);
9914 if (err == BCME_OK) {
9915 bytes_written = snprintf(command, total_len, "OK");
9916 ANDROID_INFO(("%s: pktlog dbg dump success\n", __FUNCTION__));
9917 } else {
9918 ANDROID_ERROR(("%s: pktlog dbg dump fail\n", __FUNCTION__));
9919 return BCME_ERROR;
9920 }
9921
9922 return bytes_written;
9923 }
9924 #endif /* DHD_PKT_LOGGING */
9925
9926 #if defined(CONFIG_TIZEN)
wl_android_set_powersave_mode(struct net_device * dev,char * command,int total_len)9927 static int wl_android_set_powersave_mode(
9928 struct net_device *dev, char* command, int total_len)
9929 {
9930 int pm;
9931
9932 int err = BCME_OK;
9933 #ifdef DHD_PM_OVERRIDE
9934 extern bool g_pm_override;
9935 #endif /* DHD_PM_OVERRIDE */
9936 sscanf(command, "%*s %10d", &pm);
9937 if (pm < PM_OFF || pm > PM_FAST) {
9938 ANDROID_ERROR(("check pm=%d\n", pm));
9939 return BCME_ERROR;
9940 }
9941
9942 #ifdef DHD_PM_OVERRIDE
9943 if (pm > PM_OFF) {
9944 g_pm_override = FALSE;
9945 }
9946 #endif /* DHD_PM_OVERRIDE */
9947
9948 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
9949
9950 #ifdef DHD_PM_OVERRIDE
9951 if (pm == PM_OFF) {
9952 g_pm_override = TRUE;
9953 }
9954
9955 ANDROID_ERROR(("%s: PM:%d, pm_override=%d\n", __FUNCTION__, pm, g_pm_override));
9956 #endif /* DHD_PM_OVERRIDE */
9957 return err;
9958 }
9959
wl_android_get_powersave_mode(struct net_device * dev,char * command,int total_len)9960 static int wl_android_get_powersave_mode(
9961 struct net_device *dev, char *command, int total_len)
9962 {
9963 int err, bytes_written;
9964 int pm;
9965
9966 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
9967 if (err != BCME_OK) {
9968 ANDROID_ERROR(("failed to get pm (%d)", err));
9969 return err;
9970 }
9971
9972 bytes_written = snprintf(command, total_len, "%s %d",
9973 CMD_POWERSAVEMODE_GET, pm);
9974
9975 return bytes_written;
9976 }
9977 #endif /* CONFIG_TIZEN */
9978
9979 #ifdef DHD_EVENT_LOG_FILTER
9980 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
9981
9982 #ifdef DHD_EWPR_VER2
9983 uint32 dhd_event_log_filter_serialize_bit(dhd_pub_t *dhdp, char *buf, uint32 tot_len,
9984 int index1, int index2, int index3);
9985 #endif
9986
9987 static int
wl_android_ewp_filter(struct net_device * dev,char * command,uint32 tot_len)9988 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
9989 {
9990 uint32 bytes_written = 0;
9991 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9992 #ifdef DHD_EWPR_VER2
9993 int index1 = 0, index2 = 0, index3 = 0;
9994 unsigned char *index_str = (unsigned char *)(command +
9995 strlen(CMD_EWP_FILTER) + 1);
9996 #else
9997 int type = 0;
9998 #endif
9999
10000 if (!dhdp || !command) {
10001 ANDROID_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
10002 return -EINVAL;
10003 }
10004
10005 if (!FW_SUPPORTED(dhdp, ecounters)) {
10006 ANDROID_ERROR(("does not support ecounters!\n"));
10007 return BCME_UNSUPPORTED;
10008 }
10009
10010 #ifdef DHD_EWPR_VER2
10011 if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) {
10012 sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3);
10013 ANDROID_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__,
10014 index1, index2, index3));
10015 }
10016 bytes_written += dhd_event_log_filter_serialize_bit(dhdp,
10017 &command[bytes_written], tot_len - bytes_written, index1, index2, index3);
10018 #else
10019 /* NEED TO GET TYPE if EXIST */
10020 type = 0;
10021
10022 bytes_written += dhd_event_log_filter_serialize(dhdp,
10023 &command[bytes_written], tot_len - bytes_written, type);
10024 #endif
10025
10026 return (int)bytes_written;
10027 }
10028 #endif /* DHD_EVENT_LOG_FILTER */
10029
10030 #ifdef SUPPORT_AP_SUSPEND
10031 int
wl_android_set_ap_suspend(struct net_device * dev,char * command,int total_len)10032 wl_android_set_ap_suspend(struct net_device *dev, char *command, int total_len)
10033 {
10034 int suspend = 0;
10035 char *pos, *token;
10036 char *ifname = NULL;
10037 int err = BCME_OK;
10038 char name[IFNAMSIZ];
10039
10040 /*
10041 * DRIVER SET_AP_SUSPEND <0/1> <ifname>
10042 */
10043 pos = command;
10044
10045 /* drop command */
10046 token = bcmstrtok(&pos, " ", NULL);
10047
10048 /* Enable */
10049 token = bcmstrtok(&pos, " ", NULL);
10050 if (!token) {
10051 return -EINVAL;
10052 }
10053 suspend = bcm_atoi(token);
10054
10055 /* get the interface name */
10056 token = bcmstrtok(&pos, " ", NULL);
10057 if (!token) {
10058 return -EINVAL;
10059 }
10060 ifname = token;
10061
10062 strlcpy(name, ifname, sizeof(name));
10063 ANDROID_INFO(("suspend %d, ifacename %s\n", suspend, name));
10064
10065 err = wl_set_ap_suspend(dev, suspend? TRUE: FALSE, name);
10066 if (unlikely(err)) {
10067 ANDROID_ERROR(("Failed to set suspend, suspend %d, error = %d\n", suspend, err));
10068 }
10069
10070 return err;
10071 }
10072 #endif /* SUPPORT_AP_SUSPEND */
10073
10074 #ifdef SUPPORT_AP_BWCTRL
10075 int
wl_android_set_ap_bw(struct net_device * dev,char * command,int total_len)10076 wl_android_set_ap_bw(struct net_device *dev, char *command, int total_len)
10077 {
10078 int bw = DOT11_OPER_MODE_20MHZ;
10079 char *pos, *token;
10080 char *ifname = NULL;
10081 int err = BCME_OK;
10082 char name[IFNAMSIZ];
10083
10084 /*
10085 * DRIVER SET_AP_BW <0/1/2> <ifname>
10086 * 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10087 * This is from operating mode field
10088 * in 8.4.1.50 of 802.11ac-2013
10089 */
10090 pos = command;
10091
10092 /* drop command */
10093 token = bcmstrtok(&pos, " ", NULL);
10094
10095 /* BW */
10096 token = bcmstrtok(&pos, " ", NULL);
10097 if (!token) {
10098 return -EINVAL;
10099 }
10100 bw = bcm_atoi(token);
10101
10102 /* get the interface name */
10103 token = bcmstrtok(&pos, " ", NULL);
10104 if (!token) {
10105 return -EINVAL;
10106 }
10107 ifname = token;
10108
10109 strlcpy(name, ifname, sizeof(name));
10110 ANDROID_INFO(("bw %d, ifacename %s\n", bw, name));
10111
10112 err = wl_set_ap_bw(dev, bw, name);
10113 if (unlikely(err)) {
10114 ANDROID_ERROR(("Failed to set bw, bw %d, error = %d\n", bw, err));
10115 }
10116
10117 return err;
10118 }
10119
10120 int
wl_android_get_ap_bw(struct net_device * dev,char * command,int total_len)10121 wl_android_get_ap_bw(struct net_device *dev, char *command, int total_len)
10122 {
10123 char *pos, *token;
10124 char *ifname = NULL;
10125 int bytes_written = 0;
10126 char name[IFNAMSIZ];
10127
10128 /*
10129 * DRIVER GET_AP_BW <ifname>
10130 * returns 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10131 * This is from operating mode field
10132 * in 8.4.1.50 of 802.11ac-2013
10133 */
10134 pos = command;
10135
10136 /* drop command */
10137 token = bcmstrtok(&pos, " ", NULL);
10138
10139 /* get the interface name */
10140 token = bcmstrtok(&pos, " ", NULL);
10141 if (!token) {
10142 return -EINVAL;
10143 }
10144 ifname = token;
10145
10146 strlcpy(name, ifname, sizeof(name));
10147 ANDROID_INFO(("ifacename %s\n", name));
10148
10149 bytes_written = wl_get_ap_bw(dev, command, name, total_len);
10150 if (bytes_written < 1) {
10151 ANDROID_ERROR(("Failed to get bw, error = %d\n", bytes_written));
10152 return -EPROTO;
10153 }
10154
10155 return bytes_written;
10156
10157 }
10158 #endif /* SUPPORT_AP_BWCTRL */
10159
10160 static int
wl_android_priv_cmd_log_enable_check(char * cmd)10161 wl_android_priv_cmd_log_enable_check(char* cmd)
10162 {
10163 int cnt = 0;
10164
10165 while (strlen(loging_params[cnt].command) > 0) {
10166 if (!strnicmp(cmd, loging_params[cnt].command,
10167 strlen(loging_params[cnt].command))) {
10168 return loging_params[cnt].enable;
10169 }
10170
10171 cnt++;
10172 }
10173
10174 return FALSE;
10175 }
10176
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr)10177 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
10178 {
10179 #define PRIVATE_COMMAND_MAX_LEN 8192
10180 #define PRIVATE_COMMAND_DEF_LEN 4096
10181 int ret = 0;
10182 char *command = NULL;
10183 int bytes_written = 0;
10184 android_wifi_priv_cmd priv_cmd;
10185 int buf_size = 0;
10186 dhd_pub_t *dhd = dhd_get_pub(net);
10187
10188 net_os_wake_lock(net);
10189
10190 if (!capable(CAP_NET_ADMIN)) {
10191 ret = -EPERM;
10192 goto exit;
10193 }
10194
10195 if (!ifr->ifr_data) {
10196 ret = -EINVAL;
10197 goto exit;
10198 }
10199
10200 #ifdef CONFIG_COMPAT
10201 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
10202 if (in_compat_syscall())
10203 #else
10204 if (is_compat_task())
10205 #endif
10206 {
10207 compat_android_wifi_priv_cmd compat_priv_cmd;
10208 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
10209 sizeof(compat_android_wifi_priv_cmd))) {
10210 ret = -EFAULT;
10211 goto exit;
10212
10213 }
10214 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
10215 priv_cmd.used_len = compat_priv_cmd.used_len;
10216 priv_cmd.total_len = compat_priv_cmd.total_len;
10217 } else
10218 #endif /* CONFIG_COMPAT */
10219 {
10220 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
10221 ret = -EFAULT;
10222 goto exit;
10223 }
10224 }
10225 if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
10226 ANDROID_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
10227 priv_cmd.total_len));
10228 ret = -EINVAL;
10229 goto exit;
10230 }
10231
10232 buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
10233 command = (char *)MALLOC(dhd->osh, (buf_size + 1));
10234 if (!command) {
10235 ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
10236 ret = -ENOMEM;
10237 goto exit;
10238 }
10239 if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
10240 ret = -EFAULT;
10241 goto exit;
10242 }
10243 command[priv_cmd.total_len] = '\0';
10244
10245 if (wl_android_priv_cmd_log_enable_check(command)) {
10246 ANDROID_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__,
10247 command, ifr->ifr_name));
10248 }
10249 else {
10250 ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
10251
10252 }
10253
10254 bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
10255 if (bytes_written >= 0) {
10256 if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
10257 command[0] = '\0';
10258 }
10259 if (bytes_written >= priv_cmd.total_len) {
10260 ANDROID_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
10261 __FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
10262
10263 ret = BCME_BUFTOOSHORT;
10264 goto exit;
10265 }
10266 bytes_written++;
10267 priv_cmd.used_len = bytes_written;
10268 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
10269 ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
10270 ret = -EFAULT;
10271 }
10272 }
10273 else {
10274 /* Propagate the error */
10275 ret = bytes_written;
10276 }
10277
10278 exit:
10279 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
10280 if (ret) {
10281 /* Avoid incrementing priv_cmd_errors in case of unsupported feature */
10282 if (ret != BCME_UNSUPPORTED) {
10283 wl_android_check_priv_cmd_errors(net);
10284 }
10285 } else {
10286 priv_cmd_errors = 0;
10287 }
10288 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
10289 net_os_wake_unlock(net);
10290 MFREE(dhd->osh, command, (buf_size + 1));
10291 return ret;
10292 }
10293
10294 #ifdef WLADPS_PRIVATE_CMD
10295 static int
wl_android_set_adps_mode(struct net_device * dev,const char * string_num)10296 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
10297 {
10298 int err = 0, adps_mode;
10299 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10300 #ifdef DHD_PM_CONTROL_FROM_FILE
10301 if (g_pm_control) {
10302 return -EPERM;
10303 }
10304 #endif /* DHD_PM_CONTROL_FROM_FILE */
10305
10306 adps_mode = bcm_atoi(string_num);
10307 ANDROID_ERROR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
10308
10309 if (!(adps_mode == 0 || adps_mode == 1)) {
10310 ANDROID_ERROR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode));
10311 return -EINVAL;
10312 }
10313
10314 err = dhd_enable_adps(dhdp, adps_mode);
10315 if (err != BCME_OK) {
10316 ANDROID_ERROR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
10317 return -EIO;
10318 }
10319 return err;
10320 }
10321 static int
wl_android_get_adps_mode(struct net_device * dev,char * command,int total_len)10322 wl_android_get_adps_mode(
10323 struct net_device *dev, char *command, int total_len)
10324 {
10325 int bytes_written, err = 0;
10326 uint len;
10327 char buf[WLC_IOCTL_SMLEN];
10328
10329 bcm_iov_buf_t iov_buf;
10330 bcm_iov_buf_t *ptr = NULL;
10331 wl_adps_params_v1_t *data = NULL;
10332
10333 uint8 *pdata = NULL;
10334 uint8 band, mode = 0;
10335
10336 bzero(&iov_buf, sizeof(iov_buf));
10337
10338 len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
10339
10340 iov_buf.version = WL_ADPS_IOV_VER;
10341 iov_buf.len = sizeof(band);
10342 iov_buf.id = WL_ADPS_IOV_MODE;
10343
10344 pdata = (uint8 *)&iov_buf.data;
10345
10346 for (band = 1; band <= MAX_BANDS; band++) {
10347 pdata[0] = band;
10348 err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
10349 buf, WLC_IOCTL_SMLEN, NULL);
10350 if (err != BCME_OK) {
10351 ANDROID_ERROR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n",
10352 band, err));
10353 return -EIO;
10354 }
10355 ptr = (bcm_iov_buf_t *) buf;
10356 data = (wl_adps_params_v1_t *) ptr->data;
10357 mode = data->mode;
10358 if (mode != OFF) {
10359 break;
10360 }
10361 }
10362
10363 bytes_written = snprintf(command, total_len, "%s %d",
10364 CMD_GET_ADPS, mode);
10365 return bytes_written;
10366 }
10367
10368 #ifdef WLADPS_ENERGY_GAIN
10369 static int
wl_android_get_gain_adps(struct net_device * dev,char * command,int total_len)10370 wl_android_get_gain_adps(
10371 struct net_device *dev, char *command, int total_len)
10372 {
10373 int bytes_written;
10374
10375 int ret = 0;
10376 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10377
10378 ret = dhd_event_log_filter_adps_energy_gain(dhdp);
10379 if (ret < 0) {
10380 return ret;
10381 }
10382
10383 ANDROID_INFO(("%s ADPS Energy Gain: %d uAh\n", __FUNCTION__, ret));
10384
10385 bytes_written = snprintf(command, total_len, "%s %d uAm",
10386 CMD_GET_GAIN_ADPS, ret);
10387
10388 return bytes_written;
10389 }
10390
10391 static int
wl_android_reset_gain_adps(struct net_device * dev,char * command)10392 wl_android_reset_gain_adps(
10393 struct net_device *dev, char *command)
10394 {
10395 int ret = BCME_OK;
10396
10397 bcm_iov_buf_t iov_buf;
10398 char buf[WLC_IOCTL_SMLEN] = {0, };
10399
10400 iov_buf.version = WL_ADPS_IOV_VER;
10401 iov_buf.id = WL_ADPS_IOV_RESET_GAIN;
10402 iov_buf.len = 0;
10403
10404 if ((ret = wldev_iovar_setbuf(dev, "adps", &iov_buf, sizeof(iov_buf),
10405 buf, sizeof(buf), NULL)) < 0) {
10406 ANDROID_ERROR(("%s fail to reset adps gain (%d)\n", __FUNCTION__, ret));
10407 }
10408
10409 return ret;
10410 }
10411 #endif /* WLADPS_ENERGY_GAIN */
10412 #endif /* WLADPS_PRIVATE_CMD */
10413
10414 #ifdef WL_BCNRECV
10415 #define BCNRECV_ATTR_HDR_LEN 30
10416 int
wl_android_bcnrecv_event(struct net_device * ndev,uint attr_type,uint status,uint reason,uint8 * data,uint data_len)10417 wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
10418 uint status, uint reason, uint8 *data, uint data_len)
10419 {
10420 s32 err = BCME_OK;
10421 struct sk_buff *skb;
10422 gfp_t kflags;
10423 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10424 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10425 uint len;
10426
10427 len = BCNRECV_ATTR_HDR_LEN + data_len;
10428
10429 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10430 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
10431 BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
10432 if (!skb) {
10433 ANDROID_ERROR(("skb alloc failed"));
10434 return -ENOMEM;
10435 }
10436 if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
10437 /* send bcn info to upper layer */
10438 nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
10439 } else if (attr_type == BCNRECV_ATTR_STATUS) {
10440 nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
10441 if (reason) {
10442 nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
10443 }
10444 } else {
10445 ANDROID_ERROR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
10446 kfree_skb(skb);
10447 return -EINVAL;
10448 }
10449 cfg80211_vendor_event(skb, kflags);
10450 return err;
10451 }
10452
10453 static int
_wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool user_trigger)10454 _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
10455 {
10456 s32 err = BCME_OK;
10457 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10458
10459 /* check any scan is in progress before beacon recv scan trigger IOVAR */
10460 if (wl_get_drv_status_all(cfg, SCANNING)) {
10461 err = BCME_UNSUPPORTED;
10462 ANDROID_ERROR(("Scan in progress, Aborting beacon recv start, "
10463 "error:%d\n", err));
10464 goto exit;
10465 }
10466
10467 if (wl_get_p2p_status(cfg, SCANNING)) {
10468 err = BCME_UNSUPPORTED;
10469 ANDROID_ERROR(("P2P Scan in progress, Aborting beacon recv start, "
10470 "error:%d\n", err));
10471 goto exit;
10472 }
10473
10474 if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
10475 err = BCME_UNSUPPORTED;
10476 ANDROID_ERROR(("P2P remain on channel, Aborting beacon recv start, "
10477 "error:%d\n", err));
10478 goto exit;
10479 }
10480
10481 /* check STA is in connected state, Beacon recv required connected state
10482 * else exit from beacon recv scan
10483 */
10484 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
10485 err = BCME_UNSUPPORTED;
10486 ANDROID_ERROR(("STA is in not associated state error:%d\n", err));
10487 goto exit;
10488 }
10489
10490 #ifdef WL_NAN
10491 /* Check NAN is enabled, if enabled exit else continue */
10492 if (wl_cfgnan_is_enabled(cfg)) {
10493 err = BCME_UNSUPPORTED;
10494 ANDROID_ERROR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
10495 goto exit;
10496 }
10497 #endif /* WL_NAN */
10498
10499 /* Triggering an sendup_bcn iovar */
10500 err = wldev_iovar_setint(pdev, "sendup_bcn", 1);
10501 if (unlikely(err)) {
10502 ANDROID_ERROR(("sendup_bcn failed to set, error:%d\n", err));
10503 } else {
10504 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
10505 ANDROID_INFO(("bcnrecv started. user_trigger:%d ifindex:%d\n",
10506 user_trigger, ndev->ifindex));
10507 if (user_trigger) {
10508 if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS,
10509 WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
10510 ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10511 }
10512 }
10513 }
10514 exit:
10515 /*
10516 * BCNRECV start request can be rejected from dongle
10517 * in various conditions.
10518 * Error code need to be overridden to BCME_UNSUPPORTED
10519 * to avoid hang event from continous private
10520 * command error
10521 */
10522 if (err) {
10523 err = BCME_UNSUPPORTED;
10524 }
10525 return err;
10526 }
10527
10528 int
_wl_android_bcnrecv_stop(struct bcm_cfg80211 * cfg,struct net_device * ndev,uint reason)10529 _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
10530 {
10531 s32 err = BCME_OK;
10532 u32 status;
10533 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10534
10535 /* Stop bcnrx except for fw abort event case */
10536 if (reason != WL_BCNRECV_ROAMABORT) {
10537 err = wldev_iovar_setint(pdev, "sendup_bcn", 0);
10538 if (unlikely(err)) {
10539 ANDROID_ERROR(("sendup_bcn failed to set error:%d\n", err));
10540 goto exit;
10541 }
10542 }
10543
10544 /* Send notification for all cases */
10545 if (reason == WL_BCNRECV_SUSPEND) {
10546 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
10547 status = WL_BCNRECV_SUSPENDED;
10548 } else {
10549 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
10550 ANDROID_INFO(("bcnrecv stopped. reason:%d ifindex:%d\n",
10551 reason, ndev->ifindex));
10552 if (reason == WL_BCNRECV_USER_TRIGGER) {
10553 status = WL_BCNRECV_STOPPED;
10554 } else {
10555 status = WL_BCNRECV_ABORTED;
10556 }
10557 }
10558 if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, status,
10559 reason, NULL, 0)) != BCME_OK) {
10560 ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10561 }
10562 exit:
10563 return err;
10564 }
10565
10566 static int
wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev)10567 wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
10568 {
10569 s32 err = BCME_OK;
10570
10571 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10572 mutex_lock(&cfg->scan_sync);
10573 mutex_lock(&cfg->bcn_sync);
10574 err = _wl_android_bcnrecv_start(cfg, ndev, true);
10575 mutex_unlock(&cfg->bcn_sync);
10576 mutex_unlock(&cfg->scan_sync);
10577 return err;
10578 }
10579
10580 int
wl_android_bcnrecv_stop(struct net_device * ndev,uint reason)10581 wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
10582 {
10583 s32 err = BCME_OK;
10584 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10585
10586 mutex_lock(&cfg->bcn_sync);
10587 if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
10588 (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
10589 err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
10590 }
10591 mutex_unlock(&cfg->bcn_sync);
10592 return err;
10593 }
10594
10595 int
wl_android_bcnrecv_suspend(struct net_device * ndev)10596 wl_android_bcnrecv_suspend(struct net_device *ndev)
10597 {
10598 s32 ret = BCME_OK;
10599 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10600
10601 mutex_lock(&cfg->bcn_sync);
10602 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
10603 ANDROID_INFO(("bcnrecv suspend\n"));
10604 ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
10605 }
10606 mutex_unlock(&cfg->bcn_sync);
10607 return ret;
10608 }
10609
10610 int
wl_android_bcnrecv_resume(struct net_device * ndev)10611 wl_android_bcnrecv_resume(struct net_device *ndev)
10612 {
10613 s32 ret = BCME_OK;
10614 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10615
10616 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10617 mutex_lock(&cfg->scan_sync);
10618 mutex_lock(&cfg->bcn_sync);
10619 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
10620 ANDROID_INFO(("bcnrecv resume\n"));
10621 ret = _wl_android_bcnrecv_start(cfg, ndev, false);
10622 }
10623 mutex_unlock(&cfg->bcn_sync);
10624 mutex_unlock(&cfg->scan_sync);
10625 return ret;
10626 }
10627
10628 /* Beacon recv functionality code implementation */
10629 int
wl_android_bcnrecv_config(struct net_device * ndev,char * cmd_argv,int total_len)10630 wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
10631 {
10632 struct bcm_cfg80211 *cfg = NULL;
10633 uint err = BCME_OK;
10634
10635 if (!ndev) {
10636 ANDROID_ERROR(("ndev is NULL\n"));
10637 return -EINVAL;
10638 }
10639
10640 cfg = wl_get_cfg(ndev);
10641 if (!cfg) {
10642 ANDROID_ERROR(("cfg is NULL\n"));
10643 return -EINVAL;
10644 }
10645
10646 /* sync commands from user space */
10647 mutex_lock(&cfg->usr_sync);
10648 if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
10649 ANDROID_INFO(("BCNRECV start\n"));
10650 err = wl_android_bcnrecv_start(cfg, ndev);
10651 if (err != BCME_OK) {
10652 ANDROID_ERROR(("Failed to process the start command, error:%d\n", err));
10653 goto exit;
10654 }
10655 } else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
10656 ANDROID_INFO(("BCNRECV stop\n"));
10657 err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
10658 if (err != BCME_OK) {
10659 ANDROID_ERROR(("Failed to stop the bcn recv, error:%d\n", err));
10660 goto exit;
10661 }
10662 } else {
10663 err = BCME_ERROR;
10664 }
10665 exit:
10666 mutex_unlock(&cfg->usr_sync);
10667 return err;
10668 }
10669 #endif /* WL_BCNRECV */
10670
10671 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
10672 static int
wl_android_set_latency_crt_data(struct net_device * dev,int mode)10673 wl_android_set_latency_crt_data(struct net_device *dev, int mode)
10674 {
10675 int ret;
10676 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10677 dhd_pub_t *dhdp = NULL;
10678 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10679 if (mode >= LATENCY_CRT_DATA_MODE_LAST) {
10680 return BCME_BADARG;
10681 }
10682 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10683 dhdp = wl_cfg80211_get_dhdp(dev);
10684 if (mode != LATENCY_CRT_DATA_MODE_OFF) {
10685 ANDROID_ERROR(("Not permitted GRO by framework\n"));
10686 dhdp->permitted_gro = FALSE;
10687 } else {
10688 ANDROID_ERROR(("Permitted GRO by framework\n"));
10689 dhdp->permitted_gro = TRUE;
10690 }
10691 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10692 ret = wldev_iovar_setint(dev, "latency_critical_data", mode);
10693 if (ret != BCME_OK) {
10694 ANDROID_ERROR(("failed to set latency_critical_data mode %d, error = %d\n",
10695 mode, ret));
10696 return ret;
10697 }
10698
10699 return ret;
10700 }
10701
10702 static int
wl_android_get_latency_crt_data(struct net_device * dev,char * command,int total_len)10703 wl_android_get_latency_crt_data(struct net_device *dev, char *command, int total_len)
10704 {
10705 int ret;
10706 int mode = LATENCY_CRT_DATA_MODE_OFF;
10707 int bytes_written;
10708
10709 ret = wldev_iovar_getint(dev, "latency_critical_data", &mode);
10710 if (ret != BCME_OK) {
10711 ANDROID_ERROR(("failed to get latency_critical_data error = %d\n", ret));
10712 return ret;
10713 }
10714
10715 bytes_written = snprintf(command, total_len, "%s %d",
10716 CMD_GET_LATENCY_CRITICAL_DATA, mode);
10717
10718 return bytes_written;
10719 }
10720 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
10721
10722 #ifdef WL_CAC_TS
10723 /* CAC TSPEC functionality code implementation */
10724 static void
wl_android_update_tsinfo(uint8 access_category,tspec_arg_t * tspec_arg)10725 wl_android_update_tsinfo(uint8 access_category, tspec_arg_t *tspec_arg)
10726 {
10727 uint8 tspec_id;
10728 /* Using direction as bidirectional by default */
10729 uint8 direction = TSPEC_BI_DIRECTION;
10730 /* Using U-APSD as the default power save mode */
10731 uint8 user_psb = TSPEC_UAPSD_PSB;
10732 uint8 ADDTS_AC2PRIO[4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI, PRIO_8021D_VO};
10733
10734 /* Map tspec_id from access category */
10735 tspec_id = ADDTS_AC2PRIO[access_category];
10736
10737 /* Update the tsinfo */
10738 tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
10739 (tspec_id << TSPEC_TSINFO_TID_SHIFT));
10740 tspec_arg->tsinfo.octets[1] = (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) |
10741 user_psb);
10742 tspec_arg->tsinfo.octets[2] = 0x00;
10743 }
10744
10745 static s32
wl_android_handle_cac_action(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * argv)10746 wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev, char * argv)
10747 {
10748 tspec_arg_t tspec_arg;
10749 s32 err = BCME_ERROR;
10750 u8 ts_cmd[12] = "cac_addts";
10751 uint8 access_category;
10752 s32 bssidx;
10753
10754 /* Following handling is done only for the primary interface */
10755 memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
10756 if (strncmp(argv, "addts", strlen("addts")) == 0) {
10757 tspec_arg.version = TSPEC_ARG_VERSION;
10758 tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10759 /* Read the params passed */
10760 sscanf(argv, "%*s %hhu %hu %hu", &access_category,
10761 &tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
10762 if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
10763 ((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
10764 (tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
10765 (tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
10766 ANDROID_ERROR(("Invalid params access_category %hhu nom_msdu_size %hu"
10767 " surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size,
10768 tspec_arg.surplus_bw));
10769 return BCME_USAGE_ERROR;
10770 }
10771
10772 /* Update tsinfo */
10773 wl_android_update_tsinfo(access_category, &tspec_arg);
10774 /* Update other tspec parameters */
10775 tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
10776 tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
10777 tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
10778 } else if (strncmp(argv, "delts", strlen("delts")) == 0) {
10779 snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
10780 tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10781 tspec_arg.version = TSPEC_ARG_VERSION;
10782 /* Read the params passed */
10783 sscanf(argv, "%*s %hhu", &access_category);
10784
10785 if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
10786 ANDROID_INFO(("Invalide param, access_category %hhu\n", access_category));
10787 return BCME_USAGE_ERROR;
10788 }
10789 /* Update tsinfo */
10790 wl_android_update_tsinfo(access_category, &tspec_arg);
10791 }
10792
10793 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
10794 ANDROID_ERROR(("Find index failed\n"));
10795 err = BCME_ERROR;
10796 return err;
10797 }
10798 err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
10799 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
10800 if (unlikely(err)) {
10801 ANDROID_ERROR(("%s error (%d)\n", ts_cmd, err));
10802 }
10803
10804 return err;
10805 }
10806
10807 static s32
wl_android_cac_ts_config(struct net_device * ndev,char * cmd_argv,int total_len)10808 wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len)
10809 {
10810 struct bcm_cfg80211 *cfg = NULL;
10811 s32 err = BCME_OK;
10812
10813 if (!ndev) {
10814 ANDROID_ERROR(("ndev is NULL\n"));
10815 return -EINVAL;
10816 }
10817
10818 cfg = wl_get_cfg(ndev);
10819 if (!cfg) {
10820 ANDROID_ERROR(("cfg is NULL\n"));
10821 return -EINVAL;
10822 }
10823
10824 /* Request supported only for primary interface */
10825 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
10826 ANDROID_ERROR(("Request on non-primary interface\n"));
10827 return -1;
10828 }
10829
10830 /* sync commands from user space */
10831 mutex_lock(&cfg->usr_sync);
10832 err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
10833 mutex_unlock(&cfg->usr_sync);
10834
10835 return err;
10836 }
10837 #endif /* WL_CAC_TS */
10838
10839 #ifdef WL_GET_CU
10840 /* Implementation to get channel usage from framework */
10841 static s32
wl_android_get_channel_util(struct net_device * ndev,char * command,int total_len)10842 wl_android_get_channel_util(struct net_device *ndev, char *command, int total_len)
10843 {
10844 s32 bytes_written, err = 0;
10845 wl_bssload_t bssload;
10846 u8 smbuf[WLC_IOCTL_SMLEN];
10847 u8 chan_use_percentage = 0;
10848
10849 if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL,
10850 0, smbuf, WLC_IOCTL_SMLEN, NULL))) {
10851 ANDROID_ERROR(("Getting bssload report failed with err=%d \n", err));
10852 return err;
10853 }
10854
10855 (void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
10856 /* Convert channel usage to percentage value */
10857 chan_use_percentage = (bssload.chan_util * 100) / 255;
10858
10859 bytes_written = snprintf(command, total_len, "CU %hhu",
10860 chan_use_percentage);
10861 ANDROID_INFO(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage));
10862
10863 return bytes_written;
10864 }
10865 #endif /* WL_GET_CU */
10866
10867 #ifdef RTT_GEOFENCE_INTERVAL
10868 #if defined (RTT_SUPPORT) && defined(WL_NAN)
10869 static void
wl_android_set_rtt_geofence_interval(struct net_device * ndev,char * command)10870 wl_android_set_rtt_geofence_interval(struct net_device *ndev, char *command)
10871 {
10872 int rtt_interval = 0;
10873 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
10874 char *rtt_intp = command + strlen(CMD_GEOFENCE_INTERVAL) + 1;
10875
10876 rtt_interval = bcm_atoi(rtt_intp);
10877 dhd_rtt_set_geofence_rtt_interval(dhdp, rtt_interval);
10878 }
10879 #endif /* RTT_SUPPORT && WL_NAN */
10880 #endif /* RTT_GEOFENCE_INTERVAL */
10881
10882 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
10883 int
wl_android_set_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10884 wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10885 {
10886 char *ifname = NULL;
10887 char *pos, *token;
10888 int err = BCME_OK;
10889 int enable = FALSE;
10890
10891 /*
10892 * STA/AP/GO I/F: DRIVER SET_SOFTAP_ELNA_BYPASS <ifname> <enable/disable>
10893 * the enable/disable format follows Samsung specific rules as following
10894 * Enable : 0
10895 * Disable :-1
10896 */
10897 pos = command;
10898
10899 /* drop command */
10900 token = bcmstrtok(&pos, " ", NULL);
10901
10902 /* get the interface name */
10903 token = bcmstrtok(&pos, " ", NULL);
10904 if (!token) {
10905 ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10906 return -EINVAL;
10907 }
10908 ifname = token;
10909
10910 /* get enable/disable flag */
10911 token = bcmstrtok(&pos, " ", NULL);
10912 if (!token) {
10913 ANDROID_ERROR(("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__));
10914 return -EINVAL;
10915 }
10916 enable = bcm_atoi(token);
10917
10918 CUSTOMER_HW4_EN_CONVERT(enable);
10919 err = wl_set_softap_elna_bypass(dev, ifname, enable);
10920 if (unlikely(err)) {
10921 ANDROID_ERROR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n",
10922 __FUNCTION__, err));
10923 return err;
10924 }
10925
10926 return err;
10927 }
10928
10929 int
wl_android_get_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10930 wl_android_get_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10931 {
10932 char *ifname = NULL;
10933 char *pos, *token;
10934 int err = BCME_OK;
10935 int bytes_written = 0;
10936 int softap_elnabypass = 0;
10937
10938 /*
10939 * STA/AP/GO I/F: DRIVER GET_SOFTAP_ELNA_BYPASS <ifname>
10940 */
10941 pos = command;
10942
10943 /* drop command */
10944 token = bcmstrtok(&pos, " ", NULL);
10945
10946 /* get the interface name */
10947 token = bcmstrtok(&pos, " ", NULL);
10948 if (!token) {
10949 ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10950 return -EINVAL;
10951 }
10952 ifname = token;
10953
10954 err = wl_get_softap_elna_bypass(dev, ifname, &softap_elnabypass);
10955 if (unlikely(err)) {
10956 ANDROID_ERROR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n",
10957 __FUNCTION__, err));
10958 return err;
10959 } else {
10960 softap_elnabypass--; //Convert format to Customer HW4
10961 ANDROID_INFO(("%s: eLNA Bypass feature enable status is %d\n",
10962 __FUNCTION__, softap_elnabypass));
10963 bytes_written = snprintf(command, total_len, "%s %d",
10964 CMD_GET_SOFTAP_ELNA_BYPASS, softap_elnabypass);
10965 }
10966
10967 return bytes_written;
10968 }
10969 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
10970
10971 #ifdef WL_NAN
10972 int
wl_android_get_nan_status(struct net_device * dev,char * command,int total_len)10973 wl_android_get_nan_status(struct net_device *dev, char *command, int total_len)
10974 {
10975 int bytes_written = 0;
10976 int error = BCME_OK;
10977 wl_nan_conf_status_t nstatus;
10978
10979 error = wl_cfgnan_get_status(dev, &nstatus);
10980 if (error) {
10981 ANDROID_ERROR(("Failed to get nan status (%d)\n", error));
10982 return error;
10983 }
10984
10985 bytes_written = snprintf(command, total_len,
10986 "EN:%d Role:%d EM:%d CID:"MACF" NMI:"MACF" SC(2G):%d SC(5G):%d "
10987 "MR:"NMRSTR" AMR:"NMRSTR" IMR:"NMRSTR
10988 "HC:%d AMBTT:%04x TSF[%04x:%04x]\n",
10989 nstatus.enabled,
10990 nstatus.role,
10991 nstatus.election_mode,
10992 ETHERP_TO_MACF(&(nstatus.cid)),
10993 ETHERP_TO_MACF(&(nstatus.nmi)),
10994 nstatus.social_chans[0],
10995 nstatus.social_chans[1],
10996 NMR2STR(nstatus.mr),
10997 NMR2STR(nstatus.amr),
10998 NMR2STR(nstatus.imr),
10999 nstatus.hop_count,
11000 nstatus.ambtt,
11001 nstatus.cluster_tsf_h,
11002 nstatus.cluster_tsf_l);
11003 return bytes_written;
11004 }
11005 #endif /* WL_NAN */
11006
11007 #ifdef SUPPORT_NAN_RANGING_TEST_BW
11008 enum {
11009 NAN_RANGING_5G_BW20 = 1,
11010 NAN_RANGING_5G_BW40,
11011 NAN_RANGING_5G_BW80
11012 };
11013
11014 int
wl_nan_ranging_bw(struct net_device * net,int bw,char * command)11015 wl_nan_ranging_bw(struct net_device *net, int bw, char *command)
11016 {
11017 int bytes_written, err = BCME_OK;
11018 u8 ioctl_buf[WLC_IOCTL_SMLEN];
11019 s32 val = 1;
11020 struct {
11021 u32 band;
11022 u32 bw_cap;
11023 } param = {0, 0};
11024
11025 if (bw < NAN_RANGING_5G_BW20 || bw > NAN_RANGING_5G_BW80) {
11026 ANDROID_ERROR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__));
11027 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11028 return bytes_written;
11029 }
11030
11031 switch (bw) {
11032 case NAN_RANGING_5G_BW20:
11033 ANDROID_ERROR(("NAN_RANGING 5G/BW20\n"));
11034 param.band = WLC_BAND_5G;
11035 param.bw_cap = 0x1;
11036 break;
11037 case NAN_RANGING_5G_BW40:
11038 ANDROID_ERROR(("NAN_RANGING 5G/BW40\n"));
11039 param.band = WLC_BAND_5G;
11040 param.bw_cap = 0x3;
11041 break;
11042 case NAN_RANGING_5G_BW80:
11043 ANDROID_ERROR(("NAN_RANGING 5G/BW80\n"));
11044 param.band = WLC_BAND_5G;
11045 param.bw_cap = 0x7;
11046 break;
11047 }
11048
11049 err = wldev_ioctl_set(net, WLC_DOWN, &val, sizeof(s32));
11050 if (err) {
11051 ANDROID_ERROR(("WLC_DOWN error %d\n", err));
11052 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11053 } else {
11054 err = wldev_iovar_setbuf(net, "bw_cap", ¶m, sizeof(param),
11055 ioctl_buf, sizeof(ioctl_buf), NULL);
11056
11057 if (err) {
11058 ANDROID_ERROR(("BW set failed\n"));
11059 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11060 } else {
11061 ANDROID_ERROR(("BW set done\n"));
11062 bytes_written = scnprintf(command, sizeof("OK"), "OK");
11063 }
11064
11065 err = wldev_ioctl_set(net, WLC_UP, &val, sizeof(s32));
11066 if (err < 0) {
11067 ANDROID_ERROR(("WLC_UP error %d\n", err));
11068 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11069 }
11070 }
11071 return bytes_written;
11072 }
11073 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
11074
11075 static int
wl_android_set_softap_ax_mode(struct net_device * dev,const char * cmd_str)11076 wl_android_set_softap_ax_mode(struct net_device *dev, const char* cmd_str)
11077 {
11078 int enable = 0;
11079 int err = 0;
11080 s32 bssidx = 0;
11081 struct bcm_cfg80211 *cfg = NULL;
11082
11083 if (!dev) {
11084 err = -EINVAL;
11085 goto exit;
11086 }
11087
11088 cfg = wl_get_cfg(dev);
11089 if (!cfg) {
11090 err = -EINVAL;
11091 goto exit;
11092 }
11093
11094 if (cmd_str) {
11095 enable = bcm_atoi(cmd_str);
11096 } else {
11097 ANDROID_ERROR(("failed due to wrong received parameter\n"));
11098 err = -EINVAL;
11099 goto exit;
11100 }
11101
11102 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11103 ANDROID_ERROR(("find softap index from wdev failed\n"));
11104 err = -EINVAL;
11105 goto exit;
11106 }
11107
11108 ANDROID_INFO(("HAPD_SET_AX_MODE = %d\n", enable));
11109 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, (bool)enable);
11110 if (err) {
11111 ANDROID_ERROR(("failed to set softap ax mode(%d)\n", enable));
11112
11113 }
11114 exit :
11115 return err;
11116 }
11117
11118 #ifdef WL_P2P_6G
11119 #define WL_HE_FEATURES_P2P_6G 0x0200u
11120 static int
wl_android_enable_p2p_6g(struct net_device * dev,int enable)11121 wl_android_enable_p2p_6g(struct net_device *dev, int enable)
11122 {
11123 s32 err = 0;
11124 s32 bssidx = 0;
11125 struct bcm_cfg80211 *cfg = NULL;
11126
11127 if (!dev) {
11128 err = -EINVAL;
11129 return err;
11130 }
11131
11132 cfg = wl_get_cfg(dev);
11133 if (!cfg) {
11134 err = -EINVAL;
11135 return err;
11136 }
11137
11138 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11139 ANDROID_ERROR(("find softap index from wdev failed\n"));
11140 err = -EINVAL;
11141 return err;
11142 }
11143
11144 /* Enable/disable for P2P 6G, both P2P and P2P_6G needs to be handled together */
11145 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, (WL_HE_FEATURES_HE_P2P |
11146 WL_HE_FEATURES_P2P_6G), (bool)enable);
11147 if (err == BCME_OK) {
11148 /* Set P2P 6G support flag */
11149 if (enable) {
11150 cfg->p2p_6g_enabled = TRUE;
11151 } else {
11152 cfg->p2p_6g_enabled = FALSE;
11153 }
11154 }
11155
11156 return err;
11157 }
11158 #endif /* WL_P2P_6G */
11159
11160 #ifdef WL_TWT
11161
11162 static int
wl_android_twt_setup(struct net_device * ndev,char * command,int total_len)11163 wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
11164 {
11165 wl_twt_config_t val;
11166 s32 bw;
11167 char *token, *pos;
11168 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11169 u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
11170 u64 twt;
11171 uint8 *rem = mybuf;
11172 uint16 rem_len = sizeof(mybuf);
11173 int32 val32;
11174
11175 WL_DBG_MEM(("Enter. cmd:%s\n", command));
11176
11177 if (strlen(command) == strlen(CMD_TWT_SETUP)) {
11178 ANDROID_ERROR(("Error, twt_setup cmd missing params\n"));
11179 bw = -EINVAL;
11180 goto exit;
11181 }
11182
11183 bzero(&val, sizeof(val));
11184 val.version = WL_TWT_SETUP_VER;
11185 val.length = sizeof(val.version) + sizeof(val.length);
11186
11187 /* Default values, Overide Below */
11188 val.desc.wake_time_h = 0xFFFFFFFF;
11189 val.desc.wake_time_l = 0xFFFFFFFF;
11190 val.desc.wake_int_min = 0xFFFFFFFF;
11191 val.desc.wake_int_max = 0xFFFFFFFF;
11192 val.desc.wake_dur_min = 0xFFFFFFFF;
11193 val.desc.wake_dur_max = 0xFFFFFFFF;
11194 val.desc.avg_pkt_num = 0xFFFFFFFF;
11195
11196 pos = command + sizeof(CMD_TWT_SETUP);
11197
11198 /* negotiation_type */
11199 token = strsep((char**)&pos, " ");
11200 if (!token) {
11201 ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11202 bw = -EINVAL;
11203 goto exit;
11204 }
11205 val.desc.negotiation_type = htod32((u32)bcm_atoi(token));
11206
11207 /* Wake Duration */
11208 token = strsep((char**)&pos, " ");
11209 if (!token) {
11210 ANDROID_ERROR(("Mandatory param wake Duration not present\n"));
11211 bw = -EINVAL;
11212 goto exit;
11213 }
11214 val.desc.wake_dur = htod32((u32)bcm_atoi(token));
11215
11216 /* Wake interval */
11217 token = strsep((char**)&pos, " ");
11218 if (!token) {
11219 ANDROID_ERROR(("Mandaory param Wake Interval not present\n"));
11220 bw = -EINVAL;
11221 goto exit;
11222 }
11223 val.desc.wake_int = htod32((u32)bcm_atoi(token));
11224
11225 /* Wake Time parameter */
11226 token = strsep((char**)&pos, " ");
11227 if (!token) {
11228 ANDROID_ERROR(("No Wake Time parameter provided, using default\n"));
11229 } else {
11230 twt = (u64)bcm_atoi(token);
11231 val32 = htod32((u32)(twt >> 32));
11232 if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11233 val.desc.wake_time_h = htod32((u32)(twt >> 32));
11234 val.desc.wake_time_l = htod32((u32)twt);
11235 }
11236 }
11237
11238 /* Minimum allowed Wake interval */
11239 token = strsep((char**)&pos, " ");
11240 if (!token) {
11241 ANDROID_ERROR(("No Minimum allowed Wake interval provided, using default\n"));
11242 } else {
11243 val32 = htod32((u32)bcm_atoi(token));
11244 if (val32 != -1) {
11245 val.desc.wake_int_min = htod32((u32)bcm_atoi(token));
11246 }
11247 }
11248
11249 /* Max Allowed Wake interval */
11250 token = strsep((char**)&pos, " ");
11251 if (!token) {
11252 ANDROID_ERROR(("Maximum allowed Wake interval not provided, using default\n"));
11253 } else {
11254 val32 = htod32((u32)bcm_atoi(token));
11255 if (val32 != -1) {
11256 val.desc.wake_int_max = htod32((u32)bcm_atoi(token));
11257 }
11258 }
11259
11260 /* Minimum allowed Wake duration */
11261 token = strsep((char**)&pos, " ");
11262 if (!token) {
11263 ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
11264 } else {
11265 val32 = htod32((u32)bcm_atoi(token));
11266 if (val32 != -1) {
11267 val.desc.wake_dur_min = htod32((u32)bcm_atoi(token));
11268 }
11269 }
11270
11271 /* Maximum allowed Wake duration */
11272 token = strsep((char**)&pos, " ");
11273 if (!token) {
11274 ANDROID_ERROR(("Maximum allowed Wake duration not provided, using default\n"));
11275 } else {
11276 val32 = htod32((u32)bcm_atoi(token));
11277 if (val32 != -1) {
11278 val.desc.wake_dur_max = htod32((u32)bcm_atoi(token));
11279 }
11280 }
11281
11282 /* Average number of packets */
11283 token = strsep((char**)&pos, " ");
11284 if (!token) {
11285 ANDROID_ERROR(("Average number of packets not provided, using default\n"));
11286 } else {
11287 val32 = htod32((u32)bcm_atoi(token));
11288 if (val32 != -1) {
11289 val.desc.avg_pkt_num = htod32((u32)bcm_atoi(token));
11290 }
11291 }
11292
11293 /* a peer_address */
11294 token = strsep((char**)&pos, " ");
11295 if (!token) {
11296 ANDROID_ERROR(("Average number of packets not provided, using default\n"));
11297 } else {
11298 /* get peer mac */
11299 if (!bcm_ether_atoe(token, &val.peer)) {
11300 ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11301 bw = BCME_ERROR;
11302 goto exit;
11303 }
11304 }
11305
11306 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
11307 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11308 if (bw != BCME_OK) {
11309 goto exit;
11310 }
11311
11312 bw = wldev_iovar_setbuf(ndev, "twt",
11313 mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
11314 if (bw < 0) {
11315 ANDROID_ERROR(("twt config set failed. ret:%d\n", bw));
11316 }
11317 exit:
11318 return bw;
11319 }
11320
11321 static int
wl_android_twt_display_cap(wl_twt_cap_t * result,char * command,int total_len)11322 wl_android_twt_display_cap(wl_twt_cap_t *result, char *command, int total_len)
11323 {
11324 int rem_len = 0, bytes_written = 0;
11325
11326 rem_len = total_len;
11327 bytes_written = scnprintf(command, rem_len, "Device TWT Capabilities:\n");
11328 command += bytes_written;
11329 rem_len -= bytes_written;
11330
11331 bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11332 !!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11333 command += bytes_written;
11334 rem_len -= bytes_written;
11335
11336 bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11337 !!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11338 command += bytes_written;
11339 rem_len -= bytes_written;
11340
11341 bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11342 !!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11343 command += bytes_written;
11344 rem_len -= bytes_written;
11345
11346 bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11347 !!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11348 command += bytes_written;
11349 rem_len -= bytes_written;
11350
11351 bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11352 !!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11353 command += bytes_written;
11354 rem_len -= bytes_written;
11355
11356 /* Peer capabilities */
11357 bytes_written = scnprintf(command, rem_len, "\nPeer TWT Capabilities:\n");
11358 command += bytes_written;
11359 rem_len -= bytes_written;
11360
11361 bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11362 !!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11363 command += bytes_written;
11364 rem_len -= bytes_written;
11365
11366 bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11367 !!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11368 command += bytes_written;
11369 rem_len -= bytes_written;
11370
11371 bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11372 !!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11373 command += bytes_written;
11374 rem_len -= bytes_written;
11375
11376 bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11377 !!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11378 command += bytes_written;
11379 rem_len -= bytes_written;
11380
11381 bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11382 !!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11383 command += bytes_written;
11384 rem_len -= bytes_written;
11385
11386 bytes_written = scnprintf(command, rem_len, "\t------------"
11387 "---------------------------------------------------\n\n");
11388 command += bytes_written;
11389 rem_len -= bytes_written;
11390 ANDROID_INFO(("Device TWT Capabilities:\n"));
11391 ANDROID_INFO(("Requester Support %d, \t",
11392 !!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11393 ANDROID_INFO(("Responder Support %d, \t",
11394 !!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11395 ANDROID_INFO(("Broadcast TWT Support %d, \t",
11396 !!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11397 ANDROID_INFO(("Flexible TWT Support %d, \t",
11398 !!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11399 ANDROID_INFO(("TWT Required by peer %d, \n",
11400 !!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11401 /* Peer capabilities */
11402 ANDROID_INFO(("\nPeer TWT Capabilities:\n"));
11403 ANDROID_INFO(("Requester Support %d, \t",
11404 !!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11405 ANDROID_INFO(("Responder Support %d, \t",
11406 !!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11407 ANDROID_INFO(("Broadcast TWT Support %d, \t",
11408 !!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11409 ANDROID_INFO(("Flexible TWT Support %d, \t",
11410 !!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11411 ANDROID_INFO(("TWT Required by peer %d, \n",
11412 !!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11413 ANDROID_INFO(("\t-----------------------------------------------------------------\n\n"));
11414
11415 if ((total_len - rem_len) > 0) {
11416 return (total_len - rem_len);
11417 } else {
11418 return BCME_ERROR;
11419 }
11420 }
11421
11422 static int
wl_android_twt_cap(struct net_device * dev,char * command,int total_len)11423 wl_android_twt_cap(struct net_device *dev, char *command, int total_len)
11424 {
11425 int ret = BCME_OK;
11426 char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11427 uint8 *pxtlv = NULL;
11428 uint8 *iovresp = NULL;
11429 wl_twt_cap_cmd_t cmd_cap;
11430 wl_twt_cap_t result;
11431
11432 uint16 buflen = 0, bufstart = 0;
11433 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11434
11435 bzero(&cmd_cap, sizeof(cmd_cap));
11436
11437 cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
11438 cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
11439
11440 iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11441 if (iovresp == NULL) {
11442 ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11443 goto exit;
11444 }
11445
11446 buflen = bufstart = WLC_IOCTL_SMLEN;
11447 pxtlv = (uint8 *)iovbuf;
11448
11449 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
11450 sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
11451 if (ret != BCME_OK) {
11452 ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11453 goto exit;
11454 }
11455
11456 if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11457 iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11458 ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11459 goto exit;
11460 }
11461 if (ret) {
11462 ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11463 }
11464
11465 (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11466
11467 if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
11468 ANDROID_ERROR(("capability ver %d, \n", dtoh16(result.version)));
11469 ret = wl_android_twt_display_cap(&result, command, total_len);
11470 return ret;
11471 } else {
11472 ret = BCME_UNSUPPORTED;
11473 ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11474 goto exit;
11475 }
11476
11477 exit:
11478 if (iovresp) {
11479 MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11480 }
11481
11482 return ret;
11483 }
11484
11485 static int
wl_android_twt_status_display_v1(wl_twt_status_v1_t * status,char * command,int total_len)11486 wl_android_twt_status_display_v1(wl_twt_status_v1_t *status, char *command, int total_len)
11487 {
11488 uint i;
11489 wl_twt_sdesc_t *desc = NULL;
11490 int rem_len = 0, bytes_written = 0;
11491
11492 rem_len = total_len;
11493
11494 ANDROID_ERROR(("\nNumber of Individual TWTs: %d\n", status->num_fid));
11495 bytes_written = scnprintf(command, rem_len,
11496 "\nNumber of Individual TWTs: %d\n", status->num_fid);
11497 command += bytes_written;
11498 rem_len -= bytes_written;
11499 bytes_written = scnprintf(command, rem_len,
11500 "Number of Broadcast TWTs: %d\n", status->num_bid);
11501 command += bytes_written;
11502 rem_len -= bytes_written;
11503 bytes_written = scnprintf(command, rem_len,
11504 "TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11505 !!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11506 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11507 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE));
11508 command += bytes_written;
11509 rem_len -= bytes_written;
11510 ANDROID_INFO(("Number of Broadcast TWTs: %d\n", status->num_bid));
11511 ANDROID_INFO(("TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11512 !!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11513 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11514 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE)));
11515 ANDROID_INFO(("\t---------------- Individual TWT list-------------------\n"));
11516 bytes_written = scnprintf(command, rem_len,
11517 "\t---------------- Individual TWT list-------------------\n");
11518 command += bytes_written;
11519 rem_len -= bytes_written;
11520
11521 for (i = 0; i < WL_TWT_MAX_ITWT; i ++) {
11522 if ((status->itwt_status[i].state == WL_TWT_ACTIVE) ||
11523 (status->itwt_status[i].state == WL_TWT_SUSPEND)) {
11524 desc = &status->itwt_status[i].desc;
11525 bytes_written = scnprintf(command, rem_len, "\tFlow ID %d \tState %d\t",
11526 desc->flow_id,
11527 status->itwt_status[i].state);
11528 command += bytes_written;
11529 rem_len -= bytes_written;
11530
11531 bytes_written = scnprintf(command, rem_len,
11532 "peer: "MACF"\n",
11533 ETHER_TO_MACF(status->itwt_status[i].peer));
11534 command += bytes_written;
11535 rem_len -= bytes_written;
11536
11537 bytes_written = scnprintf(command, rem_len,
11538 "Unannounced %d\tTriggered %d\tProtection %d\t"
11539 "Info Frame Disabled %d\n",
11540 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11541 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11542 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11543 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11544 command += bytes_written;
11545 rem_len -= bytes_written;
11546
11547 bytes_written = scnprintf(command, rem_len,
11548 "target wake time: 0x%08x%08x\t",
11549 desc->wake_time_h, desc->wake_time_l);
11550 command += bytes_written;
11551 rem_len -= bytes_written;
11552
11553 bytes_written = scnprintf(command, rem_len,
11554 "wake duration: %u\t", desc->wake_dur);
11555 command += bytes_written;
11556 rem_len -= bytes_written;
11557
11558 bytes_written = scnprintf(command, rem_len,
11559 "wake interval: %u\t", desc->wake_int);
11560 command += bytes_written;
11561 rem_len -= bytes_written;
11562
11563 bytes_written = scnprintf(command, rem_len,
11564 "TWT channel: %u\n", desc->channel);
11565 command += bytes_written;
11566 rem_len -= bytes_written;
11567 ANDROID_INFO(("\tFlow ID %d \tState %d\t",
11568 desc->flow_id,
11569 status->itwt_status[i].state));
11570 ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->itwt_status[i].peer)));
11571 ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11572 "Info Frame Disabled %d\n",
11573 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11574 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11575 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11576 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11577 ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11578 desc->wake_time_h, desc->wake_time_l));
11579 ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11580 ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11581 ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11582 }
11583 }
11584
11585 ANDROID_INFO(("\t---------------- Broadcast TWT list-------------------\n"));
11586 bytes_written = scnprintf(command, rem_len,
11587 "\t---------------- Broadcast TWT list-------------------\n");
11588 command += bytes_written;
11589 rem_len -= bytes_written;
11590 for (i = 0; i < WL_TWT_MAX_BTWT; i ++) {
11591 if ((status->btwt_status[i].state == WL_TWT_ACTIVE) ||
11592 (status->btwt_status[i].state == WL_TWT_SUSPEND)) {
11593 desc = &status->btwt_status[i].desc;
11594 bytes_written = scnprintf(command, rem_len,
11595 "Broadcast ID %d \tState %d\t",
11596 desc->bid, status->btwt_status[i].state);
11597 command += bytes_written;
11598 rem_len -= bytes_written;
11599
11600 bytes_written = scnprintf(command, rem_len,
11601 "peer: "MACF"\n",
11602 ETHER_TO_MACF(status->btwt_status[i].peer));
11603 command += bytes_written;
11604 rem_len -= bytes_written;
11605
11606 bytes_written = scnprintf(command, rem_len,
11607 "Unannounced %d\tTriggered %d\tProtection %d\t"
11608 "Info Frame Disabled %d\t",
11609 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11610 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11611 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11612 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11613 command += bytes_written;
11614 rem_len -= bytes_written;
11615
11616 bytes_written = scnprintf(command, rem_len,
11617 "Frame Recommendation %d\tBTWT Persistence %d\n",
11618 desc->frame_recomm, desc->btwt_persistence);
11619 command += bytes_written;
11620 rem_len -= bytes_written;
11621
11622 bytes_written = scnprintf(command, rem_len,
11623 "target wake time: 0x%08x%08x\t",
11624 desc->wake_time_h, desc->wake_time_l);
11625 command += bytes_written;
11626 rem_len -= bytes_written;
11627 bytes_written = scnprintf(command, rem_len,
11628 "wake duration: %u\t", desc->wake_dur);
11629 command += bytes_written;
11630 rem_len -= bytes_written;
11631
11632 bytes_written = scnprintf(command, rem_len,
11633 "wake interval: %u\t", desc->wake_int);
11634 command += bytes_written;
11635 rem_len -= bytes_written;
11636
11637 bytes_written = scnprintf(command, rem_len,
11638 "TWT channel: %u\n", desc->channel);
11639 command += bytes_written;
11640 rem_len -= bytes_written;
11641 ANDROID_INFO(("Broadcast ID %d \tState %d\t",
11642 desc->bid, status->btwt_status[i].state));
11643 ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->btwt_status[i].peer)));
11644 ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11645 "Info Frame Disabled %d\t",
11646 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11647 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11648 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11649 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11650 ANDROID_INFO(("Frame Recommendation %d\tBTWT Persistence %d\n",
11651 desc->frame_recomm, desc->btwt_persistence));
11652 ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11653 desc->wake_time_h, desc->wake_time_l));
11654 ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11655 ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11656 ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11657 }
11658 }
11659
11660 if ((total_len - rem_len) > 0) {
11661 return (total_len - rem_len);
11662 } else {
11663 return BCME_ERROR;
11664 }
11665 }
11666
11667 static int
wl_android_twt_status_query(struct net_device * dev,char * command,int total_len)11668 wl_android_twt_status_query(struct net_device *dev, char *command, int total_len)
11669 {
11670 int ret = BCME_OK;
11671 char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11672 uint8 *pxtlv = NULL;
11673 uint8 *iovresp = NULL;
11674 wl_twt_status_cmd_v1_t status_cmd;
11675 wl_twt_status_v1_t result;
11676
11677 uint16 buflen = 0, bufstart = 0;
11678 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11679
11680 bzero(&status_cmd, sizeof(status_cmd));
11681
11682 status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1;
11683 status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer);
11684
11685 iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11686 if (iovresp == NULL) {
11687 ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11688 goto exit;
11689 }
11690
11691 buflen = bufstart = WLC_IOCTL_SMLEN;
11692 pxtlv = (uint8 *)iovbuf;
11693
11694 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS,
11695 sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32);
11696 if (ret != BCME_OK) {
11697 ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11698 goto exit;
11699 }
11700
11701 if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11702 iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11703 ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11704 goto exit;
11705 }
11706 if (ret) {
11707 ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11708 }
11709
11710 (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11711
11712 if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) {
11713 ANDROID_ERROR(("status query ver %d, \n", dtoh16(result.version)));
11714 ret = wl_android_twt_status_display_v1(&result, command, total_len);
11715 return ret;
11716 } else {
11717 ret = BCME_UNSUPPORTED;
11718 ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11719 goto exit;
11720 }
11721
11722 exit:
11723 if (iovresp) {
11724 MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11725 }
11726
11727 return ret;
11728 }
11729
11730 static int
wl_android_twt_info(struct net_device * ndev,char * command,int total_len)11731 wl_android_twt_info(struct net_device *ndev, char *command, int total_len)
11732 {
11733 wl_twt_info_t val;
11734 s32 bw;
11735 char *token, *pos;
11736 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11737 u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11738 u64 twt;
11739 uint8 *rem = mybuf;
11740 uint16 rem_len = sizeof(mybuf);
11741 int32 val32;
11742
11743 WL_DBG_MEM(("Enter. cmd:%s\n", command));
11744
11745 if (strlen(command) == strlen(CMD_TWT_INFO)) {
11746 ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11747 bw = -EINVAL;
11748 goto exit;
11749 }
11750
11751 bzero(&val, sizeof(val));
11752 val.version = WL_TWT_INFO_VER;
11753 val.length = sizeof(val.version) + sizeof(val.length);
11754
11755 /* Default values, Overide Below */
11756 val.infodesc.flow_id = 0xFF;
11757 val.desc.next_twt_h = 0xFFFFFFFF;
11758 val.desc.next_twt_l = 0xFFFFFFFF;
11759
11760 pos = command + sizeof(CMD_TWT_TEARDOWN);
11761
11762 /* (all TWT) */
11763 token = strsep((char**)&pos, " ");
11764 if (!token) {
11765 ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11766 bw = -EINVAL;
11767 goto exit;
11768 }
11769 if (htod32((u32)bcm_atoi(token)) == 1) {
11770 val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
11771 }
11772
11773 /* Flow ID */
11774 token = strsep((char**)&pos, " ");
11775 if (!token) {
11776 ANDROID_ERROR(("flow ID not provided, using default\n"));
11777 } else {
11778 val32 = htod32((u32)bcm_atoi(token));
11779 if (val32 != -1) {
11780 val.infodesc.flow_id = htod32((u32)bcm_atoi(token));
11781 }
11782 }
11783
11784 /* resume offset */
11785 token = strsep((char**)&pos, " ");
11786 if (!token) {
11787 ANDROID_ERROR(("resume offset not provided, using default\n"));
11788 } else {
11789 twt = (u64)bcm_atoi(token);
11790 val32 = htod32((u32)(twt >> 32));
11791 if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11792 val.infodesc.next_twt_h = htod32((u32)(twt >> 32));
11793 val.infodesc.next_twt_l = htod32((u32)twt);
11794 val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
11795 }
11796 }
11797
11798 /* peer_address */
11799 token = strsep((char**)&pos, " ");
11800 if (!token) {
11801 ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11802 } else {
11803 /* get peer mac */
11804 if (!bcm_ether_atoe(token, &val.peer)) {
11805 ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11806 bw = BCME_ERROR;
11807 goto exit;
11808 }
11809 }
11810
11811 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
11812 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11813 if (bw != BCME_OK) {
11814 goto exit;
11815 }
11816
11817 bw = wldev_iovar_setbuf(ndev, "twt",
11818 mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11819 if (bw < 0) {
11820 ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11821 }
11822 exit:
11823 return bw;
11824
11825 }
11826
11827 static int
wl_android_twt_teardown(struct net_device * ndev,char * command,int total_len)11828 wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len)
11829 {
11830 wl_twt_teardown_t val;
11831 s32 bw;
11832 char *token, *pos;
11833 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11834 u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11835 uint8 *rem = mybuf;
11836 uint16 rem_len = sizeof(mybuf);
11837 int32 val32;
11838
11839 WL_DBG_MEM(("Enter. cmd:%s\n", command));
11840
11841 if (strlen(command) == strlen(CMD_TWT_TEARDOWN)) {
11842 ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11843 bw = -EINVAL;
11844 goto exit;
11845 }
11846
11847 bzero(&val, sizeof(val));
11848 val.version = WL_TWT_TEARDOWN_VER;
11849 val.length = sizeof(val.version) + sizeof(val.length);
11850
11851 /* Default values, Overide Below */
11852 val.teardesc.flow_id = 0xFF;
11853 val.teardesc.bid = 0xFF;
11854
11855 pos = command + sizeof(CMD_TWT_TEARDOWN);
11856
11857 /* negotiation_type */
11858 token = strsep((char**)&pos, " ");
11859 if (!token) {
11860 ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11861 bw = -EINVAL;
11862 goto exit;
11863 }
11864 val.teardesc.negotiation_type = htod32((u32)bcm_atoi(token));
11865
11866 /* (all TWT) */
11867 token = strsep((char**)&pos, " ");
11868 if (!token) {
11869 ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11870 bw = -EINVAL;
11871 goto exit;
11872 }
11873 val.teardesc.alltwt = htod32((u32)bcm_atoi(token));
11874
11875 /* Flow ID */
11876 token = strsep((char**)&pos, " ");
11877 if (!token) {
11878 ANDROID_ERROR(("flow ID not provided, using default\n"));
11879 } else {
11880 val32 = htod32((u32)bcm_atoi(token));
11881 if (val32 != -1) {
11882 val.teardesc.flow_id = htod32((u32)bcm_atoi(token));
11883 }
11884 }
11885
11886 /* Broadcas ID */
11887 token = strsep((char**)&pos, " ");
11888 if (!token) {
11889 ANDROID_ERROR(("flow ID not provided, using default\n"));
11890 } else {
11891 val32 = htod32((u32)bcm_atoi(token));
11892 if (val32 != -1) {
11893 val.teardesc.bid = htod32((u32)bcm_atoi(token));
11894 }
11895 }
11896
11897 /* peer_address */
11898 token = strsep((char**)&pos, " ");
11899 if (!token) {
11900 ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11901 } else {
11902 /* get peer mac */
11903 if (!bcm_ether_atoe(token, &val.peer)) {
11904 ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11905 bw = BCME_ERROR;
11906 goto exit;
11907 }
11908 }
11909
11910 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
11911 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11912 if (bw != BCME_OK) {
11913 goto exit;
11914 }
11915
11916 bw = wldev_iovar_setbuf(ndev, "twt",
11917 mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11918 if (bw < 0) {
11919 ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11920 }
11921 exit:
11922 return bw;
11923 }
11924 #endif /* WL_TWT */
11925
11926 int
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)11927 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
11928 {
11929 int bytes_written = 0;
11930 android_wifi_priv_cmd priv_cmd;
11931
11932 bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
11933 priv_cmd.total_len = cmd_len;
11934
11935 if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
11936 ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
11937 #ifdef SUPPORT_DEEP_SLEEP
11938 trigger_deep_sleep = 1;
11939 #else
11940 #ifdef BT_OVER_SDIO
11941 bytes_written = dhd_net_bus_get(net);
11942 #else
11943 bytes_written = wl_android_wifi_on(net);
11944 #endif /* BT_OVER_SDIO */
11945 #endif /* SUPPORT_DEEP_SLEEP */
11946 }
11947 else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
11948 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
11949 }
11950
11951 if (!g_wifi_on) {
11952 ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
11953 __FUNCTION__, command));
11954 return 0;
11955 }
11956
11957 if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
11958 #ifdef SUPPORT_DEEP_SLEEP
11959 trigger_deep_sleep = 1;
11960 #else
11961 #ifdef BT_OVER_SDIO
11962 bytes_written = dhd_net_bus_put(net);
11963 #else
11964 bytes_written = wl_android_wifi_off(net, FALSE);
11965 #endif /* BT_OVER_SDIO */
11966 #endif /* SUPPORT_DEEP_SLEEP */
11967 }
11968 #ifdef WL_CFG80211
11969 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
11970 wl_cfg80211_set_passive_scan(net, command);
11971 }
11972 else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
11973 wl_cfg80211_set_passive_scan(net, command);
11974 }
11975 #endif /* WL_CFG80211 */
11976 else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
11977 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
11978 }
11979 else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
11980 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
11981 }
11982 #ifdef PKT_FILTER_SUPPORT
11983 else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
11984 bytes_written = net_os_enable_packet_filter(net, 1);
11985 }
11986 else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
11987 bytes_written = net_os_enable_packet_filter(net, 0);
11988 }
11989 else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
11990 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
11991 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
11992 }
11993 else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
11994 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
11995 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
11996 }
11997 #endif /* PKT_FILTER_SUPPORT */
11998 else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
11999 /* TBD: BTCOEXSCAN-START */
12000 }
12001 else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
12002 /* TBD: BTCOEXSCAN-STOP */
12003 }
12004 else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
12005 #ifdef WL_CFG80211
12006 void *dhdp = wl_cfg80211_get_dhdp(net);
12007 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
12008 #else
12009 #ifdef PKT_FILTER_SUPPORT
12010 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
12011
12012 if (mode == 1)
12013 net_os_enable_packet_filter(net, 0); /* DHCP starts */
12014 else
12015 net_os_enable_packet_filter(net, 1); /* DHCP ends */
12016 #endif /* PKT_FILTER_SUPPORT */
12017 #endif /* WL_CFG80211 */
12018 }
12019 else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
12020 bytes_written = wl_android_set_suspendopt(net, command);
12021 }
12022 else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
12023 bytes_written = wl_android_set_suspendmode(net, command);
12024 }
12025 else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
12026 bytes_written = wl_android_set_bcn_li_dtim(net, command);
12027 }
12028 else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
12029 bytes_written = wl_android_set_max_dtim(net, command);
12030 }
12031 #ifdef DISABLE_DTIM_IN_SUSPEND
12032 else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
12033 bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
12034 }
12035 #endif /* DISABLE_DTIM_IN_SUSPEND */
12036 #ifdef WL_CFG80211
12037 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
12038 bytes_written = wl_android_set_band(net, command);
12039 }
12040 #endif /* WL_CFG80211 */
12041 else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
12042 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
12043 }
12044 #ifdef WL_CFG80211
12045 else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
12046 bytes_written = wl_android_set_csa(net, command);
12047 } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
12048 bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
12049 } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
12050 bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
12051 }
12052 #endif /* WL_CFG80211 */
12053 #ifndef CUSTOMER_SET_COUNTRY
12054 /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
12055 else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
12056 /*
12057 * Usage examples:
12058 * DRIVER COUNTRY US
12059 * DRIVER COUNTRY US/7
12060 * Wrong revinfo should be filtered:
12061 * DRIVER COUNTRY US/-1
12062 */
12063 char *country_code = command + strlen(CMD_COUNTRY) + 1;
12064 char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
12065 int revinfo = -1;
12066 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12067 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12068 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12069 if ((rev_info_delim) &&
12070 (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
12071 strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
12072 (rev_info_delim + 1)) {
12073 revinfo = bcm_atoi(rev_info_delim + 1);
12074 } else {
12075 revinfo = 0;
12076 }
12077
12078 if (revinfo < 0) {
12079 ANDROID_ERROR(("%s:failed due to wrong revinfo %d\n", __FUNCTION__, revinfo));
12080 return BCME_BADARG;
12081 }
12082
12083 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12084 if (dhdp->is_blob) {
12085 revinfo = 0;
12086 }
12087 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12088
12089 #ifdef WL_CFG80211
12090 bytes_written = wl_cfg80211_set_country_code(net, country_code,
12091 true, true, revinfo);
12092 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12093 #ifdef FCC_PWR_LIMIT_2G
12094 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
12095 ANDROID_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
12096 } else {
12097 ANDROID_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
12098 }
12099 #endif /* FCC_PWR_LIMIT_2G */
12100 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12101 #else
12102 bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
12103 #endif /* WL_CFG80211 */
12104 }
12105 #endif /* CUSTOMER_SET_COUNTRY */
12106 else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
12107 bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
12108 } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
12109 bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
12110 }
12111
12112 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12113 else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_SET, strlen(CMD_ROAM_VSIE_ENAB_SET)) == 0) {
12114 bytes_written = wl_android_set_roam_vsie_enab(net, command, priv_cmd.total_len);
12115 } else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_GET, strlen(CMD_ROAM_VSIE_ENAB_GET)) == 0) {
12116 bytes_written = wl_android_get_roam_vsie_enab(net, command, priv_cmd.total_len);
12117 } else if (strnicmp(command, CMD_BR_VSIE_ENAB_SET, strlen(CMD_BR_VSIE_ENAB_SET)) == 0) {
12118 bytes_written = wl_android_set_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12119 } else if (strnicmp(command, CMD_BR_VSIE_ENAB_GET, strlen(CMD_BR_VSIE_ENAB_GET)) == 0) {
12120 bytes_written = wl_android_get_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12121 }
12122 #ifdef WES_SUPPORT
12123 else if (strnicmp(command, CMD_GETNCHOMODE, strlen(CMD_GETNCHOMODE)) == 0) {
12124 bytes_written = wl_android_get_ncho_mode(net, command, priv_cmd.total_len);
12125 }
12126 else if (strnicmp(command, CMD_SETNCHOMODE, strlen(CMD_SETNCHOMODE)) == 0) {
12127 int mode;
12128 sscanf(command, "%*s %d", &mode);
12129 bytes_written = wl_android_set_ncho_mode(net, mode);
12130 }
12131 else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
12132 bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
12133 }
12134 else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
12135 bytes_written = wl_android_okc_enable(net, command);
12136 }
12137 else if (wl_android_legacy_check_command(net, command)) {
12138 bytes_written = wl_android_legacy_private_command(net, command, priv_cmd.total_len);
12139 }
12140 else if (wl_android_ncho_check_command(net, command)) {
12141 bytes_written = wl_android_ncho_private_command(net, command, priv_cmd.total_len);
12142 }
12143 #endif /* WES_SUPPORT */
12144 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
12145 else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
12146 bytes_written = wl_android_default_set_scan_params(net, command,
12147 priv_cmd.total_len);
12148 }
12149 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
12150 #ifdef WLTDLS
12151 else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
12152 bytes_written = wl_android_tdls_reset(net);
12153 }
12154 #endif /* WLTDLS */
12155 #ifdef CONFIG_SILENT_ROAM
12156 else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) {
12157 int mode = *(command + strlen(CMD_SROAM_TURN_ON) + 1) - '0';
12158 bytes_written = wl_android_sroam_turn_on(net, mode);
12159 }
12160 else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) {
12161 char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1);
12162 bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len);
12163 }
12164 else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) {
12165 bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len);
12166 }
12167 #endif /* CONFIG_SILENT_ROAM */
12168 #ifdef CONFIG_ROAM_RSSI_LIMIT
12169 else if (strnicmp(command, CMD_ROAM_RSSI_LMT, strlen(CMD_ROAM_RSSI_LMT)) == 0) {
12170 bytes_written = wl_android_roam_rssi_limit(net, command, priv_cmd.total_len);
12171 }
12172 #endif /* CONFIG_ROAM_RSSI_LIMIT */
12173 #ifdef CONFIG_ROAM_MIN_DELTA
12174 else if (strnicmp(command, CMD_ROAM_MIN_DELTA, strlen(CMD_ROAM_MIN_DELTA)) == 0) {
12175 bytes_written = wl_android_roam_min_delta(net, command, priv_cmd.total_len);
12176 }
12177 #endif /* CONFIG_ROAM_MIN_DELTA */
12178 else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) {
12179 bytes_written = wl_android_set_disconnect_ies(net, command);
12180 }
12181 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12182
12183 #ifdef PNO_SUPPORT
12184 else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
12185 bytes_written = dhd_dev_pno_stop_for_ssid(net);
12186 }
12187 #ifndef WL_SCHED_SCAN
12188 else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
12189 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
12190 }
12191 #endif /* !WL_SCHED_SCAN */
12192 else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
12193 int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
12194 bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
12195 }
12196 else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
12197 bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
12198 }
12199 #endif /* PNO_SUPPORT */
12200 else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
12201 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
12202 }
12203 else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
12204 int skip = strlen(CMD_P2P_SET_NOA) + 1;
12205 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
12206 priv_cmd.total_len - skip);
12207 }
12208 #ifdef WL_SDO
12209 else if (strnicmp(command, CMD_P2P_SD_OFFLOAD, strlen(CMD_P2P_SD_OFFLOAD)) == 0) {
12210 u8 *buf = command;
12211 u8 *cmd_id = NULL;
12212 int len;
12213
12214 cmd_id = strsep((char **)&buf, " ");
12215 if (!cmd_id) {
12216 /* Propagate the error */
12217 bytes_written = -EINVAL;
12218 } else {
12219 /* if buf == NULL, means no arg */
12220 if (buf == NULL) {
12221 len = 0;
12222 } else {
12223 len = strlen(buf);
12224 }
12225 bytes_written = wl_cfg80211_sd_offload(net, cmd_id, buf, len);
12226 }
12227 }
12228 #endif /* WL_SDO */
12229 #ifdef P2P_LISTEN_OFFLOADING
12230 else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
12231 u8 *sub_command = strchr(command, ' ');
12232 bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
12233 sub_command ? strlen(sub_command) : 0);
12234 }
12235 #endif /* P2P_LISTEN_OFFLOADING */
12236 #if !defined WL_ENABLE_P2P_IF
12237 else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
12238 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
12239 }
12240 #endif /* WL_ENABLE_P2P_IF */
12241 else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
12242 int skip = strlen(CMD_P2P_SET_PS) + 1;
12243 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
12244 priv_cmd.total_len - skip);
12245 }
12246 else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
12247 int skip = strlen(CMD_P2P_ECSA) + 1;
12248 bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
12249 priv_cmd.total_len - skip);
12250 }
12251 /* This command is not for normal VSDB operation but for only specific P2P operation.
12252 * Ex) P2P OTA backup operation
12253 */
12254 else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
12255 int skip = strlen(CMD_P2P_INC_BW) + 1;
12256 bytes_written = wl_cfg80211_increase_p2p_bw(net,
12257 command + skip, priv_cmd.total_len - skip);
12258 }
12259 #ifdef WL_CFG80211
12260 else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
12261 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
12262 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
12263 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
12264 priv_cmd.total_len - skip, *(command + skip - 2) - '0');
12265 }
12266 #ifdef WLFBT
12267 else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
12268 bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
12269 }
12270 #endif /* WLFBT */
12271 #endif /* WL_CFG80211 */
12272 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12273 else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
12274 strlen(CMD_GET_BEST_CHANNELS)) == 0) {
12275 bytes_written = wl_android_get_best_channels(net, command,
12276 priv_cmd.total_len);
12277 }
12278 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12279 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12280 else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
12281 strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
12282 int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
12283 bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
12284 priv_cmd.total_len);
12285 }
12286 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12287 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12288 #ifdef SUPPORT_AMPDU_MPDU_CMD
12289 /* CMD_AMPDU_MPDU */
12290 else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
12291 int skip = strlen(CMD_AMPDU_MPDU) + 1;
12292 bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
12293 }
12294 #endif /* SUPPORT_AMPDU_MPDU_CMD */
12295 #if defined (SUPPORT_HIDDEN_AP)
12296 else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
12297 strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
12298 int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
12299 wl_android_set_max_num_sta(net, (const char*)command+skip);
12300 }
12301 else if (strnicmp(command, CMD_SET_HAPD_SSID,
12302 strlen(CMD_SET_HAPD_SSID)) == 0) {
12303 int skip = strlen(CMD_SET_HAPD_SSID) + 3;
12304 wl_android_set_ssid(net, (const char*)command+skip);
12305 }
12306 else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
12307 strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
12308 int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
12309 wl_android_set_hide_ssid(net, (const char*)command+skip);
12310 }
12311 #endif /* SUPPORT_HIDDEN_AP */
12312 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
12313 else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
12314 strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
12315 int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
12316 wl_android_sta_diassoc(net, (const char*)command+skip);
12317 }
12318 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
12319 #ifdef SUPPORT_SET_LPC
12320 else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
12321 strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
12322 int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
12323 wl_android_set_lpc(net, (const char*)command+skip);
12324 }
12325 #endif /* SUPPORT_SET_LPC */
12326 #ifdef SUPPORT_TRIGGER_HANG_EVENT
12327 else if (strnicmp(command, CMD_TEST_FORCE_HANG,
12328 strlen(CMD_TEST_FORCE_HANG)) == 0) {
12329 int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
12330 net_os_send_hang_message_reason(net, (const char*)command+skip);
12331 }
12332 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
12333 else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
12334 bytes_written = wl_android_ch_res_rl(net, true);
12335 else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
12336 bytes_written = wl_android_ch_res_rl(net, false);
12337 #ifdef SUPPORT_LTECX
12338 else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
12339 int skip = strlen(CMD_LTECX_SET) + 1;
12340 bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
12341 }
12342 #endif /* SUPPORT_LTECX */
12343 #ifdef WL_RELMCAST
12344 else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
12345 int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
12346 bytes_written = wl_android_rmc_enable(net, rmc_enable);
12347 }
12348 else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
12349 int rmc_txrate;
12350 sscanf(command, "%*s %10d", &rmc_txrate);
12351 bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
12352 }
12353 else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
12354 int actperiod;
12355 sscanf(command, "%*s %10d", &actperiod);
12356 bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
12357 }
12358 else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
12359 int acktimeout;
12360 sscanf(command, "%*s %10d", &acktimeout);
12361 acktimeout *= 1000;
12362 bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
12363 }
12364 else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
12365 int skip = strlen(CMD_SET_RMC_LEADER) + 1;
12366 bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
12367 }
12368 else if (strnicmp(command, CMD_SET_RMC_EVENT,
12369 strlen(CMD_SET_RMC_EVENT)) == 0) {
12370 bytes_written = wl_android_set_rmc_event(net, command);
12371 }
12372 #endif /* WL_RELMCAST */
12373 else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
12374 bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
12375 }
12376 else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
12377 bytes_written = wl_android_set_singlecore_scan(net, command);
12378 }
12379 #ifdef TEST_TX_POWER_CONTROL
12380 else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
12381 strlen(CMD_TEST_SET_TX_POWER)) == 0) {
12382 int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
12383 wl_android_set_tx_power(net, (const char*)command+skip);
12384 }
12385 else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
12386 strlen(CMD_TEST_GET_TX_POWER)) == 0) {
12387 wl_android_get_tx_power(net, command, priv_cmd.total_len);
12388 }
12389 #endif /* TEST_TX_POWER_CONTROL */
12390 else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
12391 strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
12392 int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
12393 bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
12394 }
12395 #ifdef SUPPORT_SET_TID
12396 else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
12397 bytes_written = wl_android_set_tid(net, command);
12398 }
12399 else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
12400 bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
12401 }
12402 #endif /* SUPPORT_SET_TID */
12403 #ifdef WL_WTC
12404 else if (strnicmp(command, CMD_WTC_CONFIG, strlen(CMD_WTC_CONFIG)) == 0) {
12405 bytes_written = wl_android_wtc_config(net, command, priv_cmd.total_len);
12406 }
12407 #endif /* WL_WTC */
12408 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12409 else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
12410 int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
12411 wl_android_set_mac_address_filter(net, command+skip);
12412 }
12413 else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
12414 bytes_written = wl_android_set_roam_mode(net, command);
12415 #if defined(BCMFW_ROAM_ENABLE)
12416 else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
12417 bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
12418 }
12419 #endif /* BCMFW_ROAM_ENABLE */
12420 #ifdef WL_CFG80211
12421 else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
12422 bytes_written = wl_android_set_miracast(net, command);
12423 else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
12424 bytes_written = wl_android_set_ibss_beacon_ouidata(net,
12425 command, priv_cmd.total_len);
12426 #endif /* WL_CFG80211 */
12427 #ifdef WLAIBSS
12428 else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
12429 strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
12430 bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
12431 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
12432 strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
12433 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12434 TRUE);
12435 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
12436 strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
12437 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12438 FALSE);
12439 else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
12440 strlen(CMD_SETIBSSROUTETABLE)) == 0)
12441 bytes_written = wl_android_set_ibss_routetable(net, command);
12442 else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
12443 bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
12444 else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
12445 bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
12446 #endif /* WLAIBSS */
12447 else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
12448 int skip = strlen(CMD_KEEP_ALIVE) + 1;
12449 bytes_written = wl_keep_alive_set(net, command + skip);
12450 }
12451 #ifdef WL_CFG80211
12452 else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
12453 int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
12454 bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
12455 }
12456 else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
12457 char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
12458 ANDROID_INFO(("Creating %s interface\n", name));
12459 if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
12460 name, NULL) == NULL) {
12461 bytes_written = -ENODEV;
12462 } else {
12463 /* Return success */
12464 bytes_written = 0;
12465 }
12466 }
12467 else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
12468 char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
12469 ANDROID_INFO(("Deleteing %s interface\n", name));
12470 bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
12471 }
12472 #endif /* WL_CFG80211 */
12473 else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
12474 bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
12475 }
12476 #ifdef P2PRESP_WFDIE_SRC
12477 else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
12478 strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
12479 int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
12480 bytes_written = wl_android_set_wfdie_resp(net, mode);
12481 } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
12482 strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
12483 bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
12484 }
12485 #endif /* P2PRESP_WFDIE_SRC */
12486 #ifdef WL_CFG80211
12487 else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
12488 char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
12489 bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
12490 }
12491 #endif /* WL_CFG80211 */
12492 #ifdef WBTEXT
12493 else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
12494 bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
12495 }
12496 else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
12497 strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
12498 char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
12499 bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
12500 }
12501 else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
12502 strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
12503 char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
12504 bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
12505 command, priv_cmd.total_len);
12506 }
12507 else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
12508 strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
12509 char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
12510 bytes_written = wl_cfg80211_wbtext_table_config(net, data,
12511 command, priv_cmd.total_len);
12512 }
12513 else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
12514 strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
12515 char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
12516 bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
12517 command, priv_cmd.total_len);
12518 }
12519 else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
12520 strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
12521 bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
12522 priv_cmd.total_len);
12523 }
12524 else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
12525 strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
12526 bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
12527 priv_cmd.total_len);
12528 }
12529 else if (strnicmp(command, CMD_WBTEXT_ESTM_ENABLE,
12530 strlen(CMD_WBTEXT_ESTM_ENABLE)) == 0) {
12531 bytes_written = wl_cfg80211_wbtext_estm_enable(net, command,
12532 priv_cmd.total_len);
12533 }
12534 #endif /* WBTEXT */
12535 #ifdef WLWFDS
12536 else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
12537 bytes_written = wl_android_set_wfds_hash(net, command, 1);
12538 }
12539 else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
12540 bytes_written = wl_android_set_wfds_hash(net, command, 0);
12541 }
12542 #endif /* WLWFDS */
12543 #ifdef BT_WIFI_HANDOVER
12544 else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
12545 bytes_written = wl_tbow_teardown(net);
12546 }
12547 #endif /* BT_WIFI_HANDOVER */
12548 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12549 #ifdef FCC_PWR_LIMIT_2G
12550 else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
12551 strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
12552 bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
12553 }
12554 else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
12555 strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
12556 bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
12557 }
12558 #endif /* FCC_PWR_LIMIT_2G */
12559 else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
12560 bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
12561 }
12562 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12563 else if (strnicmp(command, CMD_MURX_BFE_CAP,
12564 strlen(CMD_MURX_BFE_CAP)) == 0) {
12565 #ifdef WL_MURX
12566 uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
12567 bytes_written = wl_android_murx_bfe_cap(net, val);
12568 #else
12569 return BCME_UNSUPPORTED;
12570 #endif /* WL_MURX */
12571 }
12572 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
12573 else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
12574 bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
12575 }
12576 else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
12577 bytes_written = wl_android_set_ap_beaconrate(net, command);
12578 }
12579 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
12580 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12581 else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
12582 bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
12583 }
12584 else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
12585 bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
12586 }
12587 else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
12588 bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
12589 }
12590 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12591 #ifdef SUPPORT_AP_SUSPEND
12592 else if (strnicmp(command, CMD_SET_AP_SUSPEND, strlen(CMD_SET_AP_SUSPEND)) == 0) {
12593 bytes_written = wl_android_set_ap_suspend(net, command, priv_cmd.total_len);
12594 }
12595 #endif /* SUPPORT_AP_SUSPEND */
12596 #ifdef SUPPORT_AP_BWCTRL
12597 else if (strnicmp(command, CMD_SET_AP_BW, strlen(CMD_SET_AP_BW)) == 0) {
12598 bytes_written = wl_android_set_ap_bw(net, command, priv_cmd.total_len);
12599 }
12600 else if (strnicmp(command, CMD_GET_AP_BW, strlen(CMD_GET_AP_BW)) == 0) {
12601 bytes_written = wl_android_get_ap_bw(net, command, priv_cmd.total_len);
12602 }
12603 #endif /* SUPPORT_AP_BWCTRL */
12604 #ifdef SUPPORT_RSSI_SUM_REPORT
12605 else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
12606 bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
12607 }
12608 else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
12609 bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
12610 }
12611 else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
12612 bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
12613 }
12614 #endif /* SUPPORT_RSSI_SUM_REPORT */
12615 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
12616 else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
12617 bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
12618 }
12619 else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
12620 == 0) {
12621 bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
12622 priv_cmd.total_len);
12623 }
12624 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
12625 #if defined(SUPPORT_RANDOM_MAC_SCAN)
12626 else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
12627 bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
12628 } else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
12629 bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
12630 }
12631 #endif /* SUPPORT_RANDOM_MAC_SCAN */
12632 #ifdef WL_NATOE
12633 else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
12634 bytes_written = wl_android_process_natoe_cmd(net, command,
12635 priv_cmd.total_len);
12636 }
12637 #endif /* WL_NATOE */
12638 #ifdef CONNECTION_STATISTICS
12639 else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
12640 strlen(CMD_GET_CONNECTION_STATS)) == 0) {
12641 bytes_written = wl_android_get_connection_stats(net, command,
12642 priv_cmd.total_len);
12643 }
12644 #endif
12645 #ifdef DHD_LOG_DUMP
12646 else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
12647 strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
12648 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12649 /* check whether it has more command */
12650 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
12651 /* compare unwanted/disconnected command */
12652 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12653 SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
12654 dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
12655 } else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12656 SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
12657 dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
12658 } else {
12659 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12660 }
12661 } else {
12662 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12663 }
12664 }
12665 #endif /* DHD_LOG_DUMP */
12666 #ifdef DHD_STATUS_LOGGING
12667 else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) {
12668 dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
12669 }
12670 else if (strnicmp(command, CMD_QUERY_STATUS_LOG, strlen(CMD_QUERY_STATUS_LOG)) == 0) {
12671 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12672 bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
12673 }
12674 #endif /* DHD_STATUS_LOGGING */
12675 #if defined(CONFIG_TIZEN)
12676 else if (strnicmp(command, CMD_POWERSAVEMODE_SET,
12677 strlen(CMD_POWERSAVEMODE_SET)) == 0) {
12678 bytes_written = wl_android_set_powersave_mode(net, command,
12679 priv_cmd.total_len);
12680 }
12681 else if (strnicmp(command, CMD_POWERSAVEMODE_GET,
12682 strlen(CMD_POWERSAVEMODE_GET)) == 0) {
12683 bytes_written = wl_android_get_powersave_mode(net, command,
12684 priv_cmd.total_len);
12685 }
12686 #endif /* CONFIG_TIZEN */
12687 #ifdef SET_PCIE_IRQ_CPU_CORE
12688 else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
12689 int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
12690 wl_android_set_irq_cpucore(net, affinity_cmd);
12691 }
12692 #endif /* SET_PCIE_IRQ_CPU_CORE */
12693 #if defined(DHD_HANG_SEND_UP_TEST)
12694 else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
12695 int skip = strlen(CMD_MAKE_HANG) + 1;
12696 wl_android_make_hang_with_reason(net, (const char*)command+skip);
12697 }
12698 #endif /* DHD_HANG_SEND_UP_TEST */
12699 #ifdef SUPPORT_LQCM
12700 else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
12701 int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
12702 bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
12703 }
12704 else if (strnicmp(command, CMD_GET_LQCM_REPORT,
12705 strlen(CMD_GET_LQCM_REPORT)) == 0) {
12706 bytes_written = wl_android_get_lqcm_report(net, command,
12707 priv_cmd.total_len);
12708 }
12709 #endif
12710 else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
12711 bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
12712 }
12713 #ifdef WLADPS_PRIVATE_CMD
12714 else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
12715 int skip = strlen(CMD_SET_ADPS) + 1;
12716 bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
12717 }
12718 else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
12719 bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
12720 }
12721 #ifdef WLADPS_ENERGY_GAIN
12722 else if (strnicmp(command, CMD_GET_GAIN_ADPS, strlen(CMD_GET_GAIN_ADPS)) == 0) {
12723 bytes_written = wl_android_get_gain_adps(net, command, priv_cmd.total_len);
12724 }
12725 else if (strnicmp(command, CMD_RESET_GAIN_ADPS, strlen(CMD_RESET_GAIN_ADPS)) == 0) {
12726 bytes_written = wl_android_reset_gain_adps(net, command);
12727 }
12728 #endif /* WLADPS_ENERGY_GAIN */
12729 #endif /* WLADPS_PRIVATE_CMD */
12730 #ifdef DHD_PKT_LOGGING
12731 else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
12732 strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
12733 bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
12734 }
12735 else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
12736 strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
12737 bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
12738 }
12739 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
12740 strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
12741 bytes_written =
12742 wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
12743 }
12744 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
12745 strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
12746 bytes_written =
12747 wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
12748 }
12749 else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
12750 bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
12751 }
12752 else if (strnicmp(command, CMD_PKTLOG_FILTER_DEL, strlen(CMD_PKTLOG_FILTER_DEL)) == 0) {
12753 bytes_written = wl_android_pktlog_filter_del(net, command, priv_cmd.total_len);
12754 }
12755 else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
12756 bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
12757 }
12758 else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
12759 bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
12760 }
12761 else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
12762 bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
12763 }
12764 else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
12765 bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
12766 }
12767 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
12768 strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
12769 bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
12770 }
12771 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
12772 strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
12773 bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
12774 }
12775 else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
12776 strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
12777 bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
12778 }
12779 else if (strnicmp(command, CMD_PKTLOG_DEBUG_DUMP, strlen(CMD_PKTLOG_DEBUG_DUMP)) == 0) {
12780 bytes_written = wl_android_pktlog_dbg_dump(net, command, priv_cmd.total_len);
12781 }
12782 #endif /* DHD_PKT_LOGGING */
12783 #ifdef WL_CFG80211
12784 else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
12785 int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
12786 bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
12787 }
12788 #endif /* WL_CFG80211 */
12789 #ifdef DHD_EVENT_LOG_FILTER
12790 else if (strnicmp(command, CMD_EWP_FILTER,
12791 strlen(CMD_EWP_FILTER)) == 0) {
12792 bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
12793 }
12794 #endif /* DHD_EVENT_LOG_FILTER */
12795 #ifdef WL_BCNRECV
12796 else if (strnicmp(command, CMD_BEACON_RECV,
12797 strlen(CMD_BEACON_RECV)) == 0) {
12798 char *data = (command + strlen(CMD_BEACON_RECV) + 1);
12799 bytes_written = wl_android_bcnrecv_config(net,
12800 data, priv_cmd.total_len);
12801 }
12802 #endif /* WL_BCNRECV */
12803 #ifdef WL_MBO
12804 else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
12805 bytes_written = wl_android_process_mbo_cmd(net, command,
12806 priv_cmd.total_len);
12807 }
12808 #endif /* WL_MBO */
12809 #ifdef WL_CAC_TS
12810 else if (strnicmp(command, CMD_CAC_TSPEC,
12811 strlen(CMD_CAC_TSPEC)) == 0) {
12812 char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
12813 bytes_written = wl_android_cac_ts_config(net,
12814 data, priv_cmd.total_len);
12815 }
12816 #endif /* WL_CAC_TS */
12817 #ifdef WL_GET_CU
12818 else if (strnicmp(command, CMD_GET_CHAN_UTIL,
12819 strlen(CMD_GET_CHAN_UTIL)) == 0) {
12820 bytes_written = wl_android_get_channel_util(net,
12821 command, priv_cmd.total_len);
12822 }
12823 #endif /* WL_GET_CU */
12824 #ifdef RTT_GEOFENCE_INTERVAL
12825 #if defined (RTT_SUPPORT) && defined(WL_NAN)
12826 else if (strnicmp(command, CMD_GEOFENCE_INTERVAL,
12827 strlen(CMD_GEOFENCE_INTERVAL)) == 0) {
12828 (void)wl_android_set_rtt_geofence_interval(net, command);
12829 }
12830 #endif /* RTT_SUPPORT && WL_NAN */
12831 #endif /* RTT_GEOFENCE_INTERVAL */
12832 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
12833 else if (strnicmp(command, CMD_SET_SOFTAP_ELNA_BYPASS,
12834 strlen(CMD_SET_SOFTAP_ELNA_BYPASS)) == 0) {
12835 bytes_written =
12836 wl_android_set_softap_elna_bypass(net, command, priv_cmd.total_len);
12837 }
12838 else if (strnicmp(command, CMD_GET_SOFTAP_ELNA_BYPASS,
12839 strlen(CMD_GET_SOFTAP_ELNA_BYPASS)) == 0) {
12840 bytes_written =
12841 wl_android_get_softap_elna_bypass(net, command, priv_cmd.total_len);
12842 }
12843 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
12844 #ifdef WL_NAN
12845 else if (strnicmp(command, CMD_GET_NAN_STATUS,
12846 strlen(CMD_GET_NAN_STATUS)) == 0) {
12847 bytes_written =
12848 wl_android_get_nan_status(net, command, priv_cmd.total_len);
12849 }
12850 #endif /* WL_NAN */
12851 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
12852 else if (strnicmp(command, CMD_NAN_RANGING_SET_BW, strlen(CMD_NAN_RANGING_SET_BW)) == 0) {
12853 int bw_cmd = *(command + strlen(CMD_NAN_RANGING_SET_BW) + 1) - '0';
12854 bytes_written = wl_nan_ranging_bw(net, bw_cmd, command);
12855 }
12856 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
12857 else if (strnicmp(command, CMD_GET_FACTORY_MAC, strlen(CMD_GET_FACTORY_MAC)) == 0) {
12858 bytes_written = wl_android_get_factory_mac_addr(net, command, priv_cmd.total_len);
12859 }
12860 else if (strnicmp(command, CMD_HAPD_SET_AX_MODE, strlen(CMD_HAPD_SET_AX_MODE)) == 0) {
12861 int skip = strlen(CMD_HAPD_SET_AX_MODE) + 1;
12862 bytes_written = wl_android_set_softap_ax_mode(net, command + skip);
12863 }
12864 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
12865 else if (strnicmp(command, CMD_SET_LATENCY_CRITICAL_DATA,
12866 strlen(CMD_SET_LATENCY_CRITICAL_DATA)) == 0) {
12867 int enable = *(command + strlen(CMD_SET_LATENCY_CRITICAL_DATA) + 1) - '0';
12868 bytes_written = wl_android_set_latency_crt_data(net, enable);
12869 }
12870 else if (strnicmp(command, CMD_GET_LATENCY_CRITICAL_DATA,
12871 strlen(CMD_GET_LATENCY_CRITICAL_DATA)) == 0) {
12872 bytes_written = wl_android_get_latency_crt_data(net, command, priv_cmd.total_len);
12873 }
12874 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
12875 #ifdef WL_TWT
12876 else if (strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) {
12877 bytes_written = wl_android_twt_setup(net, command, priv_cmd.total_len);
12878 }
12879 else if (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) {
12880 bytes_written = wl_android_twt_teardown(net, command, priv_cmd.total_len);
12881 }
12882 else if (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0) {
12883 bytes_written = wl_android_twt_info(net, command, priv_cmd.total_len);
12884 }
12885 else if (strnicmp(command, CMD_TWT_STATUS_QUERY, strlen(CMD_TWT_STATUS_QUERY)) == 0) {
12886 bytes_written = wl_android_twt_status_query(net, command, priv_cmd.total_len);
12887 }
12888 else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) {
12889 bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len);
12890 }
12891 #endif /* WL_TWT */
12892 #ifdef WL_P2P_6G
12893 else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) {
12894 int enable = *(command + strlen(CMD_ENABLE_6G_P2P) + 1) - '0';
12895 bytes_written = wl_android_enable_p2p_6g(net, enable);
12896 }
12897 #endif /* WL_P2P_6G */
12898 else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len, &bytes_written) == 0) {
12899 }
12900 else {
12901 ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
12902 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
12903 }
12904
12905 return bytes_written;
12906 }
12907
wl_android_init(void)12908 int wl_android_init(void)
12909 {
12910 int ret = 0;
12911
12912 #ifdef ENABLE_INSMOD_NO_POWER_OFF
12913 dhd_download_fw_on_driverload = TRUE;
12914 #elif defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE)
12915 dhd_download_fw_on_driverload = FALSE;
12916 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
12917 if (!iface_name[0]) {
12918 bzero(iface_name, IFNAMSIZ);
12919 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
12920 }
12921
12922 #ifdef CUSTOMER_HW4_DEBUG
12923 /* No Kernel Panic from ASSERT() on customer platform. */
12924 g_assert_type = 1;
12925 #endif /* CUSTOMER_HW4_DEBUG */
12926
12927 #ifdef WL_GENL
12928 wl_genl_init();
12929 #endif
12930 #ifdef WL_RELMCAST
12931 wl_netlink_init();
12932 #endif /* WL_RELMCAST */
12933
12934 return ret;
12935 }
12936
wl_android_exit(void)12937 int wl_android_exit(void)
12938 {
12939 int ret = 0;
12940 struct io_cfg *cur, *q;
12941
12942 #ifdef WL_GENL
12943 wl_genl_deinit();
12944 #endif /* WL_GENL */
12945 #ifdef WL_RELMCAST
12946 wl_netlink_deinit();
12947 #endif /* WL_RELMCAST */
12948
12949 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
12950 list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
12951 GCC_DIAGNOSTIC_POP();
12952 list_del(&cur->list);
12953 kfree(cur);
12954 }
12955
12956 return ret;
12957 }
12958
wl_android_post_init(void)12959 void wl_android_post_init(void)
12960 {
12961
12962 #ifdef ENABLE_4335BT_WAR
12963 bcm_bt_unlock(lock_cookie_wifi);
12964 ANDROID_ERROR(("%s: btlock released\n", __FUNCTION__));
12965 #endif /* ENABLE_4335BT_WAR */
12966
12967 if (!dhd_download_fw_on_driverload) {
12968 g_wifi_on = FALSE;
12969 }
12970 }
12971
12972 #ifdef WL_GENL
12973 /* Generic Netlink Initializaiton */
wl_genl_init(void)12974 static int wl_genl_init(void)
12975 {
12976 int ret;
12977
12978 ANDROID_INFO(("GEN Netlink Init\n\n"));
12979
12980 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
12981 /* register new family */
12982 ret = genl_register_family(&wl_genl_family);
12983 if (ret != 0)
12984 goto failure;
12985
12986 /* register functions (commands) of the new family */
12987 ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
12988 if (ret != 0) {
12989 ANDROID_ERROR(("register ops failed: %i\n", ret));
12990 genl_unregister_family(&wl_genl_family);
12991 goto failure;
12992 }
12993
12994 ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
12995 #else
12996 ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
12997 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
12998 if (ret != 0) {
12999 ANDROID_ERROR(("register mc_group failed: %i\n", ret));
13000 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13001 genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
13002 #endif
13003 genl_unregister_family(&wl_genl_family);
13004 goto failure;
13005 }
13006
13007 return 0;
13008
13009 failure:
13010 ANDROID_ERROR(("Registering Netlink failed!!\n"));
13011 return -1;
13012 }
13013
13014 /* Generic netlink deinit */
wl_genl_deinit(void)13015 static int wl_genl_deinit(void)
13016 {
13017
13018 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13019 if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
13020 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13021 #endif
13022 if (genl_unregister_family(&wl_genl_family) < 0)
13023 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13024
13025 return 0;
13026 }
13027
wl_event_to_bcm_event(u16 event_type)13028 s32 wl_event_to_bcm_event(u16 event_type)
13029 {
13030 /* When you add any new event, please mention the
13031 * version of BCM supplicant supporting it
13032 */
13033 u16 event = -1;
13034
13035 switch (event_type) {
13036 case WLC_E_SERVICE_FOUND:
13037 event = BCM_E_SVC_FOUND;
13038 break;
13039 case WLC_E_P2PO_ADD_DEVICE:
13040 event = BCM_E_DEV_FOUND;
13041 break;
13042 case WLC_E_P2PO_DEL_DEVICE:
13043 event = BCM_E_DEV_LOST;
13044 break;
13045 /* Above events are supported from BCM Supp ver 47 Onwards */
13046 #ifdef BT_WIFI_HANDOVER
13047 case WLC_E_BT_WIFI_HANDOVER_REQ:
13048 event = BCM_E_DEV_BT_WIFI_HO_REQ;
13049 break;
13050 #endif /* BT_WIFI_HANDOVER */
13051
13052 default:
13053 ANDROID_ERROR(("Event not supported\n"));
13054 }
13055
13056 return event;
13057 }
13058
13059 s32
wl_genl_send_msg(struct net_device * ndev,u32 event_type,const u8 * buf,u16 len,u8 * subhdr,u16 subhdr_len)13060 wl_genl_send_msg(
13061 struct net_device *ndev,
13062 u32 event_type,
13063 const u8 *buf,
13064 u16 len,
13065 u8 *subhdr,
13066 u16 subhdr_len)
13067 {
13068 int ret = 0;
13069 struct sk_buff *skb;
13070 void *msg;
13071 u32 attr_type = 0;
13072 bcm_event_hdr_t *hdr = NULL;
13073 int mcast = 1; /* By default sent as mutlicast type */
13074 int pid = 0;
13075 u8 *ptr = NULL, *p = NULL;
13076 u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
13077 u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13078 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13079
13080 ANDROID_INFO(("Enter \n"));
13081
13082 /* Decide between STRING event and Data event */
13083 if (event_type == 0)
13084 attr_type = BCM_GENL_ATTR_STRING;
13085 else
13086 attr_type = BCM_GENL_ATTR_MSG;
13087
13088 skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
13089 if (skb == NULL) {
13090 ret = -ENOMEM;
13091 goto out;
13092 }
13093
13094 msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
13095 if (msg == NULL) {
13096 ret = -ENOMEM;
13097 goto out;
13098 }
13099
13100 if (attr_type == BCM_GENL_ATTR_STRING) {
13101 /* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
13102 * make sure it is null terminated
13103 */
13104 if (subhdr || subhdr_len) {
13105 ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n"));
13106 ret = -EINVAL;
13107 goto out;
13108 }
13109
13110 ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
13111 if (ret != 0) {
13112 ANDROID_ERROR(("nla_put_string failed\n"));
13113 goto out;
13114 }
13115 } else {
13116 /* ATTR_MSG */
13117
13118 /* Create a single buffer for all */
13119 p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
13120 if (!ptr) {
13121 ret = -ENOMEM;
13122 ANDROID_ERROR(("ENOMEM!!\n"));
13123 goto out;
13124 }
13125
13126 /* Include the bcm event header */
13127 hdr = (bcm_event_hdr_t *)ptr;
13128 hdr->event_type = wl_event_to_bcm_event(event_type);
13129 hdr->len = len + subhdr_len;
13130 ptr += sizeof(bcm_event_hdr_t);
13131
13132 /* Copy subhdr (if any) */
13133 if (subhdr && subhdr_len) {
13134 memcpy(ptr, subhdr, subhdr_len);
13135 ptr += subhdr_len;
13136 }
13137
13138 /* Copy the data */
13139 if (buf && len) {
13140 memcpy(ptr, buf, len);
13141 }
13142
13143 ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
13144 if (ret != 0) {
13145 ANDROID_ERROR(("nla_put_string failed\n"));
13146 goto out;
13147 }
13148 }
13149
13150 if (mcast) {
13151 int err = 0;
13152 /* finalize the message */
13153 genlmsg_end(skb, msg);
13154 /* NETLINK_CB(skb).dst_group = 1; */
13155
13156 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
13157 if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
13158 #else
13159 if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
13160 #endif
13161 ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
13162 attr_type, err));
13163 else
13164 ANDROID_INFO(("Multicast msg sent successfully. attr_type:%d len:%d \n",
13165 attr_type, tot_len));
13166 } else {
13167 NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
13168
13169 /* finalize the message */
13170 genlmsg_end(skb, msg);
13171
13172 /* send the message back */
13173 if (genlmsg_unicast(&init_net, skb, pid) < 0)
13174 ANDROID_ERROR(("genlmsg_unicast failed\n"));
13175 }
13176
13177 out:
13178 if (p) {
13179 MFREE(cfg->osh, p, tot_len);
13180 }
13181 if (ret)
13182 nlmsg_free(skb);
13183
13184 return ret;
13185 }
13186
13187 static s32
wl_genl_handle_msg(struct sk_buff * skb,struct genl_info * info)13188 wl_genl_handle_msg(
13189 struct sk_buff *skb,
13190 struct genl_info *info)
13191 {
13192 struct nlattr *na;
13193 u8 *data = NULL;
13194
13195 ANDROID_INFO(("Enter \n"));
13196
13197 if (info == NULL) {
13198 return -EINVAL;
13199 }
13200
13201 na = info->attrs[BCM_GENL_ATTR_MSG];
13202 if (!na) {
13203 ANDROID_ERROR(("nlattribute NULL\n"));
13204 return -EINVAL;
13205 }
13206
13207 data = (char *)nla_data(na);
13208 if (!data) {
13209 ANDROID_ERROR(("Invalid data\n"));
13210 return -EINVAL;
13211 } else {
13212 /* Handle the data */
13213 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || \
13214 defined(WL_COMPAT_WIRELESS)
13215 ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13216 info->snd_pid));
13217 #else
13218 ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13219 info->snd_portid));
13220 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
13221 }
13222
13223 return 0;
13224 }
13225 #endif /* WL_GENL */
13226
wl_fatal_error(void * wl,int rc)13227 int wl_fatal_error(void * wl, int rc)
13228 {
13229 return FALSE;
13230 }
13231
13232 void
wl_android_set_wifi_on_flag(bool enable)13233 wl_android_set_wifi_on_flag(bool enable)
13234 {
13235 ANDROID_ERROR(("%s: %d\n", __FUNCTION__, enable));
13236 g_wifi_on = enable;
13237 }
13238
13239 #ifdef WL_STATIC_IF
13240 #include <dhd_linux_priv.h>
13241 struct net_device *
wl_cfg80211_register_static_if(struct bcm_cfg80211 * cfg,u16 iftype,char * ifname)13242 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname)
13243 {
13244 struct net_device *ndev;
13245 struct wireless_dev *wdev = NULL;
13246 int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
13247 u8 mac_addr[ETH_ALEN];
13248 struct net_device *primary_ndev;
13249 #ifdef DHD_USE_RANDMAC
13250 struct ether_addr ea_addr;
13251 #endif /* DHD_USE_RANDMAC */
13252 #ifdef CUSTOM_MULTI_MAC
13253 char hw_ether[62];
13254 dhd_pub_t *dhd = cfg->pub;
13255 #endif
13256
13257 ANDROID_INFO(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
13258
13259 if (!cfg) {
13260 ANDROID_ERROR(("cfg null\n"));
13261 return NULL;
13262 }
13263 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13264
13265 #ifdef DHD_USE_RANDMAC
13266 wl_cfg80211_generate_mac_addr(&ea_addr);
13267 (void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN);
13268 #else
13269 #if defined(CUSTOM_MULTI_MAC)
13270 if (wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, "wlan1")) {
13271 #endif
13272 /* Use primary mac with locally admin bit set */
13273 (void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
13274 mac_addr[0] |= 0x02;
13275 #if defined(CUSTOM_MULTI_MAC)
13276 } else {
13277 (void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN);
13278 }
13279 #endif
13280 #endif /* DHD_USE_RANDMAC */
13281
13282 ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
13283 WL_BSSIDX_MAX, NULL);
13284 if (unlikely(!ndev)) {
13285 ANDROID_ERROR(("Failed to allocate static_if\n"));
13286 goto fail;
13287 }
13288 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
13289 if (unlikely(!wdev)) {
13290 ANDROID_ERROR(("Failed to allocate wdev for static_if\n"));
13291 goto fail;
13292 }
13293
13294 wdev->wiphy = cfg->wdev->wiphy;
13295 wdev->iftype = iftype;
13296
13297 ndev->ieee80211_ptr = wdev;
13298 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
13299 wdev->netdev = ndev;
13300
13301 if (wl_cfg80211_register_if(cfg, ifidx,
13302 ndev, TRUE) != BCME_OK) {
13303 ANDROID_ERROR(("ndev registration failed!\n"));
13304 goto fail;
13305 }
13306
13307 cfg->static_ndev = ndev;
13308 cfg->static_ndev_state = NDEV_STATE_OS_IF_CREATED;
13309 wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
13310 ifname, NDEV_STATE_OS_IF_CREATED);
13311 ANDROID_INFO(("Static I/F (%s) Registered\n", ndev->name));
13312 return ndev;
13313
13314 fail:
13315 wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
13316 return NULL;
13317 }
13318
13319 void
wl_cfg80211_unregister_static_if(struct bcm_cfg80211 * cfg)13320 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
13321 {
13322 ANDROID_INFO(("[STATIC_IF] Enter\n"));
13323 if (!cfg || !cfg->static_ndev) {
13324 ANDROID_ERROR(("invalid input\n"));
13325 return;
13326 }
13327
13328 /* wdev free will happen from notifier context */
13329 /* free_netdev(cfg->static_ndev);
13330 */
13331 unregister_netdev(cfg->static_ndev);
13332 }
13333
13334 s32
wl_cfg80211_static_if_open(struct net_device * net)13335 wl_cfg80211_static_if_open(struct net_device *net)
13336 {
13337 struct wireless_dev *wdev = NULL;
13338 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13339 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13340 u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
13341 u16 wl_iftype, wl_mode;
13342 #ifdef CUSTOM_MULTI_MAC
13343 dhd_pub_t *dhd = dhd_get_pub(net);
13344 char hw_ether[62];
13345 #endif
13346
13347 ANDROID_INFO(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
13348 ASSERT(cfg->static_ndev == net);
13349
13350 if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) {
13351 return BCME_ERROR;
13352 }
13353 if (cfg->static_ndev_state != NDEV_STATE_FW_IF_CREATED) {
13354 #ifdef CUSTOM_MULTI_MAC
13355 if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, net->name))
13356 memcpy(net->dev_addr, hw_ether, ETHER_ADDR_LEN);
13357 #endif
13358 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr);
13359 if (!wdev) {
13360 ANDROID_ERROR(("[STATIC_IF] wdev is NULL, can't proceed"));
13361 return BCME_ERROR;
13362 }
13363 } else {
13364 ANDROID_INFO(("Fw IF for static netdev already created\n"));
13365 }
13366
13367 return BCME_OK;
13368 }
13369
13370 s32
wl_cfg80211_static_if_close(struct net_device * net)13371 wl_cfg80211_static_if_close(struct net_device *net)
13372 {
13373 int ret = BCME_OK;
13374 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13375 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13376
13377 if (cfg->static_ndev_state == NDEV_STATE_FW_IF_CREATED) {
13378 if (mutex_is_locked(&cfg->if_sync) == TRUE) {
13379 ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13380 } else {
13381 ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13382 }
13383
13384 if (unlikely(ret)) {
13385 ANDROID_ERROR(("Del iface failed for static_if %d\n", ret));
13386 }
13387 }
13388
13389 return ret;
13390 }
13391 struct net_device *
wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 * cfg,wl_if_event_info * event,u8 * addr,s32 iface_type)13392 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
13393 wl_if_event_info *event, u8 *addr, s32 iface_type)
13394 {
13395 struct net_device *new_ndev = NULL;
13396 struct wireless_dev *wdev = NULL;
13397
13398 ANDROID_INFO(("Updating static iface after Fw IF create \n"));
13399 new_ndev = cfg->static_ndev;
13400
13401 if (new_ndev) {
13402 wdev = new_ndev->ieee80211_ptr;
13403 ASSERT(wdev);
13404 wdev->iftype = iface_type;
13405 (void)memcpy_s(new_ndev->dev_addr, ETH_ALEN, addr, ETH_ALEN);
13406 }
13407
13408 cfg->static_ndev_state = NDEV_STATE_FW_IF_CREATED;
13409 wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
13410 event->name, NDEV_STATE_FW_IF_CREATED);
13411 return new_ndev;
13412 }
13413 s32
wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 * cfg,struct net_device * ndev)13414 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13415 {
13416 cfg->static_ndev_state = NDEV_STATE_FW_IF_DELETED;
13417 wl_cfg80211_update_iflist_info(cfg, ndev, WL_STATIC_IFIDX, NULL,
13418 WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
13419 wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
13420 wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
13421 return BCME_OK;
13422 }
13423 #endif /* WL_STATIC_IF */
13424
13425 #ifdef WBTEXT
13426 static int
wlc_wbtext_get_roam_prof(struct net_device * ndev,wl_roamprof_band_t * rp,uint8 band,uint8 * roam_prof_ver,uint8 * roam_prof_size)13427 wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
13428 uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size)
13429 {
13430 int err = BCME_OK;
13431 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13432 u8 *ioctl_buf = NULL;
13433
13434 ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13435 if (unlikely(!ioctl_buf)) {
13436 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13437 err = -ENOMEM;
13438 goto exit;
13439 }
13440 rp->v1.band = band;
13441 rp->v1.len = 0;
13442 /* Getting roam profile from fw */
13443 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13444 ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13445 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13446 goto exit;
13447 }
13448 memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13449 /* roam_prof version get */
13450 if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13451 ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13452 err = BCME_VERSION;
13453 goto exit;
13454 }
13455 switch (rp->v1.ver) {
13456 case WL_ROAM_PROF_VER_0:
13457 {
13458 *roam_prof_size = sizeof(wl_roam_prof_v1_t);
13459 *roam_prof_ver = WL_ROAM_PROF_VER_0;
13460 }
13461 break;
13462 case WL_ROAM_PROF_VER_1:
13463 {
13464 *roam_prof_size = sizeof(wl_roam_prof_v2_t);
13465 *roam_prof_ver = WL_ROAM_PROF_VER_1;
13466 }
13467 break;
13468 case WL_ROAM_PROF_VER_2:
13469 {
13470 *roam_prof_size = sizeof(wl_roam_prof_v3_t);
13471 *roam_prof_ver = WL_ROAM_PROF_VER_2;
13472 }
13473 break;
13474 case WL_ROAM_PROF_VER_3:
13475 {
13476 *roam_prof_size = sizeof(wl_roam_prof_v4_t);
13477 *roam_prof_ver = WL_ROAM_PROF_VER_3;
13478 }
13479 break;
13480 default:
13481 ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13482 err = BCME_VERSION;
13483 goto exit;
13484 }
13485 ANDROID_INFO(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size));
13486 if ((rp->v1.len % *roam_prof_size) != 0) {
13487 ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13488 err = BCME_BADLEN;
13489 }
13490 exit:
13491 if (ioctl_buf) {
13492 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13493 }
13494 return err;
13495 }
13496
13497 s32
wl_cfg80211_wbtext_set_default(struct net_device * ndev)13498 wl_cfg80211_wbtext_set_default(struct net_device *ndev)
13499 {
13500 char *commandp = NULL;
13501 s32 ret = BCME_OK;
13502 char *data;
13503 u8 *ioctl_buf = NULL;
13504 wl_roamprof_band_t rp;
13505 uint8 bandidx = 0;
13506 int wnmmask = 0;
13507 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13508
13509 ANDROID_INFO(("set wbtext to default\n"));
13510
13511 commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13512 if (unlikely(!commandp)) {
13513 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13514 ret = -ENOMEM;
13515 goto exit;
13516 }
13517 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13518 if (unlikely(!ioctl_buf)) {
13519 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13520 ret = -ENOMEM;
13521 goto exit;
13522 }
13523
13524 rp.v1.band = WLC_BAND_2G;
13525 rp.v1.len = 0;
13526 /* Getting roam profile from fw */
13527 if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp),
13528 ioctl_buf, WLC_IOCTL_SMLEN, NULL))) {
13529 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", ret));
13530 goto exit;
13531 }
13532 memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp));
13533 for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
13534 switch (rp.v1.ver) {
13535 case WL_ROAM_PROF_VER_1:
13536 {
13537 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13538 if (bandidx == BAND_5G_INDEX) {
13539 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13540 CMD_WBTEXT_PROFILE_CONFIG,
13541 DEFAULT_WBTEXT_PROFILE_A_V2);
13542 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13543 } else {
13544 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13545 CMD_WBTEXT_PROFILE_CONFIG,
13546 DEFAULT_WBTEXT_PROFILE_B_V2);
13547 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13548 }
13549 }
13550 break;
13551 case WL_ROAM_PROF_VER_2:
13552 case WL_ROAM_PROF_VER_3:
13553 {
13554 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13555 if (bandidx == BAND_5G_INDEX) {
13556 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13557 CMD_WBTEXT_PROFILE_CONFIG,
13558 DEFAULT_WBTEXT_PROFILE_A_V3);
13559 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13560 } else {
13561 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13562 CMD_WBTEXT_PROFILE_CONFIG,
13563 DEFAULT_WBTEXT_PROFILE_B_V3);
13564 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13565 }
13566 }
13567 break;
13568 default:
13569 ANDROID_ERROR(("No Support for roam prof ver = %d \n", rp.v1.ver));
13570 ret = -EINVAL;
13571 goto exit;
13572 }
13573 /* set roam profile */
13574 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13575 if (ret != BCME_OK) {
13576 ANDROID_ERROR(("%s: Failed to set roam_prof %s error = %d\n",
13577 __FUNCTION__, data, ret));
13578 goto exit;
13579 }
13580 }
13581
13582 /* wbtext code for backward compatibility. Newer firmwares set default value
13583 * from fw init
13584 */
13585 /* set RSSI weight */
13586 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13587 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13588 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
13589 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13590 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13591 if (ret != BCME_OK) {
13592 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13593 __FUNCTION__, data, ret));
13594 goto exit;
13595 }
13596
13597 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13598 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13599 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
13600 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13601 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13602 if (ret != BCME_OK) {
13603 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13604 __FUNCTION__, data, ret));
13605 goto exit;
13606 }
13607
13608 /* set CU weight */
13609 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13610 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13611 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
13612 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13613 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13614 if (ret != BCME_OK) {
13615 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13616 __FUNCTION__, data, ret));
13617 goto exit;
13618 }
13619
13620 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13621 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13622 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
13623 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13624 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13625 if (ret != BCME_OK) {
13626 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13627 __FUNCTION__, data, ret));
13628 goto exit;
13629 }
13630
13631 ret = wldev_iovar_getint(ndev, "wnm", &wnmmask);
13632 if (ret != BCME_OK) {
13633 ANDROID_ERROR(("%s: Failed to get wnmmask error = %d\n", __func__, ret));
13634 goto exit;
13635 }
13636 /* set ESTM DL weight. */
13637 if (wnmmask & WL_WNM_ESTM) {
13638 ANDROID_ERROR(("Setting ESTM wt\n"));
13639 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13640 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13641 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A);
13642 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13643 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13644 if (ret != BCME_OK) {
13645 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13646 __FUNCTION__, data, ret));
13647 goto exit;
13648 }
13649
13650 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13651 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13652 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B);
13653 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13654 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13655 if (ret != BCME_OK) {
13656 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13657 __FUNCTION__, data, ret));
13658 goto exit;
13659 }
13660 }
13661
13662 /* set RSSI table */
13663 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13664 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13665 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
13666 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13667 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13668 if (ret != BCME_OK) {
13669 ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13670 __FUNCTION__, data, ret));
13671 goto exit;
13672 }
13673
13674 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13675 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13676 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
13677 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13678 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13679 if (ret != BCME_OK) {
13680 ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13681 __FUNCTION__, data, ret));
13682 goto exit;
13683 }
13684
13685 /* set CU table */
13686 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13687 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13688 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
13689 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13690 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13691 if (ret != BCME_OK) {
13692 ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13693 __FUNCTION__, data, ret));
13694 goto exit;
13695 }
13696
13697 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13698 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13699 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
13700 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13701 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13702 if (ret != BCME_OK) {
13703 ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13704 __FUNCTION__, data, ret));
13705 goto exit;
13706 }
13707
13708 exit:
13709 if (commandp) {
13710 MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
13711 }
13712 if (ioctl_buf) {
13713 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_SMLEN);
13714 }
13715 return ret;
13716 }
13717
13718 s32
wl_cfg80211_wbtext_config(struct net_device * ndev,char * data,char * command,int total_len)13719 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
13720 {
13721 uint i = 0;
13722 long int rssi_lower, roam_trigger;
13723 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13724 wl_roamprof_band_t *rp = NULL;
13725 int err = -EINVAL, bytes_written = 0;
13726 size_t len = strlen(data);
13727 int rp_len = 0;
13728 u8 *ioctl_buf = NULL;
13729 uint8 roam_prof_size = 0, roam_prof_ver = 0, fs_per = 0, prof_cnt = 0;
13730
13731 data[len] = '\0';
13732 ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13733 if (unlikely(!ioctl_buf)) {
13734 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13735 err = -ENOMEM;
13736 goto exit;
13737 }
13738 rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
13739 if (unlikely(!rp)) {
13740 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13741 err = -ENOMEM;
13742 goto exit;
13743 }
13744 if (*data && (!strncmp(data, "b", 1))) {
13745 rp->v1.band = WLC_BAND_2G;
13746 } else if (*data && (!strncmp(data, "a", 1))) {
13747 rp->v1.band = WLC_BAND_5G;
13748 } else {
13749 err = snprintf(command, total_len, "Missing band\n");
13750 goto exit;
13751 }
13752 data++;
13753 rp->v1.len = 0;
13754 /* Getting roam profile from fw */
13755 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13756 ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13757 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13758 goto exit;
13759 }
13760 memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13761 /* roam_prof version get */
13762 if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13763 ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13764 err = -EINVAL;
13765 goto exit;
13766 }
13767 switch (rp->v1.ver) {
13768 case WL_ROAM_PROF_VER_0:
13769 {
13770 roam_prof_size = sizeof(wl_roam_prof_v1_t);
13771 roam_prof_ver = WL_ROAM_PROF_VER_0;
13772 }
13773 break;
13774 case WL_ROAM_PROF_VER_1:
13775 {
13776 roam_prof_size = sizeof(wl_roam_prof_v2_t);
13777 roam_prof_ver = WL_ROAM_PROF_VER_1;
13778 }
13779 break;
13780 case WL_ROAM_PROF_VER_2:
13781 {
13782 roam_prof_size = sizeof(wl_roam_prof_v3_t);
13783 roam_prof_ver = WL_ROAM_PROF_VER_2;
13784 }
13785 break;
13786 case WL_ROAM_PROF_VER_3:
13787 {
13788 roam_prof_size = sizeof(wl_roam_prof_v4_t);
13789 roam_prof_ver = WL_ROAM_PROF_VER_3;
13790 }
13791 break;
13792 default:
13793 ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13794 goto exit;
13795 }
13796 ANDROID_INFO(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size));
13797 if ((rp->v1.len % roam_prof_size) != 0) {
13798 ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13799 err = -EINVAL;
13800 goto exit;
13801 }
13802 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13803 /* printing contents of roam profile data from fw and exits
13804 * if code hits any of one of the below condtion. If remaining
13805 * length of buffer is less than roam profile size or
13806 * if there is no valid entry.
13807 */
13808 if (((i * roam_prof_size) > rp->v1.len)) {
13809 break;
13810 }
13811 if (roam_prof_ver == WL_ROAM_PROF_VER_0) {
13812 fs_per = rp->v1.roam_prof[i].fullscan_period;
13813 } else if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13814 fs_per = rp->v2.roam_prof[i].fullscan_period;
13815 } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13816 fs_per = rp->v3.roam_prof[i].fullscan_period;
13817 } else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13818 fs_per = rp->v4.roam_prof[i].fullscan_period;
13819 }
13820 if (fs_per == 0) {
13821 break;
13822 }
13823 prof_cnt++;
13824 }
13825
13826 if (!*data) {
13827 for (i = 0; (i < prof_cnt) && (i < WL_MAX_ROAM_PROF_BRACKETS); i++) {
13828 if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13829 bytes_written += scnprintf(command+bytes_written,
13830 total_len - bytes_written,
13831 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13832 rp->v2.roam_prof[i].roam_trigger,
13833 rp->v2.roam_prof[i].rssi_lower,
13834 rp->v2.roam_prof[i].channel_usage,
13835 rp->v2.roam_prof[i].cu_avg_calc_dur);
13836 } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13837 bytes_written += scnprintf(command+bytes_written,
13838 total_len - bytes_written,
13839 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13840 rp->v3.roam_prof[i].roam_trigger,
13841 rp->v3.roam_prof[i].rssi_lower,
13842 rp->v3.roam_prof[i].channel_usage,
13843 rp->v3.roam_prof[i].cu_avg_calc_dur);
13844 } else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13845 bytes_written += snprintf(command+bytes_written,
13846 total_len - bytes_written,
13847 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
13848 rp->v4.roam_prof[i].roam_trigger,
13849 rp->v4.roam_prof[i].rssi_lower,
13850 rp->v4.roam_prof[i].channel_usage,
13851 rp->v4.roam_prof[i].cu_avg_calc_dur);
13852 }
13853 }
13854 bytes_written += scnprintf(command+bytes_written, total_len - bytes_written, "\n");
13855 err = bytes_written;
13856 goto exit;
13857 } else {
13858 /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
13859 if (prof_cnt != 2) {
13860 ANDROID_ERROR(("FW must have 2 rows to fill roam_prof\n"));
13861 err = -EINVAL;
13862 goto exit;
13863 }
13864 /* setting roam profile to fw */
13865 data++;
13866 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13867 roam_trigger = simple_strtol(data, &data, 10);
13868 if (roam_trigger >= 0) {
13869 ANDROID_ERROR(("roam trigger[%d] value must be negative\n", i));
13870 err = -EINVAL;
13871 goto exit;
13872 }
13873 data++;
13874 rssi_lower = simple_strtol(data, &data, 10);
13875 if (rssi_lower >= 0) {
13876 ANDROID_ERROR(("rssi lower[%d] value must be negative\n", i));
13877 err = -EINVAL;
13878 goto exit;
13879 }
13880 if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13881 rp->v2.roam_prof[i].roam_trigger = roam_trigger;
13882 rp->v2.roam_prof[i].rssi_lower = rssi_lower;
13883 data++;
13884 rp->v2.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13885 data++;
13886 rp->v2.roam_prof[i].cu_avg_calc_dur =
13887 simple_strtol(data, &data, 10);
13888 }
13889 if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13890 rp->v3.roam_prof[i].roam_trigger = roam_trigger;
13891 rp->v3.roam_prof[i].rssi_lower = rssi_lower;
13892 data++;
13893 rp->v3.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13894 data++;
13895 rp->v3.roam_prof[i].cu_avg_calc_dur =
13896 simple_strtol(data, &data, 10);
13897 }
13898 if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13899 rp->v4.roam_prof[i].roam_trigger = roam_trigger;
13900 rp->v4.roam_prof[i].rssi_lower = rssi_lower;
13901 data++;
13902 rp->v4.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
13903 data++;
13904 rp->v4.roam_prof[i].cu_avg_calc_dur =
13905 simple_strtol(data, &data, 10);
13906 }
13907
13908 rp_len += roam_prof_size;
13909
13910 if (*data == '\0') {
13911 break;
13912 }
13913 data++;
13914 }
13915 if (i != 1) {
13916 ANDROID_ERROR(("Only two roam_prof rows supported.\n"));
13917 err = -EINVAL;
13918 goto exit;
13919 }
13920 rp->v1.len = rp_len;
13921 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
13922 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
13923 &cfg->ioctl_buf_sync)) < 0) {
13924 ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
13925 }
13926 }
13927 exit:
13928 if (rp) {
13929 MFREE(cfg->osh, rp, sizeof(*rp));
13930 }
13931 if (ioctl_buf) {
13932 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13933 }
13934 return err;
13935 }
13936
wl_cfg80211_wbtext_weight_config(struct net_device * ndev,char * data,char * command,int total_len)13937 int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
13938 char *command, int total_len)
13939 {
13940 int bytes_written = 0, err = -EINVAL, argc = 0;
13941 char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
13942 char *endptr = NULL;
13943 wnm_bss_select_weight_cfg_t *bwcfg;
13944 u8 ioctl_buf[WLC_IOCTL_SMLEN];
13945 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13946
13947 bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
13948 if (unlikely(!bwcfg)) {
13949 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13950 err = -ENOMEM;
13951 goto exit;
13952 }
13953 bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION;
13954 bwcfg->type = 0;
13955 bwcfg->weight = 0;
13956
13957 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
13958
13959 if (!strcasecmp(rssi, "rssi"))
13960 bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
13961 else if (!strcasecmp(rssi, "cu"))
13962 bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
13963 else if (!strcasecmp(rssi, "estm_dl"))
13964 bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL;
13965 else {
13966 /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu/estm_dl> <band> <weight> */
13967 ANDROID_ERROR(("%s: Command usage error\n", __func__));
13968 goto exit;
13969 }
13970
13971 if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &bwcfg->band)) {
13972 ANDROID_ERROR(("%s: Command usage error\n", __func__));
13973 goto exit;
13974 }
13975
13976 if (argc == 2) {
13977 /* If there is no data after band, getting wnm_bss_select_weight from fw */
13978 if (bwcfg->band == WLC_BAND_ALL) {
13979 ANDROID_ERROR(("band option \"all\" is for set only, not get\n"));
13980 goto exit;
13981 }
13982 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
13983 sizeof(*bwcfg),
13984 ioctl_buf, sizeof(ioctl_buf), NULL))) {
13985 ANDROID_ERROR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
13986 goto exit;
13987 }
13988 memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
13989 bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
13990 (bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" :
13991 (bwcfg->type == WNM_BSS_SELECT_TYPE_CU) ? "CU": "ESTM_DL",
13992 wl_android_get_band_str(bwcfg->band), bwcfg->weight);
13993 err = bytes_written;
13994 goto exit;
13995 } else {
13996 /* if weight is non integer returns command usage error */
13997 bwcfg->weight = simple_strtol(weight, &endptr, 0);
13998 if (*endptr != '\0') {
13999 ANDROID_ERROR(("%s: Command usage error", __func__));
14000 goto exit;
14001 }
14002 /* setting weight for iovar wnm_bss_select_weight to fw */
14003 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
14004 sizeof(*bwcfg),
14005 ioctl_buf, sizeof(ioctl_buf), NULL))) {
14006 ANDROID_ERROR(("setting wnm_bss_select_weight failed with err=%d\n", err));
14007 }
14008 }
14009 exit:
14010 if (bwcfg) {
14011 MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
14012 }
14013 return err;
14014 }
14015
14016 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
14017 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
14018
wl_cfg80211_wbtext_table_config(struct net_device * ndev,char * data,char * command,int total_len)14019 int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
14020 char *command, int total_len)
14021 {
14022 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14023 int bytes_written = 0, err = -EINVAL;
14024 char rssi[BUFSZN], band[BUFSZN];
14025 int btcfg_len = 0, i = 0, parsed_len = 0;
14026 wnm_bss_select_factor_cfg_t *btcfg;
14027 size_t slen = strlen(data);
14028 char *start_addr = NULL;
14029 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14030
14031 data[slen] = '\0';
14032 btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
14033 (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14034 if (unlikely(!btcfg)) {
14035 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14036 err = -ENOMEM;
14037 goto exit;
14038 }
14039
14040 btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
14041 btcfg->band = WLC_BAND_AUTO;
14042 btcfg->type = 0;
14043 btcfg->count = 0;
14044
14045 sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
14046
14047 if (!strcasecmp(rssi, "rssi")) {
14048 btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
14049 }
14050 else if (!strcasecmp(rssi, "cu")) {
14051 btcfg->type = WNM_BSS_SELECT_TYPE_CU;
14052 }
14053 else {
14054 ANDROID_ERROR(("%s: Command usage error\n", __func__));
14055 goto exit;
14056 }
14057
14058 if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &btcfg->band)) {
14059 ANDROID_ERROR(("%s: Command usage, Wrong band\n", __func__));
14060 goto exit;
14061 }
14062
14063 if ((slen - 1) == (strlen(rssi) + strlen(band))) {
14064 /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
14065 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
14066 sizeof(*btcfg),
14067 ioctl_buf, sizeof(ioctl_buf), NULL))) {
14068 ANDROID_ERROR(("Getting wnm_bss_select_table failed with err=%d \n", err));
14069 goto exit;
14070 }
14071 memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
14072 memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
14073
14074 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14075 "No of entries in table: %d\n", btcfg->count);
14076 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14077 "%s factor table\n",
14078 (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
14079 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14080 "low\thigh\tfactor\n");
14081 for (i = 0; i <= btcfg->count-1; i++) {
14082 bytes_written += snprintf(command + bytes_written,
14083 total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
14084 btcfg->params[i].high, btcfg->params[i].factor);
14085 }
14086 err = bytes_written;
14087 goto exit;
14088 } else {
14089 uint16 len = (sizeof(wnm_bss_select_factor_params_t) * WL_FACTOR_TABLE_MAX_LIMIT);
14090 memset_s(btcfg->params, len, 0, len);
14091 data += (strlen(rssi) + strlen(band) + 2);
14092 start_addr = data;
14093 slen = slen - (strlen(rssi) + strlen(band) + 2);
14094 for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
14095 if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
14096 btcfg->params[i].low = simple_strtol(data, &data, 10);
14097 data++;
14098 btcfg->params[i].high = simple_strtol(data, &data, 10);
14099 data++;
14100 btcfg->params[i].factor = simple_strtol(data, &data, 10);
14101 btcfg->count++;
14102 if (*data == '\0') {
14103 break;
14104 }
14105 data++;
14106 parsed_len = data - start_addr;
14107 } else {
14108 ANDROID_ERROR(("%s:Command usage:less no of args\n", __func__));
14109 goto exit;
14110 }
14111 }
14112 btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
14113 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
14114 cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
14115 ANDROID_ERROR(("seting wnm_bss_select_table failed with err %d\n", err));
14116 goto exit;
14117 }
14118 }
14119 exit:
14120 if (btcfg) {
14121 MFREE(cfg->osh, btcfg,
14122 (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14123 }
14124 return err;
14125 }
14126
14127 s32
wl_cfg80211_wbtext_delta_config(struct net_device * ndev,char * data,char * command,int total_len)14128 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
14129 {
14130 uint i = 0;
14131 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14132 int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
14133 char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
14134 wl_roamprof_band_t *rp = NULL;
14135 uint8 band_val = 0, roam_prof_size = 0, roam_prof_ver = 0;
14136
14137 rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
14138 if (unlikely(!rp)) {
14139 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14140 err = -ENOMEM;
14141 goto exit;
14142 }
14143
14144 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
14145 if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &band_val)) {
14146 ANDROID_ERROR(("%s: Missing band\n", __func__));
14147 goto exit;
14148 }
14149 if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver,
14150 &roam_prof_size))) {
14151 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
14152 err = -EINVAL;
14153 goto exit;
14154 }
14155 if (argc == 2) {
14156 /* if delta is non integer returns command usage error */
14157 val = simple_strtol(delta, &endptr, 0);
14158 if (*endptr != '\0') {
14159 ANDROID_ERROR(("%s: Command usage error", __func__));
14160 goto exit;
14161 }
14162 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
14163 /*
14164 * Checking contents of roam profile data from fw and exits
14165 * if code hits below condtion. If remaining length of buffer is
14166 * less than roam profile size or if there is no valid entry.
14167 */
14168 if (len >= rp->v1.len) {
14169 break;
14170 }
14171 if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14172 if (rp->v2.roam_prof[i].fullscan_period == 0) {
14173 break;
14174 }
14175 if (rp->v2.roam_prof[i].channel_usage != 0) {
14176 rp->v2.roam_prof[i].roam_delta = val;
14177 }
14178 } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14179 if (rp->v3.roam_prof[i].fullscan_period == 0) {
14180 break;
14181 }
14182 if (rp->v3.roam_prof[i].channel_usage != 0) {
14183 rp->v3.roam_prof[i].roam_delta = val;
14184 }
14185 } else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14186 if (rp->v4.roam_prof[i].fullscan_period == 0) {
14187 break;
14188 }
14189 if (rp->v4.roam_prof[i].channel_usage != 0) {
14190 rp->v4.roam_prof[i].roam_delta = val;
14191 }
14192 }
14193 len += roam_prof_size;
14194 }
14195 }
14196 else {
14197 if (rp->v2.roam_prof[0].channel_usage != 0) {
14198 bytes_written = snprintf(command, total_len,
14199 "%s Delta %d\n", wl_android_get_band_str(rp->v1.band),
14200 rp->v2.roam_prof[0].roam_delta);
14201 }
14202 err = bytes_written;
14203 goto exit;
14204 }
14205 rp->v1.len = len;
14206 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
14207 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
14208 &cfg->ioctl_buf_sync)) < 0) {
14209 ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
14210 }
14211 exit :
14212 if (rp) {
14213 MFREE(cfg->osh, rp, sizeof(*rp));
14214 }
14215 return err;
14216 }
14217 #endif /* WBTEXT */
14218