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