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 #define ANDROID_ERROR_MSG(x, args...) \
92 do { \
93 if (android_msg_level & ANDROID_ERROR_LEVEL) { \
94 printf("ANDROID-ERROR) " x, ## args); \
95 } \
96 } while (0)
97 #define ANDROID_TRACE_MSG(x, args...) \
98 do { \
99 if (android_msg_level & ANDROID_TRACE_LEVEL) { \
100 printf("ANDROID-TRACE) " x, ## args); \
101 } \
102 } while (0)
103 #define ANDROID_INFO_MSG(x, args...) \
104 do { \
105 if (android_msg_level & ANDROID_INFO_LEVEL) { \
106 printf("ANDROID-INFO) " x, ## args); \
107 } \
108 } while (0)
109 #define ANDROID_ERROR(x) ANDROID_ERROR_MSG x
110 #define ANDROID_TRACE(x) ANDROID_TRACE_MSG x
111 #define ANDROID_INFO(x) ANDROID_INFO_MSG x
112
113 /*
114 * Android private command strings, PLEASE define new private commands here
115 * so they can be updated easily in the future (if needed)
116 */
117
118 #define CMD_START "START"
119 #define CMD_STOP "STOP"
120 #define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
121 #define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
122 #define CMD_RSSI "RSSI"
123 #define CMD_LINKSPEED "LINKSPEED"
124 #define CMD_RXFILTER_START "RXFILTER-START"
125 #define CMD_RXFILTER_STOP "RXFILTER-STOP"
126 #define CMD_RXFILTER_ADD "RXFILTER-ADD"
127 #define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
128 #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
129 #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
130 #define CMD_BTCOEXMODE "BTCOEXMODE"
131 #define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
132 #define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
133 #define CMD_SETDTIM_IN_SUSPEND "SET_DTIM_IN_SUSPEND"
134 #define CMD_MAXDTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
135 #define CMD_DISDTIM_IN_SUSPEND "DISABLE_DTIM_IN_SUSPEND"
136 #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
137 #define CMD_SETFWPATH "SETFWPATH"
138 #define CMD_SETBAND "SETBAND"
139 #define CMD_GETBAND "GETBAND"
140 #define CMD_COUNTRY "COUNTRY"
141 #define CMD_P2P_SET_NOA "P2P_SET_NOA"
142 #if !defined WL_ENABLE_P2P_IF
143 #define CMD_P2P_GET_NOA "P2P_GET_NOA"
144 #endif /* WL_ENABLE_P2P_IF */
145 #define CMD_P2P_SD_OFFLOAD "P2P_SD_"
146 #define CMD_P2P_LISTEN_OFFLOAD "P2P_LO_"
147 #define CMD_P2P_SET_PS "P2P_SET_PS"
148 #define CMD_P2P_ECSA "P2P_ECSA"
149 #define CMD_P2P_INC_BW "P2P_INCREASE_BW"
150 #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
151 #define CMD_SETROAMMODE "SETROAMMODE"
152 #define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
153 #define CMD_MIRACAST "MIRACAST"
154 #ifdef WL_NAN
155 #define CMD_NAN "NAN_"
156 #endif /* WL_NAN */
157 #define CMD_COUNTRY_DELIMITER "/"
158
159 #if defined (WL_SUPPORT_AUTO_CHANNEL)
160 #define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
161 #endif /* WL_SUPPORT_AUTO_CHANNEL */
162
163 #define CMD_80211_MODE "MODE" /* 802.11 mode a/b/g/n/ac */
164 #define CMD_CHANSPEC "CHANSPEC"
165 #define CMD_DATARATE "DATARATE"
166 #define CMD_ASSOC_CLIENTS "ASSOCLIST"
167 #define CMD_SET_CSA "SETCSA"
168 #ifdef WL_SUPPORT_AUTO_CHANNEL
169 #define CMD_SET_HAPD_AUTO_CHANNEL "HAPD_AUTO_CHANNEL"
170 #endif /* WL_SUPPORT_AUTO_CHANNEL */
171 #ifdef CUSTOMER_HW4_PRIVATE_CMD
172 #ifdef WL_WTC
173 #define CMD_WTC_CONFIG "SETWTCMODE"
174 #endif /* WL_WTC */
175 #ifdef SUPPORT_HIDDEN_AP
176 /* Hostapd private command */
177 #define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA"
178 #define CMD_SET_HAPD_SSID "HAPD_SSID"
179 #define CMD_SET_HAPD_HIDE_SSID "HAPD_HIDE_SSID"
180 #endif /* SUPPORT_HIDDEN_AP */
181 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
182 #define CMD_HAPD_STA_DISASSOC "HAPD_STA_DISASSOC"
183 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
184 #ifdef SUPPORT_SET_LPC
185 #define CMD_HAPD_LPC_ENABLED "HAPD_LPC_ENABLED"
186 #endif /* SUPPORT_SET_LPC */
187 #ifdef SUPPORT_TRIGGER_HANG_EVENT
188 #define CMD_TEST_FORCE_HANG "TEST_FORCE_HANG"
189 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
190 #ifdef SUPPORT_LTECX
191 #define CMD_LTECX_SET "LTECOEX"
192 #endif /* SUPPORT_LTECX */
193 #ifdef TEST_TX_POWER_CONTROL
194 #define CMD_TEST_SET_TX_POWER "TEST_SET_TX_POWER"
195 #define CMD_TEST_GET_TX_POWER "TEST_GET_TX_POWER"
196 #endif /* TEST_TX_POWER_CONTROL */
197 #define CMD_SARLIMIT_TX_CONTROL "SET_TX_POWER_CALLING"
198 #ifdef SUPPORT_SET_TID
199 #define CMD_SET_TID "SET_TID"
200 #define CMD_GET_TID "GET_TID"
201 #endif /* SUPPORT_SET_TID */
202 #define CMD_ROAM_VSIE_ENAB_SET "SET_ROAMING_REASON_ENABLED"
203 #define CMD_ROAM_VSIE_ENAB_GET "GET_ROAMING_REASON_ENABLED"
204 #define CMD_BR_VSIE_ENAB_SET "SET_BR_ERR_REASON_ENABLED"
205 #define CMD_BR_VSIE_ENAB_GET "GET_BR_ERR_REASON_ENABLED"
206 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
207 #define CMD_KEEP_ALIVE "KEEPALIVE"
208
209 #ifdef PNO_SUPPORT
210 #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
211 #define CMD_PNOSETUP_SET "PNOSETUP "
212 #define CMD_PNOENABLE_SET "PNOFORCE"
213 #define CMD_PNODEBUG_SET "PNODEBUG"
214 #define CMD_WLS_BATCHING "WLS_BATCHING"
215 #endif /* PNO_SUPPORT */
216
217 #define CMD_HAPD_SET_AX_MODE "HAPD_SET_AX_MODE"
218
219 #define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
220
221 #if defined(SUPPORT_RANDOM_MAC_SCAN)
222 #define ENABLE_RANDOM_MAC "ENABLE_RANDOM_MAC"
223 #define DISABLE_RANDOM_MAC "DISABLE_RANDOM_MAC"
224 #endif /* SUPPORT_RANDOM_MAC_SCAN */
225 #define CMD_GET_FACTORY_MAC "FACTORY_MAC"
226 #ifdef CUSTOMER_HW4_PRIVATE_CMD
227
228 #ifdef ROAM_API
229 #define CMD_ROAMTRIGGER_SET "SETROAMTRIGGER"
230 #define CMD_ROAMTRIGGER_GET "GETROAMTRIGGER"
231 #define CMD_ROAMDELTA_SET "SETROAMDELTA"
232 #define CMD_ROAMDELTA_GET "GETROAMDELTA"
233 #define CMD_ROAMSCANPERIOD_SET "SETROAMSCANPERIOD"
234 #define CMD_ROAMSCANPERIOD_GET "GETROAMSCANPERIOD"
235 #define CMD_FULLROAMSCANPERIOD_SET "SETFULLROAMSCANPERIOD"
236 #define CMD_FULLROAMSCANPERIOD_GET "GETFULLROAMSCANPERIOD"
237 #define CMD_COUNTRYREV_SET "SETCOUNTRYREV"
238 #define CMD_COUNTRYREV_GET "GETCOUNTRYREV"
239 #endif /* ROAM_API */
240
241 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
242 #define CMD_NAN_RANGING_SET_BW "NAN_RANGING_SET_BW"
243 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
244
245 #ifdef WES_SUPPORT
246 #define CMD_GETSCANCHANNELTIMELEGACY "GETSCANCHANNELTIME_LEGACY"
247 #define CMD_SETSCANCHANNELTIMELEGACY "SETSCANCHANNELTIME_LEGACY"
248 #define CMD_GETSCANUNASSOCTIMELEGACY "GETSCANUNASSOCTIME_LEGACY"
249 #define CMD_SETSCANUNASSOCTIMELEGACY "SETSCANUNASSOCTIME_LEGACY"
250 #define CMD_GETSCANPASSIVETIMELEGACY "GETSCANPASSIVETIME_LEGACY"
251 #define CMD_SETSCANPASSIVETIMELEGACY "SETSCANPASSIVETIME_LEGACY"
252 #define CMD_GETSCANHOMETIMELEGACY "GETSCANHOMETIME_LEGACY"
253 #define CMD_SETSCANHOMETIMELEGACY "SETSCANHOMETIME_LEGACY"
254 #define CMD_GETSCANHOMEAWAYTIMELEGACY "GETSCANHOMEAWAYTIME_LEGACY"
255 #define CMD_SETSCANHOMEAWAYTIMELEGACY "SETSCANHOMEAWAYTIME_LEGACY"
256 #define CMD_GETROAMSCANCHLEGACY "GETROAMSCANCHANNELS_LEGACY"
257 #define CMD_ADDROAMSCANCHLEGACY "ADDROAMSCANCHANNELS_LEGACY"
258 #define CMD_GETROAMSCANFQLEGACY "GETROAMSCANFREQUENCIES_LEGACY"
259 #define CMD_ADDROAMSCANFQLEGACY "ADDROAMSCANFREQUENCIES_LEGACY"
260 #define CMD_GETROAMTRIGLEGACY "GETROAMTRIGGER_LEGACY"
261 #define CMD_SETROAMTRIGLEGACY "SETROAMTRIGGER_LEGACY"
262 #define CMD_REASSOCLEGACY "REASSOC_LEGACY"
263
264 #define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
265 #define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
266 #define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
267 #define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
268 #define CMD_ADDROAMSCANCHANNELS "ADDROAMSCANCHANNELS"
269 #define CMD_GETROAMSCANFREQS "GETROAMSCANFREQUENCIES"
270 #define CMD_SETROAMSCANFREQS "SETROAMSCANFREQUENCIES"
271 #define CMD_ADDROAMSCANFREQS "ADDROAMSCANFREQUENCIES"
272 #define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
273 #define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
274 #define CMD_GETSCANUNASSOCTIME "GETSCANUNASSOCTIME"
275 #define CMD_SETSCANUNASSOCTIME "SETSCANUNASSOCTIME"
276 #define CMD_GETSCANPASSIVETIME "GETSCANPASSIVETIME"
277 #define CMD_SETSCANPASSIVETIME "SETSCANPASSIVETIME"
278 #define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
279 #define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
280 #define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
281 #define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
282 #define CMD_GETSCANNPROBES "GETSCANNPROBES"
283 #define CMD_SETSCANNPROBES "SETSCANNPROBES"
284 #define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
285 #define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
286 #define CMD_SETJOINPREFER "SETJOINPREFER"
287
288 #define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
289 #define CMD_REASSOC "REASSOC"
290
291 #define CMD_GETWESMODE "GETWESMODE"
292 #define CMD_SETWESMODE "SETWESMODE"
293 #define CMD_GETNCHOMODE "GETNCHOMODE"
294 #define CMD_SETNCHOMODE "SETNCHOMODE"
295
296 /* Customer requested to Remove OKCMODE command */
297 #define CMD_GETOKCMODE "GETOKCMODE"
298 #define CMD_SETOKCMODE "SETOKCMODE"
299
300 #define CMD_OKC_SET_PMK "SET_PMK"
301 #define CMD_OKC_ENABLE "OKC_ENABLE"
302
303 typedef struct android_wifi_reassoc_params {
304 unsigned char bssid[18];
305 int channel;
306 } android_wifi_reassoc_params_t;
307
308 #define ANDROID_WIFI_REASSOC_PARAMS_SIZE sizeof(struct android_wifi_reassoc_params)
309
310 #define ANDROID_WIFI_ACTION_FRAME_SIZE 1040
311
312 typedef struct android_wifi_af_params {
313 unsigned char bssid[18];
314 int channel;
315 int dwell_time;
316 int len;
317 unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE];
318 } android_wifi_af_params_t;
319
320 #define ANDROID_WIFI_AF_PARAMS_SIZE sizeof(struct android_wifi_af_params)
321 #endif /* WES_SUPPORT */
322 #ifdef SUPPORT_AMPDU_MPDU_CMD
323 #define CMD_AMPDU_MPDU "AMPDU_MPDU"
324 #endif /* SUPPORT_AMPDU_MPDU_CMD */
325
326 #define CMD_CHANGE_RL "CHANGE_RL"
327 #define CMD_RESTORE_RL "RESTORE_RL"
328
329 #define CMD_SET_RMC_ENABLE "SETRMCENABLE"
330 #define CMD_SET_RMC_TXRATE "SETRMCTXRATE"
331 #define CMD_SET_RMC_ACTPERIOD "SETRMCACTIONPERIOD"
332 #define CMD_SET_RMC_IDLEPERIOD "SETRMCIDLEPERIOD"
333 #define CMD_SET_RMC_LEADER "SETRMCLEADER"
334 #define CMD_SET_RMC_EVENT "SETRMCEVENT"
335
336 #define CMD_SET_SCSCAN "SETSINGLEANT"
337 #define CMD_GET_SCSCAN "GETSINGLEANT"
338 #ifdef WLTDLS
339 #define CMD_TDLS_RESET "TDLS_RESET"
340 #endif /* WLTDLS */
341
342 #ifdef CONFIG_SILENT_ROAM
343 #define CMD_SROAM_TURN_ON "SROAMTURNON"
344 #define CMD_SROAM_SET_INFO "SROAMSETINFO"
345 #define CMD_SROAM_GET_INFO "SROAMGETINFO"
346 #endif /* CONFIG_SILENT_ROAM */
347
348 #ifdef CONFIG_ROAM_RSSI_LIMIT
349 #define CMD_ROAM_RSSI_LMT "ROAMRSSILIMIT"
350 #endif /* CONFIG_ROAM_RSSI_LIMIT */
351 #ifdef CONFIG_ROAM_MIN_DELTA
352 #define CMD_ROAM_MIN_DELTA "ROAMMINSCOREDELTA"
353 #endif /* CONFIG_ROAM_MIN_DELTA */
354
355 #define CMD_SET_DISCONNECT_IES "SET_DISCONNECT_IES"
356
357 #ifdef FCC_PWR_LIMIT_2G
358 #define CMD_GET_FCC_PWR_LIMIT_2G "GET_FCC_CHANNEL"
359 #define CMD_SET_FCC_PWR_LIMIT_2G "SET_FCC_CHANNEL"
360 /* CUSTOMER_HW4's value differs from BRCM FW value for enable/disable */
361 #define CUSTOMER_HW4_ENABLE 0
362 #define CUSTOMER_HW4_DISABLE -1
363 #endif /* FCC_PWR_LIMIT_2G */
364 #define CUSTOMER_HW4_EN_CONVERT(i) (i += 1)
365 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
366
367 #ifdef WLFBT
368 #define CMD_GET_FTKEY "GET_FTKEY"
369 #endif
370
371 #ifdef WLAIBSS
372 #define CMD_SETIBSSTXFAILEVENT "SETIBSSTXFAILEVENT"
373 #define CMD_GET_IBSS_PEER_INFO "GETIBSSPEERINFO"
374 #define CMD_GET_IBSS_PEER_INFO_ALL "GETIBSSPEERINFOALL"
375 #define CMD_SETIBSSROUTETABLE "SETIBSSROUTETABLE"
376 #define CMD_SETIBSSAMPDU "SETIBSSAMPDU"
377 #define CMD_SETIBSSANTENNAMODE "SETIBSSANTENNAMODE"
378 #endif /* WLAIBSS */
379
380 #define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
381 #define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
382 #define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
383 #define CMD_GET_LINK_STATUS "GETLINKSTATUS"
384
385 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
386 #define CMD_GET_BSS_INFO "GETBSSINFO"
387 #define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO"
388 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
389 #define CMD_GET_STA_INFO "GETSTAINFO"
390
391 /* related with CMD_GET_LINK_STATUS */
392 #define WL_ANDROID_LINK_VHT 0x01
393 #define WL_ANDROID_LINK_MIMO 0x02
394 #define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
395 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
396
397 #ifdef P2PRESP_WFDIE_SRC
398 #define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
399 #define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
400 #endif /* P2PRESP_WFDIE_SRC */
401
402 #define CMD_DFS_AP_MOVE "DFS_AP_MOVE"
403 #define CMD_WBTEXT_ENABLE "WBTEXT_ENABLE"
404 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
405 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
406 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
407 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
408 #define CMD_WBTEXT_BTM_TIMER_THRESHOLD "WBTEXT_BTM_TIMER_THRESHOLD"
409 #define CMD_WBTEXT_BTM_DELTA "WBTEXT_BTM_DELTA"
410 #define CMD_WBTEXT_ESTM_ENABLE "WBTEXT_ESTM_ENABLE"
411
412 #ifdef WBTEXT
413 #define CMD_WBTEXT_PROFILE_CONFIG "WBTEXT_PROFILE_CONFIG"
414 #define CMD_WBTEXT_WEIGHT_CONFIG "WBTEXT_WEIGHT_CONFIG"
415 #define CMD_WBTEXT_TABLE_CONFIG "WBTEXT_TABLE_CONFIG"
416 #define CMD_WBTEXT_DELTA_CONFIG "WBTEXT_DELTA_CONFIG"
417 #define DEFAULT_WBTEXT_PROFILE_A_V2 "a -70 -75 70 10 -75 -128 0 10"
418 #define DEFAULT_WBTEXT_PROFILE_B_V2 "b -60 -75 70 10 -75 -128 0 10"
419 #define DEFAULT_WBTEXT_PROFILE_A_V3 "a -70 -75 70 10 -75 -128 0 10"
420 #define DEFAULT_WBTEXT_PROFILE_B_V3 "b -60 -75 70 10 -75 -128 0 10"
421 #define DEFAULT_WBTEXT_WEIGHT_RSSI_A "RSSI a 65"
422 #define DEFAULT_WBTEXT_WEIGHT_RSSI_B "RSSI b 65"
423 #define DEFAULT_WBTEXT_WEIGHT_CU_A "CU a 35"
424 #define DEFAULT_WBTEXT_WEIGHT_CU_B "CU b 35"
425 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A "ESTM_DL a 70"
426 #define DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B "ESTM_DL b 70"
427 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_A -70
428 #define DEFAULT_WBTEXT_CU_RSSI_TRIG_B -60
429 #ifdef WBTEXT_SCORE_V2
430 #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
431 60 70 60 70 80 20 80 90 0 90 128 0"
432 #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
433 60 70 60 70 80 20 80 90 0 90 128 0"
434 #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 80 20 \
435 80 100 20"
436 #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 70 20 \
437 70 100 20"
438 #else
439 #define DEFAULT_WBTEXT_TABLE_RSSI_A "RSSI a 0 55 100 55 60 90 \
440 60 65 70 65 70 50 70 128 20"
441 #define DEFAULT_WBTEXT_TABLE_RSSI_B "RSSI b 0 55 100 55 60 90 \
442 60 65 70 65 70 50 70 128 20"
443 #define DEFAULT_WBTEXT_TABLE_CU_A "CU a 0 30 100 30 50 90 \
444 50 60 70 60 80 50 80 100 20"
445 #define DEFAULT_WBTEXT_TABLE_CU_B "CU b 0 10 100 10 25 90 \
446 25 40 70 40 70 50 70 100 20"
447 #endif /* WBTEXT_SCORE_V2 */
448 #endif /* WBTEXT */
449
450 #define BUFSZ 8
451 #define BUFSZN BUFSZ + 1
452
453 #define _S(x) #x
454 #define S(x) _S(x)
455
456 #define MAXBANDS 2 /**< Maximum #of bands */
457 #define BAND_2G_INDEX 1
458 #define BAND_5G_INDEX 0
459
460 typedef union {
461 wl_roam_prof_band_v1_t v1;
462 wl_roam_prof_band_v2_t v2;
463 wl_roam_prof_band_v3_t v3;
464 wl_roam_prof_band_v4_t v4;
465 } wl_roamprof_band_t;
466
467 #ifdef WLWFDS
468 #define CMD_ADD_WFDS_HASH "ADD_WFDS_HASH"
469 #define CMD_DEL_WFDS_HASH "DEL_WFDS_HASH"
470 #endif /* WLWFDS */
471
472 #ifdef BT_WIFI_HANDOVER
473 #define CMD_TBOW_TEARDOWN "TBOW_TEARDOWN"
474 #endif /* BT_WIFI_HANDOVER */
475
476 #define CMD_MURX_BFE_CAP "MURX_BFE_CAP"
477
478 #ifdef SUPPORT_RSSI_SUM_REPORT
479 #define CMD_SET_RSSI_LOGGING "SET_RSSI_LOGGING"
480 #define CMD_GET_RSSI_LOGGING "GET_RSSI_LOGGING"
481 #define CMD_GET_RSSI_PER_ANT "GET_RSSI_PER_ANT"
482 #endif /* SUPPORT_RSSI_SUM_REPORT */
483
484 #define CMD_GET_SNR "GET_SNR"
485
486 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
487 #define CMD_SET_AP_BEACONRATE "SET_AP_BEACONRATE"
488 #define CMD_GET_AP_BASICRATE "GET_AP_BASICRATE"
489 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
490
491 #ifdef SUPPORT_AP_RADIO_PWRSAVE
492 #define CMD_SET_AP_RPS "SET_AP_RPS"
493 #define CMD_GET_AP_RPS "GET_AP_RPS"
494 #define CMD_SET_AP_RPS_PARAMS "SET_AP_RPS_PARAMS"
495 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
496
497 #ifdef SUPPORT_AP_SUSPEND
498 #define CMD_SET_AP_SUSPEND "SET_AP_SUSPEND"
499 #endif /* SUPPORT_AP_SUSPEND */
500
501 #ifdef SUPPORT_AP_BWCTRL
502 #define CMD_SET_AP_BW "SET_AP_BW"
503 #define CMD_GET_AP_BW "GET_AP_BW"
504 #endif /* SUPPORT_AP_BWCTRL */
505
506 /* miracast related definition */
507 #define MIRACAST_MODE_OFF 0
508 #define MIRACAST_MODE_SOURCE 1
509 #define MIRACAST_MODE_SINK 2
510
511 #ifdef CONNECTION_STATISTICS
512 #define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
513
514 struct connection_stats {
515 u32 txframe;
516 u32 txbyte;
517 u32 txerror;
518 u32 rxframe;
519 u32 rxbyte;
520 u32 txfail;
521 u32 txretry;
522 u32 txretrie;
523 u32 txrts;
524 u32 txnocts;
525 u32 txexptime;
526 u32 txrate;
527 u8 chan_idle;
528 };
529 #endif /* CONNECTION_STATISTICS */
530
531 #ifdef SUPPORT_LQCM
532 #define CMD_SET_LQCM_ENABLE "SET_LQCM_ENABLE"
533 #define CMD_GET_LQCM_REPORT "GET_LQCM_REPORT"
534 #endif
535
536 static LIST_HEAD(miracast_resume_list);
537 #ifdef WL_CFG80211
538 static u8 miracast_cur_mode;
539 #endif /* WL_CFG80211 */
540
541 #ifdef DHD_LOG_DUMP
542 #define CMD_NEW_DEBUG_PRINT_DUMP "DEBUG_DUMP"
543 #define SUBCMD_UNWANTED "UNWANTED"
544 #define SUBCMD_DISCONNECTED "DISCONNECTED"
545 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
546 #endif /* DHD_LOG_DUMP */
547
548 #ifdef DHD_STATUS_LOGGING
549 #define CMD_DUMP_STATUS_LOG "DUMP_STAT_LOG"
550 #define CMD_QUERY_STATUS_LOG "QUERY_STAT_LOG"
551 #endif /* DHD_STATUS_LOGGING */
552
553 #ifdef DHD_HANG_SEND_UP_TEST
554 #define CMD_MAKE_HANG "MAKE_HANG"
555 #endif /* CMD_DHD_HANG_SEND_UP_TEST */
556 #ifdef DHD_DEBUG_UART
557 extern bool dhd_debug_uart_is_running(struct net_device *dev);
558 #endif /* DHD_DEBUG_UART */
559
560 #ifdef RTT_GEOFENCE_INTERVAL
561 #if defined (RTT_SUPPORT) && defined(WL_NAN)
562 #define CMD_GEOFENCE_INTERVAL "GEOFENCE_INT"
563 #endif /* RTT_SUPPORT && WL_NAN */
564 #endif /* RTT_GEOFENCE_INTERVAL */
565
566 struct io_cfg {
567 s8 *iovar;
568 s32 param;
569 u32 ioctl;
570 void *arg;
571 u32 len;
572 struct list_head list;
573 };
574
575 #if defined(BCMFW_ROAM_ENABLE)
576 #define CMD_SET_ROAMPREF "SET_ROAMPREF"
577
578 #define MAX_NUM_SUITES 10
579 #define WIDTH_AKM_SUITE 8
580 #define JOIN_PREF_RSSI_LEN 0x02
581 #define JOIN_PREF_RSSI_SIZE 4 /* RSSI pref header size in bytes */
582 #define JOIN_PREF_WPA_HDR_SIZE 4 /* WPA pref header size in bytes */
583 #define JOIN_PREF_WPA_TUPLE_SIZE 12 /* Tuple size in bytes */
584 #define JOIN_PREF_MAX_WPA_TUPLES 16
585 #define MAX_BUF_SIZE (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
586 (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
587 #endif /* BCMFW_ROAM_ENABLE */
588
589 #if defined(CONFIG_TIZEN)
590 /*
591 * adding these private commands corresponding to atd-server's implementation
592 * __atd_control_pm_state()
593 */
594 #define CMD_POWERSAVEMODE_SET "SETPOWERSAVEMODE"
595 #define CMD_POWERSAVEMODE_GET "GETPOWERSAVEMODE"
596 #endif /* CONFIG_TIZEN */
597
598 #define CMD_DEBUG_VERBOSE "DEBUG_VERBOSE"
599 #ifdef WL_NATOE
600
601 #define CMD_NATOE "NATOE"
602
603 #define NATOE_MAX_PORT_NUM 65535
604
605 /* natoe command info structure */
606 typedef struct wl_natoe_cmd_info {
607 uint8 *command; /* pointer to the actual command */
608 uint16 tot_len; /* total length of the command */
609 uint16 bytes_written; /* Bytes written for get response */
610 } wl_natoe_cmd_info_t;
611
612 typedef struct wl_natoe_sub_cmd wl_natoe_sub_cmd_t;
613 typedef int (natoe_cmd_handler_t)(struct net_device *dev,
614 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
615
616 struct wl_natoe_sub_cmd {
617 char *name;
618 uint8 version; /* cmd version */
619 uint16 id; /* id for the dongle f/w switch/case */
620 uint16 type; /* base type of argument */
621 natoe_cmd_handler_t *handler; /* cmd handler */
622 };
623
624 #define WL_ANDROID_NATOE_FUNC(suffix) wl_android_natoe_subcmd_ ##suffix
625 static int wl_android_process_natoe_cmd(struct net_device *dev,
626 char *command, int total_len);
627 static int wl_android_natoe_subcmd_enable(struct net_device *dev,
628 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
629 static int wl_android_natoe_subcmd_config_ips(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_ports(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_dbg_stats(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_tbl_cnt(struct net_device *dev,
636 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info);
637
638 static const wl_natoe_sub_cmd_t natoe_cmd_list[] = {
639 /* wl natoe enable [0/1] or new: "wl natoe [0/1]" */
640 {"enable", 0x01, WL_NATOE_CMD_ENABLE,
641 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(enable)
642 },
643 {"config_ips", 0x01, WL_NATOE_CMD_CONFIG_IPS,
644 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ips)
645 },
646 {"config_ports", 0x01, WL_NATOE_CMD_CONFIG_PORTS,
647 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(config_ports)
648 },
649 {"stats", 0x01, WL_NATOE_CMD_DBG_STATS,
650 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(dbg_stats)
651 },
652 {"tbl_cnt", 0x01, WL_NATOE_CMD_TBL_CNT,
653 IOVT_BUFFER, WL_ANDROID_NATOE_FUNC(tbl_cnt)
654 },
655 {NULL, 0, 0, 0, NULL}
656 };
657
658 #endif /* WL_NATOE */
659
660 #ifdef SET_PCIE_IRQ_CPU_CORE
661 #define CMD_PCIE_IRQ_CORE "PCIE_IRQ_CORE"
662 #endif /* SET_PCIE_IRQ_CPU_CORE */
663
664 #ifdef WLADPS_PRIVATE_CMD
665 #define CMD_SET_ADPS "SET_ADPS"
666 #define CMD_GET_ADPS "GET_ADPS"
667 #ifdef WLADPS_ENERGY_GAIN
668 #define CMD_GET_GAIN_ADPS "GET_GAIN_ADPS"
669 #define CMD_RESET_GAIN_ADPS "RESET_GAIN_ADPS"
670 #ifndef ADPS_GAIN_2G_PM0_IDLE
671 #define ADPS_GAIN_2G_PM0_IDLE 0
672 #endif
673 #ifndef ADPS_GAIN_5G_PM0_IDLE
674 #define ADPS_GAIN_5G_PM0_IDLE 0
675 #endif
676 #ifndef ADPS_GAIN_2G_TX_PSPOLL
677 #define ADPS_GAIN_2G_TX_PSPOLL 0
678 #endif
679 #ifndef ADPS_GAIN_5G_TX_PSPOLL
680 #define ADPS_GAIN_5G_TX_PSPOLL 0
681 #endif
682 #endif /* WLADPS_ENERGY_GAIN */
683 #endif /* WLADPS_PRIVATE_CMD */
684
685 #ifdef DHD_PKT_LOGGING
686 #define CMD_PKTLOG_FILTER_ENABLE "PKTLOG_FILTER_ENABLE"
687 #define CMD_PKTLOG_FILTER_DISABLE "PKTLOG_FILTER_DISABLE"
688 #define CMD_PKTLOG_FILTER_PATTERN_ENABLE "PKTLOG_FILTER_PATTERN_ENABLE"
689 #define CMD_PKTLOG_FILTER_PATTERN_DISABLE "PKTLOG_FILTER_PATTERN_DISABLE"
690 #define CMD_PKTLOG_FILTER_ADD "PKTLOG_FILTER_ADD"
691 #define CMD_PKTLOG_FILTER_DEL "PKTLOG_FILTER_DEL"
692 #define CMD_PKTLOG_FILTER_INFO "PKTLOG_FILTER_INFO"
693 #define CMD_PKTLOG_START "PKTLOG_START"
694 #define CMD_PKTLOG_STOP "PKTLOG_STOP"
695 #define CMD_PKTLOG_FILTER_EXIST "PKTLOG_FILTER_EXIST"
696 #define CMD_PKTLOG_MINMIZE_ENABLE "PKTLOG_MINMIZE_ENABLE"
697 #define CMD_PKTLOG_MINMIZE_DISABLE "PKTLOG_MINMIZE_DISABLE"
698 #define CMD_PKTLOG_CHANGE_SIZE "PKTLOG_CHANGE_SIZE"
699 #define CMD_PKTLOG_DEBUG_DUMP "PKTLOG_DEBUG_DUMP"
700 #endif /* DHD_PKT_LOGGING */
701
702 #ifdef DHD_EVENT_LOG_FILTER
703 #define CMD_EWP_FILTER "EWP_FILTER"
704 #endif /* DHD_EVENT_LOG_FILTER */
705
706 #ifdef WL_BCNRECV
707 #define CMD_BEACON_RECV "BEACON_RECV"
708 #endif /* WL_BCNRECV */
709 #ifdef WL_CAC_TS
710 #define CMD_CAC_TSPEC "CAC_TSPEC"
711 #endif /* WL_CAC_TS */
712 #ifdef WL_GET_CU
713 #define CMD_GET_CHAN_UTIL "GET_CU"
714 #endif /* WL_GET_CU */
715
716 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
717 #define CMD_SET_SOFTAP_ELNA_BYPASS "SET_SOFTAP_ELNA_BYPASS"
718 #define CMD_GET_SOFTAP_ELNA_BYPASS "GET_SOFTAP_ELNA_BYPASS"
719 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
720
721 #ifdef WL_NAN
722 #define CMD_GET_NAN_STATUS "GET_NAN_STATUS"
723 #endif /* WL_NAN */
724
725 #ifdef WL_TWT
726 #define CMD_TWT_SETUP "TWT_SETUP"
727 #define CMD_TWT_TEARDOWN "TWT_TEARDOWN"
728 #define CMD_TWT_INFO "TWT_INFO_FRM"
729 #define CMD_TWT_STATUS_QUERY "GET_TWT_STATUS"
730 #define CMD_TWT_CAPABILITY "GET_TWT_CAP"
731 #define CMD_TWT_GET_STATS "GET_TWT_STATISTICS"
732 #define CMD_TWT_CLR_STATS "CLEAR_TWT_STATISTICS"
733 #define WL_TWT_CMD_INVAL 255
734
735 /* setup command name to value conversion */
736 static struct {
737 const char *name;
738 uint8 val;
739 } setup_cmd_val[] = {
740 {"request", TWT_SETUP_CMD_REQUEST_TWT},
741 {"suggest", TWT_SETUP_CMD_SUGGEST_TWT},
742 {"demand", TWT_SETUP_CMD_DEMAND_TWT},
743 {"accept", TWT_SETUP_CMD_ACCEPT_TWT},
744 {"alternate", TWT_SETUP_CMD_ALTER_TWT},
745 {"reject", TWT_SETUP_CMD_REJECT_TWT}
746 };
747 #endif /* WL_TWT */
748
749 /* drv command info structure */
750 typedef struct wl_drv_cmd_info {
751 uint8 *command; /* pointer to the actual command */
752 uint16 tot_len; /* total length of the command */
753 uint16 bytes_written; /* Bytes written for get response */
754 } wl_drv_cmd_info_t;
755
756 typedef struct wl_drv_sub_cmd wl_drv_sub_cmd_t;
757 typedef int (drv_cmd_handler_t)(struct net_device *dev,
758 const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
759
760 struct wl_drv_sub_cmd {
761 char *name;
762 uint8 version; /* cmd version */
763 uint16 id; /* id for the dongle f/w switch/case */
764 uint16 type; /* base type of argument */
765 drv_cmd_handler_t *handler; /* cmd handler */
766 };
767
768 #ifdef WL_MBO
769
770 #define CMD_MBO "MBO"
771 enum {
772 WL_MBO_CMD_NON_CHAN_PREF = 1,
773 WL_MBO_CMD_CELL_DATA_CAP = 2
774 };
775 #define WL_ANDROID_MBO_FUNC(suffix) wl_android_mbo_subcmd_ ##suffix
776
777 static int wl_android_process_mbo_cmd(struct net_device *dev,
778 char *command, int total_len);
779 static int wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev,
780 const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
781 static int wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
782 const wl_drv_sub_cmd_t *cmd, char *command, wl_drv_cmd_info_t *cmd_info);
783
784 static const wl_drv_sub_cmd_t mbo_cmd_list[] = {
785 {"non_pref_chan", 0x01, WL_MBO_CMD_NON_CHAN_PREF,
786 IOVT_BUFFER, WL_ANDROID_MBO_FUNC(non_pref_chan)
787 },
788 {"cell_data_cap", 0x01, WL_MBO_CMD_CELL_DATA_CAP,
789 IOVT_BUFFER, WL_ANDROID_MBO_FUNC(cell_data_cap)
790 },
791 {NULL, 0, 0, 0, NULL}
792 };
793
794 #endif /* WL_MBO */
795
796 #ifdef WL_GENL
797 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
798 static int wl_genl_init(void);
799 static int wl_genl_deinit(void);
800
801 extern struct net init_net;
802 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
803 * possible values defined in net/netlink.h
804 */
805 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
806 [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
807 [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
808 };
809
810 #define WL_GENL_VER 1
811 /* family definition */
812 static struct genl_family wl_genl_family = {
813 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
814 .hdrsize = 0,
815 .name = "bcm-genl", /* Netlink I/F for Android */
816 .version = WL_GENL_VER, /* Version Number */
817 .maxattr = BCM_GENL_ATTR_MAX,
818 };
819
820 /* commands: mapping between the command enumeration and the actual function */
821 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
822 struct genl_ops wl_genl_ops[] = {
823 {
824 .cmd = BCM_GENL_CMD_MSG,
825 .flags = 0,
826 .policy = wl_genl_policy,
827 .doit = wl_genl_handle_msg,
828 .dumpit = NULL,
829 },
830 };
831 #else
832 struct genl_ops wl_genl_ops = {
833 .cmd = BCM_GENL_CMD_MSG,
834 .flags = 0,
835 .policy = wl_genl_policy,
836 .doit = wl_genl_handle_msg,
837 .dumpit = NULL,
838
839 };
840 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
841
842 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
843 static struct genl_multicast_group wl_genl_mcast[] = {
844 { .name = "bcm-genl-mcast", },
845 };
846 #else
847 static struct genl_multicast_group wl_genl_mcast = {
848 .id = GENL_ID_GENERATE, /* Genetlink would generate the ID */
849 .name = "bcm-genl-mcast",
850 };
851 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
852 #endif /* WL_GENL */
853
854 #ifdef SUPPORT_LQCM
855 #define LQCM_ENAB_MASK 0x000000FF /* LQCM enable flag mask */
856 #define LQCM_TX_INDEX_MASK 0x0000FF00 /* LQCM tx index mask */
857 #define LQCM_RX_INDEX_MASK 0x00FF0000 /* LQCM rx index mask */
858
859 #define LQCM_TX_INDEX_SHIFT 8 /* LQCM tx index shift */
860 #define LQCM_RX_INDEX_SHIFT 16 /* LQCM rx index shift */
861 #endif /* SUPPORT_LQCM */
862
863 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
864 #define NUMBER_SEQUENTIAL_PRIVCMD_ERRORS 7
865 static int priv_cmd_errors = 0;
866 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
867
868 #ifdef WL_P2P_6G
869 #define CMD_ENABLE_6G_P2P "ENABLE_6G_P2P"
870 #endif /* WL_P2P_6G */
871
872 /**
873 * Extern function declarations (TODO: move them to dhd_linux.h)
874 */
875 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
876 int dhd_dev_init_ioctl(struct net_device *dev);
877 #ifdef WL_CFG80211
878 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
879 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
880 #ifdef WES_SUPPORT
881 int wl_cfg80211_set_wes_mode(struct net_device *dev, int mode);
882 int wl_cfg80211_get_wes_mode(struct net_device *dev);
883 int wl_cfg80211_set_ncho_mode(struct net_device *dev, int mode);
884 int wl_cfg80211_get_ncho_mode(struct net_device *dev);
885 #endif /* WES_SUPPORT */
886 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)887 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
888 { return 0; }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)889 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
890 { return 0; }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)891 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
892 { return 0; }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)893 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
894 { return 0; }
wl_cfg80211_set_p2p_ecsa(struct net_device * net,char * buf,int len)895 int wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
896 { return 0; }
wl_cfg80211_increase_p2p_bw(struct net_device * net,char * buf,int len)897 int wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
898 { return 0; }
899 #endif /* WL_CFG80211 */
900 #if defined(WL_WTC) && defined(CUSTOMER_HW4_PRIVATE_CMD)
901 static int wl_android_wtc_config(struct net_device *dev, char *command, int total_len);
902 #endif /* WL_WTC && CUSTOMER_HW4_PRIVATE_CMD */
903 #ifdef WBTEXT
904 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len);
905 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
906 char *command, int total_len);
907 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
908 char *command, int total_len);
909 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
910 char *command, int total_len);
911 static int wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
912 uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size);
913 #ifdef WES_SUPPORT
914 static int wl_android_wbtext_enable(struct net_device *dev, int mode);
915 #endif // WES_SUPPORT
916 #endif /* WBTEXT */
917 #ifdef WES_SUPPORT
918 /* wl_roam.c */
919 extern int get_roamscan_mode(struct net_device *dev, int *mode);
920 extern int set_roamscan_mode(struct net_device *dev, int mode);
921 extern int get_roamscan_chanspec_list(struct net_device *dev, chanspec_t *chanspecs);
922 extern int set_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
923 extern int add_roamscan_chanspec_list(struct net_device *dev, uint n, chanspec_t *chanspecs);
924
925 static char* legacy_cmdlist[] =
926 {
927 CMD_GETROAMSCANCHLEGACY, CMD_ADDROAMSCANCHLEGACY,
928 CMD_GETROAMSCANFQLEGACY, CMD_ADDROAMSCANFQLEGACY,
929 CMD_GETROAMTRIGLEGACY, CMD_SETROAMTRIGLEGACY,
930 CMD_REASSOCLEGACY,
931 CMD_GETSCANCHANNELTIMELEGACY, CMD_SETSCANCHANNELTIMELEGACY,
932 CMD_GETSCANUNASSOCTIMELEGACY, CMD_SETSCANUNASSOCTIMELEGACY,
933 CMD_GETSCANPASSIVETIMELEGACY, CMD_SETSCANPASSIVETIMELEGACY,
934 CMD_GETSCANHOMETIMELEGACY, CMD_SETSCANHOMETIMELEGACY,
935 CMD_GETSCANHOMEAWAYTIMELEGACY, CMD_SETSCANHOMEAWAYTIMELEGACY,
936 "\0"
937 };
938
939 static char* ncho_cmdlist[] =
940 {
941 CMD_ROAMTRIGGER_GET, CMD_ROAMTRIGGER_SET,
942 CMD_ROAMDELTA_GET, CMD_ROAMDELTA_SET,
943 CMD_ROAMSCANPERIOD_GET, CMD_ROAMSCANPERIOD_SET,
944 CMD_FULLROAMSCANPERIOD_GET, CMD_FULLROAMSCANPERIOD_SET,
945 CMD_COUNTRYREV_GET, CMD_COUNTRYREV_SET,
946 CMD_GETROAMSCANCONTROL, CMD_SETROAMSCANCONTROL,
947 CMD_GETROAMSCANCHANNELS, CMD_SETROAMSCANCHANNELS, CMD_ADDROAMSCANCHANNELS,
948 CMD_GETROAMSCANFREQS, CMD_SETROAMSCANFREQS, CMD_ADDROAMSCANFREQS,
949 CMD_SENDACTIONFRAME,
950 CMD_REASSOC,
951 CMD_GETSCANCHANNELTIME, CMD_SETSCANCHANNELTIME,
952 CMD_GETSCANUNASSOCTIME, CMD_SETSCANUNASSOCTIME,
953 CMD_GETSCANPASSIVETIME, CMD_SETSCANPASSIVETIME,
954 CMD_GETSCANHOMETIME, CMD_SETSCANHOMETIME,
955 CMD_GETSCANHOMEAWAYTIME, CMD_SETSCANHOMEAWAYTIME,
956 CMD_GETSCANNPROBES, CMD_SETSCANNPROBES,
957 CMD_GETDFSSCANMODE, CMD_SETDFSSCANMODE,
958 CMD_SETJOINPREFER,
959 CMD_GETWESMODE, CMD_SETWESMODE,
960 "\0"
961 };
962 #endif /* WES_SUPPORT */
963 #ifdef ROAM_CHANNEL_CACHE
964 extern void wl_update_roamscan_cache_by_band(struct net_device *dev, int band);
965 #endif /* ROAM_CHANNEL_CACHE */
966
967 int wl_android_priority_roam_enable(struct net_device *dev, int mode);
968 #ifdef CONFIG_SILENT_ROAM
969 int wl_android_sroam_turn_on(struct net_device *dev, int mode);
970 #endif /* CONFIG_SILENT_ROAM */
971 int wl_android_rcroam_turn_on(struct net_device *dev, int mode);
972
973 #ifdef ENABLE_4335BT_WAR
974 extern int bcm_bt_lock(int cookie);
975 extern void bcm_bt_unlock(int cookie);
976 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
977 #endif /* ENABLE_4335BT_WAR */
978
979 extern bool ap_fw_loaded;
980 extern char iface_name[IFNAMSIZ];
981 #ifdef DHD_PM_CONTROL_FROM_FILE
982 extern bool g_pm_control;
983 #endif /* DHD_PM_CONTROL_FROM_FILE */
984
985 /* private command support for restoring roam/scan parameters */
986 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
987 #define CMD_RESTORE_SCAN_PARAMS "RESTORE_SCAN_PARAMS"
988
989 typedef int (*PRIV_CMD_HANDLER) (struct net_device *dev, char *command);
990 typedef int (*PRIV_CMD_HANDLER_WITH_LEN) (struct net_device *dev, char *command, int total_len);
991
992 enum {
993 RESTORE_TYPE_UNSPECIFIED = 0,
994 RESTORE_TYPE_PRIV_CMD = 1,
995 RESTORE_TYPE_PRIV_CMD_WITH_LEN = 2
996 };
997
998 typedef struct android_restore_scan_params {
999 char command[64];
1000 int parameter;
1001 int cmd_type;
1002 union {
1003 PRIV_CMD_HANDLER cmd_handler;
1004 PRIV_CMD_HANDLER_WITH_LEN cmd_handler_w_len;
1005 };
1006 } android_restore_scan_params_t;
1007
1008 /* function prototypes of private command handler */
1009 static int wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len);
1010 static int wl_android_set_roam_trigger(struct net_device *dev, char* command);
1011 int wl_android_set_roam_delta(struct net_device *dev, char* command);
1012 int wl_android_set_roam_scan_period(struct net_device *dev, char* command);
1013 int wl_android_set_full_roam_scan_period(struct net_device *dev, char* command);
1014 int wl_android_set_roam_scan_control(struct net_device *dev, char *command);
1015 int wl_android_set_scan_channel_time(struct net_device *dev, char *command);
1016 int wl_android_set_scan_home_time(struct net_device *dev, char *command);
1017 int wl_android_set_scan_home_away_time(struct net_device *dev, char *command);
1018 int wl_android_set_scan_nprobes(struct net_device *dev, char *command);
1019 static int wl_android_set_band(struct net_device *dev, char *command);
1020 int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command);
1021 int wl_android_set_wes_mode(struct net_device *dev, char *command);
1022 int wl_android_set_okc_mode(struct net_device *dev, char *command);
1023
1024 /* default values */
1025 #ifdef ROAM_API
1026 #define DEFAULT_ROAM_TIRGGER -75
1027 #define DEFAULT_ROAM_DELTA 10
1028 #define DEFAULT_ROAMSCANPERIOD 10
1029 #define DEFAULT_FULLROAMSCANPERIOD_SET 120
1030 #endif /* ROAM_API */
1031 #ifdef WES_SUPPORT
1032 #define DEFAULT_ROAMSCANCONTROL 0
1033 #define DEFAULT_SCANCHANNELTIME 40
1034 #ifdef BCM4361_CHIP
1035 #define DEFAULT_SCANHOMETIME 60
1036 #else
1037 #define DEFAULT_SCANHOMETIME 45
1038 #endif /* BCM4361_CHIP */
1039 #define DEFAULT_SCANHOMEAWAYTIME 100
1040 #define DEFAULT_SCANPROBES 2
1041 #define DEFAULT_DFSSCANMODE 1
1042 #define DEFAULT_WESMODE 0
1043 #define DEFAULT_OKCMODE 1
1044 #endif /* WES_SUPPORT */
1045 #define DEFAULT_BAND 0
1046 #ifdef WBTEXT
1047 #define DEFAULT_WBTEXT_ENABLE 1
1048 #endif /* WBTEXT */
1049
1050 /* restoring parameter list, please don't change order */
1051 static android_restore_scan_params_t restore_params[] =
1052 {
1053 /* wbtext need to be disabled while updating roam/scan parameters */
1054 #ifdef WBTEXT
1055 { CMD_WBTEXT_ENABLE, 0, RESTORE_TYPE_PRIV_CMD_WITH_LEN,
1056 .cmd_handler_w_len = wl_android_wbtext},
1057 #endif /* WBTEXT */
1058 #ifdef ROAM_API
1059 { CMD_ROAMTRIGGER_SET, DEFAULT_ROAM_TIRGGER,
1060 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_trigger},
1061 { CMD_ROAMDELTA_SET, DEFAULT_ROAM_DELTA,
1062 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_delta},
1063 { CMD_ROAMSCANPERIOD_SET, DEFAULT_ROAMSCANPERIOD,
1064 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_period},
1065 { CMD_FULLROAMSCANPERIOD_SET, DEFAULT_FULLROAMSCANPERIOD_SET,
1066 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_full_roam_scan_period},
1067 #endif /* ROAM_API */
1068 #ifdef WES_SUPPORT
1069 { CMD_SETROAMSCANCONTROL, DEFAULT_ROAMSCANCONTROL,
1070 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_roam_scan_control},
1071 { CMD_SETSCANCHANNELTIME, DEFAULT_SCANCHANNELTIME,
1072 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_channel_time},
1073 { CMD_SETSCANHOMETIME, DEFAULT_SCANHOMETIME,
1074 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_time},
1075 { CMD_GETSCANHOMEAWAYTIME, DEFAULT_SCANHOMEAWAYTIME,
1076 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_home_away_time},
1077 { CMD_SETSCANNPROBES, DEFAULT_SCANPROBES,
1078 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_nprobes},
1079 { CMD_SETDFSSCANMODE, DEFAULT_DFSSCANMODE,
1080 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_scan_dfs_channel_mode},
1081 { CMD_SETWESMODE, DEFAULT_WESMODE,
1082 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_wes_mode},
1083 #endif /* WES_SUPPORT */
1084 { CMD_SETBAND, DEFAULT_BAND,
1085 RESTORE_TYPE_PRIV_CMD, .cmd_handler = wl_android_set_band},
1086 #ifdef WBTEXT
1087 { CMD_WBTEXT_ENABLE, DEFAULT_WBTEXT_ENABLE,
1088 RESTORE_TYPE_PRIV_CMD_WITH_LEN, .cmd_handler_w_len = wl_android_wbtext},
1089 #endif /* WBTEXT */
1090 { "\0", 0, RESTORE_TYPE_UNSPECIFIED, .cmd_handler = NULL}
1091 };
1092 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
1093
1094 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1095 #define CMD_GET_LATENCY_CRITICAL_DATA "GET_LATENCY_CRT_DATA"
1096 #define CMD_SET_LATENCY_CRITICAL_DATA "SET_LATENCY_CRT_DATA"
1097 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
1098
1099 typedef struct android_priv_cmd_log_cfg_table {
1100 char command[64];
1101 int enable;
1102 } android_priv_cmd_log_cfg_table_t;
1103
1104 static android_priv_cmd_log_cfg_table_t loging_params[] = {
1105 {CMD_GET_SNR, FALSE},
1106 #ifdef SUPPORT_LQCM
1107 {CMD_GET_LQCM_REPORT, FALSE},
1108 #endif
1109 #ifdef WL_GET_CU
1110 {CMD_GET_CHAN_UTIL, FALSE},
1111 #endif
1112 {"\0", FALSE}
1113 };
1114
1115 /**
1116 * Local (static) functions and variables
1117 */
1118
1119 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
1120 * time (only) in dhd_open, subsequential wifi on will be handled by
1121 * wl_android_wifi_on
1122 */
1123 int g_wifi_on = TRUE;
1124
1125 /**
1126 * Local (static) function definitions
1127 */
1128
wl_android_get_band_str(u16 band)1129 static char* wl_android_get_band_str(u16 band)
1130 {
1131 switch (band) {
1132 #ifdef WL_6G_BAND
1133 case WLC_BAND_6G:
1134 return "6G";
1135 #endif /* WL_6G_BAND */
1136 case WLC_BAND_5G:
1137 return "5G";
1138 case WLC_BAND_2G:
1139 return "2G";
1140 default:
1141 ANDROID_ERROR(("Unkown band: %d \n", band));
1142 return "Unknown band";
1143 }
1144 }
1145
1146 #ifdef WBTEXT
wl_android_bandstr_to_fwband(char * band,u8 * fw_band)1147 static int wl_android_bandstr_to_fwband(char *band, u8 *fw_band)
1148 {
1149 int err = BCME_OK;
1150
1151 if (!strcasecmp(band, "a")) {
1152 *fw_band = WLC_BAND_5G;
1153 } else if (!strcasecmp(band, "b")) {
1154 *fw_band = WLC_BAND_2G;
1155 #ifdef WL_6G_BAND
1156 } else if (!strcasecmp(band, "6g")) {
1157 *fw_band = WLC_BAND_6G;
1158 #endif /* WL_6G_BAND */
1159 } else if (!strcasecmp(band, "all")) {
1160 *fw_band = WLC_BAND_ALL;
1161 } else {
1162 err = BCME_BADBAND;
1163 }
1164
1165 return err;
1166 }
1167 #endif /* WBTEXT */
1168
1169 #ifdef WLWFDS
wl_android_set_wfds_hash(struct net_device * dev,char * command,bool enable)1170 static int wl_android_set_wfds_hash(
1171 struct net_device *dev, char *command, bool enable)
1172 {
1173 int error = 0;
1174 wl_p2p_wfds_hash_t *wfds_hash = NULL;
1175 char *smbuf = NULL;
1176 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
1177
1178 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
1179 if (smbuf == NULL) {
1180 ANDROID_ERROR(("wl_android_set_wfds_hash: failed to allocated memory %d bytes\n",
1181 WLC_IOCTL_MAXLEN));
1182 return -ENOMEM;
1183 }
1184
1185 if (enable) {
1186 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_ADD_WFDS_HASH) + 1);
1187 error = wldev_iovar_setbuf(dev, "p2p_add_wfds_hash", wfds_hash,
1188 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1189 }
1190 else {
1191 wfds_hash = (wl_p2p_wfds_hash_t *)(command + strlen(CMD_DEL_WFDS_HASH) + 1);
1192 error = wldev_iovar_setbuf(dev, "p2p_del_wfds_hash", wfds_hash,
1193 sizeof(wl_p2p_wfds_hash_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
1194 }
1195
1196 if (error) {
1197 ANDROID_ERROR(("wl_android_set_wfds_hash: failed to %s, error=%d\n", command, error));
1198 }
1199
1200 if (smbuf) {
1201 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
1202 }
1203 return error;
1204 }
1205 #endif /* WLWFDS */
1206
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)1207 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
1208 {
1209 int link_speed;
1210 int bytes_written;
1211 int error;
1212
1213 error = wldev_get_link_speed(net, &link_speed);
1214 if (error) {
1215 ANDROID_ERROR(("Get linkspeed failed \n"));
1216 return -1;
1217 }
1218
1219 /* Convert Kbps to Android Mbps */
1220 link_speed = link_speed / 1000;
1221 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
1222 ANDROID_INFO(("wl_android_get_link_speed: command result is %s\n", command));
1223 return bytes_written;
1224 }
1225
wl_android_get_rssi(struct net_device * net,char * command,int total_len)1226 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
1227 {
1228 wlc_ssid_t ssid = {0, {0}};
1229 int bytes_written = 0;
1230 int error = 0;
1231 scb_val_t scbval;
1232 char *delim = NULL;
1233 struct net_device *target_ndev = net;
1234 #ifdef WL_VIRTUAL_APSTA
1235 char *pos = NULL;
1236 struct bcm_cfg80211 *cfg;
1237 #endif /* WL_VIRTUAL_APSTA */
1238
1239 delim = strchr(command, ' ');
1240 /* For Ap mode rssi command would be
1241 * driver rssi <sta_mac_addr>
1242 * for STA/GC mode
1243 * driver rssi
1244 */
1245 if (delim) {
1246 /* Ap/GO mode
1247 * driver rssi <sta_mac_addr>
1248 */
1249 ANDROID_TRACE(("wl_android_get_rssi: cmd:%s\n", delim));
1250 /* skip space from delim after finding char */
1251 delim++;
1252 if (!(bcm_ether_atoe((delim), &scbval.ea))) {
1253 ANDROID_ERROR(("wl_android_get_rssi: address err\n"));
1254 return -1;
1255 }
1256 scbval.val = htod32(0);
1257 ANDROID_TRACE(("wl_android_get_rssi: address:"MACDBG, MAC2STRDBG(scbval.ea.octet)));
1258 #ifdef WL_VIRTUAL_APSTA
1259 /* RSDB AP may have another virtual interface
1260 * In this case, format of private command is as following,
1261 * DRIVER rssi <sta_mac_addr> <AP interface name>
1262 */
1263
1264 /* Current position is start of MAC address string */
1265 pos = delim;
1266 delim = strchr(pos, ' ');
1267 if (delim) {
1268 /* skip space from delim after finding char */
1269 delim++;
1270 if (strnlen(delim, IFNAMSIZ)) {
1271 cfg = wl_get_cfg(net);
1272 target_ndev = wl_get_ap_netdev(cfg, delim);
1273 if (target_ndev == NULL)
1274 target_ndev = net;
1275 }
1276 }
1277 #endif /* WL_VIRTUAL_APSTA */
1278 }
1279 else {
1280 /* STA/GC mode */
1281 bzero(&scbval, sizeof(scb_val_t));
1282 }
1283
1284 error = wldev_get_rssi(target_ndev, &scbval);
1285 if (error)
1286 return -1;
1287 #if defined(RSSIOFFSET)
1288 scbval.val = wl_update_rssi_offset(net, scbval.val);
1289 #endif
1290
1291 error = wldev_get_ssid(target_ndev, &ssid);
1292 if (error)
1293 return -1;
1294 if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
1295 ANDROID_ERROR(("wl_android_get_rssi: wldev_get_ssid failed\n"));
1296 } else if (total_len <= ssid.SSID_len) {
1297 return -ENOMEM;
1298 } else {
1299 memcpy(command, ssid.SSID, ssid.SSID_len);
1300 bytes_written = ssid.SSID_len;
1301 }
1302 if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
1303 return -ENOMEM;
1304
1305 bytes_written += scnprintf(&command[bytes_written], total_len - bytes_written,
1306 " rssi %d", scbval.val);
1307 command[bytes_written] = '\0';
1308
1309 ANDROID_TRACE(("wl_android_get_rssi: command result is %s (%d)\n", command, bytes_written));
1310 return bytes_written;
1311 }
1312
wl_android_set_suspendopt(struct net_device * dev,char * command)1313 static int wl_android_set_suspendopt(struct net_device *dev, char *command)
1314 {
1315 int suspend_flag;
1316 int ret_now;
1317 int ret = 0;
1318
1319 suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
1320
1321 if (suspend_flag != 0) {
1322 suspend_flag = 1;
1323 }
1324 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1325
1326 if (ret_now != suspend_flag) {
1327 if (!(ret = net_os_set_suspend(dev, ret_now, 1))) {
1328 ANDROID_INFO(("wl_android_set_suspendopt: Suspend Flag %d -> %d\n",
1329 ret_now, suspend_flag));
1330 } else {
1331 ANDROID_ERROR(("wl_android_set_suspendopt: failed %d\n", ret));
1332 }
1333 }
1334
1335 return ret;
1336 }
1337
wl_android_set_suspendmode(struct net_device * dev,char * command)1338 static int wl_android_set_suspendmode(struct net_device *dev, char *command)
1339 {
1340 int ret = 0;
1341
1342 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
1343 int suspend_flag;
1344
1345 suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
1346 if (suspend_flag != 0)
1347 suspend_flag = 1;
1348
1349 if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
1350 ANDROID_INFO(("wl_android_set_suspendmode: Suspend Mode %d\n", suspend_flag));
1351 else
1352 ANDROID_ERROR(("wl_android_set_suspendmode: failed %d\n", ret));
1353 #endif
1354
1355 return ret;
1356 }
1357
1358 #ifdef WL_CFG80211
wl_android_get_80211_mode(struct net_device * dev,char * command,int total_len)1359 int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
1360 {
1361 uint8 mode[5];
1362 int error = 0;
1363 int bytes_written = 0;
1364
1365 error = wldev_get_mode(dev, mode, sizeof(mode));
1366 if (error)
1367 return -1;
1368
1369 ANDROID_INFO(("wl_android_get_80211_mode: mode:%s\n", mode));
1370 bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
1371 ANDROID_INFO(("wl_android_get_80211_mode: command:%s EXIT\n", command));
1372 return bytes_written;
1373
1374 }
1375
1376 extern chanspec_t
1377 wl_chspec_driver_to_host(chanspec_t chanspec);
wl_android_get_chanspec(struct net_device * dev,char * command,int total_len)1378 int wl_android_get_chanspec(struct net_device *dev, char *command, int total_len)
1379 {
1380 int error = 0;
1381 int bytes_written = 0;
1382 int chsp = {0};
1383 uint16 band = 0;
1384 uint16 bw = 0;
1385 uint16 channel = 0;
1386 u32 sb = 0;
1387 chanspec_t chanspec;
1388
1389 /* command is
1390 * driver chanspec
1391 */
1392 error = wldev_iovar_getint(dev, "chanspec", &chsp);
1393 if (error)
1394 return -1;
1395
1396 chanspec = wl_chspec_driver_to_host(chsp);
1397 ANDROID_INFO(("wl_android_get_80211_mode: return value of chanspec:%x\n", chanspec));
1398
1399 channel = chanspec & WL_CHANSPEC_CHAN_MASK;
1400 band = chanspec & WL_CHANSPEC_BAND_MASK;
1401 bw = chanspec & WL_CHANSPEC_BW_MASK;
1402
1403 ANDROID_INFO(("wl_android_get_80211_mode: channel:%d band:%d bandwidth:%d\n",
1404 channel, band, bw));
1405
1406 if (bw == WL_CHANSPEC_BW_160) {
1407 bw = WL_CH_BANDWIDTH_160MHZ;
1408 } else if (bw == WL_CHANSPEC_BW_80) {
1409 bw = WL_CH_BANDWIDTH_80MHZ;
1410 } else if (bw == WL_CHANSPEC_BW_40) {
1411 bw = WL_CH_BANDWIDTH_40MHZ;
1412 } else if (bw == WL_CHANSPEC_BW_20) {
1413 bw = WL_CH_BANDWIDTH_20MHZ;
1414 } else {
1415 bw = WL_CH_BANDWIDTH_20MHZ;
1416 }
1417
1418 if (bw == WL_CH_BANDWIDTH_40MHZ) {
1419 if (CHSPEC_SB_UPPER(chanspec)) {
1420 channel += CH_10MHZ_APART;
1421 } else {
1422 channel -= CH_10MHZ_APART;
1423 }
1424 }
1425 else if (bw == WL_CH_BANDWIDTH_80MHZ) {
1426 sb = chanspec & WL_CHANSPEC_CTL_SB_MASK;
1427 if (sb == WL_CHANSPEC_CTL_SB_LL) {
1428 channel -= (CH_10MHZ_APART + CH_20MHZ_APART);
1429 } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
1430 channel -= CH_10MHZ_APART;
1431 } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
1432 channel += CH_10MHZ_APART;
1433 } else {
1434 /* WL_CHANSPEC_CTL_SB_UU */
1435 channel += (CH_10MHZ_APART + CH_20MHZ_APART);
1436 }
1437 } else if (bw == WL_CH_BANDWIDTH_160MHZ) {
1438 channel = wf_chspec_primary20_chan(chanspec);
1439 }
1440 bytes_written = snprintf(command, total_len, "%s channel %d band %s bw %d", CMD_CHANSPEC,
1441 channel, wl_android_get_band_str(CHSPEC2WLC_BAND(chanspec)), bw);
1442
1443 ANDROID_INFO(("wl_android_get_chanspec: command:%s EXIT\n", command));
1444 return bytes_written;
1445
1446 }
1447 #endif /* WL_CFG80211 */
1448
1449 /* returns current datarate datarate returned from firmware are in 500kbps */
wl_android_get_datarate(struct net_device * dev,char * command,int total_len)1450 int wl_android_get_datarate(struct net_device *dev, char *command, int total_len)
1451 {
1452 int error = 0;
1453 int datarate = 0;
1454 int bytes_written = 0;
1455
1456 error = wldev_get_datarate(dev, &datarate);
1457 if (error)
1458 return -1;
1459
1460 ANDROID_INFO(("wl_android_get_datarate: datarate:%d\n", datarate));
1461
1462 bytes_written = snprintf(command, total_len, "%s %d", CMD_DATARATE, (datarate/2));
1463 return bytes_written;
1464 }
wl_android_get_assoclist(struct net_device * dev,char * command,int total_len)1465 int wl_android_get_assoclist(struct net_device *dev, char *command, int total_len)
1466 {
1467 int error = 0;
1468 int bytes_written = 0;
1469 uint i;
1470 int len = 0;
1471 char mac_buf[MAX_NUM_OF_ASSOCLIST *
1472 sizeof(struct ether_addr) + sizeof(uint)] = {0};
1473 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
1474
1475 ANDROID_TRACE(("wl_android_get_assoclist: ENTER\n"));
1476
1477 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
1478
1479 error = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
1480 if (error)
1481 return -1;
1482
1483 assoc_maclist->count = dtoh32(assoc_maclist->count);
1484 bytes_written = snprintf(command, total_len, "%s listcount: %d Stations:",
1485 CMD_ASSOC_CLIENTS, assoc_maclist->count);
1486
1487 for (i = 0; i < assoc_maclist->count; i++) {
1488 len = snprintf(command + bytes_written, total_len - bytes_written, " " MACDBG,
1489 MAC2STRDBG(assoc_maclist->ea[i].octet));
1490 /* A return value of '(total_len - bytes_written)' or more means that the
1491 * output was truncated
1492 */
1493 if ((len > 0) && (len < (total_len - bytes_written))) {
1494 bytes_written += len;
1495 } else {
1496 ANDROID_ERROR(("wl_android_get_assoclist: Insufficient buffer %d,"
1497 " bytes_written %d\n",
1498 total_len, bytes_written));
1499 bytes_written = -1;
1500 break;
1501 }
1502 }
1503 return bytes_written;
1504 }
1505
1506 #ifdef WL_CFG80211
1507 extern chanspec_t
1508 wl_chspec_host_to_driver(chanspec_t chanspec);
wl_android_set_csa(struct net_device * dev,char * command)1509 static int wl_android_set_csa(struct net_device *dev, char *command)
1510 {
1511 int error = 0;
1512 char smbuf[WLC_IOCTL_SMLEN];
1513 wl_chan_switch_t csa_arg;
1514 u32 chnsp = 0;
1515 int err = 0;
1516
1517 ANDROID_INFO(("wl_android_set_csa: command:%s\n", command));
1518
1519 command = (command + strlen(CMD_SET_CSA));
1520 /* Order is mode, count channel */
1521 if (!*++command) {
1522 ANDROID_ERROR(("wl_android_set_csa:error missing arguments\n"));
1523 return -1;
1524 }
1525 csa_arg.mode = bcm_atoi(command);
1526
1527 if (csa_arg.mode != 0 && csa_arg.mode != 1) {
1528 ANDROID_ERROR(("Invalid mode\n"));
1529 return -1;
1530 }
1531
1532 if (!*++command) {
1533 ANDROID_ERROR(("wl_android_set_csa: error missing count\n"));
1534 return -1;
1535 }
1536 command++;
1537 csa_arg.count = bcm_atoi(command);
1538
1539 csa_arg.reg = 0;
1540 csa_arg.chspec = 0;
1541 command += 2;
1542 if (!*command) {
1543 ANDROID_ERROR(("wl_android_set_csa: error missing channel\n"));
1544 return -1;
1545 }
1546
1547 chnsp = wf_chspec_aton(command);
1548 if (chnsp == 0) {
1549 ANDROID_ERROR(("wl_android_set_csa:chsp is not correct\n"));
1550 return -1;
1551 }
1552 chnsp = wl_chspec_host_to_driver(chnsp);
1553 csa_arg.chspec = chnsp;
1554
1555 if (chnsp & WL_CHANSPEC_BAND_5G) {
1556 u32 chanspec = chnsp;
1557 err = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1558 if (!err) {
1559 if ((chanspec & WL_CHAN_RADAR) || (chanspec & WL_CHAN_PASSIVE)) {
1560 ANDROID_ERROR(("Channel is radar sensitive\n"));
1561 return -1;
1562 }
1563 if (chanspec == 0) {
1564 ANDROID_ERROR(("Invalid hw channel\n"));
1565 return -1;
1566 }
1567 } else {
1568 ANDROID_ERROR(("does not support per_chan_info\n"));
1569 return -1;
1570 }
1571 ANDROID_INFO(("non radar sensitivity\n"));
1572 }
1573 error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
1574 smbuf, sizeof(smbuf), NULL);
1575 if (error) {
1576 ANDROID_ERROR(("wl_android_set_csa:set csa failed:%d\n", error));
1577 return -1;
1578 }
1579 return 0;
1580 }
1581 #endif /* WL_CFG80211 */
1582
1583 static int
wl_android_set_bcn_li_dtim(struct net_device * dev,char * command)1584 wl_android_set_bcn_li_dtim(struct net_device *dev, char *command)
1585 {
1586 int ret = 0;
1587 int dtim;
1588
1589 dtim = *(command + strlen(CMD_SETDTIM_IN_SUSPEND) + 1) - '0';
1590
1591 if (dtim > (MAX_DTIM_ALLOWED_INTERVAL / MAX_DTIM_SKIP_BEACON_INTERVAL)) {
1592 ANDROID_ERROR(("%s: failed, invalid dtim %d\n",
1593 __FUNCTION__, dtim));
1594 return BCME_ERROR;
1595 }
1596
1597 if (!(ret = net_os_set_suspend_bcn_li_dtim(dev, dtim))) {
1598 ANDROID_TRACE(("%s: SET bcn_li_dtim in suspend %d\n",
1599 __FUNCTION__, dtim));
1600 } else {
1601 ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1602 }
1603
1604 return ret;
1605 }
1606
1607 static int
wl_android_set_max_dtim(struct net_device * dev,char * command)1608 wl_android_set_max_dtim(struct net_device *dev, char *command)
1609 {
1610 int ret = 0;
1611 int dtim_flag;
1612
1613 dtim_flag = *(command + strlen(CMD_MAXDTIM_IN_SUSPEND) + 1) - '0';
1614
1615 if (!(ret = net_os_set_max_dtim_enable(dev, dtim_flag))) {
1616 ANDROID_TRACE(("wl_android_set_max_dtim: use Max bcn_li_dtim in suspend %s\n",
1617 (dtim_flag ? "Enable" : "Disable")));
1618 } else {
1619 ANDROID_ERROR(("wl_android_set_max_dtim: failed %d\n", ret));
1620 }
1621
1622 return ret;
1623 }
1624
1625 #ifdef DISABLE_DTIM_IN_SUSPEND
1626 static int
wl_android_set_disable_dtim_in_suspend(struct net_device * dev,char * command)1627 wl_android_set_disable_dtim_in_suspend(struct net_device *dev, char *command)
1628 {
1629 int ret = 0;
1630 int dtim_flag;
1631
1632 dtim_flag = *(command + strlen(CMD_DISDTIM_IN_SUSPEND) + 1) - '0';
1633
1634 if (!(ret = net_os_set_disable_dtim_in_suspend(dev, dtim_flag))) {
1635 ANDROID_TRACE(("wl_android_set_disable_dtim_in_suspend: "
1636 "use Disable bcn_li_dtim in suspend %s\n",
1637 (dtim_flag ? "Enable" : "Disable")));
1638 } else {
1639 ANDROID_ERROR(("wl_android_set_disable_dtim_in_suspend: failed %d\n", ret));
1640 }
1641
1642 return ret;
1643 }
1644 #endif /* DISABLE_DTIM_IN_SUSPEND */
1645
wl_android_get_band(struct net_device * dev,char * command,int total_len)1646 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
1647 {
1648 uint band;
1649 int bytes_written;
1650 int error = BCME_OK;
1651
1652 error = wldev_iovar_getint(dev, "if_band", &band);
1653 if (error == BCME_UNSUPPORTED) {
1654 error = wldev_get_band(dev, &band);
1655 if (error) {
1656 return error;
1657 }
1658 }
1659 bytes_written = snprintf(command, total_len, "Band %d", band);
1660 return bytes_written;
1661 }
1662
1663 #ifdef WL_CFG80211
1664 static int
wl_android_set_band(struct net_device * dev,char * command)1665 wl_android_set_band(struct net_device *dev, char *command)
1666 {
1667 int error = 0;
1668 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
1669 #ifdef WL_HOST_BAND_MGMT
1670 int ret = 0;
1671 if ((ret = wl_cfg80211_set_band(dev, band)) < 0) {
1672 if (ret == BCME_UNSUPPORTED) {
1673 /* If roam_var is unsupported, fallback to the original method */
1674 ANDROID_ERROR(("WL_HOST_BAND_MGMT defined, "
1675 "but roam_band iovar unsupported in the firmware\n"));
1676 } else {
1677 error = -1;
1678 }
1679 }
1680 if (((ret == 0) && (band == WLC_BAND_AUTO)) || (ret == BCME_UNSUPPORTED)) {
1681 /* Apply if roam_band iovar is not supported or band setting is AUTO */
1682 error = wldev_set_band(dev, band);
1683 }
1684 #else
1685 error = wl_cfg80211_set_if_band(dev, band);
1686 #endif /* WL_HOST_BAND_MGMT */
1687 #ifdef ROAM_CHANNEL_CACHE
1688 wl_update_roamscan_cache_by_band(dev, band);
1689 #endif /* ROAM_CHANNEL_CACHE */
1690 return error;
1691 }
1692 #endif /* WL_CFG80211 */
1693
1694 #ifdef CUSTOMER_HW4_PRIVATE_CMD
1695 #ifdef ROAM_API
1696 static bool
wl_android_check_wbtext_policy(struct net_device * dev)1697 wl_android_check_wbtext_policy(struct net_device *dev)
1698 {
1699 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
1700 if (dhdp->wbtext_policy == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) {
1701 return TRUE;
1702 }
1703
1704 return FALSE;
1705 }
1706
1707 static int
wl_android_set_roam_trigger(struct net_device * dev,char * command)1708 wl_android_set_roam_trigger(struct net_device *dev, char* command)
1709 {
1710 int roam_trigger[2] = {0, 0};
1711 int error;
1712
1713 #ifdef WBTEXT
1714 if (wl_android_check_wbtext_policy(dev)) {
1715 ANDROID_ERROR(("blocked to set roam trigger. try with setting roam profile\n"));
1716 return BCME_ERROR;
1717 }
1718 #endif /* WBTEXT */
1719
1720 sscanf(command, "%*s %10d", &roam_trigger[0]);
1721 if (roam_trigger[0] >= 0) {
1722 ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1723 return BCME_ERROR;
1724 }
1725
1726 roam_trigger[1] = WLC_BAND_ALL;
1727 error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1728 sizeof(roam_trigger));
1729 if (error != BCME_OK) {
1730 ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1731 return BCME_ERROR;
1732 }
1733
1734 return BCME_OK;
1735 }
1736
1737 static int
wl_android_get_roam_trigger(struct net_device * dev,char * command,int total_len)1738 wl_android_get_roam_trigger(struct net_device *dev, char *command, int total_len)
1739 {
1740 int bytes_written, error;
1741 int roam_trigger[2] = {0, 0};
1742 uint16 band = 0;
1743 int chsp = {0};
1744 chanspec_t chanspec;
1745 #ifdef WBTEXT
1746 int i;
1747 wl_roamprof_band_t rp;
1748 uint8 roam_prof_ver = 0, roam_prof_size = 0;
1749 #endif /* WBTEXT */
1750
1751 error = wldev_iovar_getint(dev, "chanspec", &chsp);
1752 if (error != BCME_OK) {
1753 ANDROID_ERROR(("failed to get chanspec (%d)\n", error));
1754 return BCME_ERROR;
1755 }
1756
1757 chanspec = wl_chspec_driver_to_host(chsp);
1758 band = CHSPEC2WLC_BAND(chanspec);
1759
1760 if (wl_android_check_wbtext_policy(dev)) {
1761 #ifdef WBTEXT
1762 memset_s(&rp, sizeof(rp), 0, sizeof(rp));
1763 if ((error = wlc_wbtext_get_roam_prof(dev, &rp, band, &roam_prof_ver,
1764 &roam_prof_size))) {
1765 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", error));
1766 return -EINVAL;
1767 }
1768 switch (roam_prof_ver) {
1769 case WL_ROAM_PROF_VER_1:
1770 {
1771 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1772 if (rp.v2.roam_prof[i].channel_usage == 0) {
1773 roam_trigger[0] = rp.v2.roam_prof[i].roam_trigger;
1774 break;
1775 }
1776 }
1777 }
1778 break;
1779 case WL_ROAM_PROF_VER_2:
1780 {
1781 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1782 if (rp.v3.roam_prof[i].channel_usage == 0) {
1783 roam_trigger[0] = rp.v3.roam_prof[i].roam_trigger;
1784 break;
1785 }
1786 }
1787 }
1788 break;
1789 case WL_ROAM_PROF_VER_3:
1790 {
1791 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
1792 if (rp.v4.roam_prof[i].channel_usage == 0) {
1793 roam_trigger[0] = rp.v4.roam_prof[i].roam_trigger;
1794 break;
1795 }
1796 }
1797 }
1798 break;
1799 default:
1800 ANDROID_ERROR(("bad version = %d \n", roam_prof_ver));
1801 return BCME_VERSION;
1802 }
1803 #endif /* WBTEXT */
1804 if (roam_trigger[0] == 0) {
1805 ANDROID_ERROR(("roam trigger was not set properly\n"));
1806 return BCME_ERROR;
1807 }
1808 } else {
1809 roam_trigger[1] = band;
1810 error = wldev_ioctl_get(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
1811 sizeof(roam_trigger));
1812 if (error != BCME_OK) {
1813 ANDROID_ERROR(("failed to get roam trigger (%d)\n", error));
1814 return BCME_ERROR;
1815 }
1816 }
1817
1818 bytes_written = snprintf(command, total_len, "%s %d",
1819 CMD_ROAMTRIGGER_GET, roam_trigger[0]);
1820
1821 return bytes_written;
1822 }
1823
1824 #ifdef WBTEXT
1825 s32
wl_cfg80211_wbtext_roam_trigger_config(struct net_device * ndev,int roam_trigger)1826 wl_cfg80211_wbtext_roam_trigger_config(struct net_device *ndev, int roam_trigger)
1827 {
1828 char *commandp = NULL;
1829 s32 ret = BCME_OK;
1830 char *data;
1831 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
1832 uint8 bandidx = 0;
1833
1834 commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
1835 if (unlikely(!commandp)) {
1836 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
1837 ret = -ENOMEM;
1838 goto exit;
1839 }
1840
1841 ANDROID_INFO(("roam trigger %d\n", roam_trigger));
1842 if (roam_trigger > 0) {
1843 ANDROID_ERROR(("Invalid roam trigger value %d\n", roam_trigger));
1844 goto exit;
1845 }
1846
1847 for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
1848 char *band;
1849 int tri0, tri1, low0, low1, cu0, cu1, dur0, dur1;
1850 int tri0_dflt;
1851 if (bandidx == BAND_5G_INDEX) {
1852 band = "a";
1853 tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_A;
1854 } else {
1855 band = "b";
1856 tri0_dflt = DEFAULT_WBTEXT_CU_RSSI_TRIG_B;
1857 }
1858
1859 /* Get ROAM Profile
1860 * WBTEXT_PROFILE_CONFIG band
1861 */
1862 bzero(commandp, WLC_IOCTL_SMLEN);
1863 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
1864 CMD_WBTEXT_PROFILE_CONFIG, band);
1865 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
1866 wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1867
1868 /* Set ROAM Profile
1869 * WBTEXT_PROFILE_CONFIG band -70 roam_trigger 70 10 roam_trigger -128 0 10
1870 */
1871 sscanf(commandp, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)"
1872 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
1873 &tri0, &low0, &cu0, &dur0, &tri1, &low1, &cu1, &dur1);
1874
1875 if (tri0_dflt <= roam_trigger) {
1876 tri0 = roam_trigger + 1;
1877 } else {
1878 tri0 = tri0_dflt;
1879 }
1880
1881 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
1882 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s %d %d %d %d %d %d %d %d",
1883 CMD_WBTEXT_PROFILE_CONFIG, band,
1884 tri0, roam_trigger, cu0, dur0, roam_trigger, low1, cu1, dur1);
1885
1886 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
1887 if (ret != BCME_OK) {
1888 ANDROID_ERROR(("Failed to set roam_prof %s error = %d\n", data, ret));
1889 goto exit;
1890 }
1891 }
1892
1893 exit:
1894 if (commandp) {
1895 MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
1896 }
1897 return ret;
1898 }
1899 #endif /* WBTEXT */
1900
1901 static int
wl_android_set_roam_trigger_legacy(struct net_device * dev,char * command)1902 wl_android_set_roam_trigger_legacy(struct net_device *dev, char* command)
1903 {
1904 int roam_trigger[2] = {0, 0};
1905 int error;
1906
1907 sscanf(command, "%*s %10d", &roam_trigger[0]);
1908 if (roam_trigger[0] >= 0) {
1909 ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1910 return BCME_ERROR;
1911 }
1912
1913 if (wl_android_check_wbtext_policy(dev)) {
1914 #ifdef WBTEXT
1915 error = wl_cfg80211_wbtext_roam_trigger_config(dev, roam_trigger[0]);
1916 if (error != BCME_OK) {
1917 ANDROID_ERROR(("failed to set roam prof trigger (%d)\n", error));
1918 return BCME_ERROR;
1919 }
1920 #endif /* WBTEXT */
1921 } else {
1922 if (roam_trigger[0] >= 0) {
1923 ANDROID_ERROR(("wrong roam trigger value (%d)\n", roam_trigger[0]));
1924 return BCME_ERROR;
1925 }
1926
1927 roam_trigger[1] = WLC_BAND_ALL;
1928 error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
1929 sizeof(roam_trigger));
1930 if (error != BCME_OK) {
1931 ANDROID_ERROR(("failed to set roam trigger (%d)\n", error));
1932 return BCME_ERROR;
1933 }
1934 }
1935
1936 return BCME_OK;
1937 }
1938
wl_android_set_roam_delta(struct net_device * dev,char * command)1939 int wl_android_set_roam_delta(
1940 struct net_device *dev, char* command)
1941 {
1942 int roam_delta[2];
1943
1944 sscanf(command, "%*s %10d", &roam_delta[0]);
1945 roam_delta[1] = WLC_BAND_ALL;
1946
1947 return wldev_ioctl_set(dev, WLC_SET_ROAM_DELTA, roam_delta,
1948 sizeof(roam_delta));
1949 }
1950
wl_android_get_roam_delta(struct net_device * dev,char * command,int total_len)1951 static int wl_android_get_roam_delta(
1952 struct net_device *dev, char *command, int total_len)
1953 {
1954 int bytes_written;
1955 int roam_delta[2] = {0, 0};
1956
1957 roam_delta[1] = WLC_BAND_2G;
1958 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1959 sizeof(roam_delta))) {
1960 roam_delta[1] = WLC_BAND_5G;
1961 #ifdef WL_6G_BAND
1962 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1963 sizeof(roam_delta))) {
1964 roam_delta[1] = WLC_BAND_6G;
1965 #endif /* WL_6G_BAND */
1966 if (wldev_ioctl_get(dev, WLC_GET_ROAM_DELTA, roam_delta,
1967 sizeof(roam_delta))) {
1968 return -1;
1969 }
1970 #ifdef WL_6G_BAND
1971 }
1972 #endif /* WL_6G_BAND */
1973 }
1974
1975 bytes_written = snprintf(command, total_len, "%s %d",
1976 CMD_ROAMDELTA_GET, roam_delta[0]);
1977
1978 return bytes_written;
1979 }
1980
wl_android_set_roam_scan_period(struct net_device * dev,char * command)1981 int wl_android_set_roam_scan_period(
1982 struct net_device *dev, char* command)
1983 {
1984 int roam_scan_period = 0;
1985
1986 sscanf(command, "%*s %10d", &roam_scan_period);
1987 return wldev_ioctl_set(dev, WLC_SET_ROAM_SCAN_PERIOD, &roam_scan_period,
1988 sizeof(roam_scan_period));
1989 }
1990
wl_android_get_roam_scan_period(struct net_device * dev,char * command,int total_len)1991 static int wl_android_get_roam_scan_period(
1992 struct net_device *dev, char *command, int total_len)
1993 {
1994 int bytes_written;
1995 int roam_scan_period = 0;
1996
1997 if (wldev_ioctl_get(dev, WLC_GET_ROAM_SCAN_PERIOD, &roam_scan_period,
1998 sizeof(roam_scan_period)))
1999 return -1;
2000
2001 bytes_written = snprintf(command, total_len, "%s %d",
2002 CMD_ROAMSCANPERIOD_GET, roam_scan_period);
2003
2004 return bytes_written;
2005 }
2006
wl_android_set_full_roam_scan_period(struct net_device * dev,char * command)2007 int wl_android_set_full_roam_scan_period(
2008 struct net_device *dev, char* command)
2009 {
2010 int error = 0;
2011 int full_roam_scan_period = 0;
2012 char smbuf[WLC_IOCTL_SMLEN];
2013
2014 sscanf(command+sizeof("SETFULLROAMSCANPERIOD"), "%d", &full_roam_scan_period);
2015 WL_TRACE(("fullroamperiod = %d\n", full_roam_scan_period));
2016
2017 error = wldev_iovar_setbuf(dev, "fullroamperiod", &full_roam_scan_period,
2018 sizeof(full_roam_scan_period), smbuf, sizeof(smbuf), NULL);
2019 if (error) {
2020 ANDROID_ERROR(("Failed to set full roam scan period, error = %d\n", error));
2021 }
2022
2023 return error;
2024 }
2025
wl_android_get_full_roam_scan_period(struct net_device * dev,char * command,int total_len)2026 static int wl_android_get_full_roam_scan_period(
2027 struct net_device *dev, char *command, int total_len)
2028 {
2029 int error;
2030 int bytes_written;
2031 int full_roam_scan_period = 0;
2032
2033 error = wldev_iovar_getint(dev, "fullroamperiod", &full_roam_scan_period);
2034
2035 if (error) {
2036 ANDROID_ERROR(("%s: get full roam scan period failed code %d\n",
2037 __func__, error));
2038 return -1;
2039 } else {
2040 ANDROID_INFO(("%s: get full roam scan period %d\n", __func__, full_roam_scan_period));
2041 }
2042
2043 bytes_written = snprintf(command, total_len, "%s %d",
2044 CMD_FULLROAMSCANPERIOD_GET, full_roam_scan_period);
2045
2046 return bytes_written;
2047 }
2048
wl_android_set_country_rev(struct net_device * dev,char * command)2049 int wl_android_set_country_rev(
2050 struct net_device *dev, char* command)
2051 {
2052 int error = 0;
2053 wl_country_t cspec = {{0}, 0, {0} };
2054 char country_code[WLC_CNTRY_BUF_SZ];
2055 char smbuf[WLC_IOCTL_SMLEN];
2056 int rev = 0;
2057
2058 bzero(country_code, sizeof(country_code));
2059 sscanf(command+sizeof("SETCOUNTRYREV"), "%3s %10d", country_code, &rev);
2060 WL_TRACE(("country_code = %s, rev = %d\n", country_code, rev));
2061
2062 memcpy(cspec.country_abbrev, country_code, sizeof(country_code));
2063 memcpy(cspec.ccode, country_code, sizeof(country_code));
2064 cspec.rev = rev;
2065
2066 error = wldev_iovar_setbuf(dev, "country", (char *)&cspec,
2067 sizeof(cspec), smbuf, sizeof(smbuf), NULL);
2068
2069 if (error) {
2070 ANDROID_ERROR(("wl_android_set_country_rev: set country '%s/%d' failed code %d\n",
2071 cspec.ccode, cspec.rev, error));
2072 } else {
2073 dhd_bus_country_set(dev, &cspec, true);
2074 ANDROID_INFO(("wl_android_set_country_rev: set country '%s/%d'\n",
2075 cspec.ccode, cspec.rev));
2076 }
2077
2078 return error;
2079 }
2080
wl_android_get_country_rev(struct net_device * dev,char * command,int total_len)2081 static int wl_android_get_country_rev(
2082 struct net_device *dev, char *command, int total_len)
2083 {
2084 int error;
2085 int bytes_written;
2086 char smbuf[WLC_IOCTL_SMLEN];
2087 wl_country_t cspec;
2088
2089 error = wldev_iovar_getbuf(dev, "country", NULL, 0, smbuf,
2090 sizeof(smbuf), NULL);
2091
2092 if (error) {
2093 ANDROID_ERROR(("wl_android_get_country_rev: get country failed code %d\n",
2094 error));
2095 return -1;
2096 } else {
2097 memcpy(&cspec, smbuf, sizeof(cspec));
2098 ANDROID_INFO(("wl_android_get_country_rev: get country '%c%c %d'\n",
2099 cspec.ccode[0], cspec.ccode[1], cspec.rev));
2100 }
2101
2102 bytes_written = snprintf(command, total_len, "%s %c%c %d",
2103 CMD_COUNTRYREV_GET, cspec.ccode[0], cspec.ccode[1], cspec.rev);
2104
2105 return bytes_written;
2106 }
2107 #endif /* ROAM_API */
2108
2109 #ifdef WES_SUPPORT
wl_android_get_roam_scan_control(struct net_device * dev,char * command,int total_len)2110 int wl_android_get_roam_scan_control(struct net_device *dev, char *command, int total_len)
2111 {
2112 int error = 0;
2113 int bytes_written = 0;
2114 int mode = 0;
2115
2116 error = get_roamscan_mode(dev, &mode);
2117 if (error) {
2118 ANDROID_ERROR(("wl_android_get_roam_scan_control: Failed to get Scan Control,"
2119 " error = %d\n", error));
2120 return -1;
2121 }
2122
2123 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETROAMSCANCONTROL, mode);
2124
2125 return bytes_written;
2126 }
2127
wl_android_set_roam_scan_control(struct net_device * dev,char * command)2128 int wl_android_set_roam_scan_control(struct net_device *dev, char *command)
2129 {
2130 int error = 0;
2131 int mode = 0;
2132
2133 if (sscanf(command, "%*s %d", &mode) != 1) {
2134 ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to get Parameter\n"));
2135 return -1;
2136 }
2137
2138 error = set_roamscan_mode(dev, mode);
2139 if (error) {
2140 ANDROID_ERROR(("wl_android_set_roam_scan_control: Failed to set Scan Control %d,"
2141 " error = %d\n",
2142 mode, error));
2143 return -1;
2144 }
2145
2146 return 0;
2147 }
2148
2149 int
wl_android_get_roam_scan_channels(struct net_device * dev,char * command,int total_len,char * cmd)2150 wl_android_get_roam_scan_channels(struct net_device *dev, char *command, int total_len, char *cmd)
2151 {
2152 int bytes_written = 0;
2153 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2154 int nchan = 0, i = 0;
2155 int buf_avail, len;
2156
2157 nchan = get_roamscan_chanspec_list(dev, chanspecs);
2158 if (nchan < 0) {
2159 ANDROID_ERROR(("Failed to Set roamscan channels, n_chan = %d\n", nchan));
2160 return BCME_ERROR;
2161 }
2162
2163 bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2164
2165 buf_avail = total_len - bytes_written;
2166 for (i = 0; i < nchan; i++) {
2167 /* A return value of 'buf_avail' or more means that the output was truncated */
2168 len = snprintf(command + bytes_written, buf_avail, " %d",
2169 CHSPEC_CHANNEL(chanspecs[i]));
2170 if (len >= buf_avail) {
2171 ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2172 ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2173 bytes_written = -1;
2174 break;
2175 }
2176 /* 'buf_avail' decremented by number of bytes written */
2177 buf_avail -= len;
2178 bytes_written += len;
2179 }
2180 ANDROID_INFO(("%s\n", command));
2181 return bytes_written;
2182 }
2183
2184 #define CHANNEL_IDX 1
2185 int
wl_android_set_roam_scan_channels(struct net_device * dev,char * command)2186 wl_android_set_roam_scan_channels(struct net_device *dev, char *command)
2187 {
2188 int error = BCME_OK, i;
2189 unsigned char *p = (unsigned char *)(command + strlen(CMD_SETROAMSCANCHANNELS) + 1);
2190 uint16 nchan = 0, channel = 0;
2191 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2192
2193 nchan = p[0];
2194 if (nchan > MAX_ROAM_CHANNEL) {
2195 ANDROID_ERROR(("Failed to Set roamscan channnels, n_chan = %d\n", nchan));
2196 return BCME_BADARG;
2197 }
2198
2199 for (i = 0; i < nchan; i++) {
2200 channel = p[i + CHANNEL_IDX];
2201 /* Convert chanspec from channel */
2202 chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2203 }
2204
2205 error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2206 if (error) {
2207 ANDROID_ERROR(("Failed to Set Scan Channels %d, error = %d\n", p[0], error));
2208 return error;
2209 }
2210
2211 return error;
2212 }
2213
2214 int
wl_android_add_roam_scan_channels(struct net_device * dev,char * command,uint cmdlen)2215 wl_android_add_roam_scan_channels(struct net_device *dev, char *command, uint cmdlen)
2216 {
2217 int i, error = BCME_OK;
2218 char *pcmd, *token;
2219 uint16 nchan = 0, channel = 0;
2220 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2221
2222 pcmd = (command + cmdlen + 1);
2223 /* Parse roam channel count */
2224 token = bcmstrtok(&pcmd, " ", NULL);
2225 if (!token) {
2226 ANDROID_ERROR(("Bad argument!\n"));
2227 return BCME_BADARG;
2228 }
2229 nchan = bcm_atoi(token);
2230 if (nchan > MAX_ROAM_CHANNEL) {
2231 ANDROID_ERROR(("Failed to Add roamscan channnels, n_chan = %d\n", nchan));
2232 return BCME_BADARG;
2233 }
2234
2235 for (i = 0; i < nchan; i++) {
2236 /* Parse roam channel list */
2237 token = bcmstrtok(&pcmd, " ", NULL);
2238 if (!token) {
2239 ANDROID_ERROR(("Bad argument!\n"));
2240 return BCME_BADARG;
2241 }
2242 channel = bcm_atoi(token);
2243 /* Convert chanspec from channel */
2244 if (channel > 0) {
2245 chanspecs[i] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2246 }
2247 }
2248
2249 error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2250 if (error) {
2251 ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2252 }
2253
2254 return error;
2255 }
2256
2257 int
wl_android_get_roam_scan_freqs(struct net_device * dev,char * command,int total_len,char * cmd)2258 wl_android_get_roam_scan_freqs(struct net_device *dev, char *command, int total_len, char *cmd)
2259 {
2260 int bytes_written = 0;
2261 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2262 int nchan = 0, i = 0;
2263 int buf_avail, len;
2264 u32 freq = 0;
2265 uint start_factor = 0;
2266
2267 nchan = get_roamscan_chanspec_list(dev, chanspecs);
2268 if (nchan < 0) {
2269 ANDROID_ERROR(("Failed to Get roamscan frequencies, n_chan = %d\n", nchan));
2270 return BCME_ERROR;
2271 }
2272
2273 bytes_written = snprintf(command, total_len, "%s %d", cmd, nchan);
2274
2275 buf_avail = total_len - bytes_written;
2276 for (i = 0; i < nchan; i++) {
2277 start_factor = WF_CHAN_FACTOR_2_4_G;
2278 if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_5G) {
2279 start_factor = WF_CHAN_FACTOR_5_G;
2280 } else if (CHSPEC_BAND(chanspecs[i]) == WL_CHANSPEC_BAND_6G) {
2281 start_factor = WF_CHAN_FACTOR_6_G;
2282 }
2283 freq = wf_channel2mhz(CHSPEC_CHANNEL(chanspecs[i]), start_factor);
2284 /* A return value of 'buf_avail' or more means that the output was truncated */
2285 len = snprintf(command + bytes_written, buf_avail, " %d", freq);
2286 if (len >= buf_avail) {
2287 ANDROID_ERROR(("Insufficient memory, %d bytes\n", total_len));
2288 bytes_written = -1;
2289 break;
2290 }
2291 /* 'buf_avail' decremented by number of bytes written */
2292 buf_avail -= len;
2293 bytes_written += len;
2294 }
2295 ANDROID_INFO(("%s\n", command));
2296 return bytes_written;
2297 }
2298
2299 int
wl_android_set_roam_scan_freqs(struct net_device * dev,char * command)2300 wl_android_set_roam_scan_freqs(struct net_device *dev, char *command)
2301 {
2302 int error = BCME_OK, i;
2303 char *pcmd, *token;
2304 uint16 nchan = 0, freq = 0;
2305 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2306
2307 pcmd = (command + strlen(CMD_SETROAMSCANFREQS) + 1);
2308 /* Parse roam channel count */
2309 token = bcmstrtok(&pcmd, " ", NULL);
2310 if (!token) {
2311 ANDROID_ERROR(("Bad argument!\n"));
2312 return BCME_BADARG;
2313 }
2314 nchan = bcm_atoi(token);
2315 if (nchan > MAX_ROAM_CHANNEL) {
2316 ANDROID_ERROR(("Failed to Set roamscan frequencies, n_chan = %d\n", nchan));
2317 return BCME_BADARG;
2318 }
2319
2320 for (i = 0; i < nchan; i++) {
2321 /* Parse roam channel list */
2322 token = bcmstrtok(&pcmd, " ", NULL);
2323 if (!token) {
2324 ANDROID_ERROR(("Bad argument!\n"));
2325 return BCME_BADARG;
2326 }
2327 freq = bcm_atoi(token);
2328 /* Convert chanspec from frequency */
2329 chanspecs[i] = wl_freq_to_chanspec(freq);
2330 }
2331
2332 error = set_roamscan_chanspec_list(dev, nchan, chanspecs);
2333 if (error) {
2334 ANDROID_ERROR(("Failed to set Scan Channels %d, error = %d\n", nchan, error));
2335 return error;
2336 }
2337
2338 return error;
2339 }
2340
2341 int
wl_android_add_roam_scan_freqs(struct net_device * dev,char * command,uint cmdlen)2342 wl_android_add_roam_scan_freqs(struct net_device *dev, char *command, uint cmdlen)
2343 {
2344 int i, error = BCME_OK;
2345 char *pcmd, *token;
2346 uint16 nchan = 0, freq = 0;
2347 chanspec_t chanspecs[MAX_ROAM_CHANNEL] = {0};
2348
2349 pcmd = (command + cmdlen + 1);
2350 /* Parse roam channel count */
2351 token = bcmstrtok(&pcmd, " ", NULL);
2352 if (!token) {
2353 ANDROID_ERROR(("Bad argument!\n"));
2354 return BCME_BADARG;
2355 }
2356 nchan = bcm_atoi(token);
2357 if (nchan > MAX_ROAM_CHANNEL) {
2358 ANDROID_ERROR(("Failed to Add roamscan frequencies, n_chan = %d\n", nchan));
2359 return BCME_BADARG;
2360 }
2361
2362 for (i = 0; i < nchan; i++) {
2363 /* Parse roam channel list */
2364 token = bcmstrtok(&pcmd, " ", NULL);
2365 if (!token) {
2366 ANDROID_ERROR(("Bad argument!\n"));
2367 return BCME_BADARG;
2368 }
2369 freq = bcm_atoi(token);
2370 /* Convert chanspec from channel */
2371 if (freq > 0) {
2372 chanspecs[i] = wl_freq_to_chanspec(freq);
2373 }
2374 }
2375
2376 error = add_roamscan_chanspec_list(dev, nchan, chanspecs);
2377 if (error) {
2378 ANDROID_ERROR(("Failed to add Scan Channels %s, error = %d\n", pcmd, error));
2379 }
2380
2381 return error;
2382 }
2383
2384 int
wl_android_get_scan_channel_time(struct net_device * dev,char * command,int total_len)2385 wl_android_get_scan_channel_time(struct net_device *dev, char *command, int total_len)
2386 {
2387 int error = BCME_OK;
2388 int bytes_written = 0;
2389 int time = 0;
2390
2391 error = wldev_ioctl_get(dev, WLC_GET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2392 if (error) {
2393 ANDROID_ERROR(("Failed to get Scan Channel Time, error = %d\n", error));
2394 return BCME_ERROR;
2395 }
2396
2397 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANCHANNELTIME, time);
2398
2399 return bytes_written;
2400 }
2401
2402 int
wl_android_set_scan_channel_time(struct net_device * dev,char * command)2403 wl_android_set_scan_channel_time(struct net_device *dev, char *command)
2404 {
2405 int error = BCME_OK;
2406 int time = 0;
2407
2408 if (sscanf(command, "%*s %d", &time) != 1) {
2409 ANDROID_ERROR(("Failed to get Parameter\n"));
2410 return BCME_ERROR;
2411 }
2412
2413 if (time == 0) {
2414 /* Set default value when Private param is 0. */
2415 time = DHD_SCAN_ASSOC_ACTIVE_TIME;
2416 }
2417 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2418 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_CHANNEL_TIME, time);
2419 error = wldev_ioctl_set(dev, WLC_SET_SCAN_CHANNEL_TIME, &time, sizeof(time));
2420 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2421 if (error) {
2422 ANDROID_ERROR(("Failed to set Scan Channel Time %d, error = %d\n", time, error));
2423 return BCME_ERROR;
2424 }
2425
2426 return error;
2427 }
2428
2429 int
wl_android_get_scan_unassoc_time(struct net_device * dev,char * command,int total_len)2430 wl_android_get_scan_unassoc_time(struct net_device *dev, char *command, int total_len)
2431 {
2432 int error = BCME_OK;
2433 int bytes_written = 0;
2434 int time = 0;
2435
2436 error = wldev_ioctl_get(dev, WLC_GET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2437 if (error) {
2438 ANDROID_ERROR(("Failed to get Scan Unassoc Time, error = %d\n", error));
2439 return BCME_ERROR;
2440 }
2441
2442 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANUNASSOCTIME, time);
2443
2444 return bytes_written;
2445 }
2446
2447 int
wl_android_set_scan_unassoc_time(struct net_device * dev,char * command)2448 wl_android_set_scan_unassoc_time(struct net_device *dev, char *command)
2449 {
2450 int error = BCME_OK;
2451 int time = 0;
2452
2453 if (sscanf(command, "%*s %d", &time) != 1) {
2454 ANDROID_ERROR(("Failed to get Parameter\n"));
2455 return BCME_ERROR;
2456 }
2457 if (time == 0) {
2458 /* Set default value when Private param is 0. */
2459 time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
2460 }
2461 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2462 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_UNASSOC_TIME, time);
2463 error = wldev_ioctl_set(dev, WLC_SET_SCAN_UNASSOC_TIME, &time, sizeof(time));
2464 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2465 if (error) {
2466 ANDROID_ERROR(("Failed to set Scan Unassoc Time %d, error = %d\n", time, error));
2467 return BCME_ERROR;
2468 }
2469
2470 return error;
2471 }
2472
2473 int
wl_android_get_scan_passive_time(struct net_device * dev,char * command,int total_len)2474 wl_android_get_scan_passive_time(struct net_device *dev, char *command, int total_len)
2475 {
2476 int error = BCME_OK;
2477 int bytes_written = 0;
2478 int time = 0;
2479
2480 error = wldev_ioctl_get(dev, WLC_GET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2481 if (error) {
2482 ANDROID_ERROR(("Failed to get Scan Passive Time, error = %d\n", error));
2483 return BCME_ERROR;
2484 }
2485
2486 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANPASSIVETIME, time);
2487
2488 return bytes_written;
2489 }
2490
2491 int
wl_android_set_scan_passive_time(struct net_device * dev,char * command)2492 wl_android_set_scan_passive_time(struct net_device *dev, char *command)
2493 {
2494 int error = BCME_OK;
2495 int time = 0;
2496
2497 if (sscanf(command, "%*s %d", &time) != 1) {
2498 ANDROID_ERROR(("Failed to get Parameter\n"));
2499 return BCME_ERROR;
2500 }
2501 if (time == 0) {
2502 /* Set default value when Private param is 0. */
2503 time = DHD_SCAN_PASSIVE_TIME;
2504 }
2505 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2506 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_PASSIVE_TIME, time);
2507 error = wldev_ioctl_set(dev, WLC_SET_SCAN_PASSIVE_TIME, &time, sizeof(time));
2508 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2509 if (error) {
2510 ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n", time, error));
2511 return BCME_ERROR;
2512 }
2513
2514 return error;
2515 }
2516
2517 int
wl_android_get_scan_home_time(struct net_device * dev,char * command,int total_len)2518 wl_android_get_scan_home_time(struct net_device *dev, char *command, int total_len)
2519 {
2520 int error = BCME_OK;
2521 int bytes_written = 0;
2522 int time = 0;
2523
2524 error = wldev_ioctl_get(dev, WLC_GET_SCAN_HOME_TIME, &time, sizeof(time));
2525 if (error) {
2526 ANDROID_ERROR(("Failed to get Scan Home Time, error = %d\n", error));
2527 return BCME_ERROR;
2528 }
2529
2530 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMETIME, time);
2531
2532 return bytes_written;
2533 }
2534
wl_android_set_scan_home_time(struct net_device * dev,char * command)2535 int wl_android_set_scan_home_time(struct net_device *dev, char *command)
2536 {
2537 int error = BCME_OK;
2538 int time = 0;
2539
2540 if (sscanf(command, "%*s %d", &time) != 1) {
2541 ANDROID_ERROR(("Failed to get Parameter\n"));
2542 return BCME_ERROR;
2543 }
2544 if (time == 0) {
2545 /* Set default value when Private param is 0. */
2546 time = DHD_SCAN_HOME_TIME;
2547 }
2548 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2549 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_TIME, time);
2550 error = wldev_ioctl_set(dev, WLC_SET_SCAN_HOME_TIME, &time, sizeof(time));
2551 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2552 if (error) {
2553 ANDROID_ERROR(("Failed to set Scan Home Time %d, error = %d\n", time, error));
2554 return BCME_ERROR;
2555 }
2556
2557 return error;
2558 }
2559
2560 int
wl_android_get_scan_home_away_time(struct net_device * dev,char * command,int total_len)2561 wl_android_get_scan_home_away_time(struct net_device *dev, char *command, int total_len)
2562 {
2563 int error = BCME_OK;
2564 int bytes_written = 0;
2565 int time = 0;
2566
2567 error = wldev_iovar_getint(dev, "scan_home_away_time", &time);
2568 if (error) {
2569 ANDROID_ERROR(("Failed to get Scan Home Away Time, error = %d\n", error));
2570 return BCME_ERROR;
2571 }
2572
2573 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, time);
2574
2575 return bytes_written;
2576 }
2577
2578 int
wl_android_set_scan_home_away_time(struct net_device * dev,char * command)2579 wl_android_set_scan_home_away_time(struct net_device *dev, char *command)
2580 {
2581 int error = BCME_OK;
2582 int time = 0;
2583
2584 if (sscanf(command, "%*s %d", &time) != 1) {
2585 ANDROID_ERROR(("Failed to get Parameter\n"));
2586 return BCME_ERROR;
2587 }
2588 if (time == 0) {
2589 /* Set default value when Private param is 0. */
2590 time = DHD_SCAN_HOME_AWAY_TIME;
2591 }
2592 #ifdef CUSTOMER_SCAN_TIMEOUT_SETTING
2593 wl_cfg80211_custom_scan_time(dev, WL_CUSTOM_SCAN_HOME_AWAY_TIME, time);
2594 error = wldev_iovar_setint(dev, "scan_home_away_time", time);
2595 #endif /* CUSTOMER_SCAN_TIMEOUT_SETTING */
2596 if (error) {
2597 ANDROID_ERROR(("Failed to set Scan Home Away Time %d, error = %d\n", time, error));
2598 return BCME_ERROR;
2599 }
2600
2601 return error;
2602 }
2603
2604 int
wl_android_get_scan_nprobes(struct net_device * dev,char * command,int total_len)2605 wl_android_get_scan_nprobes(struct net_device *dev, char *command, int total_len)
2606 {
2607 int error = BCME_OK;
2608 int bytes_written = 0;
2609 int num = 0;
2610
2611 error = wldev_ioctl_get(dev, WLC_GET_SCAN_NPROBES, &num, sizeof(num));
2612 if (error) {
2613 ANDROID_ERROR(("Failed to get Scan NProbes, error = %d\n", error));
2614 return BCME_ERROR;
2615 }
2616
2617 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETSCANNPROBES, num);
2618
2619 return bytes_written;
2620 }
2621
2622 int
wl_android_set_scan_nprobes(struct net_device * dev,char * command)2623 wl_android_set_scan_nprobes(struct net_device *dev, char *command)
2624 {
2625 int error = BCME_OK;
2626 int num = 0;
2627
2628 if (sscanf(command, "%*s %d", &num) != 1) {
2629 ANDROID_ERROR(("Failed to get Parameter\n"));
2630 return BCME_ERROR;
2631 }
2632
2633 error = wldev_ioctl_set(dev, WLC_SET_SCAN_NPROBES, &num, sizeof(num));
2634 if (error) {
2635 ANDROID_ERROR(("Failed to set Scan NProbes %d, error = %d\n", num, error));
2636 return BCME_ERROR;
2637 }
2638
2639 return error;
2640 }
2641
2642 int
wl_android_get_scan_dfs_channel_mode(struct net_device * dev,char * command,int total_len)2643 wl_android_get_scan_dfs_channel_mode(struct net_device *dev, char *command, int total_len)
2644 {
2645 int error = BCME_OK;
2646 int bytes_written = 0;
2647 int mode = 0;
2648 int scan_passive_time = 0;
2649
2650 error = wldev_iovar_getint(dev, "scan_passive_time", &scan_passive_time);
2651 if (error) {
2652 ANDROID_ERROR(("Failed to get Passive Time, error = %d\n", error));
2653 return BCME_ERROR;
2654 }
2655
2656 if (scan_passive_time == 0) {
2657 mode = 0;
2658 } else {
2659 mode = 1;
2660 }
2661
2662 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETDFSSCANMODE, mode);
2663
2664 return bytes_written;
2665 }
2666
2667 int
wl_android_set_scan_dfs_channel_mode(struct net_device * dev,char * command)2668 wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command)
2669 {
2670 int error = BCME_OK;
2671 int mode = 0;
2672 int scan_passive_time = 0;
2673
2674 if (sscanf(command, "%*s %d", &mode) != 1) {
2675 ANDROID_ERROR(("Failed to get Parameter\n"));
2676 return BCME_ERROR;
2677 }
2678
2679 if (mode == 1) {
2680 scan_passive_time = DHD_SCAN_PASSIVE_TIME;
2681 } else if (mode == 0) {
2682 scan_passive_time = 0;
2683 } else {
2684 ANDROID_ERROR(("Failed to set Scan DFS channel mode %d\n", mode));
2685 return BCME_ERROR;
2686 }
2687 error = wldev_iovar_setint(dev, "scan_passive_time", scan_passive_time);
2688 if (error) {
2689 ANDROID_ERROR(("Failed to set Scan Passive Time %d, error = %d\n",
2690 scan_passive_time, error));
2691 return BCME_ERROR;
2692 }
2693
2694 return error;
2695 }
2696
2697 #define JOINPREFFER_BUF_SIZE 12
2698
2699 static int
wl_android_set_join_prefer(struct net_device * dev,char * command)2700 wl_android_set_join_prefer(struct net_device *dev, char *command)
2701 {
2702 int error = BCME_OK;
2703 char smbuf[WLC_IOCTL_SMLEN];
2704 uint8 buf[JOINPREFFER_BUF_SIZE];
2705 char *pcmd;
2706 int total_len_left;
2707 int i;
2708 char hex[] = "XX";
2709 #ifdef WBTEXT
2710 int turn_on = OFF;
2711 char clear[] = { 0x01, 0x02, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
2712 #endif /* WBTEXT */
2713
2714 pcmd = command + strlen(CMD_SETJOINPREFER) + 1;
2715 total_len_left = strlen(pcmd);
2716
2717 bzero(buf, sizeof(buf));
2718
2719 if (total_len_left != JOINPREFFER_BUF_SIZE << 1) {
2720 ANDROID_ERROR(("wl_android_set_join_prefer: Failed to get Parameter\n"));
2721 return BCME_ERROR;
2722 }
2723
2724 /* Store the MSB first, as required by join_pref */
2725 for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) {
2726 hex[0] = *pcmd++;
2727 hex[1] = *pcmd++;
2728 buf[i] = (uint8)simple_strtoul(hex, NULL, 16);
2729 }
2730
2731 #ifdef WBTEXT
2732 /* Set WBTEXT mode */
2733 turn_on = memcmp(buf, clear, sizeof(buf)) == 0 ? TRUE : FALSE;
2734 error = wl_android_wbtext_enable(dev, turn_on);
2735 if (error) {
2736 ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2737 error, (turn_on ? "Enable" : "Disable")));
2738 }
2739 #endif /* WBTEXT */
2740
2741 prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE);
2742 error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE,
2743 smbuf, sizeof(smbuf), NULL);
2744 if (error) {
2745 ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
2746 }
2747
2748 return error;
2749 }
2750
wl_android_send_action_frame(struct net_device * dev,char * command,int total_len)2751 int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len)
2752 {
2753 int error = -1;
2754 android_wifi_af_params_t *params = NULL;
2755 wl_action_frame_t *action_frame = NULL;
2756 wl_af_params_t *af_params = NULL;
2757 char *smbuf = NULL;
2758 struct ether_addr tmp_bssid;
2759 int tmp_channel = 0;
2760 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2761
2762 if (total_len <
2763 (strlen(CMD_SENDACTIONFRAME) + 1 + sizeof(android_wifi_af_params_t))) {
2764 ANDROID_ERROR(("wl_android_send_action_frame: Invalid parameters \n"));
2765 goto send_action_frame_out;
2766 }
2767
2768 params = (android_wifi_af_params_t *)(command + strlen(CMD_SENDACTIONFRAME) + 1);
2769
2770 if ((uint16)params->len > ANDROID_WIFI_ACTION_FRAME_SIZE) {
2771 ANDROID_ERROR(("wl_android_send_action_frame: Requested action frame len"
2772 " was out of range(%d)\n",
2773 params->len));
2774 goto send_action_frame_out;
2775 }
2776
2777 smbuf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MAXLEN);
2778 if (smbuf == NULL) {
2779 ANDROID_ERROR(("wl_android_send_action_frame: failed to allocated memory %d bytes\n",
2780 WLC_IOCTL_MAXLEN));
2781 goto send_action_frame_out;
2782 }
2783
2784 af_params = (wl_af_params_t *)MALLOCZ(cfg->osh, WL_WIFI_AF_PARAMS_SIZE);
2785 if (af_params == NULL) {
2786 ANDROID_ERROR(("wl_android_send_action_frame: unable to allocate frame\n"));
2787 goto send_action_frame_out;
2788 }
2789
2790 bzero(&tmp_bssid, ETHER_ADDR_LEN);
2791 if (bcm_ether_atoe((const char *)params->bssid, (struct ether_addr *)&tmp_bssid) == 0) {
2792 bzero(&tmp_bssid, ETHER_ADDR_LEN);
2793
2794 error = wldev_ioctl_get(dev, WLC_GET_BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2795 if (error) {
2796 bzero(&tmp_bssid, ETHER_ADDR_LEN);
2797 ANDROID_ERROR(("wl_android_send_action_frame: failed to get bssid,"
2798 " error=%d\n", error));
2799 goto send_action_frame_out;
2800 }
2801 }
2802
2803 if (params->channel < 0) {
2804 struct channel_info ci;
2805 bzero(&ci, sizeof(ci));
2806 error = wldev_ioctl_get(dev, WLC_GET_CHANNEL, &ci, sizeof(ci));
2807 if (error) {
2808 ANDROID_ERROR(("wl_android_send_action_frame: failed to get channel,"
2809 " error=%d\n", error));
2810 goto send_action_frame_out;
2811 }
2812
2813 tmp_channel = ci.hw_channel;
2814 }
2815 else {
2816 tmp_channel = params->channel;
2817 }
2818
2819 af_params->channel = tmp_channel;
2820 af_params->dwell_time = params->dwell_time;
2821 memcpy(&af_params->BSSID, &tmp_bssid, ETHER_ADDR_LEN);
2822 action_frame = &af_params->action_frame;
2823
2824 action_frame->packetId = 0;
2825 memcpy(&action_frame->da, &tmp_bssid, ETHER_ADDR_LEN);
2826 action_frame->len = (uint16)params->len;
2827 memcpy(action_frame->data, params->data, action_frame->len);
2828
2829 error = wldev_iovar_setbuf(dev, "actframe", af_params,
2830 sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
2831 if (error) {
2832 ANDROID_ERROR(("wl_android_send_action_frame: failed to set action frame,"
2833 " error=%d\n", error));
2834 }
2835
2836 send_action_frame_out:
2837 if (af_params) {
2838 MFREE(cfg->osh, af_params, WL_WIFI_AF_PARAMS_SIZE);
2839 }
2840
2841 if (smbuf) {
2842 MFREE(cfg->osh, smbuf, WLC_IOCTL_MAXLEN);
2843 }
2844
2845 if (error)
2846 return -1;
2847 else
2848 return 0;
2849 }
2850
2851 int
wl_android_reassoc(struct net_device * dev,char * command,int total_len)2852 wl_android_reassoc(struct net_device *dev, char *command, int total_len)
2853 {
2854 int error = BCME_OK;
2855 android_wifi_reassoc_params_t *params = NULL;
2856 chanspec_t channel;
2857 u32 params_size;
2858 wl_reassoc_params_t reassoc_params;
2859 char pcmd[WL_PRIV_CMD_LEN + 1];
2860
2861 sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s *", pcmd);
2862 if (total_len < (strlen(pcmd) + 1 + sizeof(android_wifi_reassoc_params_t))) {
2863 ANDROID_ERROR(("Invalid parameters %s\n", command));
2864 return BCME_ERROR;
2865 }
2866 params = (android_wifi_reassoc_params_t *)(command + strlen(pcmd) + 1);
2867
2868 bzero(&reassoc_params, WL_REASSOC_PARAMS_FIXED_SIZE);
2869
2870 if (bcm_ether_atoe((const char *)params->bssid,
2871 (struct ether_addr *)&reassoc_params.bssid) == 0) {
2872 ANDROID_ERROR(("Invalid bssid \n"));
2873 return BCME_BADARG;
2874 }
2875
2876 if (params->channel < 0) {
2877 ANDROID_ERROR(("Invalid Channel %d\n", params->channel));
2878 return BCME_BADARG;
2879 }
2880
2881 reassoc_params.chanspec_num = 1;
2882
2883 channel = params->channel;
2884 if (CHANNEL_IS_2G(channel) || CHANNEL_IS_5G(channel)) {
2885 /* If reassoc Param is BSSID and Channel */
2886 reassoc_params.chanspec_list[0] = wf_channel2chspec(channel, WL_CHANSPEC_BW_20);
2887 } else {
2888 /* If reassoc Param is BSSID and Frequency */
2889 reassoc_params.chanspec_list[0] = wl_freq_to_chanspec(channel);
2890 }
2891 params_size = WL_REASSOC_PARAMS_FIXED_SIZE + sizeof(chanspec_t);
2892
2893 error = wldev_ioctl_set(dev, WLC_REASSOC, &reassoc_params, params_size);
2894 if (error) {
2895 ANDROID_ERROR(("failed to reassoc, error=%d\n", error));
2896 return error;
2897 }
2898 return error;
2899 }
2900
wl_android_get_wes_mode(struct net_device * dev,char * command,int total_len)2901 int wl_android_get_wes_mode(struct net_device *dev, char *command, int total_len)
2902 {
2903 int bytes_written = 0;
2904 int mode = 0;
2905
2906 mode = wl_cfg80211_get_wes_mode(dev);
2907
2908 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETWESMODE, mode);
2909
2910 return bytes_written;
2911 }
2912
wl_android_set_wes_mode(struct net_device * dev,char * command)2913 int wl_android_set_wes_mode(struct net_device *dev, char *command)
2914 {
2915 int error = 0;
2916 int mode = 0;
2917
2918 if (sscanf(command, "%*s %d", &mode) != 1) {
2919 ANDROID_ERROR(("wl_android_set_wes_mode: Failed to get Parameter\n"));
2920 return -1;
2921 }
2922
2923 error = wl_cfg80211_set_wes_mode(dev, mode);
2924 if (error) {
2925 ANDROID_ERROR(("wl_android_set_wes_mode: Failed to set WES Mode %d, error = %d\n",
2926 mode, error));
2927 return -1;
2928 }
2929
2930 return 0;
2931 }
2932
2933 int
wl_android_get_ncho_mode(struct net_device * dev,char * command,int total_len)2934 wl_android_get_ncho_mode(struct net_device *dev, char *command, int total_len)
2935 {
2936 int bytes_written = 0;
2937 int mode = 0;
2938
2939 mode = wl_cfg80211_get_ncho_mode(dev);
2940
2941 bytes_written = snprintf(command, total_len, "%s %d", CMD_GETNCHOMODE, mode);
2942
2943 return bytes_written;
2944 }
2945
2946 int
wl_android_set_ncho_mode(struct net_device * dev,int mode)2947 wl_android_set_ncho_mode(struct net_device *dev, int mode)
2948 {
2949 char cmd[WLC_IOCTL_SMLEN];
2950 int error = BCME_OK;
2951
2952 #ifdef WBTEXT
2953 /* Set WBTEXT mode */
2954 error = wl_android_wbtext_enable(dev, !mode);
2955 if (error) {
2956 ANDROID_ERROR(("Failed to set WBTEXT(%d) = %s\n",
2957 error, (mode ? "Disable" : "Enable")));
2958 }
2959 #endif /* WBTEXT */
2960 /* Set Piority roam mode */
2961 error = wl_android_priority_roam_enable(dev, !mode);
2962 if (error) {
2963 ANDROID_ERROR(("Failed to set Priority Roam(%d) = %s\n",
2964 error, (mode ? "Disable" : "Enable")));
2965 }
2966 #ifdef CONFIG_SILENT_ROAM
2967 /* Set Silent roam mode */
2968 error = wl_android_sroam_turn_on(dev, !mode);
2969 if (error) {
2970 ANDROID_ERROR(("Failed to set SROAM(%d) = %s\n",
2971 error, (mode ? "Disable" : "Enable")));
2972 }
2973 #endif /* CONFIG_SILENT_ROAM */
2974 /* Set RCROAM(ROAMEXT) mode */
2975 error = wl_android_rcroam_turn_on(dev, !mode);
2976 if (error) {
2977 ANDROID_ERROR(("Failed to set RCROAM(%d) = %s\n",
2978 error, (mode ? "Disable" : "Enable")));
2979 }
2980
2981 if (mode == OFF) {
2982 /* restore NCHO set parameters */
2983 bzero(cmd, WLC_IOCTL_SMLEN);
2984 snprintf(cmd, WLC_IOCTL_SMLEN, "%s", CMD_RESTORE_SCAN_PARAMS);
2985 error = wl_android_default_set_scan_params(dev, cmd, WLC_IOCTL_SMLEN);
2986 if (error) {
2987 ANDROID_ERROR(("Failed to set RESTORE_SCAN_PARAMS(%d)\n", error));
2988 }
2989
2990 wl_cfg80211_set_wes_mode(dev, OFF);
2991 set_roamscan_mode(dev, ROAMSCAN_MODE_NORMAL);
2992 }
2993
2994 error = wl_cfg80211_set_ncho_mode(dev, mode);
2995 if (error) {
2996 ANDROID_ERROR(("Failed to set NCHO Mode %d, error = %d\n", mode, error));
2997 }
2998
2999 return error;
3000 }
3001
3002 static int
wl_android_set_pmk(struct net_device * dev,char * command,int total_len)3003 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
3004 {
3005 uchar pmk[33];
3006 int error = 0;
3007 char smbuf[WLC_IOCTL_SMLEN];
3008 dhd_pub_t *dhdp;
3009 #ifdef OKC_DEBUG
3010 int i = 0;
3011 #endif
3012
3013 if (total_len < (strlen("SET_PMK ") + 32)) {
3014 ANDROID_ERROR(("wl_android_set_pmk: Invalid argument\n"));
3015 return -1;
3016 }
3017
3018 dhdp = wl_cfg80211_get_dhdp(dev);
3019 if (!dhdp) {
3020 ANDROID_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
3021 return -1;
3022 }
3023
3024 bzero(pmk, sizeof(pmk));
3025 DHD_STATLOG_CTRL(dhdp, ST(INSTALL_OKC_PMK), dhd_net2idx(dhdp->info, dev), 0);
3026 memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
3027 error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
3028 if (error) {
3029 ANDROID_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
3030 }
3031 #ifdef OKC_DEBUG
3032 ANDROID_ERROR(("PMK is "));
3033 for (i = 0; i < 32; i++)
3034 ANDROID_ERROR(("%02X ", pmk[i]));
3035
3036 ANDROID_ERROR(("\n"));
3037 #endif
3038 return error;
3039 }
3040
3041 static int
wl_android_okc_enable(struct net_device * dev,char * command)3042 wl_android_okc_enable(struct net_device *dev, char *command)
3043 {
3044 int error = 0;
3045 char okc_enable = 0;
3046
3047 okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
3048 error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
3049 if (error) {
3050 ANDROID_ERROR(("Failed to %s OKC, error = %d\n",
3051 okc_enable ? "enable" : "disable", error));
3052 }
3053
3054 return error;
3055 }
3056
3057 static int
wl_android_legacy_check_command(struct net_device * dev,char * command)3058 wl_android_legacy_check_command(struct net_device *dev, char *command)
3059 {
3060 int cnt = 0;
3061
3062 while (strlen(legacy_cmdlist[cnt]) > 0) {
3063 if (strnicmp(command, legacy_cmdlist[cnt], strlen(legacy_cmdlist[cnt])) == 0) {
3064 char cmd[WL_PRIV_CMD_LEN + 1];
3065 sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3066 if (strlen(legacy_cmdlist[cnt]) == strlen(cmd)) {
3067 return TRUE;
3068 }
3069 }
3070 cnt++;
3071 }
3072 return FALSE;
3073 }
3074
3075 static int
wl_android_legacy_private_command(struct net_device * net,char * command,int total_len)3076 wl_android_legacy_private_command(struct net_device *net, char *command, int total_len)
3077 {
3078 int bytes_written = 0;
3079 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3080
3081 if (cfg->ncho_mode == ON) {
3082 ANDROID_ERROR(("Enabled NCHO mode\n"));
3083 /* In order to avoid Sequential error HANG event. */
3084 return BCME_UNSUPPORTED;
3085 }
3086
3087 /* ROAMSCAN CHANNELS Add, Get Command */
3088 if (strnicmp(command, CMD_ADDROAMSCANCHLEGACY, strlen(CMD_ADDROAMSCANCHLEGACY)) == 0) {
3089 bytes_written = wl_android_add_roam_scan_channels(net, command,
3090 strlen(CMD_ADDROAMSCANCHLEGACY));
3091 }
3092 else if (strnicmp(command, CMD_GETROAMSCANCHLEGACY, strlen(CMD_GETROAMSCANCHLEGACY)) == 0) {
3093 bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3094 CMD_GETROAMSCANCHLEGACY);
3095 }
3096 /* ROAMSCAN FREQUENCIES Add, Get Command */
3097 else if (strnicmp(command, CMD_ADDROAMSCANFQLEGACY, strlen(CMD_ADDROAMSCANFQLEGACY)) == 0) {
3098 bytes_written = wl_android_add_roam_scan_freqs(net, command,
3099 strlen(CMD_ADDROAMSCANFQLEGACY));
3100 }
3101 else if (strnicmp(command, CMD_GETROAMSCANFQLEGACY, strlen(CMD_GETROAMSCANFQLEGACY)) == 0) {
3102 bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3103 CMD_GETROAMSCANFQLEGACY);
3104 }
3105 else if (strnicmp(command, CMD_GETROAMTRIGLEGACY, strlen(CMD_GETROAMTRIGLEGACY)) == 0) {
3106 bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3107 }
3108 else if (strnicmp(command, CMD_SETROAMTRIGLEGACY, strlen(CMD_SETROAMTRIGLEGACY)) == 0) {
3109 bytes_written = wl_android_set_roam_trigger_legacy(net, command);
3110 }
3111 else if (strnicmp(command, CMD_REASSOCLEGACY, strlen(CMD_REASSOCLEGACY)) == 0) {
3112 bytes_written = wl_android_reassoc(net, command, total_len);
3113 }
3114 else if (strnicmp(command, CMD_GETSCANCHANNELTIMELEGACY,
3115 strlen(CMD_GETSCANCHANNELTIMELEGACY)) == 0) {
3116 bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3117 }
3118 else if (strnicmp(command, CMD_SETSCANCHANNELTIMELEGACY,
3119 strlen(CMD_SETSCANCHANNELTIMELEGACY)) == 0) {
3120 bytes_written = wl_android_set_scan_channel_time(net, command);
3121 }
3122 else if (strnicmp(command, CMD_GETSCANUNASSOCTIMELEGACY,
3123 strlen(CMD_GETSCANUNASSOCTIMELEGACY)) == 0) {
3124 bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3125 }
3126 else if (strnicmp(command, CMD_SETSCANUNASSOCTIMELEGACY,
3127 strlen(CMD_SETSCANUNASSOCTIMELEGACY)) == 0) {
3128 bytes_written = wl_android_set_scan_unassoc_time(net, command);
3129 }
3130 else if (strnicmp(command, CMD_GETSCANPASSIVETIMELEGACY,
3131 strlen(CMD_GETSCANPASSIVETIMELEGACY)) == 0) {
3132 bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3133 }
3134 else if (strnicmp(command, CMD_SETSCANPASSIVETIMELEGACY,
3135 strlen(CMD_SETSCANPASSIVETIMELEGACY)) == 0) {
3136 bytes_written = wl_android_set_scan_passive_time(net, command);
3137 }
3138 else if (strnicmp(command, CMD_GETSCANHOMETIMELEGACY,
3139 strlen(CMD_GETSCANHOMETIMELEGACY)) == 0) {
3140 bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3141 }
3142 else if (strnicmp(command, CMD_SETSCANHOMETIMELEGACY,
3143 strlen(CMD_SETSCANHOMETIMELEGACY)) == 0) {
3144 bytes_written = wl_android_set_scan_home_time(net, command);
3145 }
3146 else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIMELEGACY,
3147 strlen(CMD_GETSCANHOMEAWAYTIMELEGACY)) == 0) {
3148 bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3149 }
3150 else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIMELEGACY,
3151 strlen(CMD_SETSCANHOMEAWAYTIMELEGACY)) == 0) {
3152 bytes_written = wl_android_set_scan_home_away_time(net, command);
3153 }
3154 else {
3155 ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3156 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3157 }
3158
3159 return bytes_written;
3160 }
3161
3162 static int
wl_android_ncho_check_command(struct net_device * dev,char * command)3163 wl_android_ncho_check_command(struct net_device *dev, char *command)
3164 {
3165 int cnt = 0;
3166
3167 while (strlen(ncho_cmdlist[cnt]) > 0) {
3168 if (strnicmp(command, ncho_cmdlist[cnt], strlen(ncho_cmdlist[cnt])) == 0) {
3169 char cmd[WL_PRIV_CMD_LEN + 1];
3170 sscanf(command, "%"S(WL_PRIV_CMD_LEN)"s ", cmd);
3171 if (strlen(ncho_cmdlist[cnt]) == strlen(cmd)) {
3172 return TRUE;
3173 }
3174 }
3175 cnt++;
3176 }
3177 return FALSE;
3178 }
3179
3180 static int
wl_android_ncho_private_command(struct net_device * net,char * command,int total_len)3181 wl_android_ncho_private_command(struct net_device *net, char *command, int total_len)
3182 {
3183 int bytes_written = 0;
3184 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3185
3186 if (cfg->ncho_mode == OFF) {
3187 ANDROID_ERROR(("Disable NCHO mode\n"));
3188 /* In order to avoid Sequential error HANG event. */
3189 return BCME_UNSUPPORTED;
3190 }
3191
3192 #ifdef ROAM_API
3193 if (strnicmp(command, CMD_ROAMTRIGGER_SET, strlen(CMD_ROAMTRIGGER_SET)) == 0) {
3194 bytes_written = wl_android_set_roam_trigger(net, command);
3195 } else if (strnicmp(command, CMD_ROAMTRIGGER_GET, strlen(CMD_ROAMTRIGGER_GET)) == 0) {
3196 bytes_written = wl_android_get_roam_trigger(net, command, total_len);
3197 } else if (strnicmp(command, CMD_ROAMDELTA_SET, strlen(CMD_ROAMDELTA_SET)) == 0) {
3198 bytes_written = wl_android_set_roam_delta(net, command);
3199 } else if (strnicmp(command, CMD_ROAMDELTA_GET, strlen(CMD_ROAMDELTA_GET)) == 0) {
3200 bytes_written = wl_android_get_roam_delta(net, command, total_len);
3201 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_SET,
3202 strlen(CMD_ROAMSCANPERIOD_SET)) == 0) {
3203 bytes_written = wl_android_set_roam_scan_period(net, command);
3204 } else if (strnicmp(command, CMD_ROAMSCANPERIOD_GET,
3205 strlen(CMD_ROAMSCANPERIOD_GET)) == 0) {
3206 bytes_written = wl_android_get_roam_scan_period(net, command, total_len);
3207 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_SET,
3208 strlen(CMD_FULLROAMSCANPERIOD_SET)) == 0) {
3209 bytes_written = wl_android_set_full_roam_scan_period(net, command);
3210 } else if (strnicmp(command, CMD_FULLROAMSCANPERIOD_GET,
3211 strlen(CMD_FULLROAMSCANPERIOD_GET)) == 0) {
3212 bytes_written = wl_android_get_full_roam_scan_period(net, command, total_len);
3213 } else if (strnicmp(command, CMD_COUNTRYREV_SET, strlen(CMD_COUNTRYREV_SET)) == 0) {
3214 bytes_written = wl_android_set_country_rev(net, command);
3215 #ifdef FCC_PWR_LIMIT_2G
3216 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
3217 ANDROID_ERROR(("fccpwrlimit2g deactivation is failed\n"));
3218 } else {
3219 ANDROID_ERROR(("fccpwrlimit2g is deactivated\n"));
3220 }
3221 #endif /* FCC_PWR_LIMIT_2G */
3222 } else if (strnicmp(command, CMD_COUNTRYREV_GET, strlen(CMD_COUNTRYREV_GET)) == 0) {
3223 bytes_written = wl_android_get_country_rev(net, command, total_len);
3224 } else
3225 #endif /* ROAM_API */
3226 if (strnicmp(command, CMD_GETROAMSCANCONTROL, strlen(CMD_GETROAMSCANCONTROL)) == 0) {
3227 bytes_written = wl_android_get_roam_scan_control(net, command, total_len);
3228 }
3229 else if (strnicmp(command, CMD_SETROAMSCANCONTROL, strlen(CMD_SETROAMSCANCONTROL)) == 0) {
3230 bytes_written = wl_android_set_roam_scan_control(net, command);
3231 }
3232 /* ROAMSCAN CHANNELS Add, Get, Set Command */
3233 else if (strnicmp(command, CMD_ADDROAMSCANCHANNELS, strlen(CMD_ADDROAMSCANCHANNELS)) == 0) {
3234 bytes_written = wl_android_add_roam_scan_channels(net, command,
3235 strlen(CMD_ADDROAMSCANCHANNELS));
3236 }
3237 else if (strnicmp(command, CMD_GETROAMSCANCHANNELS, strlen(CMD_GETROAMSCANCHANNELS)) == 0) {
3238 bytes_written = wl_android_get_roam_scan_channels(net, command, total_len,
3239 CMD_GETROAMSCANCHANNELS);
3240 }
3241 else if (strnicmp(command, CMD_SETROAMSCANCHANNELS, strlen(CMD_SETROAMSCANCHANNELS)) == 0) {
3242 bytes_written = wl_android_set_roam_scan_channels(net, command);
3243 }
3244 /* ROAMSCAN FREQUENCIES Add, Get, Set Command */
3245 else if (strnicmp(command, CMD_ADDROAMSCANFREQS, strlen(CMD_ADDROAMSCANFREQS)) == 0) {
3246 bytes_written = wl_android_add_roam_scan_freqs(net, command,
3247 strlen(CMD_ADDROAMSCANFREQS));
3248 }
3249 else if (strnicmp(command, CMD_GETROAMSCANFREQS, strlen(CMD_GETROAMSCANFREQS)) == 0) {
3250 bytes_written = wl_android_get_roam_scan_freqs(net, command, total_len,
3251 CMD_GETROAMSCANFREQS);
3252 }
3253 else if (strnicmp(command, CMD_SETROAMSCANFREQS, strlen(CMD_SETROAMSCANFREQS)) == 0) {
3254 bytes_written = wl_android_set_roam_scan_freqs(net, command);
3255 }
3256 else if (strnicmp(command, CMD_SENDACTIONFRAME, strlen(CMD_SENDACTIONFRAME)) == 0) {
3257 bytes_written = wl_android_send_action_frame(net, command, total_len);
3258 }
3259 else if (strnicmp(command, CMD_REASSOC, strlen(CMD_REASSOC)) == 0) {
3260 bytes_written = wl_android_reassoc(net, command, total_len);
3261 }
3262 else if (strnicmp(command, CMD_GETSCANCHANNELTIME, strlen(CMD_GETSCANCHANNELTIME)) == 0) {
3263 bytes_written = wl_android_get_scan_channel_time(net, command, total_len);
3264 }
3265 else if (strnicmp(command, CMD_SETSCANCHANNELTIME, strlen(CMD_SETSCANCHANNELTIME)) == 0) {
3266 bytes_written = wl_android_set_scan_channel_time(net, command);
3267 }
3268 else if (strnicmp(command, CMD_GETSCANUNASSOCTIME, strlen(CMD_GETSCANUNASSOCTIME)) == 0) {
3269 bytes_written = wl_android_get_scan_unassoc_time(net, command, total_len);
3270 }
3271 else if (strnicmp(command, CMD_SETSCANUNASSOCTIME, strlen(CMD_SETSCANUNASSOCTIME)) == 0) {
3272 bytes_written = wl_android_set_scan_unassoc_time(net, command);
3273 }
3274 else if (strnicmp(command, CMD_GETSCANPASSIVETIME, strlen(CMD_GETSCANPASSIVETIME)) == 0) {
3275 bytes_written = wl_android_get_scan_passive_time(net, command, total_len);
3276 }
3277 else if (strnicmp(command, CMD_SETSCANPASSIVETIME, strlen(CMD_SETSCANPASSIVETIME)) == 0) {
3278 bytes_written = wl_android_set_scan_passive_time(net, command);
3279 }
3280 else if (strnicmp(command, CMD_GETSCANHOMETIME, strlen(CMD_GETSCANHOMETIME)) == 0) {
3281 bytes_written = wl_android_get_scan_home_time(net, command, total_len);
3282 }
3283 else if (strnicmp(command, CMD_SETSCANHOMETIME, strlen(CMD_SETSCANHOMETIME)) == 0) {
3284 bytes_written = wl_android_set_scan_home_time(net, command);
3285 }
3286 else if (strnicmp(command, CMD_GETSCANHOMEAWAYTIME, strlen(CMD_GETSCANHOMEAWAYTIME)) == 0) {
3287 bytes_written = wl_android_get_scan_home_away_time(net, command, total_len);
3288 }
3289 else if (strnicmp(command, CMD_SETSCANHOMEAWAYTIME, strlen(CMD_SETSCANHOMEAWAYTIME)) == 0) {
3290 bytes_written = wl_android_set_scan_home_away_time(net, command);
3291 }
3292 else if (strnicmp(command, CMD_GETSCANNPROBES, strlen(CMD_GETSCANNPROBES)) == 0) {
3293 bytes_written = wl_android_get_scan_nprobes(net, command, total_len);
3294 }
3295 else if (strnicmp(command, CMD_SETSCANNPROBES, strlen(CMD_SETSCANNPROBES)) == 0) {
3296 bytes_written = wl_android_set_scan_nprobes(net, command);
3297 }
3298 else if (strnicmp(command, CMD_GETDFSSCANMODE, strlen(CMD_GETDFSSCANMODE)) == 0) {
3299 bytes_written = wl_android_get_scan_dfs_channel_mode(net, command, total_len);
3300 }
3301 else if (strnicmp(command, CMD_SETDFSSCANMODE, strlen(CMD_SETDFSSCANMODE)) == 0) {
3302 bytes_written = wl_android_set_scan_dfs_channel_mode(net, command);
3303 }
3304 else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) {
3305 bytes_written = wl_android_set_join_prefer(net, command);
3306 }
3307 else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) {
3308 bytes_written = wl_android_get_wes_mode(net, command, total_len);
3309 }
3310 else if (strnicmp(command, CMD_SETWESMODE, strlen(CMD_SETWESMODE)) == 0) {
3311 bytes_written = wl_android_set_wes_mode(net, command);
3312 }
3313 else {
3314 ANDROID_ERROR(("Unknown NCHO PRIVATE command %s - ignored\n", command));
3315 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
3316 }
3317
3318 return bytes_written;
3319 }
3320 #endif /* WES_SUPPORT */
3321
3322 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
3323 static int
wl_android_default_set_scan_params(struct net_device * dev,char * command,int total_len)3324 wl_android_default_set_scan_params(struct net_device *dev, char *command, int total_len)
3325 {
3326 int error = 0;
3327 uint error_cnt = 0;
3328 int cnt = 0;
3329 char restore_command[WLC_IOCTL_SMLEN];
3330
3331 while (strlen(restore_params[cnt].command) > 0 && restore_params[cnt].cmd_handler) {
3332 snprintf(restore_command, WLC_IOCTL_SMLEN, "%s %d",
3333 restore_params[cnt].command, restore_params[cnt].parameter);
3334 if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD) {
3335 error = restore_params[cnt].cmd_handler(dev, restore_command);
3336 } else if (restore_params[cnt].cmd_type == RESTORE_TYPE_PRIV_CMD_WITH_LEN) {
3337 error = restore_params[cnt].cmd_handler_w_len(dev,
3338 restore_command, total_len);
3339 } else {
3340 ANDROID_ERROR(("Unknown restore command handler\n"));
3341 error = -1;
3342 }
3343 if (error) {
3344 ANDROID_ERROR(("Failed to restore scan parameters %s, error : %d\n",
3345 restore_command, error));
3346 error_cnt++;
3347 }
3348 cnt++;
3349 }
3350 if (error_cnt > 0) {
3351 ANDROID_ERROR(("Got %d error(s) while restoring scan parameters\n",
3352 error_cnt));
3353 error = -1;
3354 }
3355 return error;
3356 }
3357 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
3358
3359 #ifdef WLTDLS
wl_android_tdls_reset(struct net_device * dev)3360 int wl_android_tdls_reset(struct net_device *dev)
3361 {
3362 int ret = 0;
3363 ret = dhd_tdls_enable(dev, false, false, NULL);
3364 if (ret < 0) {
3365 ANDROID_ERROR(("Disable tdls failed. %d\n", ret));
3366 return ret;
3367 }
3368 ret = dhd_tdls_enable(dev, true, true, NULL);
3369 if (ret < 0) {
3370 ANDROID_ERROR(("enable tdls failed. %d\n", ret));
3371 return ret;
3372 }
3373 return 0;
3374 }
3375 #endif /* WLTDLS */
3376
3377 int
wl_android_rcroam_turn_on(struct net_device * dev,int rcroam_enab)3378 wl_android_rcroam_turn_on(struct net_device *dev, int rcroam_enab)
3379 {
3380 int ret = BCME_OK;
3381 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3382 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3383 wlc_rcroam_t *prcroam;
3384 wlc_rcroam_info_v1_t *rcroam;
3385 uint rcroamlen = sizeof(*rcroam) + RCROAM_HDRLEN;
3386
3387 ANDROID_INFO(("RCROAM mode %s\n", rcroam_enab ? "enable" : "disable"));
3388
3389 prcroam = (wlc_rcroam_t *)MALLOCZ(dhdp->osh, rcroamlen);
3390 if (!prcroam) {
3391 ANDROID_ERROR(("Fail to malloc buffer\n"));
3392 return BCME_NOMEM;
3393 }
3394
3395 /* Get RCROAM param */
3396 ret = wldev_iovar_getbuf(dev, "rcroam", NULL, 0, prcroam, rcroamlen, NULL);
3397 if (ret) {
3398 ANDROID_ERROR(("Failed to get RCROAM info(%d)\n", ret));
3399 goto done;
3400 }
3401
3402 if (prcroam->ver != WLC_RC_ROAM_CUR_VER) {
3403 ret = BCME_VERSION;
3404 ANDROID_ERROR(("Ver(%d:%d). mismatch RCROAM info(%d)\n",
3405 prcroam->ver, WLC_RC_ROAM_CUR_VER, ret));
3406 goto done;
3407 }
3408
3409 /* Set RCROAM param */
3410 rcroam = (wlc_rcroam_info_v1_t *)prcroam->data;
3411 prcroam->ver = WLC_RC_ROAM_CUR_VER;
3412 prcroam->len = sizeof(*rcroam);
3413 rcroam->enab = rcroam_enab;
3414
3415 ret = wldev_iovar_setbuf(dev, "rcroam", prcroam, rcroamlen,
3416 ioctl_buf, sizeof(ioctl_buf), NULL);
3417 if (ret) {
3418 ANDROID_ERROR(("Failed to set RCROAM %s(%d)\n",
3419 rcroam_enab ? "Enable" : "Disable", ret));
3420 goto done;
3421 }
3422 done:
3423 if (prcroam) {
3424 MFREE(dhdp->osh, prcroam, rcroamlen);
3425 }
3426
3427 return ret;
3428 }
3429
3430 #ifdef CONFIG_SILENT_ROAM
3431 int
wl_android_sroam_turn_on(struct net_device * dev,int sroam_mode)3432 wl_android_sroam_turn_on(struct net_device *dev, int sroam_mode)
3433 {
3434 int ret = BCME_OK;
3435 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3436
3437 dhdp->sroam_turn_on = sroam_mode;
3438 ANDROID_INFO(("%s Silent mode %s\n", __FUNCTION__,
3439 sroam_mode ? "enable" : "disable"));
3440
3441 if (!sroam_mode) {
3442 ret = dhd_sroam_set_mon(dhdp, FALSE);
3443 if (ret) {
3444 ANDROID_ERROR(("%s Failed to Set sroam %d\n",
3445 __FUNCTION__, ret));
3446 }
3447 }
3448
3449 return ret;
3450 }
3451
3452 int
wl_android_sroam_set_info(struct net_device * dev,char * data,char * command,int total_len)3453 wl_android_sroam_set_info(struct net_device *dev, char *data,
3454 char *command, int total_len)
3455 {
3456 int ret = BCME_OK;
3457 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3458 size_t slen = strlen(data);
3459 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3460 wlc_sroam_t *psroam;
3461 wlc_sroam_info_t *sroam;
3462 uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3463
3464 data[slen] = '\0';
3465 psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3466 if (!psroam) {
3467 ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3468 ret = BCME_NOMEM;
3469 goto done;
3470 }
3471
3472 psroam->ver = WLC_SILENT_ROAM_CUR_VER;
3473 psroam->len = sizeof(*sroam);
3474 sroam = (wlc_sroam_info_t *)psroam->data;
3475
3476 sroam->sroam_on = FALSE;
3477 if (*data && *data != '\0') {
3478 sroam->sroam_min_rssi = simple_strtol(data, &data, 10);
3479 ANDROID_INFO(("1.Minimum RSSI %d\n", sroam->sroam_min_rssi));
3480 data++;
3481 }
3482 if (*data && *data != '\0') {
3483 sroam->sroam_rssi_range = simple_strtol(data, &data, 10);
3484 ANDROID_INFO(("2.RSSI Range %d\n", sroam->sroam_rssi_range));
3485 data++;
3486 }
3487 if (*data && *data != '\0') {
3488 sroam->sroam_score_delta = simple_strtol(data, &data, 10);
3489 ANDROID_INFO(("3.Score Delta %d\n", sroam->sroam_score_delta));
3490 data++;
3491 }
3492 if (*data && *data != '\0') {
3493 sroam->sroam_period_time = simple_strtol(data, &data, 10);
3494 ANDROID_INFO(("4.Sroam period %d\n", sroam->sroam_period_time));
3495 data++;
3496 }
3497 if (*data && *data != '\0') {
3498 sroam->sroam_band = simple_strtol(data, &data, 10);
3499 ANDROID_INFO(("5.Sroam Band %d\n", sroam->sroam_band));
3500 data++;
3501 }
3502 if (*data && *data != '\0') {
3503 sroam->sroam_inact_cnt = simple_strtol(data, &data, 10);
3504 ANDROID_INFO(("6.Inactivity Count %d\n", sroam->sroam_inact_cnt));
3505 data++;
3506 }
3507
3508 if (*data != '\0') {
3509 ret = BCME_BADARG;
3510 goto done;
3511 }
3512
3513 ret = wldev_iovar_setbuf(dev, "sroam", psroam, sroamlen, ioctl_buf,
3514 sizeof(ioctl_buf), NULL);
3515 if (ret) {
3516 ANDROID_ERROR(("Failed to set silent roam info(%d)\n", ret));
3517 goto done;
3518 }
3519 done:
3520 if (psroam) {
3521 MFREE(dhdp->osh, psroam, sroamlen);
3522 }
3523
3524 return ret;
3525 }
3526
3527 int
wl_android_sroam_get_info(struct net_device * dev,char * command,int total_len)3528 wl_android_sroam_get_info(struct net_device *dev, char *command, int total_len)
3529 {
3530 int ret = BCME_OK;
3531 int bytes_written = 0;
3532 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3533 wlc_sroam_t *psroam;
3534 wlc_sroam_info_t *sroam;
3535 uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
3536
3537 psroam = (wlc_sroam_t *)MALLOCZ(dhdp->osh, sroamlen);
3538 if (!psroam) {
3539 ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3540 ret = BCME_NOMEM;
3541 goto done;
3542 }
3543
3544 ret = wldev_iovar_getbuf(dev, "sroam", NULL, 0, psroam, sroamlen, NULL);
3545 if (ret) {
3546 ANDROID_ERROR(("Failed to get silent roam info(%d)\n", ret));
3547 goto done;
3548 }
3549
3550 if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) {
3551 ret = BCME_VERSION;
3552 ANDROID_ERROR(("Ver(%d:%d). mismatch silent roam info(%d)\n",
3553 psroam->ver, WLC_SILENT_ROAM_CUR_VER, ret));
3554 goto done;
3555 }
3556
3557 sroam = (wlc_sroam_info_t *)psroam->data;
3558 bytes_written = snprintf(command, total_len,
3559 "%s %d %d %d %d %d %d %d\n",
3560 CMD_SROAM_GET_INFO, sroam->sroam_on, sroam->sroam_min_rssi, sroam->sroam_rssi_range,
3561 sroam->sroam_score_delta, sroam->sroam_period_time, sroam->sroam_band,
3562 sroam->sroam_inact_cnt);
3563 ret = bytes_written;
3564
3565 ANDROID_INFO(("%s", command));
3566 done:
3567 if (psroam) {
3568 MFREE(dhdp->osh, psroam, sroamlen);
3569 }
3570
3571 return ret;
3572 }
3573 #endif /* CONFIG_SILENT_ROAM */
3574
3575 int
wl_android_priority_roam_enable(struct net_device * dev,int mode)3576 wl_android_priority_roam_enable(struct net_device *dev, int mode)
3577 {
3578 int error = BCME_OK;
3579 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3580 u8 ioctl_buf[WLC_IOCTL_SMLEN];
3581 wl_prio_roam_prof_v1_t *prio_roam;
3582 uint buf_len = sizeof(wl_prio_roam_prof_v1_t) + (uint)strlen("priority_roam") + 1;
3583
3584 prio_roam = (wl_prio_roam_prof_v1_t *)MALLOCZ(dhdp->osh, buf_len);
3585 if (!prio_roam) {
3586 ANDROID_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
3587 error = BCME_NOMEM;
3588 goto done;
3589 }
3590
3591 error = wldev_iovar_getbuf(dev, "priority_roam", NULL, 0, prio_roam, buf_len, NULL);
3592 if (error == BCME_UNSUPPORTED) {
3593 ANDROID_ERROR(("Priority Roam Unsupport\n"));
3594 error = BCME_OK;
3595 goto done;
3596 } else if (prio_roam->version != WL_PRIO_ROAM_PROF_V1) {
3597 ANDROID_ERROR(("Priority Roam Version mismatch\n"));
3598 goto done;
3599 } else if (prio_roam->prio_roam_mode == mode) {
3600 ANDROID_INFO(("Priority Roam already set(mode:%d)\n", mode));
3601 goto done;
3602 }
3603
3604 prio_roam->version = WL_PRIO_ROAM_PROF_V1;
3605 prio_roam->length = sizeof(wl_prio_roam_prof_v1_t);
3606 prio_roam->prio_roam_mode = mode;
3607
3608 error = wldev_iovar_setbuf(dev, "priority_roam", prio_roam,
3609 sizeof(wl_prio_roam_prof_v1_t), ioctl_buf, sizeof(ioctl_buf), NULL);
3610 if (error) {
3611 ANDROID_ERROR(("Failed to set Priority Roam %s(%d)\n",
3612 mode ? "Enable" : "Disable", error));
3613 goto done;
3614 }
3615 done:
3616 if (prio_roam) {
3617 MFREE(dhdp->osh, prio_roam, sizeof(wl_prio_roam_prof_v1_t));
3618 }
3619
3620 return error;
3621 }
3622
3623 #ifdef CONFIG_ROAM_RSSI_LIMIT
3624 int
wl_android_roam_rssi_limit(struct net_device * dev,char * command,int total_len)3625 wl_android_roam_rssi_limit(struct net_device *dev, char *command, int total_len)
3626 {
3627 int ret = BCME_OK;
3628 int argc, bytes_written = 0;
3629 int lmt2g, lmt5g;
3630 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3631
3632 argc = sscanf(command, CMD_ROAM_RSSI_LMT " %d %d\n", &lmt2g, &lmt5g);
3633
3634 if (!argc) {
3635 ret = dhd_roam_rssi_limit_get(dhdp, &lmt2g, &lmt5g);
3636 if (ret) {
3637 ANDROID_ERROR(("Failed to Get roam_rssi_limit (%d)\n", ret));
3638 return ret;
3639 }
3640 bytes_written = snprintf(command, total_len, "%d, %d\n", lmt2g, lmt5g);
3641 /* Get roam rssi limit */
3642 return bytes_written;
3643 } else {
3644 /* Set roam rssi limit */
3645 ret = dhd_roam_rssi_limit_set(dhdp, lmt2g, lmt5g);
3646 if (ret) {
3647 ANDROID_ERROR(("Failed to Set roam_rssi_limit (%d)\n", ret));
3648 return ret;
3649 }
3650 }
3651
3652 return ret;
3653 }
3654 #endif /* CONFIG_ROAM_RSSI_LIMIT */
3655
3656 #ifdef CONFIG_ROAM_MIN_DELTA
3657 int
wl_android_roam_min_delta(struct net_device * dev,char * command,int total_len)3658 wl_android_roam_min_delta(struct net_device *dev, char *command, int total_len)
3659 {
3660 int ret = BCME_OK;
3661 int argc, bytes_written = 0;
3662 uint32 delta2g = 0, delta5g = 0, delta = 0;
3663 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3664
3665 argc = sscanf(command, CMD_ROAM_MIN_DELTA " %d\n", &delta);
3666
3667 if (!argc) {
3668 /* Get Minimum ROAM score delta */
3669 ret = dhd_roam_min_delta_get(dhdp, &delta2g, &delta5g);
3670 if (ret) {
3671 ANDROID_ERROR(("Failed to Get roam_min_delta (%d)\n", ret));
3672 return ret;
3673 }
3674 bytes_written = snprintf(command, total_len, "%d, %d\n", delta2g, delta5g);
3675 return bytes_written;
3676 } else {
3677 /* Set Minimum ROAM score delta
3678 * Framework set one parameter # wpa_cli driver ROAMMINSCOREDELTA <value>
3679 */
3680 ret = dhd_roam_min_delta_set(dhdp, delta, delta);
3681 if (ret) {
3682 ANDROID_ERROR(("Failed to Set roam_min_delta (%d)\n", ret));
3683 return ret;
3684 }
3685 }
3686
3687 return ret;
3688 }
3689 #endif /* CONFIG_ROAM_MIN_DELTA */
3690
3691 static int
get_int_bytes(uchar * oui_str,uchar * oui,int len)3692 get_int_bytes(uchar *oui_str, uchar *oui, int len)
3693 {
3694 int idx;
3695 uchar val;
3696 uchar *src, *dest;
3697 char hexstr[3];
3698
3699 if ((oui_str == NULL) || (oui == NULL) || (len == 0)) {
3700 return BCME_BADARG;
3701 }
3702 src = oui_str;
3703 dest = oui;
3704
3705 for (idx = 0; idx < len; idx++) {
3706 if (*src == '\0') {
3707 *dest = '\0';
3708 break;
3709 }
3710 hexstr[0] = src[0];
3711 hexstr[1] = src[1];
3712 hexstr[2] = '\0';
3713
3714 val = (uchar)bcm_strtoul(hexstr, NULL, 16);
3715 if (val == (uchar)-1) {
3716 return BCME_ERROR;
3717 }
3718 *dest++ = val;
3719 src += 2;
3720 }
3721 return BCME_OK;
3722 }
3723
3724 #define TAG_BYTE 0
3725 static int
wl_android_set_disconnect_ies(struct net_device * dev,char * command)3726 wl_android_set_disconnect_ies(struct net_device *dev, char *command)
3727 {
3728 int cmd_prefix_len = 0;
3729 char ie_len = 0;
3730 int hex_ie_len = 0;
3731 int total_len = 0;
3732 int max_len = 0;
3733 int cmd_len = 0;
3734 uchar disassoc_ie[VNDR_IE_MAX_LEN] = {0};
3735 s32 bssidx = 0;
3736 struct bcm_cfg80211 *cfg = NULL;
3737 s32 ret = 0;
3738 cfg = wl_get_cfg(dev);
3739
3740 cmd_prefix_len = strlen("SET_DISCONNECT_IES ");
3741 cmd_len = strlen(command);
3742 /*
3743 * <CMD> + <IES in HEX format>
3744 * IES in hex format has to be in following format
3745 * First byte = Tag, Second Byte = len and rest of
3746 * bytes will be value. For ex: SET_DISCONNECT_IES dd0411223344
3747 * tag = dd, len =04. Total IEs len = len + 2
3748 */
3749 ANDROID_INFO(("cmd recv = %s\n", command));
3750 max_len = MIN(cmd_len, VNDR_IE_MAX_LEN);
3751 /* Validate IEs len */
3752 get_int_bytes(&command[cmd_prefix_len + 2], &ie_len, 1);
3753 ANDROID_INFO(("ie_len = %d \n", ie_len));
3754 if (ie_len <= 0 || ie_len > max_len) {
3755 ret = BCME_BADLEN;
3756 return ret;
3757 }
3758
3759 /* Total len in hex is sum of double binary len, tag and len byte */
3760 hex_ie_len = (ie_len * 2) + 4;
3761 total_len = cmd_prefix_len + hex_ie_len;
3762 if (command[total_len] != '\0' || (cmd_len != total_len)) {
3763 ANDROID_ERROR(("command recv not matching with len, command = %s"
3764 "total_len = %d, cmd_len = %d\n", command, total_len, cmd_len));
3765 ret = BCME_BADARG;
3766 return ret;
3767 }
3768
3769 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
3770 ANDROID_ERROR(("Find index failed\n"));
3771 ret = -EINVAL;
3772 return ret;
3773 }
3774
3775 /* Tag and len bytes are also part of total len of ies in binary */
3776 ie_len = ie_len + 2;
3777 /* Convert IEs in binary */
3778 get_int_bytes(&command[cmd_prefix_len], disassoc_ie, ie_len);
3779 if (disassoc_ie[TAG_BYTE] != 0xdd) {
3780 ANDROID_ERROR(("Wrong tag recv, tag = 0x%02x\n", disassoc_ie[TAG_BYTE]));
3781 ret = BCME_UNSUPPORTED;
3782 return ret;
3783 }
3784
3785 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
3786 ndev_to_cfgdev(dev), bssidx, VNDR_IE_DISASSOC_FLAG, disassoc_ie, ie_len);
3787
3788 return ret;
3789 }
3790
3791 #ifdef FCC_PWR_LIMIT_2G
3792 int
wl_android_set_fcc_pwr_limit_2g(struct net_device * dev,char * command)3793 wl_android_set_fcc_pwr_limit_2g(struct net_device *dev, char *command)
3794 {
3795 int error = 0;
3796 int enable = 0;
3797
3798 sscanf(command+sizeof("SET_FCC_CHANNEL"), "%d", &enable);
3799
3800 if ((enable != CUSTOMER_HW4_ENABLE) && (enable != CUSTOMER_HW4_DISABLE)) {
3801 ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: Invalid data\n"));
3802 return BCME_ERROR;
3803 }
3804
3805 CUSTOMER_HW4_EN_CONVERT(enable);
3806
3807 ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g set (%d)\n", enable));
3808 error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
3809 if (error) {
3810 ANDROID_ERROR(("wl_android_set_fcc_pwr_limit_2g: fccpwrlimit2g"
3811 " set returned (%d)\n", error));
3812 return BCME_ERROR;
3813 }
3814
3815 return error;
3816 }
3817
3818 int
wl_android_get_fcc_pwr_limit_2g(struct net_device * dev,char * command,int total_len)3819 wl_android_get_fcc_pwr_limit_2g(struct net_device *dev, char *command, int total_len)
3820 {
3821 int error = 0;
3822 int enable = 0;
3823 int bytes_written = 0;
3824
3825 error = wldev_iovar_getint(dev, "fccpwrlimit2g", &enable);
3826 if (error) {
3827 ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get"
3828 " error (%d)\n", error));
3829 return BCME_ERROR;
3830 }
3831 ANDROID_ERROR(("wl_android_get_fcc_pwr_limit_2g: fccpwrlimit2g get (%d)\n", enable));
3832
3833 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_FCC_PWR_LIMIT_2G, enable);
3834
3835 return bytes_written;
3836 }
3837 #endif /* FCC_PWR_LIMIT_2G */
3838
3839 /* Additional format of sta_info
3840 * tx_pkts, tx_failures, tx_rate(kbps), rssi(main), rssi(aux), tx_pkts_retried,
3841 * tx_pkts_retry_exhausted, rx_lastpkt_rssi(main), rx_lastpkt_rssi(aux),
3842 * tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
3843 * tx_pkts_fw_retry_exhausted
3844 */
3845 #define STA_INFO_ADD_FMT "%d %d %d %d %d %d %d %d %d %d %d %d %d %d"
3846
3847 #ifdef BIGDATA_SOFTAP
3848 #define BIGDATA_SOFTAP_FMT MACOUI " %d %s %d %d %d %d %d %d"
3849 #endif /* BIGDATA_SOFTAP */
3850
3851 #define STAINFO_BAND_2G 0x0001
3852 #define STAINFO_BAND_5G 0x0002
3853 #define STAINFO_BAND_6G 0x0004
3854 #define STAINFO_BAND_60G 0x0008
3855 s32
wl_cfg80211_get_sta_info(struct net_device * dev,char * command,int total_len)3856 wl_cfg80211_get_sta_info(struct net_device *dev, char* command, int total_len)
3857 {
3858 int bytes_written = -1, ret = 0;
3859 char *pos, *token, *cmdstr;
3860 bool is_macaddr = FALSE;
3861 sta_info_v4_t *sta = NULL;
3862 struct ether_addr mac;
3863 char *iovar_buf = NULL;
3864 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
3865 struct net_device *apdev = NULL;
3866 #ifdef BCMDONGLEHOST
3867 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
3868 #endif /* BCMDONGLEHOST */
3869
3870 #ifdef BIGDATA_SOFTAP
3871 void *data = NULL;
3872 wl_ap_sta_data_t *sta_data = NULL;
3873 #endif /* BIGDATA_SOFTAP */
3874
3875 /* Client information */
3876 uint16 cap = 0;
3877 uint32 rxrtry = 0, rxmulti = 0;
3878 uint32 tx_pkts = 0, tx_failures = 0, tx_rate = 0;
3879 uint32 tx_pkts_retried = 0, tx_pkts_retry_exhausted = 0;
3880 uint32 tx_pkts_total = 0, tx_pkts_retries = 0;
3881 uint32 tx_pkts_fw_total = 0, tx_pkts_fw_retries = 0;
3882 uint32 tx_pkts_fw_retry_exhausted = 0;
3883 int8 rssi[WL_STA_ANT_MAX] = {0};
3884 int8 rx_lastpkt_rssi[WL_STA_ANT_MAX] = {0};
3885 wl_if_stats_t *if_stats = NULL;
3886 u16 bands = 0;
3887 u32 sta_flags = 0;
3888 char mac_buf[MAX_NUM_OF_ASSOCLIST *
3889 sizeof(struct ether_addr) + sizeof(uint)] = {0};
3890 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
3891
3892 BCM_REFERENCE(if_stats);
3893 /* This Command used during only SoftAP mode. */
3894 ANDROID_INFO(("%s\n", command));
3895
3896 /* Check the current op_mode */
3897 if (!(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) {
3898 ANDROID_ERROR(("unsupported op mode: %d\n", dhdp->op_mode));
3899 return BCME_NOTAP;
3900 }
3901
3902 /*
3903 * DRIVER GETSTAINFO [client MAC or ALL] [ifname]
3904 */
3905 pos = command;
3906
3907 /* drop command */
3908 token = bcmstrtok(&pos, " ", NULL);
3909
3910 /* Client MAC or ALL */
3911 token = bcmstrtok(&pos, " ", NULL);
3912 if (!token) {
3913 ANDROID_ERROR(("GETSTAINFO subcmd not provided wl_cfg80211_get_sta_info\n"));
3914 return -EINVAL;
3915 }
3916 cmdstr = token;
3917
3918 bzero(&mac, ETHER_ADDR_LEN);
3919 if ((!strncmp(token, "all", 3)) || (!strncmp(token, "ALL", 3))) {
3920 is_macaddr = FALSE;
3921 } else if ((bcm_ether_atoe(token, &mac))) {
3922 is_macaddr = TRUE;
3923 } else {
3924 ANDROID_ERROR(("Failed to get address\n"));
3925 return -EINVAL;
3926 }
3927
3928 /* get the interface name */
3929 token = bcmstrtok(&pos, " ", NULL);
3930 if (!token) {
3931 /* assign requested dev for compatibility */
3932 apdev = dev;
3933 } else {
3934 /* Find a net_device for SoftAP by interface name */
3935 apdev = wl_get_ap_netdev(cfg, token);
3936 if (!apdev) {
3937 ANDROID_ERROR(("cannot find a net_device for SoftAP\n"));
3938 return -EINVAL;
3939 }
3940 }
3941
3942 iovar_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
3943 if (!iovar_buf) {
3944 ANDROID_ERROR(("Failed to allocated memory %d bytes\n",
3945 WLC_IOCTL_MAXLEN));
3946 return BCME_NOMEM;
3947 }
3948
3949 if (is_macaddr) {
3950 int cnt;
3951
3952 /* get the sta info */
3953 ret = wldev_iovar_getbuf(apdev, "sta_info",
3954 (struct ether_addr *)mac.octet, ETHER_ADDR_LEN,
3955 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
3956 if (ret < 0) {
3957 ANDROID_ERROR(("Get sta_info ERR %d\n", ret));
3958
3959 #ifdef BIGDATA_SOFTAP
3960 /* Customer wants to send basic client information
3961 * to the framework even if DHD cannot get the sta_info.
3962 */
3963 goto get_bigdata;
3964 #endif /* BIGDATA_SOFTAP */
3965
3966 #ifndef BIGDATA_SOFTAP
3967 goto error;
3968 #endif /* BIGDATA_SOFTAP */
3969 }
3970
3971 sta = (sta_info_v4_t *)iovar_buf;
3972 if (dtoh16(sta->ver) != WL_STA_VER_4) {
3973 ANDROID_ERROR(("sta_info struct version mismatch, "
3974 "host ver : %d, fw ver : %d\n", WL_STA_VER_4,
3975 dtoh16(sta->ver)));
3976
3977 #ifdef BIGDATA_SOFTAP
3978 /* Customer wants to send basic client information
3979 * to the framework even if DHD cannot get the sta_info.
3980 */
3981 goto get_bigdata;
3982 #endif /* BIGDATA_SOFTAP */
3983
3984 #ifndef BIGDATA_SOFTAP
3985 goto error;
3986 #endif /* BIGDATA_SOFTAP */
3987 }
3988 cap = dtoh16(sta->cap);
3989 rxrtry = dtoh32(sta->rx_pkts_retried);
3990 rxmulti = dtoh32(sta->rx_mcast_pkts);
3991 tx_pkts = dtoh32(sta->tx_pkts);
3992 tx_failures = dtoh32(sta->tx_failures);
3993 tx_rate = dtoh32(sta->tx_rate);
3994 tx_pkts_retried = dtoh32(sta->tx_pkts_retried);
3995 tx_pkts_retry_exhausted = dtoh32(sta->tx_pkts_retry_exhausted);
3996 tx_pkts_total = dtoh32(sta->tx_pkts_total);
3997 tx_pkts_retries = dtoh32(sta->tx_pkts_retries);
3998 tx_pkts_fw_total = dtoh32(sta->tx_pkts_fw_total);
3999 tx_pkts_fw_retries = dtoh32(sta->tx_pkts_fw_retries);
4000 tx_pkts_fw_retry_exhausted = dtoh32(sta->tx_pkts_fw_retry_exhausted);
4001 sta_flags = dtoh32(sta->flags);
4002 if (sta_flags & WL_STA_IS_2G) {
4003 bands |= STAINFO_BAND_2G;
4004 }
4005 if (sta_flags & WL_STA_IS_5G) {
4006 bands |= STAINFO_BAND_5G;
4007 }
4008 if (sta_flags & WL_STA_IS_6G) {
4009 bands |= STAINFO_BAND_6G;
4010 }
4011 for (cnt = WL_ANT_IDX_1; cnt < WL_RSSI_ANT_MAX; cnt++) {
4012 rssi[cnt] = sta->rssi[cnt];
4013 rx_lastpkt_rssi[cnt] = sta->rx_lastpkt_rssi[cnt];
4014 }
4015 } else {
4016 int i;
4017
4018 /* Check if there is an associated STA or not */
4019 assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
4020 ret = wldev_ioctl_get(apdev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf));
4021
4022 if (ret < 0) {
4023 ANDROID_ERROR(("Fail to get assoc list: %d\n", ret));
4024 goto error;
4025 }
4026
4027 assoc_maclist->count = dtoh32(assoc_maclist->count);
4028 ANDROID_INFO(("Assoc count : %d\n", assoc_maclist->count));
4029
4030 for (i = 0; i < assoc_maclist->count; i++) {
4031 /* get the sta info */
4032 ret = wldev_iovar_getbuf(apdev, "sta_info",
4033 (struct ether_addr *)assoc_maclist->ea[i].octet, ETHER_ADDR_LEN,
4034 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
4035
4036 if (ret < 0) {
4037 ANDROID_ERROR(("sta_info err : %d", ret));
4038 continue;
4039 }
4040 sta = (sta_info_v4_t *)iovar_buf;
4041 if (dtoh16(sta->ver) == WL_STA_VER_4) {
4042 rxrtry += dtoh32(sta->rx_pkts_retried);
4043 rxmulti += dtoh32(sta->rx_mcast_pkts);
4044 tx_pkts += dtoh32(sta->tx_pkts);
4045 tx_failures += dtoh32(sta->tx_failures);
4046 tx_pkts_total += dtoh32(sta->tx_pkts_total);
4047 tx_pkts_retries += dtoh32(sta->tx_pkts_retries);
4048 tx_pkts_fw_total += dtoh32(sta->tx_pkts_fw_total);
4049 tx_pkts_fw_retries += dtoh32(sta->tx_pkts_fw_retries);
4050 tx_pkts_fw_retry_exhausted +=
4051 dtoh32(sta->tx_pkts_fw_retry_exhausted);
4052 }
4053 }
4054 }
4055
4056 #ifdef BIGDATA_SOFTAP
4057 get_bigdata:
4058
4059 if (is_macaddr && wl_get_ap_stadata(cfg, &mac, &data) == BCME_OK) {
4060 ANDROID_ERROR(("mac " MACDBG" \n", MAC2STRDBG((char*)&mac)));
4061 sta_data = (wl_ap_sta_data_t *)data;
4062 #ifdef STAINFO_LEGACY
4063 bytes_written = snprintf(command, total_len,
4064 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4065 "CAP=%04x " BIGDATA_SOFTAP_FMT " " STA_INFO_ADD_FMT
4066 "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4067 MACOUI2STR((char*)&sta_data->mac),
4068 sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4069 sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4070 sta_data->nss, sta_data->mimo, sta_data->reason_code,
4071 tx_pkts, tx_failures, tx_rate,
4072 (int32)rssi[WL_ANT_IDX_1], (int32)rssi[WL_ANT_IDX_2],
4073 tx_pkts_retried, tx_pkts_retry_exhausted,
4074 (int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4075 (int32)rx_lastpkt_rssi[WL_ANT_IDX_2],
4076 tx_pkts_total, tx_pkts_retries, tx_pkts_fw_total,
4077 tx_pkts_fw_retries, tx_pkts_fw_retry_exhausted);
4078 #else
4079 bytes_written = snprintf(command, total_len,
4080 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d "
4081 "CAP=%04x " BIGDATA_SOFTAP_FMT " %d\n",
4082 CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4083 MACOUI2STR((char*)&sta_data->mac),
4084 sta_data->channel, wf_chspec_to_bw_str(sta_data->chanspec),
4085 sta_data->rssi, sta_data->rate, sta_data->mode_80211,
4086 sta_data->nss, sta_data->mimo, sta_data->reason_code, bands);
4087 #endif /* STAINFO_LEGACY */
4088 } else
4089 #endif /* BIGDATA_SOFTAP */
4090 {
4091 ANDROID_ERROR(("ALL\n"));
4092 bytes_written = snprintf(command, total_len,
4093 "%s %s Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x "
4094 STA_INFO_ADD_FMT "\n", CMD_GET_STA_INFO, cmdstr, rxrtry, rxmulti, cap,
4095 tx_pkts, tx_failures, tx_rate, (int32)rssi[WL_ANT_IDX_1],
4096 (int32)rssi[WL_ANT_IDX_2], tx_pkts_retried,
4097 tx_pkts_retry_exhausted, (int32)rx_lastpkt_rssi[WL_ANT_IDX_1],
4098 (int32)rx_lastpkt_rssi[WL_ANT_IDX_2], tx_pkts_total,
4099 tx_pkts_retries, tx_pkts_fw_total, tx_pkts_fw_retries,
4100 tx_pkts_fw_retry_exhausted);
4101 }
4102 WL_ERR_KERN(("Command: %s", command));
4103
4104 error:
4105 if (iovar_buf) {
4106 MFREE(cfg->osh, iovar_buf, WLC_IOCTL_MAXLEN);
4107 }
4108 if (if_stats) {
4109 MFREE(cfg->osh, if_stats, sizeof(*if_stats));
4110 }
4111
4112 return bytes_written;
4113 }
4114
4115 #ifdef WL_WTC
4116 /*
4117 * CMD Format
4118 * Enable format for 3 band and 2 band respectively:
4119 * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G 6G>
4120 * DRIVER SETWTCMODE 0 1 -80 -70 -65 -60
4121 * DRIVER SETWTCMODE <mode> <scan_type> <rssi_thresh> <ap_rssi_thresg 2G 5G>
4122 * DRIVER SETWTCMODE 0 1 -80 -70 -65
4123 * Disable format for 3 band and 2 band respectively:
4124 * DRIVER SETWTCMODE 1 0 0 0 0 0
4125 * DRIVER SETWTCMODE 1 0 0 0 0
4126 */
4127 #define WL_TRIBAND 3
4128 #define WL_DUALBAND 2
4129
4130 /* For WTC disable, any value >= 1 */
4131 #define WL_WTC_ENABLE 0
4132 static int
wl_android_wtc_config(struct net_device * dev,char * command,int total_len)4133 wl_android_wtc_config(struct net_device *dev, char *command, int total_len)
4134 {
4135 s32 bw;
4136 char *token, *pos;
4137 wlc_wtc_args_t *wtc_params;
4138 wlc_wtcconfig_info_v1_t *wtc_config;
4139 u32 i, wtc_paramslen, maxbands = WL_DUALBAND;
4140 u8 buf[WLC_IOCTL_SMLEN] = {0};
4141 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4142
4143 WL_DBG_MEM(("Enter. cmd:%s\n", command));
4144 #ifdef WL_6G_BAND
4145 if (cfg->band_6g_supported) {
4146 maxbands = WL_TRIBAND;
4147 }
4148 #endif /* WL_6G_BAND */
4149 wtc_paramslen = sizeof(wlc_wtcconfig_info_v1_t) + WLC_WTC_ROAM_CONFIG_HDRLEN;
4150 wtc_params = (wlc_wtc_args_t*)MALLOCZ(cfg->osh, wtc_paramslen);
4151 if (!wtc_params) {
4152 ANDROID_ERROR(("Error allocating wtc_params\n"));
4153 return -ENOMEM;
4154 }
4155
4156 wtc_config = (wlc_wtcconfig_info_v1_t *)wtc_params->data;
4157 /* Get wtc config information and check version compatibility */
4158 bw = wldev_iovar_getbuf(dev, "wnm_wbtext_wtc_config",
4159 (char*)&wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, 0);
4160 if (bw) {
4161 ANDROID_ERROR(("Error querying wnm_wbtext_wtc_config: %d\n", bw));
4162 goto exit;
4163 }
4164
4165 (void)memcpy_s(wtc_params, wtc_paramslen, buf, wtc_paramslen);
4166 if (wtc_params->ver != WLC_WTC_ROAM_VER_1) {
4167 ANDROID_ERROR(("Wrong version:%d\n", wtc_params->ver));
4168 bw = -EINVAL;
4169 goto exit;
4170 }
4171
4172 if (wtc_params->len != sizeof(wlc_wtcconfig_info_v1_t)) {
4173 ANDROID_ERROR(("Bad len\n"));
4174 bw = -EINVAL;
4175 goto exit;
4176 }
4177
4178 if (strlen(command) == strlen(CMD_WTC_CONFIG)) {
4179 /* No additional arguments given. GET case */
4180 bw += scnprintf(command, (total_len - bw), "%u %u",
4181 wtc_config->mode, wtc_config->scantype);
4182 bw += scnprintf(command + bw, (total_len - bw), " %d",
4183 wtc_config->rssithresh[0]);
4184 for (i = 0; i < maxbands; i++) {
4185 bw += scnprintf(command + bw, (total_len - bw), " %d",
4186 wtc_config->ap_rssithresh[i]);
4187 }
4188 bw += scnprintf(command + bw, (total_len - bw), "\n");
4189 } else {
4190 /* SET */
4191 pos = command + sizeof(CMD_WTC_CONFIG);
4192
4193 /* mode */
4194 token = strsep((char**)&pos, " ");
4195 if (!token) {
4196 ANDROID_ERROR(("No mode present\n"));
4197 bw = -EINVAL;
4198 goto exit;
4199 }
4200 wtc_config->mode = (u8)bcm_atoi(token);
4201
4202 /* scantype */
4203 token = strsep((char**)&pos, " ");
4204 if (!token) {
4205 ANDROID_ERROR(("No scantype present\n"));
4206 bw = -EINVAL;
4207 goto exit;
4208 }
4209 wtc_config->scantype = (u8)bcm_atoi(token);
4210
4211 /* rssithreshold */
4212 token = strsep((char**)&pos, " ");
4213 if (!token) {
4214 ANDROID_ERROR(("Invalid arg for rssi threshold\n"));
4215 bw = -EINVAL;
4216 goto exit;
4217 }
4218 for (i = 0; i < maxbands; i++) {
4219 wtc_config->rssithresh[i] = (s8)bcm_atoi(token);
4220 }
4221
4222 /* AP rssithreshold */
4223 for (i = 0; i < maxbands; i++) {
4224 token = strsep((char**)&pos, " ");
4225 if (!token) {
4226 ANDROID_ERROR(("Invalid arg for ap threshold\n"));
4227 bw = -EINVAL;
4228 goto exit;
4229 }
4230 wtc_config->ap_rssithresh[i] = (s8)bcm_atoi(token);
4231 }
4232
4233 bw = wldev_iovar_setbuf(dev, "wnm_wbtext_wtc_config",
4234 (char*)wtc_params, wtc_paramslen, buf, WLC_IOCTL_SMLEN, NULL);
4235 if (bw) {
4236 ANDROID_ERROR(("wtc config set failed. ret:%d\n", bw));
4237 }
4238 }
4239
4240 exit:
4241 if (wtc_params) {
4242 MFREE(cfg->osh, wtc_params, wtc_paramslen);
4243 }
4244 return bw;
4245 }
4246 #endif /* WL_WTC */
4247 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
4248
4249 #ifdef WBTEXT
wl_android_wbtext(struct net_device * dev,char * command,int total_len)4250 static int wl_android_wbtext(struct net_device *dev, char *command, int total_len)
4251 {
4252 int error = BCME_OK, argc = 0;
4253 int data, bytes_written;
4254 int roam_trigger[2];
4255 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4256
4257 argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
4258 if (!argc) {
4259 error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
4260 if (error) {
4261 ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4262 error));
4263 return error;
4264 }
4265 bytes_written = snprintf(command, total_len, "WBTEXT %s\n",
4266 (data == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT)?
4267 "ENABLED" : "DISABLED");
4268 return bytes_written;
4269 } else {
4270 if (data) {
4271 data = WL_BSSTRANS_POLICY_PRODUCT_WBTEXT;
4272 }
4273
4274 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
4275 ANDROID_ERROR(("wl_android_wbtext: Failed to set wbtext error = %d\n",
4276 error));
4277 return error;
4278 }
4279
4280 if (data) {
4281 /* reset roam_prof when wbtext is on */
4282 if ((error = wl_cfg80211_wbtext_set_default(dev)) != BCME_OK) {
4283 return error;
4284 }
4285 } else {
4286 /* reset legacy roam trigger when wbtext is off */
4287 roam_trigger[0] = DEFAULT_ROAM_TRIGGER_VALUE;
4288 roam_trigger[1] = WLC_BAND_ALL;
4289 if ((error = wldev_ioctl_set(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
4290 sizeof(roam_trigger))) != BCME_OK) {
4291 ANDROID_ERROR(("wl_android_wbtext: Failed to reset roam trigger = %d\n",
4292 error));
4293 return error;
4294 }
4295 }
4296 dhdp->wbtext_policy = data;
4297 }
4298 return error;
4299 }
4300
4301 #ifdef WES_SUPPORT
wl_android_check_wbtext_support(struct net_device * dev)4302 static bool wl_android_check_wbtext_support(struct net_device *dev)
4303 {
4304 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4305 return dhdp->wbtext_support;
4306 }
4307
4308 static int
wl_android_wbtext_enable(struct net_device * dev,int mode)4309 wl_android_wbtext_enable(struct net_device *dev, int mode)
4310 {
4311 int error = BCME_OK;
4312 char commandp[WLC_IOCTL_SMLEN];
4313
4314 if (wl_android_check_wbtext_support(dev)) {
4315 bzero(commandp, sizeof(commandp));
4316 snprintf(commandp, WLC_IOCTL_SMLEN, "WBTEXT_ENABLE %d", mode);
4317 error = wl_android_wbtext(dev, commandp, WLC_IOCTL_SMLEN);
4318 if (error) {
4319 ANDROID_ERROR(("Failed to set WBTEXT = %d\n", error));
4320 return error;
4321 }
4322 }
4323
4324 return error;
4325 }
4326 #endif /* WES_SUPPORT */
4327
wl_cfg80211_wbtext_btm_timer_threshold(struct net_device * dev,char * command,int total_len)4328 static int wl_cfg80211_wbtext_btm_timer_threshold(struct net_device *dev,
4329 char *command, int total_len)
4330 {
4331 int error = BCME_OK, argc = 0;
4332 int data, bytes_written;
4333
4334 argc = sscanf(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD " %d\n", &data);
4335 if (!argc) {
4336 error = wldev_iovar_getint(dev, "wnm_bsstrans_timer_threshold", &data);
4337 if (error) {
4338 ANDROID_ERROR(("Failed to get wnm_bsstrans_timer_threshold (%d)\n", error));
4339 return error;
4340 }
4341 bytes_written = snprintf(command, total_len, "%d\n", data);
4342 return bytes_written;
4343 } else {
4344 if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_timer_threshold",
4345 data)) != BCME_OK) {
4346 ANDROID_ERROR(("Failed to set wnm_bsstrans_timer_threshold (%d)\n", error));
4347 return error;
4348 }
4349 }
4350 return error;
4351 }
4352
wl_cfg80211_wbtext_btm_delta(struct net_device * dev,char * command,int total_len)4353 static int wl_cfg80211_wbtext_btm_delta(struct net_device *dev,
4354 char *command, int total_len)
4355 {
4356 int error = BCME_OK, argc = 0;
4357 int data = 0, bytes_written;
4358
4359 argc = sscanf(command, CMD_WBTEXT_BTM_DELTA " %d\n", &data);
4360 if (!argc) {
4361 error = wldev_iovar_getint(dev, "wnm_btmdelta", &data);
4362 if (error) {
4363 ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4364 return error;
4365 }
4366 bytes_written = snprintf(command, total_len, "%d\n", data);
4367 return bytes_written;
4368 } else {
4369 if ((error = wldev_iovar_setint(dev, "wnm_btmdelta",
4370 data)) != BCME_OK) {
4371 ANDROID_ERROR(("Failed to set wnm_btmdelta (%d)\n", error));
4372 return error;
4373 }
4374 }
4375 return error;
4376 }
4377
wl_cfg80211_wbtext_estm_enable(struct net_device * dev,char * command,int total_len)4378 static int wl_cfg80211_wbtext_estm_enable(struct net_device *dev,
4379 char *command, int total_len)
4380 {
4381 int error = BCME_OK;
4382 int data = 0, bytes_written = 0;
4383 int wnmmask = 0;
4384 char *pcmd = command;
4385
4386 bcmstrtok(&pcmd, " ", NULL);
4387
4388 error = wldev_iovar_getint(dev, "wnm", &wnmmask);
4389 if (error) {
4390 ANDROID_ERROR(("Failed to get wnm_btmdelta (%d)\n", error));
4391 return error;
4392 }
4393 ANDROID_INFO(("wnmmask %x\n", wnmmask));
4394 if (*pcmd == WL_IOCTL_ACTION_GET) {
4395 bytes_written = snprintf(command, total_len, "wbtext_estm_enable %d\n",
4396 (wnmmask & WL_WNM_ESTM) ? 1:0);
4397 return bytes_written;
4398 } else {
4399 data = bcm_atoi(pcmd);
4400 if (data == 0) {
4401 wnmmask &= ~WL_WNM_ESTM;
4402 } else {
4403 wnmmask |= WL_WNM_ESTM;
4404 }
4405 ANDROID_INFO(("wnmmask %x\n", wnmmask));
4406 if ((error = wldev_iovar_setint(dev, "wnm", wnmmask)) != BCME_OK) {
4407 ANDROID_ERROR(("Failed to set wnm mask (%d)\n", error));
4408 return error;
4409 }
4410 }
4411 return error;
4412 }
4413 #endif /* WBTEXT */
4414
4415 #ifdef PNO_SUPPORT
4416 #define PNO_PARAM_SIZE 50
4417 #define VALUE_SIZE 50
4418 #define LIMIT_STR_FMT ("%50s %50s")
4419 static int
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)4420 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
4421 {
4422 int err = BCME_OK;
4423 uint i, tokens, len_remain;
4424 char *pos, *pos2, *token, *token2, *delim;
4425 char param[PNO_PARAM_SIZE+1], value[VALUE_SIZE+1];
4426 struct dhd_pno_batch_params batch_params;
4427
4428 ANDROID_INFO(("wls_parse_batching_cmd: command=%s, len=%d\n", command, total_len));
4429 len_remain = total_len;
4430 if (len_remain > (strlen(CMD_WLS_BATCHING) + 1)) {
4431 pos = command + strlen(CMD_WLS_BATCHING) + 1;
4432 len_remain -= strlen(CMD_WLS_BATCHING) + 1;
4433 } else {
4434 ANDROID_ERROR(("wls_parse_batching_cmd: No arguments, total_len %d\n", total_len));
4435 err = BCME_ERROR;
4436 goto exit;
4437 }
4438 bzero(&batch_params, sizeof(struct dhd_pno_batch_params));
4439 if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
4440 if (len_remain > (strlen(PNO_BATCHING_SET) + 1)) {
4441 pos += strlen(PNO_BATCHING_SET) + 1;
4442 } else {
4443 ANDROID_ERROR(("wls_parse_batching_cmd: %s missing arguments, total_len %d\n",
4444 PNO_BATCHING_SET, total_len));
4445 err = BCME_ERROR;
4446 goto exit;
4447 }
4448 while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
4449 bzero(param, sizeof(param));
4450 bzero(value, sizeof(value));
4451 if (token == NULL || !*token)
4452 break;
4453 if (*token == '\0')
4454 continue;
4455 delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
4456 if (delim != NULL)
4457 *delim = ' ';
4458
4459 tokens = sscanf(token, LIMIT_STR_FMT, param, value);
4460 if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
4461 batch_params.scan_fr = simple_strtol(value, NULL, 0);
4462 ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
4463 } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
4464 batch_params.bestn = simple_strtol(value, NULL, 0);
4465 ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
4466 } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
4467 batch_params.mscan = simple_strtol(value, NULL, 0);
4468 ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
4469 } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
4470 i = 0;
4471 pos2 = value;
4472 tokens = sscanf(value, "<%s>", value);
4473 if (tokens != 1) {
4474 err = BCME_ERROR;
4475 ANDROID_ERROR(("wls_parse_batching_cmd: invalid format"
4476 " for channel"
4477 " <> params\n"));
4478 goto exit;
4479 }
4480 while ((token2 = strsep(&pos2,
4481 PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
4482 if (token2 == NULL || !*token2)
4483 break;
4484 if (*token2 == '\0')
4485 continue;
4486 if (*token2 == 'A' || *token2 == 'B') {
4487 batch_params.band = (*token2 == 'A')?
4488 WLC_BAND_5G : WLC_BAND_2G;
4489 ANDROID_INFO(("band : %s\n",
4490 (*token2 == 'A')? "A" : "B"));
4491 } else {
4492 if ((batch_params.nchan >= WL_NUMCHANNELS) ||
4493 (i >= WL_NUMCHANNELS)) {
4494 ANDROID_ERROR(("Too many nchan %d\n",
4495 batch_params.nchan));
4496 err = BCME_BUFTOOSHORT;
4497 goto exit;
4498 }
4499 batch_params.chan_list[i++] =
4500 simple_strtol(token2, NULL, 0);
4501 batch_params.nchan++;
4502 ANDROID_INFO(("channel :%d\n",
4503 batch_params.chan_list[i-1]));
4504 }
4505 }
4506 } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
4507 batch_params.rtt = simple_strtol(value, NULL, 0);
4508 ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
4509 } else {
4510 ANDROID_ERROR(("wls_parse_batching_cmd : unknown param: %s\n", param));
4511 err = BCME_ERROR;
4512 goto exit;
4513 }
4514 }
4515 err = dhd_dev_pno_set_for_batch(dev, &batch_params);
4516 if (err < 0) {
4517 ANDROID_ERROR(("failed to configure batch scan\n"));
4518 } else {
4519 bzero(command, total_len);
4520 err = snprintf(command, total_len, "%d", err);
4521 }
4522 } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
4523 err = dhd_dev_pno_get_for_batch(dev, command, total_len);
4524 if (err < 0) {
4525 ANDROID_ERROR(("failed to getting batching results\n"));
4526 } else {
4527 err = strlen(command);
4528 }
4529 } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
4530 err = dhd_dev_pno_stop_for_batch(dev);
4531 if (err < 0) {
4532 ANDROID_ERROR(("failed to stop batching scan\n"));
4533 } else {
4534 bzero(command, total_len);
4535 err = snprintf(command, total_len, "OK");
4536 }
4537 } else {
4538 ANDROID_ERROR(("wls_parse_batching_cmd : unknown command\n"));
4539 err = BCME_ERROR;
4540 goto exit;
4541 }
4542 exit:
4543 return err;
4544 }
4545
4546 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)4547 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
4548 {
4549 wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
4550 int res = -1;
4551 int nssid = 0;
4552 cmd_tlv_t *cmd_tlv_temp;
4553 char *str_ptr;
4554 int tlv_size_left;
4555 int pno_time = 0;
4556 int pno_repeat = 0;
4557 int pno_freq_expo_max = 0;
4558
4559 #ifdef PNO_SET_DEBUG
4560 int i;
4561 char pno_in_example[] = {
4562 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
4563 'S', '1', '2', '0',
4564 'S',
4565 0x05,
4566 'd', 'l', 'i', 'n', 'k',
4567 'S',
4568 0x04,
4569 'G', 'O', 'O', 'G',
4570 'T',
4571 '0', 'B',
4572 'R',
4573 '2',
4574 'M',
4575 '2',
4576 0x00
4577 };
4578 #endif /* PNO_SET_DEBUG */
4579 ANDROID_INFO(("wl_android_set_pno_setup: command=%s, len=%d\n", command, total_len));
4580
4581 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
4582 ANDROID_ERROR(("wl_android_set_pno_setup: argument=%d less min size\n", total_len));
4583 goto exit_proc;
4584 }
4585 #ifdef PNO_SET_DEBUG
4586 memcpy(command, pno_in_example, sizeof(pno_in_example));
4587 total_len = sizeof(pno_in_example);
4588 #endif
4589 str_ptr = command + strlen(CMD_PNOSETUP_SET);
4590 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
4591
4592 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
4593 bzero(ssids_local, sizeof(ssids_local));
4594
4595 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
4596 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
4597 (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
4598
4599 str_ptr += sizeof(cmd_tlv_t);
4600 tlv_size_left -= sizeof(cmd_tlv_t);
4601
4602 if ((nssid = wl_parse_ssid_list_tlv(&str_ptr, ssids_local,
4603 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
4604 ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
4605 goto exit_proc;
4606 } else {
4607 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
4608 ANDROID_ERROR(("wl_android_set_pno_setup: scan duration corrupted"
4609 " field size %d\n",
4610 tlv_size_left));
4611 goto exit_proc;
4612 }
4613 str_ptr++;
4614 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
4615 ANDROID_INFO(("wl_android_set_pno_setup: pno_time=%d\n", pno_time));
4616
4617 if (str_ptr[0] != 0) {
4618 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
4619 ANDROID_ERROR(("wl_android_set_pno_setup: pno repeat:"
4620 " corrupted field\n"));
4621 goto exit_proc;
4622 }
4623 str_ptr++;
4624 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
4625 ANDROID_INFO(("wl_android_set_pno_setup: got pno_repeat=%d\n",
4626 pno_repeat));
4627 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
4628 ANDROID_ERROR(("wl_android_set_pno_setup: FREQ_EXPO_MAX"
4629 " corrupted field size\n"));
4630 goto exit_proc;
4631 }
4632 str_ptr++;
4633 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
4634 ANDROID_INFO(("wl_android_set_pno_setup: pno_freq_expo_max=%d\n",
4635 pno_freq_expo_max));
4636 }
4637 }
4638 } else {
4639 ANDROID_ERROR(("wl_android_set_pno_setup: get wrong TLV command\n"));
4640 goto exit_proc;
4641 }
4642
4643 res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
4644 pno_freq_expo_max, NULL, 0);
4645 exit_proc:
4646 return res;
4647 }
4648 #endif /* !WL_SCHED_SCAN */
4649 #endif /* PNO_SUPPORT */
4650
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)4651 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
4652 {
4653 int ret;
4654 struct ether_addr p2pdev_addr;
4655
4656 #define MAC_ADDR_STR_LEN 18
4657 if (total_len < MAC_ADDR_STR_LEN) {
4658 ANDROID_ERROR(("wl_android_get_p2p_dev_addr: buflen %d is less than p2p dev addr\n",
4659 total_len));
4660 return -1;
4661 }
4662
4663 ret = wl_cfg80211_get_p2p_dev_addr(ndev, &p2pdev_addr);
4664 if (ret) {
4665 ANDROID_ERROR(("wl_android_get_p2p_dev_addr: Failed to get p2p dev addr\n"));
4666 return -1;
4667 }
4668 return (snprintf(command, total_len, MACF, ETHERP_TO_MACF(&p2pdev_addr)));
4669 }
4670
4671 int
wl_android_set_ap_mac_list(struct net_device * dev,int macmode,struct maclist * maclist)4672 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
4673 {
4674 int i, j, match;
4675 int ret = 0;
4676 char mac_buf[MAX_NUM_OF_ASSOCLIST *
4677 sizeof(struct ether_addr) + sizeof(uint)] = {0};
4678 struct maclist *assoc_maclist = (struct maclist *)mac_buf;
4679
4680 /* set filtering mode */
4681 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode)) != 0)) {
4682 ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACMODE error=%d\n", ret));
4683 return ret;
4684 }
4685 if (macmode != MACLIST_MODE_DISABLED) {
4686 /* set the MAC filter list */
4687 if ((ret = wldev_ioctl_set(dev, WLC_SET_MACLIST, maclist,
4688 sizeof(int) + sizeof(struct ether_addr) * maclist->count)) != 0) {
4689 ANDROID_ERROR(("wl_android_set_ap_mac_list : WLC_SET_MACLIST error=%d\n", ret));
4690 return ret;
4691 }
4692 /* get the current list of associated STAs */
4693 assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
4694 if ((ret = wldev_ioctl_get(dev, WLC_GET_ASSOCLIST, assoc_maclist,
4695 sizeof(mac_buf))) != 0) {
4696 ANDROID_ERROR(("wl_android_set_ap_mac_list: WLC_GET_ASSOCLIST error=%d\n",
4697 ret));
4698 return ret;
4699 }
4700 /* do we have any STA associated? */
4701 if (assoc_maclist->count) {
4702 /* iterate each associated STA */
4703 for (i = 0; i < assoc_maclist->count; i++) {
4704 match = 0;
4705 /* compare with each entry */
4706 for (j = 0; j < maclist->count; j++) {
4707 ANDROID_INFO(("wl_android_set_ap_mac_list: associated="MACDBG
4708 "list = "MACDBG "\n",
4709 MAC2STRDBG(assoc_maclist->ea[i].octet),
4710 MAC2STRDBG(maclist->ea[j].octet)));
4711 if (memcmp(assoc_maclist->ea[i].octet,
4712 maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
4713 match = 1;
4714 break;
4715 }
4716 }
4717 /* do conditional deauth */
4718 /* "if not in the allow list" or "if in the deny list" */
4719 if ((macmode == MACLIST_MODE_ALLOW && !match) ||
4720 (macmode == MACLIST_MODE_DENY && match)) {
4721 scb_val_t scbval;
4722
4723 scbval.val = htod32(1);
4724 memcpy(&scbval.ea, &assoc_maclist->ea[i],
4725 ETHER_ADDR_LEN);
4726 if ((ret = wldev_ioctl_set(dev,
4727 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
4728 &scbval, sizeof(scb_val_t))) != 0)
4729 ANDROID_ERROR(("wl_android_set_ap_mac_list:"
4730 " WLC_SCB_DEAUTHENTICATE"
4731 " error=%d\n",
4732 ret));
4733 }
4734 }
4735 }
4736 }
4737 return ret;
4738 }
4739
4740 /*
4741 * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
4742 *
4743 */
4744 static int
wl_android_set_mac_address_filter(struct net_device * dev,char * str)4745 wl_android_set_mac_address_filter(struct net_device *dev, char* str)
4746 {
4747 int i;
4748 int ret = 0;
4749 int macnum = 0;
4750 int macmode = MACLIST_MODE_DISABLED;
4751 struct maclist *list;
4752 char eabuf[ETHER_ADDR_STR_LEN];
4753 const char *token;
4754 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
4755
4756 /* string should look like below (macmode/macnum/maclist) */
4757 /* 1 2 00:11:22:33:44:55 00:11:22:33:44:ff */
4758
4759 /* get the MAC filter mode */
4760 token = strsep((char**)&str, " ");
4761 if (!token) {
4762 return -1;
4763 }
4764 macmode = bcm_atoi(token);
4765
4766 if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
4767 ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid macmode %d\n", macmode));
4768 return -1;
4769 }
4770
4771 token = strsep((char**)&str, " ");
4772 if (!token) {
4773 return -1;
4774 }
4775 macnum = bcm_atoi(token);
4776 if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
4777 ANDROID_ERROR(("wl_android_set_mac_address_filter: invalid number of MAC"
4778 " address entries %d\n",
4779 macnum));
4780 return -1;
4781 }
4782 /* allocate memory for the MAC list */
4783 list = (struct maclist*) MALLOCZ(cfg->osh, sizeof(int) +
4784 sizeof(struct ether_addr) * macnum);
4785 if (!list) {
4786 ANDROID_ERROR(("wl_android_set_mac_address_filter : failed to allocate memory\n"));
4787 return -1;
4788 }
4789 /* prepare the MAC list */
4790 list->count = htod32(macnum);
4791 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
4792 for (i = 0; i < list->count; i++) {
4793 token = strsep((char**)&str, " ");
4794 if (token == NULL) {
4795 ANDROID_ERROR(("wl_android_set_mac_address_filter : No mac address present\n"));
4796 ret = -EINVAL;
4797 goto exit;
4798 }
4799 strlcpy(eabuf, token, sizeof(eabuf));
4800 if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
4801 ANDROID_ERROR(("wl_android_set_mac_address_filter : mac parsing err index=%d,"
4802 " addr=%s\n",
4803 i, eabuf));
4804 list->count = i;
4805 break;
4806 }
4807 ANDROID_INFO(("wl_android_set_mac_address_filter : %d/%d MACADDR=%s",
4808 i, list->count, eabuf));
4809 }
4810 if (i == 0)
4811 goto exit;
4812
4813 /* set the list */
4814 if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
4815 ANDROID_ERROR(("wl_android_set_mac_address_filter: Setting MAC list failed error=%d\n",
4816 ret));
4817
4818 exit:
4819 MFREE(cfg->osh, list, sizeof(int) + sizeof(struct ether_addr) * macnum);
4820
4821 return ret;
4822 }
4823
wl_android_get_factory_mac_addr(struct net_device * ndev,char * command,int total_len)4824 static int wl_android_get_factory_mac_addr(struct net_device *ndev, char *command, int total_len)
4825 {
4826 int ret;
4827 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
4828
4829 if (total_len < ETHER_ADDR_STR_LEN) {
4830 ANDROID_ERROR(("wl_android_get_factory_mac_addr buflen %d"
4831 "is less than factory mac addr\n", total_len));
4832 return BCME_ERROR;
4833 }
4834 ret = snprintf(command, total_len, MACDBG,
4835 MAC2STRDBG(bcmcfg_to_prmry_ndev(cfg)->perm_addr));
4836 return ret;
4837 }
4838
4839 #if defined(WLAN_ACCEL_BOOT)
wl_android_wifi_accel_on(struct net_device * dev,bool force_reg_on)4840 int wl_android_wifi_accel_on(struct net_device *dev, bool force_reg_on)
4841 {
4842 int ret = 0;
4843
4844 ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4845 if (!dev) {
4846 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4847 return -EINVAL;
4848 }
4849
4850 if (force_reg_on) {
4851 /* First resume the bus if it is in suspended state */
4852 ret = dhd_net_bus_resume(dev, 0);
4853 if (ret) {
4854 ANDROID_ERROR(("%s: dhd_net_bus_resume failed\n", __FUNCTION__));
4855 }
4856 /* Toggle wl_reg_on */
4857 ret = wl_android_wifi_off(dev, TRUE);
4858 if (ret) {
4859 ANDROID_ERROR(("%s: wl_android_wifi_off failed\n", __FUNCTION__));
4860 }
4861 ret = wl_android_wifi_on(dev);
4862 if (ret) {
4863 ANDROID_ERROR(("%s: wl_android_wifi_on failed\n", __FUNCTION__));
4864 }
4865 } else {
4866 ret = dhd_net_bus_resume(dev, 0);
4867 }
4868
4869 return ret;
4870 }
4871
wl_android_wifi_accel_off(struct net_device * dev,bool force_reg_on)4872 int wl_android_wifi_accel_off(struct net_device *dev, bool force_reg_on)
4873 {
4874 int ret = 0;
4875
4876 ANDROID_ERROR(("%s: force_reg_on = %d\n", __FUNCTION__, force_reg_on));
4877 if (!dev) {
4878 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4879 return -EINVAL;
4880 }
4881
4882 if (force_reg_on) {
4883 ANDROID_ERROR(("%s: do nothing as wl_reg_on will be toggled in UP\n",
4884 __FUNCTION__));
4885 } else {
4886 ret = dhd_net_bus_suspend(dev);
4887 }
4888
4889 return ret;
4890 }
4891 #endif /* WLAN_ACCEL_BOOT */
4892
4893 #ifdef WBRC
4894 extern int wbrc_wl2bt_reset(void);
4895 #endif /* WBRC */
4896
4897 /**
4898 * Global function definitions (declared in wl_android.h)
4899 */
4900
wl_android_wifi_on(struct net_device * dev)4901 int wl_android_wifi_on(struct net_device *dev)
4902 {
4903 int ret = 0;
4904 int retry = POWERUP_MAX_RETRY;
4905 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
4906
4907 BCM_REFERENCE(dhdp);
4908 if (!dev) {
4909 ANDROID_ERROR(("wl_android_wifi_on: dev is null\n"));
4910 return -EINVAL;
4911 }
4912
4913 dhd_net_if_lock(dev);
4914 WL_MSG(dev->name, "in g_wifi_on=%d\n", g_wifi_on);
4915 if (!g_wifi_on) {
4916 do {
4917 dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
4918 #ifdef BCMSDIO
4919 ret = dhd_net_bus_resume(dev, 0);
4920 if (ret)
4921 goto retry_power;
4922 #endif /* BCMSDIO */
4923 ret = dhd_net_bus_devreset(dev, FALSE);
4924 #ifdef WBRC
4925 if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ONCE) {
4926 ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4927 __FUNCTION__, dhdp->dhd_induce_bh_error));
4928 /* Forcefully set error */
4929 ret = BCME_ERROR;
4930 /* Clear the induced bh error */
4931 dhdp->dhd_induce_bh_error = DHD_INDUCE_ERROR_CLEAR;
4932 }
4933 if (dhdp->dhd_induce_bh_error == DHD_INDUCE_BH_ON_FAIL_ALWAYS) {
4934 ANDROID_ERROR(("%s: dhd_induce_bh_error = %d\n",
4935 __FUNCTION__, dhdp->dhd_induce_bh_error));
4936 /* Forcefully set error */
4937 ret = BCME_ERROR;
4938 }
4939 #endif /* WBRC */
4940 if (ret)
4941 goto retry_power;
4942 #if defined(BCMSDIO) || defined(BCMDBUS)
4943 #ifdef BCMSDIO
4944 dhd_net_bus_resume(dev, 1);
4945 #endif /* BCMSDIO */
4946 ret = dhd_dev_init_ioctl(dev);
4947 if (ret < 0) {
4948 goto retry_bus;
4949 }
4950 #endif /* BCMSDIO || BCMDBUS */
4951 if (ret == 0) {
4952 break;
4953 }
4954 #if defined(BCMSDIO) || defined(BCMDBUS)
4955 retry_bus:
4956 #ifdef BCMSDIO
4957 dhd_net_bus_suspend(dev);
4958 #endif /* BCMSDIO */
4959 #endif /* BCMSDIO || BCMDBUS */
4960 retry_power:
4961 ANDROID_ERROR(("failed to power up wifi chip, retry again (%d left) **\n\n",
4962 retry));
4963 dhd_net_bus_devreset(dev, TRUE);
4964 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
4965 #ifdef WBRC
4966 /* Inform BT reset which will internally wait till BT reset is done */
4967 if (wbrc_wl2bt_reset()) {
4968 ANDROID_ERROR(("Failed to reset BT, nothing to be done!!!!\n"));
4969 }
4970 #endif /* WBRC */
4971 } while (retry-- > 0);
4972 if (ret != 0) {
4973 ANDROID_ERROR(("failed to power up wifi chip, max retry reached **\n\n"));
4974 #ifdef BCM_DETECT_TURN_ON_FAILURE
4975 BUG_ON(1);
4976 #endif /* BCM_DETECT_TURN_ON_FAILURE */
4977 goto exit;
4978 }
4979 g_wifi_on = TRUE;
4980 }
4981
4982 exit:
4983 if (ret)
4984 WL_MSG(dev->name, "Failed %d\n", ret);
4985 else
4986 WL_MSG(dev->name, "Success\n");
4987 dhd_net_if_unlock(dev);
4988 return ret;
4989 }
4990
wl_android_wifi_off(struct net_device * dev,bool on_failure)4991 int wl_android_wifi_off(struct net_device *dev, bool on_failure)
4992 {
4993 int ret = 0;
4994
4995 if (!dev) {
4996 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
4997 return -EINVAL;
4998 }
4999
5000 #if defined(BCMPCIE) && defined(DHD_DEBUG_UART)
5001 ret = dhd_debug_uart_is_running(dev);
5002 if (ret) {
5003 ANDROID_ERROR(("wl_android_wifi_off: - Debug UART App is running\n"));
5004 return -EBUSY;
5005 }
5006 #endif /* BCMPCIE && DHD_DEBUG_UART */
5007 dhd_net_if_lock(dev);
5008 WL_MSG(dev->name, "in g_wifi_on=%d, on_failure=%d\n", g_wifi_on, on_failure);
5009 if (g_wifi_on || on_failure) {
5010 #if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
5011 ret = dhd_net_bus_devreset(dev, TRUE);
5012 #ifdef BCMSDIO
5013 dhd_net_bus_suspend(dev);
5014 #endif /* BCMSDIO */
5015 #endif /* BCMSDIO || BCMPCIE || BCMDBUS */
5016 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
5017 g_wifi_on = FALSE;
5018 }
5019 WL_MSG(dev->name, "out\n");
5020 dhd_net_if_unlock(dev);
5021
5022 return ret;
5023 }
5024
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)5025 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
5026 {
5027 if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
5028 return -1;
5029 return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
5030 }
5031
5032 #ifdef CONNECTION_STATISTICS
5033 static int
wl_chanim_stats(struct net_device * dev,u8 * chan_idle)5034 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
5035 {
5036 int err;
5037 wl_chanim_stats_t *list;
5038 /* Parameter _and_ returned buffer of chanim_stats. */
5039 wl_chanim_stats_t param;
5040 u8 result[WLC_IOCTL_SMLEN];
5041 chanim_stats_t *stats;
5042
5043 bzero(¶m, sizeof(param));
5044
5045 param.buflen = htod32(sizeof(wl_chanim_stats_t));
5046 param.count = htod32(WL_CHANIM_COUNT_ONE);
5047
5048 if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)¶m, sizeof(wl_chanim_stats_t),
5049 (char*)result, sizeof(result), 0)) < 0) {
5050 ANDROID_ERROR(("Failed to get chanim results %d \n", err));
5051 return err;
5052 }
5053
5054 list = (wl_chanim_stats_t*)result;
5055
5056 list->buflen = dtoh32(list->buflen);
5057 list->version = dtoh32(list->version);
5058 list->count = dtoh32(list->count);
5059
5060 if (list->buflen == 0) {
5061 list->version = 0;
5062 list->count = 0;
5063 } else if (list->version != WL_CHANIM_STATS_VERSION) {
5064 ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
5065 "but driver supports only version %d.\n",
5066 list->version, WL_CHANIM_STATS_VERSION));
5067 list->buflen = 0;
5068 list->count = 0;
5069 }
5070
5071 stats = list->stats;
5072 stats->glitchcnt = dtoh32(stats->glitchcnt);
5073 stats->badplcp = dtoh32(stats->badplcp);
5074 stats->chanspec = dtoh16(stats->chanspec);
5075 stats->timestamp = dtoh32(stats->timestamp);
5076 stats->chan_idle = dtoh32(stats->chan_idle);
5077
5078 ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
5079 stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
5080 stats->timestamp));
5081
5082 *chan_idle = stats->chan_idle;
5083
5084 return (err);
5085 }
5086
5087 static int
wl_android_get_connection_stats(struct net_device * dev,char * command,int total_len)5088 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
5089 {
5090 static char iovar_buf[WLC_IOCTL_MAXLEN];
5091 const wl_cnt_wlc_t* wlc_cnt = NULL;
5092 #ifndef DISABLE_IF_COUNTERS
5093 wl_if_stats_t* if_stats = NULL;
5094 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5095 #ifdef BCMDONGLEHOST
5096 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
5097 #endif /* BCMDONGLEHOST */
5098 #endif /* DISABLE_IF_COUNTERS */
5099
5100 int link_speed = 0;
5101 struct connection_stats *output;
5102 unsigned int bufsize = 0;
5103 int bytes_written = -1;
5104 int ret = 0;
5105
5106 ANDROID_INFO(("wl_android_get_connection_stats: enter Get Connection Stats\n"));
5107
5108 if (total_len <= 0) {
5109 ANDROID_ERROR(("wl_android_get_connection_stats: invalid buffer size %d\n", total_len));
5110 goto error;
5111 }
5112
5113 bufsize = total_len;
5114 if (bufsize < sizeof(struct connection_stats)) {
5115 ANDROID_ERROR(("wl_android_get_connection_stats: not enough buffer size, provided=%u,"
5116 " requires=%zu\n",
5117 bufsize,
5118 sizeof(struct connection_stats)));
5119 goto error;
5120 }
5121
5122 output = (struct connection_stats *)command;
5123
5124 #ifndef DISABLE_IF_COUNTERS
5125 if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(*if_stats));
5126 if (if_stats == NULL) {
5127 ANDROID_ERROR(("wl_android_get_connection_stats: MALLOCZ failed\n"));
5128 goto error;
5129 }
5130 bzero(if_stats, sizeof(*if_stats));
5131
5132 #ifdef BCMDONGLEHOST
5133 if (FW_SUPPORTED(dhdp, ifst)) {
5134 ret = wl_cfg80211_ifstats_counters(dev, if_stats);
5135 } else
5136 #endif /* BCMDONGLEHOST */
5137 {
5138 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5139 (char *)if_stats, sizeof(*if_stats), NULL);
5140 }
5141
5142 ret = wldev_iovar_getbuf(dev, "if_counters", NULL, 0,
5143 (char *)if_stats, sizeof(*if_stats), NULL);
5144 if (ret) {
5145 ANDROID_ERROR(("wl_android_get_connection_stats: if_counters not supported ret=%d\n",
5146 ret));
5147
5148 /* In case if_stats IOVAR is not supported, get information from counters. */
5149 #endif /* DISABLE_IF_COUNTERS */
5150 ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
5151 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
5152 if (unlikely(ret)) {
5153 ANDROID_ERROR(("counters error (%d) - size = %zu\n", ret, sizeof(wl_cnt_wlc_t)));
5154 goto error;
5155 }
5156 ret = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
5157 if (ret != BCME_OK) {
5158 ANDROID_ERROR(("wl_android_get_connection_stats:"
5159 " wl_cntbuf_to_xtlv_format ERR %d\n",
5160 ret));
5161 goto error;
5162 }
5163
5164 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
5165 ANDROID_ERROR(("wl_android_get_connection_stats: wlc_cnt NULL!\n"));
5166 goto error;
5167 }
5168
5169 output->txframe = dtoh32(wlc_cnt->txframe);
5170 output->txbyte = dtoh32(wlc_cnt->txbyte);
5171 output->txerror = dtoh32(wlc_cnt->txerror);
5172 output->rxframe = dtoh32(wlc_cnt->rxframe);
5173 output->rxbyte = dtoh32(wlc_cnt->rxbyte);
5174 output->txfail = dtoh32(wlc_cnt->txfail);
5175 output->txretry = dtoh32(wlc_cnt->txretry);
5176 output->txretrie = dtoh32(wlc_cnt->txretrie);
5177 output->txrts = dtoh32(wlc_cnt->txrts);
5178 output->txnocts = dtoh32(wlc_cnt->txnocts);
5179 output->txexptime = dtoh32(wlc_cnt->txexptime);
5180 #ifndef DISABLE_IF_COUNTERS
5181 } else {
5182 /* Populate from if_stats. */
5183 if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
5184 ANDROID_ERROR(("wl_android_get_connection_stats: incorrect version of"
5185 " wl_if_stats_t,"
5186 " expected=%u got=%u\n",
5187 WL_IF_STATS_T_VERSION, if_stats->version));
5188 goto error;
5189 }
5190
5191 output->txframe = (uint32)dtoh64(if_stats->txframe);
5192 output->txbyte = (uint32)dtoh64(if_stats->txbyte);
5193 output->txerror = (uint32)dtoh64(if_stats->txerror);
5194 output->rxframe = (uint32)dtoh64(if_stats->rxframe);
5195 output->rxbyte = (uint32)dtoh64(if_stats->rxbyte);
5196 output->txfail = (uint32)dtoh64(if_stats->txfail);
5197 output->txretry = (uint32)dtoh64(if_stats->txretry);
5198 output->txretrie = (uint32)dtoh64(if_stats->txretrie);
5199 if (dtoh16(if_stats->length) > OFFSETOF(wl_if_stats_t, txexptime)) {
5200 output->txexptime = (uint32)dtoh64(if_stats->txexptime);
5201 output->txrts = (uint32)dtoh64(if_stats->txrts);
5202 output->txnocts = (uint32)dtoh64(if_stats->txnocts);
5203 } else {
5204 output->txexptime = 0;
5205 output->txrts = 0;
5206 output->txnocts = 0;
5207 }
5208 }
5209 #endif /* DISABLE_IF_COUNTERS */
5210
5211 /* link_speed is in kbps */
5212 ret = wldev_get_link_speed(dev, &link_speed);
5213 if (ret || link_speed < 0) {
5214 ANDROID_ERROR(("wl_android_get_connection_stats: wldev_get_link_speed()"
5215 " failed, ret=%d, speed=%d\n",
5216 ret, link_speed));
5217 goto error;
5218 }
5219
5220 output->txrate = link_speed;
5221
5222 /* Channel idle ratio. */
5223 if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
5224 output->chan_idle = 0;
5225 };
5226
5227 bytes_written = sizeof(struct connection_stats);
5228
5229 error:
5230 #ifndef DISABLE_IF_COUNTERS
5231 if (if_stats) {
5232 MFREE(cfg->osh, if_stats, sizeof(*if_stats));
5233 }
5234 #endif /* DISABLE_IF_COUNTERS */
5235
5236 return bytes_written;
5237 }
5238 #endif /* CONNECTION_STATISTICS */
5239
5240 #ifdef WL_NATOE
5241 static int
wl_android_process_natoe_cmd(struct net_device * dev,char * command,int total_len)5242 wl_android_process_natoe_cmd(struct net_device *dev, char *command, int total_len)
5243 {
5244 int ret = BCME_ERROR;
5245 char *pcmd = command;
5246 char *str = NULL;
5247 wl_natoe_cmd_info_t cmd_info;
5248 const wl_natoe_sub_cmd_t *natoe_cmd = &natoe_cmd_list[0];
5249
5250 /* skip to cmd name after "natoe" */
5251 str = bcmstrtok(&pcmd, " ", NULL);
5252
5253 /* If natoe subcmd name is not provided, return error */
5254 if (*pcmd == '\0') {
5255 ANDROID_ERROR(("natoe subcmd not provided wl_android_process_natoe_cmd\n"));
5256 ret = -EINVAL;
5257 return ret;
5258 }
5259
5260 /* get the natoe command name to str */
5261 str = bcmstrtok(&pcmd, " ", NULL);
5262
5263 while (natoe_cmd->name != NULL) {
5264 if (strcmp(natoe_cmd->name, str) == 0) {
5265 /* dispacth cmd to appropriate handler */
5266 if (natoe_cmd->handler) {
5267 cmd_info.command = command;
5268 cmd_info.tot_len = total_len;
5269 ret = natoe_cmd->handler(dev, natoe_cmd, pcmd, &cmd_info);
5270 }
5271 return ret;
5272 }
5273 natoe_cmd++;
5274 }
5275 return ret;
5276 }
5277
5278 static int
wlu_natoe_set_vars_cbfn(void * ctx,uint8 * data,uint16 type,uint16 len)5279 wlu_natoe_set_vars_cbfn(void *ctx, uint8 *data, uint16 type, uint16 len)
5280 {
5281 int res = BCME_OK;
5282 wl_natoe_cmd_info_t *cmd_info = (wl_natoe_cmd_info_t *)ctx;
5283 uint8 *command = cmd_info->command;
5284 uint16 total_len = cmd_info->tot_len;
5285 uint16 bytes_written = 0;
5286
5287 UNUSED_PARAMETER(len);
5288
5289 switch (type) {
5290
5291 case WL_NATOE_XTLV_ENABLE:
5292 {
5293 bytes_written = snprintf(command, total_len, "natoe: %s\n",
5294 *data?"enabled":"disabled");
5295 cmd_info->bytes_written = bytes_written;
5296 break;
5297 }
5298
5299 case WL_NATOE_XTLV_CONFIG_IPS:
5300 {
5301 wl_natoe_config_ips_t *config_ips;
5302 uint8 buf[16];
5303
5304 config_ips = (wl_natoe_config_ips_t *)data;
5305 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_ip, buf);
5306 bytes_written = snprintf(command, total_len, "sta ip: %s\n", buf);
5307 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_netmask, buf);
5308 bytes_written += snprintf(command + bytes_written, total_len,
5309 "sta netmask: %s\n", buf);
5310 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_router_ip, buf);
5311 bytes_written += snprintf(command + bytes_written, total_len,
5312 "sta router ip: %s\n", buf);
5313 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->sta_dnsip, buf);
5314 bytes_written += snprintf(command + bytes_written, total_len,
5315 "sta dns ip: %s\n", buf);
5316 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_ip, buf);
5317 bytes_written += snprintf(command + bytes_written, total_len,
5318 "ap ip: %s\n", buf);
5319 bcm_ip_ntoa((struct ipv4_addr *)&config_ips->ap_netmask, buf);
5320 bytes_written += snprintf(command + bytes_written, total_len,
5321 "ap netmask: %s\n", buf);
5322 cmd_info->bytes_written = bytes_written;
5323 break;
5324 }
5325
5326 case WL_NATOE_XTLV_CONFIG_PORTS:
5327 {
5328 wl_natoe_ports_config_t *ports_config;
5329
5330 ports_config = (wl_natoe_ports_config_t *)data;
5331 bytes_written = snprintf(command, total_len, "starting port num: %d\n",
5332 dtoh16(ports_config->start_port_num));
5333 bytes_written += snprintf(command + bytes_written, total_len,
5334 "number of ports: %d\n", dtoh16(ports_config->no_of_ports));
5335 cmd_info->bytes_written = bytes_written;
5336 break;
5337 }
5338
5339 case WL_NATOE_XTLV_DBG_STATS:
5340 {
5341 char *stats_dump = (char *)data;
5342
5343 bytes_written = snprintf(command, total_len, "%s\n", stats_dump);
5344 cmd_info->bytes_written = bytes_written;
5345 break;
5346 }
5347
5348 case WL_NATOE_XTLV_TBL_CNT:
5349 {
5350 bytes_written = snprintf(command, total_len, "natoe max tbl entries: %d\n",
5351 dtoh32(*(uint32 *)data));
5352 cmd_info->bytes_written = bytes_written;
5353 break;
5354 }
5355
5356 default:
5357 /* ignore */
5358 break;
5359 }
5360
5361 return res;
5362 }
5363
5364 /*
5365 * --- common for all natoe get commands ----
5366 */
5367 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)5368 wl_natoe_get_ioctl(struct net_device *dev, wl_natoe_ioc_t *natoe_ioc,
5369 uint16 iocsz, uint8 *buf, uint16 buflen, wl_natoe_cmd_info_t *cmd_info)
5370 {
5371 /* for gets we only need to pass ioc header */
5372 wl_natoe_ioc_t *iocresp = (wl_natoe_ioc_t *)buf;
5373 int res;
5374
5375 /* send getbuf natoe iovar */
5376 res = wldev_iovar_getbuf(dev, "natoe", natoe_ioc, iocsz, buf,
5377 buflen, NULL);
5378
5379 /* check the response buff */
5380 if ((res == BCME_OK)) {
5381 /* scans ioctl tlvbuf f& invokes the cbfn for processing */
5382 res = bcm_unpack_xtlv_buf(cmd_info, iocresp->data, iocresp->len,
5383 BCM_XTLV_OPTION_ALIGN32, wlu_natoe_set_vars_cbfn);
5384
5385 if (res == BCME_OK) {
5386 res = cmd_info->bytes_written;
5387 }
5388 }
5389 else
5390 {
5391 ANDROID_ERROR(("wl_natoe_get_ioctl: get command failed code %d\n", res));
5392 res = BCME_ERROR;
5393 }
5394
5395 return res;
5396 }
5397
5398 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)5399 wl_android_natoe_subcmd_enable(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5400 char *command, wl_natoe_cmd_info_t *cmd_info)
5401 {
5402 int ret = BCME_OK;
5403 wl_natoe_ioc_t *natoe_ioc;
5404 char *pcmd = command;
5405 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5406 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5407 bcm_xtlv_t *pxtlv = NULL;
5408 char *ioctl_buf = NULL;
5409 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5410
5411 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5412 if (!ioctl_buf) {
5413 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5414 return -ENOMEM;
5415 }
5416
5417 /* alloc mem for ioctl headr + tlv data */
5418 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5419 if (!natoe_ioc) {
5420 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5421 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5422 return -ENOMEM;
5423 }
5424
5425 /* make up natoe cmd ioctl header */
5426 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5427 natoe_ioc->id = htod16(cmd->id);
5428 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5429 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5430
5431 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5432 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5433 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5434 WLC_IOCTL_MEDLEN, cmd_info);
5435 if (ret != BCME_OK) {
5436 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_enable\n"));
5437 ret = -EINVAL;
5438 }
5439 } else { /* set */
5440 uint8 val = bcm_atoi(pcmd);
5441
5442 /* buflen is max tlv data we can write, it will be decremented as we pack */
5443 /* save buflen at start */
5444 uint16 buflen_at_start = buflen;
5445
5446 /* we'll adjust final ioc size at the end */
5447 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5448 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5449
5450 if (ret != BCME_OK) {
5451 ret = -EINVAL;
5452 goto exit;
5453 }
5454
5455 /* adjust iocsz to the end of last data record */
5456 natoe_ioc->len = (buflen_at_start - buflen);
5457 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5458
5459 ret = wldev_iovar_setbuf(dev, "natoe",
5460 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5461 if (ret != BCME_OK) {
5462 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5463 ret = -EINVAL;
5464 }
5465 }
5466
5467 exit:
5468 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5469 MFREE(cfg->osh, natoe_ioc, iocsz);
5470
5471 return ret;
5472 }
5473
5474 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)5475 wl_android_natoe_subcmd_config_ips(struct net_device *dev,
5476 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5477 {
5478 int ret = BCME_OK;
5479 wl_natoe_config_ips_t config_ips;
5480 wl_natoe_ioc_t *natoe_ioc;
5481 char *pcmd = command;
5482 char *str;
5483 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5484 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5485 bcm_xtlv_t *pxtlv = NULL;
5486 char *ioctl_buf = NULL;
5487 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5488
5489 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5490 if (!ioctl_buf) {
5491 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5492 return -ENOMEM;
5493 }
5494
5495 /* alloc mem for ioctl headr + tlv data */
5496 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5497 if (!natoe_ioc) {
5498 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5499 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5500 return -ENOMEM;
5501 }
5502
5503 /* make up natoe cmd ioctl header */
5504 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5505 natoe_ioc->id = htod16(cmd->id);
5506 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5507 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5508
5509 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5510 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5511 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5512 WLC_IOCTL_MEDLEN, cmd_info);
5513 if (ret != BCME_OK) {
5514 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ips\n"));
5515 ret = -EINVAL;
5516 }
5517 } else { /* set */
5518 /* buflen is max tlv data we can write, it will be decremented as we pack */
5519 /* save buflen at start */
5520 uint16 buflen_at_start = buflen;
5521
5522 bzero(&config_ips, sizeof(config_ips));
5523
5524 str = bcmstrtok(&pcmd, " ", NULL);
5525 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.sta_ip)) {
5526 ANDROID_ERROR(("Invalid STA IP addr %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_netmask)) {
5533 ANDROID_ERROR(("Invalid STA netmask %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_router_ip)) {
5540 ANDROID_ERROR(("Invalid STA router 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.sta_dnsip)) {
5547 ANDROID_ERROR(("Invalid STA DNS 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_ip)) {
5554 ANDROID_ERROR(("Invalid AP IP addr %s\n", str));
5555 ret = -EINVAL;
5556 goto exit;
5557 }
5558
5559 str = bcmstrtok(&pcmd, " ", NULL);
5560 if (!str || !bcm_atoipv4(str, (struct ipv4_addr *)&config_ips.ap_netmask)) {
5561 ANDROID_ERROR(("Invalid AP netmask %s\n", str));
5562 ret = -EINVAL;
5563 goto exit;
5564 }
5565
5566 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5567 &buflen, WL_NATOE_XTLV_CONFIG_IPS, sizeof(config_ips),
5568 &config_ips, BCM_XTLV_OPTION_ALIGN32);
5569
5570 if (ret != BCME_OK) {
5571 ret = -EINVAL;
5572 goto exit;
5573 }
5574
5575 /* adjust iocsz to the end of last data record */
5576 natoe_ioc->len = (buflen_at_start - buflen);
5577 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5578
5579 ret = wldev_iovar_setbuf(dev, "natoe",
5580 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5581 if (ret != BCME_OK) {
5582 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5583 ret = -EINVAL;
5584 }
5585 }
5586
5587 exit:
5588 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5589 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5590
5591 return ret;
5592 }
5593
5594 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)5595 wl_android_natoe_subcmd_config_ports(struct net_device *dev,
5596 const wl_natoe_sub_cmd_t *cmd, char *command, wl_natoe_cmd_info_t *cmd_info)
5597 {
5598 int ret = BCME_OK;
5599 wl_natoe_ports_config_t ports_config;
5600 wl_natoe_ioc_t *natoe_ioc;
5601 char *pcmd = command;
5602 char *str;
5603 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5604 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5605 bcm_xtlv_t *pxtlv = NULL;
5606 char *ioctl_buf = NULL;
5607 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5608
5609 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5610 if (!ioctl_buf) {
5611 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5612 return -ENOMEM;
5613 }
5614
5615 /* alloc mem for ioctl headr + tlv data */
5616 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5617 if (!natoe_ioc) {
5618 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5619 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5620 return -ENOMEM;
5621 }
5622
5623 /* make up natoe cmd ioctl header */
5624 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5625 natoe_ioc->id = htod16(cmd->id);
5626 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5627 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5628
5629 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5630 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5631 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5632 WLC_IOCTL_MEDLEN, cmd_info);
5633 if (ret != BCME_OK) {
5634 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_config_ports\n"));
5635 ret = -EINVAL;
5636 }
5637 } else { /* set */
5638 /* buflen is max tlv data we can write, it will be decremented as we pack */
5639 /* save buflen at start */
5640 uint16 buflen_at_start = buflen;
5641
5642 bzero(&ports_config, sizeof(ports_config));
5643
5644 str = bcmstrtok(&pcmd, " ", NULL);
5645 if (!str) {
5646 ANDROID_ERROR(("Invalid port string %s\n", str));
5647 ret = -EINVAL;
5648 goto exit;
5649 }
5650 ports_config.start_port_num = htod16(bcm_atoi(str));
5651
5652 str = bcmstrtok(&pcmd, " ", NULL);
5653 if (!str) {
5654 ANDROID_ERROR(("Invalid port string %s\n", str));
5655 ret = -EINVAL;
5656 goto exit;
5657 }
5658 ports_config.no_of_ports = htod16(bcm_atoi(str));
5659
5660 if ((uint32)(ports_config.start_port_num + ports_config.no_of_ports) >
5661 NATOE_MAX_PORT_NUM) {
5662 ANDROID_ERROR(("Invalid port configuration\n"));
5663 ret = -EINVAL;
5664 goto exit;
5665 }
5666 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv,
5667 &buflen, WL_NATOE_XTLV_CONFIG_PORTS, sizeof(ports_config),
5668 &ports_config, BCM_XTLV_OPTION_ALIGN32);
5669
5670 if (ret != BCME_OK) {
5671 ret = -EINVAL;
5672 goto exit;
5673 }
5674
5675 /* adjust iocsz to the end of last data record */
5676 natoe_ioc->len = (buflen_at_start - buflen);
5677 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5678
5679 ret = wldev_iovar_setbuf(dev, "natoe",
5680 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5681 if (ret != BCME_OK) {
5682 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5683 ret = -EINVAL;
5684 }
5685 }
5686
5687 exit:
5688 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5689 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5690
5691 return ret;
5692 }
5693
5694 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)5695 wl_android_natoe_subcmd_dbg_stats(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5696 char *command, wl_natoe_cmd_info_t *cmd_info)
5697 {
5698 int ret = BCME_OK;
5699 wl_natoe_ioc_t *natoe_ioc;
5700 char *pcmd = command;
5701 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5702 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ;
5703 uint16 buflen = WL_NATOE_DBG_STATS_BUFSZ;
5704 bcm_xtlv_t *pxtlv = NULL;
5705 char *ioctl_buf = NULL;
5706 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5707
5708 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5709 if (!ioctl_buf) {
5710 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5711 return -ENOMEM;
5712 }
5713
5714 /* alloc mem for ioctl headr + tlv data */
5715 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5716 if (!natoe_ioc) {
5717 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5718 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5719 return -ENOMEM;
5720 }
5721
5722 /* make up natoe cmd ioctl header */
5723 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5724 natoe_ioc->id = htod16(cmd->id);
5725 natoe_ioc->len = htod16(WL_NATOE_DBG_STATS_BUFSZ);
5726 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5727
5728 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5729 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5730 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5731 WLC_IOCTL_MAXLEN, cmd_info);
5732 if (ret != BCME_OK) {
5733 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_dbg_stats\n"));
5734 ret = -EINVAL;
5735 }
5736 } else { /* set */
5737 uint8 val = bcm_atoi(pcmd);
5738
5739 /* buflen is max tlv data we can write, it will be decremented as we pack */
5740 /* save buflen at start */
5741 uint16 buflen_at_start = buflen;
5742
5743 /* we'll adjust final ioc size at the end */
5744 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_ENABLE,
5745 sizeof(uint8), &val, BCM_XTLV_OPTION_ALIGN32);
5746
5747 if (ret != BCME_OK) {
5748 ret = -EINVAL;
5749 goto exit;
5750 }
5751
5752 /* adjust iocsz to the end of last data record */
5753 natoe_ioc->len = (buflen_at_start - buflen);
5754 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5755
5756 ret = wldev_iovar_setbuf(dev, "natoe",
5757 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
5758 if (ret != BCME_OK) {
5759 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5760 ret = -EINVAL;
5761 }
5762 }
5763
5764 exit:
5765 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MAXLEN);
5766 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_DBG_STATS_BUFSZ);
5767
5768 return ret;
5769 }
5770
5771 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)5772 wl_android_natoe_subcmd_tbl_cnt(struct net_device *dev, const wl_natoe_sub_cmd_t *cmd,
5773 char *command, wl_natoe_cmd_info_t *cmd_info)
5774 {
5775 int ret = BCME_OK;
5776 wl_natoe_ioc_t *natoe_ioc;
5777 char *pcmd = command;
5778 uint16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5779 uint16 iocsz = sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ;
5780 uint16 buflen = WL_NATOE_IOC_BUFSZ;
5781 bcm_xtlv_t *pxtlv = NULL;
5782 char *ioctl_buf = NULL;
5783 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5784
5785 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5786 if (!ioctl_buf) {
5787 ANDROID_ERROR(("ioctl memory alloc failed\n"));
5788 return -ENOMEM;
5789 }
5790
5791 /* alloc mem for ioctl headr + tlv data */
5792 natoe_ioc = (wl_natoe_ioc_t *)MALLOCZ(cfg->osh, iocsz);
5793 if (!natoe_ioc) {
5794 ANDROID_ERROR(("ioctl header memory alloc failed\n"));
5795 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5796 return -ENOMEM;
5797 }
5798
5799 /* make up natoe cmd ioctl header */
5800 natoe_ioc->version = htod16(WL_NATOE_IOCTL_VERSION);
5801 natoe_ioc->id = htod16(cmd->id);
5802 natoe_ioc->len = htod16(WL_NATOE_IOC_BUFSZ);
5803 pxtlv = (bcm_xtlv_t *)natoe_ioc->data;
5804
5805 if(*pcmd == WL_IOCTL_ACTION_GET) { /* get */
5806 iocsz = sizeof(*natoe_ioc) + sizeof(*pxtlv);
5807 ret = wl_natoe_get_ioctl(dev, natoe_ioc, iocsz, ioctl_buf,
5808 WLC_IOCTL_MEDLEN, cmd_info);
5809 if (ret != BCME_OK) {
5810 ANDROID_ERROR(("Fail to get iovar wl_android_natoe_subcmd_tbl_cnt\n"));
5811 ret = -EINVAL;
5812 }
5813 } else { /* set */
5814 uint32 val = bcm_atoi(pcmd);
5815
5816 /* buflen is max tlv data we can write, it will be decremented as we pack */
5817 /* save buflen at start */
5818 uint16 buflen_at_start = buflen;
5819
5820 /* we'll adjust final ioc size at the end */
5821 ret = bcm_pack_xtlv_entry((uint8**)&pxtlv, &buflen, WL_NATOE_XTLV_TBL_CNT,
5822 sizeof(uint32), &val, BCM_XTLV_OPTION_ALIGN32);
5823
5824 if (ret != BCME_OK) {
5825 ret = -EINVAL;
5826 goto exit;
5827 }
5828
5829 /* adjust iocsz to the end of last data record */
5830 natoe_ioc->len = (buflen_at_start - buflen);
5831 iocsz = sizeof(*natoe_ioc) + natoe_ioc->len;
5832
5833 ret = wldev_iovar_setbuf(dev, "natoe",
5834 natoe_ioc, iocsz, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
5835 if (ret != BCME_OK) {
5836 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
5837 ret = -EINVAL;
5838 }
5839 }
5840
5841 exit:
5842 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
5843 MFREE(cfg->osh, natoe_ioc, sizeof(*natoe_ioc) + WL_NATOE_IOC_BUFSZ);
5844
5845 return ret;
5846 }
5847
5848 #endif /* WL_NATOE */
5849
5850 #ifdef WL_MBO
5851 static int
wl_android_process_mbo_cmd(struct net_device * dev,char * command,int total_len)5852 wl_android_process_mbo_cmd(struct net_device *dev, char *command, int total_len)
5853 {
5854 int ret = BCME_ERROR;
5855 char *pcmd = command;
5856 char *str = NULL;
5857 wl_drv_cmd_info_t cmd_info;
5858 const wl_drv_sub_cmd_t *mbo_cmd = &mbo_cmd_list[0];
5859
5860 /* skip to cmd name after "mbo" */
5861 str = bcmstrtok(&pcmd, " ", NULL);
5862
5863 /* If mbo subcmd name is not provided, return error */
5864 if (*pcmd == '\0') {
5865 ANDROID_ERROR(("mbo subcmd not provided %s\n", __FUNCTION__));
5866 ret = -EINVAL;
5867 return ret;
5868 }
5869
5870 /* get the mbo command name to str */
5871 str = bcmstrtok(&pcmd, " ", NULL);
5872
5873 while (mbo_cmd->name != NULL) {
5874 if (strnicmp(mbo_cmd->name, str, strlen(mbo_cmd->name)) == 0) {
5875 /* dispatch cmd to appropriate handler */
5876 if (mbo_cmd->handler) {
5877 cmd_info.command = command;
5878 cmd_info.tot_len = total_len;
5879 ret = mbo_cmd->handler(dev, mbo_cmd, pcmd, &cmd_info);
5880 }
5881 return ret;
5882 }
5883 mbo_cmd++;
5884 }
5885 return ret;
5886 }
5887
5888 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)5889 wl_android_send_wnm_notif(struct net_device *dev, bcm_iov_buf_t *iov_buf,
5890 uint16 iov_buf_len, uint8 *iov_resp, uint16 iov_resp_len, uint8 sub_elem_type)
5891 {
5892 int ret = BCME_OK;
5893 uint8 *pxtlv = NULL;
5894 uint16 iovlen = 0;
5895 uint16 buflen = 0, buflen_start = 0;
5896
5897 memset_s(iov_buf, iov_buf_len, 0, iov_buf_len);
5898 iov_buf->version = WL_MBO_IOV_VERSION;
5899 iov_buf->id = WL_MBO_CMD_SEND_NOTIF;
5900 buflen = buflen_start = iov_buf_len - sizeof(bcm_iov_buf_t);
5901 pxtlv = (uint8 *)&iov_buf->data[0];
5902 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_SUB_ELEM_TYPE,
5903 sizeof(sub_elem_type), &sub_elem_type, BCM_XTLV_OPTION_ALIGN32);
5904 if (ret != BCME_OK) {
5905 return ret;
5906 }
5907 iov_buf->len = buflen_start - buflen;
5908 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
5909 ret = wldev_iovar_setbuf(dev, "mbo",
5910 iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
5911 if (ret != BCME_OK) {
5912 ANDROID_ERROR(("Fail to sent wnm notif %d\n", ret));
5913 }
5914 return ret;
5915 }
5916
5917 static int
wl_android_mbo_resp_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)5918 wl_android_mbo_resp_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
5919 {
5920 wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
5921 uint8 *command = cmd_info->command;
5922 uint16 total_len = cmd_info->tot_len;
5923 uint16 bytes_written = 0;
5924
5925 UNUSED_PARAMETER(len);
5926 /* TODO: validate data value */
5927 if (data == NULL) {
5928 ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
5929 return -EINVAL;
5930 }
5931 switch (type) {
5932 case WL_MBO_XTLV_CELL_DATA_CAP:
5933 {
5934 bytes_written = snprintf(command, total_len, "cell_data_cap: %u\n", *data);
5935 cmd_info->bytes_written = bytes_written;
5936 }
5937 break;
5938 default:
5939 ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
5940 }
5941 return BCME_OK;
5942 }
5943
5944 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)5945 wl_android_mbo_subcmd_cell_data_cap(struct net_device *dev, const wl_drv_sub_cmd_t *cmd,
5946 char *command, wl_drv_cmd_info_t *cmd_info)
5947 {
5948 int ret = BCME_OK;
5949 uint8 *pxtlv = NULL;
5950 uint16 buflen = 0, buflen_start = 0;
5951 uint16 iovlen = 0;
5952 char *pcmd = command;
5953 bcm_iov_buf_t *iov_buf = NULL;
5954 bcm_iov_buf_t *p_resp = NULL;
5955 uint8 *iov_resp = NULL;
5956 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
5957 uint16 version;
5958
5959 /* first get the configured value */
5960 iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
5961 if (iov_buf == NULL) {
5962 ret = -ENOMEM;
5963 ANDROID_ERROR(("iov buf memory alloc exited\n"));
5964 goto exit;
5965 }
5966 iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
5967 if (iov_resp == NULL) {
5968 ret = -ENOMEM;
5969 ANDROID_ERROR(("iov resp memory alloc exited\n"));
5970 goto exit;
5971 }
5972
5973 /* fill header */
5974 iov_buf->version = WL_MBO_IOV_VERSION;
5975 iov_buf->id = WL_MBO_CMD_CELLULAR_DATA_CAP;
5976
5977 ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
5978 WLC_IOCTL_MAXLEN,
5979 NULL);
5980 if (ret != BCME_OK) {
5981 goto exit;
5982 }
5983 p_resp = (bcm_iov_buf_t *)iov_resp;
5984
5985 /* get */
5986 if (*pcmd == WL_IOCTL_ACTION_GET) {
5987 /* Check for version */
5988 version = dtoh16(*(uint16 *)iov_resp);
5989 if (version != WL_MBO_IOV_VERSION) {
5990 ret = -EINVAL;
5991 }
5992 if (p_resp->id == WL_MBO_CMD_CELLULAR_DATA_CAP) {
5993 ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
5994 p_resp->len, BCM_XTLV_OPTION_ALIGN32,
5995 wl_android_mbo_resp_parse_cbfn);
5996 if (ret == BCME_OK) {
5997 ret = cmd_info->bytes_written;
5998 }
5999 } else {
6000 ret = -EINVAL;
6001 ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
6002 goto exit;
6003 }
6004 } else {
6005 uint8 cell_cap = bcm_atoi(pcmd);
6006 const uint8* old_cell_cap = NULL;
6007 uint16 len = 0;
6008
6009 old_cell_cap = bcm_get_data_from_xtlv_buf((uint8 *)p_resp->data, p_resp->len,
6010 WL_MBO_XTLV_CELL_DATA_CAP, &len, BCM_XTLV_OPTION_ALIGN32);
6011 if (old_cell_cap && *old_cell_cap == cell_cap) {
6012 ANDROID_ERROR(("No change is cellular data capability\n"));
6013 /* No change in value */
6014 goto exit;
6015 }
6016
6017 buflen = buflen_start = WLC_IOCTL_MEDLEN - sizeof(bcm_iov_buf_t);
6018
6019 if (cell_cap < MBO_CELL_DATA_CONN_AVAILABLE ||
6020 cell_cap > MBO_CELL_DATA_CONN_NOT_CAPABLE) {
6021 ANDROID_ERROR(("wrong value %u\n", cell_cap));
6022 ret = -EINVAL;
6023 goto exit;
6024 }
6025 pxtlv = (uint8 *)&iov_buf->data[0];
6026 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CELL_DATA_CAP,
6027 sizeof(cell_cap), &cell_cap, BCM_XTLV_OPTION_ALIGN32);
6028 if (ret != BCME_OK) {
6029 goto exit;
6030 }
6031 iov_buf->len = buflen_start - buflen;
6032 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6033 ret = wldev_iovar_setbuf(dev, "mbo",
6034 iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6035 if (ret != BCME_OK) {
6036 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6037 ret = -EINVAL;
6038 goto exit;
6039 }
6040 /* Skip for CUSTOMER_HW4 - WNM notification
6041 * for cellular data capability is handled by host
6042 */
6043 #if !defined(CUSTOMER_HW4)
6044 /* send a WNM notification request to associated AP */
6045 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6046 ANDROID_INFO(("Sending WNM Notif\n"));
6047 ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6048 iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_CELL_DATA_CAP);
6049 if (ret != BCME_OK) {
6050 ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6051 ret = -EINVAL;
6052 }
6053 }
6054 #endif /* CUSTOMER_HW4 */
6055 }
6056 exit:
6057 if (iov_buf) {
6058 MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6059 }
6060 if (iov_resp) {
6061 MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6062 }
6063 return ret;
6064 }
6065
6066 static int
wl_android_mbo_non_pref_chan_parse_cbfn(void * ctx,const uint8 * data,uint16 type,uint16 len)6067 wl_android_mbo_non_pref_chan_parse_cbfn(void *ctx, const uint8 *data, uint16 type, uint16 len)
6068 {
6069 wl_drv_cmd_info_t *cmd_info = (wl_drv_cmd_info_t *)ctx;
6070 uint8 *command = cmd_info->command + cmd_info->bytes_written;
6071 uint16 total_len = cmd_info->tot_len;
6072 uint16 bytes_written = 0;
6073
6074 ANDROID_INFO(("Total bytes written at begining %u\n", cmd_info->bytes_written));
6075 UNUSED_PARAMETER(len);
6076 if (data == NULL) {
6077 ANDROID_ERROR(("%s: Bad argument !!\n", __FUNCTION__));
6078 return -EINVAL;
6079 }
6080 switch (type) {
6081 case WL_MBO_XTLV_OPCLASS:
6082 {
6083 bytes_written = snprintf(command, total_len, "%u:", *data);
6084 ANDROID_ERROR(("wr %u %u\n", bytes_written, *data));
6085 command += bytes_written;
6086 cmd_info->bytes_written += bytes_written;
6087 }
6088 break;
6089 case WL_MBO_XTLV_CHAN:
6090 {
6091 bytes_written = snprintf(command, total_len, "%u:", *data);
6092 ANDROID_ERROR(("wr %u\n", bytes_written));
6093 command += bytes_written;
6094 cmd_info->bytes_written += bytes_written;
6095 }
6096 break;
6097 case WL_MBO_XTLV_PREFERENCE:
6098 {
6099 bytes_written = snprintf(command, total_len, "%u:", *data);
6100 ANDROID_ERROR(("wr %u\n", bytes_written));
6101 command += bytes_written;
6102 cmd_info->bytes_written += bytes_written;
6103 }
6104 break;
6105 case WL_MBO_XTLV_REASON_CODE:
6106 {
6107 bytes_written = snprintf(command, total_len, "%u ", *data);
6108 ANDROID_ERROR(("wr %u\n", bytes_written));
6109 command += bytes_written;
6110 cmd_info->bytes_written += bytes_written;
6111 }
6112 break;
6113 default:
6114 ANDROID_ERROR(("%s: Unknown tlv %u\n", __FUNCTION__, type));
6115 }
6116 ANDROID_INFO(("Total bytes written %u\n", cmd_info->bytes_written));
6117 return BCME_OK;
6118 }
6119
6120 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)6121 wl_android_mbo_subcmd_non_pref_chan(struct net_device *dev,
6122 const wl_drv_sub_cmd_t *cmd, char *command,
6123 wl_drv_cmd_info_t *cmd_info)
6124 {
6125 int ret = BCME_OK;
6126 uint8 *pxtlv = NULL;
6127 uint16 buflen = 0, buflen_start = 0;
6128 uint16 iovlen = 0;
6129 char *pcmd = command;
6130 bcm_iov_buf_t *iov_buf = NULL;
6131 bcm_iov_buf_t *p_resp = NULL;
6132 uint8 *iov_resp = NULL;
6133 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6134 uint16 version;
6135
6136 ANDROID_ERROR(("%s:%d\n", __FUNCTION__, __LINE__));
6137 iov_buf = (bcm_iov_buf_t *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
6138 if (iov_buf == NULL) {
6139 ret = -ENOMEM;
6140 ANDROID_ERROR(("iov buf memory alloc exited\n"));
6141 goto exit;
6142 }
6143 iov_resp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6144 if (iov_resp == NULL) {
6145 ret = -ENOMEM;
6146 ANDROID_ERROR(("iov resp memory alloc exited\n"));
6147 goto exit;
6148 }
6149 /* get */
6150 if (*pcmd == WL_IOCTL_ACTION_GET) {
6151 /* fill header */
6152 iov_buf->version = WL_MBO_IOV_VERSION;
6153 iov_buf->id = WL_MBO_CMD_LIST_CHAN_PREF;
6154
6155 ret = wldev_iovar_getbuf(dev, "mbo", iov_buf, WLC_IOCTL_MEDLEN, iov_resp,
6156 WLC_IOCTL_MAXLEN, NULL);
6157 if (ret != BCME_OK) {
6158 goto exit;
6159 }
6160 p_resp = (bcm_iov_buf_t *)iov_resp;
6161 /* Check for version */
6162 version = dtoh16(*(uint16 *)iov_resp);
6163 if (version != WL_MBO_IOV_VERSION) {
6164 ANDROID_ERROR(("Version mismatch. returned ver %u expected %u\n",
6165 version, WL_MBO_IOV_VERSION));
6166 ret = -EINVAL;
6167 }
6168 if (p_resp->id == WL_MBO_CMD_LIST_CHAN_PREF) {
6169 ret = bcm_unpack_xtlv_buf((void *)cmd_info, (uint8 *)p_resp->data,
6170 p_resp->len, BCM_XTLV_OPTION_ALIGN32,
6171 wl_android_mbo_non_pref_chan_parse_cbfn);
6172 if (ret == BCME_OK) {
6173 ret = cmd_info->bytes_written;
6174 }
6175 } else {
6176 ret = -EINVAL;
6177 ANDROID_ERROR(("Mismatch: resp id %d req id %d\n", p_resp->id, cmd->id));
6178 goto exit;
6179 }
6180 } else {
6181 char *str = pcmd;
6182 uint opcl = 0, ch = 0, pref = 0, rc = 0;
6183
6184 str = bcmstrtok(&pcmd, " ", NULL);
6185 if (!(strnicmp(str, "set", 3)) || (!strnicmp(str, "clear", 5))) {
6186 /* delete all configurations */
6187 iov_buf->version = WL_MBO_IOV_VERSION;
6188 iov_buf->id = WL_MBO_CMD_DEL_CHAN_PREF;
6189 iov_buf->len = 0;
6190 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6191 ret = wldev_iovar_setbuf(dev, "mbo",
6192 iov_buf, iovlen, iov_resp, WLC_IOCTL_MAXLEN, NULL);
6193 if (ret != BCME_OK) {
6194 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6195 ret = -EINVAL;
6196 goto exit;
6197 }
6198 } else {
6199 ANDROID_ERROR(("Unknown command %s\n", str));
6200 goto exit;
6201 }
6202 /* parse non pref channel list */
6203 if (strnicmp(str, "set", 3) == 0) {
6204 uint8 cnt = 0;
6205 str = bcmstrtok(&pcmd, " ", NULL);
6206 while (str != NULL) {
6207 ret = sscanf(str, "%u:%u:%u:%u", &opcl, &ch, &pref, &rc);
6208 ANDROID_ERROR(("buflen %u op %u, ch %u, pref %u rc %u\n",
6209 buflen, opcl, ch, pref, rc));
6210 if (ret != 4) {
6211 ANDROID_ERROR(("Not all parameter presents\n"));
6212 ret = -EINVAL;
6213 }
6214 /* TODO: add a validation check here */
6215 memset_s(iov_buf, WLC_IOCTL_MEDLEN, 0, WLC_IOCTL_MEDLEN);
6216 buflen = buflen_start = WLC_IOCTL_MEDLEN;
6217 pxtlv = (uint8 *)&iov_buf->data[0];
6218 /* opclass */
6219 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_OPCLASS,
6220 sizeof(uint8), (uint8 *)&opcl, BCM_XTLV_OPTION_ALIGN32);
6221 if (ret != BCME_OK) {
6222 goto exit;
6223 }
6224 /* channel */
6225 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_CHAN,
6226 sizeof(uint8), (uint8 *)&ch, BCM_XTLV_OPTION_ALIGN32);
6227 if (ret != BCME_OK) {
6228 goto exit;
6229 }
6230 /* preference */
6231 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_PREFERENCE,
6232 sizeof(uint8), (uint8 *)&pref, BCM_XTLV_OPTION_ALIGN32);
6233 if (ret != BCME_OK) {
6234 goto exit;
6235 }
6236 /* reason */
6237 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_MBO_XTLV_REASON_CODE,
6238 sizeof(uint8), (uint8 *)&rc, BCM_XTLV_OPTION_ALIGN32);
6239 if (ret != BCME_OK) {
6240 goto exit;
6241 }
6242 ANDROID_ERROR(("len %u\n", (buflen_start - buflen)));
6243 /* Now set the new non pref channels */
6244 iov_buf->version = WL_MBO_IOV_VERSION;
6245 iov_buf->id = WL_MBO_CMD_ADD_CHAN_PREF;
6246 iov_buf->len = buflen_start - buflen;
6247 iovlen = sizeof(bcm_iov_buf_t) + iov_buf->len;
6248 ret = wldev_iovar_setbuf(dev, "mbo",
6249 iov_buf, iovlen, iov_resp, WLC_IOCTL_MEDLEN, NULL);
6250 if (ret != BCME_OK) {
6251 ANDROID_ERROR(("Fail to set iovar %d\n", ret));
6252 ret = -EINVAL;
6253 goto exit;
6254 }
6255 cnt++;
6256 if (cnt >= MBO_MAX_CHAN_PREF_ENTRIES) {
6257 break;
6258 }
6259 ANDROID_ERROR(("%d cnt %u\n", __LINE__, cnt));
6260 str = bcmstrtok(&pcmd, " ", NULL);
6261 }
6262 }
6263 /* send a WNM notification request to associated AP */
6264 if (wl_get_drv_status(cfg, CONNECTED, dev)) {
6265 ANDROID_INFO(("Sending WNM Notif\n"));
6266 ret = wl_android_send_wnm_notif(dev, iov_buf, WLC_IOCTL_MEDLEN,
6267 iov_resp, WLC_IOCTL_MAXLEN, MBO_ATTR_NON_PREF_CHAN_REPORT);
6268 if (ret != BCME_OK) {
6269 ANDROID_ERROR(("Fail to send WNM notification %d\n", ret));
6270 ret = -EINVAL;
6271 }
6272 }
6273 }
6274 exit:
6275 if (iov_buf) {
6276 MFREE(cfg->osh, iov_buf, WLC_IOCTL_MEDLEN);
6277 }
6278 if (iov_resp) {
6279 MFREE(cfg->osh, iov_resp, WLC_IOCTL_MAXLEN);
6280 }
6281 return ret;
6282 }
6283 #endif /* WL_MBO */
6284
6285 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6286 #ifdef SUPPORT_AMPDU_MPDU_CMD
6287 /* CMD_AMPDU_MPDU */
6288 static int
wl_android_set_ampdu_mpdu(struct net_device * dev,const char * string_num)6289 wl_android_set_ampdu_mpdu(struct net_device *dev, const char* string_num)
6290 {
6291 int err = 0;
6292 int ampdu_mpdu;
6293
6294 ampdu_mpdu = bcm_atoi(string_num);
6295
6296 if (ampdu_mpdu > 32) {
6297 ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu MAX value is 32.\n"));
6298 return -1;
6299 }
6300
6301 ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu = %d\n", ampdu_mpdu));
6302 err = wldev_iovar_setint(dev, "ampdu_mpdu", ampdu_mpdu);
6303 if (err < 0) {
6304 ANDROID_ERROR(("wl_android_set_ampdu_mpdu : ampdu_mpdu set error. %d\n", err));
6305 return -1;
6306 }
6307
6308 return 0;
6309 }
6310 #endif /* SUPPORT_AMPDU_MPDU_CMD */
6311 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
6312
6313 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6314 extern int wl_cfg80211_send_msg_to_ril(void);
6315 extern void wl_cfg80211_register_dev_ril_bridge_event_notifier(void);
6316 extern void wl_cfg80211_unregister_dev_ril_bridge_event_notifier(void);
6317 extern int g_mhs_chan_for_cpcoex;
6318 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6319
6320 #if defined (WL_SUPPORT_AUTO_CHANNEL)
6321 static s32
wl_android_set_auto_channel_scan_state(struct net_device * ndev)6322 wl_android_set_auto_channel_scan_state(struct net_device *ndev)
6323 {
6324 u32 val = 0;
6325 s32 ret = BCME_ERROR;
6326 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6327 /* Set interface up, explicitly. */
6328 val = 1;
6329
6330 ret = wldev_ioctl_set(ndev, WLC_UP, (void *)&val, sizeof(val));
6331 if (ret < 0) {
6332 ANDROID_ERROR(("set interface up failed, error = %d\n", ret));
6333 goto done;
6334 }
6335
6336 /* Stop all scan explicitly, till auto channel selection complete. */
6337 wl_set_drv_status(cfg, SCANNING, ndev);
6338 if (cfg->escan_info.ndev == NULL) {
6339 ret = BCME_OK;
6340 goto done;
6341 }
6342
6343 wl_cfgscan_cancel_scan(cfg);
6344
6345 done:
6346 return ret;
6347 }
6348
6349 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)6350 wl_android_get_freq_list_chanspecs(struct net_device *ndev, wl_uint32_list_t *list,
6351 s32 buflen, const char* cmd_str, int sta_channel, chanspec_band_t sta_acs_band)
6352 {
6353 u32 freq = 0;
6354 chanspec_t chanspec = 0;
6355 s32 ret = BCME_OK;
6356 int i = 0;
6357 char *pcmd, *token;
6358 int len = buflen;
6359
6360 pcmd = bcmstrstr(cmd_str, FREQ_STR);
6361 pcmd += strlen(FREQ_STR);
6362
6363 len -= sizeof(list->count);
6364
6365 while ((token = strsep(&pcmd, ",")) != NULL) {
6366 if (*token == '\0')
6367 continue;
6368
6369 if (len < sizeof(list->element[i]))
6370 break;
6371
6372 freq = bcm_atoi(token);
6373 /* Convert chanspec from frequency */
6374 if ((freq > 0) &&
6375 ((chanspec = wl_freq_to_chanspec(freq)) != INVCHANSPEC)) {
6376 ANDROID_INFO(("Adding chanspec in list : 0x%x at the index %d\n", chanspec, i));
6377 list->element[i] = chanspec;
6378 len -= sizeof(list->element[i]);
6379 i++;
6380 #ifdef WL_5G_SOFTAP_ONLY_ON_DEF_CHAN
6381 /* Android includes 2g channels even for 5g band configuration. For
6382 * customers using only single channel 5G AP, set the channel and
6383 * return without doing ACS
6384 */
6385 if (CHSPEC_BAND(chanspec) == WL_CHANSPEC_BAND_5G) {
6386 ANDROID_INFO(("Pick default channnel from 5g\n"));
6387 if (!sta_channel) {
6388 list->element[0] = chanspec;
6389 list->count = 1;
6390 return ret;
6391 }
6392 break;
6393 }
6394 #endif /* WL_5G_SOFTAP_ONLY_ON_DEF_CHAN */
6395 }
6396 }
6397
6398 list->count = i;
6399 /* valid chanspec present in the list */
6400 if (list->count && sta_channel) {
6401 /* STA associated case. Can't do ACS.
6402 * Frequency list is order of lower to higher band.
6403 * check with the highest band entry.
6404 */
6405 chanspec = list->element[i-1];
6406 if (CHSPEC_BAND(chanspec) == sta_acs_band) {
6407 /* softap request is for same band. Use SCC
6408 * Convert sta channel to freq
6409 */
6410 freq = wl_channel_to_frequency(sta_channel, sta_acs_band);
6411 list->element[0] =
6412 wl_freq_to_chanspec(freq);
6413 ANDROID_INFO(("Softap on same band as STA."
6414 "Use SCC. chanspec:0x%x\n", chanspec));
6415 } else {
6416 list->element[0] = chanspec;
6417 ANDROID_INFO(("RSDB case chanspec:0x%x\n", chanspec));
6418 }
6419 list->count = 1;
6420 return ret;
6421 }
6422 return ret;
6423 }
6424
6425 s32
wl_android_get_band_chanspecs(struct net_device * ndev,void * buf,s32 buflen,chanspec_band_t band,bool acs_req)6426 wl_android_get_band_chanspecs(struct net_device *ndev, void *buf, s32 buflen,
6427 chanspec_band_t band, bool acs_req)
6428 {
6429 u32 channel = 0;
6430 s32 ret = BCME_ERROR;
6431 s32 i = 0;
6432 s32 j = 0;
6433 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6434 wl_uint32_list_t *list = NULL;
6435 chanspec_t chanspec = 0;
6436
6437 if (band != 0xff) {
6438 chanspec |= (band | WL_CHANSPEC_BW_20 |
6439 WL_CHANSPEC_CTL_SB_NONE);
6440 chanspec = wl_chspec_host_to_driver(chanspec);
6441 }
6442
6443 ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
6444 sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
6445 if (ret < 0) {
6446 ANDROID_ERROR(("get 'chanspecs' failed, error = %d\n", ret));
6447 goto done;
6448 }
6449
6450 list = (wl_uint32_list_t *)buf;
6451 /* Skip DFS and inavlid P2P channel. */
6452 for (i = 0, j = 0; i < dtoh32(list->count); i++) {
6453 if (!CHSPEC_IS20(list->element[i])) {
6454 continue;
6455 }
6456 chanspec = (chanspec_t) dtoh32(list->element[i]);
6457 channel = chanspec | WL_CHANSPEC_BW_20;
6458 channel = wl_chspec_host_to_driver(channel);
6459
6460 ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
6461 if (ret < 0) {
6462 ANDROID_ERROR(("get 'per_chan_info' failed, error = %d\n", ret));
6463 goto done;
6464 }
6465
6466 if (CHSPEC_IS5G(chanspec) && (CHANNEL_IS_RADAR(channel) ||
6467 #ifndef ALLOW_5G_ACS
6468 ((acs_req == true) && (CHSPEC_CHANNEL(chanspec) != APCS_DEFAULT_5G_CH)) ||
6469 #endif /* !ALLOW_5G_ACS */
6470 (0))) {
6471 continue;
6472 } else if (!(CHSPEC_IS2G(chanspec) || CHSPEC_IS5G(chanspec)) &&
6473 !(CHSPEC_IS_6G_PSC(chanspec))) {
6474 continue;
6475 }
6476 else {
6477 list->element[j] = list->element[i];
6478 ANDROID_INFO(("Adding chanspec in list : %x\n", list->element[j]));
6479 }
6480
6481 j++;
6482 }
6483
6484 list->count = j;
6485
6486 done:
6487 return ret;
6488 }
6489
6490 static s32
wl_android_get_best_channel(struct net_device * ndev,void * buf,int buflen,int * channel)6491 wl_android_get_best_channel(struct net_device *ndev, void *buf, int buflen,
6492 int *channel)
6493 {
6494 s32 ret = BCME_ERROR;
6495 int chosen = 0;
6496 int retry = 0;
6497
6498 /* Start auto channel selection scan. */
6499 ret = wldev_ioctl_set(ndev, WLC_START_CHANNEL_SEL, NULL, 0);
6500 if (ret < 0) {
6501 ANDROID_ERROR(("can't start auto channel scan, error = %d\n", ret));
6502 *channel = 0;
6503 goto done;
6504 }
6505
6506 /* Wait for auto channel selection, worst case possible delay is 5250ms. */
6507 retry = CHAN_SEL_RETRY_COUNT;
6508
6509 while (retry--) {
6510 OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
6511 chosen = 0;
6512 ret = wldev_ioctl_get(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6513 if ((ret == 0) && (dtoh32(chosen) != 0)) {
6514 *channel = (u16)(chosen & 0x00FF);
6515 ANDROID_INFO(("selected channel = %d\n", *channel));
6516 break;
6517 }
6518 ANDROID_INFO(("attempt = %d, ret = %d, chosen = %d\n",
6519 (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
6520 }
6521
6522 if (retry <= 0) {
6523 ANDROID_ERROR(("failure, auto channel selection timed out\n"));
6524 *channel = 0;
6525 ret = BCME_ERROR;
6526 }
6527
6528 done:
6529 return ret;
6530 }
6531
6532 static s32
wl_android_restore_auto_channel_scan_state(struct net_device * ndev)6533 wl_android_restore_auto_channel_scan_state(struct net_device *ndev)
6534 {
6535 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
6536 /* Clear scan stop driver status. */
6537 wl_clr_drv_status(cfg, SCANNING, ndev);
6538
6539 return BCME_OK;
6540 }
6541
6542 s32
wl_android_get_best_channels(struct net_device * dev,char * cmd,int total_len)6543 wl_android_get_best_channels(struct net_device *dev, char* cmd, int total_len)
6544 {
6545 int channel = 0;
6546 s32 ret = BCME_ERROR;
6547 u8 *buf = NULL;
6548 char *pos = cmd;
6549 struct bcm_cfg80211 *cfg = NULL;
6550 struct net_device *ndev = NULL;
6551
6552 bzero(cmd, total_len);
6553 cfg = wl_get_cfg(dev);
6554
6555 buf = (u8 *)MALLOC(cfg->osh, CHANSPEC_BUF_SIZE);
6556 if (buf == NULL) {
6557 ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6558 return -ENOMEM;
6559 }
6560
6561 /*
6562 * Always use primary interface, irrespective of interface on which
6563 * command came.
6564 */
6565 ndev = bcmcfg_to_prmry_ndev(cfg);
6566
6567 /*
6568 * Make sure that FW and driver are in right state to do auto channel
6569 * selection scan.
6570 */
6571 ret = wl_android_set_auto_channel_scan_state(ndev);
6572 if (ret < 0) {
6573 ANDROID_ERROR(("can't set auto channel scan state, error = %d\n", ret));
6574 goto done;
6575 }
6576
6577 /* Best channel selection in 2.4GHz band. */
6578 ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6579 WL_CHANSPEC_BAND_2G, false);
6580 if (ret < 0) {
6581 ANDROID_ERROR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
6582 goto done;
6583 }
6584
6585 ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6586 &channel);
6587 if (ret < 0) {
6588 ANDROID_ERROR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
6589 goto done;
6590 }
6591
6592 if (CHANNEL_IS_2G(channel)) {
6593 channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
6594 } else {
6595 ANDROID_ERROR(("invalid 2.4GHz channel, channel = %d\n", channel));
6596 channel = 0;
6597 }
6598
6599 pos += snprintf(pos, total_len, "%04d ", channel);
6600
6601 /* Best channel selection in 5GHz band. */
6602 ret = wl_android_get_band_chanspecs(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6603 WL_CHANSPEC_BAND_5G, false);
6604 if (ret < 0) {
6605 ANDROID_ERROR(("can't get chanspecs in 5GHz, error = %d\n", ret));
6606 goto done;
6607 }
6608
6609 ret = wl_android_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
6610 &channel);
6611 if (ret < 0) {
6612 ANDROID_ERROR(("can't select best channel scan in 5GHz, error = %d\n", ret));
6613 goto done;
6614 }
6615
6616 if (CHANNEL_IS_5G(channel)) {
6617 channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
6618 } else {
6619 ANDROID_ERROR(("invalid 5GHz channel, channel = %d\n", channel));
6620 channel = 0;
6621 }
6622
6623 pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6624
6625 /* Set overall best channel same as 5GHz best channel. */
6626 pos += snprintf(pos, total_len - (pos - cmd), "%04d ", channel);
6627
6628 done:
6629 if (NULL != buf) {
6630 MFREE(cfg->osh, buf, CHANSPEC_BUF_SIZE);
6631 }
6632
6633 /* Restore FW and driver back to normal state. */
6634 ret = wl_android_restore_auto_channel_scan_state(ndev);
6635 if (ret < 0) {
6636 ANDROID_ERROR(("can't restore auto channel scan state, error = %d\n", ret));
6637 }
6638
6639 return (pos - cmd);
6640 }
6641
6642 int
wl_android_set_spect(struct net_device * dev,int spect)6643 wl_android_set_spect(struct net_device *dev, int spect)
6644 {
6645 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6646 int wlc_down = 1;
6647 int wlc_up = 1;
6648 int err = BCME_OK;
6649
6650 if (!wl_get_drv_status_all(cfg, CONNECTED)) {
6651 err = wldev_ioctl_set(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down));
6652 if (err) {
6653 ANDROID_ERROR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
6654 return err;
6655 }
6656
6657 err = wldev_ioctl_set(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect));
6658 if (err) {
6659 ANDROID_ERROR(("%s: error setting spect: code: %d\n", __func__, err));
6660 return err;
6661 }
6662
6663 err = wldev_ioctl_set(dev, WLC_UP, &wlc_up, sizeof(wlc_up));
6664 if (err) {
6665 ANDROID_ERROR(("%s: WLC_UP failed: code: %d\n", __func__, err));
6666 return err;
6667 }
6668 }
6669 return err;
6670 }
6671
6672 static int
wl_android_get_sta_channel(struct bcm_cfg80211 * cfg)6673 wl_android_get_sta_channel(struct bcm_cfg80211 *cfg)
6674 {
6675 chanspec_t *sta_chanspec = NULL;
6676 u32 channel = 0;
6677
6678 if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg))) {
6679 if ((sta_chanspec = (chanspec_t *)wl_read_prof(cfg,
6680 bcmcfg_to_prmry_ndev(cfg), WL_PROF_CHAN))) {
6681 channel = wf_chspec_ctlchan(*sta_chanspec);
6682 }
6683 }
6684 return channel;
6685 }
6686
6687 static int
wl_cfg80211_get_acs_band(int band)6688 wl_cfg80211_get_acs_band(int band)
6689 {
6690 chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6691 switch (band) {
6692 case WLC_BAND_AUTO:
6693 ANDROID_INFO(("ACS full channel scan \n"));
6694 /* Restricting band to 2G in case of hw_mode any */
6695 acs_band = WL_CHANSPEC_BAND_2G;
6696 break;
6697 #ifdef WL_6G_BAND
6698 case WLC_BAND_6G:
6699 ANDROID_INFO(("ACS 6G band scan \n"));
6700 acs_band = WL_CHANSPEC_BAND_6G;
6701 break;
6702 #endif /* WL_6G_BAND */
6703 case WLC_BAND_5G:
6704 ANDROID_INFO(("ACS 5G band scan \n"));
6705 acs_band = WL_CHANSPEC_BAND_5G;
6706 break;
6707 case WLC_BAND_2G:
6708 /*
6709 * If channel argument is not provided/ argument 20 is provided,
6710 * Restrict channel to 2GHz, 20MHz BW, No SB
6711 */
6712 ANDROID_INFO(("ACS 2G band scan \n"));
6713 acs_band = WL_CHANSPEC_BAND_2G;
6714 break;
6715 default:
6716 ANDROID_ERROR(("ACS: No band chosen\n"));
6717 break;
6718 }
6719 ANDROID_INFO(("%s: ACS: band = %d, acs_band = 0x%x\n", __FUNCTION__, band, acs_band));
6720 return acs_band;
6721 }
6722
6723 /* SoftAP feature */
6724 static int
wl_android_set_auto_channel(struct net_device * dev,const char * cmd_str,char * command,int total_len)6725 wl_android_set_auto_channel(struct net_device *dev, const char* cmd_str,
6726 char* command, int total_len)
6727 {
6728 int channel = 0, sta_channel = 0;
6729 int chosen = 0;
6730 int retry = 0;
6731 int ret = 0;
6732 int spect = 0;
6733 u8 *reqbuf = NULL;
6734 uint32 band = WLC_BAND_INVALID, sta_band = WLC_BAND_INVALID;
6735 chanspec_band_t acs_band = WLC_ACS_BAND_INVALID;
6736 uint32 buf_size;
6737 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6738 bool acs_freq_list_present = false;
6739 char *pcmd;
6740
6741 if (cmd_str) {
6742 ANDROID_INFO(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
6743 pcmd = bcmstrstr(cmd_str, FREQ_STR);
6744 if (pcmd) {
6745 acs_freq_list_present = true;
6746 ANDROID_INFO(("ACS has freq list\n"));
6747 } else if (strnicmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
6748 band = WLC_BAND_AUTO;
6749 #ifdef WL_6G_BAND
6750 } else if (strnicmp(cmd_str, APCS_BAND_6G, strlen(APCS_BAND_6G)) == 0) {
6751 band = WLC_BAND_6G;
6752 #endif /* WL_6G_BAND */
6753 } else if (strnicmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
6754 band = WLC_BAND_5G;
6755 } else if (strnicmp(cmd_str, APCS_BAND_2G, strlen(APCS_BAND_2G)) == 0) {
6756 band = WLC_BAND_2G;
6757 } else {
6758 /*
6759 * For backward compatibility: Some platforms used to issue argument 20 or 0
6760 * to enforce the 2G channel selection
6761 */
6762 channel = bcm_atoi(cmd_str);
6763 if ((channel == APCS_BAND_2G_LEGACY1) ||
6764 (channel == APCS_BAND_2G_LEGACY2)) {
6765 band = WLC_BAND_2G;
6766 } else {
6767 ANDROID_ERROR(("Invalid argument\n"));
6768 return -EINVAL;
6769 }
6770 }
6771 } else {
6772 /* If no argument is provided, default to 2G */
6773 ANDROID_ERROR(("No argument given default to 2.4G scan\n"));
6774 band = WLC_BAND_2G;
6775 }
6776 ANDROID_INFO(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
6777
6778 #if defined(CONFIG_WLAN_BEYONDX) || defined(CONFIG_SEC_5GMODEL)
6779 wl_cfg80211_register_dev_ril_bridge_event_notifier();
6780 if (band == WLC_BAND_2G) {
6781 wl_cfg80211_send_msg_to_ril();
6782
6783 if (g_mhs_chan_for_cpcoex) {
6784 channel = g_mhs_chan_for_cpcoex;
6785 g_mhs_chan_for_cpcoex = 0;
6786 goto done2;
6787 }
6788 }
6789 wl_cfg80211_unregister_dev_ril_bridge_event_notifier();
6790 #endif /* CONFIG_WLAN_BEYONDX || defined(CONFIG_SEC_5GMODEL) */
6791
6792 /* If STA is connected, return is STA channel, else ACS can be issued,
6793 * set spect to 0 and proceed with ACS
6794 */
6795 sta_channel = wl_android_get_sta_channel(cfg);
6796 sta_band = WL_GET_BAND(sta_channel);
6797 if (sta_channel && (band != WLC_BAND_INVALID)) {
6798 switch (sta_band) {
6799 case (WLC_BAND_5G):
6800 #ifdef WL_6G_BAND
6801 case (WLC_BAND_6G):
6802 #endif /* WL_6G_BAND */
6803 {
6804 if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
6805 channel = APCS_DEFAULT_2G_CH;
6806 } else if (band == WLC_BAND_5G) {
6807 channel = sta_channel;
6808 }
6809 break;
6810 }
6811 case (WLC_BAND_2G): {
6812 if (band == WLC_BAND_5G) {
6813 channel = APCS_DEFAULT_5G_CH;
6814 } else if (band == WLC_BAND_2G) {
6815 channel = sta_channel;
6816 }
6817 #ifdef WL_6G_BAND
6818 else if (band == WLC_BAND_6G) {
6819 channel = APCS_DEFAULT_6G_CH;
6820 }
6821 #endif /* WL_6G_BAND */
6822 break;
6823 }
6824 default:
6825 /* Intentional fall through to use same sta channel for softap */
6826 channel = sta_channel;
6827 break;
6828 }
6829 WL_MSG(dev->name, "band=%d, sta_band=%d, channel=%d\n", band, sta_band, channel);
6830 goto done2;
6831 }
6832
6833 /* If AP is started on wlan0 iface,
6834 * do not issue any iovar to fw and choose default ACS channel for softap
6835 */
6836 if (dev == bcmcfg_to_prmry_ndev(cfg)) {
6837 if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
6838 ANDROID_INFO(("Softap started on primary iface\n"));
6839 goto done;
6840 }
6841 }
6842
6843 chosen = wl_ext_autochannel(dev, ACS_DRV_BIT, band);
6844 channel = wf_chspec_ctlchan(chosen);
6845 if (channel) {
6846 acs_band = CHSPEC_BAND(channel);
6847 goto done2;
6848 } else
6849 goto done;
6850
6851 ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
6852 if (ret) {
6853 ANDROID_ERROR(("ACS: error getting the spect, ret=%d\n", ret));
6854 goto done;
6855 }
6856
6857 if (spect > 0) {
6858 ret = wl_android_set_spect(dev, 0);
6859 if (ret < 0) {
6860 ANDROID_ERROR(("ACS: error while setting spect, ret=%d\n", ret));
6861 goto done;
6862 }
6863 }
6864
6865 reqbuf = (u8 *)MALLOCZ(cfg->osh, CHANSPEC_BUF_SIZE);
6866 if (reqbuf == NULL) {
6867 ANDROID_ERROR(("failed to allocate chanspec buffer\n"));
6868 return -ENOMEM;
6869 }
6870
6871 if (acs_freq_list_present) {
6872 wl_uint32_list_t *list = NULL;
6873 bzero(reqbuf, sizeof(*reqbuf));
6874 list = (wl_uint32_list_t *)reqbuf;
6875
6876 ret = wl_android_get_freq_list_chanspecs(dev, list, CHANSPEC_BUF_SIZE,
6877 cmd_str, sta_channel, wl_cfg80211_get_acs_band(sta_band));
6878 if (ret < 0) {
6879 ANDROID_ERROR(("ACS chanspec set failed!\n"));
6880 goto done;
6881 }
6882
6883 /* skip ACS for single channel case */
6884 if (list->count == 1) {
6885 cfg->acs_chspec = (chanspec_t)list->element[0];
6886 channel = wf_chspec_ctlchan((chanspec_t)list->element[0]);
6887 acs_band = CHSPEC_BAND((chanspec_t)list->element[0]);
6888 goto done2;
6889 }
6890 } else {
6891 acs_band = wl_cfg80211_get_acs_band(band);
6892 if (acs_band == WLC_ACS_BAND_INVALID) {
6893 ANDROID_ERROR(("ACS: No band chosen\n"));
6894 goto done2;
6895 }
6896
6897 if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE,
6898 acs_band, true)) < 0) {
6899 ANDROID_ERROR(("ACS chanspec retrieval failed! \n"));
6900 goto done;
6901 }
6902 }
6903
6904 buf_size = CHANSPEC_BUF_SIZE;
6905 ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
6906 buf_size);
6907 if (ret < 0) {
6908 ANDROID_ERROR(("can't start auto channel scan, err = %d\n", ret));
6909 channel = 0;
6910 goto done;
6911 }
6912
6913 /* Wait for auto channel selection, max 3000 ms */
6914 if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) {
6915 OSL_SLEEP(500);
6916 } else {
6917 /*
6918 * Full channel scan at the minimum takes 1.2secs
6919 * even with parallel scan. max wait time: 3500ms
6920 */
6921 OSL_SLEEP(1000);
6922 }
6923
6924 retry = APCS_MAX_RETRY;
6925 while (retry--) {
6926 ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
6927 sizeof(chosen));
6928 if (ret < 0) {
6929 chosen = 0;
6930 } else {
6931 chosen = dtoh32(chosen);
6932 }
6933
6934 if (chosen) {
6935 /* Update chanspec which can be used during softAP bringup with right BW */
6936 cfg->acs_chspec = chosen;
6937 channel = wf_chspec_ctlchan(chosen);
6938 acs_band = CHSPEC_BAND(chosen);
6939 break;
6940 }
6941 ANDROID_INFO(("%d tried, ret = %d, chosen = 0x%x, acs_band = 0x%x\n",
6942 (APCS_MAX_RETRY - retry), ret, chosen, acs_band));
6943 OSL_SLEEP(250);
6944 }
6945
6946 done:
6947 if ((retry == 0) || (ret < 0)) {
6948 /* On failure, fallback to a default channel */
6949 if (band == WLC_BAND_5G) {
6950 channel = APCS_DEFAULT_5G_CH;
6951 #ifdef WL_6G_BAND
6952 } else if (band == WLC_BAND_6G) {
6953 channel = APCS_DEFAULT_6G_CH;
6954 #endif /* WL_6G_BAND */
6955 } else {
6956 channel = APCS_DEFAULT_2G_CH;
6957 }
6958 ANDROID_ERROR(("ACS failed. Fall back to default channel (%d) \n", channel));
6959 }
6960 done2:
6961 if (spect > 0) {
6962 if ((ret = wl_android_set_spect(dev, spect) < 0)) {
6963 ANDROID_ERROR(("ACS: error while setting spect\n"));
6964 }
6965 }
6966
6967 if (reqbuf) {
6968 MFREE(cfg->osh, reqbuf, CHANSPEC_BUF_SIZE);
6969 }
6970
6971 if (channel) {
6972 ret = snprintf(command, total_len, "%d", channel);
6973 ANDROID_INFO(("command result is %s \n", command));
6974 }
6975
6976 return ret;
6977 }
6978 #endif /* WL_SUPPORT_AUTO_CHANNEL */
6979
6980 #ifdef CUSTOMER_HW4_PRIVATE_CMD
6981 static int
wl_android_set_roam_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)6982 wl_android_set_roam_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
6983 {
6984 s32 err = BCME_OK;
6985 u32 roam_vsie_enable = 0;
6986 u32 cmd_str_len = (u32)strlen(CMD_ROAM_VSIE_ENAB_SET);
6987 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
6988
6989 /* <CMD><SPACE><VAL> */
6990 if (!cmd || (cmd_len < (cmd_str_len + 1))) {
6991 ANDROID_ERROR(("wrong arg\n"));
6992 err = -EINVAL;
6993 goto exit;
6994 }
6995
6996 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
6997 ANDROID_ERROR(("config not supported on non primary i/f\n"));
6998 err = -ENODEV;
6999 goto exit;
7000 }
7001
7002 roam_vsie_enable = cmd[(cmd_str_len + 1)] - '0';
7003 if (roam_vsie_enable > 1) {
7004 roam_vsie_enable = 1;
7005 }
7006
7007 WL_DBG_MEM(("set roam vsie %d\n", roam_vsie_enable));
7008 err = wldev_iovar_setint(dev, "roam_vsie", roam_vsie_enable);
7009 if (unlikely(err)) {
7010 ANDROID_ERROR(("set roam vsie enable failed. ret:%d\n", err));
7011 }
7012
7013 exit:
7014 return err;
7015 }
7016
7017 static int
wl_android_get_roam_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7018 wl_android_get_roam_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7019 {
7020 s32 err = BCME_OK;
7021 u32 roam_vsie_enable = 0;
7022 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7023 int bytes_written;
7024
7025 /* <CMD> */
7026 if (!cmd) {
7027 ANDROID_ERROR(("wrong arg\n"));
7028 return -1;
7029 }
7030
7031 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7032 ANDROID_ERROR(("config not supported on non primary i/f\n"));
7033 return -1;
7034 }
7035
7036 err = wldev_iovar_getint(dev, "roam_vsie", &roam_vsie_enable);
7037 if (unlikely(err)) {
7038 ANDROID_ERROR(("get roam vsie enable failed. ret:%d\n", err));
7039 return -1;
7040 }
7041 ANDROID_INFO(("get roam vsie %d\n", roam_vsie_enable));
7042
7043 bytes_written = snprintf(cmd, cmd_len, "%s %d",
7044 CMD_ROAM_VSIE_ENAB_GET, roam_vsie_enable);
7045
7046 return bytes_written;
7047 }
7048
7049 static int
wl_android_set_bcn_rpt_vsie_enab(struct net_device * dev,const char * cmd,u32 cmd_len)7050 wl_android_set_bcn_rpt_vsie_enab(struct net_device *dev, const char *cmd, u32 cmd_len)
7051 {
7052 s32 err;
7053 u32 bcn_vsie_enable = 0;
7054 u32 cmd_str_len = (u32)strlen(CMD_BR_VSIE_ENAB_SET);
7055 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7056
7057 /* <CMD><SPACE><VAL> */
7058 if (!cmd || (cmd_len < (cmd_str_len + 1))) {
7059 ANDROID_ERROR(("invalid arg\n"));
7060 err = -EINVAL;
7061 goto exit;
7062 }
7063
7064 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7065 ANDROID_ERROR(("config not supported on non primary i/f\n"));
7066 err = -ENODEV;
7067 goto exit;
7068 }
7069
7070 bcn_vsie_enable = cmd[cmd_str_len + 1] - '0';
7071 if (bcn_vsie_enable > 1) {
7072 bcn_vsie_enable = 1;
7073 }
7074
7075 WL_DBG_MEM(("set bcn report vsie %d\n", bcn_vsie_enable));
7076 err = wldev_iovar_setint(dev, "bcnrpt_vsie_en", bcn_vsie_enable);
7077 if (unlikely(err)) {
7078 ANDROID_ERROR(("set bcn vsie failed. ret:%d\n", err));
7079 }
7080
7081 exit:
7082 return err;
7083 }
7084
7085 static int
wl_android_get_bcn_rpt_vsie_enab(struct net_device * dev,char * cmd,u32 cmd_len)7086 wl_android_get_bcn_rpt_vsie_enab(struct net_device *dev, char *cmd, u32 cmd_len)
7087 {
7088 s32 err = BCME_OK;
7089 u32 bcn_vsie_enable = 0;
7090 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7091 int bytes_written;
7092
7093 /* <CMD> */
7094 if (!cmd) {
7095 ANDROID_ERROR(("wrong arg\n"));
7096 return -1;
7097 }
7098
7099 if (dev != bcmcfg_to_prmry_ndev(cfg)) {
7100 ANDROID_ERROR(("config not supported on non primary i/f\n"));
7101 return -1;
7102 }
7103
7104 err = wldev_iovar_getint(dev, "bcnrpt_vsie_en", &bcn_vsie_enable);
7105 if (unlikely(err)) {
7106 ANDROID_ERROR(("get bcn vsie failed. ret:%d\n", err));
7107 return -1;
7108 }
7109 ANDROID_INFO(("get bcn report vsie %d\n", bcn_vsie_enable));
7110
7111 bytes_written = snprintf(cmd, cmd_len, "%s %d",
7112 CMD_BR_VSIE_ENAB_GET, bcn_vsie_enable);
7113
7114 return bytes_written;
7115 }
7116
7117 #ifdef SUPPORT_HIDDEN_AP
7118 static int
wl_android_set_max_num_sta(struct net_device * dev,const char * string_num)7119 wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
7120 {
7121 int err = BCME_ERROR;
7122 int max_assoc;
7123
7124 max_assoc = bcm_atoi(string_num);
7125 ANDROID_INFO(("wl_android_set_max_num_sta : HAPD_MAX_NUM_STA = %d\n", max_assoc));
7126
7127 err = wldev_iovar_setint(dev, "maxassoc", max_assoc);
7128 if (err < 0) {
7129 ANDROID_ERROR(("failed to set maxassoc, error:%d\n", err));
7130 }
7131
7132 return err;
7133 }
7134
7135 static int
wl_android_set_ssid(struct net_device * dev,const char * hapd_ssid)7136 wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
7137 {
7138 wlc_ssid_t ssid;
7139 s32 ret;
7140
7141 ssid.SSID_len = strlen(hapd_ssid);
7142 if (ssid.SSID_len == 0) {
7143 ANDROID_ERROR(("wl_android_set_ssids : No SSID\n"));
7144 return -1;
7145 }
7146 if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
7147 ssid.SSID_len = DOT11_MAX_SSID_LEN;
7148 ANDROID_ERROR(("wl_android_set_ssid : Too long SSID Length %zu\n", strlen(hapd_ssid)));
7149 }
7150 bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
7151 ANDROID_INFO(("wl_android_set_ssid: HAPD_SSID = %s\n", ssid.SSID));
7152 ret = wldev_ioctl_set(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t));
7153 if (ret < 0) {
7154 ANDROID_ERROR(("wl_android_set_ssid : WLC_SET_SSID Error:%d\n", ret));
7155 }
7156 return 1;
7157
7158 }
7159
7160 static int
wl_android_set_hide_ssid(struct net_device * dev,const char * string_num)7161 wl_android_set_hide_ssid(struct net_device *dev, const char* string_num)
7162 {
7163 int hide_ssid;
7164 int enable = 0;
7165 int err = BCME_ERROR;
7166
7167 hide_ssid = bcm_atoi(string_num);
7168 ANDROID_INFO(("wl_android_set_hide_ssid: HAPD_HIDE_SSID = %d\n", hide_ssid));
7169 if (hide_ssid) {
7170 enable = 1;
7171 }
7172
7173 err = wldev_iovar_setint(dev, "closednet", enable);
7174 if (err < 0) {
7175 ANDROID_ERROR(("failed to set closednet, error:%d\n", err));
7176 }
7177
7178 return err;
7179 }
7180 #endif /* SUPPORT_HIDDEN_AP */
7181
7182 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
7183 static int
wl_android_sta_diassoc(struct net_device * dev,const char * straddr)7184 wl_android_sta_diassoc(struct net_device *dev, const char* straddr)
7185 {
7186 scb_val_t scbval;
7187 int error = 0;
7188
7189 ANDROID_INFO(("wl_android_sta_diassoc: deauth STA %s\n", straddr));
7190
7191 /* Unspecified reason */
7192 scbval.val = htod32(1);
7193
7194 if (bcm_ether_atoe(straddr, &scbval.ea) == 0) {
7195 ANDROID_ERROR(("wl_android_sta_diassoc: Invalid station MAC Address!!!\n"));
7196 return -1;
7197 }
7198
7199 ANDROID_ERROR(("wl_android_sta_diassoc: deauth STA: "MACDBG " scb_val.val %d\n",
7200 MAC2STRDBG(scbval.ea.octet), scbval.val));
7201
7202 error = wldev_ioctl_set(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
7203 sizeof(scb_val_t));
7204 if (error) {
7205 ANDROID_ERROR(("Fail to DEAUTH station, error = %d\n", error));
7206 }
7207
7208 return 1;
7209 }
7210 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
7211
7212 #ifdef SUPPORT_SET_LPC
7213 static int
wl_android_set_lpc(struct net_device * dev,const char * string_num)7214 wl_android_set_lpc(struct net_device *dev, const char* string_num)
7215 {
7216 int lpc_enabled, ret;
7217 s32 val = 1;
7218
7219 lpc_enabled = bcm_atoi(string_num);
7220 ANDROID_INFO(("wl_android_set_lpc: HAPD_LPC_ENABLED = %d\n", lpc_enabled));
7221
7222 ret = wldev_ioctl_set(dev, WLC_DOWN, &val, sizeof(s32));
7223 if (ret < 0)
7224 ANDROID_ERROR(("WLC_DOWN error %d\n", ret));
7225
7226 wldev_iovar_setint(dev, "lpc", lpc_enabled);
7227
7228 ret = wldev_ioctl_set(dev, WLC_UP, &val, sizeof(s32));
7229 if (ret < 0)
7230 ANDROID_ERROR(("WLC_UP error %d\n", ret));
7231
7232 return 1;
7233 }
7234 #endif /* SUPPORT_SET_LPC */
7235
7236 static int
wl_android_ch_res_rl(struct net_device * dev,bool change)7237 wl_android_ch_res_rl(struct net_device *dev, bool change)
7238 {
7239 int error = 0;
7240 s32 srl = 7;
7241 s32 lrl = 4;
7242 ANDROID_ERROR(("wl_android_ch_res_rl: enter\n"));
7243 if (change) {
7244 srl = 4;
7245 lrl = 2;
7246 }
7247
7248 BCM_REFERENCE(lrl);
7249
7250 error = wldev_ioctl_set(dev, WLC_SET_SRL, &srl, sizeof(s32));
7251 if (error) {
7252 ANDROID_ERROR(("Failed to set SRL, error = %d\n", error));
7253 }
7254 #ifndef CUSTOM_LONG_RETRY_LIMIT
7255 error = wldev_ioctl_set(dev, WLC_SET_LRL, &lrl, sizeof(s32));
7256 if (error) {
7257 ANDROID_ERROR(("Failed to set LRL, error = %d\n", error));
7258 }
7259 #endif /* CUSTOM_LONG_RETRY_LIMIT */
7260 return error;
7261 }
7262
7263 #ifdef SUPPORT_LTECX
7264 #define DEFAULT_WLANRX_PROT 1
7265 #define DEFAULT_LTERX_PROT 0
7266 #define DEFAULT_LTETX_ADV 1200
7267
7268 static int
wl_android_set_ltecx(struct net_device * dev,const char * string_num)7269 wl_android_set_ltecx(struct net_device *dev, const char* string_num)
7270 {
7271 uint16 chan_bitmap;
7272 int ret;
7273
7274 chan_bitmap = bcm_strtoul(string_num, NULL, 16);
7275
7276 ANDROID_INFO(("wl_android_set_ltecx: LTECOEX 0x%x\n", chan_bitmap));
7277
7278 if (chan_bitmap) {
7279 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7280 if (ret < 0) {
7281 ANDROID_ERROR(("mws_coex_bitmap error %d\n", ret));
7282 }
7283
7284 ret = wldev_iovar_setint(dev, "mws_wlanrx_prot", DEFAULT_WLANRX_PROT);
7285 if (ret < 0) {
7286 ANDROID_ERROR(("mws_wlanrx_prot error %d\n", ret));
7287 }
7288
7289 ret = wldev_iovar_setint(dev, "mws_lterx_prot", DEFAULT_LTERX_PROT);
7290 if (ret < 0) {
7291 ANDROID_ERROR(("mws_lterx_prot error %d\n", ret));
7292 }
7293
7294 ret = wldev_iovar_setint(dev, "mws_ltetx_adv", DEFAULT_LTETX_ADV);
7295 if (ret < 0) {
7296 ANDROID_ERROR(("mws_ltetx_adv error %d\n", ret));
7297 }
7298 } else {
7299 ret = wldev_iovar_setint(dev, "mws_coex_bitmap", chan_bitmap);
7300 if (ret < 0) {
7301 if (ret == BCME_UNSUPPORTED) {
7302 ANDROID_ERROR(("LTECX_CHAN_BITMAP is UNSUPPORTED\n"));
7303 } else {
7304 ANDROID_ERROR(("LTECX_CHAN_BITMAP error %d\n", ret));
7305 }
7306 }
7307 }
7308 return 1;
7309 }
7310 #endif /* SUPPORT_LTECX */
7311
7312 #ifdef WL_RELMCAST
7313 static int
wl_android_rmc_enable(struct net_device * net,int rmc_enable)7314 wl_android_rmc_enable(struct net_device *net, int rmc_enable)
7315 {
7316 int err;
7317
7318 err = wldev_iovar_setint(net, "rmc_ackreq", rmc_enable);
7319 if (err != BCME_OK) {
7320 ANDROID_ERROR(("wl_android_rmc_enable: rmc_ackreq, error = %d\n", err));
7321 }
7322 return err;
7323 }
7324
7325 static int
wl_android_rmc_set_leader(struct net_device * dev,const char * straddr)7326 wl_android_rmc_set_leader(struct net_device *dev, const char* straddr)
7327 {
7328 int error = BCME_OK;
7329 char smbuf[WLC_IOCTL_SMLEN];
7330 wl_rmc_entry_t rmc_entry;
7331 ANDROID_INFO(("wl_android_rmc_set_leader: Set new RMC leader %s\n", straddr));
7332
7333 bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7334 if (!bcm_ether_atoe(straddr, &rmc_entry.addr)) {
7335 if (strlen(straddr) == 1 && bcm_atoi(straddr) == 0) {
7336 ANDROID_INFO(("wl_android_rmc_set_leader: Set auto leader selection mode\n"));
7337 bzero(&rmc_entry, sizeof(wl_rmc_entry_t));
7338 } else {
7339 ANDROID_ERROR(("wl_android_rmc_set_leader: No valid mac address provided\n"));
7340 return BCME_ERROR;
7341 }
7342 }
7343
7344 error = wldev_iovar_setbuf(dev, "rmc_ar", &rmc_entry, sizeof(wl_rmc_entry_t),
7345 smbuf, sizeof(smbuf), NULL);
7346
7347 if (error != BCME_OK) {
7348 ANDROID_ERROR(("wl_android_rmc_set_leader: Unable to set RMC leader, error = %d\n",
7349 error));
7350 }
7351
7352 return error;
7353 }
7354
wl_android_set_rmc_event(struct net_device * dev,char * command)7355 static int wl_android_set_rmc_event(struct net_device *dev, char *command)
7356 {
7357 int err = 0;
7358 int pid = 0;
7359
7360 if (sscanf(command, CMD_SET_RMC_EVENT " %d", &pid) <= 0) {
7361 ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
7362 return -1;
7363 }
7364
7365 /* set pid, and if the event was happened, let's send a notification through netlink */
7366 wl_cfg80211_set_rmc_pid(dev, pid);
7367
7368 ANDROID_INFO(("RMC pid=%d\n", pid));
7369
7370 return err;
7371 }
7372 #endif /* WL_RELMCAST */
7373
wl_android_get_singlecore_scan(struct net_device * dev,char * command,int total_len)7374 int wl_android_get_singlecore_scan(struct net_device *dev, char *command, int total_len)
7375 {
7376 int error = 0;
7377 int bytes_written = 0;
7378 int mode = 0;
7379
7380 error = wldev_iovar_getint(dev, "scan_ps", &mode);
7381 if (error) {
7382 ANDROID_ERROR(("wl_android_get_singlecore_scan: Failed to get single core scan Mode,"
7383 " error = %d\n",
7384 error));
7385 return -1;
7386 }
7387
7388 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_SCSCAN, mode);
7389
7390 return bytes_written;
7391 }
7392
wl_android_set_singlecore_scan(struct net_device * dev,char * command)7393 int wl_android_set_singlecore_scan(struct net_device *dev, char *command)
7394 {
7395 int error = 0;
7396 int mode = 0;
7397
7398 if (sscanf(command, "%*s %d", &mode) != 1) {
7399 ANDROID_ERROR(("wl_android_set_singlecore_scan: Failed to get Parameter\n"));
7400 return -1;
7401 }
7402
7403 error = wldev_iovar_setint(dev, "scan_ps", mode);
7404 if (error) {
7405 ANDROID_ERROR(("wl_android_set_singlecore_scan[1]: Failed to set Mode %d, error = %d\n",
7406 mode, error));
7407 return -1;
7408 }
7409
7410 return error;
7411 }
7412 #ifdef TEST_TX_POWER_CONTROL
7413 static int
wl_android_set_tx_power(struct net_device * dev,const char * string_num)7414 wl_android_set_tx_power(struct net_device *dev, const char* string_num)
7415 {
7416 int err = 0;
7417 s32 dbm;
7418 enum nl80211_tx_power_setting type;
7419
7420 dbm = bcm_atoi(string_num);
7421
7422 if (dbm < -1) {
7423 ANDROID_ERROR(("wl_android_set_tx_power: dbm is negative...\n"));
7424 return -EINVAL;
7425 }
7426
7427 if (dbm == -1)
7428 type = NL80211_TX_POWER_AUTOMATIC;
7429 else
7430 type = NL80211_TX_POWER_FIXED;
7431
7432 err = wl_set_tx_power(dev, type, dbm);
7433 if (unlikely(err)) {
7434 ANDROID_ERROR(("wl_android_set_tx_power: error (%d)\n", err));
7435 return err;
7436 }
7437
7438 return 1;
7439 }
7440
7441 static int
wl_android_get_tx_power(struct net_device * dev,char * command,int total_len)7442 wl_android_get_tx_power(struct net_device *dev, char *command, int total_len)
7443 {
7444 int err;
7445 int bytes_written;
7446 s32 dbm = 0;
7447
7448 err = wl_get_tx_power(dev, &dbm);
7449 if (unlikely(err)) {
7450 ANDROID_ERROR(("wl_android_get_tx_power: error (%d)\n", err));
7451 return err;
7452 }
7453
7454 bytes_written = snprintf(command, total_len, "%s %d",
7455 CMD_TEST_GET_TX_POWER, dbm);
7456
7457 ANDROID_ERROR(("wl_android_get_tx_power: GET_TX_POWER: dBm=%d\n", dbm));
7458
7459 return bytes_written;
7460 }
7461 #endif /* TEST_TX_POWER_CONTROL */
7462
7463 static int
wl_android_set_sarlimit_txctrl(struct net_device * dev,const char * string_num)7464 wl_android_set_sarlimit_txctrl(struct net_device *dev, const char* string_num)
7465 {
7466 int err = BCME_ERROR;
7467 int setval = 0;
7468 s32 mode = bcm_atoi(string_num);
7469 s32 mode_bit = 0;
7470 int enab = 0;
7471
7472 /* As Samsung specific and their requirement,
7473 * the mode set as the following form.
7474 * -1 : HEAD SAR disabled
7475 * 0 : HEAD SAR enabled
7476 * 1 : GRIP SAR disabled
7477 * 2 : GRIP SAR enabled
7478 * 3 : NR mmWave SAR disabled
7479 * 4 : NR mmWave SAR enabled
7480 * 5 : NR Sub6 SAR disabled
7481 * 6 : NR Sub6 SAR enabled
7482 * 7 : SAR BACKOFF disabled all
7483 * The 'SAR BACKOFF disabled all' index should be the end of the mode.
7484 */
7485 if ((mode < HEAD_SAR_BACKOFF_DISABLE) || (mode > SAR_BACKOFF_DISABLE_ALL)) {
7486 ANDROID_ERROR(("%s: Request for Unsupported:%d\n", __FUNCTION__, bcm_atoi(string_num)));
7487 err = BCME_RANGE;
7488 goto error;
7489 }
7490
7491 mode_bit = mode + 1;
7492 enab = mode_bit % 2;
7493 mode_bit = mode_bit / 2;
7494
7495 err = wldev_iovar_getint(dev, "sar_enable", &setval);
7496 if (unlikely(err)) {
7497 ANDROID_ERROR(("%s: Failed to get sar_enable - error (%d)\n", __FUNCTION__, err));
7498 goto error;
7499 }
7500
7501 if (mode == SAR_BACKOFF_DISABLE_ALL) {
7502 ANDROID_ERROR(("%s: SAR limit control all mode disable!\n", __FUNCTION__));
7503 setval = 0;
7504 } else {
7505 ANDROID_ERROR(("%s: SAR limit control mode %d enab %d\n",
7506 __FUNCTION__, mode_bit, enab));
7507 if (enab) {
7508 setval |= (1 << mode_bit);
7509 } else {
7510 setval &= ~(1 << mode_bit);
7511 }
7512 }
7513
7514 err = wldev_iovar_setint(dev, "sar_enable", setval);
7515 if (unlikely(err)) {
7516 ANDROID_ERROR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
7517 goto error;
7518 }
7519 err = BCME_OK;
7520 error:
7521 return err;
7522 }
7523
7524 #ifdef SUPPORT_SET_TID
7525 static int
wl_android_set_tid(struct net_device * dev,char * command)7526 wl_android_set_tid(struct net_device *dev, char* command)
7527 {
7528 int err = BCME_ERROR;
7529 char *pos = command;
7530 char *token = NULL;
7531 uint8 mode = 0;
7532 uint32 uid = 0;
7533 uint8 prio = 0;
7534 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7535
7536 if (!dhdp) {
7537 ANDROID_ERROR(("dhd is NULL\n"));
7538 return err;
7539 }
7540
7541 ANDROID_INFO(("%s: command[%s]\n", __FUNCTION__, command));
7542
7543 /* drop command */
7544 token = bcmstrtok(&pos, " ", NULL);
7545
7546 token = bcmstrtok(&pos, " ", NULL);
7547 if (!token) {
7548 ANDROID_ERROR(("Invalid arguments\n"));
7549 return err;
7550 }
7551
7552 mode = bcm_atoi(token);
7553
7554 if (mode < SET_TID_OFF || mode > SET_TID_BASED_ON_UID) {
7555 ANDROID_ERROR(("Invalid arguments, mode %d\n", mode));
7556 return err;
7557 }
7558
7559 if (mode) {
7560 token = bcmstrtok(&pos, " ", NULL);
7561 if (!token) {
7562 ANDROID_ERROR(("Invalid arguments for target uid\n"));
7563 return err;
7564 }
7565
7566 uid = bcm_atoi(token);
7567
7568 token = bcmstrtok(&pos, " ", NULL);
7569 if (!token) {
7570 ANDROID_ERROR(("Invalid arguments for target tid\n"));
7571 return err;
7572 }
7573
7574 prio = bcm_atoi(token);
7575 if (prio >= 0 && prio <= MAXPRIO) {
7576 dhdp->tid_mode = mode;
7577 dhdp->target_uid = uid;
7578 dhdp->target_tid = prio;
7579 } else {
7580 ANDROID_ERROR(("Invalid arguments, prio %d\n", prio));
7581 return err;
7582 }
7583 } else {
7584 dhdp->tid_mode = SET_TID_OFF;
7585 dhdp->target_uid = 0;
7586 dhdp->target_tid = 0;
7587 }
7588
7589 ANDROID_INFO(("%s mode [%d], uid [%d], tid [%d]\n", __FUNCTION__,
7590 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid));
7591
7592 err = BCME_OK;
7593 return err;
7594 }
7595
7596 static int
wl_android_get_tid(struct net_device * dev,char * command,int total_len)7597 wl_android_get_tid(struct net_device *dev, char* command, int total_len)
7598 {
7599 int bytes_written = BCME_ERROR;
7600 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
7601
7602 if (!dhdp) {
7603 ANDROID_ERROR(("dhd is NULL\n"));
7604 return bytes_written;
7605 }
7606
7607 bytes_written = snprintf(command, total_len, "mode %d uid %d tid %d",
7608 dhdp->tid_mode, dhdp->target_uid, dhdp->target_tid);
7609
7610 ANDROID_INFO(("%s: command results %s\n", __FUNCTION__, command));
7611
7612 return bytes_written;
7613 }
7614 #endif /* SUPPORT_SET_TID */
7615 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
7616
wl_android_set_roam_mode(struct net_device * dev,char * command)7617 int wl_android_set_roam_mode(struct net_device *dev, char *command)
7618 {
7619 int error = 0;
7620 int mode = 0;
7621
7622 if (sscanf(command, "%*s %d", &mode) != 1) {
7623 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7624 return -1;
7625 }
7626
7627 error = wldev_iovar_setint(dev, "roam_off", mode);
7628 if (error) {
7629 ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
7630 __FUNCTION__, mode, error));
7631 return -1;
7632 }
7633 else
7634 ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
7635 __FUNCTION__, mode, error));
7636 return 0;
7637 }
7638
7639 #ifdef WL_CFG80211
wl_android_set_ibss_beacon_ouidata(struct net_device * dev,char * command,int total_len)7640 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
7641 {
7642 char ie_buf[VNDR_IE_MAX_LEN];
7643 char *ioctl_buf = NULL;
7644 char hex[] = "XX";
7645 char *pcmd = NULL;
7646 int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
7647 vndr_ie_setbuf_t *vndr_ie = NULL;
7648 s32 iecount;
7649 uint32 pktflag;
7650 s32 err = BCME_OK, bssidx;
7651 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7652
7653 /* Check the VSIE (Vendor Specific IE) which was added.
7654 * If exist then send IOVAR to delete it
7655 */
7656 if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
7657 return -EINVAL;
7658 }
7659
7660 if (total_len < (strlen(CMD_SETIBSSBEACONOUIDATA) + 1)) {
7661 ANDROID_ERROR(("error. total_len:%d\n", total_len));
7662 return -EINVAL;
7663 }
7664
7665 pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
7666 for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
7667 if (*pcmd == '\0') {
7668 ANDROID_ERROR(("error while parsing OUI.\n"));
7669 return -EINVAL;
7670 }
7671 hex[0] = *pcmd++;
7672 hex[1] = *pcmd++;
7673 ie_buf[idx] = (uint8)simple_strtoul(hex, NULL, 16);
7674 }
7675 pcmd++;
7676 while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
7677 hex[0] = *pcmd++;
7678 hex[1] = *pcmd++;
7679 ie_buf[idx++] = (uint8)simple_strtoul(hex, NULL, 16);
7680 datalen++;
7681 }
7682
7683 if (datalen <= 0) {
7684 ANDROID_ERROR(("error. vndr ie len:%d\n", datalen));
7685 return -EINVAL;
7686 }
7687
7688 tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (datalen - 1));
7689 vndr_ie = (vndr_ie_setbuf_t *)MALLOCZ(cfg->osh, tot_len);
7690 if (!vndr_ie) {
7691 ANDROID_ERROR(("IE memory alloc failed\n"));
7692 return -ENOMEM;
7693 }
7694 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
7695 strlcpy(vndr_ie->cmd, "add", sizeof(vndr_ie->cmd));
7696
7697 /* Set the IE count - the buffer contains only 1 IE */
7698 iecount = htod32(1);
7699 memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
7700
7701 /* Set packet flag to indicate that BEACON's will contain this IE */
7702 pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
7703 memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
7704 sizeof(u32));
7705 /* Set the IE ID */
7706 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
7707
7708 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
7709 DOT11_OUI_LEN);
7710 memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
7711 &ie_buf[DOT11_OUI_LEN], datalen);
7712
7713 ielen = DOT11_OUI_LEN + datalen;
7714 vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
7715
7716 ioctl_buf = (char *)MALLOC(cfg->osh, WLC_IOCTL_MEDLEN);
7717 if (!ioctl_buf) {
7718 ANDROID_ERROR(("ioctl memory alloc failed\n"));
7719 if (vndr_ie) {
7720 MFREE(cfg->osh, vndr_ie, tot_len);
7721 }
7722 return -ENOMEM;
7723 }
7724 bzero(ioctl_buf, WLC_IOCTL_MEDLEN); /* init the buffer */
7725 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
7726 ANDROID_ERROR(("Find index failed\n"));
7727 err = BCME_ERROR;
7728 goto end;
7729 }
7730 err = wldev_iovar_setbuf_bsscfg(dev, "vndr_ie", vndr_ie, tot_len, ioctl_buf,
7731 WLC_IOCTL_MEDLEN, bssidx, &cfg->ioctl_buf_sync);
7732 end:
7733 if (err != BCME_OK) {
7734 err = -EINVAL;
7735 if (vndr_ie) {
7736 MFREE(cfg->osh, vndr_ie, tot_len);
7737 }
7738 }
7739 else {
7740 /* do NOT free 'vndr_ie' for the next process */
7741 wl_cfg80211_ibss_vsie_set_buffer(dev, vndr_ie, tot_len);
7742 }
7743
7744 if (ioctl_buf) {
7745 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
7746 }
7747
7748 return err;
7749 }
7750 #endif /* WL_CFG80211 */
7751
7752 #if defined(BCMFW_ROAM_ENABLE)
7753 static int
wl_android_set_roampref(struct net_device * dev,char * command,int total_len)7754 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
7755 {
7756 int error = 0;
7757 char smbuf[WLC_IOCTL_SMLEN];
7758 uint8 buf[MAX_BUF_SIZE];
7759 uint8 *pref = buf;
7760 char *pcmd;
7761 int num_ucipher_suites = 0;
7762 int num_akm_suites = 0;
7763 wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
7764 wpa_suite_t akm_suites[MAX_NUM_SUITES];
7765 int num_tuples = 0;
7766 int total_bytes = 0;
7767 int total_len_left;
7768 int i, j;
7769 char hex[] = "XX";
7770
7771 pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
7772 total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
7773
7774 num_akm_suites = simple_strtoul(pcmd, NULL, 16);
7775 if (num_akm_suites > MAX_NUM_SUITES) {
7776 ANDROID_ERROR(("too many AKM suites = %d\n", num_akm_suites));
7777 return -1;
7778 }
7779
7780 /* Increment for number of AKM suites field + space */
7781 pcmd += 3;
7782 total_len_left -= 3;
7783
7784 /* check to make sure pcmd does not overrun */
7785 if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
7786 return -1;
7787
7788 bzero(buf, sizeof(buf));
7789 bzero(akm_suites, sizeof(akm_suites));
7790 bzero(ucipher_suites, sizeof(ucipher_suites));
7791
7792 /* Save the AKM suites passed in the command */
7793 for (i = 0; i < num_akm_suites; i++) {
7794 /* Store the MSB first, as required by join_pref */
7795 for (j = 0; j < 4; j++) {
7796 hex[0] = *pcmd++;
7797 hex[1] = *pcmd++;
7798 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7799 }
7800 memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
7801 }
7802
7803 total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
7804 num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
7805 /* Increment for number of cipher suites field + space */
7806 pcmd += 3;
7807 total_len_left -= 3;
7808
7809 if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
7810 return -1;
7811
7812 /* Save the cipher suites passed in the command */
7813 for (i = 0; i < num_ucipher_suites; i++) {
7814 /* Store the MSB first, as required by join_pref */
7815 for (j = 0; j < 4; j++) {
7816 hex[0] = *pcmd++;
7817 hex[1] = *pcmd++;
7818 buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
7819 }
7820 memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
7821 }
7822
7823 /* Join preference for RSSI
7824 * Type : 1 byte (0x01)
7825 * Length : 1 byte (0x02)
7826 * Value : 2 bytes (reserved)
7827 */
7828 *pref++ = WL_JOIN_PREF_RSSI;
7829 *pref++ = JOIN_PREF_RSSI_LEN;
7830 *pref++ = 0;
7831 *pref++ = 0;
7832
7833 /* Join preference for WPA
7834 * Type : 1 byte (0x02)
7835 * Length : 1 byte (not used)
7836 * Value : (variable length)
7837 * reserved: 1 byte
7838 * count : 1 byte (no of tuples)
7839 * Tuple1 : 12 bytes
7840 * akm[4]
7841 * ucipher[4]
7842 * mcipher[4]
7843 * Tuple2 : 12 bytes
7844 * Tuplen : 12 bytes
7845 */
7846 num_tuples = num_akm_suites * num_ucipher_suites;
7847 if (num_tuples != 0) {
7848 if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
7849 *pref++ = WL_JOIN_PREF_WPA;
7850 *pref++ = 0;
7851 *pref++ = 0;
7852 *pref++ = (uint8)num_tuples;
7853 total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
7854 (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
7855 } else {
7856 ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
7857 return -1;
7858 }
7859 } else {
7860 /* No WPA config, configure only RSSI preference */
7861 total_bytes = JOIN_PREF_RSSI_SIZE;
7862 }
7863
7864 /* akm-ucipher-mcipher tuples in the format required for join_pref */
7865 for (i = 0; i < num_ucipher_suites; i++) {
7866 for (j = 0; j < num_akm_suites; j++) {
7867 memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
7868 pref += WPA_SUITE_LEN;
7869 memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
7870 pref += WPA_SUITE_LEN;
7871 /* Set to 0 to match any available multicast cipher */
7872 bzero(pref, WPA_SUITE_LEN);
7873 pref += WPA_SUITE_LEN;
7874 }
7875 }
7876
7877 prhex("join pref", (uint8 *)buf, total_bytes);
7878 error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
7879 if (error) {
7880 ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
7881 }
7882 return error;
7883 }
7884 #endif /* defined(BCMFW_ROAM_ENABLE */
7885
7886 #ifdef WL_CFG80211
7887 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)7888 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
7889 {
7890 struct io_cfg *resume_cfg;
7891 s32 ret;
7892 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7893
7894 resume_cfg = (struct io_cfg *)MALLOCZ(cfg->osh, sizeof(struct io_cfg));
7895 if (!resume_cfg)
7896 return -ENOMEM;
7897
7898 if (config->iovar) {
7899 ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
7900 if (ret) {
7901 ANDROID_ERROR(("%s: Failed to get current %s value\n",
7902 __FUNCTION__, config->iovar));
7903 goto error;
7904 }
7905
7906 ret = wldev_iovar_setint(dev, config->iovar, config->param);
7907 if (ret) {
7908 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7909 config->iovar, config->param));
7910 goto error;
7911 }
7912
7913 resume_cfg->iovar = config->iovar;
7914 } else {
7915 resume_cfg->arg = MALLOCZ(cfg->osh, config->len);
7916 if (!resume_cfg->arg) {
7917 ret = -ENOMEM;
7918 goto error;
7919 }
7920 ret = wldev_ioctl_get(dev, config->ioctl, resume_cfg->arg, config->len);
7921 if (ret) {
7922 ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
7923 config->ioctl));
7924 goto error;
7925 }
7926 ret = wldev_ioctl_set(dev, config->ioctl + 1, config->arg, config->len);
7927 if (ret) {
7928 ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
7929 config->iovar, config->param));
7930 goto error;
7931 }
7932 if (config->ioctl + 1 == WLC_SET_PM)
7933 wl_cfg80211_update_power_mode(dev);
7934 resume_cfg->ioctl = config->ioctl;
7935 resume_cfg->len = config->len;
7936 }
7937
7938 /* assuming only one active user and no list protection */
7939 list_add(&resume_cfg->list, head);
7940
7941 return 0;
7942 error:
7943 MFREE(cfg->osh, resume_cfg->arg, config->len);
7944 MFREE(cfg->osh, resume_cfg, sizeof(struct io_cfg));
7945 return ret;
7946 }
7947
7948 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)7949 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
7950 {
7951 struct io_cfg *config;
7952 struct list_head *cur, *q;
7953 s32 ret = 0;
7954 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7955 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
7956 list_for_each_safe(cur, q, head) {
7957 config = list_entry(cur, struct io_cfg, list);
7958 GCC_DIAGNOSTIC_POP();
7959 if (config->iovar) {
7960 if (!ret)
7961 ret = wldev_iovar_setint(dev, config->iovar,
7962 config->param);
7963 } else {
7964 if (!ret)
7965 ret = wldev_ioctl_set(dev, config->ioctl + 1,
7966 config->arg, config->len);
7967 if (config->ioctl + 1 == WLC_SET_PM)
7968 wl_cfg80211_update_power_mode(dev);
7969 MFREE(cfg->osh, config->arg, config->len);
7970 }
7971 list_del(cur);
7972 MFREE(cfg->osh, config, sizeof(struct io_cfg));
7973 }
7974 }
7975
7976 static int
wl_android_set_miracast(struct net_device * dev,char * command)7977 wl_android_set_miracast(struct net_device *dev, char *command)
7978 {
7979 int mode, val = 0;
7980 int ret = 0;
7981 struct io_cfg config;
7982
7983 if (sscanf(command, "%*s %d", &mode) != 1) {
7984 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
7985 return -1;
7986 }
7987
7988 ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
7989
7990 if (miracast_cur_mode == mode) {
7991 return 0;
7992 }
7993
7994 wl_android_iolist_resume(dev, &miracast_resume_list);
7995 miracast_cur_mode = MIRACAST_MODE_OFF;
7996
7997 bzero((void *)&config, sizeof(config));
7998 switch (mode) {
7999 case MIRACAST_MODE_SOURCE:
8000 #ifdef MIRACAST_MCHAN_ALGO
8001 /* setting mchan_algo to platform specific value */
8002 config.iovar = "mchan_algo";
8003
8004 /* check for station's beacon interval(BI)
8005 * If BI is over 100ms, don't use mchan_algo
8006 */
8007 ret = wldev_ioctl_get(dev, WLC_GET_BCNPRD, &val, sizeof(int));
8008 if (!ret && val > 100) {
8009 config.param = 0;
8010 ANDROID_ERROR(("%s: Connected station's beacon interval: "
8011 "%d and set mchan_algo to %d \n",
8012 __FUNCTION__, val, config.param));
8013 } else {
8014 config.param = MIRACAST_MCHAN_ALGO;
8015 }
8016 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8017 if (ret) {
8018 goto resume;
8019 }
8020 #endif /* MIRACAST_MCHAN_ALGO */
8021
8022 #ifdef MIRACAST_MCHAN_BW
8023 /* setting mchan_bw to platform specific value */
8024 config.iovar = "mchan_bw";
8025 config.param = MIRACAST_MCHAN_BW;
8026 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8027 if (ret) {
8028 goto resume;
8029 }
8030 #endif /* MIRACAST_MCHAN_BW */
8031
8032 #ifdef MIRACAST_AMPDU_SIZE
8033 /* setting apmdu to platform specific value */
8034 config.iovar = "ampdu_mpdu";
8035 config.param = MIRACAST_AMPDU_SIZE;
8036 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8037 if (ret) {
8038 goto resume;
8039 }
8040 #endif /* MIRACAST_AMPDU_SIZE */
8041 /* FALLTROUGH */
8042 /* Source mode shares most configurations with sink mode.
8043 * Fall through here to avoid code duplication
8044 */
8045 case MIRACAST_MODE_SINK:
8046 /* disable internal roaming */
8047 config.iovar = "roam_off";
8048 config.param = 1;
8049 config.arg = NULL;
8050 config.len = 0;
8051 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8052 if (ret) {
8053 goto resume;
8054 }
8055
8056 #ifdef CUSTOMER_HW10
8057 /* [CSP#812738] Change scan engine parameters to reduce scan time
8058 * and guarantee more times to mirroring.
8059 */
8060 val = 10;
8061 config.iovar = NULL;
8062 config.ioctl = WLC_GET_SCAN_CHANNEL_TIME;
8063 config.arg = &val;
8064 config.len = sizeof(int);
8065 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8066 if (ret)
8067 goto resume;
8068
8069 val = 180;
8070 config.iovar = NULL;
8071 config.ioctl = WLC_GET_SCAN_HOME_TIME;
8072 config.arg = &val;
8073 config.len = sizeof(int);
8074 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8075 if (ret)
8076 goto resume;
8077
8078 #if defined(BCM4339_CHIP)
8079 config.iovar = "phy_watchdog";
8080 config.param = 0;
8081 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8082 ANDROID_INFO(("%s: do iovar cmd=%s (ret=%d)\n",
8083 __FUNCTION__, config.iovar, ret));
8084 #endif
8085 #endif /* CUSTOMER_HW10 */
8086
8087 #ifndef CUSTOMER_HW10
8088
8089 /* tunr off pm */
8090 ret = wldev_ioctl_get(dev, WLC_GET_PM, &val, sizeof(val));
8091 if (ret) {
8092 goto resume;
8093 }
8094
8095 if (val != PM_OFF) {
8096 val = PM_OFF;
8097 config.iovar = NULL;
8098 config.ioctl = WLC_GET_PM;
8099 config.arg = &val;
8100 config.len = sizeof(int);
8101 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
8102 if (ret) {
8103 goto resume;
8104 }
8105 }
8106 #endif /* CUSTOMER_HW10 */
8107 break;
8108 case MIRACAST_MODE_OFF:
8109 default:
8110 break;
8111 }
8112 miracast_cur_mode = mode;
8113
8114 return 0;
8115
8116 resume:
8117 ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
8118 wl_android_iolist_resume(dev, &miracast_resume_list);
8119 return ret;
8120 }
8121 #endif /* WL_CFG80211 */
8122
8123 #ifdef WL_RELMCAST
8124 #define NETLINK_OXYGEN 30
8125 #define AIBSS_BEACON_TIMEOUT 10
8126
8127 static struct sock *nl_sk = NULL;
8128
wl_netlink_recv(struct sk_buff * skb)8129 static void wl_netlink_recv(struct sk_buff *skb)
8130 {
8131 ANDROID_ERROR(("netlink_recv called\n"));
8132 }
8133
wl_netlink_init(void)8134 static int wl_netlink_init(void)
8135 {
8136 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
8137 struct netlink_kernel_cfg cfg = {
8138 .input = wl_netlink_recv,
8139 };
8140 #endif
8141
8142 if (nl_sk != NULL) {
8143 ANDROID_ERROR(("nl_sk already exist\n"));
8144 return BCME_ERROR;
8145 }
8146
8147 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
8148 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
8149 0, wl_netlink_recv, NULL, THIS_MODULE);
8150 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
8151 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
8152 #else
8153 nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
8154 #endif
8155
8156 if (nl_sk == NULL) {
8157 ANDROID_ERROR(("nl_sk is not ready\n"));
8158 return BCME_ERROR;
8159 }
8160
8161 return BCME_OK;
8162 }
8163
wl_netlink_deinit(void)8164 static void wl_netlink_deinit(void)
8165 {
8166 if (nl_sk) {
8167 netlink_kernel_release(nl_sk);
8168 nl_sk = NULL;
8169 }
8170 }
8171
8172 s32
wl_netlink_send_msg(int pid,int type,int seq,const void * data,size_t size)8173 wl_netlink_send_msg(int pid, int type, int seq, const void *data, size_t size)
8174 {
8175 struct sk_buff *skb = NULL;
8176 struct nlmsghdr *nlh = NULL;
8177 int ret = -1;
8178
8179 if (nl_sk == NULL) {
8180 ANDROID_ERROR(("nl_sk was not initialized\n"));
8181 goto nlmsg_failure;
8182 }
8183
8184 skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
8185 if (skb == NULL) {
8186 ANDROID_ERROR(("failed to allocate memory\n"));
8187 goto nlmsg_failure;
8188 }
8189
8190 nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
8191 if (nlh == NULL) {
8192 ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
8193 skb_tailroom(skb), nlmsg_total_size(size)));
8194 dev_kfree_skb(skb);
8195 goto nlmsg_failure;
8196 }
8197
8198 memcpy(nlmsg_data(nlh), data, size);
8199 nlh->nlmsg_seq = seq;
8200 nlh->nlmsg_type = type;
8201
8202 /* netlink_unicast() takes ownership of the skb and frees it itself. */
8203 ret = netlink_unicast(nl_sk, skb, pid, 0);
8204 ANDROID_INFO(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
8205
8206 nlmsg_failure:
8207 return ret;
8208 }
8209 #endif /* WL_RELMCAST */
8210
8211 #ifdef WLAIBSS
wl_android_set_ibss_txfail_event(struct net_device * dev,char * command,int total_len)8212 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
8213 {
8214 int err = 0;
8215 int retry = 0;
8216 int pid = 0;
8217 aibss_txfail_config_t txfail_config = {0, 0, 0, 0, 0};
8218 char smbuf[WLC_IOCTL_SMLEN];
8219
8220 if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
8221 ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
8222 return -1;
8223 }
8224
8225 /* set pid, and if the event was happened, let's send a notification through netlink */
8226 wl_cfg80211_set_txfail_pid(dev, pid);
8227
8228 #ifdef WL_RELMCAST
8229 /* using same pid for RMC, AIBSS shares same pid with RMC and it is set once */
8230 wl_cfg80211_set_rmc_pid(dev, pid);
8231 #endif /* WL_RELMCAST */
8232
8233 /* If retry value is 0, it disables the functionality for TX Fail. */
8234 if (retry > 0) {
8235 txfail_config.max_tx_retry = retry;
8236 txfail_config.bcn_timeout = 0; /* 0 : disable tx fail from beacon */
8237 }
8238 txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
8239 txfail_config.len = sizeof(txfail_config);
8240
8241 err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
8242 sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
8243 ANDROID_INFO(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
8244
8245 return ((err == 0)?total_len:err);
8246 }
8247
wl_android_get_ibss_peer_info(struct net_device * dev,char * command,int total_len,bool bAll)8248 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
8249 int total_len, bool bAll)
8250 {
8251 int error;
8252 int bytes_written = 0;
8253 void *buf = NULL;
8254 bss_peer_list_info_t peer_list_info;
8255 bss_peer_info_t *peer_info;
8256 int i;
8257 bool found = false;
8258 struct ether_addr mac_ea;
8259 char *str = command;
8260 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8261
8262 ANDROID_INFO(("get ibss peer info(%s)\n", bAll?"true":"false"));
8263
8264 if (!bAll) {
8265 if (bcmstrtok(&str, " ", NULL) == NULL) {
8266 ANDROID_ERROR(("invalid command\n"));
8267 return -1;
8268 }
8269
8270 if (!str || !bcm_ether_atoe(str, &mac_ea)) {
8271 ANDROID_ERROR(("invalid MAC address\n"));
8272 return -1;
8273 }
8274 }
8275
8276 if ((buf = MALLOC(cfg->osh, WLC_IOCTL_MAXLEN)) == NULL) {
8277 ANDROID_ERROR(("kmalloc failed\n"));
8278 return -1;
8279 }
8280
8281 error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
8282 if (unlikely(error)) {
8283 ANDROID_ERROR(("could not get ibss peer info (%d)\n", error));
8284 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8285 return -1;
8286 }
8287
8288 memcpy(&peer_list_info, buf, sizeof(peer_list_info));
8289 peer_list_info.version = htod16(peer_list_info.version);
8290 peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
8291 peer_list_info.count = htod32(peer_list_info.count);
8292
8293 ANDROID_INFO(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
8294 peer_list_info.bss_peer_info_len, peer_list_info.count));
8295
8296 if (peer_list_info.count > 0) {
8297 if (bAll)
8298 bytes_written += snprintf(&command[bytes_written], total_len, "%u ",
8299 peer_list_info.count);
8300
8301 peer_info = (bss_peer_info_t *) ((char *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
8302
8303 for (i = 0; i < peer_list_info.count; i++) {
8304
8305 ANDROID_INFO(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
8306 peer_info->tx_rate, peer_info->rx_rate));
8307
8308 if (!bAll &&
8309 memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
8310 found = true;
8311 }
8312
8313 if (bAll || found) {
8314 bytes_written += snprintf(&command[bytes_written],
8315 total_len - bytes_written,
8316 MACF" %u %d ", ETHER_TO_MACF(peer_info->ea),
8317 peer_info->tx_rate/1000, peer_info->rssi);
8318 if (bytes_written >= total_len) {
8319 ANDROID_ERROR(("wl_android_get_ibss_peer_info: Insufficient"
8320 " memory, %d bytes\n",
8321 total_len));
8322 bytes_written = -1;
8323 break;
8324 }
8325 }
8326
8327 if (found)
8328 break;
8329
8330 peer_info = (bss_peer_info_t *)((char *)peer_info+sizeof(bss_peer_info_t));
8331 }
8332 }
8333 else {
8334 ANDROID_ERROR(("could not get ibss peer info : no item\n"));
8335 }
8336 ANDROID_INFO(("command(%u):%s\n", total_len, command));
8337 ANDROID_INFO(("bytes_written:%d\n", bytes_written));
8338
8339 MFREE(cfg->osh, buf, WLC_IOCTL_MAXLEN);
8340 return bytes_written;
8341 }
8342
wl_android_set_ibss_routetable(struct net_device * dev,char * command)8343 int wl_android_set_ibss_routetable(struct net_device *dev, char *command)
8344 {
8345
8346 char *pcmd = command;
8347 char *str = NULL;
8348 ibss_route_tbl_t *route_tbl = NULL;
8349 char *ioctl_buf = NULL;
8350 s32 err = BCME_OK;
8351 uint32 route_tbl_len;
8352 uint32 entries;
8353 char *endptr;
8354 uint32 i = 0;
8355 struct ipv4_addr dipaddr;
8356 struct ether_addr ea;
8357 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8358
8359 route_tbl_len = sizeof(ibss_route_tbl_t) +
8360 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
8361 route_tbl = (ibss_route_tbl_t *)MALLOCZ(cfg->osh, route_tbl_len);
8362 if (!route_tbl) {
8363 ANDROID_ERROR(("Route TBL alloc failed\n"));
8364 return -ENOMEM;
8365 }
8366 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
8367 if (!ioctl_buf) {
8368 ANDROID_ERROR(("ioctl memory alloc failed\n"));
8369 if (route_tbl) {
8370 MFREE(cfg->osh, route_tbl, route_tbl_len);
8371 }
8372 return -ENOMEM;
8373 }
8374 bzero(ioctl_buf, WLC_IOCTL_MEDLEN);
8375
8376 /* drop command */
8377 str = bcmstrtok(&pcmd, " ", NULL);
8378
8379 /* get count */
8380 str = bcmstrtok(&pcmd, " ", NULL);
8381 if (!str) {
8382 ANDROID_ERROR(("Invalid number parameter %s\n", str));
8383 err = -EINVAL;
8384 goto exit;
8385 }
8386 entries = bcm_strtoul(str, &endptr, 0);
8387 if (*endptr != '\0') {
8388 ANDROID_ERROR(("Invalid number parameter %s\n", str));
8389 err = -EINVAL;
8390 goto exit;
8391 }
8392 if (entries > MAX_IBSS_ROUTE_TBL_ENTRY) {
8393 ANDROID_ERROR(("Invalid entries number %u\n", entries));
8394 err = -EINVAL;
8395 goto exit;
8396 }
8397
8398 ANDROID_INFO(("Routing table count:%u\n", entries));
8399 route_tbl->num_entry = entries;
8400
8401 for (i = 0; i < entries; i++) {
8402 str = bcmstrtok(&pcmd, " ", NULL);
8403 if (!str || !bcm_atoipv4(str, &dipaddr)) {
8404 ANDROID_ERROR(("Invalid ip string %s\n", str));
8405 err = -EINVAL;
8406 goto exit;
8407 }
8408
8409 str = bcmstrtok(&pcmd, " ", NULL);
8410 if (!str || !bcm_ether_atoe(str, &ea)) {
8411 ANDROID_ERROR(("Invalid ethernet string %s\n", str));
8412 err = -EINVAL;
8413 goto exit;
8414 }
8415 bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
8416 bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
8417 }
8418
8419 route_tbl_len = sizeof(ibss_route_tbl_t) +
8420 ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
8421 err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
8422 route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
8423 if (err != BCME_OK) {
8424 ANDROID_ERROR(("Fail to set iovar %d\n", err));
8425 err = -EINVAL;
8426 }
8427
8428 exit:
8429 if (route_tbl) {
8430 MFREE(cfg->osh, route_tbl, sizeof(ibss_route_tbl_t) +
8431 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t));
8432 }
8433 if (ioctl_buf) {
8434 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
8435 }
8436 return err;
8437
8438 }
8439
8440 int
wl_android_set_ibss_ampdu(struct net_device * dev,char * command,int total_len)8441 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
8442 {
8443 char *pcmd = command;
8444 char *str = NULL, *endptr = NULL;
8445 struct ampdu_aggr aggr;
8446 char smbuf[WLC_IOCTL_SMLEN];
8447 int idx;
8448 int err = 0;
8449 int wme_AC2PRIO[AC_COUNT][2] = {
8450 {PRIO_8021D_VO, PRIO_8021D_NC}, /* AC_VO - 3 */
8451 {PRIO_8021D_CL, PRIO_8021D_VI}, /* AC_VI - 2 */
8452 {PRIO_8021D_BK, PRIO_8021D_NONE}, /* AC_BK - 1 */
8453 {PRIO_8021D_BE, PRIO_8021D_EE}}; /* AC_BE - 0 */
8454
8455 ANDROID_INFO(("set ibss ampdu:%s\n", command));
8456
8457 bzero(&aggr, sizeof(aggr));
8458 /* Cofigure all priorities */
8459 aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
8460
8461 /* acquire parameters */
8462 /* drop command */
8463 str = bcmstrtok(&pcmd, " ", NULL);
8464
8465 for (idx = 0; idx < AC_COUNT; idx++) {
8466 bool on;
8467 str = bcmstrtok(&pcmd, " ", NULL);
8468 if (!str) {
8469 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8470 return -EINVAL;
8471 }
8472 on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
8473 if (*endptr != '\0') {
8474 ANDROID_ERROR(("Invalid number format %s\n", str));
8475 return -EINVAL;
8476 }
8477 if (on) {
8478 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
8479 setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
8480 }
8481 }
8482
8483 err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
8484 sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
8485
8486 return ((err == 0) ? total_len : err);
8487 }
8488
wl_android_set_ibss_antenna(struct net_device * dev,char * command,int total_len)8489 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
8490 {
8491 char *pcmd = command;
8492 char *str = NULL;
8493 int txchain, rxchain;
8494 int err = 0;
8495
8496 ANDROID_INFO(("set ibss antenna:%s\n", command));
8497
8498 /* acquire parameters */
8499 /* drop command */
8500 str = bcmstrtok(&pcmd, " ", NULL);
8501
8502 /* TX chain */
8503 str = bcmstrtok(&pcmd, " ", NULL);
8504 if (!str) {
8505 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8506 return -EINVAL;
8507 }
8508 txchain = bcm_atoi(str);
8509
8510 /* RX chain */
8511 str = bcmstrtok(&pcmd, " ", NULL);
8512 if (!str) {
8513 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
8514 return -EINVAL;
8515 }
8516 rxchain = bcm_atoi(str);
8517
8518 err = wldev_iovar_setint(dev, "txchain", txchain);
8519 if (err != 0)
8520 return err;
8521 err = wldev_iovar_setint(dev, "rxchain", rxchain);
8522 return ((err == 0)?total_len:err);
8523 }
8524 #endif /* WLAIBSS */
8525
wl_keep_alive_set(struct net_device * dev,char * extra)8526 int wl_keep_alive_set(struct net_device *dev, char* extra)
8527 {
8528 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
8529 int ret;
8530 uint period_msec = 0;
8531 char *buf;
8532 dhd_pub_t *dhd = dhd_get_pub(dev);
8533
8534 if (extra == NULL) {
8535 ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
8536 return -1;
8537 }
8538 if (sscanf(extra, "%d", &period_msec) != 1) {
8539 ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
8540 return -EINVAL;
8541 }
8542 ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
8543
8544 bzero(&mkeep_alive_pkt, sizeof(wl_mkeep_alive_pkt_t));
8545
8546 mkeep_alive_pkt.period_msec = period_msec;
8547 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
8548 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
8549
8550 /* Setup keep alive zero for null packet generation */
8551 mkeep_alive_pkt.keep_alive_id = 0;
8552 mkeep_alive_pkt.len_bytes = 0;
8553
8554 buf = (char *)MALLOC(dhd->osh, WLC_IOCTL_SMLEN);
8555 if (!buf) {
8556 ANDROID_ERROR(("%s: buffer alloc failed\n", __FUNCTION__));
8557 return BCME_NOMEM;
8558 }
8559 ret = wldev_iovar_setbuf(dev, "mkeep_alive", (char *)&mkeep_alive_pkt,
8560 WL_MKEEP_ALIVE_FIXED_LEN, buf, WLC_IOCTL_SMLEN, NULL);
8561 if (ret < 0)
8562 ANDROID_ERROR(("%s:keep_alive set failed:%d\n", __FUNCTION__, ret));
8563 else
8564 ANDROID_TRACE(("%s:keep_alive set ok\n", __FUNCTION__));
8565 MFREE(dhd->osh, buf, WLC_IOCTL_SMLEN);
8566 return ret;
8567 }
8568
8569 #ifdef P2PRESP_WFDIE_SRC
wl_android_get_wfdie_resp(struct net_device * dev,char * command,int total_len)8570 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
8571 {
8572 int error = 0;
8573 int bytes_written = 0;
8574 int only_resp_wfdsrc = 0;
8575
8576 error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
8577 if (error) {
8578 ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
8579 __FUNCTION__, error));
8580 return -1;
8581 }
8582
8583 bytes_written = snprintf(command, total_len, "%s %d",
8584 CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
8585
8586 return bytes_written;
8587 }
8588
wl_android_set_wfdie_resp(struct net_device * dev,int only_resp_wfdsrc)8589 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
8590 {
8591 int error = 0;
8592
8593 error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
8594 if (error) {
8595 ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
8596 __FUNCTION__, only_resp_wfdsrc, error));
8597 return -1;
8598 }
8599
8600 return 0;
8601 }
8602 #endif /* P2PRESP_WFDIE_SRC */
8603
8604 #ifdef BT_WIFI_HANDOVER
8605 static int
wl_tbow_teardown(struct net_device * dev)8606 wl_tbow_teardown(struct net_device *dev)
8607 {
8608 int err = BCME_OK;
8609 char buf[WLC_IOCTL_SMLEN];
8610 tbow_setup_netinfo_t netinfo;
8611 bzero(&netinfo, sizeof(netinfo));
8612 netinfo.opmode = TBOW_HO_MODE_TEARDOWN;
8613
8614 err = wldev_iovar_setbuf_bsscfg(dev, "tbow_doho", &netinfo,
8615 sizeof(tbow_setup_netinfo_t), buf, WLC_IOCTL_SMLEN, 0, NULL);
8616 if (err < 0) {
8617 ANDROID_ERROR(("tbow_doho iovar error %d\n", err));
8618 return err;
8619 }
8620 return err;
8621 }
8622 #endif /* BT_WIFI_HANOVER */
8623
wl_android_get_link_status(struct net_device * dev,char * command,int total_len)8624 static int wl_android_get_link_status(struct net_device *dev, char *command,
8625 int total_len)
8626 {
8627 int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
8628 uint32 rspec;
8629 uint encode, txexp;
8630 wl_bss_info_t *bi;
8631 int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
8632 char buf[WLC_IOCTL_SMLEN];
8633
8634 if (datalen > WLC_IOCTL_SMLEN) {
8635 ANDROID_ERROR(("data too big\n"));
8636 return -1;
8637 }
8638
8639 bzero(buf, datalen);
8640 /* get BSS information */
8641 *(u32 *) buf = htod32(datalen);
8642 error = wldev_ioctl_get(dev, WLC_GET_BSS_INFO, (void *)buf, datalen);
8643 if (unlikely(error)) {
8644 ANDROID_ERROR(("Could not get bss info %d\n", error));
8645 return -1;
8646 }
8647
8648 bi = (wl_bss_info_t*) (buf + sizeof(uint32));
8649
8650 for (i = 0; i < ETHER_ADDR_LEN; i++) {
8651 if (bi->BSSID.octet[i] > 0) {
8652 break;
8653 }
8654 }
8655
8656 if (i == ETHER_ADDR_LEN) {
8657 ANDROID_INFO(("No BSSID\n"));
8658 return -1;
8659 }
8660
8661 /* check VHT capability at beacon */
8662 if (bi->vht_cap) {
8663 if (CHSPEC_IS5G(bi->chanspec)) {
8664 result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
8665 }
8666 }
8667
8668 /* get a rspec (radio spectrum) rate */
8669 error = wldev_iovar_getint(dev, "nrate", &rspec);
8670 if (unlikely(error) || rspec == 0) {
8671 ANDROID_ERROR(("get link status error (%d)\n", error));
8672 return -1;
8673 }
8674
8675 /* referred wl_nrate_print() for the calculation */
8676 encode = (rspec & WL_RSPEC_ENCODING_MASK);
8677 txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
8678
8679 switch (encode) {
8680 case WL_RSPEC_ENCODE_HT:
8681 /* check Rx MCS Map for HT */
8682 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
8683 int8 bitmap = 0xFF;
8684 if (i == MAX_STREAMS_SUPPORTED-1) {
8685 bitmap = 0x7F;
8686 }
8687 if (bi->basic_mcs[i] & bitmap) {
8688 nss++;
8689 }
8690 }
8691 break;
8692 case WL_RSPEC_ENCODE_VHT:
8693 /* check Rx MCS Map for VHT */
8694 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
8695 mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
8696 if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
8697 nss++;
8698 }
8699 }
8700 break;
8701 }
8702
8703 /* check MIMO capability with nss in beacon */
8704 if (nss > 1) {
8705 result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
8706 }
8707
8708 /* Legacy rates WL_RSPEC_ENCODE_RATE are single stream, and
8709 * HT rates for mcs 0-7 are single stream.
8710 * In case of VHT NSS comes from rspec.
8711 */
8712 single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
8713 ((encode == WL_RSPEC_ENCODE_HT) && (rspec & WL_RSPEC_HT_MCS_MASK) < 8) ||
8714 ((encode == WL_RSPEC_ENCODE_VHT) &&
8715 ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
8716
8717 if (txexp == 0) {
8718 if ((rspec & WL_RSPEC_STBC) && single_stream) {
8719 stf = OLD_NRATE_STF_STBC;
8720 } else {
8721 stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
8722 }
8723 } else if (txexp == 1 && single_stream) {
8724 stf = OLD_NRATE_STF_CDD;
8725 }
8726
8727 /* check 11ac (VHT) */
8728 if (encode == WL_RSPEC_ENCODE_VHT) {
8729 if (CHSPEC_IS5G(bi->chanspec)) {
8730 result |= WL_ANDROID_LINK_VHT;
8731 }
8732 }
8733
8734 /* check MIMO */
8735 if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
8736 switch (stf) {
8737 case OLD_NRATE_STF_SISO:
8738 break;
8739 case OLD_NRATE_STF_CDD:
8740 case OLD_NRATE_STF_STBC:
8741 result |= WL_ANDROID_LINK_MIMO;
8742 break;
8743 case OLD_NRATE_STF_SDM:
8744 if (!single_stream) {
8745 result |= WL_ANDROID_LINK_MIMO;
8746 }
8747 break;
8748 }
8749 }
8750
8751 ANDROID_INFO(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
8752 __FUNCTION__, result, stf, single_stream, nss));
8753
8754 bytes_written = snprintf(command, total_len, "%s %d", CMD_GET_LINK_STATUS, result);
8755
8756 return bytes_written;
8757 }
8758
8759 #ifdef P2P_LISTEN_OFFLOADING
8760
8761 s32
wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 * cfg)8762 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
8763 {
8764 s32 bssidx;
8765 int ret = 0;
8766 int p2plo_pause = 0;
8767 dhd_pub_t *dhd = NULL;
8768 if (!cfg || !cfg->p2p) {
8769 ANDROID_ERROR(("Wl %p or cfg->p2p %p is null\n",
8770 cfg, cfg ? cfg->p2p : 0));
8771 return 0;
8772 }
8773
8774 dhd = (dhd_pub_t *)(cfg->pub);
8775 if (!dhd->up) {
8776 ANDROID_ERROR(("bus is already down\n"));
8777 return ret;
8778 }
8779
8780 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8781 ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
8782 "p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
8783 cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
8784 if (ret < 0) {
8785 ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8786 }
8787
8788 return ret;
8789 }
8790 s32
wl_cfg80211_p2plo_listen_start(struct net_device * dev,u8 * buf,int len)8791 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
8792 {
8793 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8794 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8795 wl_p2plo_listen_t p2plo_listen;
8796 int ret = -EAGAIN;
8797 int channel = 0;
8798 int period = 0;
8799 int interval = 0;
8800 int count = 0;
8801 if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
8802 ANDROID_ERROR(("Sending Action Frames. Try it again.\n"));
8803 goto exit;
8804 }
8805
8806 if (wl_get_drv_status_all(cfg, SCANNING)) {
8807 ANDROID_ERROR(("Scanning already\n"));
8808 goto exit;
8809 }
8810
8811 if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
8812 ANDROID_ERROR(("Scanning being aborted\n"));
8813 goto exit;
8814 }
8815
8816 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8817 ANDROID_ERROR(("p2p listen offloading already running\n"));
8818 goto exit;
8819 }
8820
8821 /* Just in case if it is not enabled */
8822 if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
8823 ANDROID_ERROR(("cfgp2p_enable discovery failed"));
8824 goto exit;
8825 }
8826
8827 bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
8828
8829 if (len) {
8830 sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
8831 if ((channel == 0) || (period == 0) ||
8832 (interval == 0) || (count == 0)) {
8833 ANDROID_ERROR(("Wrong argument %d/%d/%d/%d \n",
8834 channel, period, interval, count));
8835 ret = -EAGAIN;
8836 goto exit;
8837 }
8838 p2plo_listen.period = period;
8839 p2plo_listen.interval = interval;
8840 p2plo_listen.count = count;
8841
8842 ANDROID_ERROR(("channel:%d period:%d, interval:%d count:%d\n",
8843 channel, period, interval, count));
8844 } else {
8845 ANDROID_ERROR(("Argument len is wrong.\n"));
8846 ret = -EAGAIN;
8847 goto exit;
8848 }
8849
8850 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
8851 sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8852 bssidx, &cfg->ioctl_buf_sync)) < 0) {
8853 ANDROID_ERROR(("p2po_listen_channel Failed :%d\n", ret));
8854 goto exit;
8855 }
8856
8857 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
8858 sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8859 bssidx, &cfg->ioctl_buf_sync)) < 0) {
8860 ANDROID_ERROR(("p2po_listen Failed :%d\n", ret));
8861 goto exit;
8862 }
8863
8864 wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
8865 exit :
8866 return ret;
8867 }
8868 s32
wl_cfg80211_p2plo_listen_stop(struct net_device * dev)8869 wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
8870 {
8871 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8872 s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
8873 int ret = -EAGAIN;
8874
8875 if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
8876 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
8877 bssidx, &cfg->ioctl_buf_sync)) < 0) {
8878 ANDROID_ERROR(("p2po_stop Failed :%d\n", ret));
8879 goto exit;
8880 }
8881
8882 exit:
8883 return ret;
8884 }
8885
8886 s32
wl_cfg80211_p2plo_offload(struct net_device * dev,char * cmd,char * buf,int len)8887 wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
8888 {
8889 int ret = 0;
8890
8891 ANDROID_ERROR(("Entry cmd:%s arg_len:%d \n", cmd, len));
8892
8893 if (strncmp(cmd, "P2P_LO_START", strlen("P2P_LO_START")) == 0) {
8894 ret = wl_cfg80211_p2plo_listen_start(dev, buf, len);
8895 } else if (strncmp(cmd, "P2P_LO_STOP", strlen("P2P_LO_STOP")) == 0) {
8896 ret = wl_cfg80211_p2plo_listen_stop(dev);
8897 } else {
8898 ANDROID_ERROR(("Request for Unsupported CMD:%s \n", buf));
8899 ret = -EINVAL;
8900 }
8901 return ret;
8902 }
8903 void
wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 * cfg)8904 wl_cfg80211_cancel_p2plo(struct bcm_cfg80211 *cfg)
8905 {
8906 struct wireless_dev *wdev;
8907 if (!cfg) {
8908 return;
8909 }
8910
8911 wdev = bcmcfg_to_p2p_wdev(cfg);
8912
8913 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
8914 ANDROID_INFO(("P2P_FIND: Discovery offload is already in progress."
8915 "it aborted\n"));
8916 wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
8917 if (wdev != NULL) {
8918 #if defined(WL_CFG80211_P2P_DEV_IF)
8919 cfg80211_remain_on_channel_expired(wdev,
8920 cfg->last_roc_id,
8921 &cfg->remain_on_chan, GFP_KERNEL);
8922 #else
8923 cfg80211_remain_on_channel_expired(wdev,
8924 cfg->last_roc_id,
8925 &cfg->remain_on_chan,
8926 cfg->remain_on_chan_type, GFP_KERNEL);
8927 #endif /* WL_CFG80211_P2P_DEV_IF */
8928 }
8929 wl_cfg80211_p2plo_deinit(cfg);
8930 }
8931 }
8932 #endif /* P2P_LISTEN_OFFLOADING */
8933
8934 #ifdef WL_MURX
8935 int
wl_android_murx_bfe_cap(struct net_device * dev,int val)8936 wl_android_murx_bfe_cap(struct net_device *dev, int val)
8937 {
8938 int err = BCME_OK;
8939 int iface_count = wl_cfg80211_iface_count(dev);
8940 struct ether_addr bssid;
8941 wl_reassoc_params_t params;
8942
8943 if (iface_count > 1) {
8944 ANDROID_ERROR(("murx_bfe_cap change is not allowed when "
8945 "there are multiple interfaces\n"));
8946 return -EINVAL;
8947 }
8948 /* Now there is only single interface */
8949 err = wldev_iovar_setint(dev, "murx_bfe_cap", val);
8950 if (unlikely(err)) {
8951 ANDROID_ERROR(("Failed to set murx_bfe_cap IOVAR to %d,"
8952 "error %d\n", val, err));
8953 return err;
8954 }
8955
8956 /* If successful intiate a reassoc */
8957 bzero(&bssid, ETHER_ADDR_LEN);
8958 if ((err = wldev_ioctl_get(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN)) < 0) {
8959 ANDROID_ERROR(("Failed to get bssid, error=%d\n", err));
8960 return err;
8961 }
8962
8963 bzero(¶ms, sizeof(wl_reassoc_params_t));
8964 memcpy(¶ms.bssid, &bssid, ETHER_ADDR_LEN);
8965
8966 if ((err = wldev_ioctl_set(dev, WLC_REASSOC, ¶ms,
8967 sizeof(wl_reassoc_params_t))) < 0) {
8968 ANDROID_ERROR(("reassoc failed err:%d \n", err));
8969 } else {
8970 ANDROID_INFO(("reassoc issued successfully\n"));
8971 }
8972
8973 return err;
8974 }
8975 #endif /* WL_MURX */
8976
8977 #ifdef SUPPORT_RSSI_SUM_REPORT
8978 int
wl_android_get_rssi_per_ant(struct net_device * dev,char * command,int total_len)8979 wl_android_get_rssi_per_ant(struct net_device *dev, char *command, int total_len)
8980 {
8981 wl_rssi_ant_mimo_t rssi_ant_mimo;
8982 char *ifname = NULL;
8983 char *peer_mac = NULL;
8984 char *mimo_cmd = "mimo";
8985 char *pos, *token;
8986 int err = BCME_OK;
8987 int bytes_written = 0;
8988 bool mimo_rssi = FALSE;
8989
8990 bzero(&rssi_ant_mimo, sizeof(wl_rssi_ant_mimo_t));
8991 /*
8992 * STA I/F: DRIVER GET_RSSI_PER_ANT <ifname> <mimo>
8993 * AP/GO I/F: DRIVER GET_RSSI_PER_ANT <ifname> <Peer MAC addr> <mimo>
8994 */
8995 pos = command;
8996
8997 /* drop command */
8998 token = bcmstrtok(&pos, " ", NULL);
8999
9000 /* get the interface name */
9001 token = bcmstrtok(&pos, " ", NULL);
9002 if (!token) {
9003 ANDROID_ERROR(("Invalid arguments\n"));
9004 return -EINVAL;
9005 }
9006 ifname = token;
9007
9008 /* Optional: Check the MIMO RSSI mode or peer MAC address */
9009 token = bcmstrtok(&pos, " ", NULL);
9010 if (token) {
9011 /* Check the MIMO RSSI mode */
9012 if (strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9013 mimo_rssi = TRUE;
9014 } else {
9015 peer_mac = token;
9016 }
9017 }
9018
9019 /* Optional: Check the MIMO RSSI mode - RSSI sum across antennas */
9020 token = bcmstrtok(&pos, " ", NULL);
9021 if (token && strncmp(token, mimo_cmd, strlen(mimo_cmd)) == 0) {
9022 mimo_rssi = TRUE;
9023 }
9024
9025 err = wl_get_rssi_per_ant(dev, ifname, peer_mac, &rssi_ant_mimo);
9026 if (unlikely(err)) {
9027 ANDROID_ERROR(("Failed to get RSSI info, err=%d\n", err));
9028 return err;
9029 }
9030
9031 /* Parse the results */
9032 ANDROID_INFO(("ifname %s, version %d, count %d, mimo rssi %d\n",
9033 ifname, rssi_ant_mimo.version, rssi_ant_mimo.count, mimo_rssi));
9034 if (mimo_rssi) {
9035 ANDROID_INFO(("MIMO RSSI: %d\n", rssi_ant_mimo.rssi_sum));
9036 bytes_written = snprintf(command, total_len, "%s MIMO %d",
9037 CMD_GET_RSSI_PER_ANT, rssi_ant_mimo.rssi_sum);
9038 } else {
9039 int cnt;
9040 bytes_written = snprintf(command, total_len, "%s PER_ANT ", CMD_GET_RSSI_PER_ANT);
9041 for (cnt = 0; cnt < rssi_ant_mimo.count; cnt++) {
9042 ANDROID_INFO(("RSSI[%d]: %d\n", cnt, rssi_ant_mimo.rssi_ant[cnt]));
9043 bytes_written = snprintf(command, total_len, "%d ",
9044 rssi_ant_mimo.rssi_ant[cnt]);
9045 }
9046 }
9047
9048 return bytes_written;
9049 }
9050
9051 int
wl_android_set_rssi_logging(struct net_device * dev,char * command,int total_len)9052 wl_android_set_rssi_logging(struct net_device *dev, char *command, int total_len)
9053 {
9054 rssilog_set_param_t set_param;
9055 char *pos, *token;
9056 int err = BCME_OK;
9057
9058 bzero(&set_param, sizeof(rssilog_set_param_t));
9059 /*
9060 * DRIVER SET_RSSI_LOGGING <enable/disable> <RSSI Threshold> <Time Threshold>
9061 */
9062 pos = command;
9063
9064 /* drop command */
9065 token = bcmstrtok(&pos, " ", NULL);
9066
9067 /* enable/disable */
9068 token = bcmstrtok(&pos, " ", NULL);
9069 if (!token) {
9070 ANDROID_ERROR(("Invalid arguments\n"));
9071 return -EINVAL;
9072 }
9073 set_param.enable = bcm_atoi(token);
9074
9075 /* RSSI Threshold */
9076 token = bcmstrtok(&pos, " ", NULL);
9077 if (!token) {
9078 ANDROID_ERROR(("Invalid arguments\n"));
9079 return -EINVAL;
9080 }
9081 set_param.rssi_threshold = bcm_atoi(token);
9082
9083 /* Time Threshold */
9084 token = bcmstrtok(&pos, " ", NULL);
9085 if (!token) {
9086 ANDROID_ERROR(("Invalid arguments\n"));
9087 return -EINVAL;
9088 }
9089 set_param.time_threshold = bcm_atoi(token);
9090
9091 ANDROID_INFO(("enable %d, RSSI threshold %d, Time threshold %d\n", set_param.enable,
9092 set_param.rssi_threshold, set_param.time_threshold));
9093
9094 err = wl_set_rssi_logging(dev, (void *)&set_param);
9095 if (unlikely(err)) {
9096 ANDROID_ERROR(("Failed to configure RSSI logging: enable %d, RSSI Threshold %d,"
9097 " Time Threshold %d\n", set_param.enable, set_param.rssi_threshold,
9098 set_param.time_threshold));
9099 }
9100
9101 return err;
9102 }
9103
9104 int
wl_android_get_rssi_logging(struct net_device * dev,char * command,int total_len)9105 wl_android_get_rssi_logging(struct net_device *dev, char *command, int total_len)
9106 {
9107 rssilog_get_param_t get_param;
9108 int err = BCME_OK;
9109 int bytes_written = 0;
9110
9111 err = wl_get_rssi_logging(dev, (void *)&get_param);
9112 if (unlikely(err)) {
9113 ANDROID_ERROR(("Failed to get RSSI logging info\n"));
9114 return BCME_ERROR;
9115 }
9116
9117 ANDROID_INFO(("report_count %d, enable %d, rssi_threshold %d, time_threshold %d\n",
9118 get_param.report_count, get_param.enable, get_param.rssi_threshold,
9119 get_param.time_threshold));
9120
9121 /* Parse the parameter */
9122 if (!get_param.enable) {
9123 ANDROID_INFO(("RSSI LOGGING: Feature is disables\n"));
9124 bytes_written = snprintf(command, total_len,
9125 "%s FEATURE DISABLED\n", CMD_GET_RSSI_LOGGING);
9126 } else if (get_param.enable &
9127 (RSSILOG_FLAG_FEATURE_SW | RSSILOG_FLAG_REPORT_READY)) {
9128 if (!get_param.report_count) {
9129 ANDROID_INFO(("[PASS] RSSI difference across antennas is within"
9130 " threshold limits\n"));
9131 bytes_written = snprintf(command, total_len, "%s PASS\n",
9132 CMD_GET_RSSI_LOGGING);
9133 } else {
9134 ANDROID_INFO(("[FAIL] RSSI difference across antennas found "
9135 "to be greater than %3d dB\n", get_param.rssi_threshold));
9136 ANDROID_INFO(("[FAIL] RSSI difference check have failed for "
9137 "%d out of %d times\n", get_param.report_count,
9138 get_param.time_threshold));
9139 ANDROID_INFO(("[FAIL] RSSI difference is being monitored once "
9140 "per second, for a %d secs window\n", get_param.time_threshold));
9141 bytes_written = snprintf(command, total_len, "%s FAIL - RSSI Threshold "
9142 "%d dBm for %d out of %d times\n", CMD_GET_RSSI_LOGGING,
9143 get_param.rssi_threshold, get_param.report_count,
9144 get_param.time_threshold);
9145 }
9146 } else {
9147 ANDROID_INFO(("[BUSY] Reprot is not ready\n"));
9148 bytes_written = snprintf(command, total_len, "%s BUSY - NOT READY\n",
9149 CMD_GET_RSSI_LOGGING);
9150 }
9151
9152 return bytes_written;
9153 }
9154 #endif /* SUPPORT_RSSI_SUM_REPORT */
9155
9156 #ifdef SET_PCIE_IRQ_CPU_CORE
9157 void
wl_android_set_irq_cpucore(struct net_device * net,int affinity_cmd)9158 wl_android_set_irq_cpucore(struct net_device *net, int affinity_cmd)
9159 {
9160 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
9161 if (!dhdp) {
9162 ANDROID_ERROR(("dhd is NULL\n"));
9163 return;
9164 }
9165
9166 dhd_set_irq_cpucore(dhdp, affinity_cmd);
9167 }
9168 #endif /* SET_PCIE_IRQ_CPU_CORE */
9169
9170 #ifdef SUPPORT_LQCM
9171 static int
wl_android_lqcm_enable(struct net_device * net,int lqcm_enable)9172 wl_android_lqcm_enable(struct net_device *net, int lqcm_enable)
9173 {
9174 int err = 0;
9175
9176 err = wldev_iovar_setint(net, "lqcm", lqcm_enable);
9177 if (err != BCME_OK) {
9178 ANDROID_ERROR(("failed to set lqcm enable %d, error = %d\n", lqcm_enable, err));
9179 return -EIO;
9180 }
9181 return err;
9182 }
9183
9184 static int
wl_android_get_lqcm_report(struct net_device * dev,char * command,int total_len)9185 wl_android_get_lqcm_report(struct net_device *dev, char *command, int total_len)
9186 {
9187 int bytes_written, err = 0;
9188 uint32 lqcm_report = 0;
9189 uint32 lqcm_enable, tx_lqcm_idx, rx_lqcm_idx;
9190
9191 err = wldev_iovar_getint(dev, "lqcm", &lqcm_report);
9192 if (err != BCME_OK) {
9193 ANDROID_ERROR(("failed to get lqcm report, error = %d\n", err));
9194 return -EIO;
9195 }
9196 lqcm_enable = lqcm_report & LQCM_ENAB_MASK;
9197 tx_lqcm_idx = (lqcm_report & LQCM_TX_INDEX_MASK) >> LQCM_TX_INDEX_SHIFT;
9198 rx_lqcm_idx = (lqcm_report & LQCM_RX_INDEX_MASK) >> LQCM_RX_INDEX_SHIFT;
9199
9200 ANDROID_INFO(("lqcm report EN:%d, TX:%d, RX:%d\n", lqcm_enable, tx_lqcm_idx, rx_lqcm_idx));
9201
9202 bytes_written = snprintf(command, total_len, "%s %d",
9203 CMD_GET_LQCM_REPORT, lqcm_report);
9204
9205 return bytes_written;
9206 }
9207 #endif /* SUPPORT_LQCM */
9208
9209 int
wl_android_get_snr(struct net_device * dev,char * command,int total_len)9210 wl_android_get_snr(struct net_device *dev, char *command, int total_len)
9211 {
9212 int bytes_written, error = 0;
9213 s32 snr = 0;
9214
9215 error = wldev_iovar_getint(dev, "snr", &snr);
9216 if (error) {
9217 ANDROID_ERROR(("%s: Failed to get SNR %d, error = %d\n",
9218 __FUNCTION__, snr, error));
9219 return -EIO;
9220 }
9221
9222 bytes_written = snprintf(command, total_len, "snr %d", snr);
9223 ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
9224 return bytes_written;
9225 }
9226
9227 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
9228 int
wl_android_set_ap_beaconrate(struct net_device * dev,char * command)9229 wl_android_set_ap_beaconrate(struct net_device *dev, char *command)
9230 {
9231 int rate = 0;
9232 char *pos, *token;
9233 char *ifname = NULL;
9234 int err = BCME_OK;
9235
9236 /*
9237 * DRIVER SET_AP_BEACONRATE <rate> <ifname>
9238 */
9239 pos = command;
9240
9241 /* drop command */
9242 token = bcmstrtok(&pos, " ", NULL);
9243
9244 /* Rate */
9245 token = bcmstrtok(&pos, " ", NULL);
9246 if (!token)
9247 return -EINVAL;
9248 rate = bcm_atoi(token);
9249
9250 /* get the interface name */
9251 token = bcmstrtok(&pos, " ", NULL);
9252 if (!token)
9253 return -EINVAL;
9254 ifname = token;
9255
9256 ANDROID_INFO(("rate %d, ifacename %s\n", rate, ifname));
9257
9258 err = wl_set_ap_beacon_rate(dev, rate, ifname);
9259 if (unlikely(err)) {
9260 ANDROID_ERROR(("Failed to set ap beacon rate to %d, error = %d\n", rate, err));
9261 }
9262
9263 return err;
9264 }
9265
wl_android_get_ap_basicrate(struct net_device * dev,char * command,int total_len)9266 int wl_android_get_ap_basicrate(struct net_device *dev, char *command, int total_len)
9267 {
9268 char *pos, *token;
9269 char *ifname = NULL;
9270 int bytes_written = 0;
9271 /*
9272 * DRIVER GET_AP_BASICRATE <ifname>
9273 */
9274 pos = command;
9275
9276 /* drop command */
9277 token = bcmstrtok(&pos, " ", NULL);
9278
9279 /* get the interface name */
9280 token = bcmstrtok(&pos, " ", NULL);
9281 if (!token)
9282 return -EINVAL;
9283 ifname = token;
9284
9285 ANDROID_INFO(("ifacename %s\n", ifname));
9286
9287 bytes_written = wl_get_ap_basic_rate(dev, command, ifname, total_len);
9288 if (bytes_written < 1) {
9289 ANDROID_ERROR(("Failed to get ap basic rate, error = %d\n", bytes_written));
9290 return -EPROTO;
9291 }
9292
9293 return bytes_written;
9294 }
9295 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
9296
9297 #ifdef SUPPORT_AP_RADIO_PWRSAVE
9298 int
wl_android_get_ap_rps(struct net_device * dev,char * command,int total_len)9299 wl_android_get_ap_rps(struct net_device *dev, char *command, int total_len)
9300 {
9301 char *pos, *token;
9302 char *ifname = NULL;
9303 int bytes_written = 0;
9304 char name[IFNAMSIZ];
9305 /*
9306 * DRIVER GET_AP_RPS <ifname>
9307 */
9308 pos = command;
9309
9310 /* drop command */
9311 token = bcmstrtok(&pos, " ", NULL);
9312
9313 /* get the interface name */
9314 token = bcmstrtok(&pos, " ", NULL);
9315 if (!token)
9316 return -EINVAL;
9317 ifname = token;
9318
9319 strlcpy(name, ifname, sizeof(name));
9320 ANDROID_INFO(("ifacename %s\n", name));
9321
9322 bytes_written = wl_get_ap_rps(dev, command, name, total_len);
9323 if (bytes_written < 1) {
9324 ANDROID_ERROR(("Failed to get rps, error = %d\n", bytes_written));
9325 return -EPROTO;
9326 }
9327
9328 return bytes_written;
9329
9330 }
9331
9332 int
wl_android_set_ap_rps(struct net_device * dev,char * command,int total_len)9333 wl_android_set_ap_rps(struct net_device *dev, char *command, int total_len)
9334 {
9335 int enable = 0;
9336 char *pos, *token;
9337 char *ifname = NULL;
9338 int err = BCME_OK;
9339 char name[IFNAMSIZ];
9340
9341 /*
9342 * DRIVER SET_AP_RPS <0/1> <ifname>
9343 */
9344 pos = command;
9345
9346 /* drop command */
9347 token = bcmstrtok(&pos, " ", NULL);
9348
9349 /* Enable */
9350 token = bcmstrtok(&pos, " ", NULL);
9351 if (!token)
9352 return -EINVAL;
9353 enable = bcm_atoi(token);
9354
9355 /* get the interface name */
9356 token = bcmstrtok(&pos, " ", NULL);
9357 if (!token)
9358 return -EINVAL;
9359 ifname = token;
9360
9361 strlcpy(name, ifname, sizeof(name));
9362 ANDROID_INFO(("enable %d, ifacename %s\n", enable, name));
9363
9364 err = wl_set_ap_rps(dev, enable? TRUE: FALSE, name);
9365 if (unlikely(err)) {
9366 ANDROID_ERROR(("Failed to set rps, enable %d, error = %d\n", enable, err));
9367 }
9368
9369 return err;
9370 }
9371
9372 int
wl_android_set_ap_rps_params(struct net_device * dev,char * command,int total_len)9373 wl_android_set_ap_rps_params(struct net_device *dev, char *command, int total_len)
9374 {
9375 ap_rps_info_t rps;
9376 char *pos, *token;
9377 char *ifname = NULL;
9378 int err = BCME_OK;
9379 char name[IFNAMSIZ];
9380
9381 bzero(&rps, sizeof(rps));
9382 /*
9383 * DRIVER SET_AP_RPS_PARAMS <pps> <level> <quiettime> <assoccheck> <ifname>
9384 */
9385 pos = command;
9386
9387 /* drop command */
9388 token = bcmstrtok(&pos, " ", NULL);
9389
9390 /* pps */
9391 token = bcmstrtok(&pos, " ", NULL);
9392 if (!token)
9393 return -EINVAL;
9394 rps.pps = bcm_atoi(token);
9395
9396 /* level */
9397 token = bcmstrtok(&pos, " ", NULL);
9398 if (!token)
9399 return -EINVAL;
9400 rps.level = bcm_atoi(token);
9401
9402 /* quiettime */
9403 token = bcmstrtok(&pos, " ", NULL);
9404 if (!token)
9405 return -EINVAL;
9406 rps.quiet_time = bcm_atoi(token);
9407
9408 /* sta assoc check */
9409 token = bcmstrtok(&pos, " ", NULL);
9410 if (!token)
9411 return -EINVAL;
9412 rps.sta_assoc_check = bcm_atoi(token);
9413
9414 /* get the interface name */
9415 token = bcmstrtok(&pos, " ", NULL);
9416 if (!token)
9417 return -EINVAL;
9418 ifname = token;
9419 strlcpy(name, ifname, sizeof(name));
9420
9421 ANDROID_INFO(("pps %d, level %d, quiettime %d, sta_assoc_check %d, "
9422 "ifacename %s\n", rps.pps, rps.level, rps.quiet_time,
9423 rps.sta_assoc_check, name));
9424
9425 err = wl_update_ap_rps_params(dev, &rps, name);
9426 if (unlikely(err)) {
9427 ANDROID_ERROR(("Failed to update rps, pps %d, level %d, quiettime %d, "
9428 "sta_assoc_check %d, err = %d\n", rps.pps, rps.level, rps.quiet_time,
9429 rps.sta_assoc_check, err));
9430 }
9431
9432 return err;
9433 }
9434 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
9435
9436 #if defined(DHD_HANG_SEND_UP_TEST)
9437 void
wl_android_make_hang_with_reason(struct net_device * dev,const char * string_num)9438 wl_android_make_hang_with_reason(struct net_device *dev, const char *string_num)
9439 {
9440 dhd_make_hang_with_reason(dev, string_num);
9441 }
9442 #endif /* DHD_HANG_SEND_UP_TEST */
9443
9444 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
9445 static void
wl_android_check_priv_cmd_errors(struct net_device * dev)9446 wl_android_check_priv_cmd_errors(struct net_device *dev)
9447 {
9448 dhd_pub_t *dhdp;
9449 int memdump_mode;
9450
9451 if (!dev) {
9452 ANDROID_ERROR(("dev is NULL\n"));
9453 return;
9454 }
9455
9456 dhdp = wl_cfg80211_get_dhdp(dev);
9457 if (!dhdp) {
9458 ANDROID_ERROR(("dhdp is NULL\n"));
9459 return;
9460 }
9461
9462 #ifdef DHD_FW_COREDUMP
9463 memdump_mode = dhdp->memdump_enabled;
9464 #else
9465 /* Default enable if DHD doesn't support SOCRAM dump */
9466 memdump_mode = 1;
9467 #endif /* DHD_FW_COREDUMP */
9468
9469 if (report_hang_privcmd_err) {
9470 priv_cmd_errors++;
9471 } else {
9472 priv_cmd_errors = 0;
9473 }
9474
9475 /* Trigger HANG event only if memdump mode is enabled
9476 * due to customer's request
9477 */
9478 if (memdump_mode == DUMP_MEMFILE_BUGON &&
9479 (priv_cmd_errors > NUMBER_SEQUENTIAL_PRIVCMD_ERRORS)) {
9480 ANDROID_ERROR(("Send HANG event due to sequential private cmd errors\n"));
9481 priv_cmd_errors = 0;
9482 #ifdef DHD_FW_COREDUMP
9483 /* Take a SOCRAM dump */
9484 dhdp->memdump_type = DUMP_TYPE_SEQUENTIAL_PRIVCMD_ERROR;
9485 dhd_common_socram_dump(dhdp);
9486 #endif /* DHD_FW_COREDUMP */
9487 /* Send the HANG event to upper layer */
9488 dhdp->hang_reason = HANG_REASON_SEQUENTIAL_PRIVCMD_ERROR;
9489 dhd_os_check_hang(dhdp, 0, -EREMOTEIO);
9490 }
9491 }
9492 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
9493
9494 #ifdef DHD_PKT_LOGGING
9495 static int
wl_android_pktlog_filter_enable(struct net_device * dev,char * command,int total_len)9496 wl_android_pktlog_filter_enable(struct net_device *dev, char *command, int total_len)
9497 {
9498 int bytes_written = 0;
9499 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9500 dhd_pktlog_filter_t *filter;
9501 int err = BCME_OK;
9502
9503 if (!dhdp || !dhdp->pktlog) {
9504 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9505 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9506 return -EINVAL;
9507 }
9508
9509 filter = dhdp->pktlog->pktlog_filter;
9510
9511 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, TRUE);
9512 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, TRUE);
9513 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, TRUE);
9514
9515 if (err == BCME_OK) {
9516 bytes_written = snprintf(command, total_len, "OK");
9517 ANDROID_ERROR(("%s: pktlog filter enable success\n", __FUNCTION__));
9518 } else {
9519 ANDROID_ERROR(("%s: pktlog filter enable fail\n", __FUNCTION__));
9520 return BCME_ERROR;
9521 }
9522
9523 return bytes_written;
9524 }
9525
9526 static int
wl_android_pktlog_filter_disable(struct net_device * dev,char * command,int total_len)9527 wl_android_pktlog_filter_disable(struct net_device *dev, char *command, int total_len)
9528 {
9529 int bytes_written = 0;
9530 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9531 dhd_pktlog_filter_t *filter;
9532 int err = BCME_OK;
9533
9534 if (!dhdp || !dhdp->pktlog) {
9535 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9536 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9537 return -EINVAL;
9538 }
9539
9540 filter = dhdp->pktlog->pktlog_filter;
9541
9542 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXPKT_CASE, FALSE);
9543 err = dhd_pktlog_filter_enable(filter, PKTLOG_TXSTATUS_CASE, FALSE);
9544 err = dhd_pktlog_filter_enable(filter, PKTLOG_RXPKT_CASE, FALSE);
9545
9546 if (err == BCME_OK) {
9547 bytes_written = snprintf(command, total_len, "OK");
9548 ANDROID_ERROR(("%s: pktlog filter disable success\n", __FUNCTION__));
9549 } else {
9550 ANDROID_ERROR(("%s: pktlog filter disable fail\n", __FUNCTION__));
9551 return BCME_ERROR;
9552 }
9553
9554 return bytes_written;
9555 }
9556
9557 static int
wl_android_pktlog_filter_pattern_enable(struct net_device * dev,char * command,int total_len)9558 wl_android_pktlog_filter_pattern_enable(struct net_device *dev, char *command, int total_len)
9559 {
9560 int bytes_written = 0;
9561 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9562 dhd_pktlog_filter_t *filter;
9563 int err = BCME_OK;
9564
9565 if (!dhdp || !dhdp->pktlog) {
9566 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9567 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9568 return -EINVAL;
9569 }
9570
9571 filter = dhdp->pktlog->pktlog_filter;
9572
9573 if (strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1 > total_len) {
9574 return BCME_ERROR;
9575 }
9576
9577 err = dhd_pktlog_filter_pattern_enable(filter,
9578 command + strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE) + 1, TRUE);
9579
9580 if (err == BCME_OK) {
9581 bytes_written = snprintf(command, total_len, "OK");
9582 ANDROID_ERROR(("%s: pktlog filter pattern enable success\n", __FUNCTION__));
9583 } else {
9584 ANDROID_ERROR(("%s: pktlog filter pattern enable fail\n", __FUNCTION__));
9585 return BCME_ERROR;
9586 }
9587
9588 return bytes_written;
9589 }
9590
9591 static int
wl_android_pktlog_filter_pattern_disable(struct net_device * dev,char * command,int total_len)9592 wl_android_pktlog_filter_pattern_disable(struct net_device *dev, char *command, int total_len)
9593 {
9594 int bytes_written = 0;
9595 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9596 dhd_pktlog_filter_t *filter;
9597 int err = BCME_OK;
9598
9599 if (!dhdp || !dhdp->pktlog) {
9600 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9601 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9602 return -EINVAL;
9603 }
9604
9605 filter = dhdp->pktlog->pktlog_filter;
9606
9607 if (strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1 > total_len) {
9608 return BCME_ERROR;
9609 }
9610
9611 err = dhd_pktlog_filter_pattern_enable(filter,
9612 command + strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE) + 1, FALSE);
9613
9614 if (err == BCME_OK) {
9615 bytes_written = snprintf(command, total_len, "OK");
9616 ANDROID_ERROR(("%s: pktlog filter pattern disable success\n", __FUNCTION__));
9617 } else {
9618 ANDROID_ERROR(("%s: pktlog filter pattern disable fail\n", __FUNCTION__));
9619 return BCME_ERROR;
9620 }
9621
9622 return bytes_written;
9623 }
9624
9625 static int
wl_android_pktlog_filter_add(struct net_device * dev,char * command,int total_len)9626 wl_android_pktlog_filter_add(struct net_device *dev, char *command, int total_len)
9627 {
9628 int bytes_written = 0;
9629 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9630 dhd_pktlog_filter_t *filter;
9631 int err = BCME_OK;
9632
9633 if (!dhdp || !dhdp->pktlog) {
9634 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9635 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9636 return -EINVAL;
9637 }
9638
9639 filter = dhdp->pktlog->pktlog_filter;
9640
9641 if (strlen(CMD_PKTLOG_FILTER_ADD) + 1 > total_len) {
9642 return BCME_ERROR;
9643 }
9644
9645 err = dhd_pktlog_filter_add(filter, command + strlen(CMD_PKTLOG_FILTER_ADD) + 1);
9646
9647 if (err == BCME_OK) {
9648 bytes_written = snprintf(command, total_len, "OK");
9649 ANDROID_ERROR(("%s: pktlog filter add success\n", __FUNCTION__));
9650 } else {
9651 ANDROID_ERROR(("%s: pktlog filter add fail\n", __FUNCTION__));
9652 return BCME_ERROR;
9653 }
9654
9655 return bytes_written;
9656 }
9657
9658 static int
wl_android_pktlog_filter_del(struct net_device * dev,char * command,int total_len)9659 wl_android_pktlog_filter_del(struct net_device *dev, char *command, int total_len)
9660 {
9661 int bytes_written = 0;
9662 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9663 dhd_pktlog_filter_t *filter;
9664 int err = BCME_OK;
9665
9666 if (!dhdp || !dhdp->pktlog) {
9667 ANDROID_ERROR(("%s(): dhdp=%p pktlog=%p\n",
9668 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9669 return -EINVAL;
9670 }
9671
9672 filter = dhdp->pktlog->pktlog_filter;
9673
9674 if (strlen(CMD_PKTLOG_FILTER_DEL) + 1 > total_len) {
9675 DHD_PKT_LOG(("%s(): wrong cmd length %d found\n",
9676 __FUNCTION__, (int)strlen(CMD_PKTLOG_FILTER_DEL)));
9677 return BCME_ERROR;
9678 }
9679
9680 err = dhd_pktlog_filter_del(filter, command + strlen(CMD_PKTLOG_FILTER_DEL) + 1);
9681 if (err == BCME_OK) {
9682 bytes_written = snprintf(command, total_len, "OK");
9683 ANDROID_ERROR(("%s: pktlog filter del success\n", __FUNCTION__));
9684 } else {
9685 ANDROID_ERROR(("%s: pktlog filter del fail\n", __FUNCTION__));
9686 return BCME_ERROR;
9687 }
9688
9689 return bytes_written;
9690 }
9691
9692 static int
wl_android_pktlog_filter_info(struct net_device * dev,char * command,int total_len)9693 wl_android_pktlog_filter_info(struct net_device *dev, char *command, int total_len)
9694 {
9695 int bytes_written = 0;
9696 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9697 dhd_pktlog_filter_t *filter;
9698 int err = BCME_OK;
9699
9700 if (!dhdp || !dhdp->pktlog) {
9701 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9702 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9703 return -EINVAL;
9704 }
9705
9706 filter = dhdp->pktlog->pktlog_filter;
9707
9708 err = dhd_pktlog_filter_info(filter);
9709
9710 if (err == BCME_OK) {
9711 bytes_written = snprintf(command, total_len, "OK");
9712 ANDROID_ERROR(("%s: pktlog filter info success\n", __FUNCTION__));
9713 } else {
9714 ANDROID_ERROR(("%s: pktlog filter info fail\n", __FUNCTION__));
9715 return BCME_ERROR;
9716 }
9717
9718 return bytes_written;
9719 }
9720
9721 static int
wl_android_pktlog_start(struct net_device * dev,char * command,int total_len)9722 wl_android_pktlog_start(struct net_device *dev, char *command, int total_len)
9723 {
9724 int bytes_written = 0;
9725 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9726
9727 if (!dhdp || !dhdp->pktlog) {
9728 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9729 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9730 return -EINVAL;
9731 }
9732
9733 if (!dhdp->pktlog->pktlog_ring) {
9734 DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9735 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9736 return -EINVAL;
9737 }
9738
9739 atomic_set(&dhdp->pktlog->pktlog_ring->start, TRUE);
9740
9741 bytes_written = snprintf(command, total_len, "OK");
9742
9743 ANDROID_ERROR(("%s: pktlog start success\n", __FUNCTION__));
9744
9745 return bytes_written;
9746 }
9747
9748 static int
wl_android_pktlog_stop(struct net_device * dev,char * command,int total_len)9749 wl_android_pktlog_stop(struct net_device *dev, char *command, int total_len)
9750 {
9751 int bytes_written = 0;
9752 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9753
9754 if (!dhdp || !dhdp->pktlog) {
9755 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9756 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9757 return -EINVAL;
9758 }
9759
9760 if (!dhdp->pktlog->pktlog_ring) {
9761 DHD_PKT_LOG(("%s(): _pktlog_ring=%p\n",
9762 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9763 return -EINVAL;
9764 }
9765
9766 atomic_set(&dhdp->pktlog->pktlog_ring->start, FALSE);
9767
9768 bytes_written = snprintf(command, total_len, "OK");
9769
9770 ANDROID_ERROR(("%s: pktlog stop success\n", __FUNCTION__));
9771
9772 return bytes_written;
9773 }
9774
9775 static int
wl_android_pktlog_filter_exist(struct net_device * dev,char * command,int total_len)9776 wl_android_pktlog_filter_exist(struct net_device *dev, char *command, int total_len)
9777 {
9778 int bytes_written = 0;
9779 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9780 dhd_pktlog_filter_t *filter;
9781 uint32 id;
9782 bool exist = FALSE;
9783
9784 if (!dhdp || !dhdp->pktlog) {
9785 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9786 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9787 return -EINVAL;
9788 }
9789
9790 filter = dhdp->pktlog->pktlog_filter;
9791
9792 if (strlen(CMD_PKTLOG_FILTER_EXIST) + 1 > total_len) {
9793 return BCME_ERROR;
9794 }
9795
9796 exist = dhd_pktlog_filter_existed(filter, command + strlen(CMD_PKTLOG_FILTER_EXIST) + 1,
9797 &id);
9798
9799 if (exist) {
9800 bytes_written = snprintf(command, total_len, "TRUE");
9801 ANDROID_ERROR(("%s: pktlog filter pattern id: %d is existed\n", __FUNCTION__, id));
9802 } else {
9803 bytes_written = snprintf(command, total_len, "FALSE");
9804 ANDROID_ERROR(("%s: pktlog filter pattern id: %d is not existed\n", __FUNCTION__, id));
9805 }
9806
9807 return bytes_written;
9808 }
9809
9810 static int
wl_android_pktlog_minmize_enable(struct net_device * dev,char * command,int total_len)9811 wl_android_pktlog_minmize_enable(struct net_device *dev, char *command, int total_len)
9812 {
9813 int bytes_written = 0;
9814 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9815
9816 if (!dhdp || !dhdp->pktlog) {
9817 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9818 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9819 return -EINVAL;
9820 }
9821
9822 if (!dhdp->pktlog->pktlog_ring) {
9823 DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9824 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9825 return -EINVAL;
9826 }
9827
9828 dhdp->pktlog->pktlog_ring->pktlog_minmize = TRUE;
9829
9830 bytes_written = snprintf(command, total_len, "OK");
9831
9832 ANDROID_ERROR(("%s: pktlog pktlog_minmize enable\n", __FUNCTION__));
9833
9834 return bytes_written;
9835 }
9836
9837 static int
wl_android_pktlog_minmize_disable(struct net_device * dev,char * command,int total_len)9838 wl_android_pktlog_minmize_disable(struct net_device *dev, char *command, int total_len)
9839 {
9840 int bytes_written = 0;
9841 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9842
9843 if (!dhdp || !dhdp->pktlog) {
9844 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9845 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9846 return -EINVAL;
9847 }
9848
9849 if (!dhdp->pktlog->pktlog_ring) {
9850 DHD_PKT_LOG(("%s(): pktlog_ring=%p\n",
9851 __FUNCTION__, dhdp->pktlog->pktlog_ring));
9852 return -EINVAL;
9853 }
9854
9855 dhdp->pktlog->pktlog_ring->pktlog_minmize = FALSE;
9856
9857 bytes_written = snprintf(command, total_len, "OK");
9858
9859 ANDROID_ERROR(("%s: pktlog pktlog_minmize disable\n", __FUNCTION__));
9860
9861 return bytes_written;
9862 }
9863
9864 static int
wl_android_pktlog_change_size(struct net_device * dev,char * command,int total_len)9865 wl_android_pktlog_change_size(struct net_device *dev, char *command, int total_len)
9866 {
9867 int bytes_written = 0;
9868 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9869 int err = BCME_OK;
9870 int size;
9871
9872 if (!dhdp || !dhdp->pktlog) {
9873 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9874 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9875 return -EINVAL;
9876 }
9877
9878 if (strlen(CMD_PKTLOG_CHANGE_SIZE) + 1 > total_len) {
9879 return BCME_ERROR;
9880 }
9881
9882 size = bcm_strtoul(command + strlen(CMD_PKTLOG_CHANGE_SIZE) + 1, NULL, 0);
9883
9884 dhdp->pktlog->pktlog_ring =
9885 dhd_pktlog_ring_change_size(dhdp->pktlog->pktlog_ring, size);
9886 if (!dhdp->pktlog->pktlog_ring) {
9887 err = BCME_ERROR;
9888 }
9889
9890 if (err == BCME_OK) {
9891 bytes_written = snprintf(command, total_len, "OK");
9892 ANDROID_ERROR(("%s: pktlog change size success\n", __FUNCTION__));
9893 } else {
9894 ANDROID_ERROR(("%s: pktlog change size fail\n", __FUNCTION__));
9895 return BCME_ERROR;
9896 }
9897
9898 return bytes_written;
9899 }
9900
9901 static int
wl_android_pktlog_dbg_dump(struct net_device * dev,char * command,int total_len)9902 wl_android_pktlog_dbg_dump(struct net_device *dev, char *command, int total_len)
9903 {
9904 int bytes_written = 0;
9905 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9906 int err = BCME_OK;
9907
9908 if (!dhdp || !dhdp->pktlog) {
9909 DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
9910 __FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
9911 return -EINVAL;
9912 }
9913
9914 if (strlen(CMD_PKTLOG_DEBUG_DUMP) + 1 > total_len) {
9915 return BCME_ERROR;
9916 }
9917
9918 err = dhd_pktlog_debug_dump(dhdp);
9919 if (err == BCME_OK) {
9920 bytes_written = snprintf(command, total_len, "OK");
9921 ANDROID_INFO(("%s: pktlog dbg dump success\n", __FUNCTION__));
9922 } else {
9923 ANDROID_ERROR(("%s: pktlog dbg dump fail\n", __FUNCTION__));
9924 return BCME_ERROR;
9925 }
9926
9927 return bytes_written;
9928 }
9929 #endif /* DHD_PKT_LOGGING */
9930
9931 #if defined(CONFIG_TIZEN)
wl_android_set_powersave_mode(struct net_device * dev,char * command,int total_len)9932 static int wl_android_set_powersave_mode(
9933 struct net_device *dev, char* command, int total_len)
9934 {
9935 int pm;
9936
9937 int err = BCME_OK;
9938 #ifdef DHD_PM_OVERRIDE
9939 extern bool g_pm_override;
9940 #endif /* DHD_PM_OVERRIDE */
9941 sscanf(command, "%*s %10d", &pm);
9942 if (pm < PM_OFF || pm > PM_FAST) {
9943 ANDROID_ERROR(("check pm=%d\n", pm));
9944 return BCME_ERROR;
9945 }
9946
9947 #ifdef DHD_PM_OVERRIDE
9948 if (pm > PM_OFF) {
9949 g_pm_override = FALSE;
9950 }
9951 #endif /* DHD_PM_OVERRIDE */
9952
9953 err = wldev_ioctl_set(dev, WLC_SET_PM, &pm, sizeof(pm));
9954
9955 #ifdef DHD_PM_OVERRIDE
9956 if (pm == PM_OFF) {
9957 g_pm_override = TRUE;
9958 }
9959
9960 ANDROID_ERROR(("%s: PM:%d, pm_override=%d\n", __FUNCTION__, pm, g_pm_override));
9961 #endif /* DHD_PM_OVERRIDE */
9962 return err;
9963 }
9964
wl_android_get_powersave_mode(struct net_device * dev,char * command,int total_len)9965 static int wl_android_get_powersave_mode(
9966 struct net_device *dev, char *command, int total_len)
9967 {
9968 int err, bytes_written;
9969 int pm;
9970
9971 err = wldev_ioctl_get(dev, WLC_GET_PM, &pm, sizeof(pm));
9972 if (err != BCME_OK) {
9973 ANDROID_ERROR(("failed to get pm (%d)", err));
9974 return err;
9975 }
9976
9977 bytes_written = snprintf(command, total_len, "%s %d",
9978 CMD_POWERSAVEMODE_GET, pm);
9979
9980 return bytes_written;
9981 }
9982 #endif /* CONFIG_TIZEN */
9983
9984 #ifdef DHD_EVENT_LOG_FILTER
9985 uint32 dhd_event_log_filter_serialize(dhd_pub_t *dhdp, char *buf, uint32 tot_len, int type);
9986
9987 #ifdef DHD_EWPR_VER2
9988 uint32 dhd_event_log_filter_serialize_bit(dhd_pub_t *dhdp, char *buf, uint32 tot_len,
9989 int index1, int index2, int index3);
9990 #endif
9991
9992 static int
wl_android_ewp_filter(struct net_device * dev,char * command,uint32 tot_len)9993 wl_android_ewp_filter(struct net_device *dev, char *command, uint32 tot_len)
9994 {
9995 uint32 bytes_written = 0;
9996 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
9997 #ifdef DHD_EWPR_VER2
9998 int index1 = 0, index2 = 0, index3 = 0;
9999 unsigned char *index_str = (unsigned char *)(command +
10000 strlen(CMD_EWP_FILTER) + 1);
10001 #else
10002 int type = 0;
10003 #endif
10004
10005 if (!dhdp || !command) {
10006 ANDROID_ERROR(("%s(): dhdp=%p \n", __FUNCTION__, dhdp));
10007 return -EINVAL;
10008 }
10009
10010 if (!FW_SUPPORTED(dhdp, ecounters)) {
10011 ANDROID_ERROR(("does not support ecounters!\n"));
10012 return BCME_UNSUPPORTED;
10013 }
10014
10015 #ifdef DHD_EWPR_VER2
10016 if (strlen(command) > strlen(CMD_EWP_FILTER) + 1) {
10017 sscanf(index_str, "%10d %10d %10d", &index1, &index2, &index3);
10018 ANDROID_TRACE(("%s(): get index request: %d %d %d\n", __FUNCTION__,
10019 index1, index2, index3));
10020 }
10021 bytes_written += dhd_event_log_filter_serialize_bit(dhdp,
10022 &command[bytes_written], tot_len - bytes_written, index1, index2, index3);
10023 #else
10024 /* NEED TO GET TYPE if EXIST */
10025 type = 0;
10026
10027 bytes_written += dhd_event_log_filter_serialize(dhdp,
10028 &command[bytes_written], tot_len - bytes_written, type);
10029 #endif
10030
10031 return (int)bytes_written;
10032 }
10033 #endif /* DHD_EVENT_LOG_FILTER */
10034
10035 #ifdef SUPPORT_AP_SUSPEND
10036 int
wl_android_set_ap_suspend(struct net_device * dev,char * command,int total_len)10037 wl_android_set_ap_suspend(struct net_device *dev, char *command, int total_len)
10038 {
10039 int suspend = 0;
10040 char *pos, *token;
10041 char *ifname = NULL;
10042 int err = BCME_OK;
10043 char name[IFNAMSIZ];
10044
10045 /*
10046 * DRIVER SET_AP_SUSPEND <0/1> <ifname>
10047 */
10048 pos = command;
10049
10050 /* drop command */
10051 token = bcmstrtok(&pos, " ", NULL);
10052
10053 /* Enable */
10054 token = bcmstrtok(&pos, " ", NULL);
10055 if (!token) {
10056 return -EINVAL;
10057 }
10058 suspend = bcm_atoi(token);
10059
10060 /* get the interface name */
10061 token = bcmstrtok(&pos, " ", NULL);
10062 if (!token) {
10063 return -EINVAL;
10064 }
10065 ifname = token;
10066
10067 strlcpy(name, ifname, sizeof(name));
10068 ANDROID_INFO(("suspend %d, ifacename %s\n", suspend, name));
10069
10070 err = wl_set_ap_suspend(dev, suspend? TRUE: FALSE, name);
10071 if (unlikely(err)) {
10072 ANDROID_ERROR(("Failed to set suspend, suspend %d, error = %d\n", suspend, err));
10073 }
10074
10075 return err;
10076 }
10077 #endif /* SUPPORT_AP_SUSPEND */
10078
10079 #ifdef SUPPORT_AP_BWCTRL
10080 int
wl_android_set_ap_bw(struct net_device * dev,char * command,int total_len)10081 wl_android_set_ap_bw(struct net_device *dev, char *command, int total_len)
10082 {
10083 int bw = DOT11_OPER_MODE_20MHZ;
10084 char *pos, *token;
10085 char *ifname = NULL;
10086 int err = BCME_OK;
10087 char name[IFNAMSIZ];
10088
10089 /*
10090 * DRIVER SET_AP_BW <0/1/2> <ifname>
10091 * 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10092 * This is from operating mode field
10093 * in 8.4.1.50 of 802.11ac-2013
10094 */
10095 pos = command;
10096
10097 /* drop command */
10098 token = bcmstrtok(&pos, " ", NULL);
10099
10100 /* BW */
10101 token = bcmstrtok(&pos, " ", NULL);
10102 if (!token) {
10103 return -EINVAL;
10104 }
10105 bw = bcm_atoi(token);
10106
10107 /* get the interface name */
10108 token = bcmstrtok(&pos, " ", NULL);
10109 if (!token) {
10110 return -EINVAL;
10111 }
10112 ifname = token;
10113
10114 strlcpy(name, ifname, sizeof(name));
10115 ANDROID_INFO(("bw %d, ifacename %s\n", bw, name));
10116
10117 err = wl_set_ap_bw(dev, bw, name);
10118 if (unlikely(err)) {
10119 ANDROID_ERROR(("Failed to set bw, bw %d, error = %d\n", bw, err));
10120 }
10121
10122 return err;
10123 }
10124
10125 int
wl_android_get_ap_bw(struct net_device * dev,char * command,int total_len)10126 wl_android_get_ap_bw(struct net_device *dev, char *command, int total_len)
10127 {
10128 char *pos, *token;
10129 char *ifname = NULL;
10130 int bytes_written = 0;
10131 char name[IFNAMSIZ];
10132
10133 /*
10134 * DRIVER GET_AP_BW <ifname>
10135 * returns 0 : 20MHz, 1 : 40MHz, 2 : 80MHz 3: 80+80 or 160MHz
10136 * This is from operating mode field
10137 * in 8.4.1.50 of 802.11ac-2013
10138 */
10139 pos = command;
10140
10141 /* drop command */
10142 token = bcmstrtok(&pos, " ", NULL);
10143
10144 /* get the interface name */
10145 token = bcmstrtok(&pos, " ", NULL);
10146 if (!token) {
10147 return -EINVAL;
10148 }
10149 ifname = token;
10150
10151 strlcpy(name, ifname, sizeof(name));
10152 ANDROID_INFO(("ifacename %s\n", name));
10153
10154 bytes_written = wl_get_ap_bw(dev, command, name, total_len);
10155 if (bytes_written < 1) {
10156 ANDROID_ERROR(("Failed to get bw, error = %d\n", bytes_written));
10157 return -EPROTO;
10158 }
10159
10160 return bytes_written;
10161
10162 }
10163 #endif /* SUPPORT_AP_BWCTRL */
10164
10165 static int
wl_android_priv_cmd_log_enable_check(char * cmd)10166 wl_android_priv_cmd_log_enable_check(char* cmd)
10167 {
10168 int cnt = 0;
10169
10170 while (strlen(loging_params[cnt].command) > 0) {
10171 if (!strnicmp(cmd, loging_params[cnt].command,
10172 strlen(loging_params[cnt].command))) {
10173 return loging_params[cnt].enable;
10174 }
10175
10176 cnt++;
10177 }
10178
10179 return FALSE;
10180 }
10181
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr)10182 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr)
10183 {
10184 #define PRIVATE_COMMAND_MAX_LEN 8192
10185 #define PRIVATE_COMMAND_DEF_LEN 4096
10186 int ret = 0;
10187 char *command = NULL;
10188 int bytes_written = 0;
10189 android_wifi_priv_cmd priv_cmd;
10190 int buf_size = 0;
10191 dhd_pub_t *dhd = dhd_get_pub(net);
10192
10193 net_os_wake_lock(net);
10194
10195 if (!capable(CAP_NET_ADMIN)) {
10196 ret = -EPERM;
10197 goto exit;
10198 }
10199
10200 if (!ifr->ifr_data) {
10201 ret = -EINVAL;
10202 goto exit;
10203 }
10204
10205 #ifdef CONFIG_COMPAT
10206 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
10207 if (in_compat_syscall())
10208 #else
10209 if (is_compat_task())
10210 #endif
10211 {
10212 compat_android_wifi_priv_cmd compat_priv_cmd;
10213 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
10214 sizeof(compat_android_wifi_priv_cmd))) {
10215 ret = -EFAULT;
10216 goto exit;
10217
10218 }
10219 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
10220 priv_cmd.used_len = compat_priv_cmd.used_len;
10221 priv_cmd.total_len = compat_priv_cmd.total_len;
10222 } else
10223 #endif /* CONFIG_COMPAT */
10224 {
10225 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
10226 ret = -EFAULT;
10227 goto exit;
10228 }
10229 }
10230 if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
10231 ANDROID_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
10232 priv_cmd.total_len));
10233 ret = -EINVAL;
10234 goto exit;
10235 }
10236
10237 buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
10238 command = (char *)MALLOC(dhd->osh, (buf_size + 1));
10239 if (!command) {
10240 ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
10241 ret = -ENOMEM;
10242 goto exit;
10243 }
10244 if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
10245 ret = -EFAULT;
10246 goto exit;
10247 }
10248 command[priv_cmd.total_len] = '\0';
10249
10250 if (wl_android_priv_cmd_log_enable_check(command)) {
10251 ANDROID_ERROR(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__,
10252 command, ifr->ifr_name));
10253 }
10254 else {
10255 ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
10256
10257 }
10258
10259 bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
10260 if (bytes_written >= 0) {
10261 if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
10262 command[0] = '\0';
10263 }
10264 if (bytes_written >= priv_cmd.total_len) {
10265 ANDROID_ERROR(("%s: err. bytes_written:%d >= total_len:%d, buf_size:%d\n",
10266 __FUNCTION__, bytes_written, priv_cmd.total_len, buf_size));
10267
10268 ret = BCME_BUFTOOSHORT;
10269 goto exit;
10270 }
10271 bytes_written++;
10272 priv_cmd.used_len = bytes_written;
10273 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
10274 ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
10275 ret = -EFAULT;
10276 }
10277 }
10278 else {
10279 /* Propagate the error */
10280 ret = bytes_written;
10281 }
10282
10283 exit:
10284 #ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
10285 if (ret) {
10286 /* Avoid incrementing priv_cmd_errors in case of unsupported feature
10287 * or BUSY state specific to TWT commands
10288 */
10289 if (
10290 #ifdef WL_TWT
10291 ((ret != BCME_BUSY) &&
10292 ((strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) ||
10293 (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) ||
10294 (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0))) ||
10295 #endif /* WL_TWT */
10296 (ret != BCME_UNSUPPORTED)) {
10297 wl_android_check_priv_cmd_errors(net);
10298 }
10299 } else {
10300 priv_cmd_errors = 0;
10301 }
10302 #endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
10303 net_os_wake_unlock(net);
10304 MFREE(dhd->osh, command, (buf_size + 1));
10305 return ret;
10306 }
10307
10308 #ifdef WLADPS_PRIVATE_CMD
10309 static int
wl_android_set_adps_mode(struct net_device * dev,const char * string_num)10310 wl_android_set_adps_mode(struct net_device *dev, const char* string_num)
10311 {
10312 int err = 0, adps_mode;
10313 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10314 #ifdef DHD_PM_CONTROL_FROM_FILE
10315 if (g_pm_control) {
10316 return -EPERM;
10317 }
10318 #endif /* DHD_PM_CONTROL_FROM_FILE */
10319
10320 adps_mode = bcm_atoi(string_num);
10321 ANDROID_ERROR(("%s: SET_ADPS %d\n", __FUNCTION__, adps_mode));
10322
10323 if (!(adps_mode == 0 || adps_mode == 1)) {
10324 ANDROID_ERROR(("wl_android_set_adps_mode: Invalid value %d.\n", adps_mode));
10325 return -EINVAL;
10326 }
10327
10328 err = dhd_enable_adps(dhdp, adps_mode);
10329 if (err != BCME_OK) {
10330 ANDROID_ERROR(("failed to set adps mode %d, error = %d\n", adps_mode, err));
10331 return -EIO;
10332 }
10333 return err;
10334 }
10335 static int
wl_android_get_adps_mode(struct net_device * dev,char * command,int total_len)10336 wl_android_get_adps_mode(
10337 struct net_device *dev, char *command, int total_len)
10338 {
10339 int bytes_written, err = 0;
10340 uint len;
10341 char buf[WLC_IOCTL_SMLEN];
10342
10343 bcm_iov_buf_t iov_buf;
10344 bcm_iov_buf_t *ptr = NULL;
10345 wl_adps_params_v1_t *data = NULL;
10346
10347 uint8 *pdata = NULL;
10348 uint8 band, mode = 0;
10349
10350 bzero(&iov_buf, sizeof(iov_buf));
10351
10352 len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(band);
10353
10354 iov_buf.version = WL_ADPS_IOV_VER;
10355 iov_buf.len = sizeof(band);
10356 iov_buf.id = WL_ADPS_IOV_MODE;
10357
10358 pdata = (uint8 *)&iov_buf.data;
10359
10360 for (band = 1; band <= MAX_BANDS; band++) {
10361 pdata[0] = band;
10362 err = wldev_iovar_getbuf(dev, "adps", &iov_buf, len,
10363 buf, WLC_IOCTL_SMLEN, NULL);
10364 if (err != BCME_OK) {
10365 ANDROID_ERROR(("wl_android_get_adps_mode fail to get adps band %d(%d).\n",
10366 band, err));
10367 return -EIO;
10368 }
10369 ptr = (bcm_iov_buf_t *) buf;
10370 data = (wl_adps_params_v1_t *) ptr->data;
10371 mode = data->mode;
10372 if (mode != OFF) {
10373 break;
10374 }
10375 }
10376
10377 bytes_written = snprintf(command, total_len, "%s %d",
10378 CMD_GET_ADPS, mode);
10379 return bytes_written;
10380 }
10381
10382 #ifdef WLADPS_ENERGY_GAIN
10383 static int
wl_android_get_gain_adps(struct net_device * dev,char * command,int total_len)10384 wl_android_get_gain_adps(
10385 struct net_device *dev, char *command, int total_len)
10386 {
10387 int bytes_written;
10388
10389 int ret = 0;
10390 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
10391
10392 ret = dhd_event_log_filter_adps_energy_gain(dhdp);
10393 if (ret < 0) {
10394 return ret;
10395 }
10396
10397 ANDROID_INFO(("%s ADPS Energy Gain: %d uAh\n", __FUNCTION__, ret));
10398
10399 bytes_written = snprintf(command, total_len, "%s %d uAm",
10400 CMD_GET_GAIN_ADPS, ret);
10401
10402 return bytes_written;
10403 }
10404
10405 static int
wl_android_reset_gain_adps(struct net_device * dev,char * command)10406 wl_android_reset_gain_adps(
10407 struct net_device *dev, char *command)
10408 {
10409 int ret = BCME_OK;
10410
10411 bcm_iov_buf_t iov_buf;
10412 char buf[WLC_IOCTL_SMLEN] = {0, };
10413
10414 iov_buf.version = WL_ADPS_IOV_VER;
10415 iov_buf.id = WL_ADPS_IOV_RESET_GAIN;
10416 iov_buf.len = 0;
10417
10418 if ((ret = wldev_iovar_setbuf(dev, "adps", &iov_buf, sizeof(iov_buf),
10419 buf, sizeof(buf), NULL)) < 0) {
10420 ANDROID_ERROR(("%s fail to reset adps gain (%d)\n", __FUNCTION__, ret));
10421 }
10422
10423 return ret;
10424 }
10425 #endif /* WLADPS_ENERGY_GAIN */
10426 #endif /* WLADPS_PRIVATE_CMD */
10427
10428 #ifdef WL_BCNRECV
10429 #define BCNRECV_ATTR_HDR_LEN 30
10430 int
wl_android_bcnrecv_event(struct net_device * ndev,uint attr_type,uint status,uint reason,uint8 * data,uint data_len)10431 wl_android_bcnrecv_event(struct net_device *ndev, uint attr_type,
10432 uint status, uint reason, uint8 *data, uint data_len)
10433 {
10434 s32 err = BCME_OK;
10435 struct sk_buff *skb;
10436 gfp_t kflags;
10437 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10438 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
10439 uint len;
10440
10441 len = BCNRECV_ATTR_HDR_LEN + data_len;
10442
10443 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
10444 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev), len,
10445 BRCM_VENDOR_EVENT_BEACON_RECV, kflags);
10446 if (!skb) {
10447 ANDROID_ERROR(("skb alloc failed"));
10448 return -ENOMEM;
10449 }
10450 if ((attr_type == BCNRECV_ATTR_BCNINFO) && (data)) {
10451 /* send bcn info to upper layer */
10452 nla_put(skb, BCNRECV_ATTR_BCNINFO, data_len, data);
10453 } else if (attr_type == BCNRECV_ATTR_STATUS) {
10454 nla_put_u32(skb, BCNRECV_ATTR_STATUS, status);
10455 if (reason) {
10456 nla_put_u32(skb, BCNRECV_ATTR_REASON, reason);
10457 }
10458 } else {
10459 ANDROID_ERROR(("UNKNOWN ATTR_TYPE. attr_type:%d\n", attr_type));
10460 kfree_skb(skb);
10461 return -EINVAL;
10462 }
10463 cfg80211_vendor_event(skb, kflags);
10464 return err;
10465 }
10466
10467 static int
_wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev,bool user_trigger)10468 _wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool user_trigger)
10469 {
10470 s32 err = BCME_OK;
10471 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10472
10473 /* check any scan is in progress before beacon recv scan trigger IOVAR */
10474 if (wl_get_drv_status_all(cfg, SCANNING)) {
10475 err = BCME_UNSUPPORTED;
10476 ANDROID_ERROR(("Scan in progress, Aborting beacon recv start, "
10477 "error:%d\n", err));
10478 goto exit;
10479 }
10480
10481 if (wl_get_p2p_status(cfg, SCANNING)) {
10482 err = BCME_UNSUPPORTED;
10483 ANDROID_ERROR(("P2P Scan in progress, Aborting beacon recv start, "
10484 "error:%d\n", err));
10485 goto exit;
10486 }
10487
10488 if (wl_get_drv_status(cfg, REMAINING_ON_CHANNEL, ndev)) {
10489 err = BCME_UNSUPPORTED;
10490 ANDROID_ERROR(("P2P remain on channel, Aborting beacon recv start, "
10491 "error:%d\n", err));
10492 goto exit;
10493 }
10494
10495 /* check STA is in connected state, Beacon recv required connected state
10496 * else exit from beacon recv scan
10497 */
10498 if (!wl_get_drv_status(cfg, CONNECTED, ndev)) {
10499 err = BCME_UNSUPPORTED;
10500 ANDROID_ERROR(("STA is in not associated state error:%d\n", err));
10501 goto exit;
10502 }
10503
10504 #ifdef WL_NAN
10505 /* Check NAN is enabled, if enabled exit else continue */
10506 if (wl_cfgnan_is_enabled(cfg)) {
10507 err = BCME_UNSUPPORTED;
10508 ANDROID_ERROR(("Nan is enabled, NAN+STA+FAKEAP concurrency is not supported\n"));
10509 goto exit;
10510 }
10511 #endif /* WL_NAN */
10512
10513 /* Triggering an sendup_bcn iovar */
10514 err = wldev_iovar_setint(pdev, "sendup_bcn", 1);
10515 if (unlikely(err)) {
10516 ANDROID_ERROR(("sendup_bcn failed to set, error:%d\n", err));
10517 } else {
10518 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STARTED;
10519 ANDROID_INFO(("bcnrecv started. user_trigger:%d ifindex:%d\n",
10520 user_trigger, ndev->ifindex));
10521 if (user_trigger) {
10522 if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS,
10523 WL_BCNRECV_STARTED, 0, NULL, 0)) != BCME_OK) {
10524 ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10525 }
10526 }
10527 }
10528 exit:
10529 /*
10530 * BCNRECV start request can be rejected from dongle
10531 * in various conditions.
10532 * Error code need to be overridden to BCME_UNSUPPORTED
10533 * to avoid hang event from continous private
10534 * command error
10535 */
10536 if (err) {
10537 err = BCME_UNSUPPORTED;
10538 }
10539 return err;
10540 }
10541
10542 int
_wl_android_bcnrecv_stop(struct bcm_cfg80211 * cfg,struct net_device * ndev,uint reason)10543 _wl_android_bcnrecv_stop(struct bcm_cfg80211 *cfg, struct net_device *ndev, uint reason)
10544 {
10545 s32 err = BCME_OK;
10546 u32 status;
10547 struct net_device *pdev = bcmcfg_to_prmry_ndev(cfg);
10548
10549 /* Stop bcnrx except for fw abort event case */
10550 if (reason != WL_BCNRECV_ROAMABORT) {
10551 err = wldev_iovar_setint(pdev, "sendup_bcn", 0);
10552 if (unlikely(err)) {
10553 ANDROID_ERROR(("sendup_bcn failed to set error:%d\n", err));
10554 goto exit;
10555 }
10556 }
10557
10558 /* Send notification for all cases */
10559 if (reason == WL_BCNRECV_SUSPEND) {
10560 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_SUSPENDED;
10561 status = WL_BCNRECV_SUSPENDED;
10562 } else {
10563 cfg->bcnrecv_info.bcnrecv_state = BEACON_RECV_STOPPED;
10564 ANDROID_INFO(("bcnrecv stopped. reason:%d ifindex:%d\n",
10565 reason, ndev->ifindex));
10566 if (reason == WL_BCNRECV_USER_TRIGGER) {
10567 status = WL_BCNRECV_STOPPED;
10568 } else {
10569 status = WL_BCNRECV_ABORTED;
10570 }
10571 }
10572 if ((err = wl_android_bcnrecv_event(pdev, BCNRECV_ATTR_STATUS, status,
10573 reason, NULL, 0)) != BCME_OK) {
10574 ANDROID_ERROR(("failed to send bcnrecv event, error:%d\n", err));
10575 }
10576 exit:
10577 return err;
10578 }
10579
10580 static int
wl_android_bcnrecv_start(struct bcm_cfg80211 * cfg,struct net_device * ndev)10581 wl_android_bcnrecv_start(struct bcm_cfg80211 *cfg, struct net_device *ndev)
10582 {
10583 s32 err = BCME_OK;
10584
10585 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10586 mutex_lock(&cfg->scan_sync);
10587 mutex_lock(&cfg->bcn_sync);
10588 err = _wl_android_bcnrecv_start(cfg, ndev, true);
10589 mutex_unlock(&cfg->bcn_sync);
10590 mutex_unlock(&cfg->scan_sync);
10591 return err;
10592 }
10593
10594 int
wl_android_bcnrecv_stop(struct net_device * ndev,uint reason)10595 wl_android_bcnrecv_stop(struct net_device *ndev, uint reason)
10596 {
10597 s32 err = BCME_OK;
10598 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10599
10600 mutex_lock(&cfg->bcn_sync);
10601 if ((cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) ||
10602 (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED)) {
10603 err = _wl_android_bcnrecv_stop(cfg, ndev, reason);
10604 }
10605 mutex_unlock(&cfg->bcn_sync);
10606 return err;
10607 }
10608
10609 int
wl_android_bcnrecv_suspend(struct net_device * ndev)10610 wl_android_bcnrecv_suspend(struct net_device *ndev)
10611 {
10612 s32 ret = BCME_OK;
10613 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10614
10615 mutex_lock(&cfg->bcn_sync);
10616 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
10617 ANDROID_INFO(("bcnrecv suspend\n"));
10618 ret = _wl_android_bcnrecv_stop(cfg, ndev, WL_BCNRECV_SUSPEND);
10619 }
10620 mutex_unlock(&cfg->bcn_sync);
10621 return ret;
10622 }
10623
10624 int
wl_android_bcnrecv_resume(struct net_device * ndev)10625 wl_android_bcnrecv_resume(struct net_device *ndev)
10626 {
10627 s32 ret = BCME_OK;
10628 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
10629
10630 /* Adding scan_sync mutex to avoid race condition in b/w scan_req and bcn recv */
10631 mutex_lock(&cfg->scan_sync);
10632 mutex_lock(&cfg->bcn_sync);
10633 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_SUSPENDED) {
10634 ANDROID_INFO(("bcnrecv resume\n"));
10635 ret = _wl_android_bcnrecv_start(cfg, ndev, false);
10636 }
10637 mutex_unlock(&cfg->bcn_sync);
10638 mutex_unlock(&cfg->scan_sync);
10639 return ret;
10640 }
10641
10642 /* Beacon recv functionality code implementation */
10643 int
wl_android_bcnrecv_config(struct net_device * ndev,char * cmd_argv,int total_len)10644 wl_android_bcnrecv_config(struct net_device *ndev, char *cmd_argv, int total_len)
10645 {
10646 struct bcm_cfg80211 *cfg = NULL;
10647 uint err = BCME_OK;
10648
10649 if (!ndev) {
10650 ANDROID_ERROR(("ndev is NULL\n"));
10651 return -EINVAL;
10652 }
10653
10654 cfg = wl_get_cfg(ndev);
10655 if (!cfg) {
10656 ANDROID_ERROR(("cfg is NULL\n"));
10657 return -EINVAL;
10658 }
10659
10660 /* sync commands from user space */
10661 mutex_lock(&cfg->usr_sync);
10662 if (strncmp(cmd_argv, "start", strlen("start")) == 0) {
10663 ANDROID_INFO(("BCNRECV start\n"));
10664 err = wl_android_bcnrecv_start(cfg, ndev);
10665 if (err != BCME_OK) {
10666 ANDROID_ERROR(("Failed to process the start command, error:%d\n", err));
10667 goto exit;
10668 }
10669 } else if (strncmp(cmd_argv, "stop", strlen("stop")) == 0) {
10670 ANDROID_INFO(("BCNRECV stop\n"));
10671 err = wl_android_bcnrecv_stop(ndev, WL_BCNRECV_USER_TRIGGER);
10672 if (err != BCME_OK) {
10673 ANDROID_ERROR(("Failed to stop the bcn recv, error:%d\n", err));
10674 goto exit;
10675 }
10676 } else {
10677 err = BCME_ERROR;
10678 }
10679 exit:
10680 mutex_unlock(&cfg->usr_sync);
10681 return err;
10682 }
10683 #endif /* WL_BCNRECV */
10684
10685 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
10686 static int
wl_android_set_latency_crt_data(struct net_device * dev,int mode)10687 wl_android_set_latency_crt_data(struct net_device *dev, int mode)
10688 {
10689 int ret;
10690 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10691 dhd_pub_t *dhdp = NULL;
10692 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10693 if (mode >= LATENCY_CRT_DATA_MODE_LAST) {
10694 return BCME_BADARG;
10695 }
10696 #ifdef DHD_GRO_ENABLE_HOST_CTRL
10697 dhdp = wl_cfg80211_get_dhdp(dev);
10698 if (mode != LATENCY_CRT_DATA_MODE_OFF) {
10699 ANDROID_ERROR(("Not permitted GRO by framework\n"));
10700 dhdp->permitted_gro = FALSE;
10701 } else {
10702 ANDROID_ERROR(("Permitted GRO by framework\n"));
10703 dhdp->permitted_gro = TRUE;
10704 }
10705 #endif /* DHD_GRO_ENABLE_HOST_CTRL */
10706 ret = wldev_iovar_setint(dev, "latency_critical_data", mode);
10707 if (ret != BCME_OK) {
10708 ANDROID_ERROR(("failed to set latency_critical_data mode %d, error = %d\n",
10709 mode, ret));
10710 return ret;
10711 }
10712
10713 return ret;
10714 }
10715
10716 static int
wl_android_get_latency_crt_data(struct net_device * dev,char * command,int total_len)10717 wl_android_get_latency_crt_data(struct net_device *dev, char *command, int total_len)
10718 {
10719 int ret;
10720 int mode = LATENCY_CRT_DATA_MODE_OFF;
10721 int bytes_written;
10722
10723 ret = wldev_iovar_getint(dev, "latency_critical_data", &mode);
10724 if (ret != BCME_OK) {
10725 ANDROID_ERROR(("failed to get latency_critical_data error = %d\n", ret));
10726 return ret;
10727 }
10728
10729 bytes_written = snprintf(command, total_len, "%s %d",
10730 CMD_GET_LATENCY_CRITICAL_DATA, mode);
10731
10732 return bytes_written;
10733 }
10734 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
10735
10736 #ifdef WL_CAC_TS
10737 /* CAC TSPEC functionality code implementation */
10738 static void
wl_android_update_tsinfo(uint8 access_category,tspec_arg_t * tspec_arg)10739 wl_android_update_tsinfo(uint8 access_category, tspec_arg_t *tspec_arg)
10740 {
10741 uint8 tspec_id;
10742 /* Using direction as bidirectional by default */
10743 uint8 direction = TSPEC_BI_DIRECTION;
10744 /* Using U-APSD as the default power save mode */
10745 uint8 user_psb = TSPEC_UAPSD_PSB;
10746 uint8 ADDTS_AC2PRIO[4] = {PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_VI, PRIO_8021D_VO};
10747
10748 /* Map tspec_id from access category */
10749 tspec_id = ADDTS_AC2PRIO[access_category];
10750
10751 /* Update the tsinfo */
10752 tspec_arg->tsinfo.octets[0] = (uint8)(TSPEC_EDCA_ACCESS | direction |
10753 (tspec_id << TSPEC_TSINFO_TID_SHIFT));
10754 tspec_arg->tsinfo.octets[1] = (uint8)((tspec_id << TSPEC_TSINFO_PRIO_SHIFT) |
10755 user_psb);
10756 tspec_arg->tsinfo.octets[2] = 0x00;
10757 }
10758
10759 static s32
wl_android_handle_cac_action(struct bcm_cfg80211 * cfg,struct net_device * ndev,char * argv)10760 wl_android_handle_cac_action(struct bcm_cfg80211 * cfg, struct net_device * ndev, char * argv)
10761 {
10762 tspec_arg_t tspec_arg;
10763 s32 err = BCME_ERROR;
10764 u8 ts_cmd[12] = "cac_addts";
10765 uint8 access_category;
10766 s32 bssidx;
10767
10768 /* Following handling is done only for the primary interface */
10769 memset_s(&tspec_arg, sizeof(tspec_arg), 0, sizeof(tspec_arg));
10770 if (strncmp(argv, "addts", strlen("addts")) == 0) {
10771 tspec_arg.version = TSPEC_ARG_VERSION;
10772 tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10773 /* Read the params passed */
10774 sscanf(argv, "%*s %hhu %hu %hu", &access_category,
10775 &tspec_arg.nom_msdu_size, &tspec_arg.surplus_bw);
10776 if ((access_category > TSPEC_MAX_ACCESS_CATEGORY) ||
10777 ((tspec_arg.surplus_bw < TSPEC_MIN_SURPLUS_BW) ||
10778 (tspec_arg.surplus_bw > TSPEC_MAX_SURPLUS_BW)) ||
10779 (tspec_arg.nom_msdu_size > TSPEC_MAX_MSDU_SIZE)) {
10780 ANDROID_ERROR(("Invalid params access_category %hhu nom_msdu_size %hu"
10781 " surplus BW %hu\n", access_category, tspec_arg.nom_msdu_size,
10782 tspec_arg.surplus_bw));
10783 return BCME_USAGE_ERROR;
10784 }
10785
10786 /* Update tsinfo */
10787 wl_android_update_tsinfo(access_category, &tspec_arg);
10788 /* Update other tspec parameters */
10789 tspec_arg.dialog_token = TSPEC_DEF_DIALOG_TOKEN;
10790 tspec_arg.mean_data_rate = TSPEC_DEF_MEAN_DATA_RATE;
10791 tspec_arg.min_phy_rate = TSPEC_DEF_MIN_PHY_RATE;
10792 } else if (strncmp(argv, "delts", strlen("delts")) == 0) {
10793 snprintf(ts_cmd, sizeof(ts_cmd), "cac_delts");
10794 tspec_arg.length = sizeof(tspec_arg_t) - (2 * sizeof(uint16));
10795 tspec_arg.version = TSPEC_ARG_VERSION;
10796 /* Read the params passed */
10797 sscanf(argv, "%*s %hhu", &access_category);
10798
10799 if (access_category > TSPEC_MAX_ACCESS_CATEGORY) {
10800 ANDROID_INFO(("Invalide param, access_category %hhu\n", access_category));
10801 return BCME_USAGE_ERROR;
10802 }
10803 /* Update tsinfo */
10804 wl_android_update_tsinfo(access_category, &tspec_arg);
10805 }
10806
10807 if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr)) < 0) {
10808 ANDROID_ERROR(("Find index failed\n"));
10809 err = BCME_ERROR;
10810 return err;
10811 }
10812 err = wldev_iovar_setbuf_bsscfg(ndev, ts_cmd, &tspec_arg, sizeof(tspec_arg),
10813 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
10814 if (unlikely(err)) {
10815 ANDROID_ERROR(("%s error (%d)\n", ts_cmd, err));
10816 }
10817
10818 return err;
10819 }
10820
10821 static s32
wl_android_cac_ts_config(struct net_device * ndev,char * cmd_argv,int total_len)10822 wl_android_cac_ts_config(struct net_device *ndev, char *cmd_argv, int total_len)
10823 {
10824 struct bcm_cfg80211 *cfg = NULL;
10825 s32 err = BCME_OK;
10826
10827 if (!ndev) {
10828 ANDROID_ERROR(("ndev is NULL\n"));
10829 return -EINVAL;
10830 }
10831
10832 cfg = wl_get_cfg(ndev);
10833 if (!cfg) {
10834 ANDROID_ERROR(("cfg is NULL\n"));
10835 return -EINVAL;
10836 }
10837
10838 /* Request supported only for primary interface */
10839 if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
10840 ANDROID_ERROR(("Request on non-primary interface\n"));
10841 return -1;
10842 }
10843
10844 /* sync commands from user space */
10845 mutex_lock(&cfg->usr_sync);
10846 err = wl_android_handle_cac_action(cfg, ndev, cmd_argv);
10847 mutex_unlock(&cfg->usr_sync);
10848
10849 return err;
10850 }
10851 #endif /* WL_CAC_TS */
10852
10853 #ifdef WL_GET_CU
10854 /* Implementation to get channel usage from framework */
10855 static s32
wl_android_get_channel_util(struct net_device * ndev,char * command,int total_len)10856 wl_android_get_channel_util(struct net_device *ndev, char *command, int total_len)
10857 {
10858 s32 bytes_written, err = 0;
10859 wl_bssload_t bssload;
10860 u8 smbuf[WLC_IOCTL_SMLEN];
10861 u8 chan_use_percentage = 0;
10862
10863 if ((err = wldev_iovar_getbuf(ndev, "bssload_report", NULL,
10864 0, smbuf, WLC_IOCTL_SMLEN, NULL))) {
10865 ANDROID_ERROR(("Getting bssload report failed with err=%d \n", err));
10866 return err;
10867 }
10868
10869 (void)memcpy_s(&bssload, sizeof(wl_bssload_t), smbuf, sizeof(wl_bssload_t));
10870 /* Convert channel usage to percentage value */
10871 chan_use_percentage = (bssload.chan_util * 100) / 255;
10872
10873 bytes_written = snprintf(command, total_len, "CU %hhu",
10874 chan_use_percentage);
10875 ANDROID_INFO(("Channel Utilization %u %u\n", bssload.chan_util, chan_use_percentage));
10876
10877 return bytes_written;
10878 }
10879 #endif /* WL_GET_CU */
10880
10881 #ifdef RTT_GEOFENCE_INTERVAL
10882 #if defined (RTT_SUPPORT) && defined(WL_NAN)
10883 static void
wl_android_set_rtt_geofence_interval(struct net_device * ndev,char * command)10884 wl_android_set_rtt_geofence_interval(struct net_device *ndev, char *command)
10885 {
10886 int rtt_interval = 0;
10887 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
10888 char *rtt_intp = command + strlen(CMD_GEOFENCE_INTERVAL) + 1;
10889
10890 rtt_interval = bcm_atoi(rtt_intp);
10891 dhd_rtt_set_geofence_rtt_interval(dhdp, rtt_interval);
10892 }
10893 #endif /* RTT_SUPPORT && WL_NAN */
10894 #endif /* RTT_GEOFENCE_INTERVAL */
10895
10896 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
10897 int
wl_android_set_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10898 wl_android_set_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10899 {
10900 char *ifname = NULL;
10901 char *pos, *token;
10902 int err = BCME_OK;
10903 int enable = FALSE;
10904
10905 /*
10906 * STA/AP/GO I/F: DRIVER SET_SOFTAP_ELNA_BYPASS <ifname> <enable/disable>
10907 * the enable/disable format follows Samsung specific rules as following
10908 * Enable : 0
10909 * Disable :-1
10910 */
10911 pos = command;
10912
10913 /* drop command */
10914 token = bcmstrtok(&pos, " ", NULL);
10915
10916 /* get the interface name */
10917 token = bcmstrtok(&pos, " ", NULL);
10918 if (!token) {
10919 ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10920 return -EINVAL;
10921 }
10922 ifname = token;
10923
10924 /* get enable/disable flag */
10925 token = bcmstrtok(&pos, " ", NULL);
10926 if (!token) {
10927 ANDROID_ERROR(("%s: Invalid arguments about Enable/Disable\n", __FUNCTION__));
10928 return -EINVAL;
10929 }
10930 enable = bcm_atoi(token);
10931
10932 CUSTOMER_HW4_EN_CONVERT(enable);
10933 err = wl_set_softap_elna_bypass(dev, ifname, enable);
10934 if (unlikely(err)) {
10935 ANDROID_ERROR(("%s: Failed to set ELNA Bypass of SoftAP mode, err=%d\n",
10936 __FUNCTION__, err));
10937 return err;
10938 }
10939
10940 return err;
10941 }
10942
10943 int
wl_android_get_softap_elna_bypass(struct net_device * dev,char * command,int total_len)10944 wl_android_get_softap_elna_bypass(struct net_device *dev, char *command, int total_len)
10945 {
10946 char *ifname = NULL;
10947 char *pos, *token;
10948 int err = BCME_OK;
10949 int bytes_written = 0;
10950 int softap_elnabypass = 0;
10951
10952 /*
10953 * STA/AP/GO I/F: DRIVER GET_SOFTAP_ELNA_BYPASS <ifname>
10954 */
10955 pos = command;
10956
10957 /* drop command */
10958 token = bcmstrtok(&pos, " ", NULL);
10959
10960 /* get the interface name */
10961 token = bcmstrtok(&pos, " ", NULL);
10962 if (!token) {
10963 ANDROID_ERROR(("%s: Invalid arguments about interface name\n", __FUNCTION__));
10964 return -EINVAL;
10965 }
10966 ifname = token;
10967
10968 err = wl_get_softap_elna_bypass(dev, ifname, &softap_elnabypass);
10969 if (unlikely(err)) {
10970 ANDROID_ERROR(("%s: Failed to get ELNA Bypass of SoftAP mode, err=%d\n",
10971 __FUNCTION__, err));
10972 return err;
10973 } else {
10974 softap_elnabypass--; //Convert format to Customer HW4
10975 ANDROID_INFO(("%s: eLNA Bypass feature enable status is %d\n",
10976 __FUNCTION__, softap_elnabypass));
10977 bytes_written = snprintf(command, total_len, "%s %d",
10978 CMD_GET_SOFTAP_ELNA_BYPASS, softap_elnabypass);
10979 }
10980
10981 return bytes_written;
10982 }
10983 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
10984
10985 #ifdef WL_NAN
10986 int
wl_android_get_nan_status(struct net_device * dev,char * command,int total_len)10987 wl_android_get_nan_status(struct net_device *dev, char *command, int total_len)
10988 {
10989 int bytes_written = 0;
10990 int error = BCME_OK;
10991 wl_nan_conf_status_t nstatus;
10992
10993 error = wl_cfgnan_get_status(dev, &nstatus);
10994 if (error) {
10995 ANDROID_ERROR(("Failed to get nan status (%d)\n", error));
10996 return error;
10997 }
10998
10999 bytes_written = snprintf(command, total_len,
11000 "EN:%d Role:%d EM:%d CID:"MACF" NMI:"MACF" SC(2G):%d SC(5G):%d "
11001 "MR:"NMRSTR" AMR:"NMRSTR" IMR:"NMRSTR
11002 "HC:%d AMBTT:%04x TSF[%04x:%04x]\n",
11003 nstatus.enabled,
11004 nstatus.role,
11005 nstatus.election_mode,
11006 ETHERP_TO_MACF(&(nstatus.cid)),
11007 ETHERP_TO_MACF(&(nstatus.nmi)),
11008 nstatus.social_chans[0],
11009 nstatus.social_chans[1],
11010 NMR2STR(nstatus.mr),
11011 NMR2STR(nstatus.amr),
11012 NMR2STR(nstatus.imr),
11013 nstatus.hop_count,
11014 nstatus.ambtt,
11015 nstatus.cluster_tsf_h,
11016 nstatus.cluster_tsf_l);
11017 return bytes_written;
11018 }
11019 #endif /* WL_NAN */
11020
11021 #ifdef SUPPORT_NAN_RANGING_TEST_BW
11022 enum {
11023 NAN_RANGING_5G_BW20 = 1,
11024 NAN_RANGING_5G_BW40,
11025 NAN_RANGING_5G_BW80
11026 };
11027
11028 int
wl_nan_ranging_bw(struct net_device * net,int bw,char * command)11029 wl_nan_ranging_bw(struct net_device *net, int bw, char *command)
11030 {
11031 int bytes_written, err = BCME_OK;
11032 u8 ioctl_buf[WLC_IOCTL_SMLEN];
11033 s32 val = 1;
11034 struct {
11035 u32 band;
11036 u32 bw_cap;
11037 } param = {0, 0};
11038
11039 if (bw < NAN_RANGING_5G_BW20 || bw > NAN_RANGING_5G_BW80) {
11040 ANDROID_ERROR(("Wrong BW cmd:%d, %s\n", bw, __FUNCTION__));
11041 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11042 return bytes_written;
11043 }
11044
11045 switch (bw) {
11046 case NAN_RANGING_5G_BW20:
11047 ANDROID_ERROR(("NAN_RANGING 5G/BW20\n"));
11048 param.band = WLC_BAND_5G;
11049 param.bw_cap = 0x1;
11050 break;
11051 case NAN_RANGING_5G_BW40:
11052 ANDROID_ERROR(("NAN_RANGING 5G/BW40\n"));
11053 param.band = WLC_BAND_5G;
11054 param.bw_cap = 0x3;
11055 break;
11056 case NAN_RANGING_5G_BW80:
11057 ANDROID_ERROR(("NAN_RANGING 5G/BW80\n"));
11058 param.band = WLC_BAND_5G;
11059 param.bw_cap = 0x7;
11060 break;
11061 }
11062
11063 err = wldev_ioctl_set(net, WLC_DOWN, &val, sizeof(s32));
11064 if (err) {
11065 ANDROID_ERROR(("WLC_DOWN error %d\n", err));
11066 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11067 } else {
11068 err = wldev_iovar_setbuf(net, "bw_cap", ¶m, sizeof(param),
11069 ioctl_buf, sizeof(ioctl_buf), NULL);
11070
11071 if (err) {
11072 ANDROID_ERROR(("BW set failed\n"));
11073 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11074 } else {
11075 ANDROID_ERROR(("BW set done\n"));
11076 bytes_written = scnprintf(command, sizeof("OK"), "OK");
11077 }
11078
11079 err = wldev_ioctl_set(net, WLC_UP, &val, sizeof(s32));
11080 if (err < 0) {
11081 ANDROID_ERROR(("WLC_UP error %d\n", err));
11082 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
11083 }
11084 }
11085 return bytes_written;
11086 }
11087 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
11088
11089 static int
wl_android_set_softap_ax_mode(struct net_device * dev,const char * cmd_str)11090 wl_android_set_softap_ax_mode(struct net_device *dev, const char* cmd_str)
11091 {
11092 int enable = 0;
11093 int err = 0;
11094 s32 bssidx = 0;
11095 struct bcm_cfg80211 *cfg = NULL;
11096
11097 if (!dev) {
11098 err = -EINVAL;
11099 goto exit;
11100 }
11101
11102 cfg = wl_get_cfg(dev);
11103 if (!cfg) {
11104 err = -EINVAL;
11105 goto exit;
11106 }
11107
11108 if (cmd_str) {
11109 enable = bcm_atoi(cmd_str);
11110 } else {
11111 ANDROID_ERROR(("failed due to wrong received parameter\n"));
11112 err = -EINVAL;
11113 goto exit;
11114 }
11115
11116 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11117 ANDROID_ERROR(("find softap index from wdev failed\n"));
11118 err = -EINVAL;
11119 goto exit;
11120 }
11121
11122 ANDROID_INFO(("HAPD_SET_AX_MODE = %d\n", enable));
11123 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, WL_HE_FEATURES_HE_AP, (bool)enable);
11124 if (err) {
11125 ANDROID_ERROR(("failed to set softap ax mode(%d)\n", enable));
11126
11127 }
11128 exit :
11129 return err;
11130 }
11131
11132 #ifdef WL_P2P_6G
11133 #define WL_HE_FEATURES_P2P_6G 0x0200u
11134 static int
wl_android_enable_p2p_6g(struct net_device * dev,int enable)11135 wl_android_enable_p2p_6g(struct net_device *dev, int enable)
11136 {
11137 s32 err = 0;
11138 s32 bssidx = 0;
11139 struct bcm_cfg80211 *cfg = NULL;
11140
11141 if (!dev) {
11142 err = -EINVAL;
11143 return err;
11144 }
11145
11146 cfg = wl_get_cfg(dev);
11147 if (!cfg) {
11148 err = -EINVAL;
11149 return err;
11150 }
11151
11152 if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
11153 ANDROID_ERROR(("find softap index from wdev failed\n"));
11154 err = -EINVAL;
11155 return err;
11156 }
11157
11158 /* Enable/disable for P2P 6G, both P2P and P2P_6G needs to be handled together */
11159 err = wl_cfg80211_set_he_mode(dev, cfg, bssidx, (WL_HE_FEATURES_HE_P2P |
11160 WL_HE_FEATURES_P2P_6G), (bool)enable);
11161 if (err == BCME_OK) {
11162 /* Set P2P 6G support flag */
11163 if (enable) {
11164 cfg->p2p_6g_enabled = TRUE;
11165 } else {
11166 cfg->p2p_6g_enabled = FALSE;
11167 }
11168 }
11169
11170 return err;
11171 }
11172 #endif /* WL_P2P_6G */
11173
11174 #ifdef WL_TWT
11175
11176 static uint8
wl_twt_cmd2val(const char * name)11177 wl_twt_cmd2val(const char *name)
11178 {
11179 uint i;
11180
11181 for (i = 0; i < ARRAYSIZE(setup_cmd_val); i ++) {
11182 if (strcmp(name, setup_cmd_val[i].name) == 0) {
11183 return setup_cmd_val[i].val;
11184 }
11185 }
11186
11187 return WL_TWT_CMD_INVAL;
11188 }
11189
11190 static int
wl_android_twt_setup(struct net_device * ndev,char * command,int total_len)11191 wl_android_twt_setup(struct net_device *ndev, char *command, int total_len)
11192 {
11193 wl_twt_setup_t val;
11194 s32 bw = 0;
11195 char *token, *pos;
11196 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11197 u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
11198 uint8 *rem = mybuf;
11199 uint16 rem_len = sizeof(mybuf);
11200 uint8 tmp;
11201
11202 WL_DBG_MEM(("Enter. cmd:%s\n", command));
11203
11204 if (strlen(command) == strlen(CMD_TWT_SETUP)) {
11205 ANDROID_ERROR(("Error, twt_setup cmd missing params\n"));
11206 bw = -EINVAL;
11207 goto exit;
11208 }
11209
11210 bzero(&val, sizeof(val));
11211 val.version = WL_TWT_SETUP_VER;
11212 val.length = sizeof(val.version) + sizeof(val.length);
11213
11214 val.desc.bid = WL_TWT_INV_BCAST_ID;
11215 val.desc.flow_id = WL_TWT_INV_FLOW_ID;
11216 val.desc.btwt_persistence = WL_TWT_INFINITE_BTWT_PERSIST;
11217 val.desc.wake_type = WL_TWT_TIME_TYPE_AUTO;
11218
11219 pos = command + sizeof(CMD_TWT_SETUP);
11220
11221 /* setup_cmd */
11222 token = strsep((char**)&pos, " ");
11223 if (!token) {
11224 ANDROID_ERROR(("Mandaory param setup_cmd not present\n"));
11225 bw = -EINVAL;
11226 goto exit;
11227 }
11228
11229 val.desc.setup_cmd = wl_twt_cmd2val(token);
11230 if (val.desc.setup_cmd == WL_TWT_CMD_INVAL) {
11231 ANDROID_ERROR(("Unrecognized TWT Setup command '%s'\n", token));
11232 }
11233 ANDROID_INFO(("TWT_SETUP val.desc.setup_cmd %s\n", token));
11234
11235 /* negotiation_type */
11236 token = strsep((char**)&pos, " ");
11237 if (!token) {
11238 ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11239 bw = -EINVAL;
11240 goto exit;
11241 }
11242 val.desc.negotiation_type = htod32((u32)bcm_atoi(token));
11243 ANDROID_INFO(("TWT_SETUP val.desc.negotiation_type %d\n", val.desc.negotiation_type));
11244
11245 if (pos != NULL) {
11246 ANDROID_INFO(("TWT_SETUP string %s\n", pos));
11247 while ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11248 ANDROID_INFO(("TWT_SETUP token is %s\n", token));
11249
11250 if (!strnicmp(token, "u", 1)) {
11251 val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNANNOUNCED;
11252 }
11253 else if (!strnicmp(token, "t", 1)) {
11254 val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER;
11255 }
11256 else if (!strnicmp(token, "n", 1)) {
11257 val.desc.flow_flags |= WL_TWT_FLOW_FLAG_UNSOLICITED;
11258 }
11259 else if (!strnicmp(token, "p", 1)) {
11260 token++;
11261 val.desc.btwt_persistence = (int)simple_strtol(token, NULL, 0);
11262 ANDROID_INFO(("TWT_SETUP broadcast persistence %d\n",
11263 val.desc.btwt_persistence));
11264 }
11265 /* Wake Duration */
11266 else if (!strnicmp(token, "-d", 2)) {
11267 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11268 val.desc.wake_dur = (int)simple_strtol(token, NULL, 0);
11269 ANDROID_INFO(("TWT_SETUP val.desc.wake_dur %d\n",
11270 val.desc.wake_dur));
11271 }
11272 }
11273 /* Wake Interval */
11274 else if (!strnicmp(token, "-i", 2)) {
11275 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11276 val.desc.wake_int = (int)simple_strtol(token, NULL, 0);
11277 ANDROID_INFO(("TWT_SETUP val.desc.wake_int %d\n",
11278 val.desc.wake_int));
11279 }
11280 }
11281 /* flow id */
11282 else if (!strnicmp(token, "-f", 2)) {
11283 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11284 val.desc.flow_id = (int)simple_strtol(token, NULL, 0);
11285 ANDROID_INFO(("TWT_SETUP val.desc.flow_id %d\n",
11286 val.desc.flow_id));
11287 }
11288 }
11289 else if (!strnicmp(token, "-b", 2)) {
11290 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11291 val.desc.bid = (int)simple_strtol(token, NULL, 0);
11292 ANDROID_INFO(("TWT_SETUP val.desc.bid %d\n", val.desc.bid));
11293 }
11294 }
11295 else if (!strnicmp(token, "-r", 2)) {
11296 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11297 tmp = (int)simple_strtol(token, NULL, 0);
11298 if (tmp > TWT_BCAST_FRAME_RECOMM_3) {
11299 bw = -EINVAL;
11300 goto exit;
11301 }
11302 val.desc.bid = tmp;
11303 ANDROID_INFO(("TWT_SETUP frame recommendation %d\n",
11304 val.desc.frame_recomm));
11305 }
11306 }
11307 else if (!strnicmp(token, "-s", 2)) {
11308 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11309 val.desc.duty_cycle_min =
11310 (int)simple_strtol(token, NULL, 0);
11311 ANDROID_INFO(("TWT_SETUP duty_cycle_min %d\n",
11312 val.desc.duty_cycle_min));
11313 }
11314 }
11315 else if (!strnicmp(token, "-v", 2)) {
11316 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11317 val.desc.wake_int_max = (int)simple_strtol(token, NULL, 0);
11318 ANDROID_INFO(("TWT_SETUP wake_int_max %d\n",
11319 val.desc.wake_int_max));
11320 }
11321 }
11322 /* a peer_address */
11323 else if (!strnicmp(token, "-a", 2)) {
11324 if ((token = bcmstrtok(&pos, " ", 0)) != NULL) {
11325 if (!bcm_ether_atoe(token, &val.peer)) {
11326 ANDROID_ERROR(("%s : Malformed peer addr\n",
11327 __FUNCTION__));
11328 bw = -EINVAL;
11329 goto exit;
11330 }
11331 }
11332 }
11333 }
11334 }
11335
11336 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_SETUP,
11337 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11338 if (bw != BCME_OK) {
11339 goto exit;
11340 }
11341
11342 bw = wldev_iovar_setbuf(ndev, "twt",
11343 mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
11344 if (bw < 0) {
11345 ANDROID_ERROR(("twt setup failed. ret:%d\n", bw));
11346 }
11347 exit:
11348 return bw;
11349 }
11350
11351 static int
wl_android_twt_display_cap(wl_twt_cap_t * result,char * command,int total_len)11352 wl_android_twt_display_cap(wl_twt_cap_t *result, char *command, int total_len)
11353 {
11354 int rem_len = 0, bytes_written = 0;
11355
11356 rem_len = total_len;
11357 bytes_written = scnprintf(command, rem_len, "Device 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->device_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->device_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->device_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->device_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->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11383 command += bytes_written;
11384 rem_len -= bytes_written;
11385
11386 /* Peer capabilities */
11387 bytes_written = scnprintf(command, rem_len, "\nPeer TWT Capabilities:\n");
11388 command += bytes_written;
11389 rem_len -= bytes_written;
11390
11391 bytes_written = scnprintf(command, rem_len, "Requester Support %d, \t",
11392 !!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT));
11393 command += bytes_written;
11394 rem_len -= bytes_written;
11395
11396 bytes_written = scnprintf(command, rem_len, "Responder Support %d, \t",
11397 !!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT));
11398 command += bytes_written;
11399 rem_len -= bytes_written;
11400
11401 bytes_written = scnprintf(command, rem_len, "Broadcast TWT Support %d, \t",
11402 !!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT));
11403 command += bytes_written;
11404 rem_len -= bytes_written;
11405
11406 bytes_written = scnprintf(command, rem_len, "Flexible TWT Support %d, \t",
11407 !!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT));
11408 command += bytes_written;
11409 rem_len -= bytes_written;
11410
11411 bytes_written = scnprintf(command, rem_len, "TWT Required by peer %d, \n",
11412 !!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED));
11413 command += bytes_written;
11414 rem_len -= bytes_written;
11415
11416 bytes_written = scnprintf(command, rem_len, "\t------------"
11417 "---------------------------------------------------\n\n");
11418 command += bytes_written;
11419 rem_len -= bytes_written;
11420 ANDROID_INFO(("Device TWT Capabilities:\n"));
11421 ANDROID_INFO(("Requester Support %d, \t",
11422 !!(result->device_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11423 ANDROID_INFO(("Responder Support %d, \t",
11424 !!(result->device_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11425 ANDROID_INFO(("Broadcast TWT Support %d, \t",
11426 !!(result->device_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11427 ANDROID_INFO(("Flexible TWT Support %d, \t",
11428 !!(result->device_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11429 ANDROID_INFO(("TWT Required by peer %d, \n",
11430 !!(result->device_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11431 /* Peer capabilities */
11432 ANDROID_INFO(("\nPeer TWT Capabilities:\n"));
11433 ANDROID_INFO(("Requester Support %d, \t",
11434 !!(result->peer_cap & WL_TWT_CAP_FLAGS_REQ_SUPPORT)));
11435 ANDROID_INFO(("Responder Support %d, \t",
11436 !!(result->peer_cap & WL_TWT_CAP_FLAGS_RESP_SUPPORT)));
11437 ANDROID_INFO(("Broadcast TWT Support %d, \t",
11438 !!(result->peer_cap & WL_TWT_CAP_FLAGS_BTWT_SUPPORT)));
11439 ANDROID_INFO(("Flexible TWT Support %d, \t",
11440 !!(result->peer_cap & WL_TWT_CAP_FLAGS_FLEX_SUPPORT)));
11441 ANDROID_INFO(("TWT Required by peer %d, \n",
11442 !!(result->peer_cap & WL_TWT_CAP_FLAGS_TWT_REQUIRED)));
11443 ANDROID_INFO(("\t-----------------------------------------------------------------\n\n"));
11444
11445 if ((total_len - rem_len) > 0) {
11446 return (total_len - rem_len);
11447 } else {
11448 return BCME_ERROR;
11449 }
11450 }
11451
11452 static int
wl_android_twt_cap(struct net_device * dev,char * command,int total_len)11453 wl_android_twt_cap(struct net_device *dev, char *command, int total_len)
11454 {
11455 int ret = BCME_OK;
11456 char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11457 uint8 *pxtlv = NULL;
11458 uint8 *iovresp = NULL;
11459 wl_twt_cap_cmd_t cmd_cap;
11460 wl_twt_cap_t result;
11461
11462 uint16 buflen = 0, bufstart = 0;
11463 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11464
11465 bzero(&cmd_cap, sizeof(cmd_cap));
11466
11467 cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
11468 cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
11469
11470 iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11471 if (iovresp == NULL) {
11472 ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11473 goto exit;
11474 }
11475
11476 buflen = bufstart = WLC_IOCTL_SMLEN;
11477 pxtlv = (uint8 *)iovbuf;
11478
11479 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
11480 sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
11481 if (ret != BCME_OK) {
11482 ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11483 goto exit;
11484 }
11485
11486 if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11487 iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11488 ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11489 goto exit;
11490 }
11491 if (ret) {
11492 ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11493 }
11494
11495 (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11496
11497 if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
11498 ANDROID_ERROR(("capability ver %d, \n", dtoh16(result.version)));
11499 ret = wl_android_twt_display_cap(&result, command, total_len);
11500 return ret;
11501 } else {
11502 ret = BCME_UNSUPPORTED;
11503 ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11504 goto exit;
11505 }
11506
11507 exit:
11508 if (iovresp) {
11509 MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11510 }
11511
11512 return ret;
11513 }
11514
11515 static int
wl_android_twt_status_display_v1(wl_twt_status_v1_t * status,char * command,int total_len)11516 wl_android_twt_status_display_v1(wl_twt_status_v1_t *status, char *command, int total_len)
11517 {
11518 uint i;
11519 wl_twt_sdesc_t *desc = NULL;
11520 int rem_len = 0, bytes_written = 0;
11521
11522 rem_len = total_len;
11523
11524 ANDROID_ERROR(("\nNumber of Individual TWTs: %d\n", status->num_fid));
11525 bytes_written = scnprintf(command, rem_len,
11526 "\nNumber of Individual TWTs: %d\n", status->num_fid);
11527 command += bytes_written;
11528 rem_len -= bytes_written;
11529 bytes_written = scnprintf(command, rem_len,
11530 "Number of Broadcast TWTs: %d\n", status->num_bid);
11531 command += bytes_written;
11532 rem_len -= bytes_written;
11533 bytes_written = scnprintf(command, rem_len,
11534 "TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11535 !!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11536 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11537 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE));
11538 command += bytes_written;
11539 rem_len -= bytes_written;
11540 ANDROID_INFO(("Number of Broadcast TWTs: %d\n", status->num_bid));
11541 ANDROID_INFO(("TWT SPPS Enabled %d \t STA Wake Status %d \t Wake Override %d\n",
11542 !!(status->status_flags & WL_TWT_STATUS_FLAG_SPPS_ENAB),
11543 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_STATE),
11544 !!(status->status_flags & WL_TWT_STATUS_FLAG_WAKE_OVERRIDE)));
11545 ANDROID_INFO(("\t---------------- Individual TWT list-------------------\n"));
11546 bytes_written = scnprintf(command, rem_len,
11547 "\t---------------- Individual TWT list-------------------\n");
11548 command += bytes_written;
11549 rem_len -= bytes_written;
11550
11551 for (i = 0; i < WL_TWT_MAX_ITWT; i ++) {
11552 if ((status->itwt_status[i].state == WL_TWT_ACTIVE) ||
11553 (status->itwt_status[i].state == WL_TWT_SUSPEND)) {
11554 desc = &status->itwt_status[i].desc;
11555 bytes_written = scnprintf(command, rem_len, "\tFlow ID %d \tState %d\t",
11556 desc->flow_id,
11557 status->itwt_status[i].state);
11558 command += bytes_written;
11559 rem_len -= bytes_written;
11560
11561 bytes_written = scnprintf(command, rem_len,
11562 "peer: "MACF"\n",
11563 ETHER_TO_MACF(status->itwt_status[i].peer));
11564 command += bytes_written;
11565 rem_len -= bytes_written;
11566
11567 bytes_written = scnprintf(command, rem_len,
11568 "Unannounced %d\tTriggered %d\tProtection %d\t"
11569 "Info Frame Disabled %d\n",
11570 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11571 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11572 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11573 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11574 command += bytes_written;
11575 rem_len -= bytes_written;
11576
11577 bytes_written = scnprintf(command, rem_len,
11578 "target wake time: 0x%08x%08x\t",
11579 desc->wake_time_h, desc->wake_time_l);
11580 command += bytes_written;
11581 rem_len -= bytes_written;
11582
11583 bytes_written = scnprintf(command, rem_len,
11584 "wake duration: %u\t", desc->wake_dur);
11585 command += bytes_written;
11586 rem_len -= bytes_written;
11587
11588 bytes_written = scnprintf(command, rem_len,
11589 "wake interval: %u\t", desc->wake_int);
11590 command += bytes_written;
11591 rem_len -= bytes_written;
11592
11593 bytes_written = scnprintf(command, rem_len,
11594 "TWT channel: %u\n", desc->channel);
11595 command += bytes_written;
11596 rem_len -= bytes_written;
11597 ANDROID_INFO(("\tFlow ID %d \tState %d\t",
11598 desc->flow_id,
11599 status->itwt_status[i].state));
11600 ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->itwt_status[i].peer)));
11601 ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11602 "Info Frame Disabled %d\n",
11603 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11604 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11605 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11606 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11607 ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11608 desc->wake_time_h, desc->wake_time_l));
11609 ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11610 ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11611 ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11612 }
11613 }
11614
11615 ANDROID_INFO(("\t---------------- Broadcast TWT list-------------------\n"));
11616 bytes_written = scnprintf(command, rem_len,
11617 "\t---------------- Broadcast TWT list-------------------\n");
11618 command += bytes_written;
11619 rem_len -= bytes_written;
11620 for (i = 0; i < WL_TWT_MAX_BTWT; i ++) {
11621 if ((status->btwt_status[i].state == WL_TWT_ACTIVE) ||
11622 (status->btwt_status[i].state == WL_TWT_SUSPEND)) {
11623 desc = &status->btwt_status[i].desc;
11624 bytes_written = scnprintf(command, rem_len,
11625 "Broadcast ID %d \tState %d\t",
11626 desc->bid, status->btwt_status[i].state);
11627 command += bytes_written;
11628 rem_len -= bytes_written;
11629
11630 bytes_written = scnprintf(command, rem_len,
11631 "peer: "MACF"\n",
11632 ETHER_TO_MACF(status->btwt_status[i].peer));
11633 command += bytes_written;
11634 rem_len -= bytes_written;
11635
11636 bytes_written = scnprintf(command, rem_len,
11637 "Unannounced %d\tTriggered %d\tProtection %d\t"
11638 "Info Frame Disabled %d\t",
11639 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11640 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11641 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11642 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED));
11643 command += bytes_written;
11644 rem_len -= bytes_written;
11645
11646 bytes_written = scnprintf(command, rem_len,
11647 "Frame Recommendation %d\tBTWT Persistence %d\n",
11648 desc->frame_recomm, desc->btwt_persistence);
11649 command += bytes_written;
11650 rem_len -= bytes_written;
11651
11652 bytes_written = scnprintf(command, rem_len,
11653 "target wake time: 0x%08x%08x\t",
11654 desc->wake_time_h, desc->wake_time_l);
11655 command += bytes_written;
11656 rem_len -= bytes_written;
11657 bytes_written = scnprintf(command, rem_len,
11658 "wake duration: %u\t", desc->wake_dur);
11659 command += bytes_written;
11660 rem_len -= bytes_written;
11661
11662 bytes_written = scnprintf(command, rem_len,
11663 "wake interval: %u\t", desc->wake_int);
11664 command += bytes_written;
11665 rem_len -= bytes_written;
11666
11667 bytes_written = scnprintf(command, rem_len,
11668 "TWT channel: %u\n", desc->channel);
11669 command += bytes_written;
11670 rem_len -= bytes_written;
11671 ANDROID_INFO(("Broadcast ID %d \tState %d\t",
11672 desc->bid, status->btwt_status[i].state));
11673 ANDROID_INFO(("peer: "MACF"\n", ETHER_TO_MACF(status->btwt_status[i].peer)));
11674 ANDROID_INFO(("Unannounced %d\tTriggered %d\tProtection %d\t"
11675 "Info Frame Disabled %d\t",
11676 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_UNANNOUNCED),
11677 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER),
11678 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_PROTECT),
11679 !!(desc->flow_flags & WL_TWT_FLOW_FLAG_INFO_FRM_DISABLED)));
11680 ANDROID_INFO(("Frame Recommendation %d\tBTWT Persistence %d\n",
11681 desc->frame_recomm, desc->btwt_persistence));
11682 ANDROID_INFO(("target wake time: 0x%08x%08x\t",
11683 desc->wake_time_h, desc->wake_time_l));
11684 ANDROID_INFO(("wake duration: %u\t", desc->wake_dur));
11685 ANDROID_INFO(("wake interval: %u\t", desc->wake_int));
11686 ANDROID_INFO(("TWT channel: %u\n", desc->channel));
11687 }
11688 }
11689
11690 if ((total_len - rem_len) > 0) {
11691 return (total_len - rem_len);
11692 } else {
11693 return BCME_ERROR;
11694 }
11695 }
11696
11697 static int
wl_android_twt_status_query(struct net_device * dev,char * command,int total_len)11698 wl_android_twt_status_query(struct net_device *dev, char *command, int total_len)
11699 {
11700 int ret = BCME_OK;
11701 char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11702 uint8 *pxtlv = NULL;
11703 uint8 *iovresp = NULL;
11704 wl_twt_status_cmd_v1_t status_cmd;
11705 wl_twt_status_v1_t result;
11706
11707 uint16 buflen = 0, bufstart = 0;
11708 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11709
11710 bzero(&status_cmd, sizeof(status_cmd));
11711
11712 status_cmd.version = WL_TWT_CMD_STATUS_VERSION_1;
11713 status_cmd.length = sizeof(status_cmd) - OFFSETOF(wl_twt_status_cmd_v1_t, peer);
11714
11715 iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
11716 if (iovresp == NULL) {
11717 ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
11718 goto exit;
11719 }
11720
11721 buflen = bufstart = WLC_IOCTL_SMLEN;
11722 pxtlv = (uint8 *)iovbuf;
11723
11724 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATUS,
11725 sizeof(status_cmd), (uint8 *)&status_cmd, BCM_XTLV_OPTION_ALIGN32);
11726 if (ret != BCME_OK) {
11727 ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
11728 goto exit;
11729 }
11730
11731 if ((ret = wldev_iovar_getbuf(dev, "twt", iovbuf, bufstart-buflen,
11732 iovresp, WLC_IOCTL_MEDLEN, NULL))) {
11733 ANDROID_ERROR(("Getting twt status failed with err=%d \n", ret));
11734 goto exit;
11735 }
11736 if (ret) {
11737 ANDROID_ERROR(("%s : Error return during twt iovar set :%d\n", __FUNCTION__, ret));
11738 }
11739
11740 (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
11741
11742 if (dtoh16(result.version) == WL_TWT_CMD_STATUS_VERSION_1) {
11743 ANDROID_ERROR(("status query ver %d, \n", dtoh16(result.version)));
11744 ret = wl_android_twt_status_display_v1(&result, command, total_len);
11745 return ret;
11746 } else {
11747 ret = BCME_UNSUPPORTED;
11748 ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
11749 goto exit;
11750 }
11751
11752 exit:
11753 if (iovresp) {
11754 MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
11755 }
11756
11757 return ret;
11758 }
11759
11760 static int
wl_android_twt_info(struct net_device * ndev,char * command,int total_len)11761 wl_android_twt_info(struct net_device *ndev, char *command, int total_len)
11762 {
11763 wl_twt_info_t val;
11764 s32 bw;
11765 char *token, *pos;
11766 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11767 u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11768 u64 twt;
11769 uint8 *rem = mybuf;
11770 uint16 rem_len = sizeof(mybuf);
11771 int32 val32;
11772
11773 WL_DBG_MEM(("Enter. cmd:%s\n", command));
11774
11775 if (strlen(command) == strlen(CMD_TWT_INFO)) {
11776 ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11777 bw = -EINVAL;
11778 goto exit;
11779 }
11780
11781 bzero(&val, sizeof(val));
11782 val.version = WL_TWT_INFO_VER;
11783 val.length = sizeof(val.version) + sizeof(val.length);
11784
11785 /* Default values, Overide Below */
11786 val.infodesc.flow_id = 0xFF;
11787 val.desc.next_twt_h = 0xFFFFFFFF;
11788 val.desc.next_twt_l = 0xFFFFFFFF;
11789
11790 pos = command + sizeof(CMD_TWT_TEARDOWN);
11791
11792 /* (all TWT) */
11793 token = strsep((char**)&pos, " ");
11794 if (!token) {
11795 ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11796 bw = -EINVAL;
11797 goto exit;
11798 }
11799 if (htod32((u32)bcm_atoi(token)) == 1) {
11800 val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
11801 }
11802
11803 /* Flow ID */
11804 token = strsep((char**)&pos, " ");
11805 if (!token) {
11806 ANDROID_ERROR(("flow ID not provided, using default\n"));
11807 } else {
11808 val32 = htod32((u32)bcm_atoi(token));
11809 if (val32 != -1) {
11810 val.infodesc.flow_id = htod32((u32)bcm_atoi(token));
11811 }
11812 }
11813
11814 /* resume offset */
11815 token = strsep((char**)&pos, " ");
11816 if (!token) {
11817 ANDROID_ERROR(("resume offset not provided, using default\n"));
11818 } else {
11819 twt = (u64)bcm_atoi(token);
11820 val32 = htod32((u32)(twt >> 32));
11821 if ((val32 != -1) && ((int32)(htod32((u32)twt)) != -1)) {
11822 val.infodesc.next_twt_h = htod32((u32)(twt >> 32));
11823 val.infodesc.next_twt_l = htod32((u32)twt);
11824 val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
11825 }
11826 }
11827
11828 /* peer_address */
11829 token = strsep((char**)&pos, " ");
11830 if (!token) {
11831 ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11832 } else {
11833 /* get peer mac */
11834 if (!bcm_ether_atoe(token, &val.peer)) {
11835 ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11836 bw = BCME_ERROR;
11837 goto exit;
11838 }
11839 }
11840
11841 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
11842 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11843 if (bw != BCME_OK) {
11844 goto exit;
11845 }
11846
11847 bw = wldev_iovar_setbuf(ndev, "twt",
11848 mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11849 if (bw < 0) {
11850 ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11851 }
11852 exit:
11853 return bw;
11854
11855 }
11856
11857 static int
wl_android_twt_teardown(struct net_device * ndev,char * command,int total_len)11858 wl_android_twt_teardown(struct net_device *ndev, char *command, int total_len)
11859 {
11860 wl_twt_teardown_t val;
11861 s32 bw;
11862 char *token, *pos;
11863 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
11864 u8 res_buf[WLC_IOCTL_SMLEN] = {0};
11865 uint8 *rem = mybuf;
11866 uint16 rem_len = sizeof(mybuf);
11867 int32 val32;
11868
11869 WL_DBG_MEM(("Enter. cmd:%s\n", command));
11870
11871 if (strlen(command) == strlen(CMD_TWT_TEARDOWN)) {
11872 ANDROID_ERROR(("Error, twt teardown cmd missing params\n"));
11873 bw = -EINVAL;
11874 goto exit;
11875 }
11876
11877 bzero(&val, sizeof(val));
11878 val.version = WL_TWT_TEARDOWN_VER;
11879 val.length = sizeof(val.version) + sizeof(val.length);
11880
11881 /* Default values, Overide Below */
11882 val.teardesc.flow_id = 0xFF;
11883 val.teardesc.bid = 0xFF;
11884
11885 pos = command + sizeof(CMD_TWT_TEARDOWN);
11886
11887 /* negotiation_type */
11888 token = strsep((char**)&pos, " ");
11889 if (!token) {
11890 ANDROID_ERROR(("Mandatory param negotiation type not present\n"));
11891 bw = -EINVAL;
11892 goto exit;
11893 }
11894 val.teardesc.negotiation_type = htod32((u32)bcm_atoi(token));
11895
11896 /* (all TWT) */
11897 token = strsep((char**)&pos, " ");
11898 if (!token) {
11899 ANDROID_ERROR(("Mandatory all TWT type not present\n"));
11900 bw = -EINVAL;
11901 goto exit;
11902 }
11903 val.teardesc.alltwt = htod32((u32)bcm_atoi(token));
11904
11905 /* Flow ID */
11906 token = strsep((char**)&pos, " ");
11907 if (!token) {
11908 ANDROID_ERROR(("flow ID not provided, using default\n"));
11909 } else {
11910 val32 = htod32((u32)bcm_atoi(token));
11911 if (val32 != -1) {
11912 val.teardesc.flow_id = htod32((u32)bcm_atoi(token));
11913 }
11914 }
11915
11916 /* Broadcas ID */
11917 token = strsep((char**)&pos, " ");
11918 if (!token) {
11919 ANDROID_ERROR(("flow ID not provided, using default\n"));
11920 } else {
11921 val32 = htod32((u32)bcm_atoi(token));
11922 if (val32 != -1) {
11923 val.teardesc.bid = htod32((u32)bcm_atoi(token));
11924 }
11925 }
11926
11927 /* peer_address */
11928 token = strsep((char**)&pos, " ");
11929 if (!token) {
11930 ANDROID_ERROR(("Peer Addr not provided, using default\n"));
11931 } else {
11932 /* get peer mac */
11933 if (!bcm_ether_atoe(token, &val.peer)) {
11934 ANDROID_ERROR(("%s : Malformed peer addr\n", __FUNCTION__));
11935 bw = BCME_ERROR;
11936 goto exit;
11937 }
11938 }
11939
11940 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
11941 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
11942 if (bw != BCME_OK) {
11943 goto exit;
11944 }
11945
11946 bw = wldev_iovar_setbuf(ndev, "twt",
11947 mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
11948 if (bw < 0) {
11949 ANDROID_ERROR(("twt teardown failed. ret:%d\n", bw));
11950 }
11951 exit:
11952 return bw;
11953 }
11954
11955 /* wl twt stats result display version 2 */
11956 static int
wl_android_twt_stats_display_v2(wl_twt_stats_v2_t * stats,char * command,int total_len)11957 wl_android_twt_stats_display_v2(wl_twt_stats_v2_t *stats, char *command, int total_len)
11958 {
11959 u32 i;
11960 wl_twt_peer_stats_v2_t *peer_stats;
11961 int rem_len = 0, bytes_written = 0;
11962
11963 rem_len = total_len;
11964 for (i = 0; i < stats->num_stats; i++) {
11965 peer_stats = &stats->peer_stats_list[i];
11966
11967 bytes_written = scnprintf(command, rem_len,
11968 "%u %u %u %u %u",
11969 peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg,
11970 peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg);
11971 CHECK_SCNPRINTF_RET_VAL(bytes_written);
11972 command += bytes_written;
11973 rem_len -= bytes_written;
11974 }
11975
11976 if ((total_len - rem_len) > 0) {
11977 return (total_len - rem_len);
11978 } else {
11979 return BCME_ERROR;
11980 }
11981 }
11982
11983 static int
wl_android_twt_stats(struct net_device * ndev,char * command,int total_len)11984 wl_android_twt_stats(struct net_device *ndev, char *command, int total_len)
11985 {
11986 wl_twt_stats_cmd_v1_t query;
11987 wl_twt_stats_v2_t stats_v2;
11988 int ret = BCME_OK;
11989 char iovbuf[WLC_IOCTL_SMLEN] = {0, };
11990 uint8 *pxtlv = NULL;
11991 uint8 *iovresp = NULL;
11992 char *token, *pos;
11993 uint16 buflen = 0, bufstart = 0;
11994 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
11995
11996 WL_DBG_MEM(("Enter. cmd:%s\n", command));
11997
11998 bzero(&query, sizeof(query));
11999 query.version = WL_TWT_STATS_CMD_VERSION_1;
12000 query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer);
12001
12002 /* Default values, Overide Below */
12003 query.num_bid = 0xFF;
12004 query.num_fid = 0xFF;
12005
12006 if (!(strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)))) {
12007 query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET;
12008 pos = command + sizeof(CMD_TWT_CLR_STATS);
12009 } else if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) {
12010 pos = command + sizeof(CMD_TWT_GET_STATS);
12011 }
12012
12013 /* Config ID */
12014 token = strsep((char**)&pos, " ");
12015 if (!token) {
12016 ANDROID_ERROR(("Mandatory param config ID not present\n"));
12017 ret = -EINVAL;
12018 goto exit;
12019 }
12020 query.configID = (u8)bcm_atoi(token);
12021
12022 iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
12023 if (iovresp == NULL) {
12024 ANDROID_ERROR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
12025 goto exit;
12026 }
12027
12028 buflen = bufstart = WLC_IOCTL_SMLEN;
12029 pxtlv = (uint8 *)iovbuf;
12030 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS,
12031 sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
12032 if (ret != BCME_OK) {
12033 ANDROID_ERROR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
12034 goto exit;
12035 }
12036
12037 if ((ret = wldev_iovar_getbuf(ndev, "twt", iovbuf, bufstart-buflen,
12038 iovresp, WLC_IOCTL_MEDLEN, NULL))) {
12039 ANDROID_ERROR(("twt status failed with err=%d \n", ret));
12040 goto exit;
12041 }
12042
12043 (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2));
12044
12045 if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) {
12046 if (!(strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)))) {
12047 ANDROID_ERROR(("stats query ver %d, \n", dtoh16(stats_v2.version)));
12048 ret = wl_android_twt_stats_display_v2((wl_twt_stats_v2_t*)iovresp,
12049 command, total_len);
12050 }
12051 } else {
12052 ret = BCME_UNSUPPORTED;
12053 ANDROID_ERROR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version)));
12054 goto exit;
12055 }
12056
12057 exit:
12058 if (iovresp) {
12059 MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
12060 }
12061
12062 return ret;
12063 }
12064 #endif /* WL_TWT */
12065
12066 int
wl_handle_private_cmd(struct net_device * net,char * command,u32 cmd_len)12067 wl_handle_private_cmd(struct net_device *net, char *command, u32 cmd_len)
12068 {
12069 int bytes_written = 0;
12070 android_wifi_priv_cmd priv_cmd;
12071
12072 bzero(&priv_cmd, sizeof(android_wifi_priv_cmd));
12073 priv_cmd.total_len = cmd_len;
12074
12075 if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
12076 ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
12077 #ifdef SUPPORT_DEEP_SLEEP
12078 trigger_deep_sleep = 1;
12079 #else
12080 #ifdef BT_OVER_SDIO
12081 bytes_written = dhd_net_bus_get(net);
12082 #else
12083 bytes_written = wl_android_wifi_on(net);
12084 #endif /* BT_OVER_SDIO */
12085 #endif /* SUPPORT_DEEP_SLEEP */
12086 }
12087 else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
12088 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
12089 }
12090
12091 if (!g_wifi_on) {
12092 ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
12093 __FUNCTION__, command));
12094 return 0;
12095 }
12096
12097 if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
12098 #ifdef SUPPORT_DEEP_SLEEP
12099 trigger_deep_sleep = 1;
12100 #else
12101 #ifdef BT_OVER_SDIO
12102 bytes_written = dhd_net_bus_put(net);
12103 #else
12104 bytes_written = wl_android_wifi_off(net, FALSE);
12105 #endif /* BT_OVER_SDIO */
12106 #endif /* SUPPORT_DEEP_SLEEP */
12107 }
12108 #ifdef WL_CFG80211
12109 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
12110 wl_cfg80211_set_passive_scan(net, command);
12111 }
12112 else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
12113 wl_cfg80211_set_passive_scan(net, command);
12114 }
12115 #endif /* WL_CFG80211 */
12116 else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
12117 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
12118 }
12119 else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
12120 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
12121 }
12122 #ifdef PKT_FILTER_SUPPORT
12123 else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
12124 bytes_written = net_os_enable_packet_filter(net, 1);
12125 }
12126 else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
12127 bytes_written = net_os_enable_packet_filter(net, 0);
12128 }
12129 else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
12130 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
12131 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
12132 }
12133 else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
12134 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
12135 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
12136 }
12137 #endif /* PKT_FILTER_SUPPORT */
12138 else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
12139 /* TBD: BTCOEXSCAN-START */
12140 }
12141 else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
12142 /* TBD: BTCOEXSCAN-STOP */
12143 }
12144 else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
12145 #ifdef WL_CFG80211
12146 void *dhdp = wl_cfg80211_get_dhdp(net);
12147 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
12148 #else
12149 #ifdef PKT_FILTER_SUPPORT
12150 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
12151
12152 if (mode == 1)
12153 net_os_enable_packet_filter(net, 0); /* DHCP starts */
12154 else
12155 net_os_enable_packet_filter(net, 1); /* DHCP ends */
12156 #endif /* PKT_FILTER_SUPPORT */
12157 #endif /* WL_CFG80211 */
12158 }
12159 else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
12160 bytes_written = wl_android_set_suspendopt(net, command);
12161 }
12162 else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
12163 bytes_written = wl_android_set_suspendmode(net, command);
12164 }
12165 else if (strnicmp(command, CMD_SETDTIM_IN_SUSPEND, strlen(CMD_SETDTIM_IN_SUSPEND)) == 0) {
12166 bytes_written = wl_android_set_bcn_li_dtim(net, command);
12167 }
12168 else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
12169 bytes_written = wl_android_set_max_dtim(net, command);
12170 }
12171 #ifdef DISABLE_DTIM_IN_SUSPEND
12172 else if (strnicmp(command, CMD_DISDTIM_IN_SUSPEND, strlen(CMD_DISDTIM_IN_SUSPEND)) == 0) {
12173 bytes_written = wl_android_set_disable_dtim_in_suspend(net, command);
12174 }
12175 #endif /* DISABLE_DTIM_IN_SUSPEND */
12176 #ifdef WL_CFG80211
12177 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
12178 bytes_written = wl_android_set_band(net, command);
12179 }
12180 #endif /* WL_CFG80211 */
12181 else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
12182 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
12183 }
12184 #ifdef WL_CFG80211
12185 else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
12186 bytes_written = wl_android_set_csa(net, command);
12187 } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
12188 bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
12189 } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
12190 bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
12191 }
12192 #endif /* WL_CFG80211 */
12193 #ifndef CUSTOMER_SET_COUNTRY
12194 /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
12195 else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
12196 /*
12197 * Usage examples:
12198 * DRIVER COUNTRY US
12199 * DRIVER COUNTRY US/7
12200 * Wrong revinfo should be filtered:
12201 * DRIVER COUNTRY US/-1
12202 */
12203 char *country_code = command + strlen(CMD_COUNTRY) + 1;
12204 char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
12205 int revinfo = -1;
12206 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12207 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12208 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12209 if ((rev_info_delim) &&
12210 (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
12211 strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
12212 (rev_info_delim + 1)) {
12213 revinfo = bcm_atoi(rev_info_delim + 1);
12214 } else {
12215 revinfo = 0;
12216 }
12217
12218 if (revinfo < 0) {
12219 ANDROID_ERROR(("%s:failed due to wrong revinfo %d\n", __FUNCTION__, revinfo));
12220 return BCME_BADARG;
12221 }
12222
12223 #if defined(DHD_BLOB_EXISTENCE_CHECK)
12224 if (dhdp->is_blob) {
12225 revinfo = 0;
12226 }
12227 #endif /* DHD_BLOB_EXISTENCE_CHECK */
12228
12229 #ifdef WL_CFG80211
12230 bytes_written = wl_cfg80211_set_country_code(net, country_code,
12231 true, true, revinfo);
12232 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12233 #ifdef FCC_PWR_LIMIT_2G
12234 if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
12235 ANDROID_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
12236 } else {
12237 ANDROID_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
12238 }
12239 #endif /* FCC_PWR_LIMIT_2G */
12240 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12241 #else
12242 bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
12243 #endif /* WL_CFG80211 */
12244 }
12245 #endif /* CUSTOMER_SET_COUNTRY */
12246 else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
12247 bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
12248 } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
12249 bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
12250 }
12251
12252 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12253 else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_SET, strlen(CMD_ROAM_VSIE_ENAB_SET)) == 0) {
12254 bytes_written = wl_android_set_roam_vsie_enab(net, command, priv_cmd.total_len);
12255 } else if (strnicmp(command, CMD_ROAM_VSIE_ENAB_GET, strlen(CMD_ROAM_VSIE_ENAB_GET)) == 0) {
12256 bytes_written = wl_android_get_roam_vsie_enab(net, command, priv_cmd.total_len);
12257 } else if (strnicmp(command, CMD_BR_VSIE_ENAB_SET, strlen(CMD_BR_VSIE_ENAB_SET)) == 0) {
12258 bytes_written = wl_android_set_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12259 } else if (strnicmp(command, CMD_BR_VSIE_ENAB_GET, strlen(CMD_BR_VSIE_ENAB_GET)) == 0) {
12260 bytes_written = wl_android_get_bcn_rpt_vsie_enab(net, command, priv_cmd.total_len);
12261 }
12262 #ifdef WES_SUPPORT
12263 else if (strnicmp(command, CMD_GETNCHOMODE, strlen(CMD_GETNCHOMODE)) == 0) {
12264 bytes_written = wl_android_get_ncho_mode(net, command, priv_cmd.total_len);
12265 }
12266 else if (strnicmp(command, CMD_SETNCHOMODE, strlen(CMD_SETNCHOMODE)) == 0) {
12267 int mode;
12268 sscanf(command, "%*s %d", &mode);
12269 bytes_written = wl_android_set_ncho_mode(net, mode);
12270 }
12271 else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0) {
12272 bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
12273 }
12274 else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0) {
12275 bytes_written = wl_android_okc_enable(net, command);
12276 }
12277 else if (wl_android_legacy_check_command(net, command)) {
12278 bytes_written = wl_android_legacy_private_command(net, command, priv_cmd.total_len);
12279 }
12280 else if (wl_android_ncho_check_command(net, command)) {
12281 bytes_written = wl_android_ncho_private_command(net, command, priv_cmd.total_len);
12282 }
12283 #endif /* WES_SUPPORT */
12284 #if defined(SUPPORT_RESTORE_SCAN_PARAMS) || defined(WES_SUPPORT)
12285 else if (strnicmp(command, CMD_RESTORE_SCAN_PARAMS, strlen(CMD_RESTORE_SCAN_PARAMS)) == 0) {
12286 bytes_written = wl_android_default_set_scan_params(net, command,
12287 priv_cmd.total_len);
12288 }
12289 #endif /* SUPPORT_RESTORE_SCAN_PARAMS || WES_SUPPORT */
12290 #ifdef WLTDLS
12291 else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
12292 bytes_written = wl_android_tdls_reset(net);
12293 }
12294 #endif /* WLTDLS */
12295 #ifdef CONFIG_SILENT_ROAM
12296 else if (strnicmp(command, CMD_SROAM_TURN_ON, strlen(CMD_SROAM_TURN_ON)) == 0) {
12297 int mode = *(command + strlen(CMD_SROAM_TURN_ON) + 1) - '0';
12298 bytes_written = wl_android_sroam_turn_on(net, mode);
12299 }
12300 else if (strnicmp(command, CMD_SROAM_SET_INFO, strlen(CMD_SROAM_SET_INFO)) == 0) {
12301 char *data = (command + strlen(CMD_SROAM_SET_INFO) + 1);
12302 bytes_written = wl_android_sroam_set_info(net, data, command, priv_cmd.total_len);
12303 }
12304 else if (strnicmp(command, CMD_SROAM_GET_INFO, strlen(CMD_SROAM_GET_INFO)) == 0) {
12305 bytes_written = wl_android_sroam_get_info(net, command, priv_cmd.total_len);
12306 }
12307 #endif /* CONFIG_SILENT_ROAM */
12308 #ifdef CONFIG_ROAM_RSSI_LIMIT
12309 else if (strnicmp(command, CMD_ROAM_RSSI_LMT, strlen(CMD_ROAM_RSSI_LMT)) == 0) {
12310 bytes_written = wl_android_roam_rssi_limit(net, command, priv_cmd.total_len);
12311 }
12312 #endif /* CONFIG_ROAM_RSSI_LIMIT */
12313 #ifdef CONFIG_ROAM_MIN_DELTA
12314 else if (strnicmp(command, CMD_ROAM_MIN_DELTA, strlen(CMD_ROAM_MIN_DELTA)) == 0) {
12315 bytes_written = wl_android_roam_min_delta(net, command, priv_cmd.total_len);
12316 }
12317 #endif /* CONFIG_ROAM_MIN_DELTA */
12318 else if (strnicmp(command, CMD_SET_DISCONNECT_IES, strlen(CMD_SET_DISCONNECT_IES)) == 0) {
12319 bytes_written = wl_android_set_disconnect_ies(net, command);
12320 }
12321 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12322
12323 #ifdef PNO_SUPPORT
12324 else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
12325 bytes_written = dhd_dev_pno_stop_for_ssid(net);
12326 }
12327 #ifndef WL_SCHED_SCAN
12328 else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
12329 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
12330 }
12331 #endif /* !WL_SCHED_SCAN */
12332 else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
12333 int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
12334 bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
12335 }
12336 else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
12337 bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
12338 }
12339 #endif /* PNO_SUPPORT */
12340 else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
12341 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
12342 }
12343 else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
12344 int skip = strlen(CMD_P2P_SET_NOA) + 1;
12345 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
12346 priv_cmd.total_len - skip);
12347 }
12348 #ifdef WL_SDO
12349 else if (strnicmp(command, CMD_P2P_SD_OFFLOAD, strlen(CMD_P2P_SD_OFFLOAD)) == 0) {
12350 u8 *buf = command;
12351 u8 *cmd_id = NULL;
12352 int len;
12353
12354 cmd_id = strsep((char **)&buf, " ");
12355 if (!cmd_id) {
12356 /* Propagate the error */
12357 bytes_written = -EINVAL;
12358 } else {
12359 /* if buf == NULL, means no arg */
12360 if (buf == NULL) {
12361 len = 0;
12362 } else {
12363 len = strlen(buf);
12364 }
12365 bytes_written = wl_cfg80211_sd_offload(net, cmd_id, buf, len);
12366 }
12367 }
12368 #endif /* WL_SDO */
12369 #ifdef P2P_LISTEN_OFFLOADING
12370 else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
12371 u8 *sub_command = strchr(command, ' ');
12372 bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
12373 sub_command ? strlen(sub_command) : 0);
12374 }
12375 #endif /* P2P_LISTEN_OFFLOADING */
12376 #if !defined WL_ENABLE_P2P_IF
12377 else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
12378 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
12379 }
12380 #endif /* WL_ENABLE_P2P_IF */
12381 else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
12382 int skip = strlen(CMD_P2P_SET_PS) + 1;
12383 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
12384 priv_cmd.total_len - skip);
12385 }
12386 else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
12387 int skip = strlen(CMD_P2P_ECSA) + 1;
12388 bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
12389 priv_cmd.total_len - skip);
12390 }
12391 /* This command is not for normal VSDB operation but for only specific P2P operation.
12392 * Ex) P2P OTA backup operation
12393 */
12394 else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
12395 int skip = strlen(CMD_P2P_INC_BW) + 1;
12396 bytes_written = wl_cfg80211_increase_p2p_bw(net,
12397 command + skip, priv_cmd.total_len - skip);
12398 }
12399 #ifdef WL_CFG80211
12400 else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
12401 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
12402 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
12403 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
12404 priv_cmd.total_len - skip, *(command + skip - 2) - '0');
12405 }
12406 #ifdef WLFBT
12407 else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
12408 bytes_written = wl_cfg80211_get_fbt_key(net, command, priv_cmd.total_len);
12409 }
12410 #endif /* WLFBT */
12411 #endif /* WL_CFG80211 */
12412 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12413 else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
12414 strlen(CMD_GET_BEST_CHANNELS)) == 0) {
12415 bytes_written = wl_android_get_best_channels(net, command,
12416 priv_cmd.total_len);
12417 }
12418 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12419 #if defined (WL_SUPPORT_AUTO_CHANNEL)
12420 else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
12421 strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
12422 int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
12423 bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
12424 priv_cmd.total_len);
12425 }
12426 #endif /* WL_SUPPORT_AUTO_CHANNEL */
12427 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12428 #ifdef SUPPORT_AMPDU_MPDU_CMD
12429 /* CMD_AMPDU_MPDU */
12430 else if (strnicmp(command, CMD_AMPDU_MPDU, strlen(CMD_AMPDU_MPDU)) == 0) {
12431 int skip = strlen(CMD_AMPDU_MPDU) + 1;
12432 bytes_written = wl_android_set_ampdu_mpdu(net, (const char*)command+skip);
12433 }
12434 #endif /* SUPPORT_AMPDU_MPDU_CMD */
12435 #if defined (SUPPORT_HIDDEN_AP)
12436 else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
12437 strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
12438 int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
12439 wl_android_set_max_num_sta(net, (const char*)command+skip);
12440 }
12441 else if (strnicmp(command, CMD_SET_HAPD_SSID,
12442 strlen(CMD_SET_HAPD_SSID)) == 0) {
12443 int skip = strlen(CMD_SET_HAPD_SSID) + 3;
12444 wl_android_set_ssid(net, (const char*)command+skip);
12445 }
12446 else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
12447 strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
12448 int skip = strlen(CMD_SET_HAPD_HIDE_SSID) + 3;
12449 wl_android_set_hide_ssid(net, (const char*)command+skip);
12450 }
12451 #endif /* SUPPORT_HIDDEN_AP */
12452 #ifdef SUPPORT_SOFTAP_SINGL_DISASSOC
12453 else if (strnicmp(command, CMD_HAPD_STA_DISASSOC,
12454 strlen(CMD_HAPD_STA_DISASSOC)) == 0) {
12455 int skip = strlen(CMD_HAPD_STA_DISASSOC) + 1;
12456 wl_android_sta_diassoc(net, (const char*)command+skip);
12457 }
12458 #endif /* SUPPORT_SOFTAP_SINGL_DISASSOC */
12459 #ifdef SUPPORT_SET_LPC
12460 else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
12461 strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
12462 int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
12463 wl_android_set_lpc(net, (const char*)command+skip);
12464 }
12465 #endif /* SUPPORT_SET_LPC */
12466 #ifdef SUPPORT_TRIGGER_HANG_EVENT
12467 else if (strnicmp(command, CMD_TEST_FORCE_HANG,
12468 strlen(CMD_TEST_FORCE_HANG)) == 0) {
12469 int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
12470 net_os_send_hang_message_reason(net, (const char*)command+skip);
12471 }
12472 #endif /* SUPPORT_TRIGGER_HANG_EVENT */
12473 else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
12474 bytes_written = wl_android_ch_res_rl(net, true);
12475 else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
12476 bytes_written = wl_android_ch_res_rl(net, false);
12477 #ifdef SUPPORT_LTECX
12478 else if (strnicmp(command, CMD_LTECX_SET, strlen(CMD_LTECX_SET)) == 0) {
12479 int skip = strlen(CMD_LTECX_SET) + 1;
12480 bytes_written = wl_android_set_ltecx(net, (const char*)command+skip);
12481 }
12482 #endif /* SUPPORT_LTECX */
12483 #ifdef WL_RELMCAST
12484 else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
12485 int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
12486 bytes_written = wl_android_rmc_enable(net, rmc_enable);
12487 }
12488 else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
12489 int rmc_txrate;
12490 sscanf(command, "%*s %10d", &rmc_txrate);
12491 bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
12492 }
12493 else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
12494 int actperiod;
12495 sscanf(command, "%*s %10d", &actperiod);
12496 bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
12497 }
12498 else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
12499 int acktimeout;
12500 sscanf(command, "%*s %10d", &acktimeout);
12501 acktimeout *= 1000;
12502 bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
12503 }
12504 else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
12505 int skip = strlen(CMD_SET_RMC_LEADER) + 1;
12506 bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
12507 }
12508 else if (strnicmp(command, CMD_SET_RMC_EVENT,
12509 strlen(CMD_SET_RMC_EVENT)) == 0) {
12510 bytes_written = wl_android_set_rmc_event(net, command);
12511 }
12512 #endif /* WL_RELMCAST */
12513 else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
12514 bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
12515 }
12516 else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
12517 bytes_written = wl_android_set_singlecore_scan(net, command);
12518 }
12519 #ifdef TEST_TX_POWER_CONTROL
12520 else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
12521 strlen(CMD_TEST_SET_TX_POWER)) == 0) {
12522 int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
12523 wl_android_set_tx_power(net, (const char*)command+skip);
12524 }
12525 else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
12526 strlen(CMD_TEST_GET_TX_POWER)) == 0) {
12527 wl_android_get_tx_power(net, command, priv_cmd.total_len);
12528 }
12529 #endif /* TEST_TX_POWER_CONTROL */
12530 else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
12531 strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
12532 int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
12533 bytes_written = wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
12534 }
12535 #ifdef SUPPORT_SET_TID
12536 else if (strnicmp(command, CMD_SET_TID, strlen(CMD_SET_TID)) == 0) {
12537 bytes_written = wl_android_set_tid(net, command);
12538 }
12539 else if (strnicmp(command, CMD_GET_TID, strlen(CMD_GET_TID)) == 0) {
12540 bytes_written = wl_android_get_tid(net, command, priv_cmd.total_len);
12541 }
12542 #endif /* SUPPORT_SET_TID */
12543 #ifdef WL_WTC
12544 else if (strnicmp(command, CMD_WTC_CONFIG, strlen(CMD_WTC_CONFIG)) == 0) {
12545 bytes_written = wl_android_wtc_config(net, command, priv_cmd.total_len);
12546 }
12547 #endif /* WL_WTC */
12548 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12549 else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
12550 int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
12551 wl_android_set_mac_address_filter(net, command+skip);
12552 }
12553 else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
12554 bytes_written = wl_android_set_roam_mode(net, command);
12555 #if defined(BCMFW_ROAM_ENABLE)
12556 else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
12557 bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
12558 }
12559 #endif /* BCMFW_ROAM_ENABLE */
12560 #ifdef WL_CFG80211
12561 else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
12562 bytes_written = wl_android_set_miracast(net, command);
12563 else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
12564 bytes_written = wl_android_set_ibss_beacon_ouidata(net,
12565 command, priv_cmd.total_len);
12566 #endif /* WL_CFG80211 */
12567 #ifdef WLAIBSS
12568 else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
12569 strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
12570 bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
12571 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
12572 strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
12573 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12574 TRUE);
12575 else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
12576 strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
12577 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
12578 FALSE);
12579 else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
12580 strlen(CMD_SETIBSSROUTETABLE)) == 0)
12581 bytes_written = wl_android_set_ibss_routetable(net, command);
12582 else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
12583 bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
12584 else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
12585 bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
12586 #endif /* WLAIBSS */
12587 else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
12588 int skip = strlen(CMD_KEEP_ALIVE) + 1;
12589 bytes_written = wl_keep_alive_set(net, command + skip);
12590 }
12591 #ifdef WL_CFG80211
12592 else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
12593 int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
12594 bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
12595 }
12596 else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
12597 char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
12598 ANDROID_INFO(("Creating %s interface\n", name));
12599 if (wl_cfg80211_add_if(wl_get_cfg(net), net, WL_IF_TYPE_STA,
12600 name, NULL) == NULL) {
12601 bytes_written = -ENODEV;
12602 } else {
12603 /* Return success */
12604 bytes_written = 0;
12605 }
12606 }
12607 else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
12608 char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
12609 ANDROID_INFO(("Deleteing %s interface\n", name));
12610 bytes_written = wl_cfg80211_del_if(wl_get_cfg(net), net, NULL, name);
12611 }
12612 #endif /* WL_CFG80211 */
12613 else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
12614 bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
12615 }
12616 #ifdef P2PRESP_WFDIE_SRC
12617 else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
12618 strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
12619 int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
12620 bytes_written = wl_android_set_wfdie_resp(net, mode);
12621 } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
12622 strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
12623 bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
12624 }
12625 #endif /* P2PRESP_WFDIE_SRC */
12626 #ifdef WL_CFG80211
12627 else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
12628 char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
12629 bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
12630 }
12631 #endif /* WL_CFG80211 */
12632 #ifdef WBTEXT
12633 else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
12634 bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
12635 }
12636 else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
12637 strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
12638 char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
12639 bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
12640 }
12641 else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
12642 strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
12643 char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
12644 bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
12645 command, priv_cmd.total_len);
12646 }
12647 else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
12648 strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
12649 char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
12650 bytes_written = wl_cfg80211_wbtext_table_config(net, data,
12651 command, priv_cmd.total_len);
12652 }
12653 else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
12654 strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
12655 char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
12656 bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
12657 command, priv_cmd.total_len);
12658 }
12659 else if (strnicmp(command, CMD_WBTEXT_BTM_TIMER_THRESHOLD,
12660 strlen(CMD_WBTEXT_BTM_TIMER_THRESHOLD)) == 0) {
12661 bytes_written = wl_cfg80211_wbtext_btm_timer_threshold(net, command,
12662 priv_cmd.total_len);
12663 }
12664 else if (strnicmp(command, CMD_WBTEXT_BTM_DELTA,
12665 strlen(CMD_WBTEXT_BTM_DELTA)) == 0) {
12666 bytes_written = wl_cfg80211_wbtext_btm_delta(net, command,
12667 priv_cmd.total_len);
12668 }
12669 else if (strnicmp(command, CMD_WBTEXT_ESTM_ENABLE,
12670 strlen(CMD_WBTEXT_ESTM_ENABLE)) == 0) {
12671 bytes_written = wl_cfg80211_wbtext_estm_enable(net, command,
12672 priv_cmd.total_len);
12673 }
12674 #endif /* WBTEXT */
12675 #ifdef WLWFDS
12676 else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
12677 bytes_written = wl_android_set_wfds_hash(net, command, 1);
12678 }
12679 else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
12680 bytes_written = wl_android_set_wfds_hash(net, command, 0);
12681 }
12682 #endif /* WLWFDS */
12683 #ifdef BT_WIFI_HANDOVER
12684 else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
12685 bytes_written = wl_tbow_teardown(net);
12686 }
12687 #endif /* BT_WIFI_HANDOVER */
12688 #ifdef CUSTOMER_HW4_PRIVATE_CMD
12689 #ifdef FCC_PWR_LIMIT_2G
12690 else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
12691 strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
12692 bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
12693 }
12694 else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
12695 strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
12696 bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command);
12697 }
12698 #endif /* FCC_PWR_LIMIT_2G */
12699 else if (strnicmp(command, CMD_GET_STA_INFO, strlen(CMD_GET_STA_INFO)) == 0) {
12700 bytes_written = wl_cfg80211_get_sta_info(net, command, priv_cmd.total_len);
12701 }
12702 #endif /* CUSTOMER_HW4_PRIVATE_CMD */
12703 else if (strnicmp(command, CMD_MURX_BFE_CAP,
12704 strlen(CMD_MURX_BFE_CAP)) == 0) {
12705 #ifdef WL_MURX
12706 uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
12707 bytes_written = wl_android_murx_bfe_cap(net, val);
12708 #else
12709 return BCME_UNSUPPORTED;
12710 #endif /* WL_MURX */
12711 }
12712 #ifdef SUPPORT_AP_HIGHER_BEACONRATE
12713 else if (strnicmp(command, CMD_GET_AP_BASICRATE, strlen(CMD_GET_AP_BASICRATE)) == 0) {
12714 bytes_written = wl_android_get_ap_basicrate(net, command, priv_cmd.total_len);
12715 }
12716 else if (strnicmp(command, CMD_SET_AP_BEACONRATE, strlen(CMD_SET_AP_BEACONRATE)) == 0) {
12717 bytes_written = wl_android_set_ap_beaconrate(net, command);
12718 }
12719 #endif /* SUPPORT_AP_HIGHER_BEACONRATE */
12720 #ifdef SUPPORT_AP_RADIO_PWRSAVE
12721 else if (strnicmp(command, CMD_SET_AP_RPS_PARAMS, strlen(CMD_SET_AP_RPS_PARAMS)) == 0) {
12722 bytes_written = wl_android_set_ap_rps_params(net, command, priv_cmd.total_len);
12723 }
12724 else if (strnicmp(command, CMD_SET_AP_RPS, strlen(CMD_SET_AP_RPS)) == 0) {
12725 bytes_written = wl_android_set_ap_rps(net, command, priv_cmd.total_len);
12726 }
12727 else if (strnicmp(command, CMD_GET_AP_RPS, strlen(CMD_GET_AP_RPS)) == 0) {
12728 bytes_written = wl_android_get_ap_rps(net, command, priv_cmd.total_len);
12729 }
12730 #endif /* SUPPORT_AP_RADIO_PWRSAVE */
12731 #ifdef SUPPORT_AP_SUSPEND
12732 else if (strnicmp(command, CMD_SET_AP_SUSPEND, strlen(CMD_SET_AP_SUSPEND)) == 0) {
12733 bytes_written = wl_android_set_ap_suspend(net, command, priv_cmd.total_len);
12734 }
12735 #endif /* SUPPORT_AP_SUSPEND */
12736 #ifdef SUPPORT_AP_BWCTRL
12737 else if (strnicmp(command, CMD_SET_AP_BW, strlen(CMD_SET_AP_BW)) == 0) {
12738 bytes_written = wl_android_set_ap_bw(net, command, priv_cmd.total_len);
12739 }
12740 else if (strnicmp(command, CMD_GET_AP_BW, strlen(CMD_GET_AP_BW)) == 0) {
12741 bytes_written = wl_android_get_ap_bw(net, command, priv_cmd.total_len);
12742 }
12743 #endif /* SUPPORT_AP_BWCTRL */
12744 #ifdef SUPPORT_RSSI_SUM_REPORT
12745 else if (strnicmp(command, CMD_SET_RSSI_LOGGING, strlen(CMD_SET_RSSI_LOGGING)) == 0) {
12746 bytes_written = wl_android_set_rssi_logging(net, command, priv_cmd.total_len);
12747 }
12748 else if (strnicmp(command, CMD_GET_RSSI_LOGGING, strlen(CMD_GET_RSSI_LOGGING)) == 0) {
12749 bytes_written = wl_android_get_rssi_logging(net, command, priv_cmd.total_len);
12750 }
12751 else if (strnicmp(command, CMD_GET_RSSI_PER_ANT, strlen(CMD_GET_RSSI_PER_ANT)) == 0) {
12752 bytes_written = wl_android_get_rssi_per_ant(net, command, priv_cmd.total_len);
12753 }
12754 #endif /* SUPPORT_RSSI_SUM_REPORT */
12755 #if defined(DHD_ENABLE_BIGDATA_LOGGING)
12756 else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
12757 bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
12758 }
12759 else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
12760 == 0) {
12761 bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
12762 priv_cmd.total_len);
12763 }
12764 #endif /* DHD_ENABLE_BIGDATA_LOGGING */
12765 #if defined(SUPPORT_RANDOM_MAC_SCAN)
12766 else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
12767 bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
12768 } else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
12769 bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
12770 }
12771 #endif /* SUPPORT_RANDOM_MAC_SCAN */
12772 #ifdef WL_NATOE
12773 else if (strnicmp(command, CMD_NATOE, strlen(CMD_NATOE)) == 0) {
12774 bytes_written = wl_android_process_natoe_cmd(net, command,
12775 priv_cmd.total_len);
12776 }
12777 #endif /* WL_NATOE */
12778 #ifdef CONNECTION_STATISTICS
12779 else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
12780 strlen(CMD_GET_CONNECTION_STATS)) == 0) {
12781 bytes_written = wl_android_get_connection_stats(net, command,
12782 priv_cmd.total_len);
12783 }
12784 #endif
12785 #ifdef DHD_LOG_DUMP
12786 else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
12787 strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
12788 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12789 /* check whether it has more command */
12790 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP), " ", 1) == 0) {
12791 /* compare unwanted/disconnected command */
12792 if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12793 SUBCMD_UNWANTED, strlen(SUBCMD_UNWANTED)) == 0) {
12794 dhd_log_dump_trigger(dhdp, CMD_UNWANTED);
12795 } else if (strnicmp(command + strlen(CMD_NEW_DEBUG_PRINT_DUMP) + 1,
12796 SUBCMD_DISCONNECTED, strlen(SUBCMD_DISCONNECTED)) == 0) {
12797 dhd_log_dump_trigger(dhdp, CMD_DISCONNECTED);
12798 } else {
12799 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12800 }
12801 } else {
12802 dhd_log_dump_trigger(dhdp, CMD_DEFAULT);
12803 }
12804 }
12805 #endif /* DHD_LOG_DUMP */
12806 #ifdef DHD_STATUS_LOGGING
12807 else if (strnicmp(command, CMD_DUMP_STATUS_LOG, strlen(CMD_DUMP_STATUS_LOG)) == 0) {
12808 dhd_statlog_dump_scr(wl_cfg80211_get_dhdp(net));
12809 }
12810 else if (strnicmp(command, CMD_QUERY_STATUS_LOG, strlen(CMD_QUERY_STATUS_LOG)) == 0) {
12811 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
12812 bytes_written = dhd_statlog_query(dhdp, command, priv_cmd.total_len);
12813 }
12814 #endif /* DHD_STATUS_LOGGING */
12815 #if defined(CONFIG_TIZEN)
12816 else if (strnicmp(command, CMD_POWERSAVEMODE_SET,
12817 strlen(CMD_POWERSAVEMODE_SET)) == 0) {
12818 bytes_written = wl_android_set_powersave_mode(net, command,
12819 priv_cmd.total_len);
12820 }
12821 else if (strnicmp(command, CMD_POWERSAVEMODE_GET,
12822 strlen(CMD_POWERSAVEMODE_GET)) == 0) {
12823 bytes_written = wl_android_get_powersave_mode(net, command,
12824 priv_cmd.total_len);
12825 }
12826 #endif /* CONFIG_TIZEN */
12827 #ifdef SET_PCIE_IRQ_CPU_CORE
12828 else if (strnicmp(command, CMD_PCIE_IRQ_CORE, strlen(CMD_PCIE_IRQ_CORE)) == 0) {
12829 int affinity_cmd = *(command + strlen(CMD_PCIE_IRQ_CORE) + 1) - '0';
12830 wl_android_set_irq_cpucore(net, affinity_cmd);
12831 }
12832 #endif /* SET_PCIE_IRQ_CPU_CORE */
12833 #if defined(DHD_HANG_SEND_UP_TEST)
12834 else if (strnicmp(command, CMD_MAKE_HANG, strlen(CMD_MAKE_HANG)) == 0) {
12835 int skip = strlen(CMD_MAKE_HANG) + 1;
12836 wl_android_make_hang_with_reason(net, (const char*)command+skip);
12837 }
12838 #endif /* DHD_HANG_SEND_UP_TEST */
12839 #ifdef SUPPORT_LQCM
12840 else if (strnicmp(command, CMD_SET_LQCM_ENABLE, strlen(CMD_SET_LQCM_ENABLE)) == 0) {
12841 int lqcm_enable = *(command + strlen(CMD_SET_LQCM_ENABLE) + 1) - '0';
12842 bytes_written = wl_android_lqcm_enable(net, lqcm_enable);
12843 }
12844 else if (strnicmp(command, CMD_GET_LQCM_REPORT,
12845 strlen(CMD_GET_LQCM_REPORT)) == 0) {
12846 bytes_written = wl_android_get_lqcm_report(net, command,
12847 priv_cmd.total_len);
12848 }
12849 #endif
12850 else if (strnicmp(command, CMD_GET_SNR, strlen(CMD_GET_SNR)) == 0) {
12851 bytes_written = wl_android_get_snr(net, command, priv_cmd.total_len);
12852 }
12853 #ifdef WLADPS_PRIVATE_CMD
12854 else if (strnicmp(command, CMD_SET_ADPS, strlen(CMD_SET_ADPS)) == 0) {
12855 int skip = strlen(CMD_SET_ADPS) + 1;
12856 bytes_written = wl_android_set_adps_mode(net, (const char*)command+skip);
12857 }
12858 else if (strnicmp(command, CMD_GET_ADPS, strlen(CMD_GET_ADPS)) == 0) {
12859 bytes_written = wl_android_get_adps_mode(net, command, priv_cmd.total_len);
12860 }
12861 #ifdef WLADPS_ENERGY_GAIN
12862 else if (strnicmp(command, CMD_GET_GAIN_ADPS, strlen(CMD_GET_GAIN_ADPS)) == 0) {
12863 bytes_written = wl_android_get_gain_adps(net, command, priv_cmd.total_len);
12864 }
12865 else if (strnicmp(command, CMD_RESET_GAIN_ADPS, strlen(CMD_RESET_GAIN_ADPS)) == 0) {
12866 bytes_written = wl_android_reset_gain_adps(net, command);
12867 }
12868 #endif /* WLADPS_ENERGY_GAIN */
12869 #endif /* WLADPS_PRIVATE_CMD */
12870 #ifdef DHD_PKT_LOGGING
12871 else if (strnicmp(command, CMD_PKTLOG_FILTER_ENABLE,
12872 strlen(CMD_PKTLOG_FILTER_ENABLE)) == 0) {
12873 bytes_written = wl_android_pktlog_filter_enable(net, command, priv_cmd.total_len);
12874 }
12875 else if (strnicmp(command, CMD_PKTLOG_FILTER_DISABLE,
12876 strlen(CMD_PKTLOG_FILTER_DISABLE)) == 0) {
12877 bytes_written = wl_android_pktlog_filter_disable(net, command, priv_cmd.total_len);
12878 }
12879 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_ENABLE,
12880 strlen(CMD_PKTLOG_FILTER_PATTERN_ENABLE)) == 0) {
12881 bytes_written =
12882 wl_android_pktlog_filter_pattern_enable(net, command, priv_cmd.total_len);
12883 }
12884 else if (strnicmp(command, CMD_PKTLOG_FILTER_PATTERN_DISABLE,
12885 strlen(CMD_PKTLOG_FILTER_PATTERN_DISABLE)) == 0) {
12886 bytes_written =
12887 wl_android_pktlog_filter_pattern_disable(net, command, priv_cmd.total_len);
12888 }
12889 else if (strnicmp(command, CMD_PKTLOG_FILTER_ADD, strlen(CMD_PKTLOG_FILTER_ADD)) == 0) {
12890 bytes_written = wl_android_pktlog_filter_add(net, command, priv_cmd.total_len);
12891 }
12892 else if (strnicmp(command, CMD_PKTLOG_FILTER_DEL, strlen(CMD_PKTLOG_FILTER_DEL)) == 0) {
12893 bytes_written = wl_android_pktlog_filter_del(net, command, priv_cmd.total_len);
12894 }
12895 else if (strnicmp(command, CMD_PKTLOG_FILTER_INFO, strlen(CMD_PKTLOG_FILTER_INFO)) == 0) {
12896 bytes_written = wl_android_pktlog_filter_info(net, command, priv_cmd.total_len);
12897 }
12898 else if (strnicmp(command, CMD_PKTLOG_START, strlen(CMD_PKTLOG_START)) == 0) {
12899 bytes_written = wl_android_pktlog_start(net, command, priv_cmd.total_len);
12900 }
12901 else if (strnicmp(command, CMD_PKTLOG_STOP, strlen(CMD_PKTLOG_STOP)) == 0) {
12902 bytes_written = wl_android_pktlog_stop(net, command, priv_cmd.total_len);
12903 }
12904 else if (strnicmp(command, CMD_PKTLOG_FILTER_EXIST, strlen(CMD_PKTLOG_FILTER_EXIST)) == 0) {
12905 bytes_written = wl_android_pktlog_filter_exist(net, command, priv_cmd.total_len);
12906 }
12907 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_ENABLE,
12908 strlen(CMD_PKTLOG_MINMIZE_ENABLE)) == 0) {
12909 bytes_written = wl_android_pktlog_minmize_enable(net, command, priv_cmd.total_len);
12910 }
12911 else if (strnicmp(command, CMD_PKTLOG_MINMIZE_DISABLE,
12912 strlen(CMD_PKTLOG_MINMIZE_DISABLE)) == 0) {
12913 bytes_written = wl_android_pktlog_minmize_disable(net, command, priv_cmd.total_len);
12914 }
12915 else if (strnicmp(command, CMD_PKTLOG_CHANGE_SIZE,
12916 strlen(CMD_PKTLOG_CHANGE_SIZE)) == 0) {
12917 bytes_written = wl_android_pktlog_change_size(net, command, priv_cmd.total_len);
12918 }
12919 else if (strnicmp(command, CMD_PKTLOG_DEBUG_DUMP, strlen(CMD_PKTLOG_DEBUG_DUMP)) == 0) {
12920 bytes_written = wl_android_pktlog_dbg_dump(net, command, priv_cmd.total_len);
12921 }
12922 #endif /* DHD_PKT_LOGGING */
12923 #ifdef WL_CFG80211
12924 else if (strnicmp(command, CMD_DEBUG_VERBOSE, strlen(CMD_DEBUG_VERBOSE)) == 0) {
12925 int verbose_level = *(command + strlen(CMD_DEBUG_VERBOSE) + 1) - '0';
12926 bytes_written = wl_cfg80211_set_dbg_verbose(net, verbose_level);
12927 }
12928 #endif /* WL_CFG80211 */
12929 #ifdef DHD_EVENT_LOG_FILTER
12930 else if (strnicmp(command, CMD_EWP_FILTER,
12931 strlen(CMD_EWP_FILTER)) == 0) {
12932 bytes_written = wl_android_ewp_filter(net, command, priv_cmd.total_len);
12933 }
12934 #endif /* DHD_EVENT_LOG_FILTER */
12935 #ifdef WL_BCNRECV
12936 else if (strnicmp(command, CMD_BEACON_RECV,
12937 strlen(CMD_BEACON_RECV)) == 0) {
12938 char *data = (command + strlen(CMD_BEACON_RECV) + 1);
12939 bytes_written = wl_android_bcnrecv_config(net,
12940 data, priv_cmd.total_len);
12941 }
12942 #endif /* WL_BCNRECV */
12943 #ifdef WL_MBO
12944 else if (strnicmp(command, CMD_MBO, strlen(CMD_MBO)) == 0) {
12945 bytes_written = wl_android_process_mbo_cmd(net, command,
12946 priv_cmd.total_len);
12947 }
12948 #endif /* WL_MBO */
12949 #ifdef WL_CAC_TS
12950 else if (strnicmp(command, CMD_CAC_TSPEC,
12951 strlen(CMD_CAC_TSPEC)) == 0) {
12952 char *data = (command + strlen(CMD_CAC_TSPEC) + 1);
12953 bytes_written = wl_android_cac_ts_config(net,
12954 data, priv_cmd.total_len);
12955 }
12956 #endif /* WL_CAC_TS */
12957 #ifdef WL_GET_CU
12958 else if (strnicmp(command, CMD_GET_CHAN_UTIL,
12959 strlen(CMD_GET_CHAN_UTIL)) == 0) {
12960 bytes_written = wl_android_get_channel_util(net,
12961 command, priv_cmd.total_len);
12962 }
12963 #endif /* WL_GET_CU */
12964 #ifdef RTT_GEOFENCE_INTERVAL
12965 #if defined (RTT_SUPPORT) && defined(WL_NAN)
12966 else if (strnicmp(command, CMD_GEOFENCE_INTERVAL,
12967 strlen(CMD_GEOFENCE_INTERVAL)) == 0) {
12968 (void)wl_android_set_rtt_geofence_interval(net, command);
12969 }
12970 #endif /* RTT_SUPPORT && WL_NAN */
12971 #endif /* RTT_GEOFENCE_INTERVAL */
12972 #ifdef SUPPORT_SOFTAP_ELNA_BYPASS
12973 else if (strnicmp(command, CMD_SET_SOFTAP_ELNA_BYPASS,
12974 strlen(CMD_SET_SOFTAP_ELNA_BYPASS)) == 0) {
12975 bytes_written =
12976 wl_android_set_softap_elna_bypass(net, command, priv_cmd.total_len);
12977 }
12978 else if (strnicmp(command, CMD_GET_SOFTAP_ELNA_BYPASS,
12979 strlen(CMD_GET_SOFTAP_ELNA_BYPASS)) == 0) {
12980 bytes_written =
12981 wl_android_get_softap_elna_bypass(net, command, priv_cmd.total_len);
12982 }
12983 #endif /* SUPPORT_SOFTAP_ELNA_BYPASS */
12984 #ifdef WL_NAN
12985 else if (strnicmp(command, CMD_GET_NAN_STATUS,
12986 strlen(CMD_GET_NAN_STATUS)) == 0) {
12987 bytes_written =
12988 wl_android_get_nan_status(net, command, priv_cmd.total_len);
12989 }
12990 #endif /* WL_NAN */
12991 #if defined(SUPPORT_NAN_RANGING_TEST_BW)
12992 else if (strnicmp(command, CMD_NAN_RANGING_SET_BW, strlen(CMD_NAN_RANGING_SET_BW)) == 0) {
12993 int bw_cmd = *(command + strlen(CMD_NAN_RANGING_SET_BW) + 1) - '0';
12994 bytes_written = wl_nan_ranging_bw(net, bw_cmd, command);
12995 }
12996 #endif /* SUPPORT_NAN_RANGING_TEST_BW */
12997 else if (strnicmp(command, CMD_GET_FACTORY_MAC, strlen(CMD_GET_FACTORY_MAC)) == 0) {
12998 bytes_written = wl_android_get_factory_mac_addr(net, command, priv_cmd.total_len);
12999 }
13000 else if (strnicmp(command, CMD_HAPD_SET_AX_MODE, strlen(CMD_HAPD_SET_AX_MODE)) == 0) {
13001 int skip = strlen(CMD_HAPD_SET_AX_MODE) + 1;
13002 bytes_written = wl_android_set_softap_ax_mode(net, command + skip);
13003 }
13004 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
13005 else if (strnicmp(command, CMD_SET_LATENCY_CRITICAL_DATA,
13006 strlen(CMD_SET_LATENCY_CRITICAL_DATA)) == 0) {
13007 int enable = *(command + strlen(CMD_SET_LATENCY_CRITICAL_DATA) + 1) - '0';
13008 bytes_written = wl_android_set_latency_crt_data(net, enable);
13009 }
13010 else if (strnicmp(command, CMD_GET_LATENCY_CRITICAL_DATA,
13011 strlen(CMD_GET_LATENCY_CRITICAL_DATA)) == 0) {
13012 bytes_written = wl_android_get_latency_crt_data(net, command, priv_cmd.total_len);
13013 }
13014 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
13015 #ifdef WL_TWT
13016 else if (strnicmp(command, CMD_TWT_SETUP, strlen(CMD_TWT_SETUP)) == 0) {
13017 bytes_written = wl_android_twt_setup(net, command, priv_cmd.total_len);
13018 }
13019 else if (strnicmp(command, CMD_TWT_TEARDOWN, strlen(CMD_TWT_TEARDOWN)) == 0) {
13020 bytes_written = wl_android_twt_teardown(net, command, priv_cmd.total_len);
13021 }
13022 else if (strnicmp(command, CMD_TWT_INFO, strlen(CMD_TWT_INFO)) == 0) {
13023 bytes_written = wl_android_twt_info(net, command, priv_cmd.total_len);
13024 }
13025 else if (strnicmp(command, CMD_TWT_STATUS_QUERY, strlen(CMD_TWT_STATUS_QUERY)) == 0) {
13026 bytes_written = wl_android_twt_status_query(net, command, priv_cmd.total_len);
13027 }
13028 else if (strnicmp(command, CMD_TWT_CAPABILITY, strlen(CMD_TWT_CAPABILITY)) == 0) {
13029 bytes_written = wl_android_twt_cap(net, command, priv_cmd.total_len);
13030 }
13031 else if ((strnicmp(command, CMD_TWT_GET_STATS, strlen(CMD_TWT_GET_STATS)) == 0) ||
13032 (strnicmp(command, CMD_TWT_CLR_STATS, strlen(CMD_TWT_CLR_STATS)) == 0)) {
13033 bytes_written = wl_android_twt_stats(net, command, priv_cmd.total_len);
13034 }
13035 #endif /* WL_TWT */
13036 #ifdef WL_P2P_6G
13037 else if (strnicmp(command, CMD_ENABLE_6G_P2P, strlen(CMD_ENABLE_6G_P2P)) == 0) {
13038 int enable = *(command + strlen(CMD_ENABLE_6G_P2P) + 1) - '0';
13039 bytes_written = wl_android_enable_p2p_6g(net, enable);
13040 }
13041 #endif /* WL_P2P_6G */
13042 else if (wl_android_ext_priv_cmd(net, command, priv_cmd.total_len, &bytes_written) == 0) {
13043 }
13044 else {
13045 ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
13046 bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
13047 }
13048
13049 return bytes_written;
13050 }
13051
13052 /*
13053 * ENABLE_INSMOD_NO_FW_LOAD X O O O
13054 * ENABLE_INSMOD_NO_POWER_OFF X X O O
13055 * NO_POWER_OFF_AFTER_OPEN X X X O
13056 * after insmod H L H H
13057 * wlan0 down H L L H
13058 * fw trap trigger wlan0 down H L L L
13059 */
13060
wl_android_init(void)13061 int wl_android_init(void)
13062 {
13063 int ret = 0;
13064
13065 #ifdef ENABLE_INSMOD_NO_POWER_OFF
13066 dhd_download_fw_on_driverload = TRUE;
13067 #elif defined(ENABLE_INSMOD_NO_FW_LOAD) || defined(BUS_POWER_RESTORE)
13068 dhd_download_fw_on_driverload = FALSE;
13069 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
13070 if (!iface_name[0]) {
13071 bzero(iface_name, IFNAMSIZ);
13072 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
13073 }
13074
13075 #ifdef CUSTOMER_HW4_DEBUG
13076 /* No Kernel Panic from ASSERT() on customer platform. */
13077 g_assert_type = 1;
13078 #endif /* CUSTOMER_HW4_DEBUG */
13079
13080 #ifdef WL_GENL
13081 wl_genl_init();
13082 #endif
13083 #ifdef WL_RELMCAST
13084 wl_netlink_init();
13085 #endif /* WL_RELMCAST */
13086
13087 return ret;
13088 }
13089
wl_android_exit(void)13090 int wl_android_exit(void)
13091 {
13092 int ret = 0;
13093 struct io_cfg *cur, *q;
13094
13095 #ifdef WL_GENL
13096 wl_genl_deinit();
13097 #endif /* WL_GENL */
13098 #ifdef WL_RELMCAST
13099 wl_netlink_deinit();
13100 #endif /* WL_RELMCAST */
13101
13102 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
13103 list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
13104 GCC_DIAGNOSTIC_POP();
13105 list_del(&cur->list);
13106 kfree(cur);
13107 }
13108
13109 return ret;
13110 }
13111
wl_android_post_init(void)13112 void wl_android_post_init(void)
13113 {
13114
13115 #ifdef ENABLE_4335BT_WAR
13116 bcm_bt_unlock(lock_cookie_wifi);
13117 ANDROID_ERROR(("%s: btlock released\n", __FUNCTION__));
13118 #endif /* ENABLE_4335BT_WAR */
13119
13120 if (!dhd_download_fw_on_driverload) {
13121 g_wifi_on = FALSE;
13122 }
13123 }
13124
13125 #ifdef WL_GENL
13126 /* Generic Netlink Initializaiton */
wl_genl_init(void)13127 static int wl_genl_init(void)
13128 {
13129 int ret;
13130
13131 ANDROID_INFO(("GEN Netlink Init\n\n"));
13132
13133 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13134 /* register new family */
13135 ret = genl_register_family(&wl_genl_family);
13136 if (ret != 0)
13137 goto failure;
13138
13139 /* register functions (commands) of the new family */
13140 ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
13141 if (ret != 0) {
13142 ANDROID_ERROR(("register ops failed: %i\n", ret));
13143 genl_unregister_family(&wl_genl_family);
13144 goto failure;
13145 }
13146
13147 ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
13148 #else
13149 ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
13150 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
13151 if (ret != 0) {
13152 ANDROID_ERROR(("register mc_group failed: %i\n", ret));
13153 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13154 genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
13155 #endif
13156 genl_unregister_family(&wl_genl_family);
13157 goto failure;
13158 }
13159
13160 return 0;
13161
13162 failure:
13163 ANDROID_ERROR(("Registering Netlink failed!!\n"));
13164 return -1;
13165 }
13166
13167 /* Generic netlink deinit */
wl_genl_deinit(void)13168 static int wl_genl_deinit(void)
13169 {
13170
13171 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
13172 if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
13173 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13174 #endif
13175 if (genl_unregister_family(&wl_genl_family) < 0)
13176 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
13177
13178 return 0;
13179 }
13180
wl_event_to_bcm_event(u16 event_type)13181 s32 wl_event_to_bcm_event(u16 event_type)
13182 {
13183 /* When you add any new event, please mention the
13184 * version of BCM supplicant supporting it
13185 */
13186 u16 event = -1;
13187
13188 switch (event_type) {
13189 case WLC_E_SERVICE_FOUND:
13190 event = BCM_E_SVC_FOUND;
13191 break;
13192 case WLC_E_P2PO_ADD_DEVICE:
13193 event = BCM_E_DEV_FOUND;
13194 break;
13195 case WLC_E_P2PO_DEL_DEVICE:
13196 event = BCM_E_DEV_LOST;
13197 break;
13198 /* Above events are supported from BCM Supp ver 47 Onwards */
13199 #ifdef BT_WIFI_HANDOVER
13200 case WLC_E_BT_WIFI_HANDOVER_REQ:
13201 event = BCM_E_DEV_BT_WIFI_HO_REQ;
13202 break;
13203 #endif /* BT_WIFI_HANDOVER */
13204
13205 default:
13206 ANDROID_ERROR(("Event not supported\n"));
13207 }
13208
13209 return event;
13210 }
13211
13212 s32
wl_genl_send_msg(struct net_device * ndev,u32 event_type,const u8 * buf,u16 len,u8 * subhdr,u16 subhdr_len)13213 wl_genl_send_msg(
13214 struct net_device *ndev,
13215 u32 event_type,
13216 const u8 *buf,
13217 u16 len,
13218 u8 *subhdr,
13219 u16 subhdr_len)
13220 {
13221 int ret = 0;
13222 struct sk_buff *skb;
13223 void *msg;
13224 u32 attr_type = 0;
13225 bcm_event_hdr_t *hdr = NULL;
13226 int mcast = 1; /* By default sent as mutlicast type */
13227 int pid = 0;
13228 u8 *ptr = NULL, *p = NULL;
13229 u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
13230 u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
13231 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13232
13233 ANDROID_INFO(("Enter \n"));
13234
13235 /* Decide between STRING event and Data event */
13236 if (event_type == 0)
13237 attr_type = BCM_GENL_ATTR_STRING;
13238 else
13239 attr_type = BCM_GENL_ATTR_MSG;
13240
13241 skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
13242 if (skb == NULL) {
13243 ret = -ENOMEM;
13244 goto out;
13245 }
13246
13247 msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
13248 if (msg == NULL) {
13249 ret = -ENOMEM;
13250 goto out;
13251 }
13252
13253 if (attr_type == BCM_GENL_ATTR_STRING) {
13254 /* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
13255 * make sure it is null terminated
13256 */
13257 if (subhdr || subhdr_len) {
13258 ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n"));
13259 ret = -EINVAL;
13260 goto out;
13261 }
13262
13263 ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
13264 if (ret != 0) {
13265 ANDROID_ERROR(("nla_put_string failed\n"));
13266 goto out;
13267 }
13268 } else {
13269 /* ATTR_MSG */
13270
13271 /* Create a single buffer for all */
13272 p = ptr = (u8 *)MALLOCZ(cfg->osh, tot_len);
13273 if (!ptr) {
13274 ret = -ENOMEM;
13275 ANDROID_ERROR(("ENOMEM!!\n"));
13276 goto out;
13277 }
13278
13279 /* Include the bcm event header */
13280 hdr = (bcm_event_hdr_t *)ptr;
13281 hdr->event_type = wl_event_to_bcm_event(event_type);
13282 hdr->len = len + subhdr_len;
13283 ptr += sizeof(bcm_event_hdr_t);
13284
13285 /* Copy subhdr (if any) */
13286 if (subhdr && subhdr_len) {
13287 memcpy(ptr, subhdr, subhdr_len);
13288 ptr += subhdr_len;
13289 }
13290
13291 /* Copy the data */
13292 if (buf && len) {
13293 memcpy(ptr, buf, len);
13294 }
13295
13296 ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
13297 if (ret != 0) {
13298 ANDROID_ERROR(("nla_put_string failed\n"));
13299 goto out;
13300 }
13301 }
13302
13303 if (mcast) {
13304 int err = 0;
13305 /* finalize the message */
13306 genlmsg_end(skb, msg);
13307 /* NETLINK_CB(skb).dst_group = 1; */
13308
13309 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
13310 if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
13311 #else
13312 if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
13313 #endif
13314 ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
13315 attr_type, err));
13316 else
13317 ANDROID_INFO(("Multicast msg sent successfully. attr_type:%d len:%d \n",
13318 attr_type, tot_len));
13319 } else {
13320 NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
13321
13322 /* finalize the message */
13323 genlmsg_end(skb, msg);
13324
13325 /* send the message back */
13326 if (genlmsg_unicast(&init_net, skb, pid) < 0)
13327 ANDROID_ERROR(("genlmsg_unicast failed\n"));
13328 }
13329
13330 out:
13331 if (p) {
13332 MFREE(cfg->osh, p, tot_len);
13333 }
13334 if (ret)
13335 nlmsg_free(skb);
13336
13337 return ret;
13338 }
13339
13340 static s32
wl_genl_handle_msg(struct sk_buff * skb,struct genl_info * info)13341 wl_genl_handle_msg(
13342 struct sk_buff *skb,
13343 struct genl_info *info)
13344 {
13345 struct nlattr *na;
13346 u8 *data = NULL;
13347
13348 ANDROID_INFO(("Enter \n"));
13349
13350 if (info == NULL) {
13351 return -EINVAL;
13352 }
13353
13354 na = info->attrs[BCM_GENL_ATTR_MSG];
13355 if (!na) {
13356 ANDROID_ERROR(("nlattribute NULL\n"));
13357 return -EINVAL;
13358 }
13359
13360 data = (char *)nla_data(na);
13361 if (!data) {
13362 ANDROID_ERROR(("Invalid data\n"));
13363 return -EINVAL;
13364 } else {
13365 /* Handle the data */
13366 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || \
13367 defined(WL_COMPAT_WIRELESS)
13368 ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13369 info->snd_pid));
13370 #else
13371 ANDROID_INFO(("%s: Data received from pid (%d) \n", __func__,
13372 info->snd_portid));
13373 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
13374 }
13375
13376 return 0;
13377 }
13378 #endif /* WL_GENL */
13379
wl_fatal_error(void * wl,int rc)13380 int wl_fatal_error(void * wl, int rc)
13381 {
13382 return FALSE;
13383 }
13384
13385 void
wl_android_set_wifi_on_flag(bool enable)13386 wl_android_set_wifi_on_flag(bool enable)
13387 {
13388 ANDROID_ERROR(("%s: %d\n", __FUNCTION__, enable));
13389 g_wifi_on = enable;
13390 }
13391
13392 #ifdef WL_STATIC_IF
13393 #include <dhd_linux_priv.h>
13394 struct net_device *
wl_cfg80211_register_static_if(struct bcm_cfg80211 * cfg,u16 iftype,char * ifname,int static_ifidx)13395 wl_cfg80211_register_static_if(struct bcm_cfg80211 *cfg, u16 iftype, char *ifname,
13396 int static_ifidx)
13397 {
13398 #if defined(CUSTOM_MULTI_MAC) || defined(WL_EXT_IAPSTA)
13399 dhd_pub_t *dhd = cfg->pub;
13400 #endif
13401 struct net_device *ndev;
13402 struct wireless_dev *wdev = NULL;
13403 int ifidx = WL_STATIC_IFIDX; /* Register ndev with a reserved ifidx */
13404 u8 mac_addr[ETH_ALEN];
13405 struct net_device *primary_ndev;
13406 #ifdef DHD_USE_RANDMAC
13407 struct ether_addr ea_addr;
13408 #endif /* DHD_USE_RANDMAC */
13409 #ifdef CUSTOM_MULTI_MAC
13410 char hw_ether[62];
13411 #endif
13412
13413 ANDROID_INFO(("[STATIC_IF] Enter (%s) iftype:%d\n", ifname, iftype));
13414
13415 if (!cfg) {
13416 ANDROID_ERROR(("cfg null\n"));
13417 return NULL;
13418 }
13419 primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13420
13421 ifidx += static_ifidx;
13422 #ifdef DHD_USE_RANDMAC
13423 wl_cfg80211_generate_mac_addr(&ea_addr);
13424 (void)memcpy_s(mac_addr, ETH_ALEN, ea_addr.octet, ETH_ALEN);
13425 #else
13426 #if defined(CUSTOM_MULTI_MAC)
13427 if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1)) {
13428 (void)memcpy_s(mac_addr, ETH_ALEN, hw_ether, ETH_ALEN);
13429 } else
13430 #endif
13431 {
13432 /* Use primary mac with locally admin bit set */
13433 (void)memcpy_s(mac_addr, ETH_ALEN, primary_ndev->dev_addr, ETH_ALEN);
13434 mac_addr[0] |= 0x02;
13435 #ifdef WL_EXT_IAPSTA
13436 wl_ext_iapsta_get_vif_macaddr(dhd, static_ifidx+1, mac_addr);
13437 #endif
13438 }
13439 #endif /* DHD_USE_RANDMAC */
13440
13441 ndev = wl_cfg80211_allocate_if(cfg, ifidx, ifname, mac_addr,
13442 WL_BSSIDX_MAX, NULL);
13443 if (unlikely(!ndev)) {
13444 ANDROID_ERROR(("Failed to allocate static_if\n"));
13445 goto fail;
13446 }
13447 wdev = (struct wireless_dev *)MALLOCZ(cfg->osh, sizeof(*wdev));
13448 if (unlikely(!wdev)) {
13449 ANDROID_ERROR(("Failed to allocate wdev for static_if\n"));
13450 goto fail;
13451 }
13452
13453 wdev->wiphy = cfg->wdev->wiphy;
13454 wdev->iftype = iftype;
13455
13456 ndev->ieee80211_ptr = wdev;
13457 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
13458 wdev->netdev = ndev;
13459
13460 if (wl_cfg80211_register_if(cfg, ifidx,
13461 ndev, TRUE) != BCME_OK) {
13462 ANDROID_ERROR(("ndev registration failed!\n"));
13463 goto fail;
13464 }
13465
13466 cfg->static_ndev[static_ifidx] = ndev;
13467 cfg->static_ndev_state[static_ifidx] = NDEV_STATE_OS_IF_CREATED;
13468 wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL, WL_BSSIDX_MAX,
13469 ifname, NDEV_STATE_OS_IF_CREATED);
13470 ANDROID_INFO(("Static I/F (%s) Registered\n", ndev->name));
13471 return ndev;
13472
13473 fail:
13474 wl_cfg80211_remove_if(cfg, ifidx, ndev, false);
13475 return NULL;
13476 }
13477
13478 void
wl_cfg80211_unregister_static_if(struct bcm_cfg80211 * cfg)13479 wl_cfg80211_unregister_static_if(struct bcm_cfg80211 *cfg)
13480 {
13481 int i;
13482
13483 ANDROID_INFO(("[STATIC_IF] Enter\n"));
13484 if (!cfg) {
13485 ANDROID_ERROR(("invalid input\n"));
13486 return;
13487 }
13488
13489 /* wdev free will happen from notifier context */
13490 /* free_netdev(cfg->static_ndev);
13491 */
13492 for (i=0; i<DHD_MAX_STATIC_IFS; i++) {
13493 if (cfg->static_ndev[i])
13494 unregister_netdev(cfg->static_ndev[i]);
13495 }
13496 }
13497
13498 s32
wl_cfg80211_static_if_open(struct net_device * net)13499 wl_cfg80211_static_if_open(struct net_device *net)
13500 {
13501 struct wireless_dev *wdev = NULL;
13502 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13503 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13504 u16 iftype = net->ieee80211_ptr ? net->ieee80211_ptr->iftype : 0;
13505 u16 wl_iftype, wl_mode;
13506 #ifdef CUSTOM_MULTI_MAC
13507 dhd_pub_t *dhd = dhd_get_pub(net);
13508 char hw_ether[62];
13509 #endif
13510 int static_ifidx;
13511
13512 ANDROID_INFO(("[STATIC_IF] dev_open ndev %p and wdev %p\n", net, net->ieee80211_ptr));
13513 static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
13514 ASSERT(static_ifidx >= 0);
13515
13516 if (cfg80211_to_wl_iftype(iftype, &wl_iftype, &wl_mode) < 0) {
13517 return BCME_ERROR;
13518 }
13519 if (cfg->static_ndev_state[static_ifidx] != NDEV_STATE_FW_IF_CREATED) {
13520 #ifdef CUSTOM_MULTI_MAC
13521 if (!wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether, static_ifidx+1))
13522 dev_addr_set(net, hw_ether);
13523 #endif
13524 wdev = wl_cfg80211_add_if(cfg, primary_ndev, wl_iftype, net->name, net->dev_addr);
13525 if (!wdev) {
13526 ANDROID_ERROR(("[STATIC_IF] wdev is NULL, can't proceed\n"));
13527 return BCME_ERROR;
13528 }
13529 } else {
13530 ANDROID_INFO(("Fw IF for static netdev already created\n"));
13531 }
13532
13533 return BCME_OK;
13534 }
13535
13536 s32
wl_cfg80211_static_if_close(struct net_device * net)13537 wl_cfg80211_static_if_close(struct net_device *net)
13538 {
13539 int ret = BCME_OK;
13540 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
13541 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
13542 int static_ifidx;
13543
13544 static_ifidx = wl_cfg80211_static_ifidx(cfg, net);
13545
13546 if (cfg->static_ndev_state[static_ifidx] == NDEV_STATE_FW_IF_CREATED) {
13547 if (mutex_is_locked(&cfg->if_sync) == TRUE) {
13548 ret = _wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13549 } else {
13550 ret = wl_cfg80211_del_if(cfg, primary_ndev, net->ieee80211_ptr, net->name);
13551 }
13552
13553 if (unlikely(ret)) {
13554 ANDROID_ERROR(("Del iface failed for static_if %d\n", ret));
13555 }
13556 }
13557
13558 return ret;
13559 }
13560 struct net_device *
wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 * cfg,wl_if_event_info * event,u8 * addr,s32 iface_type,int static_ifidx)13561 wl_cfg80211_post_static_ifcreate(struct bcm_cfg80211 *cfg,
13562 wl_if_event_info *event, u8 *addr, s32 iface_type, int static_ifidx)
13563 {
13564 struct net_device *new_ndev = NULL;
13565 struct wireless_dev *wdev = NULL;
13566
13567 ANDROID_INFO(("Updating static iface after Fw IF create \n"));
13568 new_ndev = cfg->static_ndev[static_ifidx];
13569
13570 if (new_ndev) {
13571 wdev = new_ndev->ieee80211_ptr;
13572 ASSERT(wdev);
13573 wdev->iftype = iface_type;
13574 dev_addr_set(new_ndev, addr);
13575 }
13576
13577 cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_CREATED;
13578 wl_cfg80211_update_iflist_info(cfg, new_ndev, event->ifidx, addr, event->bssidx,
13579 event->name, NDEV_STATE_FW_IF_CREATED);
13580 return new_ndev;
13581 }
13582 s32
wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 * cfg,struct net_device * ndev)13583 wl_cfg80211_post_static_ifdel(struct bcm_cfg80211 *cfg, struct net_device *ndev)
13584 {
13585 int static_ifidx;
13586 int ifidx = WL_STATIC_IFIDX;
13587
13588 static_ifidx = wl_cfg80211_static_ifidx(cfg, ndev);
13589 ifidx += static_ifidx;
13590 cfg->static_ndev_state[static_ifidx] = NDEV_STATE_FW_IF_DELETED;
13591 wl_cfg80211_update_iflist_info(cfg, ndev, ifidx, NULL,
13592 WL_BSSIDX_MAX, NULL, NDEV_STATE_FW_IF_DELETED);
13593 wl_cfg80211_clear_per_bss_ies(cfg, ndev->ieee80211_ptr);
13594 wl_dealloc_netinfo_by_wdev(cfg, ndev->ieee80211_ptr);
13595 return BCME_OK;
13596 }
13597 #endif /* WL_STATIC_IF */
13598
13599 #ifdef WBTEXT
13600 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)13601 wlc_wbtext_get_roam_prof(struct net_device *ndev, wl_roamprof_band_t *rp,
13602 uint8 band, uint8 *roam_prof_ver, uint8 *roam_prof_size)
13603 {
13604 int err = BCME_OK;
13605 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13606 u8 *ioctl_buf = NULL;
13607
13608 ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13609 if (unlikely(!ioctl_buf)) {
13610 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13611 err = -ENOMEM;
13612 goto exit;
13613 }
13614 rp->v1.band = band;
13615 rp->v1.len = 0;
13616 /* Getting roam profile from fw */
13617 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13618 ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13619 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13620 goto exit;
13621 }
13622 memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13623 /* roam_prof version get */
13624 if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13625 ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13626 err = BCME_VERSION;
13627 goto exit;
13628 }
13629 switch (rp->v1.ver) {
13630 case WL_ROAM_PROF_VER_0:
13631 {
13632 *roam_prof_size = sizeof(wl_roam_prof_v1_t);
13633 *roam_prof_ver = WL_ROAM_PROF_VER_0;
13634 }
13635 break;
13636 case WL_ROAM_PROF_VER_1:
13637 {
13638 *roam_prof_size = sizeof(wl_roam_prof_v2_t);
13639 *roam_prof_ver = WL_ROAM_PROF_VER_1;
13640 }
13641 break;
13642 case WL_ROAM_PROF_VER_2:
13643 {
13644 *roam_prof_size = sizeof(wl_roam_prof_v3_t);
13645 *roam_prof_ver = WL_ROAM_PROF_VER_2;
13646 }
13647 break;
13648 case WL_ROAM_PROF_VER_3:
13649 {
13650 *roam_prof_size = sizeof(wl_roam_prof_v4_t);
13651 *roam_prof_ver = WL_ROAM_PROF_VER_3;
13652 }
13653 break;
13654 default:
13655 ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13656 err = BCME_VERSION;
13657 goto exit;
13658 }
13659 ANDROID_INFO(("roam prof ver %u size %u\n", *roam_prof_ver, *roam_prof_size));
13660 if ((rp->v1.len % *roam_prof_size) != 0) {
13661 ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13662 err = BCME_BADLEN;
13663 }
13664 exit:
13665 if (ioctl_buf) {
13666 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
13667 }
13668 return err;
13669 }
13670
13671 s32
wl_cfg80211_wbtext_set_default(struct net_device * ndev)13672 wl_cfg80211_wbtext_set_default(struct net_device *ndev)
13673 {
13674 char *commandp = NULL;
13675 s32 ret = BCME_OK;
13676 char *data;
13677 u8 *ioctl_buf = NULL;
13678 wl_roamprof_band_t rp;
13679 uint8 bandidx = 0;
13680 int wnmmask = 0;
13681 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13682
13683 ANDROID_INFO(("set wbtext to default\n"));
13684
13685 commandp = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13686 if (unlikely(!commandp)) {
13687 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13688 ret = -ENOMEM;
13689 goto exit;
13690 }
13691 ioctl_buf = (char *)MALLOCZ(cfg->osh, WLC_IOCTL_SMLEN);
13692 if (unlikely(!ioctl_buf)) {
13693 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13694 ret = -ENOMEM;
13695 goto exit;
13696 }
13697
13698 rp.v1.band = WLC_BAND_2G;
13699 rp.v1.len = 0;
13700 /* Getting roam profile from fw */
13701 if ((ret = wldev_iovar_getbuf(ndev, "roam_prof", &rp, sizeof(rp),
13702 ioctl_buf, WLC_IOCTL_SMLEN, NULL))) {
13703 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", ret));
13704 goto exit;
13705 }
13706 memcpy_s(&rp, sizeof(rp), ioctl_buf, sizeof(rp));
13707 for (bandidx = 0; bandidx < MAXBANDS; bandidx++) {
13708 switch (rp.v1.ver) {
13709 case WL_ROAM_PROF_VER_1:
13710 {
13711 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13712 if (bandidx == BAND_5G_INDEX) {
13713 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13714 CMD_WBTEXT_PROFILE_CONFIG,
13715 DEFAULT_WBTEXT_PROFILE_A_V2);
13716 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13717 } else {
13718 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13719 CMD_WBTEXT_PROFILE_CONFIG,
13720 DEFAULT_WBTEXT_PROFILE_B_V2);
13721 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13722 }
13723 }
13724 break;
13725 case WL_ROAM_PROF_VER_2:
13726 case WL_ROAM_PROF_VER_3:
13727 {
13728 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13729 if (bandidx == BAND_5G_INDEX) {
13730 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13731 CMD_WBTEXT_PROFILE_CONFIG,
13732 DEFAULT_WBTEXT_PROFILE_A_V3);
13733 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13734 } else {
13735 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13736 CMD_WBTEXT_PROFILE_CONFIG,
13737 DEFAULT_WBTEXT_PROFILE_B_V3);
13738 data = (commandp + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
13739 }
13740 }
13741 break;
13742 default:
13743 ANDROID_ERROR(("No Support for roam prof ver = %d \n", rp.v1.ver));
13744 ret = -EINVAL;
13745 goto exit;
13746 }
13747 /* set roam profile */
13748 ret = wl_cfg80211_wbtext_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13749 if (ret != BCME_OK) {
13750 ANDROID_ERROR(("%s: Failed to set roam_prof %s error = %d\n",
13751 __FUNCTION__, data, ret));
13752 goto exit;
13753 }
13754 }
13755
13756 /* wbtext code for backward compatibility. Newer firmwares set default value
13757 * from fw init
13758 */
13759 /* set RSSI weight */
13760 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13761 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13762 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_A);
13763 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13764 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13765 if (ret != BCME_OK) {
13766 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13767 __FUNCTION__, data, ret));
13768 goto exit;
13769 }
13770
13771 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13772 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13773 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_RSSI_B);
13774 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13775 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13776 if (ret != BCME_OK) {
13777 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13778 __FUNCTION__, data, ret));
13779 goto exit;
13780 }
13781
13782 /* set CU weight */
13783 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13784 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13785 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_A);
13786 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13787 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13788 if (ret != BCME_OK) {
13789 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13790 __FUNCTION__, data, ret));
13791 goto exit;
13792 }
13793
13794 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13795 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13796 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_CU_B);
13797 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13798 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13799 if (ret != BCME_OK) {
13800 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13801 __FUNCTION__, data, ret));
13802 goto exit;
13803 }
13804
13805 ret = wldev_iovar_getint(ndev, "wnm", &wnmmask);
13806 if (ret != BCME_OK) {
13807 ANDROID_ERROR(("%s: Failed to get wnmmask error = %d\n", __func__, ret));
13808 goto exit;
13809 }
13810 /* set ESTM DL weight. */
13811 if (wnmmask & WL_WNM_ESTM) {
13812 ANDROID_ERROR(("Setting ESTM wt\n"));
13813 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13814 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13815 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_A);
13816 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13817 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13818 if (ret != BCME_OK) {
13819 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13820 __FUNCTION__, data, ret));
13821 goto exit;
13822 }
13823
13824 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13825 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13826 CMD_WBTEXT_WEIGHT_CONFIG, DEFAULT_WBTEXT_WEIGHT_ESTM_DL_B);
13827 data = (commandp + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
13828 ret = wl_cfg80211_wbtext_weight_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13829 if (ret != BCME_OK) {
13830 ANDROID_ERROR(("%s: Failed to set weight config %s error = %d\n",
13831 __FUNCTION__, data, ret));
13832 goto exit;
13833 }
13834 }
13835
13836 /* set RSSI table */
13837 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13838 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13839 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_A);
13840 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13841 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13842 if (ret != BCME_OK) {
13843 ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13844 __FUNCTION__, data, ret));
13845 goto exit;
13846 }
13847
13848 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13849 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13850 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_RSSI_B);
13851 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13852 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13853 if (ret != BCME_OK) {
13854 ANDROID_ERROR(("%s: Failed to set RSSI table %s error = %d\n",
13855 __FUNCTION__, data, ret));
13856 goto exit;
13857 }
13858
13859 /* set CU table */
13860 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13861 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13862 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_A);
13863 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13864 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13865 if (ret != BCME_OK) {
13866 ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13867 __FUNCTION__, data, ret));
13868 goto exit;
13869 }
13870
13871 memset_s(commandp, WLC_IOCTL_SMLEN, 0, WLC_IOCTL_SMLEN);
13872 snprintf(commandp, WLC_IOCTL_SMLEN, "%s %s",
13873 CMD_WBTEXT_TABLE_CONFIG, DEFAULT_WBTEXT_TABLE_CU_B);
13874 data = (commandp + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
13875 ret = wl_cfg80211_wbtext_table_config(ndev, data, commandp, WLC_IOCTL_SMLEN);
13876 if (ret != BCME_OK) {
13877 ANDROID_ERROR(("%s: Failed to set CU table %s error = %d\n",
13878 __FUNCTION__, data, ret));
13879 goto exit;
13880 }
13881
13882 exit:
13883 if (commandp) {
13884 MFREE(cfg->osh, commandp, WLC_IOCTL_SMLEN);
13885 }
13886 if (ioctl_buf) {
13887 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_SMLEN);
13888 }
13889 return ret;
13890 }
13891
13892 s32
wl_cfg80211_wbtext_config(struct net_device * ndev,char * data,char * command,int total_len)13893 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
13894 {
13895 uint i = 0;
13896 long int rssi_lower, roam_trigger;
13897 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
13898 wl_roamprof_band_t *rp = NULL;
13899 int err = -EINVAL, bytes_written = 0;
13900 size_t len = strlen(data);
13901 int rp_len = 0;
13902 u8 *ioctl_buf = NULL;
13903 uint8 roam_prof_size = 0, roam_prof_ver = 0, fs_per = 0, prof_cnt = 0;
13904
13905 data[len] = '\0';
13906 ioctl_buf = (u8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
13907 if (unlikely(!ioctl_buf)) {
13908 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13909 err = -ENOMEM;
13910 goto exit;
13911 }
13912 rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
13913 if (unlikely(!rp)) {
13914 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
13915 err = -ENOMEM;
13916 goto exit;
13917 }
13918 if (*data && (!strncmp(data, "b", 1))) {
13919 rp->v1.band = WLC_BAND_2G;
13920 } else if (*data && (!strncmp(data, "a", 1))) {
13921 rp->v1.band = WLC_BAND_5G;
13922 } else {
13923 err = snprintf(command, total_len, "Missing band\n");
13924 goto exit;
13925 }
13926 data++;
13927 rp->v1.len = 0;
13928 /* Getting roam profile from fw */
13929 if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
13930 ioctl_buf, WLC_IOCTL_MEDLEN, NULL))) {
13931 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
13932 goto exit;
13933 }
13934 memcpy_s(rp, sizeof(*rp), ioctl_buf, sizeof(*rp));
13935 /* roam_prof version get */
13936 if (rp->v1.ver > WL_ROAM_PROF_VER_3) {
13937 ANDROID_ERROR(("bad version (=%d) in return data\n", rp->v1.ver));
13938 err = -EINVAL;
13939 goto exit;
13940 }
13941 switch (rp->v1.ver) {
13942 case WL_ROAM_PROF_VER_0:
13943 {
13944 roam_prof_size = sizeof(wl_roam_prof_v1_t);
13945 roam_prof_ver = WL_ROAM_PROF_VER_0;
13946 }
13947 break;
13948 case WL_ROAM_PROF_VER_1:
13949 {
13950 roam_prof_size = sizeof(wl_roam_prof_v2_t);
13951 roam_prof_ver = WL_ROAM_PROF_VER_1;
13952 }
13953 break;
13954 case WL_ROAM_PROF_VER_2:
13955 {
13956 roam_prof_size = sizeof(wl_roam_prof_v3_t);
13957 roam_prof_ver = WL_ROAM_PROF_VER_2;
13958 }
13959 break;
13960 case WL_ROAM_PROF_VER_3:
13961 {
13962 roam_prof_size = sizeof(wl_roam_prof_v4_t);
13963 roam_prof_ver = WL_ROAM_PROF_VER_3;
13964 }
13965 break;
13966 default:
13967 ANDROID_ERROR(("bad version = %d \n", rp->v1.ver));
13968 goto exit;
13969 }
13970 ANDROID_INFO(("roam prof ver %u size %u\n", roam_prof_ver, roam_prof_size));
13971 if ((rp->v1.len % roam_prof_size) != 0) {
13972 ANDROID_ERROR(("bad length (=%d) in return data\n", rp->v1.len));
13973 err = -EINVAL;
13974 goto exit;
13975 }
13976 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
13977 /* printing contents of roam profile data from fw and exits
13978 * if code hits any of one of the below condtion. If remaining
13979 * length of buffer is less than roam profile size or
13980 * if there is no valid entry.
13981 */
13982 if (((i * roam_prof_size) > rp->v1.len)) {
13983 break;
13984 }
13985 if (roam_prof_ver == WL_ROAM_PROF_VER_0) {
13986 fs_per = rp->v1.roam_prof[i].fullscan_period;
13987 } else if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
13988 fs_per = rp->v2.roam_prof[i].fullscan_period;
13989 } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
13990 fs_per = rp->v3.roam_prof[i].fullscan_period;
13991 } else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
13992 fs_per = rp->v4.roam_prof[i].fullscan_period;
13993 }
13994 if (fs_per == 0) {
13995 break;
13996 }
13997 prof_cnt++;
13998 }
13999
14000 if (!*data) {
14001 for (i = 0; (i < prof_cnt) && (i < WL_MAX_ROAM_PROF_BRACKETS); i++) {
14002 if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14003 bytes_written += scnprintf(command+bytes_written,
14004 total_len - bytes_written,
14005 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
14006 rp->v2.roam_prof[i].roam_trigger,
14007 rp->v2.roam_prof[i].rssi_lower,
14008 rp->v2.roam_prof[i].channel_usage,
14009 rp->v2.roam_prof[i].cu_avg_calc_dur);
14010 } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14011 bytes_written += scnprintf(command+bytes_written,
14012 total_len - bytes_written,
14013 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
14014 rp->v3.roam_prof[i].roam_trigger,
14015 rp->v3.roam_prof[i].rssi_lower,
14016 rp->v3.roam_prof[i].channel_usage,
14017 rp->v3.roam_prof[i].cu_avg_calc_dur);
14018 } else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14019 bytes_written += snprintf(command+bytes_written,
14020 total_len - bytes_written,
14021 "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)",
14022 rp->v4.roam_prof[i].roam_trigger,
14023 rp->v4.roam_prof[i].rssi_lower,
14024 rp->v4.roam_prof[i].channel_usage,
14025 rp->v4.roam_prof[i].cu_avg_calc_dur);
14026 }
14027 }
14028 bytes_written += scnprintf(command+bytes_written, total_len - bytes_written, "\n");
14029 err = bytes_written;
14030 goto exit;
14031 } else {
14032 /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
14033 if (prof_cnt != 2) {
14034 ANDROID_ERROR(("FW must have 2 rows to fill roam_prof\n"));
14035 err = -EINVAL;
14036 goto exit;
14037 }
14038 /* setting roam profile to fw */
14039 data++;
14040 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
14041 roam_trigger = simple_strtol(data, &data, 10);
14042 if (roam_trigger >= 0) {
14043 ANDROID_ERROR(("roam trigger[%d] value must be negative\n", i));
14044 err = -EINVAL;
14045 goto exit;
14046 }
14047 data++;
14048 rssi_lower = simple_strtol(data, &data, 10);
14049 if (rssi_lower >= 0) {
14050 ANDROID_ERROR(("rssi lower[%d] value must be negative\n", i));
14051 err = -EINVAL;
14052 goto exit;
14053 }
14054 if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14055 rp->v2.roam_prof[i].roam_trigger = roam_trigger;
14056 rp->v2.roam_prof[i].rssi_lower = rssi_lower;
14057 data++;
14058 rp->v2.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
14059 data++;
14060 rp->v2.roam_prof[i].cu_avg_calc_dur =
14061 simple_strtol(data, &data, 10);
14062 }
14063 if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14064 rp->v3.roam_prof[i].roam_trigger = roam_trigger;
14065 rp->v3.roam_prof[i].rssi_lower = rssi_lower;
14066 data++;
14067 rp->v3.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
14068 data++;
14069 rp->v3.roam_prof[i].cu_avg_calc_dur =
14070 simple_strtol(data, &data, 10);
14071 }
14072 if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14073 rp->v4.roam_prof[i].roam_trigger = roam_trigger;
14074 rp->v4.roam_prof[i].rssi_lower = rssi_lower;
14075 data++;
14076 rp->v4.roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
14077 data++;
14078 rp->v4.roam_prof[i].cu_avg_calc_dur =
14079 simple_strtol(data, &data, 10);
14080 }
14081
14082 rp_len += roam_prof_size;
14083
14084 if (*data == '\0') {
14085 break;
14086 }
14087 data++;
14088 }
14089 if (i != 1) {
14090 ANDROID_ERROR(("Only two roam_prof rows supported.\n"));
14091 err = -EINVAL;
14092 goto exit;
14093 }
14094 rp->v1.len = rp_len;
14095 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
14096 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
14097 &cfg->ioctl_buf_sync)) < 0) {
14098 ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
14099 }
14100 }
14101 exit:
14102 if (rp) {
14103 MFREE(cfg->osh, rp, sizeof(*rp));
14104 }
14105 if (ioctl_buf) {
14106 MFREE(cfg->osh, ioctl_buf, WLC_IOCTL_MEDLEN);
14107 }
14108 return err;
14109 }
14110
wl_cfg80211_wbtext_weight_config(struct net_device * ndev,char * data,char * command,int total_len)14111 int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
14112 char *command, int total_len)
14113 {
14114 int bytes_written = 0, err = -EINVAL, argc = 0;
14115 char rssi[BUFSZN], band[BUFSZN], weight[BUFSZN];
14116 char *endptr = NULL;
14117 wnm_bss_select_weight_cfg_t *bwcfg;
14118 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14119 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14120
14121 bwcfg = (wnm_bss_select_weight_cfg_t *)MALLOCZ(cfg->osh, sizeof(*bwcfg));
14122 if (unlikely(!bwcfg)) {
14123 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14124 err = -ENOMEM;
14125 goto exit;
14126 }
14127 bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION;
14128 bwcfg->type = 0;
14129 bwcfg->weight = 0;
14130
14131 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band, weight);
14132
14133 if (!strcasecmp(rssi, "rssi"))
14134 bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
14135 else if (!strcasecmp(rssi, "cu"))
14136 bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
14137 else if (!strcasecmp(rssi, "estm_dl"))
14138 bwcfg->type = WNM_BSS_SELECT_TYPE_ESTM_DL;
14139 else {
14140 /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu/estm_dl> <band> <weight> */
14141 ANDROID_ERROR(("%s: Command usage error\n", __func__));
14142 goto exit;
14143 }
14144
14145 if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &bwcfg->band)) {
14146 ANDROID_ERROR(("%s: Command usage error\n", __func__));
14147 goto exit;
14148 }
14149
14150 if (argc == 2) {
14151 /* If there is no data after band, getting wnm_bss_select_weight from fw */
14152 if (bwcfg->band == WLC_BAND_ALL) {
14153 ANDROID_ERROR(("band option \"all\" is for set only, not get\n"));
14154 goto exit;
14155 }
14156 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
14157 sizeof(*bwcfg),
14158 ioctl_buf, sizeof(ioctl_buf), NULL))) {
14159 ANDROID_ERROR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
14160 goto exit;
14161 }
14162 memcpy(bwcfg, ioctl_buf, sizeof(*bwcfg));
14163 bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
14164 (bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" :
14165 (bwcfg->type == WNM_BSS_SELECT_TYPE_CU) ? "CU": "ESTM_DL",
14166 wl_android_get_band_str(bwcfg->band), bwcfg->weight);
14167 err = bytes_written;
14168 goto exit;
14169 } else {
14170 /* if weight is non integer returns command usage error */
14171 bwcfg->weight = simple_strtol(weight, &endptr, 0);
14172 if (*endptr != '\0') {
14173 ANDROID_ERROR(("%s: Command usage error", __func__));
14174 goto exit;
14175 }
14176 /* setting weight for iovar wnm_bss_select_weight to fw */
14177 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
14178 sizeof(*bwcfg),
14179 ioctl_buf, sizeof(ioctl_buf), NULL))) {
14180 ANDROID_ERROR(("setting wnm_bss_select_weight failed with err=%d\n", err));
14181 }
14182 }
14183 exit:
14184 if (bwcfg) {
14185 MFREE(cfg->osh, bwcfg, sizeof(*bwcfg));
14186 }
14187 return err;
14188 }
14189
14190 /* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
14191 #define WBTEXT_TUPLE_MIN_LEN_CHECK 5
14192
wl_cfg80211_wbtext_table_config(struct net_device * ndev,char * data,char * command,int total_len)14193 int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
14194 char *command, int total_len)
14195 {
14196 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14197 int bytes_written = 0, err = -EINVAL;
14198 char rssi[BUFSZN], band[BUFSZN];
14199 int btcfg_len = 0, i = 0, parsed_len = 0;
14200 wnm_bss_select_factor_cfg_t *btcfg;
14201 size_t slen = strlen(data);
14202 char *start_addr = NULL;
14203 u8 ioctl_buf[WLC_IOCTL_SMLEN];
14204
14205 data[slen] = '\0';
14206 btcfg = (wnm_bss_select_factor_cfg_t *)MALLOCZ(cfg->osh,
14207 (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14208 if (unlikely(!btcfg)) {
14209 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14210 err = -ENOMEM;
14211 goto exit;
14212 }
14213
14214 btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
14215 btcfg->band = WLC_BAND_AUTO;
14216 btcfg->type = 0;
14217 btcfg->count = 0;
14218
14219 sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", rssi, band);
14220
14221 if (!strcasecmp(rssi, "rssi")) {
14222 btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
14223 }
14224 else if (!strcasecmp(rssi, "cu")) {
14225 btcfg->type = WNM_BSS_SELECT_TYPE_CU;
14226 }
14227 else {
14228 ANDROID_ERROR(("%s: Command usage error\n", __func__));
14229 goto exit;
14230 }
14231
14232 if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &btcfg->band)) {
14233 ANDROID_ERROR(("%s: Command usage, Wrong band\n", __func__));
14234 goto exit;
14235 }
14236
14237 if ((slen - 1) == (strlen(rssi) + strlen(band))) {
14238 /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
14239 if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
14240 sizeof(*btcfg),
14241 ioctl_buf, sizeof(ioctl_buf), NULL))) {
14242 ANDROID_ERROR(("Getting wnm_bss_select_table failed with err=%d \n", err));
14243 goto exit;
14244 }
14245 memcpy(btcfg, ioctl_buf, sizeof(*btcfg));
14246 memcpy(btcfg, ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
14247
14248 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14249 "No of entries in table: %d\n", btcfg->count);
14250 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14251 "%s factor table\n",
14252 (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
14253 bytes_written += snprintf(command + bytes_written, total_len - bytes_written,
14254 "low\thigh\tfactor\n");
14255 for (i = 0; i <= btcfg->count-1; i++) {
14256 bytes_written += snprintf(command + bytes_written,
14257 total_len - bytes_written, "%d\t%d\t%d\n", btcfg->params[i].low,
14258 btcfg->params[i].high, btcfg->params[i].factor);
14259 }
14260 err = bytes_written;
14261 goto exit;
14262 } else {
14263 uint16 len = (sizeof(wnm_bss_select_factor_params_t) * WL_FACTOR_TABLE_MAX_LIMIT);
14264 memset_s(btcfg->params, len, 0, len);
14265 data += (strlen(rssi) + strlen(band) + 2);
14266 start_addr = data;
14267 slen = slen - (strlen(rssi) + strlen(band) + 2);
14268 for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
14269 if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
14270 btcfg->params[i].low = simple_strtol(data, &data, 10);
14271 data++;
14272 btcfg->params[i].high = simple_strtol(data, &data, 10);
14273 data++;
14274 btcfg->params[i].factor = simple_strtol(data, &data, 10);
14275 btcfg->count++;
14276 if (*data == '\0') {
14277 break;
14278 }
14279 data++;
14280 parsed_len = data - start_addr;
14281 } else {
14282 ANDROID_ERROR(("%s:Command usage:less no of args\n", __func__));
14283 goto exit;
14284 }
14285 }
14286 btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
14287 if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
14288 cfg->ioctl_buf, WLC_IOCTL_MEDLEN, &cfg->ioctl_buf_sync)) < 0) {
14289 ANDROID_ERROR(("seting wnm_bss_select_table failed with err %d\n", err));
14290 goto exit;
14291 }
14292 }
14293 exit:
14294 if (btcfg) {
14295 MFREE(cfg->osh, btcfg,
14296 (sizeof(*btcfg) + sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT));
14297 }
14298 return err;
14299 }
14300
14301 s32
wl_cfg80211_wbtext_delta_config(struct net_device * ndev,char * data,char * command,int total_len)14302 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
14303 {
14304 uint i = 0;
14305 struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
14306 int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
14307 char delta[BUFSZN], band[BUFSZN], *endptr = NULL;
14308 wl_roamprof_band_t *rp = NULL;
14309 uint8 band_val = 0, roam_prof_size = 0, roam_prof_ver = 0;
14310
14311 rp = (wl_roamprof_band_t *)MALLOCZ(cfg->osh, sizeof(*rp));
14312 if (unlikely(!rp)) {
14313 ANDROID_ERROR(("%s: failed to allocate memory\n", __func__));
14314 err = -ENOMEM;
14315 goto exit;
14316 }
14317
14318 argc = sscanf(data, "%"S(BUFSZ)"s %"S(BUFSZ)"s", band, delta);
14319 if (BCME_BADBAND == wl_android_bandstr_to_fwband(band, &band_val)) {
14320 ANDROID_ERROR(("%s: Missing band\n", __func__));
14321 goto exit;
14322 }
14323 if ((err = wlc_wbtext_get_roam_prof(ndev, rp, band_val, &roam_prof_ver,
14324 &roam_prof_size))) {
14325 ANDROID_ERROR(("Getting roam_profile failed with err=%d \n", err));
14326 err = -EINVAL;
14327 goto exit;
14328 }
14329 if (argc == 2) {
14330 /* if delta is non integer returns command usage error */
14331 val = simple_strtol(delta, &endptr, 0);
14332 if (*endptr != '\0') {
14333 ANDROID_ERROR(("%s: Command usage error", __func__));
14334 goto exit;
14335 }
14336 for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
14337 /*
14338 * Checking contents of roam profile data from fw and exits
14339 * if code hits below condtion. If remaining length of buffer is
14340 * less than roam profile size or if there is no valid entry.
14341 */
14342 if (len >= rp->v1.len) {
14343 break;
14344 }
14345 if (roam_prof_ver == WL_ROAM_PROF_VER_1) {
14346 if (rp->v2.roam_prof[i].fullscan_period == 0) {
14347 break;
14348 }
14349 if (rp->v2.roam_prof[i].channel_usage != 0) {
14350 rp->v2.roam_prof[i].roam_delta = val;
14351 }
14352 } else if (roam_prof_ver == WL_ROAM_PROF_VER_2) {
14353 if (rp->v3.roam_prof[i].fullscan_period == 0) {
14354 break;
14355 }
14356 if (rp->v3.roam_prof[i].channel_usage != 0) {
14357 rp->v3.roam_prof[i].roam_delta = val;
14358 }
14359 } else if (roam_prof_ver == WL_ROAM_PROF_VER_3) {
14360 if (rp->v4.roam_prof[i].fullscan_period == 0) {
14361 break;
14362 }
14363 if (rp->v4.roam_prof[i].channel_usage != 0) {
14364 rp->v4.roam_prof[i].roam_delta = val;
14365 }
14366 }
14367 len += roam_prof_size;
14368 }
14369 }
14370 else {
14371 if (rp->v2.roam_prof[0].channel_usage != 0) {
14372 bytes_written = snprintf(command, total_len,
14373 "%s Delta %d\n", wl_android_get_band_str(rp->v1.band),
14374 rp->v2.roam_prof[0].roam_delta);
14375 }
14376 err = bytes_written;
14377 goto exit;
14378 }
14379 rp->v1.len = len;
14380 if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
14381 sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN,
14382 &cfg->ioctl_buf_sync)) < 0) {
14383 ANDROID_ERROR(("seting roam_profile failed with err %d\n", err));
14384 }
14385 exit :
14386 if (rp) {
14387 MFREE(cfg->osh, rp, sizeof(*rp));
14388 }
14389 return err;
14390 }
14391 #endif /* WBTEXT */
14392