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