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